diff options
271 files changed, 71076 insertions, 0 deletions
diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 000000000..98c606041 --- /dev/null +++ b/.cvsignore @@ -0,0 +1,14 @@ +*.gz +stamp-h +stamp-h.in +stamp-h1 +.*.swp +libtool +ltmain.sh +intltool* +configure +config.* +aclocal.m4 +Makefile +Makefile.in +*.cache diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/AUTHORS diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..d60c31a97 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 000000000..971d6188a --- /dev/null +++ b/ChangeLog @@ -0,0 +1,875 @@ +2002-12-30 Marco Pesenti Gritti <marco@it.gnome.org> + + * embed/ephy-favicon-cache.c: (ephy_favicon_cache_dest), + (ephy_favicon_cache_insert_from_url), + (favicon_download_completed_cb): + * lib/ephy-dnd.c: (ephy_dnd_enable_model_drag_source): + * lib/ephy-dnd.h: + * lib/widgets/eggtreemultidnd.c: + (egg_tree_multi_drag_source_drag_data_get), + (egg_tree_multi_drag_drag_data_get): + * lib/widgets/eggtreemultidnd.h: + * lib/widgets/ephy-tree-model-sort.c: + (ephy_tree_model_sort_multi_drag_data_delete), + (each_url_get_data_binder), + (ephy_tree_model_sort_multi_drag_data_get): + * src/bookmarks/ephy-bookmarks-editor.c: + (ephy_bookmarks_editor_construct): + * src/bookmarks/ephy-node-view.c: + (ephy_node_view_enable_drag_source): + * src/bookmarks/ephy-node-view.h: + * src/history-dialog.c: (history_dialog_setup_view): + + Use ephy-dnd for tree model too. + Fix favicons. + +2002-12-30 Marco Pesenti Gritti <marco@it.gnome.org> + + * data/epiphany.schemas.in: + * lib/widgets/eggtreemodelfilter.c: + (egg_tree_model_filter_build_level): + * lib/widgets/ephy-autocompletion-window.c: + (ephy_autocompletion_window_get_dimensions), + (ephy_autocompletion_window_show), (hack_tree_view_move_selection), + (ephy_autocompletion_window_key_press_hack), + (ephy_autocompletion_window_key_press_cb), + (ephy_autocompletion_window_hide): + * src/bookmarks/ephy-bookmarks.c: + (ephy_bookmarks_clean_empty_keywords), (bookmarks_removed_cb): + * src/bookmarks/ephy-new-bookmark.c: (build_editing_table), + (ephy_new_bookmark_construct): + * src/bookmarks/ephy-node-view.c: (ephy_node_view_finalize): + * src/history-dialog.c: (history_dialog_finalize): + + Fix some bookmarks crashes. + Cycle between the two views in autocompletion when + moving with keys. + +2002-12-29 Marco Pesenti Gritti <marco@it.gnome.org> + + * TODO: + * lib/ephy-dnd.h: + * lib/ephy-marshal.c: (ephy_marshal_VOID__POINTER_POINTER): + * lib/ephy-marshal.h: + * lib/ephy-marshal.list: + * lib/widgets/Makefile.am: + * src/bookmarks/ephy-bookmarks-editor.c: + (ephy_bookmarks_editor_construct): + * src/bookmarks/ephy-new-bookmark.c: (ephy_new_bookmark_new): + * src/bookmarks/ephy-node-view.c: + (ephy_node_view_row_activated_cb), (node_from_sort_iter_cb), + (ephy_node_view_construct), (ephy_node_view_add_column), + (get_selection), (ephy_node_view_select_node), + (ephy_node_view_enable_drag_source): + * src/bookmarks/ephy-node-view.h: + * src/history-dialog.c: (add_column), + (history_view_row_activated_cb), (node_from_sort_iter_cb), + (history_dialog_setup_view): + + Implement column sorting / drag and drop for history + and bookmarks. + +2002-12-29 Marco Pesenti Gritti <marco@it.gnome.org> + + * data/glade/epiphany.glade: + * embed/ephy-history.c: (hosts_added_cb), (hosts_removed_cb), + (ephy_history_add_host), (ephy_history_add_page), + (ephy_history_set_page_title): + * embed/ephy-history.h: + * src/bookmarks/ephy-node-filter.c: + (ephy_node_filter_expression_evaluate): + * src/ephy-history-model.c: (get_one_level_path_real), + (get_path_real), (ephy_history_model_get_path), + (get_property_as_date), (ephy_history_model_get_value), + (ephy_history_model_update_node), (root_child_removed_cb), + (root_child_added_cb): + * src/history-dialog.c: (history_view_row_activated_cb), + (history_dialog_setup_view), (get_date_filter), + (history_dialog_setup_filter), (history_dialog_init), + (history_dialog_new_with_parent): + + Reimplement filtering, fix a few bugs. Please remove + ephy-history.xml again, should be the last time, sorry. + +2002-12-28 Marco Pesenti Gritti <marco@it.gnome.org> + + * embed/ephy-history.c: (ephy_history_add_page): + * src/ephy-history-model.c: (get_one_level_path_real), + (get_path_real), (ephy_history_model_get_path), + (ephy_history_model_update_node), (root_child_removed_cb), + (root_child_added_cb): + + Update the model correctly when the history changes. + +2002-12-28 Marco Pesenti Gritti <marco@it.gnome.org> + + * embed/ephy-history.c: (ephy_history_add_host): + + Fix memory corruption. The history now should work + better but please kill ephy-history.xml or you could + get crashes. + +2002-12-28 Marco Pesenti Gritti <marco@it.gnome.org> + + * embed/ephy-history.c: (ephy_history_init), + (ephy_history_add_page), (ephy_history_clear), + (ephy_history_get_hosts), (ephy_history_get_pages): + * embed/ephy-history.h: + * src/Makefile.am: + * src/ephy-history-model.c: (ephy_history_model_get_type), + (ephy_history_model_class_init), (ephy_history_model_init), + (ephy_history_model_finalize), (filter_changed_cb), + (ephy_history_model_set_property), + (ephy_history_model_get_property), (ephy_history_model_new), + (ephy_history_model_tree_model_init), + (ephy_history_model_get_flags), (ephy_history_model_get_n_columns), + (ephy_history_model_get_column_type), + (ephy_history_model_get_iter), (ensure_iter), (get_parent_node), + (get_path_real), (ephy_history_model_get_path), + (ephy_history_model_get_host_value), + (ephy_history_model_get_value), (ephy_history_model_iter_next), + (ephy_history_model_iter_children), + (ephy_history_model_iter_has_child), + (ephy_history_model_iter_n_children), + (ephy_history_model_iter_nth_child), + (ephy_history_model_iter_parent), + (ephy_history_model_node_from_iter), + (ephy_history_model_iter_from_node), + (ephy_history_model_update_node), (root_child_removed_cb), + (root_child_added_cb), (root_child_changed_cb), + (ephy_history_model_column_get_type): + * src/ephy-history-model.h: + * src/history-dialog.c: (add_column), (history_dialog_setup_view), + (history_dialog_init): + + Implement an history model and use it. + +2002-12-27 Marco Pesenti Gritti <marco@it.gnome.org> + + * data/Makefile.am: + * embed/Makefile.am: + * embed/ephy-embed-favicon.c: (location_changed_cb), + (ephy_embed_favicon_set_property): + * embed/ephy-embed-shell.c: (ephy_embed_shell_init), + (ephy_embed_shell_finalize), (ephy_embed_shell_get_favicon_cache), + (impl_get_global_history): + * embed/ephy-embed-shell.h: + * embed/ephy-favicon-cache.c: (ephy_favicon_cache_set_property), + (ephy_favicon_cache_get_property), (ephy_favicon_cache_class_init), + (ephy_favicon_cache_init), (ephy_favicon_cache_finalize), + (ephy_favicon_cache_new), (ephy_favicon_cache_lookup), + (ephy_favicon_cache_lookup_direct), (ephy_favicon_cache_insert), + (ephy_favicon_cache_dest): + * embed/ephy-favicon-cache.h: + * embed/ephy-favicon.c: (cache_changed_cb): + * embed/ephy-history.c: (ephy_history_get_type), + (ephy_history_autocompletion_source_set_basic_key), + (ephy_history_autocompletion_source_foreach), + (ephy_history_emit_data_changed), + (ephy_history_autocompletion_source_init), + (ephy_history_class_init), (ephy_history_load), + (ephy_history_save), (hosts_added_cb), (hosts_removed_cb), + (pages_added_cb), (pages_removed_cb), (ephy_history_init), + (ephy_history_finalize), (ephy_history_new), + (ephy_history_add_host), (ephy_history_visited), + (ephy_history_get_page_visits), (ephy_history_add_page), + (ephy_history_get_page), (ephy_history_is_page_visited), + (ephy_history_set_page_title), (ephy_history_clear), + (ephy_history_get_root), (ephy_history_get_last_page): + * embed/ephy-history.h: + * embed/global-history.c: + * embed/global-history.h: + * embed/mozilla/EphyWrapper.cpp: + * embed/mozilla/GlobalHistory.cpp: + * lib/Makefile.am: + * lib/ephy-node.c: (ephy_node_get_type), (ephy_node_class_init), + (int_equal), (int_hash), (ephy_node_init), (ephy_node_finalize), + (remove_child), (ephy_node_dispose), + (ephy_node_set_object_property), (ephy_node_get_object_property), + (ephy_node_new), (ephy_node_get_id), (node_from_id_real), + (ephy_node_get_from_id), (ephy_node_ref), (ephy_node_unref), + (ephy_node_freeze), (ephy_node_thaw), (child_changed), + (real_set_property), (ephy_node_set_property), + (ephy_node_get_property), (ephy_node_get_property_string), + (ephy_node_get_property_boolean), (ephy_node_get_property_long), + (ephy_node_get_property_int), (ephy_node_get_property_double), + (ephy_node_get_property_float), (ephy_node_get_property_node), + (ephy_node_get_property_time), (save_parent), + (ephy_node_save_to_xml), (ephy_node_new_from_xml), + (real_add_child), (ephy_node_add_child), (real_remove_child), + (ephy_node_remove_child), (ephy_node_has_child), + (ephy_node_get_children), (ephy_node_get_n_children), + (ephy_node_get_nth_child), (get_child_index_real), + (ephy_node_get_child_index), (ephy_node_get_next_child), + (ephy_node_get_previous_child), (ephy_node_system_init), + (ephy_node_system_shutdown), (ephy_node_new_id), + (id_factory_set_to), (write_lock_to_read_lock), + (read_lock_to_write_lock), (lock_gdk), (unlock_gdk): + * lib/ephy-node.h: + * src/bookmarks/Makefile.am: + * src/bookmarks/ephy-bookmarks.c: (get_history_item_score), + (compute_lower_fav), (add_to_favorites), (history_site_visited_cb), + (ephy_setup_history_notifiers), (ephy_bookmarks_init), + (ephy_bookmarks_finalize): + * src/bookmarks/ephy-node.c: + * src/bookmarks/ephy-node.h: + * src/ephy-shell.c: (ephy_shell_init), (ephy_shell_finalize), + (build_homepage_url), (ephy_shell_get_autocompletion): + * src/ephy-shell.h: + * src/history-dialog.c: (history_dialog_setup_view), + (history_dialog_setup_filter), (history_dialog_init), + (history_dialog_set_embedded), (history_dialog_finalize), + (history_host_checkbutton_toggled_cb), (history_entry_changed_cb), + (history_time_optionmenu_changed_cb), + (history_clear_button_clicked_cb): + + Rewrite the history using ephy node. + Use the history to store favicons locations. + +2002-12-26 Marco Pesenti Gritti <marco@it.gnome.org> + + * embed/ephy-embed-favicon.c: (net_state_cb), (favicon_cb): + + fix some bugs + +2002-12-26 Marco Pesenti Gritti <marco@it.gnome.org> + + * TODO: + * embed/ephy-embed-favicon.c: (net_state_cb), (favicon_cb), + (ephy_embed_favicon_set_property), + (ephy_embed_favicon_get_property), (ephy_embed_favicon_get_embed): + * embed/ephy-embed.c: (ephy_embed_base_init), + (ephy_embed_get_link_tags): + * embed/ephy-embed.h: + * embed/mozilla/EphyWrapper.cpp: + * embed/mozilla/EphyWrapper.h: + * embed/mozilla/Makefile.am: + * embed/mozilla/mozilla-embed.cpp: + + Make favicons work :) + +2002-12-26 Marco Pesenti Gritti <marco@it.gnome.org> + + * configure.in: + * embed/find-dialog.c: (find_dialog_go_next), + (find_dialog_go_prev): + * lib/ephy-autocompletion.c: + (ephy_autocompletion_get_matches_sorted_by_score), + (ephy_autocompletion_refine_matches), + (ephy_autocompletion_update_matches_full), + (ephy_autocompletion_sort_by_score): + * lib/ephy-autocompletion.h: + * lib/widgets/ephy-autocompletion-window.c: + (ephy_autocompletion_window_get_dimensions), + (ephy_autocompletion_window_fill_store_chunk), + (ephy_autocompletion_window_show): + * src/popup-commands.c: (popup_cmd_add_bookmark): + + Fix a regression in find dialog. + Fix autocompletion flickering + +2002-12-25 Marco Pesenti Gritti <marco@it.gnome.org> + + * embed/find-dialog.c: (find_dialog_go_next), + (find_dialog_go_prev): + * src/bookmarks/ephy-bookmarks.c: + (ephy_bookmarks_autocompletion_source_foreach): + + Fix crash on find next. + Fix crash on autocompletion. + +2002-12-24 Marco Pesenti Gritti <marco@it.gnome.org> + + * src/bookmarks/ephy-bookmarks-editor.c: + (keyword_node_selected_cb), (ephy_bookmarks_editor_construct): + + Regression fixed. + +2002-12-24 Marco Pesenti Gritti <marco@it.gnome.org> + + * src/bookmarks/Makefile.am: + * src/bookmarks/ephy-bookmarks-editor.c: (keywords_changed_cb), + (keywords_removed_cb), (ephy_bookmarks_editor_construct): + * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_add), + (ephy_bookmarks_unset_keyword), (diff_keywords), + (ephy_bookmarks_update_keywords): + * src/bookmarks/ephy-bookmarks.h: + * src/window-commands.c: (window_cmd_bookmarks_add_default): + + Implement a small dialog asking title/keywords when adding + bookmarks. + (Regression: removing a selected keyword doesnt work + anymore, will fix) + +2002-12-24 Marco Pesenti Gritti <marco@it.gnome.org> + + * data/glade/epiphany.glade: + * data/ui/epiphany-ui.xml.in: + * embed/mozilla/ContentHandler.cpp: + * embed/mozilla/FilePicker.cpp: + * embed/mozilla/FilePicker.h: + * lib/widgets/Makefile.am: + * lib/widgets/ephy-sidebar.c: + * lib/widgets/ephy-sidebar.h: + * src/ephy-tab.c: (ephy_tab_init), (get_host_name_from_uri): + * src/ephy-window.c: (update_layout_toggles), (setup_layout_menus), + (ephy_window_init), (save_window_chrome), + (translate_default_chrome), (ephy_window_set_chrome), + (ephy_window_update_all_controls): + * src/ephy-window.h: + * src/session.c: + + Drop sidebar and useless bytes progress messages. + +2002-12-23 Marco Pesenti Gritti <marco@it.gnome.org> + + * lib/widgets/ephy-autocompletion-window.c: + (ephy_autocompletion_window_get_dimensions), + (ephy_autocompletion_window_show), + (ephy_autocompletion_window_hide): + * src/session.c: (do_session_resume), (crashed_resume_dialog), + (session_autoresume): + + fix autocompl bugs. + Simpler recover dialog. + +2002-12-23 Marco Pesenti Gritti <marco@it.gnome.org> + + * lib/widgets/ephy-autocompletion-window.c: + (ephy_autocompletion_window_finalize_impl), + (ephy_autocompletion_window_init_widgets), + (ephy_autocompletion_window_set_autocompletion), + (ephy_autocompletion_window_get_dimensions), + (ephy_autocompletion_window_fill_store_chunk), + (ephy_autocompletion_window_show), + (ephy_autocompletion_window_event_after_cb): + * lib/widgets/ephy-location-entry.c: (ephy_location_ignore_prefix), + (ephy_location_entry_autocompletion_show_alternatives_to), + (ephy_location_entry_key_press_event_cb): + * src/bookmarks/ephy-bookmarks.c: + (ephy_bookmarks_autocompletion_source_foreach): + + Never show an horizontal scrollbar. + Put a limit to completions, ever show bookmarks / smart + bookmarks matches. Order bookmarks at the bottom of + completions. + Ignore common used web prefixes (like www) + +2002-12-22 Marco Pesenti Gritti <marco@it.gnome.org> + + * lib/ephy-autocompletion.c: (ephy_autocompletion_get_num_matches), + (ephy_autocompletion_get_num_action_matches), + (ephy_autocompletion_refine_matches), + (ephy_autocompletion_update_matches_full_item), (acma_destroy), + (acma_append): + * lib/ephy-autocompletion.h: + * lib/widgets/ephy-autocompletion-window.c: + (ephy_autocompletion_window_init), + (ephy_autocompletion_window_finalize_impl), + (ephy_autocompletion_window_selection_changed_cb), + (ephy_autocompletion_window_get_dimensions), + (ephy_autocompletion_window_show), + (ephy_autocompletion_window_key_press_hack), + (ephy_autocompletion_window_key_press_cb), + (ephy_autocompletion_window_event_after_cb): + * lib/widgets/ephy-location-entry.c: (ephy_location_entry_init), + (ephy_location_entry_content_is_text), + (ephy_location_entry_activate_cb), + (ephy_location_entry_autocompletion_window_url_activated_cb): + * src/bookmarks/ephy-bookmarks.c: + (ephy_bookmarks_autocompletion_source_foreach), + (ephy_bookmarks_save), (ephy_bookmarks_solve_smart_url): + * src/ephy-shell.c: (ephy_shell_get_autocompletion): + * src/toolbar.c: (toolbar_location_url_activate_cb): + + Complete smart bookmarks "autocompletion". + +2002-12-21 Marco Pesenti Gritti <marco@it.gnome.org> + + * lib/ephy-autocompletion.c: (ephy_autocompletion_refine_matches), + (ephy_autocompletion_update_matches), + (ephy_autocompletion_update_matches_full_item): + * lib/ephy-autocompletion.h: + * lib/widgets/ephy-autocompletion-window.c: + (ephy_autocompletion_window_class_init), + (ephy_autocompletion_window_selection_add_selected), + (ephy_autocompletion_window_get_dimensions), + (ephy_autocompletion_window_fill_store_chunk), + (ephy_autocompletion_window_show), + (ephy_autocompletion_window_key_press_hack), + (ephy_autocompletion_window_event_after_cb): + * lib/widgets/ephy-autocompletion-window.h: + * lib/widgets/ephy-location-entry.c: + (ephy_location_entry_class_init), + (ephy_location_entry_activate_cb), + (ephy_location_entry_set_autocompletion), + (ephy_location_entry_autocompletion_window_url_activated_cb), + (ephy_location_entry_list_event_after_cb): + * lib/widgets/ephy-location-entry.h: + * src/bookmarks/ephy-bookmarks.c: (options_skip_spaces), + (options_find_value_end), (options_find_next_option), + (smart_url_options_get), (get_smarturl_only), + (ephy_bookmarks_solve_smart_url): + * src/bookmarks/ephy-bookmarks.h: + * src/toolbar.c: (toolbar_location_url_activate_cb), + (toolbar_setup_location_entry): + + Hide views when empty, fix sizing to deal with + visibility. + Make bookmarks open correctly. + Add some smart bookmarks solving code. + +2002-12-21 Marco Pesenti Gritti <marco@it.gnome.org> + + * data/Makefile.am: + * data/epiphany.schemas.in: + * embed/mozilla/Makefile.am: + * embed/mozilla/MozRegisterComponents.cpp: + * embed/mozilla/StartHereProtocolHandler.cpp: + * embed/mozilla/StartHereProtocolHandler.h: + * lib/ephy-gui.c: (shift_color_component), + (ephy_gui_rgb_shift_color), (rgb16_to_rgb), + (ephy_gui_gdk_color_to_rgb), (ephy_gui_gdk_rgb_to_color): + * lib/ephy-gui.h: + * lib/widgets/ephy-autocompletion-window.c: + (ephy_autocompletion_window_init_widgets): + * src/bookmarks/ephy-bookmarks.c: + (ephy_bookmarks_autocompletion_source_foreach): + * src/popup-commands.c: (popup_cmd_add_bookmark): + + Use a darker color for the actions part of the + autocompletion window. + Add a (sucky) start-here: page and use it as + default homepage. + +2002-12-20 Marco Pesenti Gritti <marco@it.gnome.org> + + * embed/global-history.c: (history_add_url_to_list), + (global_history_get_urls_list), + (global_history_autocompletion_source_foreach_aux), + (global_history_autocompletion_source_foreach): + * lib/ephy-autocompletion-source.c: + (ephy_autocompletion_source_base_init): + * lib/ephy-autocompletion-source.h: + * lib/ephy-autocompletion.c: + (ephy_autocompletion_get_common_prefix), + (ephy_autocompletion_update_matches), + (ephy_autocompletion_update_matches_full_item), + (ephy_autocompletion_update_matches_full), + (ephy_autocompletion_compare_scores_and_alpha), + (ephy_autocompletion_sort_by_score): + * lib/ephy-autocompletion.h: + * lib/ephy-filesystem-autocompletion.c: + (ephy_filesystem_autocompletion_autocompletion_source_foreach): + * lib/widgets/ephy-autocompletion-window.c: + (ephy_autocompletion_window_finalize_impl), + (ephy_autocompletion_window_init_widgets), + (ephy_autocompletion_window_selection_changed_cb), + (ephy_autocompletion_window_selection_add_selected), + (ephy_autocompletion_window_get_dimensions), + (ephy_autocompletion_window_fill_store_chunk), + (ephy_autocompletion_window_show): + * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_get_type), + (ephy_bookmarks_autocompletion_source_set_basic_key), + (ephy_bookmarks_autocompletion_source_foreach), + (ephy_bookmarks_emit_data_changed), + (ephy_bookmarks_autocompletion_source_init), + (bookmarks_removed_cb), (ephy_bookmarks_init), + (ephy_bookmarks_add): + * src/bookmarks/ephy-bookmarks.h: + * src/ephy-shell.c: (ephy_shell_get_autocompletion): + * src/window-commands.c: (window_cmd_bookmarks_add_default): + + Begin to implement smarter location entry. Now it looks + for bookmarks/keywords and show them by title. + Urls are showed just as urls (no more title). + At the bottom you can select smartbookmarks in a mozilla + like way (how do you add smb ? just edit xml for now ;)). + It's still incomplete but prolly it's not going to be all + the work I thought at beginning. + +2002-12-20 Marco Pesenti Gritti <marco@it.gnome.org> + + * src/bookmarks/ephy-bookmarks-editor.c: (diff_keywords), + (update_keywords): + * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_find_keyword): + * src/bookmarks/ephy-keywords-entry.c: (try_to_expand_keyword): + + Fix several keywords bugs. Should start to get usable. + +2002-12-19 Marco Pesenti Gritti <marco@it.gnome.org> + + * src/bookmarks/ephy-bookmarks-editor.c: (build_editing_table): + * src/bookmarks/ephy-bookmarks.c: + (ephy_bookmarks_clean_empty_keywords), (keywords_added_cb), + (keywords_removed_cb), (bookmarks_removed_cb), + (ephy_bookmarks_init), (ephy_bookmarks_finalize), + (ephy_bookmarks_find_keyword), (ephy_bookmarks_set_keyword), + (ephy_bookmarks_unset_keyword): + * src/bookmarks/ephy-keywords-entry.c: + (ephy_keywords_entry_class_init), (try_to_expand_keyword), + (entry_would_have_inserted_characters), + (ephy_keywords_entry_key_press), (ephy_keywords_entry_init): + * src/bookmarks/ephy-keywords-entry.h: + + Complete autocompletion implementation. + Rewrite keywords removing code. Still bad bugs + but getting better. + +2002-12-16 Marco Pesenti Gritti <marco@it.gnome.org> + + * configure.in: + * src/bookmarks/Makefile.am: + * src/bookmarks/ephy-bookmarks-editor.c: (update_keywords), + (keywords_changed_cb), (build_editing_table): + * src/bookmarks/ephy-bookmarks.c: (keywords_added_cb), + (keywords_removed_cb), (partial_match_equal), + (ephy_bookmarks_init), (ephy_bookmarks_finalize), + (ephy_bookmarks_find_keyword), (ephy_bookmarks_set_keyword), + (ephy_bookmarks_unset_keyword): + * src/bookmarks/ephy-bookmarks.h: + * src/bookmarks/ephy-node-view.c: (ephy_node_view_select_node): + * src/bookmarks/ephy-node-view.h: + + Fix some keywords bugs and start working on autocompletion + +2002-12-15 Marco Pesenti Gritti <marco@it.gnome.org> + + * src/bookmarks/ephy-bookmarks-editor.c: + (ephy_bookmarks_editor_construct): + * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_save), + (add_to_favorites), (history_site_visited_cb), + (ephy_bookmarks_finalize): + * src/ephy-favorites-menu.c: (ephy_favorites_menu_set_path), + (ephy_favorites_menu_verb_cb), (ephy_favorites_menu_rebuild), + (ephy_favorites_menu_update): + * src/ephy-window.c: (ephy_window_init): + + Make favorites really work + +2002-12-15 Marco Pesenti Gritti <marco@it.gnome.org> + + * TODO: + * embed/global-history.c: (global_history_get_item): + * embed/global-history.h: + * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_save), + (get_history_item_score), (compute_lower_fav), + (ephy_bookmarks_update_favorites), (add_to_favorites), + (update_favorites_menus), (history_site_visited_cb), + (keywords_added_cb), (keywords_removed_cb), (favorites_added_cb), + (favorites_removed_cb), (ephy_bookmarks_init), + (ephy_bookmarks_finalize), (ephy_bookmarks_get_keyword): + + Complete favorites implementation, still buggy. + +2002-12-14 Marco Pesenti Gritti <marco@it.gnome.org> + + * data/ui/epiphany-ui.xml.in: + * embed/global-history.c: (global_history_class_init), + (global_history_visited): + * embed/global-history.h: + * src/Makefile.am: + * src/bookmarks/ephy-bookmarks.c: (history_site_visited_cb), + (ephy_setup_history_notifiers), (bookmarks_added_cb), + (bookmarks_removed_cb), (ephy_bookmarks_init), + (ephy_bookmarks_finalize), (ephy_bookmarks_get_favorites): + * src/bookmarks/ephy-bookmarks.h: + * src/ephy-favorites-menu.c: (ephy_favorites_menu_class_init), + (ephy_favorites_menu_init), (ephy_favorites_menu_finalize_impl), + (ephy_favorites_menu_set_property), + (ephy_favorites_menu_get_property), (ephy_favorites_menu_new), + (ephy_favorites_menu_set_path), (ephy_favorites_menu_rebuild), + (ephy_favorites_menu_update), (ephy_favorites_menu_verb_cb): + * src/ephy-favorites-menu.h: + * src/ephy-window.c: (ephy_window_init), + (update_favorites_control), (ephy_window_update_control): + * src/ephy-window.h: + * src/window-recent-history-menu.c: + * src/window-recent-history-menu.h: some work on favorites, + still not working quite well + +2002-12-14 Marco Pesenti Gritti <marco@it.gnome.org> + + * src/bookmarks/ephy-bookmarks-editor.c: + (ephy_bookmarks_editor_node_selected_cb), (diff_keywords), + (update_keywords), (keywords_entry_changed_cb), (bookmarks_filter), + (keyword_node_selected_cb), (build_search_box), + (ephy_bookmarks_editor_construct): + * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_save), + (ephy_bookmarks_init), (ephy_bookmarks_set_keyword): + * src/bookmarks/ephy-node-view.c: (ephy_node_view_set_browse_mode): + * src/bookmarks/ephy-node-view.h: complete keyword implementation, + still buggy + +2002-12-14 Marco Pesenti Gritti <marco@it.gnome.org> + + * src/bookmarks/ephy-bookmarks-editor.c: + (ephy_bookmarks_editor_finalize), (update_keywords), + (keywords_entry_changed_cb), (search_entry_changed_cb), + (build_search_box), (ephy_bookmarks_editor_construct): + * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_save), + (ephy_bookmarks_init), (ephy_bookmarks_finalize), + (ephy_bookmarks_add_keyword), (ephy_bookmarks_get_keyword), + (ephy_bookmarks_set_keyword), (ephy_bookmarks_get_keywords): + * src/bookmarks/ephy-bookmarks.h: + * src/bookmarks/ephy-tree-model-node.c: + (ephy_tree_model_node_get_column_type), + (ephy_tree_model_node_get_value), + (ephy_tree_model_node_column_get_type): + * src/bookmarks/ephy-tree-model-node.h: + * src/ephy-window.c: some work on keywords implementation, + still not working + +2002-12-13 Marco Pesenti Gritti <marco@it.gnome.org> + + * data/glade/epiphany.glade: + * data/glade/prefs-dialog.glade: + * data/ui/epiphany-ui.xml.in: + * embed/downloader-view.c: (get_selected_row), + (download_dialog_abort_cb): + * src/Makefile.am: + * src/ephy-tab.c: (ephy_tab_location_cb), (ephy_tab_title_cb): + * src/ephy-window.c: (ephy_window_init), (ephy_window_finalize), + (ephy_window_get_toolbar): + * src/ephy-window.h: + * src/history-dialog.c: (each_url_get_data_binder): + * src/language-editor.c: + (language_editor_remove_button_clicked_cb): + * src/pdm-dialog.c: (cookies_treeview_selection_changed_cb), + (action_treeview_selection_changed_cb), + (pdm_dialog_remove_button_clicked_cb), (setup_action), + (pdm_dialog_init), + (pdm_dialog_cookies_properties_button_clicked_cb): + * src/window-commands.c: + * src/window-commands.h: + * src/window-recent-history.c: + * src/window-recent-history.h: some menu rehashing, remove recent + history to be replaced by favourites. Fix all tree views. + +2002-12-12 Marco Pesenti Gritti <marco@it.gnome.org> + + * embed/find-dialog.c: (impl_show): grab focus on the entry + +2002-12-08 Marco Pesenti Gritti <marco@it.gnome.org> + + * src/bookmarks/ephy-bookmarks-editor.c: + (ephy_bookmarks_editor_node_selected_cb), (update_prop_from_entry): + + Fix some memory corruption. + +2002-12-08 Marco Pesenti Gritti <marco@it.gnome.org> + + * TODO: + * src/bookmarks/ephy-bookmarks-editor.c: + (ephy_bookmarks_editor_node_selected_cb), (update_prop_from_entry), + (title_entry_changed_cb), (keywords_entry_changed_cb), + (build_editing_table), (ephy_bookmarks_editor_construct): + * src/bookmarks/ephy-bookmarks.h: + * src/bookmarks/ephy-node-view.c: (ephy_node_view_class_init), + (ephy_node_view_selection_changed_cb), (ephy_node_view_construct): + * src/bookmarks/ephy-node-view.h: + + Add ability to edit title and keywords (useless atm). + +2002-12-08 Marco Pesenti Gritti <marco@it.gnome.org> + + * Makefile.am: + * README: + * configure.in: + * embed/mozilla/Makefile.am: + * lib/Makefile.am: + * po/.cvsignore: + * po/POTFILES.in: + + Make it pass distcheck. + + * src/ephy-tab.c: (ephy_tab_dom_mouse_down_cb): + + Reintroduce page load on url pasting. + +2002-12-08 Marco Pesenti Gritti <marco@it.gnome.org> + + * src/bookmarks/Makefile.am: + * src/bookmarks/ephy-bookmarks-editor.c: + (ephy_bookmarks_editor_node_activated_cb), + (ephy_bookmarks_editor_response_cb), + (ephy_bookmarks_editor_construct), (ephy_bookmarks_editor_new): + * src/bookmarks/ephy-bookmarks-editor.h: + * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_save), + (ephy_bookmarks_finalize), (ephy_bookmarks_add): + * src/bookmarks/ephy-node-view.c: + (ephy_node_view_row_activated_cb), (ephy_node_view_construct), + (ephy_node_view_new), (ephy_node_view_init), (get_selection), + (ephy_node_view_get_selection), (ephy_node_view_remove): + * src/bookmarks/ephy-node-view.h: + * src/bookmarks/ephy-tree-model-node.c: (ephy_tree_model_node_new): + * src/ephy-shell.c: (ephy_shell_finalize): + * src/window-commands.c: (window_cmd_bookmarks_edit): + + You can now at least add bookmarks to a list + +2002-12-07 Marco Pesenti Gritti <marco@it.gnome.org> + + * embed/mozilla/EphyWrapper.cpp: + * embed/mozilla/EphyWrapper.h: remove some unused code, + should build with mozilla head again + +2002-12-06 Marco Pesenti Gritti <marco@it.gnome.org> + + * src/bookmarks/ephy-bookmarks-editor.c: + (ephy_bookmarks_editor_class_init), + (ephy_bookmarks_editor_construct), (ephy_bookmarks_editor_new), + (ephy_bookmarks_editor_set_property), + (ephy_bookmarks_editor_get_property), (ephy_bookmarks_editor_init): + * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_load), + (ephy_bookmarks_init), (ephy_bookmarks_finalize), + (ephy_bookmarks_add), (ephy_bookmarks_get_bookmarks): + * src/bookmarks/ephy-bookmarks.h: + * src/window-commands.c: (window_cmd_bookmarks_edit), + (window_cmd_bookmarks_add_default): more bookmarks work + +2002-12-05 Bastien Nocera <hadess@hadess.net> + + * src/ephy-main.c: (ephy_main_start): get the Bonobo warning go away and Ephy to + just actually work + +2002-12-05 Marco Pesenti Gritti <marco@it.gnome.org> + + * embed/mozilla/FilePicker.cpp: actually parent the file picker + * src/Makefile.am: + * src/bookmarks/ephy-bookmarks-editor.c: + (ephy_bookmarks_editor_class_init), (ephy_bookmarks_editor_new), + (ephy_bookmarks_editor_construct), + (ephy_bookmarks_editor_set_object_property), + (ephy_bookmarks_editor_get_object_property), + (ephy_bookmarks_editor_init): + * src/bookmarks/ephy-bookmarks-editor.h: + * src/bookmarks/ephy-node-view.c: (ephy_node_view_set_property), + (ephy_node_view_construct), (ephy_node_view_add_column), + (ephy_node_view_init): + * src/ephy-shell.c: (ephy_shell_init), (ephy_shell_get_bookmarks): + * src/ephy-shell.h: + * src/window-commands.c: (window_cmd_bookmarks_edit): + more useless bookmarks work + +2002-12-01 Marco Pesenti Gritti <marco@it.gnome.org> + + * src/bookmarks/Makefile.am: + * src/bookmarks/eggtreemodelfilter.c: + * src/bookmarks/eggtreemodelfilter.h: + * src/bookmarks/ephy-bookmarks-editor.c: + * src/bookmarks/ephy-bookmarks-editor.h: + * src/bookmarks/ephy-node-view.c: + * src/bookmarks/ephy-node-view.h: more bookmarks work + +2002-11-30 Marco Pesenti Gritti <marco@it.gnome.org> + + * embed/ephy-embed.h: + * embed/find-dialog.c: (find_dialog_go_next), + (find_dialog_go_prev), (find_next_button_clicked_cb), + (find_prev_button_clicked_cb), (find_entry_activate_cb): + * embed/find-dialog.h: + * embed/mozilla/EphyWrapper.cpp: + * embed/mozilla/EphyWrapper.h: + * embed/mozilla/Makefile.am: + * embed/mozilla/mozilla-embed.cpp: + * src/bookmarks/Makefile.am: + * src/bookmarks/ephy-bookmarks.h: + * src/bookmarks/ephy-node-filter.c: + * src/bookmarks/ephy-node-filter.h: + * src/bookmarks/ephy-node.c: (ephy_node_class_init): + * src/bookmarks/ephy-tree-model-node.c: + * src/bookmarks/ephy-tree-model-node.h: + * src/window-commands.c: fix dialog/typeahead find + interaction. More infrastucture bookmarks work. + +2002-11-29 Marco Pesenti Gritti <marco@it.gnome.org> + + * lib/ephy-string.c: + * lib/ephy-string.h: remove no more used helper + * src/window-recent-history-menu.c: + (ephy_window_recent_history_menu_rebuild): correctly + encode xml strings + +2002-11-28 Marco Pesenti Gritti <marco@it.gnome.org> + + * configure.in: + * lib/Makefile.am: + * lib/ephy-string.c: (ephy_string_store_time_in_string), + (ephy_string_time_to_string): + * lib/ephy-string.h: + * src/Makefile.am: + * src/bookmarks/Makefile.am: + * src/bookmarks/ephy-bookmarks.c: + * src/bookmarks/ephy-bookmarks.h: + * src/bookmarks/ephy-node.c: + * src/bookmarks/ephy-node.h: + * src/ephy-shell.c: + * src/history-dialog.c: (history_dialog_update_host_item), + (history_dialog_update_url_item): some configure cleanups, + some bookmarks architecture stuff. Credits to rhythmbox + developers. + +2002-11-27 Marco Pesenti Gritti <marco@it.gnome.org> + + * data/epiphany.schemas.in: + * embed/ephy-embed-event.h: + * embed/ephy-embed-persist.c: (ephy_embed_persist_new): + * embed/ephy-embed-popup.c: (setup_element_menu), + (setup_document_menu): + * embed/mozilla/Makefile.am: fix favicons, remove mozilla-config.h + and use the old hack. Damn we need a real fix for this. + +2002-11-27 Marco Pesenti Gritti <marco@it.gnome.org> + + * data/glade/toolbar-editor.glade: + * lib/toolbar/ephy-toolbar-editor.c: (update_arrows_sensitivity), + (ephy_tb_editor_treeview_selection_changed_cb), + (ephy_tb_editor_setup_treeview): fix arrows sensitivity in the + toolbar editor + +2002-11-27 Marco Pesenti Gritti <marco@it.gnome.org> + + * README: wrote + * src/ephy-shell.c: (ephy_init_services): add the monitor on the + right gconf dir + * src/history-dialog.c: fix gcon paths + +2002-11-27 Marco Pesenti Gritti <marco@it.gnome.org> + + * data/art/epiphany-secure.png: + * data/art/epiphany-unsecure.png: resize to 18x18 + * configure.in: + * embed/Makefile.am: + * embed/mozilla/Makefile.am: + * src/Makefile.am: + * lib/Makefile.am: + * lib/toolbar/Makefile.am: + * lib/widgets/Makefile.am: enable werror + * lib/ephy-file-helpers.c: missing includes + * lib/widgets/ephy-location-entry.c: disable completion_to by default + (ephy_location_entry_key_press_event_cb): + * src/statusbar.c: (statusbar_set_security_state): really fix it + +2002-11-27 Marco Pesenti Gritti <marco@it.gnome.org> + + * data/GNOME_Epiphany_NautilusView.server.in: + * data/epiphany.schemas.in: + * data/glade/epiphany.glade: + * data/ui/epiphany-ui.xml.in: + * data/ui/nautilus-epiphany-view.xml.in: + * embed/global-history.c: (history_save): + * embed/mozilla/ContentHandler.cpp: + * lib/ephy-file-helpers.c: (ephy_ensure_dir_exists): + * lib/ephy-file-helpers.h: + * src/ephy-shell.c: (ephy_shell_init): + * src/history-dialog.c: (history_dialog_set_embedded): + * src/pdm-dialog.c: (pdm_dialog_init): + * src/session.c: (crashed_resume_dialog): + * src/statusbar.c: (statusbar_set_security_state): + Fix a few typos, get rid of mime handlers list, + reimplement security icon + +2002-11-26 Marco Pesenti Gritti <marco@it.gnome.org> + + * Checked in initial codebase. diff --git a/HACKING b/HACKING new file mode 100644 index 000000000..430e0ff7b --- /dev/null +++ b/HACKING @@ -0,0 +1,16 @@ +In order to keep the code nice and clean we have a few requirements you'll +need to stick to in order to get your patch accepted: + +- use 8-space tabs for indentation +- curly brackets are on a new line +- please compare with NULL or FALSE isntead of using "!" +- callback functions have a suffix _cb + + Comment blocks are written like this: + +/** + * bla_bla_cb: This is an example comment block + */ + +Do NOT commit to this module without permission from me +(marco@it.gnome.org) diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..b42a17ac4 --- /dev/null +++ b/INSTALL @@ -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 --git a/Makefile.am b/Makefile.am new file mode 100644 index 000000000..068ec8e39 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = lib embed src data po + +EXTRA_DIST = \ + intltool-merge.in \ + intltool-update.in \ + intltool-extract.in @@ -0,0 +1,121 @@ +Epiphany is a GNOME web browser based on the mozilla +rendering engine. +The name meaning: +"An intuitive grasp of reality through +something (as an event) usually simple and striking" + +MANIFESTO + +A web browser is more than an application, it is a way of thinking, it is +a way of seeing the world. Epiphany's principles are simplicity and standards +compliance. + +Simplicity: + +While Mozilla has an excellent rendering engine, its default +XUL-based interface is considered to be overcrowded and bloated. Furthermore, +on slower processors even trivial tasks such as pulling down a menu is less +than responsive. + +Epiphany aims to utilize the simplest interface possible for a browser. Keep +in mind that simple does not necessarily mean less powerful. We believe +the commonly used browsers of today are too big, buggy, and bloated. Epiphany +addresses simplicity with a small browser designed for the web -- not mail, +newsgroups, file management, instant messenging or coffee making. The UNIX +philosophy is to design small tools that do one thing, and do it well. + +Epiphany also address simplicity with modularity to make a light and powerful +application. If something can be implemented using external applications +or components, we use it rather than wasting resources in the web browser. +Integration will be achived with CORBA, Bonobo, and the ever popular +command line. + +Mail will be handled with your favorite e-mail application (Evolution, pine, +mutt, balsa, pronto, whatever). + +Standards compliance: + +The introduction of non-standard features in browsers could make it difficult +or impossible to use alternative products like Epiphany if developers embrace +them. Alternative (standards complying) browsers could not be able to +fully access web sites making use of these features. The success of +non-standard features can ultimately lead to forcing one browser, on +one platform to dominate the market. + +Standards compliance ensures the freedom of choice. Epiphany aims to achieve +this. + +USER INTERFACE LINES + +- HIG compliance + +Epiphany is going to follow version 1.0 of the gnome +user guidelines. Unless there are very seriuos reasons to make an +exception not following it will be considered a bug. +"I follow the HIG only when I like it" is not a legitimate approach. +Any areas where we diverge from the HIG will communicated +to the HIG team for future consideration. + +- Gnome integration + +Epiphany's main goal is to be integrated with the gnome desktop. +We dont aim to make epiphany usable outside Gnome. If someone will like +to use it anyway, it's just a plus. Ex: Making people happy that +don't have control center installed is not a good reason +to have mime configuration in epiphany itself. + +- Simple design + +Feature bloat and user interface clutter is evil :) + +- Preferences + +We will follow the new gnome policy about preferences. +I think Havoc Pennington already explained it a lot +better than I could ever do. +http://www106.pair.com/rhp/free-software-ui.html + +- User target + +We target non-technical users by design. +This happens to be 90% of the user population. +(Technical details should not exposed in the interface) +We target web users, we dont directly target web developers. +A few geek-oriented feautures can be kept as +long as they are non-obtrusive. + +REQUIREMENTS + +You will need a complete installation of Gnome 2.2 desktop. +Mozilla API is not stable. I'll be keeping in sync epiphany cvs +head with mozilla cvs head. +The required mozilla version will be specified in the +release notes. + +HOW TO HELP + +You can report new bugs on http://epiphany.mozdev.org/bugs.html. +Feel free to send patches. + +About new feautures I'll just quote Metacity FAQ. + +Q: Will you add my feature? + +A: If it makes sense to turn on unconditionally, + or is genuinely a harmless preference that I would not + be embarrassed to put in a simple, uncluttered, user-friendly + configuration dialog. + + If the only rationale for your feature is that other + [browsers] have it, or that you are personally used to it, or something + like that, then I will not be impressed. [Epiphany] is firmly in the + "choose good defaults" camp rather than the "offer 6 equally broken + ways to do it, and let the user pick one" camp. + + Don't let this discourage patches and fixes - I love those. ;-) + Just be prepared to hear the above objections if your patch + adds some crack-ridden configuration option. + +CONTACTS + +Marco Pesenti Gritti <marco@it.gnome.org> @@ -0,0 +1,17 @@ +To do: + +- favicons doesnt work anymore +- ephy-dnd.c we still need it ? +- implement phoenix like popup blocking +- urls like www.gnome.org and gnome.org should use same folder in history +- history scoring for autocompletion + +Done: + +* simpler crash recover +* open url on middle click +* tree views are borked, maybe the new api doesnt return a list of rows +* dont autocomplete on www. +* simplify/clean autocompletion entry code +* favicons should not be fetched on load end +* open bookmarks, close galeon -> crash diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 000000000..ee45fadb9 --- /dev/null +++ b/acconfig.h @@ -0,0 +1,6 @@ +#undef ENABLE_NLS +#undef HAVE_CATGETS +#undef HAVE_GETTEXT +#undef GETTEXT_PACKAGE +#undef HAVE_LC_MESSAGES +#undef NAUTILUS_PREFIX diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 000000000..4eeaa4ed9 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +PKG_NAME="epiphany" + +(test -f $srcdir/configure.in) || { + echo -n "**Error**: Directory "\`$srcdir\'" does not look like the" + echo " top-level $PKG_NAME directory" + exit 1 +} + +which gnome-autogen.sh || { + echo "You need to install gnome-common from the GNOME CVS" + exit 1 +} +USE_GNOME2_MACROS=1 . gnome-autogen.sh diff --git a/configure.in b/configure.in new file mode 100644 index 000000000..34bfb362b --- /dev/null +++ b/configure.in @@ -0,0 +1,171 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_INIT(configure.in) +AC_PREREQ(2.50) + +GCONF_REQUIRED=1.0.4 +GDK_PIXBUF_REQUIRED=0.13.0 +GLIB_REQUIRED=1.2.9 +LIBGLADE_REQUIRED=0.13 +GNOME_LIBS_REQUIRED=1.2.11 +GNOME_REQUIRED=1.2.8 +GNOME_VFS_REQUIRED=1.0.1 +GTK_REQUIRED=1.2.9 +LIBXML_REQUIRED=1.8.14 +OAF_REQUIRED=0.6.5 +ORBIT_REQUIRED=0.5.7 +MOZILLA_REQUIRED=1.1 +SCROLLKEEPER_REQUIRED=0.1.4 + +AC_SUBST(SCROLLKEEPER_REQUIRED) +AC_SUBST(GNOME_VFS_REQUIRED) +AC_SUBST(LIBXML_REQUIRED) +AC_SUBST(ORBIT_REQUIRED) +AC_SUBST(LIBGLADE_REQUIRED) +AC_SUBST(GNOME_LIBS_REQUIRED) +AC_SUBST(MOZILLA_REQUIRED) + +AC_ENABLE_SHARED(yes) +AC_ENABLE_STATIC(no) + +AM_INIT_AUTOMAKE(epiphany, 0.4.1) +AM_CONFIG_HEADER(config.h) + +AM_PROG_LIBTOOL + +AC_ISC_POSIX +AC_PROG_CC +AC_PROG_CXX +AM_PROG_CC_STDC +AC_HEADER_STDC +AC_PROG_INTLTOOL +AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal) + +GNOME_COMPILE_WARNINGS(error) + +dnl ****************************** +dnl Nautilus View checking +dnl ****************************** + +build_nautilus_view=no +AC_ARG_ENABLE(nautilus-view, [ --enable-nautilus-view (auto,yes,no) + Enable Nautilus View Galeon Component]) + +AC_MSG_CHECKING(if NautilusView Galeon component is wanted) +if test "x$enable_nautilus_view" = "x" ; then + enable_nautilus_view=auto +fi +if test "x$enable_nautilus_view" = "xauto"; then + temptest=`pkg-config --cflags libnautilus 2> /dev/null` + if test "x$temptest" = "x" ; then + enable_nautilus_view=no + else + enable_nautilus_view=yes + fi +fi +if test "x$enable_nautilus_view" = "xyes"; then + dnl AC_DEFINE(ENABLE_NAUTILUS_VIEW) + nautilusview_pkgs=libnautilus +fi +AC_MSG_RESULT($enable_nautilus_view) +AM_CONDITIONAL(ENABLE_NAUTILUS_VIEW, test "x$enable_nautilus_view" = "xyes") + +dnl See if nautilus is installed in other prefix than epiphany so that we can load +dnl nautilus throbbers even then. +dnl Maybe FIXME: make this check not require libnautilus.pc +dnl +nautilus_prefix=`pkg-config --variable=prefix libnautilus 2> /dev/null` +if test "x${nautilus_prefix}" != "x"; then + if test "x${prefix}" = "xNONE"; then + epiphany_prefix="${ac_default_prefix}" + else + epiphany_prefix="${prefix}" + fi + + dnl We already search for nautilus throbbers in epiphany prefix, don't add the + dnl same directory or we'd show the throbbers twice. + if test "x${nautilus_prefix}" != "x${epiphany_prefix}"; then + AC_DEFINE_UNQUOTED(NAUTILUS_PREFIX, "${nautilus_prefix}") + fi +fi + +PKG_CHECK_MODULES(EPIPHANY_DEPENDENCY, gtk+-2.0 libxml-2.0 libgnomeui-2.0 libglade-2.0 bonobo-activation-2.0 ORBit-2.0 libglade-2.0 gnome-vfs-2.0 gnome-vfs-module-2.0 gconf-2.0 $nautilusview_pkgs) +AC_SUBST(EPIPHANY_DEPENDENCY_CFLAGS) +AC_SUBST(EPIPHANY_DEPENDENCY_LIBS) + +ORBIT_IDL="`$PKG_CONFIG --variable=orbit_idl ORBit-2.0`" +AC_SUBST(ORBIT_IDL) + +LIBBONOBO_IDL="`$PKG_CONFIG --variable=idldir libbonobo-2.0`" +AC_SUBST(LIBBONOBO_IDL) + +BONOBO_ACTIVATION_IDL="`$PKG_CONFIG --variable=idldir bonobo-activation-2.0`" +AC_SUBST(BONOBO_ACTIVATION_IDL) + +PKG_CHECK_MODULES(MOZILLA_COMPONENT, mozilla-gtkmozembed) +dnl AC_DEFINE(ENABLE_MOZILLA_EMBED) +AC_SUBST(MOZILLA_COMPONENT_CFLAGS) +AC_SUBST(MOZILLA_COMPONENT_LIBS) + +MOZILLA_INCLUDE_ROOT="`$PKG_CONFIG --variable=includedir mozilla-gtkmozembed`" +AC_SUBST(MOZILLA_INCLUDE_ROOT) + +MOZILLA_HOME="`$PKG_CONFIG --variable=libdir mozilla-gtkmozembed`" +AC_SUBST(MOZILLA_HOME) + +dnl whether to build with DEBUG defined +AC_ARG_WITH(mozilla-debug, + [ --with-mozilla-debug Use a debug mozilla build], + CXXFLAGS="-DDEBUG $CXXFLAGS",) + +AC_ARG_ENABLE(cpp-rtti, + [ --enable-cpp-rtti Enable C++ RTTI (for cvs gcc)],, + enable_cpp_rtti=no) + +if test "x$enable_cpp_rtti" = "xno"; then + CXXFLAGS="-fno-rtti $CXXFLAGS" +fi + +dnl Specify the gconf configuration source, +dnl default to xml::$(sysconfdir)/gconf/gconf.xml.defaults + +AC_PATH_PROG(GCONFTOOL, gconftool-2, no) + +if test x"$GCONFTOOL" = xno; then + AC_MSG_ERROR([gconftool-2 executable not found in your path - should be installed with GConf]) +fi + +AM_GCONF_SOURCE_2 + +dnl ******************************* +dnl Internationalization +dnl ******************************* +dnl Add the languages which your application supports here. + +ALL_LINGUAS="" +GETTEXT_PACKAGE=epiphany-2.0 +AC_SUBST(GETTEXT_PACKAGE) +AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE") +AM_GLIB_GNU_GETTEXT + +dnl uninstalled share dir to search data +AC_DEFINE_UNQUOTED(SHARE_UNINSTALLED_DIR,"`pwd`/data",[path to source data dir]) + +AC_OUTPUT([ +Makefile +data/Makefile +data/glade/Makefile +data/art/Makefile +data/ui/Makefile +data/GNOME_Epiphany_NautilusView.server +data/epiphany.schemas +data/GNOME_Epiphany_Automation.server +lib/Makefile +lib/widgets/Makefile +lib/toolbar/Makefile +embed/Makefile +embed/mozilla/Makefile +src/Makefile +src/bookmarks/Makefile +po/Makefile.in +]) diff --git a/data/.cvsignore b/data/.cvsignore new file mode 100644 index 000000000..1f6558686 --- /dev/null +++ b/data/.cvsignore @@ -0,0 +1,5 @@ +GNOME_Epiphany_Automation.server +GNOME_Epiphany_NautilusView.server +Makefile +Makefile.in +epiphany.schemas diff --git a/data/GNOME_Epiphany_Automation.server.in b/data/GNOME_Epiphany_Automation.server.in new file mode 100644 index 000000000..05b831039 --- /dev/null +++ b/data/GNOME_Epiphany_Automation.server.in @@ -0,0 +1,20 @@ +<oaf_info> + +<oaf_server iid="OAFIID:GNOME_Epiphany_Automation_Factory" type="exe" location="epiphany"> + <oaf_attribute name="repo_ids" type="stringv"> + <item value="IDL:GNOME/ObjectFactory:1.0"/> + </oaf_attribute> + <oaf_attribute name="name" type="string" value="Epiphany automation"/> + <oaf_attribute name="description" type="string" value="Epiphany automation factory"/> +</oaf_server> + +<oaf_server iid="OAFIID:GNOME_Epiphany_Automation" type="factory" location="OAFIID:GNOME_Epiphany_Automation_Factory"> + <oaf_attribute name="repo_ids" type="stringv"> + <item value="IDL:Bonobo/Unknown:1.0"/> + <item value="IDL:GNOME/EpiphanyAutomation:1.0"/> + </oaf_attribute> + <oaf_attribute name="name" type="string" _value="Epiphany automation"/> + <oaf_attribute name="description" type="string" value="Epiphany automation"/> +</oaf_server> + +</oaf_info> diff --git a/data/GNOME_Epiphany_NautilusView.server.in b/data/GNOME_Epiphany_NautilusView.server.in new file mode 100644 index 000000000..8af14019b --- /dev/null +++ b/data/GNOME_Epiphany_NautilusView.server.in @@ -0,0 +1,30 @@ +<oaf_info> + +<oaf_server iid="OAFIID:GNOME_Epiphany_NautilusViewFactory" type="exe" location="epiphany --nautilus-view"> + <oaf_attribute name="repo_ids" type="stringv"> + <item value="IDL:GNOME/ObjectFactory:1.0"/> + </oaf_attribute> + <oaf_attribute name="name" type="string" _value="Epiphany Nautilus view factory"/> + <oaf_attribute name="description" type="string" _value="Epiphany content view component's factory"/> +</oaf_server> + +<oaf_server iid="OAFIID:GNOME_Epiphany_NautilusView" type="factory" location="OAFIID:GNOME_Epiphany_NautilusViewFactory"> + <oaf_attribute name="repo_ids" type="stringv"> + <item value="IDL:Bonobo/Unknown:1.0"/> + <item value="IDL:Bonobo/Control:1.0"/> + <item value="IDL:Nautilus/View:1.0"/> + </oaf_attribute> + <oaf_attribute name="name" type="string" _value="Epiphany Nautilus view"/> + <oaf_attribute name="description" type="string" _value="Epiphany content view component"/> + <oaf_attribute name="bonobo:supported_mime_types" type="stringv"> + <item value="text/html"/> + <item value="text/xml"/> + <item value="x-directory/webdav"/> + <item value="x-directory/webdav-prefer-directory"/> + </oaf_attribute> + <oaf_attribute name="nautilus:view_as_name" type="string" _value="Web Page (Epiphany)"/> + <oaf_attribute name="nautilus:view_as_label" type="string" _value="View as Web Page (Epiphany)"/> + <oaf_attribute name="nautilus:viewer_label" type="string" _value="Web Page Viewer (Epiphany)"/> +</oaf_server> + +</oaf_info> diff --git a/data/Makefile.am b/data/Makefile.am new file mode 100644 index 000000000..60b11c546 --- /dev/null +++ b/data/Makefile.am @@ -0,0 +1,29 @@ +SUBDIRS = ui art glade + +@INTLTOOL_SERVER_RULE@ +@INTLTOOL_DESKTOP_RULE@ + +server_in_files = GNOME_Epiphany_Automation.server.in GNOME_Epiphany_NautilusView.server.in +server_DATA = GNOME_Epiphany_Automation.server GNOME_Epiphany_NautilusView.server +serverdir = $(libdir)/bonobo/servers + +schemadir = $(sysconfdir)/gconf/schemas +schema_DATA = epiphany.schemas + +startheredir = $(pkgdatadir) +starthere_DATA = start_here.html + +EXTRA_DIST = $(glade_DATA) + +install-data-local: + if test -z "$(DESTDIR)" ; then \ + for p in $(schema_DATA) ; do \ + GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(top_builddir)/data/$$p; \ + done \ + fi + +CLEANFILES = GNOME_Epiphany_Automation.server + +EXTRA_DIST = $(server_in_files) \ + $(schema_DATA) \ + $(starthere_DATA) diff --git a/data/art/.cvsignore b/data/art/.cvsignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/data/art/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/data/art/Makefile.am b/data/art/Makefile.am new file mode 100644 index 000000000..f4f5c3b5f --- /dev/null +++ b/data/art/Makefile.am @@ -0,0 +1,7 @@ +art_DATA = \ + epiphany-secure.png \ + epiphany-unsecure.png + +artdir = $(pkgdatadir)/art + +EXTRA_DIST = $(art_DATA) diff --git a/data/art/epiphany-secure.png b/data/art/epiphany-secure.png Binary files differnew file mode 100644 index 000000000..cbfc2d2b1 --- /dev/null +++ b/data/art/epiphany-secure.png diff --git a/data/art/epiphany-unsecure.png b/data/art/epiphany-unsecure.png Binary files differnew file mode 100644 index 000000000..5ee7106d9 --- /dev/null +++ b/data/art/epiphany-unsecure.png diff --git a/data/epiphany.schemas.in b/data/epiphany.schemas.in new file mode 100644 index 000000000..7450fefc7 --- /dev/null +++ b/data/epiphany.schemas.in @@ -0,0 +1,627 @@ +<gconfschemafile> + <schemalist> + <schema> + <key>/schemas/apps/epiphany/general/start_page</key> + <applyto>/apps/epiphany/general/start_page</applyto> + <owner>epiphany</owner> + <type>string</type> + <default>start-here:</default> + <locale name="C"> + <short>Home page</short> + <long>URL for the user's home page. Displayed on start up + and when a new window or tab is created </long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/general/newpage_type</key> + <applyto>/apps/epiphany/general/newpage_type</applyto> + <owner>epiphany</owner> + <type>int</type> + <default>0</default> + <locale name="C"> + <short>New page type</short> + <long>Type of page to show when opening a new window or tab. Possible + values are: 0 (home page), 1 (last page), 2 (blank)</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/find/match_case</key> + <applyto>/apps/epiphany/find/match_case</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>0</default> + <locale name="C"> + <short>Match case for find in page</short> + <long>Match case for find in page.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/find/autowrap</key> + <applyto>/apps/epiphany/find/autowrap</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>1</default> + <locale name="C"> + <short>Autowrap for find in page</short> + <long>For find in page, whether to start again at the beginning after + reaching the end of the page</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/filtering/allow_popups</key> + <applyto>/apps/epiphany/filtering/allow_popups</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>true</default> + <locale name="C"> + <short>Allow popups</short> + <long>Allow sites to open new windows using JavaScript (if JavaScript + is enabled).</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/rendering/use_own_colors</key> + <applyto>/apps/epiphany/rendering/use_own_colors</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>false</default> + <locale name="C"> + <short>Use own colors</short> + <long>Use your own colors instead of the colors the page + requests.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/rendering/use_own_fonts</key> + <applyto>/apps/epiphany/rendering/use_own_fonts</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>false</default> + <locale name="C"> + <short>Use own fonts</short> + <long>Use your own fonts instead of the fonts the page + requests.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/rendering/background_color</key> + <applyto>/apps/epiphany/rendering/background_color</applyto> + <owner>epiphany</owner> + <type>string</type> + <default>#FFFFFF</default> + <locale name="C"> + <short>Default page background color</short> + <long>Default page background color in #RRGGBB hex format.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/rendering/text_color</key> + <applyto>/apps/epiphany/rendering/text_color</applyto> + <owner>epiphany</owner> + <type>string</type> + <default>#000000</default> + <locale name="C"> + <short>Default page text color</short> + <long>Default page text color in #RRGGBB hex format.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/rendering/visited_link_color</key> + <applyto>/apps/epiphany/rendering/visited_link_color</applyto> + <owner>epiphany</owner> + <type>string</type> + <default>#FF0000</default> + <locale name="C"> + <short>Default visited link color</short> + <long>Default color for visited links in #RRGGBB hex format.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/rendering/unvisited_link_color</key> + <applyto>/apps/epiphany/rendering/unvisited_link_color</applyto> + <owner>epiphany</owner> + <type>string</type> + <default>#0000FF</default> + <locale name="C"> + <short>Default unvisited link color</short> + <long>Default color for unvisited links in #RRGGBB hex format.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/rendering/underline_links</key> + <applyto>/apps/epiphany/rendering/underline_links</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>true</default> + <locale name="C"> + <short>Underline links</short> + <long>Underline links.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/interface/open_in_tab</key> + <applyto>/apps/epiphany/interface/open_in_tab</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>false</default> + <locale name="C"> + <short>Use tabs</short> + <long>Open in tabs by default.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/interface/popups_in_tab</key> + <applyto>/apps/epiphany/interface/popups_in_tab</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>false</default> + <locale name="C"> + <short>Open popups in tabs</short> + <long>Open popups in tabs instead of new windows.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/interface/jumpto_tab</key> + <applyto>/apps/epiphany/interface/jumpto_tab</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>false</default> + <locale name="C"> + <short>Jump to new tabs</short> + <long>Jump to new tabs.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/interface/show_toolbars_in_fullscreen</key> + <applyto>/apps/epiphany/interface/show_toolbars_in_fullscreen</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>1</default> + <locale name="C"> + <short>Show toolbars in full screen mode</short> + <long>Show toolbars in full screen mode.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/interface/show_statusbar_in_fullscreen</key> + <applyto>/apps/epiphany/interface/show_statusbar_in_fullscreen</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>0</default> + <locale name="C"> + <short>Show statusbar in full screen mode</short> + <long>Show statusbar in full screen mode.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/interface/show_sidebar_in_fullscreen</key> + <applyto>/apps/epiphany/interface/show_sidebar_in_fullscreen</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>0</default> + <locale name="C"> + <short>Show sidebar in full screen mode</short> + <long>Show sidebar in full screen mode.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/interface/show_sidebar</key> + <applyto>/apps/epiphany/interface/show_sidebar</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>0</default> + <locale name="C"> + <short>Show sidebar by default</short> + <long>Show sidebar by default.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/interface/sidebar_size</key> + <applyto>/apps/epiphany/interface/sidebar_size</applyto> + <owner>epiphany</owner> + <type>int</type> + <default>100</default> + <locale name="C"> + <short>Default sidebar size</short> + <long>Default sidebar size.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/interface/sidebar_page</key> + <applyto>/apps/epiphany/interface/sidebar_page</applyto> + <owner>epiphany</owner> + <type>string</type> + <default>history</default> + <locale name="C"> + <short>Default sidebar page</short> + <long>Default sidebar page.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/interface/show_toolbars</key> + <applyto>/apps/epiphany/interface/show_toolbars</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>1</default> + <locale name="C"> + <short>Show toolbars by default</short> + <long>Show toolbars by default.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/interface/show_statusbar</key> + <applyto>/apps/epiphany/interface/show_statusbar</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>1</default> + <locale name="C"> + <short>Show statusbar by default</short> + <long>Show statusbar by default.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/filtering/image_loading_type</key> + <applyto>/apps/epiphany/filtering/image_loading_type</applyto> + <owner>epiphany</owner> + <type>int</type> + <default>0</default> + <locale name="C"> + <short>When to load images</short> + <long>When to load images. Possible values are 0 (always), 1 (from + current server only), 2 (never)</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/filtering/animate_type</key> + <applyto>/apps/epiphany/filtering/animate_type</applyto> + <owner>epiphany</owner> + <type>int</type> + <default>0</default> + <locale name="C"> + <short>Image animation type</short> + <long>Image animation type. Possible values are 0 (continuously), 1 + (once through), 2 (never)</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/rendering/default_charset</key> + <applyto>/apps/epiphany/rendering/default_charset</applyto> + <owner>epiphany</owner> + <type>string</type> + <default>Western (ISO-8859-1)</default> + <locale name="C"> + <short>Default charset</short> + <long>Default charset.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/rendering/default_font</key> + <applyto>/apps/epiphany/rendering/default_font</applyto> + <owner>epiphany</owner> + <type>int</type> + <default>0</default> + <locale name="C"> + <short>Default font type</short> + <long>Default font type. Possible values are 0 (serif), 1 + (sans-serif)</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/interface/spinner_theme</key> + <applyto>/apps/epiphany/interface/spinner_theme</applyto> + <owner>epiphany</owner> + <type>string</type> + <default>gnome</default> + <locale name="C"> + <short>Default spinner theme</short> + <long>Default spinner theme</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/interface/toolbar_setup</key> + <applyto>/apps/epiphany/interface/toolbar_setup</applyto> + <owner>epiphany</owner> + <type>string</type> + <default>back=std_toolitem(item=back);back_history=navigation_history(direction=back);forward=std_toolitem(item=forward);forward_history=navigation_history(direction=forward);stop=std_toolitem(item=stop);reload=std_toolitem(item=reload);home_separator=separator;home=std_toolitem(item=home);favicons_separator=separator;favicon=favicon;location=location;spinner=spinner;</default> + <locale name="C"> + <short>Toolbar setup</short> + <long>The list of controls that will be present in the toolbar. You should edit + this setting with the toolbar editor unless you know what you are doing.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/downloader/keep_open</key> + <applyto>/apps/epiphany/downloader/keep_open</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>true</default> + <locale name="C"> + <short>Keep downloader open after download finished</short> + <long>Keep downloader open after all downloads have finished.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/filtering/java_enabled</key> + <applyto>/apps/epiphany/filtering/java_enabled</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>1</default> + <locale name="C"> + <short>Allow Java</short> + <long>Allow Java.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/filtering/javascript_enabled</key> + <applyto>/apps/epiphany/filtering/javascript_enabled</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>1</default> + <locale name="C"> + <short>Allow JavaScript</short> + <long>Allow JavaScript.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/network/no_proxies_for</key> + <applyto>/apps/epiphany/network/no_proxies_for</applyto> + <owner>epiphany</owner> + <type>string</type> + <default></default> + <locale name="C"> + <short>No proxy for</short> + <long>List of domains for wherefore not to use the proxy, comma + delimited</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/network/disk_cache_size</key> + <applyto>/apps/epiphany/network/disk_cache_size</applyto> + <owner>epiphany</owner> + <type>int</type> + <default>50000</default> + <locale name="C"> + <short>Size of disk cache</short> + <long>Size of disk cache, in KB.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/network/mem_cache_size</key> + <applyto>/apps/epiphany/network/mem_cache_size</applyto> + <owner>epiphany</owner> + <type>int</type> + <default>4096</default> + <locale name="C"> + <short>Size of memory cache</short> + <long>Size of memory cache, in KB.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/network/cache_compare</key> + <applyto>/apps/epiphany/network/cache_compare</applyto> + <owner>epiphany</owner> + <type>int</type> + <default>3</default> + <locale name="C"> + <short>When to compare cached copy</short> + <long>When to compare cached copy to web copy. Possible values are 0 + (once per session), 1 (every time), 2 (never), 3 (automatic).</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/rendering/lang</key> + <applyto>/apps/epiphany/rendering/lang</applyto> + <owner>epiphany</owner> + <type>list</type> + <list_type>string</list_type> + <default>[en]</default> + <locale name="C"> + <short>Languages</short> + <long>Preferred languages, two letter codes.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/filterin/passwords_save</key> + <applyto>/apps/epiphany/filtering/passwords_save</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>true</default> + <locale name="C"> + <short>Save passwords</short> + <long>Save passwords.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/history/expire</key> + <applyto>/apps/epiphany/history/expire</applyto> + <owner>epiphany</owner> + <type>int</type> + <default>30</default> + <locale name="C"> + <short>Expire history</short> + <long>Expire history after how many days.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/history/search_time</key> + <applyto>/apps/epiphany/history/search_time</applyto> + <owner>epiphany</owner> + <type>int</type> + <default>1</default> + <locale name="C"> + <short>History search time</short> + <long>Show only history entries from a particular time. Possible + values are 0 (all items), 1 (today), 2 (yesterday), 3 (two days ago), 4 + (this week), 5 (this month).</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/print/top_margin</key> + <applyto>/apps/epiphany/print/top_margin</applyto> + <owner>epiphany</owner> + <type>float</type> + <default>0.5</default> + <locale name="C"> + <short>Printing top margin</short> + <long>Printing top margin (in inches).</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/print/bottom_margin</key> + <applyto>/apps/epiphany/print/bottom_margin</applyto> + <owner>epiphany</owner> + <type>float</type> + <default>0.5</default> + <locale name="C"> + <short>Printing bottom margin</short> + <long>Printing bottom margin (in inches).</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/print/left_margin</key> + <applyto>/apps/epiphany/print/left_margin</applyto> + <owner>epiphany</owner> + <type>float</type> + <default>0.5</default> + <locale name="C"> + <short>Printing left margin</short> + <long>Printing left margin (in inches).</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/print/right_margin</key> + <applyto>/apps/epiphany/print/right_margin</applyto> + <owner>epiphany</owner> + <type>float</type> + <default>0.5</default> + <locale name="C"> + <short>Printing right margin</short> + <long>Printing right margin (in inches).</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/print/page_title_toggle</key> + <applyto>/apps/epiphany/print/page_title_toggle</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>true</default> + <locale name="C"> + <short>Whether to print the page title in the header.</short> + <long>Whether to print the page title in the header.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/print/page_url_toggle</key> + <applyto>/apps/epiphany/print/page_url_toggle</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>true</default> + <locale name="C"> + <short>Whether to print the page URL in the header</short> + <long>Whether to print the page URL in the header</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/print/date_toggle</key> + <applyto>/apps/epiphany/print/date_toggle</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>true</default> + <locale name="C"> + <short>Whether to print the date in the footer.</short> + <long>Whether to print the date in the footer.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/print/page_numbers_toggle</key> + <applyto>/apps/epiphany/print/page_numbers_toggle</applyto> + <owner>epiphany</owner> + <type>bool</type> + <default>true</default> + <locale name="C"> + <short>Whether to print the page numbers (x of total) in the footer.</short> + <long>Whether to print the page numbers (x of total) in the footer.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/print/printer</key> + <applyto>/apps/epiphany/print/printer</applyto> + <owner>epiphany</owner> + <type>string</type> + <default>lpr</default> + <locale name="C"> + <short>Printer name</short> + <long>Printer name.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/print/file</key> + <applyto>/apps/epiphany/print/file</applyto> + <owner>epiphany</owner> + <type>string</type> + <locale name="C"> + <short>Filename to print to</short> + <long>Filename to print to.</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/print/printon</key> + <applyto>/apps/epiphany/print/printon</applyto> + <owner>epiphany</owner> + <type>int</type> + <default>0</default> + <locale name="C"> + <short>Print range</short> + <long>Print range: 0 (all pages), 1 (specific range).</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/print/paper</key> + <applyto>/apps/epiphany/print/paper</applyto> + <owner>epiphany</owner> + <type>int</type> + <default>0</default> + <locale name="C"> + <short>Paper type</short> + <long>Paper type: 0 (Letter), 1 (Legal), 2 (Executive), 3 (A4).</long> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/directories/opendir</key> + <applyto>/apps/epiphany/directories/opendir</applyto> + <owner>epiphany</owner> + <type>string</type> + <default>~</default> + <locale name="C"> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/directories/savedir</key> + <applyto>/apps/epiphany/directories/savedir</applyto> + <owner>epiphany</owner> + <type>string</type> + <default>~</default> + <locale name="C"> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/directories/saveimagedir</key> + <applyto>/apps/epiphany/directories/saveimagedir</applyto> + <owner>epiphany</owner> + <type>string</type> + <default>~</default> + <locale name="C"> + </locale> + </schema> + <schema> + <key>/schemas/apps/epiphany/rendering/autodetect_charset</key> + <applyto>/apps/epiphany/rendering/autodetect_charset</applyto> + <owner>epiphany</owner> + <type>int</type> + <default>0</default> + <locale name="C"> + </locale> + </schema> + </schemalist> +</gconfschemafile> + diff --git a/data/glade/.cvsignore b/data/glade/.cvsignore new file mode 100644 index 000000000..06ac86832 --- /dev/null +++ b/data/glade/.cvsignore @@ -0,0 +1,3 @@ +Makefile +Makefile.in +*.gladep diff --git a/data/glade/Makefile.am b/data/glade/Makefile.am new file mode 100644 index 000000000..1013895d5 --- /dev/null +++ b/data/glade/Makefile.am @@ -0,0 +1,10 @@ +glade_DATA = \ + epiphany.glade \ + prompts.glade \ + toolbar-editor.glade \ + prefs-dialog.glade \ + print.glade + +gladedir = $(pkgdatadir)/glade + +EXTRA_DIST = $(glade_DATA) diff --git a/data/glade/epiphany.glade b/data/glade/epiphany.glade new file mode 100644 index 000000000..520d9217e --- /dev/null +++ b/data/glade/epiphany.glade @@ -0,0 +1,1582 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> + +<glade-interface> +<requires lib="gnome"/> + +<widget class="GtkDialog" id="history_dialog"> + <property name="border_width">6</property> + <property name="height_request">400</property> + <property name="title" translatable="yes">History</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="has_separator">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="history_dialog_b"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area2"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="history_clear_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">0</property> + <signal name="clicked" handler="history_clear_button_clicked_cb"/> + + <child> + <widget class="GtkAlignment" id="alignment8"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + + <child> + <widget class="GtkHBox" id="hbox86"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image6"> + <property name="visible">True</property> + <property name="stock">gtk-clear</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1223"> + <property name="visible">True</property> + <property name="label" translatable="yes">C_lear</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkButton" id="history_ok_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-close</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-7</property> + <signal name="clicked" handler="history_ok_button_clicked_cb"/> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox98"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkHBox" id="hbox41"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label224"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Find:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">history_entry</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="history_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="has_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">False</property> + <signal name="changed" handler="history_entry_changed_cb" last_modification_time="Sun, 27 Oct 2002 13:43:51 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label225"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Time:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">1</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">history_time_optionmenu</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkOptionMenu" id="history_time_optionmenu"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="history">0</property> + <signal name="changed" handler="history_time_optionmenu_changed_cb" last_modification_time="Wed, 01 May 2002 11:40:31 GMT"/> + + <child internal-child="menu"> + <widget class="GtkMenu" id="convertwidget1"> + <property name="visible">True</property> + + <child> + <widget class="GtkMenuItem" id="convertwidget2"> + <property name="visible">True</property> + <property name="label" translatable="yes">Ever</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="convertwidget3"> + <property name="visible">True</property> + <property name="label" translatable="yes">Today</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="convertwidget4"> + <property name="visible">True</property> + <property name="label" translatable="yes">Last two days</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="convertwidget5"> + <property name="visible">True</property> + <property name="label" translatable="yes">Last three days</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="convertwidget6"> + <property name="visible">True</property> + <property name="label" translatable="yes">Week</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="convertwidget7"> + <property name="visible">True</property> + <property name="label" translatable="yes">Month</property> + <property name="use_underline">True</property> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow1136"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="history_treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">True</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkDialog" id="find_dialog"> + <property name="border_width">6</property> + <property name="title" translatable="yes">Find text...</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="has_separator">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox4"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area4"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="BClose"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-close</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">0</property> + <signal name="clicked" handler="find_close_button_clicked_cb"/> + </widget> + </child> + + <child> + <widget class="GtkButton" id="back_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">0</property> + <signal name="clicked" handler="find_prev_button_clicked_cb"/> + + <child> + <widget class="GtkAlignment" id="alignment7"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + + <child> + <widget class="GtkHBox" id="hbox85"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image5"> + <property name="visible">True</property> + <property name="stock">gtk-go-back</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1222"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Previous</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkButton" id="forward_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">0</property> + <signal name="clicked" handler="find_next_button_clicked_cb"/> + + <child> + <widget class="GtkAlignment" id="alignment6"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + + <child> + <widget class="GtkHBox" id="hbox84"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image4"> + <property name="visible">True</property> + <property name="stock">gtk-go-forward</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1221"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Next</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox131"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkVBox" id="vbox109"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkHBox" id="hbox72"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label63"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Find text in the document:</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">7.45058e-09</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GnomeEntry" id="find_gnome_entry"> + <property name="visible">True</property> + <property name="history_id">FindEntry</property> + <property name="max_saved">10</property> + + <child internal-child="entry"> + <widget class="GtkEntry" id="find_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="has_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">False</property> + <signal name="activate" handler="find_entry_activate_cb"/> + <signal name="changed" handler="find_entry_changed_cb"/> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="case_check"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Match upper/lower case</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="find_check_toggled_cb" last_modification_time="Wed, 03 Apr 2002 12:46:24 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="wrap_check"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Automatically _wrap around</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="find_check_toggled_cb" last_modification_time="Wed, 03 Apr 2002 12:47:04 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">2</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="download_manager_dialog"> + <property name="border_width">12</property> + <property name="title" translatable="yes">Downloading</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <signal name="delete_event" handler="download_dialog_delete_cb"/> + + <child> + <widget class="GtkVBox" id="vbox106"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">12</property> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox10"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <property name="spacing">8</property> + + <child> + <widget class="GtkButton" id="open_button"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-open</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <signal name="clicked" handler="download_dialog_open_cb" last_modification_time="Tue, 04 Jun 2002 18:01:15 GMT"/> + </widget> + </child> + + <child> + <widget class="GtkButton" id="pause_button"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Pause</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <signal name="clicked" handler="download_dialog_pause_cb" last_modification_time="Sat, 01 Jun 2002 23:54:37 GMT"/> + </widget> + </child> + + <child> + <widget class="GtkButton" id="resume_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Resume</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <signal name="clicked" handler="download_dialog_resume_cb" last_modification_time="Sun, 02 Jun 2002 00:08:23 GMT"/> + </widget> + </child> + + <child> + <widget class="GtkButton" id="abort_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-stop</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <signal name="clicked" handler="download_dialog_abort_cb" last_modification_time="Sat, 01 Jun 2002 23:54:50 GMT"/> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox107"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow1134"> + <property name="height_request">100</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="clist"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">True</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox82"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkCheckButton" id="keep_open_check"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Keep the dialog open</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkToggleButton" id="details_togglebutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <signal name="toggled" handler="download_dialog_details_cb" last_modification_time="Sat, 01 Jun 2002 23:52:31 GMT"/> + + <child> + <widget class="GtkAlignment" id="alignment5"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + + <child> + <widget class="GtkHBox" id="hbox83"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image3"> + <property name="visible">True</property> + <property name="stock">gtk-dialog-info</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1220"> + <property name="visible">True</property> + <property name="label" translatable="yes">Download _details...</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHSeparator" id="details_separator"> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="details_frame"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkTable" id="details_table"> + <property name="visible">True</property> + <property name="n_rows">6</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">6</property> + + <child> + <widget class="GtkLabel" id="label1142"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Location:</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_RIGHT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1143"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>File:</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_RIGHT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1211"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Status:</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1212"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Time Elapsed:</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1213"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Time Remaining:</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="details_elapsed"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="details_remaining"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="details_status"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkProgressBar" id="details_progress"> + <property name="visible">True</property> + <property name="orientation">GTK_PROGRESS_LEFT_TO_RIGHT</property> + <property name="fraction">0</property> + <property name="pulse_step">0.1</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">2</property> + <property name="top_attach">5</property> + <property name="bottom_attach">6</property> + <property name="y_options">fill</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkDialog" id="pdm_dialog"> + <property name="border_width">7</property> + <property name="width_request">400</property> + <property name="height_request">300</property> + <property name="title" translatable="yes">Personal data manager</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="has_separator">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox27"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area27"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="closebutton1"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-close</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-7</property> + <signal name="clicked" handler="pdm_dialog_close_button_clicked_cb" last_modification_time="Mon, 17 Jun 2002 11:00:39 GMT"/> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkNotebook" id="notebook3"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="show_tabs">True</property> + <property name="show_border">True</property> + <property name="tab_pos">GTK_POS_TOP</property> + <property name="scrollable">False</property> + <property name="enable_popup">False</property> + + <child> + <widget class="GtkHBox" id="hbox87"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow1139"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="cookies_treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">True</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVButtonBox" id="vbuttonbox1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_START</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkButton" id="cookies_remove_button"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-remove</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="cookies_properties_button"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-properties</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <signal name="clicked" handler="pdm_dialog_cookies_properties_button_clicked_cb" last_modification_time="Thu, 20 Jun 2002 08:12:23 GMT"/> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="tab_expand">False</property> + <property name="tab_fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1227"> + <property name="visible">True</property> + <property name="label" translatable="yes">Cookies</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="type">tab</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox88"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow1140"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="passwords_treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">True</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVButtonBox" id="vbuttonbox2"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_START</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkButton" id="passwords_remove_button"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-remove</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="tab_expand">False</property> + <property name="tab_fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1228"> + <property name="visible">True</property> + <property name="label" translatable="yes">Passwords</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="type">tab</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkDialog" id="mime_ask_action_dialog"> + <property name="border_width">6</property> + <property name="title" translatable="yes">Choose the file type action</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">False</property> + <property name="destroy_with_parent">False</property> + <property name="has_separator">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox28"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">12</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area28"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="mime_ask_dialog_save"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-save</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">0</property> + <signal name="clicked" handler="mime_ask_dialog_save_clicked_cb" last_modification_time="Sun, 01 Sep 2002 13:39:41 GMT"/> + </widget> + </child> + + <child> + <widget class="GtkButton" id="mime_ask_dialog_cancel"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-6</property> + <signal name="clicked" handler="mime_ask_dialog_cancel_clicked_cb" last_modification_time="Sun, 01 Sep 2002 13:08:43 GMT"/> + </widget> + </child> + + <child> + <widget class="GtkButton" id="mime_ask_dialog_open"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-open</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">0</property> + <signal name="clicked" handler="mime_ask_dialog_open_clicked_cb" last_modification_time="Sun, 01 Sep 2002 13:09:36 GMT"/> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox135"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkHBox" id="hbox95"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkImage" id="image8"> + <property name="visible">True</property> + <property name="stock">gtk-dialog-question</property> + <property name="icon_size">6</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox136"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkLabel" id="label1231"> + <property name="visible">True</property> + <property name="label" translatable="yes"><span weight="bold" size="larger">What do you want to do with this file? +</span> +It's not possible to view this file type directly in the browser:</property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox93"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">12</property> + + <child> + <widget class="GtkLabel" id="label1235"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkImage" id="mime_ask_action_icon"> + <property name="visible">True</property> + <property name="stock">gtk-justify-center</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="mime_ask_action_description"> + <property name="visible">True</property> + <property name="label" translatable="yes">DYNAMIC</property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="mime_ask_dialog_choice_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">You can open it with another application or save it on disk.</property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +</glade-interface> diff --git a/data/glade/prefs-dialog.glade b/data/glade/prefs-dialog.glade new file mode 100644 index 000000000..4042ddbcc --- /dev/null +++ b/data/glade/prefs-dialog.glade @@ -0,0 +1,3083 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> + +<glade-interface> +<requires lib="gnome"/> + +<widget class="GtkWindow" id="general_page_dialog"> + <property name="visible">True</property> + <property name="title" translatable="yes">window1</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + + <child> + <widget class="GtkVBox" id="general_page_box"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">18</property> + + <child> + <widget class="GtkVBox" id="vbox152"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label1238"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Home page</b></property> + <property name="use_underline">True</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">homepage_entry</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox136"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label1239"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox154"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkHBox" id="hbox138"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">12</property> + + <child> + <widget class="GtkLabel" id="label1243"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Location:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">homepage_entry</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="homepage_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox12"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkButton" id="button1"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Set to _Current Page</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <signal name="clicked" handler="prefs_homepage_current_button_clicked_cb"/> + </widget> + </child> + + <child> + <widget class="GtkButton" id="button9"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Set to _Blank Page</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <signal name="clicked" handler="prefs_homepage_blank_button_clicked_cb" last_modification_time="Tue, 14 May 2002 10:37:08 GMT"/> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox153"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label1240"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>On New Page</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox137"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label1241"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox155"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkRadioButton" id="new_page_show_homepage"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Show hom_e page</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="radiobutton32"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Show la_st page</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">new_page_show_homepage</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="radiobutton33"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Show blan_k page</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">new_page_show_homepage</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox156"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label1242"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Language</b></property> + <property name="use_underline">True</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table85"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="n_rows">3</property> + <property name="n_columns">3</property> + <property name="homogeneous">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + + <child> + <widget class="GtkLabel" id="label1205"> + <property name="visible">True</property> + <property name="label" translatable="yes">Autodetec_t encoding:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">1</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">autocharset_optionmenu</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1206"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Default encoding:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">default_charset_optionmenu</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1208"> + <property name="visible">True</property> + <property name="label" translatable="yes">Lan_guage:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">language_optionmenu</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkOptionMenu" id="language_optionmenu"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="history">-1</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkOptionMenu" id="default_charset_optionmenu"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="history">-1</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkOptionMenu" id="autocharset_optionmenu"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="history">0</property> + + <child internal-child="menu"> + <widget class="GtkMenu" id="menu6"> + <property name="visible">True</property> + + <child> + <widget class="GtkMenuItem" id="menuitem39"> + <property name="visible">True</property> + <property name="label" translatable="yes">Off</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem40"> + <property name="visible">True</property> + <property name="label" translatable="yes">Chinese</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem41"> + <property name="visible">True</property> + <property name="label" translatable="yes">East asian</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem42"> + <property name="visible">True</property> + <property name="label" translatable="yes">Japanese</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem43"> + <property name="visible">True</property> + <property name="label" translatable="yes">Korean</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem44"> + <property name="visible">True</property> + <property name="label" translatable="yes">Russian</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem45"> + <property name="visible">True</property> + <property name="label" translatable="yes">Simplified Chinese</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem46"> + <property name="visible">True</property> + <property name="label" translatable="yes">Traditional Chinese</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem47"> + <property name="visible">True</property> + <property name="label" translatable="yes">Ukrainian</property> + <property name="use_underline">True</property> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkImage" id="image3"> + <property name="visible">True</property> + <property name="stock">gtk-select-font</property> + <property name="icon_size">6</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox10"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_DEFAULT_STYLE</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkButton" id="language_more_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_More...</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <signal name="clicked" handler="prefs_language_more_button_clicked_cb" last_modification_time="Tue, 14 May 2002 11:07:13 GMT"/> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="appearance_page_dialog"> + <property name="visible">True</property> + <property name="title" translatable="yes">window2</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + + <child> + <widget class="GtkVBox" id="appearance_page_box"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">18</property> + + <child> + <widget class="GtkVBox" id="vbox157"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label1244"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Fonts</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox139"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label1245"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table70"> + <property name="visible">True</property> + <property name="n_rows">7</property> + <property name="n_columns">4</property> + <property name="homogeneous">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + + <child> + <widget class="GtkLabel" id="label1132"> + <property name="visible">True</property> + <property name="label" translatable="yes">Siz_e:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">fixed_size_spinbutton</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="fixed_size_spinbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">False</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">1 0 100 1 10 10</property> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1131"> + <property name="visible">True</property> + <property name="label" translatable="yes">Si_ze:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">variable_size_spinbutton</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="variable_size_spinbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">False</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">0 0 100 1 10 10</property> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1133"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Proportional:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">proportional_optionmenu</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1134"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Serif:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">combo-entry1</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1135"> + <property name="visible">True</property> + <property name="label" translatable="yes">S_ans serif:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">combo-entry2</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1138"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Monospace:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">combo-entry5</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1121"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Language encoding:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">optionmenu2</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkOptionMenu" id="optionmenu2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="history">0</property> + <signal name="changed" handler="fonts_language_optionmenu_changed_cb" last_modification_time="Fri, 17 May 2002 10:44:00 GMT"/> + + <child internal-child="menu"> + <widget class="GtkMenu" id="menu2"> + <property name="visible">True</property> + + <child> + <widget class="GtkMenuItem" id="menuitem18"> + <property name="visible">True</property> + <property name="label" translatable="yes">Western</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem19"> + <property name="visible">True</property> + <property name="label" translatable="yes">Central European</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem20"> + <property name="visible">True</property> + <property name="label" translatable="yes">Japanese</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem21"> + <property name="visible">True</property> + <property name="label" translatable="yes">Traditional Chinese</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem22"> + <property name="visible">True</property> + <property name="label" translatable="yes">Simplified Chinese</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem23"> + <property name="visible">True</property> + <property name="label" translatable="yes">Korean</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem24"> + <property name="visible">True</property> + <property name="label" translatable="yes">Cyrillic</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem25"> + <property name="visible">True</property> + <property name="label" translatable="yes">Baltic</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem26"> + <property name="visible">True</property> + <property name="label" translatable="yes">Greek</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem27"> + <property name="visible">True</property> + <property name="label" translatable="yes">Turkish</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem28"> + <property name="visible">True</property> + <property name="label" translatable="yes">Unicode</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem29"> + <property name="visible">True</property> + <property name="label" translatable="yes">Thai</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem30"> + <property name="visible">True</property> + <property name="label" translatable="yes">Hebrew</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="menuitem31"> + <property name="visible">True</property> + <property name="label" translatable="yes">Arabic</property> + <property name="use_underline">True</property> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkOptionMenu" id="proportional_optionmenu"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="history">0</property> + + <child> + <widget class="GtkMenu" id="menu3"> + + <child> + <widget class="GtkMenuItem" id="serif1"> + <property name="visible">True</property> + <property name="label" translatable="yes">Serif</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="sans_serif1"> + <property name="visible">True</property> + <property name="label" translatable="yes">Sans Serif</property> + <property name="use_underline">True</property> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox133"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkCheckButton" id="use_fonts_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Always us_e these fonts</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1217"> + <property name="visible">True</property> + <property name="label" translatable="yes">Min_imum font size:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">min_size_spinbutton</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="min_size_spinbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">False</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">0 0 100 1 10 10</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">4</property> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> + <property name="x_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkCombo" id="serif_combo"> + <property name="visible">True</property> + <property name="value_in_list">False</property> + <property name="allow_empty">True</property> + <property name="case_sensitive">False</property> + <property name="enable_arrow_keys">True</property> + <property name="enable_arrows_always">False</property> + + <child internal-child="entry"> + <widget class="GtkEntry" id="combo-entry1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">False</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">False</property> + </widget> + </child> + + <child internal-child="list"> + <widget class="GtkList" id="combo-list1"> + <property name="visible">True</property> + <property name="selection_mode">GTK_SELECTION_BROWSE</property> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCombo" id="sansserif_combo"> + <property name="visible">True</property> + <property name="value_in_list">False</property> + <property name="allow_empty">True</property> + <property name="case_sensitive">False</property> + <property name="enable_arrow_keys">True</property> + <property name="enable_arrows_always">False</property> + + <child internal-child="entry"> + <widget class="GtkEntry" id="combo-entry2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">False</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">False</property> + </widget> + </child> + + <child internal-child="list"> + <widget class="GtkList" id="combo-list2"> + <property name="visible">True</property> + <property name="selection_mode">GTK_SELECTION_BROWSE</property> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCombo" id="monospace_combo"> + <property name="visible">True</property> + <property name="value_in_list">False</property> + <property name="allow_empty">True</property> + <property name="case_sensitive">False</property> + <property name="enable_arrow_keys">True</property> + <property name="enable_arrows_always">False</property> + + <child internal-child="entry"> + <widget class="GtkEntry" id="combo-entry5"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">False</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">False</property> + </widget> + </child> + + <child internal-child="list"> + <widget class="GtkList" id="combo-list5"> + <property name="visible">True</property> + <property name="selection_mode">GTK_SELECTION_BROWSE</property> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1275"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">5</property> + <property name="bottom_attach">6</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox162"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkVBox" id="vbox158"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label1246"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Colors</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox140"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label1247"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox174"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkHBox" id="hbox163"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GnomeColorPicker" id="background_cpick"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="dither">True</property> + <property name="use_alpha">False</property> + <property name="title" translatable="yes">Pick the background color</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1250"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Background</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">1</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox165"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GnomeColorPicker" id="text_cpick"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="dither">True</property> + <property name="use_alpha">False</property> + <property name="title" translatable="yes">Pick the text color</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1251"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Text</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="use_syscolors_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Use s_ystem colors</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="use_colors_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Al_ways use these colors</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox176"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label1280"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Links</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox166"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label1281"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox177"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkHBox" id="hbox167"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GnomeColorPicker" id="unvisited_cpick"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="dither">True</property> + <property name="use_alpha">False</property> + <property name="title" translatable="yes">Pick the unvisited link color</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1249"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Unvisited link</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">1</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox168"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GnomeColorPicker" id="visited_cpick"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="dither">True</property> + <property name="use_alpha">False</property> + <property name="title" translatable="yes">Pick the visited link color</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1248"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Visited link</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="ui_page_dialog"> + <property name="visible">True</property> + <property name="title" translatable="yes">window1</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + + <child> + <widget class="GtkVBox" id="ui_page_box"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">18</property> + + <child> + <widget class="GtkVBox" id="vbox159"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label1252"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Tabs</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox145"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label1253"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox160"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkCheckButton" id="open_in_tabs_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Open in tabs by default</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="jump_to_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Jump to new tabs automatically</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="popups_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Open _popups in tabs</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox161"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label1254"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Spinner</b></property> + <property name="use_underline">True</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox146"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label1255"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow1131"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GnomeIconList" id="spinners_iconlist"> + <property name="height_request">160</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="selection_mode">GTK_SELECTION_SINGLE</property> + <property name="icon_width">78</property> + <property name="row_spacing">4</property> + <property name="column_spacing">2</property> + <property name="text_spacing">2</property> + <property name="text_editable">False</property> + <property name="text_static">False</property> + <signal name="select_icon" handler="spinners_iconlist_select_icon_cb" last_modification_time="Sat, 18 May 2002 10:07:15 GMT"/> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="network_page_dialog"> + <property name="visible">True</property> + <property name="title" translatable="yes">window1</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + + <child> + <widget class="GtkVBox" id="network_page_box"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">18</property> + + <child> + <widget class="GtkVBox" id="vbox162"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label1256"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Caches</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox147"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label1257"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox178"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">12</property> + + <child> + <widget class="GtkVBox" id="vbox179"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label1282"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Compare page:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="cache_compare_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Once per _session</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="radiobutton54"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">E_very time</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">cache_compare_radiobutton</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="radiobutton55"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Never</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">cache_compare_radiobutton</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="radiobutton56"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Automatically</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">cache_compare_radiobutton</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table77"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">4</property> + <property name="homogeneous">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + + <child> + <widget class="GtkLabel" id="label1167"> + <property name="visible">True</property> + <property name="label" translatable="yes">kB</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1168"> + <property name="visible">True</property> + <property name="label" translatable="yes">kB</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1170"> + <property name="visible">True</property> + <property name="label" translatable="yes">Dis_k cache:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">disk_cache_spin</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1171"> + <property name="visible">True</property> + <property name="label" translatable="yes">Memor_y cache:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">memory_cache_spin</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="memory_cache_spin"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">False</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">1 0 1e+06 1000 10 10</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="disk_cache_spin"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">False</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">1 0 1e+06 1000 10 10</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="button6"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Clear _Memory Cache</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <signal name="clicked" handler="prefs_clear_memory_cache_button_clicked_cb"/> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="button5"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Clear _Disk Cache</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <signal name="clicked" handler="prefs_clear_disk_cache_button_clicked_cb"/> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="filtering_page_dialog"> + <property name="visible">True</property> + <property name="title" translatable="yes">window2</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + + <child> + <widget class="GtkVBox" id="filtering_page_box"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">18</property> + + <child> + <widget class="GtkVBox" id="vbox165"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label1261"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Cookies</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox150"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label1264"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox168"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkRadioButton" id="cookies_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Always accept</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="radiobutton51"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Accept _from current server only</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">cookies_radiobutton</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="radiobutton52"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Never accept</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">cookies_radiobutton</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="warn_cookie_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Warn before accepting a cookie</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="session_cookie_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Coo_kies expire at the end of the session</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox164"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label1260"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Images</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox149"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label1263"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox167"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkRadioButton" id="images_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Always load</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="radiobutton48"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Load from current server only</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">images_radiobutton</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="radiobutton49"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Never load</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">images_radiobutton</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox166"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label1262"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Others</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox151"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label1265"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table90"> + <property name="visible">True</property> + <property name="n_rows">3</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">6</property> + + <child> + <widget class="GtkCheckButton" id="allow_java_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Allow _Java (requires plugin)</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="allow_js_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Allow Java_Script</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="allow_popups_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Allow _popups</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="allow_statusbar_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Allow statusbar _messages</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="remember_passwords_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Remember passwords</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkDialog" id="languages_dialog"> + <property name="border_width">6</property> + <property name="height_request">300</property> + <property name="title" translatable="yes">Languages editor</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="has_separator">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="add_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-add</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">0</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="remove_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-remove</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">0</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="button12"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-close</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-7</property> + <signal name="clicked" handler="language_editor_close_button_cb" last_modification_time="Thu, 16 May 2002 18:58:11 GMT"/> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox146"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkHBox" id="hbox132"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label1216"> + <property name="visible">True</property> + <property name="label" translatable="yes">Language</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkOptionMenu" id="languages_optionmenu"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="history">-1</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow1130"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="languages_treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">True</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +</glade-interface> diff --git a/data/glade/print.glade b/data/glade/print.glade new file mode 100644 index 000000000..66a55bef0 --- /dev/null +++ b/data/glade/print.glade @@ -0,0 +1,1573 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> + +<glade-interface> +<requires lib="gnome"/> + +<widget class="GtkDialog" id="print_dialog"> + <property name="border_width">7</property> + <property name="visible">True</property> + <property name="title" translatable="yes">Print</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="has_separator">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox8"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area8"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="preview_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-print-preview</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">50</property> + <signal name="clicked" handler="print_preview_button_cb"/> + </widget> + </child> + + <child> + <widget class="GtkButton" id="cancel_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-6</property> + <signal name="clicked" handler="print_cancel_button_cb"/> + </widget> + </child> + + <child> + <widget class="GtkButton" id="print_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-print</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-5</property> + <signal name="clicked" handler="print_ok_button_cb"/> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkNotebook" id="print_notebook"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="show_tabs">True</property> + <property name="show_border">True</property> + <property name="tab_pos">GTK_POS_TOP</property> + <property name="scrollable">False</property> + <property name="tab_hborder">2</property> + <property name="tab_vborder">2</property> + <property name="enable_popup">False</property> + + <child> + <widget class="GtkVBox" id="vbox127"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">18</property> + + <child> + <widget class="GtkVBox" id="vbox128"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label251"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Printer</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox70"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label252"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table47"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + + <child> + <widget class="GtkRadioButton" id="printer_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Printer</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="file_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_File</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">printer_radiobutton</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="printer_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes">lpr</property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GnomeFileEntry" id="fileentry1"> + <property name="visible">True</property> + <property name="max_saved">10</property> + <property name="browse_dialog_title" translatable="yes">Choose a file to print to</property> + <property name="directory_entry">False</property> + <property name="modal">False</property> + + <child internal-child="entry"> + <widget class="GtkEntry" id="file_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">False</property> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox129"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label253"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Pages range</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox71"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label254"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table49"> + <property name="visible">True</property> + <property name="n_rows">3</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">6</property> + + <child> + <widget class="GtkRadioButton" id="all_pages_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_All pages</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="pages_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Pa_ges</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">all_pages_radiobutton</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox49"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkLabel" id="label241"> + <property name="visible">True</property> + <property name="label" translatable="yes">from:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="from_spinbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">False</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">1 0 100 1 10 10</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label242"> + <property name="visible">True</property> + <property name="label" translatable="yes">to:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="to_spinbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">False</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">1 0 100 1 10 10</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="radiobutton1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Selection</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">all_pages_radiobutton</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="tab_expand">False</property> + <property name="tab_fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label249"> + <property name="visible">True</property> + <property name="label" translatable="yes">General</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="type">tab</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox131"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">18</property> + + <child> + <widget class="GtkVBox" id="vbox132"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label257"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Size</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox73"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label259"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox84"> + <property name="visible">True</property> + <property name="homogeneous">True</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkRadioButton" id="letter_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Letter (8.5" x 11")</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="legal_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">L_egal (8.5" x 14")</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">letter_radiobutton</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="executive_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">E_xecutive (7.25" x 10.5")</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">letter_radiobutton</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="A4_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">A_4 (8.27" x 11.69")</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">True</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">letter_radiobutton</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="stock">gtk-dnd</property> + <property name="icon_size">6</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox133"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label258"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Orientation</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox74"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label260"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox135"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="orient_p_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">P_ortrait</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="orient_l_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Lan_dscape</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">orient_p_radiobutton</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="tab_expand">False</property> + <property name="tab_fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label250"> + <property name="visible">True</property> + <property name="label" translatable="yes">Paper Details</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="type">tab</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox144"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">18</property> + + <child> + <widget class="GtkHBox" id="hbox84"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">18</property> + + <child> + <widget class="GtkVBox" id="vbox137"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label261"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Margins (inches)</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox78"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label271"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table48"> + <property name="visible">True</property> + <property name="n_rows">4</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">6</property> + + <child> + <widget class="GtkLabel" id="label238"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Bottom</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">bottom_spinbutton</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label239"> + <property name="visible">True</property> + <property name="label" translatable="yes">Le_ft</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">left_spinbutton</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label240"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Right</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">right_spinbutton</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label237"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Top</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">top_spinbutton</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="bottom_spinbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">0.1</property> + <property name="digits">1</property> + <property name="numeric">True</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">0.6 0 100 0.1 10 10</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="left_spinbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">0.1</property> + <property name="digits">1</property> + <property name="numeric">True</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">0.5 0 100 0.1 10 10</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="top_spinbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">0.1</property> + <property name="digits">1</property> + <property name="numeric">True</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">0.3 0 100 0.1 10 10</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="right_spinbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">0.1</property> + <property name="digits">1</property> + <property name="numeric">True</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">0.5 0 100 0.1 10 10</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox141"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label272"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Colors</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox80"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label273"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox142"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkRadioButton" id="print_color_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Color</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="print_grayscale_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">G_rayscale</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">print_color_radiobutton</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkImage" id="image2"> + <property name="visible">True</property> + <property name="stock">gtk-select-color</property> + <property name="icon_size">6</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox85"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkVBox" id="vbox140"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label269"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Footers</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox77"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label270"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox125"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkCheckButton" id="print_page_numbers_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Page nu_mbers</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="print_date_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Date</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox138"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label267"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Headers</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox76"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label268"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox124"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkCheckButton" id="print_page_title_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">P_age Title</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="print_page_url_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Page _URL</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="tab_expand">False</property> + <property name="tab_fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label276"> + <property name="visible">True</property> + <property name="label" translatable="yes">Appearance</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="type">tab</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +</glade-interface> diff --git a/data/glade/prompts.glade b/data/glade/prompts.glade new file mode 100644 index 000000000..e13a51e70 --- /dev/null +++ b/data/glade/prompts.glade @@ -0,0 +1,722 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> + +<glade-interface> + +<widget class="GtkDialog" id="prompt_user_pass_dialog"> + <property name="border_width">6</property> + <property name="title" translatable="yes"></property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="default_width">350</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="has_separator">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox9"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area9"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="button51"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-6</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="button49"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-ok</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-5</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table60"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="n_rows">4</property> + <property name="n_columns">3</property> + <property name="homogeneous">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + + <child> + <widget class="GtkCheckButton" id="check_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">DYNAMIC</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="password_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">False</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="username_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="has_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1029"> + <property name="visible">True</property> + <property name="label" translatable="yes">Password</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">1</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1028"> + <property name="visible">True</property> + <property name="label" translatable="yes">Username</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">1</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label"> + <property name="visible">True</property> + <property name="label" translatable="yes">DYNAMIC</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_FILL</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + </packing> + </child> + + <child> + <widget class="GtkImage" id="pixmap"> + <property name="visible">True</property> + <property name="stock">gtk-dialog-question</property> + <property name="icon_size">6</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkDialog" id="prompt_dialog"> + <property name="border_width">6</property> + <property name="title" translatable="yes"></property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="default_width">350</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="has_separator">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox11"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area11"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="button57"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-6</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="button55"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-ok</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-5</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table55"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">3</property> + <property name="homogeneous">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + + <child> + <widget class="GtkEntry" id="entry"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="has_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label"> + <property name="visible">True</property> + <property name="label" translatable="yes">DYNAMIC</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">1</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="check_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">DYNAMIC</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options">expand</property> + </packing> + </child> + + <child> + <widget class="GtkImage" id="pixmap"> + <property name="visible">True</property> + <property name="stock">gtk-dialog-question</property> + <property name="icon_size">6</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkDialog" id="prompt_pass_dialog"> + <property name="border_width">6</property> + <property name="title" translatable="yes"></property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="default_width">350</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="has_separator">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox12"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area12"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="button60"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-6</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="button58"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-ok</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-5</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label"> + <property name="visible">True</property> + <property name="label" translatable="yes">DYNAMIC</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_FILL</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table56"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">3</property> + <property name="homogeneous">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + + <child> + <widget class="GtkLabel" id="label1026"> + <property name="visible">True</property> + <property name="label" translatable="yes">Password</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">1</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="check_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">DYNAMIC</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options">expand</property> + </packing> + </child> + + <child> + <widget class="GtkImage" id="pixmap"> + <property name="visible">True</property> + <property name="stock">gtk-dialog-question</property> + <property name="icon_size">6</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="password_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="has_focus">True</property> + <property name="editable">True</property> + <property name="visibility">False</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options">fill</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkDialog" id="select_dialog"> + <property name="border_width">6</property> + <property name="title" translatable="yes"></property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="has_separator">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox16"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area16"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="button70"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-6</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="button71"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-ok</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-5</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table63"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + + <child> + <widget class="GtkLabel" id="label"> + <property name="visible">True</property> + <property name="label" translatable="yes">DYNAMIC</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_FILL</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">7.45058e-09</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkImage" id="pixmap"> + <property name="visible">True</property> + <property name="stock">gtk-dialog-question</property> + <property name="icon_size">6</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options">shrink|fill</property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">True</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +</glade-interface> diff --git a/data/glade/toolbar-editor.glade b/data/glade/toolbar-editor.glade new file mode 100644 index 000000000..b5c4704d3 --- /dev/null +++ b/data/glade/toolbar-editor.glade @@ -0,0 +1,418 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> + +<glade-interface> + +<widget class="GtkDialog" id="toolbar-editor-dialog"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="title" translatable="yes">Toolbar Editor</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="has_separator">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox1"> + <property name="width_request">450</property> + <property name="height_request">350</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="toolbar-editor-revert-button"> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">0</property> + + <child> + <widget class="GtkAlignment" id="alignment1"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + + <child> + <widget class="GtkHBox" id="hbox2"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="stock">gtk-revert-to-saved</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label4"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Reset to defaults</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkButton" id="toolbar-editor-undo-button"> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-undo</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">0</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="toolbar-editor-close-button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-close</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">0</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox1"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkVBox" id="vbox5"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label5"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>_Available Controls</b></property> + <property name="use_underline">True</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow4"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="toolbar-editor-available-view"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">False</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox4"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <placeholder/> + </child> + + <child> + <widget class="GtkTable" id="table1"> + <property name="visible">True</property> + <property name="n_rows">3</property> + <property name="n_columns">3</property> + <property name="homogeneous">False</property> + <property name="row_spacing">0</property> + <property name="column_spacing">0</property> + + <child> + <widget class="GtkButton" id="toolbar-editor-up-button"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NONE</property> + + <child> + <widget class="GtkArrow" id="arrow2"> + <property name="visible">True</property> + <property name="arrow_type">GTK_ARROW_UP</property> + <property name="shadow_type">GTK_SHADOW_OUT</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="toolbar-editor-right-button"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NONE</property> + + <child> + <widget class="GtkArrow" id="arrow1"> + <property name="visible">True</property> + <property name="arrow_type">GTK_ARROW_RIGHT</property> + <property name="shadow_type">GTK_SHADOW_OUT</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="toolbar-editor-down-button"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NONE</property> + + <child> + <widget class="GtkArrow" id="arrow4"> + <property name="visible">True</property> + <property name="arrow_type">GTK_ARROW_DOWN</property> + <property name="shadow_type">GTK_SHADOW_OUT</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="toolbar-editor-left-button"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NONE</property> + + <child> + <widget class="GtkArrow" id="arrow3"> + <property name="visible">True</property> + <property name="arrow_type">GTK_ARROW_LEFT</property> + <property name="shadow_type">GTK_SHADOW_OUT</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <placeholder/> + </child> + </widget> + <packing> + <property name="padding">4</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox6"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label6"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Cu_rrent Controls</b></property> + <property name="use_underline">True</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow5"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="toolbar-editor-current-view"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">False</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +</glade-interface> diff --git a/data/start_here.html b/data/start_here.html new file mode 100644 index 000000000..73a0e908e --- /dev/null +++ b/data/start_here.html @@ -0,0 +1,23 @@ +<html> +<head> +</head> +<body> +<h1>Welcome ...</h1> +<h2>Smart Bookmarks</h2> +<p> +Right click the icon and choose "Add Bookmark" from the menu list. +</p> +<dl> +<li> +<a type="text/smartbookmark" href="http://www.google.com/" rel="http://www.google.com/search?q=%s" title="Search the web - Google"> +Search the web - Google +</a> +</li> +<li> +<a type="text/smartbookmark" href="http://images.google.com/" rel="http://images.google.com/images?q=%s" title="Search images - Google"> +Search images - Google +</a> +</li> +</ol> +</body> +</html> diff --git a/data/ui/.cvsignore b/data/ui/.cvsignore new file mode 100644 index 000000000..765506f45 --- /dev/null +++ b/data/ui/.cvsignore @@ -0,0 +1,4 @@ +Makefile +Makefile.in +epiphany-ui.xml +nautilus-epiphany-view.xml diff --git a/data/ui/Makefile.am b/data/ui/Makefile.am new file mode 100644 index 000000000..658ebf3f1 --- /dev/null +++ b/data/ui/Makefile.am @@ -0,0 +1,11 @@ +uixmldir = $(datadir)/gnome-2.0/ui +uixml_in_files = epiphany-ui.xml.in \ + nautilus-epiphany-view.xml.in + +uixml_DATA = $(uixml_in_files:.xml.in=.xml) + +@INTLTOOL_XML_RULE@ + +EXTRA_DIST = $(uixml_in_files) + +CLEANFILES = $(uixml_DATA) diff --git a/data/ui/epiphany-ui.xml.in b/data/ui/epiphany-ui.xml.in new file mode 100644 index 000000000..cb966a4e4 --- /dev/null +++ b/data/ui/epiphany-ui.xml.in @@ -0,0 +1,454 @@ +<Root> + +<commands> + <cmd name="FileOpen" _label="Open" + _tip="Open a file" pixtype="stock" pixname="gtk-open" accel="*Control*O"/> + + <cmd name="FileSaveAs" _label="Save As" + _tip="Save the current file with a different name" + pixtype="stock" pixname="gtk-save-as" + accel="*Shift**Control*S"/> + + <cmd name="FilePrint" _label="Print" + _tip="Print the current file" pixtype="stock" pixname="gtk-print" + accel="*Control*P"/> + + <cmd name="FileCloseTab" _tip="Close the current tab" + pixtype="stock" pixname="gtk-close"/> + + <cmd name="FileCloseWindow" _tip="Close the current window"/> + + <cmd name="EditCut" _label="Cut" _tip="Cut the selection" + pixtype="stock" pixname="gtk-cut"/> + + <cmd name="EditCopy" _label="Copy" + _tip="Copy the selection" pixtype="stock" pixname="gtk-copy"/> + + <cmd name="EditPaste" _label="Paste" + _tip="Paste the clipboard" pixtype="stock" pixname="gtk-paste"/> + + <cmd name="EditSelectAll" _label="Select All" _tip="Select the entire document" + accel="*Control*A"/> + + <cmd name="EditFind" _label="Find" _tip="Search for a string" + pixtype="stock" pixname="gtk-find" accel="*Control*F"/> + + <cmd name="Zoom In" _label="Zoom In" + _tip="Show the contents in more detail"/> + <cmd name="Zoom Out" _label="Zoom Out" + _tip="Show the contents in less detail"/> + <cmd name="Zoom Normal" _label="Normal Size" + _tip="Show the contents at the normal size"/> + + <cmd name="SettingsPreferences" _label="Preferences" _tip="Configure the application" + pixtype="stock" pixname="gtk-preferences"/> + + <cmd name="SettingsToolbarEditor" _label="Toolbar" _tip="Edit the main toolbar"/> + + <cmd name="HelpContents" _label="Contents" _tip="Open the Epiphany manual" + accel="F1"/> + + <cmd name="About" _label="About..." _tip="About this application" + pixtype="stock" pixname="About"/> + + <cmd name="BookmarksAddDefault" _label="Add bookmark" + _tip="Add a bookmark to the default folder"/> + + <cmd name="BookmarksEdit" _label="Edit bookmarks" + _tip="Open a bookmarks editor"/> + + <cmd name="GoBack" _label="_Back" + sensitive="0"/> + + <cmd name="GoUp" _label="_Up" + sensitive="0"/> + + <cmd name="GoHome" _label="_Home"/> + + <cmd name="GoMyportal" _label="_My portal"/> + + <cmd name="GoForward" _label="_Forward" + sensitive="0"/> + + <cmd name="GoStop" _label="_Stop" + sensitive="0" + _tip="Stop current data transfer"/> + + <cmd name="GoReload" _label="_Reload" + _tip="Display the latest content of the current page"/> + + <cmd name="GoGo" _label="_Go" + _tip="Load the URL in the location entry"/> + + <cmd name="EPOpenInNewWindow" _label="Open in New Window"/> + + <cmd name="EPOpenInNewTab" _label="Open in New Tab"/> + + <cmd name="EPCopyLinkLocation" _label="Copy Link Location"/> + + <cmd name="EPCopyEmail" _label="Copy Email Address"/> + + <cmd name="EPDownloadLink" _label="Download Link"/> + + <cmd name="EPAddBookmark" _label="Add Bookmark"/> + + <cmd name="EPOpenImage" _label="Open Image"/> + + <cmd name="EPOpenImageInNewWindow" _label="Open Image in New Window"/> + + <cmd name="EPOpenImageInNewTab" _label="Open Image in New Tab"/> + + <cmd name="EPSaveImageAs" _label="Save Image As..."/> + + <cmd name="EPSetImageAsBackground" _label="Use Image as Background"/> + + <cmd name="EPCopyImageLocation" _label="Copy Image Location"/> + + <cmd name="DPCopyLocation" _label="Copy Page location"/> + + <cmd name="DPOpenFrame" _label="Open Frame"/> + + <cmd name="DPOpenFrameInNewWindow" _label="Open Frame in New Window"/> + + <cmd name="DPOpenFrameInNewTab" _label="Open Frame in New Tab"/> + + <cmd name="DPReloadFrame" _label="Reload Frame"/> + + <cmd name="DPAddFrameBookmark" _label="Add Bookmark for Frame"/> + + <cmd name="DPSavePageAs" _label="Save Page As..."/> + + <cmd name="DPSaveBackgroundAs" _label="Save Background As..."/> + + <cmd name="DPAddPageBookmark" verb="Add Bookmark"/> + + <cmd name="PPVGotoFirst" _label="First"/> + + <cmd name="PPVGotoLast" _label="Last"/> + + <cmd name="PPVGoBack" _label="Previous"/> + + <cmd name="PPVGoForward" _label="Next"/> + +</commands> + +<keybindings> + <accel name="*Control*S" verb="FileSaveAs"/> +</keybindings> + +<menu> + +<submenu name="File" _label="_File"> + + <menuitem name="FileNewWindow" verb="" + _label="_New Window" + pixtype="stock" pixname="gtk-new" + accel="*Control*n"/> + + <menuitem name="FileNewTab" verb="" _label="New _Tab" accel="*Control*t"/> + + <menuitem name="FileOpen" verb="" _label="_Open..."/> + + <separator/> + + <menuitem name="FileSaveAs" verb="" _label="Save _As..."/> + + <separator/> + + <menuitem name="FilePrint" verb="" _label="_Print..."/> + <menuitem name="FileSendTo" verb="" + pixtype="stock" pixname="epiphany-send-link" + _label="S_end To..."/> + + <separator/> + + <menuitem name="BookmarksAddDefault" verb="" _label="_Add Bookmark" + _tip="Add a bookmark for the current location to the default folder" + pixtype="stock" pixname="gtk-add" accel="*Control*d"/> + + <separator/> + + <menuitem name="FileCloseTab" verb="" _label="_Close Tab" accel="*Control*W"/> + + <menuitem name="FileCloseWindow" verb="" _label="Close _Window" accel="*Shift**Control*W"/> + +</submenu> + +<submenu name="Edit" _label="_Edit"> + + <menuitem name="EditCut" verb="" _label="Cu_t" accel="*Control*X"/> + + <menuitem name="EditCopy" verb="" _label="_Copy" accel="*Control*c"/> + + <menuitem name="EditPaste" verb="" _label="_Paste" accel="*Control*v"/> + + <separator/> + + <menuitem name="EditSelectAll" verb="" _label="Select _All"/> + + <separator/> + + <menuitem name="EditFind" verb="" _label="_Find..."/> + <menuitem name="EditFindNext" verb="" + accel="*Control*G" _label="Find Ne_xt"/> + <menuitem name="EditFindPrev" verb="" + accel="*Shift**Control*G" _label="Find Pre_vious"/> + + <separator/> + + <menuitem name="PDM" verb="ToolsPDM" _label="P_ersonal Data"/> + + <menuitem name="EditToolbar" + _label="T_oolbar" + verb="SettingsToolbarEditor"/> + + <menuitem name="EditPrefs" + _label="P_references" + _tip="Edit Ephy preferences" + pixtype="stock" pixname="gtk-preferences" + verb="EditPrefs"/> +</submenu> + +<submenu name="View" _label="_View"> + + <menuitem name="GoStop" + pixtype="stock" pixname="gtk-stop" + verb="" accel="Escape"/> + + <menuitem name="GoReload" + pixtype="stock" pixname="gtk-refresh" + verb="" accel="*Control*R"/> + + <separator/> + + <menuitem name="View Toolbar" id="View Toolbar" type="toggle" + _label="_Toolbar" verb="" accel="*Shift**Control*T"/> + + <menuitem name="View Statusbar" id="View Statusbar" + type="toggle" _label="St_atusbar" verb=""/> + + <menuitem name="View Fullscreen" id="View Fullscreen" + type="toggle" _label="_Fullscreen" verb="" accel="F11"/> + + <separator/> + + <menuitem name="Zoom In" + _label="Zoom _In" accel="*Control*plus" + pixtype="stock" pixname="zoom-in" + verb="Zoom In"/> + + <menuitem name="Zoom Out" + _label="Zoom _Out" accel="*Control*minus" + pixtype="stock" pixname="zoom-out" + verb="Zoom Out"/> + + <menuitem name="Zoom Normal" + _label="_Normal Size" + pixtype="stock" pixname="zoom-100" + verb="Zoom Normal"/> + + <separator/> + + <placeholder name="EncodingMenuPlaceholder"/> + + <menuitem name="Page Source" + _label="_Page Source" + verb="ViewPageSource"/> + +</submenu> + +<submenu name="Go" _label="_Go"> + <menuitem name="GoBack" + pixtype="stock" pixname="gtk-go-back" + verb="" accel="*Alt*Left"/> + + <menuitem name="GoForward" + pixtype="stock" pixname="gtk-go-forward" + verb="" accel="*Alt*Right"/> + + <menuitem name="GoUp" + pixtype="stock" pixname="gtk-go-up" + verb="" accel="*Alt*Up"/> + + <separator/> + + <menuitem name="GoHome" + pixtype="stock" pixname="gtk-home" + verb="" accel="*Alt*Home"/> + + <menuitem name="GoLocation" _label="_Location..." + verb="" accel="*Ctrl*l"/> + + <separator/> + + <menuitem name="History" verb="ToolsHistory" + _label="_History" accel="*Control*H"/> + + <menuitem name="BookmarksEdit" verb="" _label="_Bookmarks" + accel="*Control*b"/> + + <placeholder name="Favorites" delimit="top"/> +</submenu> + +<submenu name="Tabs" _label="_Tabs"> + <menuitem name="Previous Tab" verb="TabsPrevious" _label="_Previous Tab" + accel="*Control*Page_Up"/> + <menuitem name="Next Tab" verb="TabsNext" _label="_Next Tab" + accel="*Control*Page_Down"/> + <separator/> + <menuitem name="Tab Left" verb="TabsMoveLeft" _label="Move Tab _Left" + accel="*Shift**Control*Page_Up"/> + <menuitem name="Tab Right" verb="TabsMoveRight" _label="Move Tab _Right" + accel="*Shift**Control*Page_Down"/> + <menuitem name="Move Tab to New Window" verb="TabsDetach" _label="_Detach Tab" + accel="*Shift**Control*m"/> +</submenu> + +<submenu name="Help" _label="_Help"> + + <menuitem name="HelpContents" verb="" + pixtype="stock" pixname="gtk-help" + _label="_Contents"/> + + <menuitem name="About" verb="" _label="_About"/> + +</submenu> + +</menu> + +<popups> + + <popup name="EphyEmbedInputPopup"> + <menuitem name="EditCut" + pixtype="stock" pixname="gtk-cut" + verb=""/> + <menuitem name="EditCopy" + pixtype="stock" pixname="gtk-copy" + verb=""/> + <menuitem name="EditPaste" + pixtype="stock" pixname="gtk-paste" + verb=""/> + </popup> + + <popup name="EphyEmbedDocumentPopup"> + <placeholder name="NavigationItems"> + <menuitem name="GoBack" + pixtype="stock" pixname="gtk-go-back" + verb=""/> + + <menuitem name="GoForward" + pixtype="stock" pixname="gtk-go-forward" + verb=""/> + + <menuitem name="GoReload" + pixtype="stock" pixname="gtk-refresh" + verb=""/> + + <separator/> + </placeholder> + + <menuitem name="DPSavePageAs" + pixtype="stock" pixname="gtk-save" + verb=""/> + + <menuitem name="DPSaveBackgroundAs" verb=""/> + + <menuitem name="DPViewSource" _label="Page Source" + verb="ViewPageSource"/> + + <menuitem name="DPAddPageBookmark" + verb=""/> + + <menuitem name="DPCopyLocation" + pixtype="stock" pixname="gtk-copy" + verb=""/> + + <placeholder name="FrameItems"> + <separator/> + <menuitem name="DPOpenFrame" verb=""/> + <menuitem name="DPOpenFrameInNewWindow" verb=""/> + <menuitem name="DPOpenFrameInNewTab" verb=""/> + <menuitem name="DPReloadFrame" verb=""/> + <menuitem name="DPAddFrameBookmark" verb=""/> + </placeholder> + </popup> + + <popup name="EphyEmbedElementPopup"> + <placeholder name="LinkItems"> + <menuitem name="EPOpenInNewWindow" + pixtype="stock" pixname="gtk-open" + verb=""/> + + <menuitem name="EPOpenInNewTab" verb=""/> + + <menuitem name="EPCopyLinkLocation" + pixtype="stock" pixname="gtk-copy" + verb=""/> + + <menuitem name="EPDownloadLink" verb=""/> + + <menuitem name="EPAddBookmark" + pixtype="stock" pixname="gtk-add" + verb=""/> + </placeholder> + <placeholder name="EmailLinkItems"> + <menuitem name="EPCopyEmail" + pixtype="stock" pixname="gtk-copy" + verb=""/> + </placeholder> + <placeholder name="BetweenElements1"> + <separator/> + </placeholder> + + <placeholder name="ImageItems"> + <menuitem name="EPOpenImage" + pixtype="stock" pixname="gtk-open" + verb=""/> + + <menuitem name="EPOpenImageInNewWindow" verb=""/> + <menuitem name="EPOpenImageInNewTab" verb=""/> + + <menuitem name="EPSaveImageAs" + pixtype="stock" pixname="gtk-save" + verb=""/> + + <menuitem name="EPSetImageAsBackground" verb=""/> + + <menuitem name="EPCopyImageLocation" + pixtype="stock" pixname="gtk-copy" + verb=""/> + </placeholder> + </popup> +</popups> + +<dockitem name="Toolbar" behavior="exclusive" config="0"> +</dockitem> + +<dockitem name="PrintPreview" behavior="exclusive"> + <toolitem name="PPVGotoFirst" + pixtype="stock" pixname="gtk-goto-first" + verb="PPVGotoFirst"/> + <toolitem name="PPVGoBack" + pixtype="stock" pixname="gtk-go-back" + verb="PPVGoBack"/> + <toolitem name="PPVGoForward" + pixtype="stock" pixname="gtk-go-forward" + priority="1" + verb="PPVGoForward"/> + <toolitem name="PPVGotoLast" + pixtype="stock" pixname="gtk-goto-last" + verb="PPVGotoLast"/> + <toolitem name="Close" _label="Close" + pixtype="stock" pixname="gtk-close" + priority="1" + verb="PPVClose"/> +</dockitem> + +<status resize_grip="0"> + <item name="main"/> + <control name="SecurityIconWrapper"/> + <control name="ProgressWrapper"/> +</status> + +</Root> + diff --git a/data/ui/nautilus-epiphany-view.xml.in b/data/ui/nautilus-epiphany-view.xml.in new file mode 100644 index 000000000..d46e5f9f4 --- /dev/null +++ b/data/ui/nautilus-epiphany-view.xml.in @@ -0,0 +1,130 @@ +<Root> +<commands> + + <cmd name="FilePrint" _label="Print" + _tip="Print the Current File" pixtype="stock" pixname="gtk-print" + accel="*Control*P"/> + + <cmd name="EditCut" _label="Cut" _tip="Cut the Selection" + pixtype="stock" pixname="gtk-cut"/> + + <cmd name="EditCopy" _label="Copy" + _tip="Copy the Selection" pixtype="stock" pixname="gtk-copy"/> + + <cmd name="EditPaste" _label="Paste" + _tip="Paste the Clipboard" pixtype="stock" pixname="gtk-paste"/> + + <cmd name="EditSelectAll" _label="Select All" _tip="Select the Entire Document" + accel="*Control*A"/> + + <cmd name="EditFind" _label="Find" _tip="Search for a String" + pixtype="stock" pixname="gtk-find" accel="*Control*F"/> + + + <cmd name="EPOpenInNewWindow" _label="Open in New Window" + pixtype="stock" pixname="gtk-new"/> + + <cmd name="EPCopyLinkLocation" _label="Copy Link Location" + pixtype="stock" pixname="gtk-copy"/> + + <cmd name="EPDownloadLink" _label="Download Link"/> + + <cmd name="EPOpenImage" _label="Open Image" + pixtype="stock" pixname="gtk-open"/> + + <cmd name="EPOpenImageInNewWindow" _label="Open Image in New Window"/> + + <cmd name="EPSaveImageAs" _label="Save Image As..." + pixtype="stock" pixname="gtk-save"/> + + <cmd name="EPSetImageAsBackground" _label="Use Image as Background"/> + + <cmd name="EPCopyImageLocation" _label="Copy Image Location" + pixtype="stock" pixname="gtk-copy"/> + + <cmd name="DPCopyLocation" _label="Copy Page Location" + pixtype="stock" pixname="gtk-copy"/> + + <cmd name="DPOpenFrame" _label="Open Frame" + pixtype="stock" pixname="gtk-open"/> + + <cmd name="DPOpenFrameInNewWindow" _label="Open Frame in New Window"/> + + <cmd name="DPAddFrameBookmark" _label="Add Bookmark for Frame" + pixtype="stock" pixname="gtk-add"/> + + <cmd name="DPSavePageAs" _label="Save Page As..." + pixtype="stock" pixname="gtk-save"/> + + <cmd name="DPSaveBackgroundAs" _label="Save Background As..."/> + + <cmd name="PPVGotoFirst" _label="First"/> + + <cmd name="PPVGotoLast" _label="Last"/> + + <cmd name="PPVGoBack" _label="Previous"/> + + <cmd name="PPVGoForward" _label="Next"/> + + <cmd name="EPCopyEmail" _label="Copy Email Address"/> + +</commands> + +<menu> + <submenu name="File" _label="_File"> + <menuitem name="FilePrint" verb="" _label="_Print..."/> + </submenu> + <submenu name="Edit" _label="_Edit"> + <menuitem name="EditFind" verb="" _label="_Find..."/> + </submenu> + <submenu name="View"> + <placeholder name="Encoding"/> + </submenu> +</menu> + +<popups> + + <popup name="EphyEmbedInputPopup"> + <menuitem name="EditCut" verb=""/> + <menuitem name="EditCopy" verb=""/> + <menuitem name="EditPaste" verb=""/> + </popup> + + <popup name="EphyEmbedDocumentPopup"> + <menuitem name="DPSavePageAs" verb=""/> + <menuitem name="DPSaveBackgroundAs" verb=""/> + <menuitem name="DPCopyLocation" verb=""/> + <submenu name="DPOpenWith" _label="Open With"/> + <placeholder name="FrameItems"> + <separator/> + <menuitem name="DPOpenFrame" verb=""/> + <menuitem name="DPOpenFrameInNewWindow" verb=""/> + </placeholder> + </popup> + + <popup name="EphyEmbedElementPopup"> + <placeholder name="LinkItems"> + <menuitem name="EPOpenInNewWindow" verb=""/> + <menuitem name="EPCopyLinkLocation" verb=""/> + <menuitem name="EPDownloadLink" verb=""/> + </placeholder> + <placeholder name="EmailLinkItems"> + <menuitem name="EPCopyEmail" + pixtype="stock" pixname="gtk-copy" + verb=""/> + </placeholder> + <placeholder name="BetweenElements1"> + <separator/> + </placeholder> + <placeholder name="ImageItems"> + <menuitem name="EPOpenImage" verb=""/> + <submenu name="EPOpenImageWith" _label="Open Image with"/> + <menuitem name="EPOpenImageInNewWindow" verb=""/> + <menuitem name="EPSaveImageAs" verb=""/> + <menuitem name="EPSetImageAsBackground" verb=""/> + <menuitem name="EPCopyImageLocation" verb=""/> + </placeholder> + </popup> +</popups> + +</Root> diff --git a/embed/.cvsignore b/embed/.cvsignore new file mode 100644 index 000000000..20e4cb0c8 --- /dev/null +++ b/embed/.cvsignore @@ -0,0 +1,6 @@ +Makefile +Makefile.in +*.lo +.deps +.libs +*.la diff --git a/embed/Makefile.am b/embed/Makefile.am new file mode 100644 index 000000000..a6f43fb46 --- /dev/null +++ b/embed/Makefile.am @@ -0,0 +1,57 @@ +SUBDIRS = mozilla + +INCLUDES = \ + -I$(top_srcdir)/embed/mozilla \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/lib/widgets \ + -I$(MOZILLA_INCLUDE_ROOT)/gtkembedmoz \ + $(WARN_CFLAGS) \ + $(EPIPHANY_DEPENDENCY_CFLAGS) \ + -DSHARE_DIR=\"$(pkgdatadir)\" \ + -DG_DISABLE_DEPRECATED \ + -DGDK_DISABLE_DEPRECATED \ + -DGTK_DISABLE_DEPRECATED \ + -DGDK_PIXBUF_DISABLE_DEPRECATED \ + -DGNOME_DISABLE_DEPRECATED + +noinst_LTLIBRARIES = libephyembed.la + +libephyembed_la_SOURCES = \ + ephy-embed-types.h \ + downloader-view.c \ + downloader-view.h \ + ephy-history.c \ + ephy-history.h \ + ephy-embed.c \ + ephy-embed.h \ + ephy-embed-shell.c \ + ephy-embed-shell.h \ + ephy-embed-persist.c \ + ephy-embed-persist.h \ + ephy-embed-popup.c \ + ephy-embed-popup.h \ + ephy-embed-popup-bw.c \ + ephy-embed-popup-bw.h \ + ephy-embed-popup-control.c \ + ephy-embed-popup-control.h \ + ephy-embed-event.c \ + ephy-embed-event.h \ + ephy-embed-utils.c \ + ephy-embed-utils.h \ + ephy-embed-dialog.c \ + ephy-embed-dialog.h \ + find-dialog.c \ + find-dialog.h \ + print-dialog.c \ + print-dialog.h \ + ephy-embed-prefs.h \ + ephy-favicon-cache.c \ + ephy-favicon-cache.h \ + ephy-embed-favicon.c \ + ephy-embed-favicon.h \ + ephy-favicon.c \ + ephy-favicon.h + + +libephyembed_la_LIBADD = \ + $(top_builddir)/embed/mozilla/libephymozillaembed.la diff --git a/embed/downloader-view.c b/embed/downloader-view.c new file mode 100644 index 000000000..97e05a613 --- /dev/null +++ b/embed/downloader-view.c @@ -0,0 +1,1100 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "downloader-view.h" +#include "eel-gconf-extensions.h" +#include "ephy-gui.h" +#include "ephy-prefs.h" +#include "ephy-ellipsizing-label.h" +#include "ephy-embed-utils.h" +#include "ephy-file-helpers.h" + +#include <gtk/gtktreeview.h> +#include <gtk/gtkliststore.h> +#include <gtk/gtktreeviewcolumn.h> +#include <libgnome/gnome-i18n.h> +#include <libgnomeui/gnome-dialog-util.h> +#include <libgnomeui/gnome-dialog.h> +#include <gtk/gtkprogressbar.h> +#include <libgnomevfs/gnome-vfs-mime-handlers.h> + +enum +{ + DOWNLOAD_REMOVE, + DOWNLOAD_PAUSE, + DOWNLOAD_RESUME, + LAST_SIGNAL +}; + +enum +{ + COL_PERCENT, + COL_FILENAME, + COL_SIZE, + COL_REMAINING, + COL_PERSIST_OBJECT +}; + +struct DownloaderViewPrivate +{ + GHashTable *details_hash; + GtkTreeModel *model; + gboolean show_details; + + /* Widgets */ + GtkWidget *treeview; + GtkWidget *details_file; + GtkWidget *details_location; + GtkWidget *details_status; + GtkWidget *details_elapsed; + GtkWidget *details_remaining; + GtkWidget *details_progress; + GtkWidget *details_button; + GtkWidget *keep_open_check; + GtkWidget *pause_button; + GtkWidget *resume_button; + GtkWidget *abort_button; + GtkWidget *open_button; +}; + +typedef struct +{ + glong elapsed; + glong remaining; + gfloat speed; + gint size_total; + gint size_done; + gfloat progress; + gboolean can_pause; + gchar *filename; + gchar *source; + gchar *dest; + DownloadStatus status; + + GtkTreeRowReference *ref; +} DownloadDetails; + +typedef struct +{ + gboolean can_resume; + gboolean can_pause; + gboolean can_abort; + gboolean can_open; + DownloaderViewPrivate *priv; +} ControlsInfo; + +enum +{ + PROP_TREEVIEW, + PROP_KEEP_OPEN, + PROP_DETAILS_FRAME, + PROP_DETAILS_SEPARATOR, + PROP_DETAILS_TABLE, + PROP_DETAILS_STATUS, + PROP_DETAILS_ELAPSED, + PROP_DETAILS_REMAINING, + PROP_DETAILS_PROGRESS, + PROP_PAUSE_BUTTON, + PROP_RESUME_BUTTON, + PROP_ABORT_BUTTON, + PROP_OPEN_BUTTON, + PROP_DETAILS_BUTTON +}; + +static const +EphyDialogProperty properties [] = +{ + { PROP_TREEVIEW, "clist", NULL, PT_NORMAL, NULL }, + { PROP_KEEP_OPEN, "keep_open_check", CONF_DOWNLOADING_KEEP_OPEN, PT_NORMAL, NULL }, + { PROP_DETAILS_FRAME, "details_frame", NULL, PT_NORMAL, NULL }, + { PROP_DETAILS_SEPARATOR, "details_separator", NULL, PT_NORMAL, NULL }, + { PROP_DETAILS_TABLE, "details_table", NULL, PT_NORMAL, NULL }, + { PROP_DETAILS_STATUS, "details_status", NULL, PT_NORMAL, NULL }, + { PROP_DETAILS_ELAPSED, "details_elapsed", NULL, PT_NORMAL, NULL }, + { PROP_DETAILS_REMAINING, "details_remaining", NULL, PT_NORMAL, NULL }, + { PROP_DETAILS_PROGRESS, "details_progress", NULL, PT_NORMAL, NULL }, + { PROP_PAUSE_BUTTON, "pause_button", NULL, PT_NORMAL, NULL }, + { PROP_RESUME_BUTTON, "resume_button", NULL, PT_NORMAL, NULL }, + { PROP_ABORT_BUTTON, "abort_button", NULL, PT_NORMAL, NULL }, + { PROP_OPEN_BUTTON, "open_button", NULL, PT_NORMAL, NULL }, + { PROP_DETAILS_BUTTON, "details_togglebutton", CONF_DOWNLOADING_SHOW_DETAILS, PT_NORMAL, NULL }, + + { -1, NULL, NULL } +}; + +static void +downloader_view_build_ui (DownloaderView *dv); +static void +downloader_view_class_init (DownloaderViewClass *klass); +static void +downloader_view_finalize (GObject *object); +static void +downloader_view_init (DownloaderView *dv); + +/* Callbacks */ +void +download_dialog_resume_cb (GtkButton *button, DownloaderView *dv); +void +download_dialog_pause_cb (GtkButton *button, DownloaderView *dv); +void +download_dialog_abort_cb (GtkButton *button, DownloaderView *dv); +static void +downloader_treeview_selection_changed_cb (GtkTreeSelection *selection, + DownloaderView *dv); +gboolean +download_dialog_delete_cb (GtkWidget *window, GdkEventAny *event, + DownloaderView *dv); +void +download_dialog_details_cb (GtkToggleButton *button, + DownloaderView *dv); +void +download_dialog_open_cb (GtkWidget *button, + DownloaderView *dv); + +static GObjectClass *parent_class = NULL; +static guint downloader_view_signals[LAST_SIGNAL] = { 0 }; + +GType +downloader_view_get_type (void) +{ + static GType downloader_view_type = 0; + + if (downloader_view_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (DownloaderViewClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) downloader_view_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (DownloaderView), + 0, /* n_preallocs */ + (GInstanceInitFunc) downloader_view_init + }; + + downloader_view_type = g_type_register_static (EPHY_DIALOG_TYPE, + "DownloaderView", + &our_info, 0); + } + + return downloader_view_type; +} + +static void +format_time (gchar *buffer, glong time) +{ + gint secs, hours, mins; + + secs = (gint)(time + .5); + hours = secs / 3600; + secs -= hours * 3600; + mins = secs / 60; + secs -= mins * 60; + + if (hours) + { + sprintf (buffer, "%u:%02u.%02u", hours, mins, secs); + } + else + { + sprintf (buffer, "%02u.%02u", mins, secs); + } +} + +static void +downloader_view_class_init (DownloaderViewClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + EphyDialogClass *ephy_dialog_class; + + parent_class = g_type_class_peek_parent (klass); + ephy_dialog_class = EPHY_DIALOG_CLASS (klass); + + object_class->finalize = downloader_view_finalize; + + /* init signals */ + downloader_view_signals[DOWNLOAD_REMOVE] = + g_signal_new ("download_remove", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (DownloaderViewClass, download_remove), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + downloader_view_signals[DOWNLOAD_PAUSE] = + g_signal_new ("download_pause", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (DownloaderViewClass, download_pause), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + downloader_view_signals[DOWNLOAD_RESUME] = + g_signal_new ("download_resume", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (DownloaderViewClass, download_resume), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + +} + +static void +destroy_details_cb (DownloadDetails *details) +{ + g_free (details->filename); + g_free (details->source); + g_free (details->dest); + g_free (details); +} + +static void +downloader_view_init (DownloaderView *dv) +{ + dv->priv = g_new0 (DownloaderViewPrivate, 1); + dv->priv->details_hash = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify)destroy_details_cb); + + downloader_view_build_ui (dv); +} + +static void +downloader_view_finalize (GObject *object) +{ + DownloaderView *dv; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_DOWNLOADER_VIEW (object)); + + dv = DOWNLOADER_VIEW (object); + + g_return_if_fail (dv->priv != NULL); + + g_hash_table_destroy (dv->priv->details_hash); + + g_free (dv->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +DownloaderView * +downloader_view_new (void) +{ + return DOWNLOADER_VIEW (g_object_new + (DOWNLOADER_VIEW_TYPE, NULL)); +} + +static void +controls_info_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + ControlsInfo *info) +{ + DownloadDetails *details; + GValue val = {0, }; + gpointer persist_object; + + gtk_tree_model_get_value (model, iter, COL_PERSIST_OBJECT, &val); + persist_object = g_value_get_pointer (&val); + + details = g_hash_table_lookup (info->priv->details_hash, + persist_object); + + info->can_pause |= details->can_pause; + info->can_resume |= (details->status == DOWNLOAD_STATUS_PAUSED); + info->can_abort |= (details->status != DOWNLOAD_STATUS_COMPLETED); + info->can_open |= (details->status == DOWNLOAD_STATUS_COMPLETED); +} + +static void +downloader_view_update_controls (DownloaderViewPrivate *priv) +{ + GtkTreeSelection *selection; + ControlsInfo *info; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(priv->treeview)); + + info = g_new0 (ControlsInfo, 1); + info->priv = priv; + + /* initial conditions */ + info->can_pause = info->can_resume = info->can_abort + = info->can_open = FALSE; + + if (selection) + { + gtk_tree_selection_selected_foreach + (selection, + (GtkTreeSelectionForeachFunc)controls_info_foreach, + info); + } + + /* setup buttons */ + gtk_widget_set_sensitive (priv->pause_button, info->can_pause); + gtk_widget_set_sensitive (priv->resume_button, info->can_resume); + gtk_widget_set_sensitive (priv->abort_button, info->can_abort); + gtk_widget_set_sensitive (priv->open_button, info->can_open); + + g_free (info); +} + +static void +downloader_view_update_details (DownloaderViewPrivate *priv, + DownloadDetails *details) +{ + gchar buffer[50]; + + ephy_ellipsizing_label_set_text + (EPHY_ELLIPSIZING_LABEL (priv->details_location), + details->source); + ephy_ellipsizing_label_set_text + (EPHY_ELLIPSIZING_LABEL (priv->details_file), + details->filename); + + if (details->size_total >= 10000) + { + sprintf (buffer, _("%.1f of %.1f MB"), + details->size_done / 1024.0, + details->size_total / 1024.0); + } + else if (details->size_total > 0) + { + sprintf (buffer, _("%d of %d KB"), + details->size_done, + details->size_total); + } + else + { + sprintf (buffer, _("%d KB"), + details->size_done); + } + + if (details->speed > 0) + { + sprintf (buffer, "%s at %.1f KB/s", buffer, details->speed); + } + gtk_label_set_text (GTK_LABEL (priv->details_status), + buffer); + + format_time (buffer, details->elapsed/1000000); + gtk_label_set_text (GTK_LABEL (priv->details_elapsed), + buffer); + + format_time (buffer, details->remaining); + gtk_label_set_text (GTK_LABEL (priv->details_remaining), + buffer); + + if (details->progress >= 0) + { + gtk_progress_bar_set_fraction + (GTK_PROGRESS_BAR (priv->details_progress), + details->progress); + } + else + { + gtk_progress_bar_pulse + (GTK_PROGRESS_BAR (priv->details_progress)); + } +} + +static gboolean +get_selected_row (DownloaderViewPrivate *priv, GtkTreeIter *iter) +{ + GList *l; + GtkTreePath *node; + GtkTreeSelection *selection; + GtkTreeModel *model; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(priv->treeview)); + l = gtk_tree_selection_get_selected_rows (selection, &model); + + if (l == NULL) return FALSE; + + node = l->data; + gtk_tree_model_get_iter (model, iter, node); + + g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL); + g_list_free (l); + + return TRUE; +} + +static void +downloader_view_set_download_info (DownloaderViewPrivate *priv, + DownloadDetails *details, + GtkTreeIter *iter) +{ + gchar buffer[50]; + GtkTreePath *path; + GtkTreePath *selected_path = NULL; + GtkTreeIter selected_iter; + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection + (GTK_TREE_VIEW(priv->treeview)); + + if (get_selected_row (priv, &selected_iter)) + { + selected_path = gtk_tree_model_get_path + (priv->model, &selected_iter); + } + + path = gtk_tree_row_reference_get_path (details->ref); + + gtk_list_store_set (GTK_LIST_STORE (priv->model), + iter, + COL_FILENAME, details->filename, + -1); + + /* Progress */ + if (details->status == DOWNLOAD_STATUS_COMPLETED) + details->progress = 1; + sprintf (buffer, "%.1f%%", + details->progress > 0 ? + details->progress * 100.0 : + 0); + gtk_list_store_set (GTK_LIST_STORE (priv->model), + iter, + COL_PERCENT, buffer, + -1); + + /* Total */ + if (details->size_total >= 10000) + { + sprintf (buffer, "%.2f MB", details->size_total / 1024.0); + } + else if (details->size_total > 0) + { + sprintf (buffer, "%d KB", details->size_total); + } + else + { + sprintf (buffer, _("Unknown")); + } + + gtk_list_store_set (GTK_LIST_STORE (priv->model), + iter, + COL_SIZE, buffer, + -1); + + /* Remaining */ + if (details->remaining >= 0) + { + format_time (buffer, details->remaining); + } + else + { + sprintf (buffer, _("Unknown")); + } + gtk_list_store_set (GTK_LIST_STORE (priv->model), + iter, + COL_REMAINING, buffer, + -1); + + if (gtk_tree_path_compare (path, selected_path) == 0) + { + downloader_view_update_details (priv, details); + } +} + +static void +ensure_selected_row (DownloaderView *dv) +{ + GtkTreeIter iter; + GtkTreeSelection *selection; + + g_return_if_fail (IS_DOWNLOADER_VIEW(dv)); + + selection = gtk_tree_view_get_selection + (GTK_TREE_VIEW(dv->priv->treeview)); + if (get_selected_row (dv->priv, &iter)) + { + /* there is already a selection */ + return; + } + + if (gtk_tree_model_get_iter_first (dv->priv->model, &iter)) + { + gtk_tree_selection_select_iter (selection, &iter); + } +} + +void +downloader_view_add_download (DownloaderView *dv, + gchar *filename, + gchar *source, + gchar *dest, + gpointer persist_object) +{ + GtkTreeIter iter; + DownloadDetails *details; + GtkTreeSelection *selection; + + details = g_new0 (DownloadDetails, 1); + details->filename = g_strdup (filename); + details->source = g_strdup (source); + details->dest = g_strdup (dest); + details->elapsed = -1; + details->remaining = -1; + details->speed = -1; + details->size_total = -1; + details->size_done = -1; + details->progress = -1; + dv->priv->show_details = FALSE; + + g_hash_table_insert (dv->priv->details_hash, + persist_object, + details); + + gtk_list_store_append (GTK_LIST_STORE (dv->priv->model), + &iter); + + details->ref = gtk_tree_row_reference_new + (GTK_TREE_MODEL (dv->priv->model), + gtk_tree_model_get_path + (GTK_TREE_MODEL (dv->priv->model), &iter)); + + gtk_list_store_set (GTK_LIST_STORE (dv->priv->model), + &iter, + COL_PERSIST_OBJECT, persist_object, + -1); + + selection = gtk_tree_view_get_selection + (GTK_TREE_VIEW(dv->priv->treeview)); + gtk_tree_selection_unselect_all (selection); + gtk_tree_selection_select_iter (selection, &iter); + + downloader_view_set_download_info (dv->priv, details, &iter); + + ephy_dialog_show (EPHY_DIALOG(dv)); +} + +void +downloader_view_remove_download (DownloaderView *dv, + gpointer persist_object) +{ + DownloadDetails *details; + GtkTreeIter iter; + GValue keep_open = {0, }; + + details = g_hash_table_lookup (dv->priv->details_hash, + persist_object); + g_return_if_fail (details); + + gtk_tree_model_get_iter (GTK_TREE_MODEL (dv->priv->model), + &iter, + gtk_tree_row_reference_get_path (details->ref)); + + gtk_list_store_remove (GTK_LIST_STORE (dv->priv->model), &iter); + + g_hash_table_remove (dv->priv->details_hash, + persist_object); + + ephy_dialog_get_value (EPHY_DIALOG(dv), PROP_KEEP_OPEN, &keep_open); + + if (!g_value_get_boolean (&keep_open) && + g_hash_table_size (dv->priv->details_hash) == 0) + { + g_object_unref (dv); + } + else + { + ensure_selected_row (dv); + } +} + +void +downloader_view_set_download_progress (DownloaderView *dv, + glong elapsed, + glong remaining, + gfloat speed, + gint size_total, + gint size_done, + gfloat progress, + gboolean can_pause, + gpointer persist_object) +{ + DownloadDetails *details; + GtkTreeIter iter; + + details = g_hash_table_lookup (dv->priv->details_hash, + persist_object); + g_return_if_fail (details); + + details->elapsed = elapsed; + details->remaining = remaining; + details->speed = speed; + details->size_total = size_total; + details->size_done = size_done; + details->can_pause = can_pause; + details->progress = progress; + + gtk_tree_model_get_iter (GTK_TREE_MODEL (dv->priv->model), + &iter, + gtk_tree_row_reference_get_path (details->ref)); + + downloader_view_set_download_info (dv->priv, details, &iter); +} + +void +downloader_view_set_download_status (DownloaderView *dv, + DownloadStatus status, + gpointer persist_object) +{ + DownloadDetails *details; + GtkTreeIter iter; + GValue keep_open = {0, }; + + details = g_hash_table_lookup (dv->priv->details_hash, + persist_object); + g_return_if_fail (details); + + details->status = status; + + gtk_tree_model_get_iter (GTK_TREE_MODEL (dv->priv->model), + &iter, + gtk_tree_row_reference_get_path (details->ref)); + + downloader_view_set_download_info (dv->priv, details, &iter); + downloader_view_update_controls (dv->priv); + + ephy_dialog_get_value (EPHY_DIALOG(dv), PROP_KEEP_OPEN, &keep_open); + + if (status == DOWNLOAD_STATUS_COMPLETED && + !g_value_get_boolean (&keep_open)) + { + downloader_view_remove_download (dv, persist_object); + } +} + +static void +downloader_view_build_ui (DownloaderView *dv) +{ + DownloaderViewPrivate *priv = dv->priv; + GtkListStore *liststore; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GtkTreeSelection *selection; + GtkWidget *details_table; + EphyDialog *d = EPHY_DIALOG (dv); + + ephy_dialog_construct (d, + properties, + "epiphany.glade", + "download_manager_dialog"); + + /* lookup needed widgets */ + priv->treeview = ephy_dialog_get_control (d, PROP_TREEVIEW); + priv->details_status = ephy_dialog_get_control (d, PROP_DETAILS_STATUS); + priv->details_elapsed = ephy_dialog_get_control (d, PROP_DETAILS_ELAPSED); + priv->details_remaining = ephy_dialog_get_control (d, PROP_DETAILS_REMAINING); + priv->details_progress = ephy_dialog_get_control (d, PROP_DETAILS_PROGRESS); + priv->keep_open_check = ephy_dialog_get_control (d, PROP_KEEP_OPEN); + priv->details_button = ephy_dialog_get_control (d, PROP_DETAILS_BUTTON); + priv->pause_button = ephy_dialog_get_control (d, PROP_PAUSE_BUTTON); + priv->resume_button = ephy_dialog_get_control (d, PROP_RESUME_BUTTON); + priv->abort_button = ephy_dialog_get_control (d, PROP_ABORT_BUTTON); + priv->open_button = ephy_dialog_get_control (d, PROP_OPEN_BUTTON); + details_table = ephy_dialog_get_control (d, PROP_DETAILS_TABLE); + + /* create file and location details labels */ + priv->details_location = ephy_ellipsizing_label_new (""); + priv->details_file = ephy_ellipsizing_label_new (""); + gtk_table_attach_defaults (GTK_TABLE(details_table), priv->details_location, + 1, 2, 0, 1); + gtk_table_attach_defaults (GTK_TABLE(details_table), priv->details_file, + 1, 2, 1, 2); + gtk_misc_set_alignment (GTK_MISC(priv->details_location), 0, 0); + gtk_misc_set_alignment (GTK_MISC(priv->details_file), 0, 0); + gtk_label_set_selectable (GTK_LABEL(priv->details_location), TRUE); + gtk_label_set_selectable (GTK_LABEL(priv->details_file), TRUE); + gtk_widget_show (priv->details_location); + gtk_widget_show (priv->details_file); + + liststore = gtk_list_store_new (5, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_POINTER); + + gtk_tree_view_set_model (GTK_TREE_VIEW(priv->treeview), + GTK_TREE_MODEL (liststore)); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(priv->treeview), + TRUE); + + renderer = gtk_cell_renderer_text_new (); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(priv->treeview), + 0, _("%"), + renderer, + "text", 0, + NULL); + column = gtk_tree_view_get_column (GTK_TREE_VIEW(priv->treeview), 0); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_reorderable (column, TRUE); + gtk_tree_view_column_set_sort_column_id (column, COL_PERCENT); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(priv->treeview), + COL_FILENAME, _("Filename"), + renderer, + "text", COL_FILENAME, + NULL); + column = gtk_tree_view_get_column (GTK_TREE_VIEW(priv->treeview), + COL_FILENAME); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_reorderable (column, TRUE); + gtk_tree_view_column_set_sort_column_id (column, COL_FILENAME); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(priv->treeview), + COL_SIZE, _("Size"), + renderer, + "text", COL_SIZE, + NULL); + column = gtk_tree_view_get_column (GTK_TREE_VIEW(priv->treeview), + COL_SIZE); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_reorderable (column, TRUE); + gtk_tree_view_column_set_sort_column_id (column, COL_SIZE); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(priv->treeview), + COL_REMAINING, _("Remaining"), + renderer, + "text", COL_REMAINING, + NULL); + column = gtk_tree_view_get_column (GTK_TREE_VIEW(priv->treeview), + COL_REMAINING); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_reorderable (column, TRUE); + gtk_tree_view_column_set_sort_column_id (column, COL_REMAINING); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(priv->treeview)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); + g_signal_connect (G_OBJECT (selection), "changed", + G_CALLBACK (downloader_treeview_selection_changed_cb), dv); + + priv->model = GTK_TREE_MODEL (liststore); +} + +static void +resume_selection_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, + DownloaderView *dv) +{ + DownloadDetails *details; + GValue val = {0, }; + gpointer *persist_object; + + gtk_tree_model_get_value (model, iter, COL_PERSIST_OBJECT, &val); + persist_object = g_value_get_pointer (&val); + + details = g_hash_table_lookup (dv->priv->details_hash, + persist_object); + g_return_if_fail (details); + + if (details->status == DOWNLOAD_STATUS_COMPLETED) return; + + downloader_view_set_download_status (dv, DOWNLOAD_STATUS_RESUMING, persist_object); + + g_signal_emit (G_OBJECT (dv), downloader_view_signals[DOWNLOAD_RESUME], 0); +} + +void +download_dialog_resume_cb (GtkButton *button, DownloaderView *dv) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dv->priv->treeview)); + + gtk_tree_selection_selected_foreach + (selection, + (GtkTreeSelectionForeachFunc)resume_selection_foreach, + (gpointer)dv); +} + +static void +pause_selection_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, + DownloaderView *dv) +{ + DownloadDetails *details; + GValue val = {0, }; + gpointer *persist_object; + + gtk_tree_model_get_value (model, iter, COL_PERSIST_OBJECT, &val); + persist_object = g_value_get_pointer (&val); + + details = g_hash_table_lookup (dv->priv->details_hash, + persist_object); + g_return_if_fail (details); + + if (details->status == DOWNLOAD_STATUS_COMPLETED) return; + + downloader_view_set_download_status (dv, DOWNLOAD_STATUS_PAUSED, persist_object); + + g_signal_emit (G_OBJECT (dv), downloader_view_signals[DOWNLOAD_PAUSE], 0); +} + +void +download_dialog_pause_cb (GtkButton *button, DownloaderView *dv) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dv->priv->treeview)); + + gtk_tree_selection_selected_foreach + (selection, + (GtkTreeSelectionForeachFunc)pause_selection_foreach, + (gpointer)dv); +} + +void +download_dialog_abort_cb (GtkButton *button, DownloaderView *dv) +{ + GList *l, *r = NULL; + GtkTreeSelection *selection; + GtkTreeModel *model; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dv->priv->treeview)); + l = gtk_tree_selection_get_selected_rows (selection, &model); + for (;l != NULL; l = l->next) + { + r = g_list_append (r, gtk_tree_row_reference_new + (model, (GtkTreePath *)l->data)); + } + + for (; r != NULL; r = g_list_next (r)) + { + GtkTreeRowReference *node = r->data; + GValue val = {0, }; + gpointer *persist_object; + GtkTreeIter iter; + DownloadDetails *details; + + gtk_tree_model_get_iter (model, &iter, + gtk_tree_row_reference_get_path (node)); + + gtk_tree_model_get_value (model, &iter, + COL_PERSIST_OBJECT, &val); + persist_object = g_value_get_pointer (&val); + + details = g_hash_table_lookup (dv->priv->details_hash, + persist_object); + g_return_if_fail (details); + + g_signal_emit (G_OBJECT (dv), downloader_view_signals[DOWNLOAD_REMOVE], 0); + + downloader_view_remove_download (dv, persist_object); + + gtk_tree_row_reference_free (node); + } + + l = g_list_first (l); + g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL); + g_list_free (l); + g_list_free (r); +} + +static void +downloader_treeview_selection_changed_cb (GtkTreeSelection *selection, + DownloaderView *dv) +{ + GtkTreeIter iter; + GValue val = {0, }; + gpointer *persist_object; + DownloadDetails *details = NULL; + GtkWidget *details_frame; + DownloaderViewPrivate *priv= dv->priv; + + details_frame = ephy_dialog_get_control (EPHY_DIALOG(dv), + PROP_DETAILS_FRAME); + + if (get_selected_row (priv, &iter)) + { + gtk_tree_model_get_value (priv->model, &iter, COL_PERSIST_OBJECT, &val); + persist_object = g_value_get_pointer (&val); + + details = g_hash_table_lookup (priv->details_hash, + persist_object); + g_return_if_fail (details); + + gtk_widget_set_sensitive (details_frame, TRUE); + + downloader_view_update_details (priv, details); + downloader_view_update_controls (priv); + } + else + { + gtk_label_set_text (GTK_LABEL (priv->details_location), ""); + gtk_label_set_text (GTK_LABEL (priv->details_file), ""); + gtk_label_set_text (GTK_LABEL (priv->details_status), ""); + gtk_label_set_text (GTK_LABEL (priv->details_elapsed), ""); + gtk_label_set_text (GTK_LABEL (priv->details_remaining), ""); + gtk_progress_bar_set_fraction + (GTK_PROGRESS_BAR (priv->details_progress), + 0); + + gtk_widget_set_sensitive (details_frame, FALSE); + } +} + +static void +alive_download_foreach (gpointer persist_object, + DownloadDetails *details, + gboolean *alive) +{ + if (details->status != DOWNLOAD_STATUS_COMPLETED) + { + *alive = TRUE; + } +} + +static gboolean +delete_pending_foreach (gpointer persist_object, + DownloadDetails *details, + DownloaderView *dv) +{ + g_signal_emit (G_OBJECT (dv), downloader_view_signals[DOWNLOAD_REMOVE], + 0, persist_object); + + return TRUE; +} + +gboolean +download_dialog_delete_cb (GtkWidget *window, GdkEventAny *event, + DownloaderView *dv) +{ + GtkWidget *dialog; + gboolean choice; + gboolean alive_download = FALSE; + + g_hash_table_foreach (dv->priv->details_hash, + (GHFunc)alive_download_foreach, + &alive_download); + + if (!alive_download) return FALSE; + + /* build question dialog */ + dialog = gtk_message_dialog_new ( + GTK_WINDOW(window), + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_YES_NO, + _("Cancel all pending downloads?")); + + /* run it */ + choice = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + /* do the appropriate thing */ + if (choice == GTK_RESPONSE_YES) + { + g_hash_table_foreach_remove (dv->priv->details_hash, + (GHRFunc)delete_pending_foreach, + dv); + return FALSE; + } + + return TRUE; +} + +void +download_dialog_details_cb (GtkToggleButton *button, + DownloaderView *dv) +{ + GtkWidget *details_frame; + GtkWidget *details_separator; + + details_frame = ephy_dialog_get_control (EPHY_DIALOG(dv), + PROP_DETAILS_FRAME); + details_separator = ephy_dialog_get_control (EPHY_DIALOG(dv), + PROP_DETAILS_SEPARATOR); + + if (gtk_toggle_button_get_active (button)) + { + gtk_widget_show (GTK_WIDGET (details_frame)); + gtk_widget_show (GTK_WIDGET (details_separator)); + dv->priv->show_details = TRUE; + } + else + { + gtk_widget_hide (GTK_WIDGET (details_frame)); + gtk_widget_hide (GTK_WIDGET (details_separator)); + dv->priv->show_details = FALSE; + } + +} + +static void +open_selection_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, + DownloaderView *dv) +{ + DownloadDetails *details; + GValue val = {0, }; + gpointer *persist_object; + GnomeVFSMimeApplication *app; + char *mime; + + gtk_tree_model_get_value (model, iter, COL_PERSIST_OBJECT, &val); + persist_object = g_value_get_pointer (&val); + + details = g_hash_table_lookup (dv->priv->details_hash, + persist_object); + g_return_if_fail (details); + + if (details->status != DOWNLOAD_STATUS_COMPLETED) return; + + mime = gnome_vfs_get_mime_type (details->dest); + g_return_if_fail (mime != NULL); + + app = gnome_vfs_mime_get_default_application (mime); + if (app) + { + ephy_file_launch_application (app->command, + details->dest, + app->requires_terminal); + } + else + { + GtkWidget *parent; + parent = gtk_widget_get_toplevel (dv->priv->open_button); + ephy_embed_utils_nohandler_dialog_run (parent); + } + + g_free(mime); +} + +void +download_dialog_open_cb (GtkWidget *button, + DownloaderView *dv) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dv->priv->treeview)); + + gtk_tree_selection_selected_foreach + (selection, + (GtkTreeSelectionForeachFunc)open_selection_foreach, + (gpointer)dv); +} diff --git a/embed/downloader-view.h b/embed/downloader-view.h new file mode 100644 index 000000000..a01d5f30d --- /dev/null +++ b/embed/downloader-view.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef DOWNLOADER_VIEW_H +#define DOWNLOADER_VIEW_H + +#include "ephy-dialog.h" + +#include <glib-object.h> +#include <glib.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct DownloaderView DownloaderView; +typedef struct DownloaderViewClass DownloaderViewClass; + +#define DOWNLOADER_VIEW_TYPE (downloader_view_get_type ()) +#define DOWNLOADER_VIEW(obj) (GTK_CHECK_CAST ((obj), DOWNLOADER_VIEW_TYPE, DownloaderView)) +#define DOWNLOADER_VIEW_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), DOWNLOADER_VIEW, DownloaderViewClass)) +#define IS_DOWNLOADER_VIEW(obj) (GTK_CHECK_TYPE ((obj), DOWNLOADER_VIEW_TYPE)) +#define IS_DOWNLOADER_VIEW_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), DOWNLOADER_VIEW)) + +typedef struct DownloaderViewPrivate DownloaderViewPrivate; + +#define CONF_DOWNLOADING_KEEP_OPEN "/apps/epiphany/downloader/keep_open" + +typedef enum +{ + DOWNLOAD_STATUS_DOWNLOADING, + DOWNLOAD_STATUS_PAUSED, + DOWNLOAD_STATUS_RESUMING, + DOWNLOAD_STATUS_COMPLETED +} DownloadStatus; + +struct DownloaderView +{ + EphyDialog parent; + DownloaderViewPrivate *priv; +}; + +struct DownloaderViewClass +{ + EphyDialogClass parent_class; + + void (*download_remove) (DownloaderView *dv); + + void (*download_pause) (DownloaderView *dv); + + void (*download_resume) (DownloaderView *dv); +}; + +GType downloader_view_get_type (void); + +DownloaderView *downloader_view_new (void); + +void downloader_view_add_download (DownloaderView *dv, + gchar *filename, + gchar *source, + gchar *dest, + gpointer persist_object); + +void downloader_view_remove_download (DownloaderView *dv, + gpointer persist_object); + +void downloader_view_set_download_status (DownloaderView *dv, + DownloadStatus status, + gpointer persist_object); + +void downloader_view_set_download_progress (DownloaderView *dv, + glong elapsed, + glong remaining, + gfloat speed, + gint size_total, + gint size_done, + gfloat progress, + gboolean can_pause, + gpointer persist_object); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/embed/ephy-embed-dialog.c b/embed/ephy-embed-dialog.c new file mode 100644 index 000000000..cc019253a --- /dev/null +++ b/embed/ephy-embed-dialog.c @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-embed-dialog.h" +#include "ephy-embed-shell.h" + +static void +ephy_embed_dialog_class_init (EphyEmbedDialogClass *klass); +static void +ephy_embed_dialog_init (EphyEmbedDialog *window); +static void +ephy_embed_dialog_finalize (GObject *object); +static void +ephy_embed_dialog_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void +ephy_embed_dialog_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); + +enum +{ + PROP_0, + PROP_EPHY_EMBED +}; + +struct EphyEmbedDialogPrivate +{ + EphyEmbed *embed; +}; + +static GObjectClass *parent_class = NULL; + +GType +ephy_embed_dialog_get_type (void) +{ + static GType ephy_embed_dialog_type = 0; + + if (ephy_embed_dialog_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyEmbedDialogClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_embed_dialog_class_init, + NULL, + NULL, /* class_data */ + sizeof (EphyEmbedDialog), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_embed_dialog_init + }; + + ephy_embed_dialog_type = g_type_register_static (EPHY_DIALOG_TYPE, + "EphyEmbedDialog", + &our_info, 0); + } + + return ephy_embed_dialog_type; +} + +static void +ephy_embed_dialog_class_init (EphyEmbedDialogClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_embed_dialog_finalize; + object_class->set_property = ephy_embed_dialog_set_property; + object_class->get_property = ephy_embed_dialog_get_property; + + g_object_class_install_property (object_class, + PROP_EPHY_EMBED, + g_param_spec_object ("EphyEmbed", + "EphyEmbed", + "Ephy Embed", + G_TYPE_OBJECT, + G_PARAM_READWRITE)); +} + +static void +ephy_embed_dialog_init (EphyEmbedDialog *dialog) +{ + dialog->priv = g_new0 (EphyEmbedDialogPrivate, 1); + + dialog->priv->embed = NULL; +} + +static void +ephy_embed_dialog_finalize (GObject *object) +{ + EphyEmbedDialog *dialog; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_EPHY_EMBED_DIALOG (object)); + + dialog = EPHY_EMBED_DIALOG (object); + + g_return_if_fail (dialog->priv != NULL); + + g_free (dialog->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +ephy_embed_dialog_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyEmbedDialog *d = EPHY_EMBED_DIALOG (object); + + switch (prop_id) + { + case PROP_EPHY_EMBED: + ephy_embed_dialog_set_embed (d, g_value_get_object (value)); + break; + } +} + +static void +ephy_embed_dialog_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyEmbedDialog *d = EPHY_EMBED_DIALOG (object); + + switch (prop_id) + { + case PROP_EPHY_EMBED: + g_value_set_object (value, d->priv->embed); + break; + } +} + +EphyEmbedDialog * +ephy_embed_dialog_new (EphyEmbed *embed) +{ + return EPHY_EMBED_DIALOG (g_object_new (EPHY_EMBED_DIALOG_TYPE, + "EphyEmbed", embed, + NULL)); +} + +EphyEmbedDialog * +ephy_embed_dialog_new_with_parent (GtkWidget *parent_window, + EphyEmbed *embed) +{ + return EPHY_EMBED_DIALOG (g_object_new + (EPHY_EMBED_DIALOG_TYPE, + "ParentWindow", parent_window, + "EphyEmbed", embed, + NULL)); +} + +void +ephy_embed_dialog_set_embed (EphyEmbedDialog *dialog, + EphyEmbed *embed) +{ + dialog->priv->embed = embed; +} + +EphyEmbed * +ephy_embed_dialog_get_embed (EphyEmbedDialog *dialog) +{ + if (dialog->priv->embed == NULL) + { + EphyEmbed *embed; + embed = ephy_embed_shell_get_active_embed (embed_shell); + ephy_embed_dialog_set_embed (dialog, embed); + } + + return dialog->priv->embed; +} diff --git a/embed/ephy-embed-dialog.h b/embed/ephy-embed-dialog.h new file mode 100644 index 000000000..e8b7d3a3e --- /dev/null +++ b/embed/ephy-embed-dialog.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_EMBED_DIALOG_H +#define EPHY_EMBED_DIALOG_H + +#include "ephy-embed.h" +#include "ephy-dialog.h" + +#include <glib-object.h> +#include <glib.h> +#include <gtk/gtkwidget.h> + +G_BEGIN_DECLS + +typedef struct EphyEmbedDialogClass EphyEmbedDialogClass; + +#define EPHY_EMBED_DIALOG_TYPE (ephy_embed_dialog_get_type ()) +#define EPHY_EMBED_DIALOG(obj) (GTK_CHECK_CAST ((obj), EPHY_EMBED_DIALOG_TYPE, EphyEmbedDialog)) +#define EPHY_EMBED_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_EMBED_DIALOG_TYPE, EphyEmbedDialogClass)) +#define IS_EPHY_EMBED_DIALOG(obj) (GTK_CHECK_TYPE ((obj), EPHY_EMBED_DIALOG_TYPE)) +#define IS_EPHY_EMBED_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_EMBED_DIALOG)) +#define EPHY_EMBED_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EPHY_EMBED_DIALOG_TYPE, EphyEmbedDialogClass)) + +typedef struct EphyEmbedDialog EphyEmbedDialog; +typedef struct EphyEmbedDialogPrivate EphyEmbedDialogPrivate; + +struct EphyEmbedDialog +{ + EphyDialog parent; + EphyEmbedDialogPrivate *priv; +}; + +struct EphyEmbedDialogClass +{ + EphyDialogClass parent_class; +}; + +GType ephy_embed_dialog_get_type (void); + +EphyEmbedDialog *ephy_embed_dialog_new (EphyEmbed *embed); + +EphyEmbedDialog *ephy_embed_dialog_new_with_parent (GtkWidget *parent_window, + EphyEmbed *embed); + +void ephy_embed_dialog_set_embed (EphyEmbedDialog *dialog, + EphyEmbed *embed); + +EphyEmbed * ephy_embed_dialog_get_embed (EphyEmbedDialog *dialog); + +G_END_DECLS + +#endif + diff --git a/embed/ephy-embed-event.c b/embed/ephy-embed-event.c new file mode 100644 index 000000000..fdbd53eab --- /dev/null +++ b/embed/ephy-embed-event.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-embed-event.h" + +#include <bonobo/bonobo-i18n.h> +#include <glib/ghash.h> +#include <gtk/gtktypeutils.h> + +struct EphyEmbedEventPrivate +{ + GHashTable *props; +}; + +static void +ephy_embed_event_class_init (EphyEmbedEventClass *klass); +static void +ephy_embed_event_init (EphyEmbedEvent *ges); +static void +ephy_embed_event_finalize (GObject *object); + +static GObjectClass *parent_class = NULL; + +GType +ephy_embed_event_get_type (void) +{ + static GType ephy_embed_event_type = 0; + + if (ephy_embed_event_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyEmbedEventClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_embed_event_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EphyEmbedEvent), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_embed_event_init + }; + + ephy_embed_event_type = g_type_register_static (G_TYPE_OBJECT, + "EphyEmbedEvent", + &our_info, 0); + } + + return ephy_embed_event_type; +} + +static void +ephy_embed_event_class_init (EphyEmbedEventClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_embed_event_finalize; +} + +static void +ephy_embed_event_init (EphyEmbedEvent *event) +{ + event->priv = g_new0 (EphyEmbedEventPrivate, 1); + + event->priv->props = g_hash_table_new (g_str_hash, g_str_equal); +} + +static void +ephy_embed_event_finalize (GObject *object) +{ + EphyEmbedEvent *event; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_EPHY_EMBED_EVENT (object)); + + event = EPHY_EMBED_EVENT (object); + + g_return_if_fail (event->priv != NULL); + + g_hash_table_foreach_remove (event->priv->props, + (GHRFunc)g_free, + NULL); + g_hash_table_destroy (event->priv->props); + + g_free (event->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + + +EphyEmbedEvent * +ephy_embed_event_new (void) +{ + EphyEmbedEvent *event; + + event = EPHY_EMBED_EVENT (g_object_new (EPHY_EMBED_EVENT_TYPE, NULL)); + + g_return_val_if_fail (event->priv != NULL, NULL); + + return event; +} + +guint +ephy_embed_event_get_modifier (EphyEmbedEvent *event) +{ + return event->modifier; +} + +gresult +ephy_embed_event_get_mouse_button (EphyEmbedEvent *event, + guint *mouse_button) +{ + *mouse_button = event->mouse_button; + return G_OK; +} + +gresult +ephy_embed_event_get_mouse_coords (EphyEmbedEvent *event, + guint *x, guint *y) +{ + *x = event->mouse_x; + *y = event->mouse_y; + return G_OK; +} + +gresult +ephy_embed_event_get_context (EphyEmbedEvent *event, + EmbedEventContext *context) +{ + *context = event->context; + return G_OK; +} + +void +ephy_embed_event_set_property (EphyEmbedEvent *event, + const char *name, + GValue *value) +{ + g_hash_table_insert (event->priv->props, + g_strdup (name), + value); +} + +void +ephy_embed_event_get_property (EphyEmbedEvent *event, + const char *name, + GValue **value) +{ + *value = g_hash_table_lookup (event->priv->props, name); +} + +gboolean +ephy_embed_event_has_property (EphyEmbedEvent *event, + const char *name) +{ + gpointer tmp; + + tmp = g_hash_table_lookup (event->priv->props, + name); + + return tmp != NULL; +} diff --git a/embed/ephy-embed-event.h b/embed/ephy-embed-event.h new file mode 100644 index 000000000..1256dcffc --- /dev/null +++ b/embed/ephy-embed-event.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_EMBED_EVENT_H +#define EPHY_EMBED_EVENT_H + +#include "ephy-embed-types.h" + +#include <glib-object.h> +#include <glib.h> + +G_BEGIN_DECLS + +typedef struct EphyEmbedEventClass EphyEmbedEventClass; + +#define EPHY_EMBED_EVENT_TYPE (ephy_embed_event_get_type ()) +#define EPHY_EMBED_EVENT(obj) (GTK_CHECK_CAST ((obj), EPHY_EMBED_EVENT_TYPE, EphyEmbedEvent)) +#define EPHY_EMBED_EVENT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_PERSIST_SHELL, EphyEmbedEventClass)) +#define IS_EPHY_EMBED_EVENT(obj) (GTK_CHECK_TYPE ((obj), EPHY_EMBED_EVENT_TYPE)) +#define IS_EPHY_EMBED_EVENT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_EMBED_EVENT)) +#define EPHY_EMBED_EVENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EPHY_EMBED_SHELL_TYPE, EphyEmbedEventClass)) + +typedef struct EphyEmbedEvent EphyEmbedEvent; +typedef struct EphyEmbedEventPrivate EphyEmbedEventPrivate; + +typedef enum +{ + EMBED_CONTEXT_NONE = 0, + EMBED_CONTEXT_DEFAULT = 1 << 1, + EMBED_CONTEXT_LINK = 1 << 2, + EMBED_CONTEXT_IMAGE = 1 << 3, + EMBED_CONTEXT_DOCUMENT = 1 << 4, + EMBED_CONTEXT_INPUT = 1 << 5, + EMBED_CONTEXT_XUL = 1 << 7, + EMBED_CONTEXT_EMAIL_LINK = 1 << 8 +} EmbedEventContext; + +struct EphyEmbedEvent +{ + GObject parent; + EphyEmbedEventPrivate *priv; + + /* Public to the embed implementations */ + guint modifier; + guint mouse_button; + guint context; + guint timestamp; + guint mouse_x, mouse_y; +}; + +struct EphyEmbedEventClass +{ + GObjectClass parent_class; +}; + +GType ephy_embed_event_get_type (void); + +EphyEmbedEvent *ephy_embed_event_new (void); + +guint ephy_embed_event_get_modifier (EphyEmbedEvent *event); + +gresult ephy_embed_event_get_mouse_button (EphyEmbedEvent *event, + guint *mouse_button); + +gresult ephy_embed_event_get_mouse_coords (EphyEmbedEvent *event, + guint *x, guint *y); + +gresult ephy_embed_event_get_context (EphyEmbedEvent *event, + EmbedEventContext *context); + +void ephy_embed_event_set_property (EphyEmbedEvent *event, + const char *name, + GValue *value); + +void ephy_embed_event_get_property (EphyEmbedEvent *event, + const char *name, + GValue **value); + +gboolean ephy_embed_event_has_property (EphyEmbedEvent *event, + const char *name); + + +G_END_DECLS + +#endif diff --git a/embed/ephy-embed-favicon.c b/embed/ephy-embed-favicon.c new file mode 100644 index 000000000..d88eb91cf --- /dev/null +++ b/embed/ephy-embed-favicon.c @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <string.h> + +#include "ephy-embed-favicon.h" +#include "ephy-embed-shell.h" + +static void ephy_embed_favicon_class_init (EphyEmbedFaviconClass *klass); +static void ephy_embed_favicon_init (EphyEmbedFavicon *ma); +static void ephy_embed_favicon_finalize (GObject *object); +static void ephy_embed_favicon_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ephy_embed_favicon_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +struct EphyEmbedFaviconPrivate +{ + EphyEmbed *embed; +}; + +enum +{ + PROP_0, + PROP_EMBED +}; + +static GObjectClass *parent_class = NULL; + +GType +ephy_embed_favicon_get_type (void) +{ + static GType ephy_embed_favicon_type = 0; + + if (ephy_embed_favicon_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyEmbedFaviconClass), + NULL, + NULL, + (GClassInitFunc) ephy_embed_favicon_class_init, + NULL, + NULL, + sizeof (EphyEmbedFavicon), + 0, + (GInstanceInitFunc) ephy_embed_favicon_init + }; + + ephy_embed_favicon_type = g_type_register_static (EPHY_TYPE_FAVICON, + "EphyEmbedFavicon", + &our_info, 0); + } + + return ephy_embed_favicon_type; +} + +static void +ephy_embed_favicon_class_init (EphyEmbedFaviconClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_embed_favicon_finalize; + + object_class->set_property = ephy_embed_favicon_set_property; + object_class->get_property = ephy_embed_favicon_get_property; + + g_object_class_install_property (object_class, + PROP_EMBED, + g_param_spec_object ("embed", + "Associated embed", + "Associated embed", + G_TYPE_OBJECT, + G_PARAM_READWRITE)); +} + +static void +ephy_embed_favicon_init (EphyEmbedFavicon *ma) +{ + ma->priv = g_new0 (EphyEmbedFaviconPrivate, 1); +} + +static void +ephy_embed_favicon_finalize (GObject *object) +{ + EphyEmbedFavicon *ma; + + g_return_if_fail (object != NULL); + g_return_if_fail (EPHY_IS_EMBED_FAVICON (object)); + + ma = EPHY_EMBED_FAVICON (object); + + g_return_if_fail (ma->priv != NULL); + + g_free (ma->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +location_changed_cb (EphyEmbed *embed, + EphyEmbedFavicon *favicon) +{ + char *location; + + ephy_embed_get_location (embed, TRUE, FALSE, &location); + ephy_favicon_set_url (EPHY_FAVICON (favicon), location); + + g_free (location); +} + +static void +favicon_cb (EphyEmbed *embed, + const char *favicon_url, + EphyEmbedFavicon *favicon) +{ + char *url = NULL; + EphyFaviconCache *cache; + + if (favicon->priv->embed == NULL) + return; + + ephy_embed_get_location (favicon->priv->embed, TRUE, TRUE, &url); + + g_object_get (G_OBJECT (favicon), + "cache", &cache, + NULL); + + ephy_favicon_cache_insert_from_url (cache, + url, + favicon_url); + + g_object_unref (cache); + + g_free (url); +} + +static void +ephy_embed_favicon_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyEmbedFavicon *favicon = EPHY_EMBED_FAVICON (object); + + switch (prop_id) + { + case PROP_EMBED: + favicon->priv->embed = g_value_get_object (value); + + if (favicon->priv->embed != NULL) + { + g_signal_connect_object (G_OBJECT (favicon->priv->embed), + "ge_favicon", + G_CALLBACK (favicon_cb), + favicon, + 0); + g_signal_connect_object (G_OBJECT (favicon->priv->embed), + "ge_location", + G_CALLBACK (location_changed_cb), + favicon, + 0); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ephy_embed_favicon_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyEmbedFavicon *favicon = EPHY_EMBED_FAVICON (object); + + switch (prop_id) + { + case PROP_EMBED: + g_value_set_object (value, favicon->priv->embed); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +GtkWidget * +ephy_embed_favicon_new (EphyEmbed *embed) +{ + EphyEmbedFavicon *favicon; + EphyFaviconCache *cache = ephy_embed_shell_get_favicon_cache (embed_shell); + + g_return_val_if_fail (EPHY_IS_FAVICON_CACHE (cache), NULL); + + favicon = EPHY_EMBED_FAVICON (g_object_new (EPHY_TYPE_EMBED_FAVICON, + "cache", cache, + "embed", embed, + NULL)); + + g_return_val_if_fail (favicon->priv != NULL, NULL); + + return GTK_WIDGET (favicon); +} + +void +ephy_embed_favicon_set_embed (EphyEmbedFavicon *favicon, + EphyEmbed *embed) +{ + g_return_if_fail (EPHY_IS_EMBED_FAVICON (favicon)); + + g_object_set (G_OBJECT (favicon), + "embed", embed, + NULL); +} + +EphyEmbed * +ephy_embed_favicon_get_embed (EphyEmbedFavicon *favicon) +{ + EphyEmbed *embed; + + g_return_val_if_fail (EPHY_IS_EMBED_FAVICON (favicon), NULL); + + g_object_get (G_OBJECT (favicon), + "embed", &embed, + NULL); + + return embed; +} diff --git a/embed/ephy-embed-favicon.h b/embed/ephy-embed-favicon.h new file mode 100644 index 000000000..36f69cc82 --- /dev/null +++ b/embed/ephy-embed-favicon.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <glib-object.h> +#include <gtk/gtkimage.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "ephy-favicon.h" +#include "ephy-embed.h" + +#ifndef __EPHY_EMBED_FAVICON_H +#define __EPHY_EMBED_FAVICON_H + +G_BEGIN_DECLS + +#define EPHY_TYPE_EMBED_FAVICON (ephy_embed_favicon_get_type ()) +#define EPHY_EMBED_FAVICON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_EMBED_FAVICON, EphyEmbedFavicon)) +#define EPHY_EMBED_FAVICON_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EPHY_TYPE_EMBED_FAVICON, EphyEmbedFaviconClass)) +#define EPHY_IS_EMBED_FAVICON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_EMBED_FAVICON)) +#define EPHY_IS_EMBED_FAVICON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_EMBED_FAVICON)) +#define EPHY_EMBED_FAVICON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_EMBED_FAVICON, EphyEmbedFaviconClass)) + +typedef struct EphyEmbedFaviconPrivate EphyEmbedFaviconPrivate; + +typedef struct +{ + EphyFavicon parent; + + EphyEmbedFaviconPrivate *priv; +} EphyEmbedFavicon; + +typedef struct +{ + EphyFaviconClass parent_class; +} EphyEmbedFaviconClass; + +GType ephy_embed_favicon_get_type (void); + +GtkWidget *ephy_embed_favicon_new (EphyEmbed *embed); + +void ephy_embed_favicon_set_embed (EphyEmbedFavicon *favicon, + EphyEmbed *embed); + +EphyEmbed *ephy_embed_favicon_get_embed (EphyEmbedFavicon *favicon); + +G_END_DECLS + +#endif /* __EPHY_EMBED_FAVICON_H */ diff --git a/embed/ephy-embed-persist.c b/embed/ephy-embed-persist.c new file mode 100644 index 000000000..a1d742587 --- /dev/null +++ b/embed/ephy-embed-persist.c @@ -0,0 +1,491 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <config.h> + +#include "ephy-embed-persist.h" + +#include "mozilla-embed.h" +#include "mozilla-embed-persist.h" + +#include <bonobo/bonobo-i18n.h> + +enum +{ + COMPLETED, + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_EMBED, + PROP_SOURCE, + PROP_DEST, + PROP_MAX_SIZE, + PROP_FLAGS, + PROP_HANDLER +}; + +struct EphyEmbedPersistPrivate +{ + char *dir; + char *src; + PersistHandlerInfo *handler; + EphyEmbed *embed; + int max_size; + EmbedPersistFlags flags; +}; + +static void +ephy_embed_persist_class_init (EphyEmbedPersistClass *klass); +static void +ephy_embed_persist_init (EphyEmbedPersist *ges); +static void +ephy_embed_persist_finalize (GObject *object); +static void +ephy_embed_persist_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void +ephy_embed_persist_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +static gresult +impl_set_source (EphyEmbedPersist *persist, + const char *url); +static gresult +impl_set_dest (EphyEmbedPersist *persist, + const char *dir); +static gresult +impl_set_max_size (EphyEmbedPersist *persist, + int kb_size); +static gresult +impl_set_embed (EphyEmbedPersist *persist, + EphyEmbed *embed); +static gresult +impl_set_flags (EphyEmbedPersist *persist, + EmbedPersistFlags flags); +static gresult +impl_set_handler (EphyEmbedPersist *persist, + const char *command, + gboolean need_terminal); + +static GObjectClass *parent_class = NULL; +static guint ephy_embed_persist_signals[LAST_SIGNAL] = { 0 }; + +GType +ephy_embed_persist_get_type (void) +{ + static GType ephy_embed_persist_type = 0; + + if (ephy_embed_persist_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyEmbedPersistClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_embed_persist_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EphyEmbedPersist), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_embed_persist_init + }; + + ephy_embed_persist_type = g_type_register_static (G_TYPE_OBJECT, + "EphyEmbedPersist", + &our_info, 0); + } + + return ephy_embed_persist_type; +} + +static void +ephy_embed_persist_class_init (EphyEmbedPersistClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_embed_persist_finalize; + object_class->set_property = ephy_embed_persist_set_property; + object_class->get_property = ephy_embed_persist_get_property; + + klass->set_source = impl_set_source; + klass->set_dest = impl_set_dest; + klass->set_embed = impl_set_embed; + klass->set_max_size = impl_set_max_size; + klass->set_flags = impl_set_flags; + klass->set_handler = impl_set_handler; + + /* init signals */ + ephy_embed_persist_signals[COMPLETED] = + g_signal_new ("completed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyEmbedPersistClass, completed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + g_object_class_install_property (object_class, + PROP_EMBED, + g_param_spec_object ("embed", + "Embed", + "The embed containing the document", + G_TYPE_OBJECT, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_SOURCE, + g_param_spec_string ("source", + "Source", + "Url of the document to save", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_DEST, + g_param_spec_string ("dest", + "Destination", + "Destination directory", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_MAX_SIZE, + g_param_spec_int ("max_size", + "Maxsize", + "Maximum size of the file", + 0, + G_MAXINT, + 0, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_FLAGS, + g_param_spec_int ("flags", + "Flags", + "Flags", + 0, + G_MAXINT, + 0, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_HANDLER, + g_param_spec_pointer ("handler", + "Handler", + "Handler", + G_PARAM_READWRITE)); +} + +static void +ephy_embed_persist_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyEmbedPersist *persist; + PersistHandlerInfo *h; + + persist = EPHY_EMBED_PERSIST (object); + + switch (prop_id) + { + case PROP_EMBED: + ephy_embed_persist_set_embed (persist, + g_value_get_object (value)); + break; + case PROP_SOURCE: + ephy_embed_persist_set_source (persist, + g_value_get_string (value)); + break; + case PROP_DEST: + ephy_embed_persist_set_dest (persist, + g_value_get_string (value)); + break; + case PROP_MAX_SIZE: + ephy_embed_persist_set_max_size (persist, + g_value_get_int (value)); + break; + case PROP_FLAGS: + ephy_embed_persist_set_flags + (persist, + (EmbedPersistFlags)g_value_get_int (value)); + break; + case PROP_HANDLER: + h = (PersistHandlerInfo *)g_value_get_pointer (value); + ephy_embed_persist_set_handler + (persist, h->command, h->need_terminal); + break; + } +} + +static void +ephy_embed_persist_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyEmbedPersist *persist; + + persist = EPHY_EMBED_PERSIST (object); + + switch (prop_id) + { + case PROP_EMBED: + g_value_set_object (value, persist->priv->embed); + break; + case PROP_SOURCE: + g_value_set_string (value, persist->priv->src); + break; + case PROP_DEST: + g_value_set_string (value, persist->priv->dir); + break; + case PROP_MAX_SIZE: + g_value_set_int (value, persist->priv->max_size); + break; + case PROP_FLAGS: + g_value_set_int (value, (int)persist->priv->flags); + break; + case PROP_HANDLER: + g_value_set_pointer (value, persist->priv->handler); + } +} + +static void +ephy_embed_persist_init (EphyEmbedPersist *persist) +{ + persist->priv = g_new0 (EphyEmbedPersistPrivate, 1); + persist->priv->src = NULL; + persist->priv->dir = NULL; + persist->priv->handler = NULL; +} + +static void +ephy_embed_persist_finalize (GObject *object) +{ + EphyEmbedPersist *persist; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_EPHY_EMBED_PERSIST (object)); + + persist = EPHY_EMBED_PERSIST (object); + + g_return_if_fail (persist->priv != NULL); + + g_free (persist->priv->dir); + g_free (persist->priv->src); + + if (persist->priv->handler) + { + g_free (persist->priv->handler->command); + g_free (persist->priv->handler); + } + + g_free (persist->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + + +EphyEmbedPersist * +ephy_embed_persist_new (EphyEmbed *embed) +{ + EphyEmbedPersist *persist; + GType type = 0; + + type = MOZILLA_EMBED_PERSIST_TYPE; + + g_assert (type != 0); + + persist = EPHY_EMBED_PERSIST (g_object_new (type, + "embed", embed, + NULL)); + + g_return_val_if_fail (persist->priv != NULL, NULL); + + return persist; +} + +gresult +ephy_embed_persist_set_source (EphyEmbedPersist *persist, + const char *url) +{ + EphyEmbedPersistClass *klass = EPHY_EMBED_PERSIST_GET_CLASS (persist); + return klass->set_source (persist, url); +} + +gresult +ephy_embed_persist_get_source (EphyEmbedPersist *persist, + const char **url) +{ + *url = persist->priv->src; + + return G_OK; +} + +gresult +ephy_embed_persist_get_dest (EphyEmbedPersist *persist, + const char **dir) +{ + *dir = persist->priv->dir; + + return G_OK; +} + +gresult +ephy_embed_persist_set_dest (EphyEmbedPersist *persist, + const char *dir) +{ + EphyEmbedPersistClass *klass = EPHY_EMBED_PERSIST_GET_CLASS (persist); + return klass->set_dest (persist, dir); +} + +gresult +ephy_embed_persist_save (EphyEmbedPersist *persist) +{ + EphyEmbedPersistClass *klass = EPHY_EMBED_PERSIST_GET_CLASS (persist); + return klass->save (persist); +} + +gresult +ephy_embed_persist_set_max_size (EphyEmbedPersist *persist, + int kb_size) +{ + EphyEmbedPersistClass *klass = EPHY_EMBED_PERSIST_GET_CLASS (persist); + return klass->set_max_size (persist, kb_size); +} + +gresult +ephy_embed_persist_set_embed (EphyEmbedPersist *persist, + EphyEmbed *embed) +{ + EphyEmbedPersistClass *klass = EPHY_EMBED_PERSIST_GET_CLASS (persist); + return klass->set_embed (persist, embed); +} + +gresult +ephy_embed_persist_get_embed (EphyEmbedPersist *persist, + EphyEmbed **embed) +{ + *embed = persist->priv->embed; + + return G_OK; +} + +gresult +ephy_embed_persist_set_flags (EphyEmbedPersist *persist, + EmbedPersistFlags flags) +{ + EphyEmbedPersistClass *klass = EPHY_EMBED_PERSIST_GET_CLASS (persist); + return klass->set_flags (persist, flags); +} + +gresult +ephy_embed_persist_get_flags (EphyEmbedPersist *persist, + EmbedPersistFlags *flags) +{ + *flags = persist->priv->flags= persist->priv->flags; + + return G_OK; +} + +gresult +ephy_embed_persist_set_handler (EphyEmbedPersist *persist, + const char *command, + gboolean need_terminal) +{ + EphyEmbedPersistClass *klass = EPHY_EMBED_PERSIST_GET_CLASS (persist); + return klass->set_handler (persist, command, need_terminal); +} + +static gresult +impl_set_handler (EphyEmbedPersist *persist, + const char *command, + gboolean need_terminal) +{ + persist->priv->handler = g_new0 (PersistHandlerInfo, 1); + persist->priv->handler->command = g_strdup (command); + persist->priv->handler->need_terminal = need_terminal; + + g_object_notify (G_OBJECT(persist), "handler"); + + return G_OK; +} + +static gresult +impl_set_flags (EphyEmbedPersist *persist, + EmbedPersistFlags flags) +{ + persist->priv->flags = flags; + + g_object_notify (G_OBJECT(persist), "flags"); + + return G_OK; +} + +static gresult +impl_set_source (EphyEmbedPersist *persist, + const char *url) +{ + persist->priv->src = g_strdup(url); + + g_object_notify (G_OBJECT(persist), "source"); + + return G_OK; +} + +static gresult +impl_set_dest (EphyEmbedPersist *persist, + const char *dir) +{ + persist->priv->dir = g_strdup (dir); + + g_object_notify (G_OBJECT(persist), "dest"); + + return G_OK; +} + +static gresult +impl_set_max_size (EphyEmbedPersist *persist, + int kb_size) +{ + persist->priv->max_size = kb_size; + + g_object_notify (G_OBJECT(persist), "max_size"); + + return G_OK; +} + +static gresult +impl_set_embed (EphyEmbedPersist *persist, + EphyEmbed *embed) +{ + persist->priv->embed = embed; + + g_object_notify (G_OBJECT(persist), "embed"); + + return G_OK; +} diff --git a/embed/ephy-embed-persist.h b/embed/ephy-embed-persist.h new file mode 100644 index 000000000..2ad883647 --- /dev/null +++ b/embed/ephy-embed-persist.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_EMBED_PERSIST_H +#define EPHY_EMBED_PERSIST_H + +#include "ephy-embed.h" + +#include <glib-object.h> +#include <glib.h> + +G_BEGIN_DECLS + +typedef struct EphyEmbedPersistClass EphyEmbedPersistClass; + +#define EPHY_EMBED_PERSIST_TYPE (ephy_embed_persist_get_type ()) +#define EPHY_EMBED_PERSIST(obj) (GTK_CHECK_CAST ((obj), EPHY_EMBED_PERSIST_TYPE, EphyEmbedPersist)) +#define EPHY_EMBED_PERSIST_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_EMBED_PERSIST_TYPE, EphyEmbedPersistClass)) +#define IS_EPHY_EMBED_PERSIST(obj) (GTK_CHECK_TYPE ((obj), EPHY_EMBED_PERSIST_TYPE)) +#define IS_EPHY_EMBED_PERSIST_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_EMBED_PERSIST)) +#define EPHY_EMBED_PERSIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EPHY_EMBED_PERSIST_TYPE, EphyEmbedPersistClass)) + +typedef struct EphyEmbedPersist EphyEmbedPersist; +typedef struct EphyEmbedPersistPrivate EphyEmbedPersistPrivate; + +typedef enum +{ + EMBED_PERSIST_SHOW_PROGRESS = 1 << 0, + EMBED_PERSIST_SAVE_CONTENT = 1 << 1, + EMBED_PERSIST_FROMCACHE = 1 << 2, + EMBED_PERSIST_BYPASSCACHE = 1 << 3, + EMBED_PERSIST_MAINDOC = 1 << 4 +} EmbedPersistFlags; + +typedef struct +{ + char *command; + gboolean need_terminal; +} PersistHandlerInfo; + +struct EphyEmbedPersist +{ + GObject parent; + EphyEmbedPersistPrivate *priv; +}; + +struct EphyEmbedPersistClass +{ + GObjectClass parent_class; + + void (* completed) (EphyEmbedPersist *persist); + + /* Methods */ + + gresult (* set_source) (EphyEmbedPersist *persist, + const char *url); + gresult (* set_dest) (EphyEmbedPersist *persist, + const char *dir); + gresult (* save) (EphyEmbedPersist *persist); + + gresult (* set_max_size) (EphyEmbedPersist *persist, + int max_size); + + gresult (* set_embed) (EphyEmbedPersist *persist, + EphyEmbed *embed); + + gresult (* set_flags) (EphyEmbedPersist *persist, + EmbedPersistFlags flags); + + gresult (* set_handler) (EphyEmbedPersist *persist, + const char *command, + gboolean need_terminal); +}; + +GType ephy_embed_persist_get_type (void); + +EphyEmbedPersist *ephy_embed_persist_new (EphyEmbed *embed); + +gresult ephy_embed_persist_set_source (EphyEmbedPersist *persist, + const char *url); + +gresult ephy_embed_persist_get_source (EphyEmbedPersist *persist, + const char **url); + +gresult ephy_embed_persist_set_dest (EphyEmbedPersist *persist, + const char *dir); + +gresult ephy_embed_persist_get_dest (EphyEmbedPersist *persist, + const char **dir); + +gresult ephy_embed_persist_set_handler (EphyEmbedPersist *persist, + const char *handler, + gboolean need_terminal); + +gresult ephy_embed_persist_set_max_size (EphyEmbedPersist *persist, + int kb_size); + +gresult ephy_embed_persist_set_embed (EphyEmbedPersist *persist, + EphyEmbed *embed); + +gresult ephy_embed_persist_get_embed (EphyEmbedPersist *persist, + EphyEmbed **embed); + +gresult ephy_embed_persist_set_flags (EphyEmbedPersist *persist, + EmbedPersistFlags flags); + +gresult ephy_embed_persist_get_flags (EphyEmbedPersist *persist, + EmbedPersistFlags *flags); + +gresult ephy_embed_persist_save (EphyEmbedPersist *persist); + +G_END_DECLS + +#endif diff --git a/embed/ephy-embed-popup-bw.c b/embed/ephy-embed-popup-bw.c new file mode 100644 index 000000000..553f73205 --- /dev/null +++ b/embed/ephy-embed-popup-bw.c @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-embed-popup-bw.h" +#include "ephy-gobject-misc.h" + +#include <gtk/gtkmain.h> + +enum +{ + PROP_0, + PROP_BONOBO_WINDOW +}; + +struct EphyEmbedPopupBWPrivate +{ + BonoboWindow *window; + GtkWidget *menu; +}; + +static void +ephy_embed_popup_bw_class_init (EphyEmbedPopupBWClass *klass); +static void +ephy_embed_popup_bw_init (EphyEmbedPopupBW *gep); +static void +ephy_embed_popup_bw_finalize (GObject *object); +static void +ephy_embed_popup_bw_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void +ephy_embed_popup_bw_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void +ephy_embed_popup_bw_set_window (EphyEmbedPopupBW *p, + BonoboWindow *window); +static void +ephy_embed_popup_bw_show_impl (EphyEmbedPopup *p, + EphyEmbed *embed); + +static EphyEmbedPopupClass *parent_class = NULL; + +MAKE_GET_TYPE (ephy_embed_popup_bw, "EphyEmbedPopupBW", EphyEmbedPopupBW, + ephy_embed_popup_bw_class_init, ephy_embed_popup_bw_init, EPHY_EMBED_POPUP_TYPE); + +static void +ephy_embed_popup_bw_class_init (EphyEmbedPopupBWClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = EPHY_EMBED_POPUP_CLASS (g_type_class_peek_parent (klass)); + + object_class->finalize = ephy_embed_popup_bw_finalize; + object_class->set_property = ephy_embed_popup_bw_set_property; + object_class->get_property = ephy_embed_popup_bw_get_property; + + g_object_class_install_property (object_class, + PROP_BONOBO_WINDOW, + g_param_spec_object ("BonoboWindow", + "BonoboWindow", + "Bonobo window", + BONOBO_TYPE_WINDOW, + G_PARAM_READWRITE)); + + EPHY_EMBED_POPUP_CLASS (klass)->show = ephy_embed_popup_bw_show_impl; +} + +static void +ephy_embed_popup_bw_init (EphyEmbedPopupBW *gep) +{ + gep->priv = g_new0 (EphyEmbedPopupBWPrivate, 1); + gep->priv->window = NULL; + gep->priv->menu = NULL; +} + +static void +ephy_embed_popup_bw_finalize (GObject *object) +{ + EphyEmbedPopupBW *gep; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_EPHY_EMBED_POPUP_BW (object)); + + gep = EPHY_EMBED_POPUP_BW (object); + + g_return_if_fail (gep->priv != NULL); + + g_free (gep->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +ephy_embed_popup_bw_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyEmbedPopupBW *p = EPHY_EMBED_POPUP_BW (object); + + switch (prop_id) + { + case PROP_BONOBO_WINDOW: + ephy_embed_popup_bw_set_window (p, g_value_get_object (value)); + break; + } +} + +static void +ephy_embed_popup_bw_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyEmbedPopupBW *p = EPHY_EMBED_POPUP_BW (object); + + switch (prop_id) + { + case PROP_BONOBO_WINDOW: + g_value_set_object (value, p->priv->window); + break; + } +} + +static void +ephy_embed_popup_bw_set_window (EphyEmbedPopupBW *p, + BonoboWindow *window) +{ + p->priv->window = window; +} + +EphyEmbedPopupBW * +ephy_embed_popup_bw_new (BonoboWindow *window) +{ + EphyEmbedPopupBW *p; + + p = EPHY_EMBED_POPUP_BW (g_object_new (EPHY_EMBED_POPUP_BW_TYPE, + "BonoboWindow", window, + NULL)); + + g_return_val_if_fail (p->priv != NULL, NULL); + + return p; +} + +static void +ephy_embed_popup_bw_show_impl (EphyEmbedPopup *pp, + EphyEmbed *embed) +{ + EphyEmbedPopupBW *p = EPHY_EMBED_POPUP_BW (pp); + EphyEmbedEvent *event = ephy_embed_popup_get_event (pp); + guint button; + + ephy_embed_popup_set_embed (pp, embed); + + ephy_embed_event_get_mouse_button (event, &button); + + p->priv->menu = gtk_menu_new (); + gtk_widget_show (p->priv->menu); + + bonobo_window_add_popup (p->priv->window, + GTK_MENU (p->priv->menu), + ephy_embed_popup_get_popup_path (EPHY_EMBED_POPUP (p))); + + gtk_menu_popup (GTK_MENU (p->priv->menu), + NULL, NULL, NULL, NULL, + button, gtk_get_current_event_time ()); +} + diff --git a/embed/ephy-embed-popup-bw.h b/embed/ephy-embed-popup-bw.h new file mode 100644 index 000000000..49f8fecd5 --- /dev/null +++ b/embed/ephy-embed-popup-bw.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_EMBED_POPUP_BW_H +#define EPHY_EMBED_POPUP_BW_H + +#include "ephy-embed-popup.h" +#include <bonobo/bonobo-window.h> + +G_BEGIN_DECLS + +typedef struct EphyEmbedPopupBWClass EphyEmbedPopupBWClass; + +#define EPHY_EMBED_POPUP_BW_TYPE (ephy_embed_popup_bw_get_type ()) +#define EPHY_EMBED_POPUP_BW(obj) (GTK_CHECK_CAST ((obj), EPHY_EMBED_POPUP_BW_TYPE, \ + EphyEmbedPopupBW)) +#define EPHY_EMBED_POPUP_BW_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_EMBED_POPUP_BW_TYPE,\ + EphyEmbedPopupBWClass)) +#define IS_EPHY_EMBED_POPUP_BW(obj) (GTK_CHECK_TYPE ((obj), EPHY_EMBED_POPUP_BW_TYPE)) +#define IS_EPHY_EMBED_POPUP_BW_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_EMBED_POPUP_BW)) +#define EPHY_EMBED_POPUP_BW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + EPHY_EMBED_POPUP_BW_TYPE, EphyEmbedPopupBWClass)) + +typedef struct EphyEmbedPopupBW EphyEmbedPopupBW; +typedef struct EphyEmbedPopupBWPrivate EphyEmbedPopupBWPrivate; + +struct EphyEmbedPopupBW +{ + EphyEmbedPopup parent; + EphyEmbedPopupBWPrivate *priv; +}; + +struct EphyEmbedPopupBWClass +{ + EphyEmbedPopupClass parent_class; +}; + +GType ephy_embed_popup_bw_get_type (void); +EphyEmbedPopupBW * ephy_embed_popup_bw_new (BonoboWindow *window); + +G_END_DECLS + +#endif diff --git a/embed/ephy-embed-popup-control.c b/embed/ephy-embed-popup-control.c new file mode 100644 index 000000000..a74249cc8 --- /dev/null +++ b/embed/ephy-embed-popup-control.c @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2000, 2001, 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-embed-popup-control.h" +#include "ephy-gobject-misc.h" +#include "ephy-bonobo-extensions.h" + +#include <gtk/gtkmain.h> + +enum +{ + PROP_0, + PROP_BONOBO_CONTROL +}; + +struct EphyEmbedPopupControlPrivate +{ + BonoboControl *control; +}; + +static void +ephy_embed_popup_control_class_init (EphyEmbedPopupControlClass *klass); +static void +ephy_embed_popup_control_init (EphyEmbedPopupControl *gep); +static void +ephy_embed_popup_control_finalize (GObject *object); +static void +ephy_embed_popup_control_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void +ephy_embed_popup_control_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void +ephy_embed_popup_control_set_control (EphyEmbedPopupControl *p, + BonoboControl *control); +static void +ephy_embed_popup_control_show_impl (EphyEmbedPopup *p, + EphyEmbed *embed); + +static EphyEmbedPopupClass *parent_class = NULL; + +MAKE_GET_TYPE (ephy_embed_popup_control, "EphyEmbedPopupControl", EphyEmbedPopupControl, + ephy_embed_popup_control_class_init, ephy_embed_popup_control_init, + EPHY_EMBED_POPUP_TYPE); + +static void +ephy_embed_popup_control_class_init (EphyEmbedPopupControlClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = EPHY_EMBED_POPUP_CLASS (g_type_class_peek_parent (klass)); + + object_class->finalize = ephy_embed_popup_control_finalize; + object_class->set_property = ephy_embed_popup_control_set_property; + object_class->get_property = ephy_embed_popup_control_get_property; + + g_object_class_install_property (object_class, + PROP_BONOBO_CONTROL, + g_param_spec_object ("BonoboControl", + "BonoboControl", + "Bonobo control", + BONOBO_TYPE_CONTROL, + G_PARAM_READWRITE)); + + EPHY_EMBED_POPUP_CLASS (klass)->show = ephy_embed_popup_control_show_impl; +} + +static void +ephy_embed_popup_control_init (EphyEmbedPopupControl *gep) +{ + gep->priv = g_new0 (EphyEmbedPopupControlPrivate, 1); + gep->priv->control = NULL; +} + +static void +ephy_embed_popup_control_finalize (GObject *object) +{ + EphyEmbedPopupControl *gep; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_EPHY_EMBED_POPUP_CONTROL (object)); + + gep = EPHY_EMBED_POPUP_CONTROL (object); + + g_return_if_fail (gep->priv != NULL); + + g_free (gep->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +ephy_embed_popup_control_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyEmbedPopupControl *p = EPHY_EMBED_POPUP_CONTROL (object); + + switch (prop_id) + { + case PROP_BONOBO_CONTROL: + ephy_embed_popup_control_set_control (p, g_value_get_object (value)); + break; + } +} + +static void +ephy_embed_popup_control_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyEmbedPopupControl *p = EPHY_EMBED_POPUP_CONTROL (object); + + switch (prop_id) + { + case PROP_BONOBO_CONTROL: + g_value_set_object (value, p->priv->control); + break; + } +} + +static void +ephy_embed_popup_control_set_control (EphyEmbedPopupControl *p, + BonoboControl *control) +{ + p->priv->control = control; +} + +EphyEmbedPopupControl * +ephy_embed_popup_control_new (BonoboControl *control) +{ + EphyEmbedPopupControl *p; + + p = EPHY_EMBED_POPUP_CONTROL (g_object_new (EPHY_EMBED_POPUP_CONTROL_TYPE, + "BonoboControl", control, + NULL)); + + g_return_val_if_fail (p->priv != NULL, NULL); + + return p; +} + +static void +ephy_embed_popup_control_show_impl (EphyEmbedPopup *pp, + EphyEmbed *embed) +{ + EphyEmbedPopupControl *p = EPHY_EMBED_POPUP_CONTROL (pp); + EphyEmbedEvent *event = ephy_embed_popup_get_event (pp); + BonoboUIComponent *uic = bonobo_control_get_popup_ui_component (p->priv->control); + const char *path; + char *path_dst; + guint button; + + ephy_embed_event_get_mouse_button (event, &button); + ephy_embed_popup_set_embed (pp, embed); + path = ephy_embed_popup_get_popup_path (pp); + path_dst = g_strdup_printf ("/popups/button%d", button); + + /* this is a hack because bonobo apis for showing popups are broken */ + ephy_bonobo_replace_path (uic, path, path_dst); + + bonobo_control_do_popup (p->priv->control, button, + gtk_get_current_event_time ()); + + g_free (path_dst); +} + diff --git a/embed/ephy-embed-popup-control.h b/embed/ephy-embed-popup-control.h new file mode 100644 index 000000000..4f45efe5f --- /dev/null +++ b/embed/ephy-embed-popup-control.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2000, 2001, 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_EMBED_POPUP_CONTROL_H +#define EPHY_EMBED_POPUP_CONTROL_H + +#include "ephy-embed-popup.h" +#include <bonobo/bonobo-control.h> + +G_BEGIN_DECLS + +typedef struct EphyEmbedPopupControlClass EphyEmbedPopupControlClass; + +#define EPHY_EMBED_POPUP_CONTROL_TYPE (ephy_embed_popup_control_get_type ()) +#define EPHY_EMBED_POPUP_CONTROL(obj) (GTK_CHECK_CAST ((obj), EPHY_EMBED_POPUP_CONTROL_TYPE, \ + EphyEmbedPopupControl)) +#define EPHY_EMBED_POPUP_CONTROL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), \ + EPHY_EMBED_POPUP_CONTROL_TYPE,\ + EphyEmbedPopupControlClass)) +#define IS_EPHY_EMBED_POPUP_CONTROL(obj) (GTK_CHECK_TYPE ((obj), EPHY_EMBED_POPUP_CONTROL_TYPE)) +#define IS_EPHY_EMBED_POPUP_CONTROL_CLASS(klass)(GTK_CHECK_CLASS_TYPE ((klass), \ + EPHY_EMBED_POPUP_CONTROL)) +#define EPHY_EMBED_POPUP_CONTROL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + EPHY_EMBED_POPUP_CONTROL_TYPE, \ + EphyEmbedPopupControlClass)) + +typedef struct EphyEmbedPopupControl EphyEmbedPopupControl; +typedef struct EphyEmbedPopupControlPrivate EphyEmbedPopupControlPrivate; + +struct EphyEmbedPopupControl +{ + EphyEmbedPopup parent; + EphyEmbedPopupControlPrivate *priv; +}; + +struct EphyEmbedPopupControlClass +{ + EphyEmbedPopupClass parent_class; +}; + +GType ephy_embed_popup_control_get_type (void); +EphyEmbedPopupControl *ephy_embed_popup_control_new (BonoboControl *control); + +G_END_DECLS + +#endif diff --git a/embed/ephy-embed-popup.c b/embed/ephy-embed-popup.c new file mode 100644 index 000000000..4710fa211 --- /dev/null +++ b/embed/ephy-embed-popup.c @@ -0,0 +1,623 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-embed-popup.h" +#include "ephy-embed-event.h" +#include "ephy-embed-utils.h" +#include "ephy-prefs.h" +#include "eel-gconf-extensions.h" +#include "ephy-bonobo-extensions.h" +#include "ephy-file-helpers.h" + +#include <string.h> +#include <bonobo/bonobo-ui-component.h> +#include <gtk/gtkclipboard.h> +#include <libgnome/gnome-exec.h> + +typedef enum +{ + EMBED_POPUP_INPUT, + EMBED_POPUP_DOCUMENT, + EMBED_POPUP_ELEMENT +} EmbedPopupType; + +struct EphyEmbedPopupPrivate +{ + EphyEmbedEvent *event; + EphyEmbed *embed; + EmbedEventContext context; + BonoboUIComponent *ui_component; + char *selection; + EmbedPopupType popup_type; +}; + +static void +ephy_embed_popup_class_init (EphyEmbedPopupClass *klass); +static void +ephy_embed_popup_init (EphyEmbedPopup *gep); +static void +ephy_embed_popup_finalize (GObject *object); +static void +embed_popup_copy_location_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); +static void +embed_popup_copy_email_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); +static void +embed_popup_copy_link_location_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); +static void +embed_popup_download_link_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); +static void +embed_popup_save_image_as_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); +static void +embed_popup_set_image_as_background_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); +static void +embed_popup_copy_image_location_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); +static void +embed_popup_save_page_as_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); +static void +embed_popup_save_background_as_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); +static void +embed_popup_open_frame_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); +static void +embed_popup_reload_frame_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); + +static void +embed_popup_open_image_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); +static void +embed_popup_copy_to_clipboard (EphyEmbedPopup *popup, const char *text); + +static GObjectClass *parent_class = NULL; + +#define DOCUMENT_POPUP_PATH "/popups/EphyEmbedDocumentPopup" +#define ELEMENT_POPUP_PATH "/popups/EphyEmbedElementPopup" +#define INPUT_POPUP_PATH "/popups/EphyEmbedInputPopup" + +#define EPHY_POPUP_NAVIGATION_ITEMS_PLACEHOLDER "/popups/EphyEmbedDocumentPopup/NavigationItems" +#define EPHY_POPUP_LINK_ITEMS_PLACEHOLDER "/popups/EphyEmbedElementPopup/LinkItems" +#define EPHY_POPUP_EMAIL_LINK_ITEMS_PLACEHOLDER "/popups/EphyEmbedElementPopup/EmailLinkItems" +#define EPHY_POPUP_IMAGE_ITEMS_PLACEHOLDER "/popups/EphyEmbedElementPopup/ImageItems" +#define EPHY_POPUP_FRAME_ITEMS_PLACEHOLDER "/popups/EphyEmbedDocumentPopup/FrameItems" +#define EPHY_POPUP_BETWEEN_ELEMENTS1_PLACEHOLDER "/popups/EphyEmbedElementPopup/BetweenElements1" +#define EPHY_POPUP_SAVE_BG_PATH "/commands/DPSaveBackgroundAs" +#define EPHY_POPUP_OPEN_IMAGE_PATH "/commands/EPOpenImage" + +BonoboUIVerb embed_popup_verbs [] = { + BONOBO_UI_VERB ("EPCopyLinkLocation", (BonoboUIVerbFn)embed_popup_copy_link_location_cmd), + BONOBO_UI_VERB ("EPDownloadLink", (BonoboUIVerbFn)embed_popup_download_link_cmd), + BONOBO_UI_VERB ("EPOpenImage", (BonoboUIVerbFn)embed_popup_open_image_cmd), + BONOBO_UI_VERB ("EPSaveImageAs", (BonoboUIVerbFn)embed_popup_save_image_as_cmd), + BONOBO_UI_VERB ("EPSetImageAsBackground", (BonoboUIVerbFn)embed_popup_set_image_as_background_cmd), + BONOBO_UI_VERB ("EPCopyImageLocation", (BonoboUIVerbFn)embed_popup_copy_image_location_cmd), + + BONOBO_UI_VERB ("DPCopyLocation", (BonoboUIVerbFn)embed_popup_copy_location_cmd), + BONOBO_UI_VERB ("EPCopyEmail", (BonoboUIVerbFn)embed_popup_copy_email_cmd), + BONOBO_UI_VERB ("DPSavePageAs", (BonoboUIVerbFn)embed_popup_save_page_as_cmd), + BONOBO_UI_VERB ("DPSaveBackgroundAs", (BonoboUIVerbFn)embed_popup_save_background_as_cmd), + BONOBO_UI_VERB ("DPOpenFrame", (BonoboUIVerbFn)embed_popup_open_frame_cmd), + BONOBO_UI_VERB ("DPReloadFrame", (BonoboUIVerbFn)embed_popup_reload_frame_cmd), + + BONOBO_UI_VERB_END +}; + +GType +ephy_embed_popup_get_type (void) +{ + static GType ephy_embed_popup_type = 0; + + if (ephy_embed_popup_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyEmbedPopupClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_embed_popup_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EphyEmbedPopup), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_embed_popup_init + }; + + + ephy_embed_popup_type = g_type_register_static (G_TYPE_OBJECT, + "EphyEmbedPopup", + &our_info, 0); + } + + return ephy_embed_popup_type; +} + +static void +ephy_embed_popup_class_init (EphyEmbedPopupClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = (GObjectClass *) g_type_class_peek_parent (klass); + + object_class->finalize = ephy_embed_popup_finalize; + + klass->show = NULL; /* abstract */ +} + +static void +ephy_embed_popup_init (EphyEmbedPopup *gep) +{ + gep->priv = g_new0 (EphyEmbedPopupPrivate, 1); + gep->priv->embed = NULL; + gep->priv->event = NULL; + gep->priv->ui_component = NULL; +} + +static void +ephy_embed_popup_finalize (GObject *object) +{ + EphyEmbedPopup *gep; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_EPHY_EMBED_POPUP (object)); + + gep = EPHY_EMBED_POPUP (object); + + g_return_if_fail (gep->priv != NULL); + + if (gep->priv->event) + { + g_object_unref (G_OBJECT (gep->priv->event)); + } + + g_free (gep->priv->selection); + + g_free (gep->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +setup_element_menu (EphyEmbedPopup *p) +{ + gboolean is_link, is_image, is_email_link; + + is_image = p->priv->context & EMBED_CONTEXT_IMAGE; + is_email_link = p->priv->context & EMBED_CONTEXT_EMAIL_LINK; + is_link = (p->priv->context & EMBED_CONTEXT_LINK) && !is_email_link; + + ephy_bonobo_set_hidden (p->priv->ui_component, + EPHY_POPUP_LINK_ITEMS_PLACEHOLDER, + !is_link); + ephy_bonobo_set_hidden (p->priv->ui_component, + EPHY_POPUP_IMAGE_ITEMS_PLACEHOLDER, + !is_image); + ephy_bonobo_set_hidden (p->priv->ui_component, + EPHY_POPUP_EMAIL_LINK_ITEMS_PLACEHOLDER, + !is_email_link); + ephy_bonobo_set_hidden (p->priv->ui_component, + EPHY_POPUP_BETWEEN_ELEMENTS1_PLACEHOLDER, + !is_image || (!is_link && !is_email_link)); +} + +static void +setup_document_menu (EphyEmbedPopup *p) +{ + gboolean is_framed; + GValue *value; + gboolean has_background; + + ephy_embed_event_get_property (p->priv->event, + "framed_page", &value); + is_framed = g_value_get_int (value); + ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(p->priv->ui_component), + EPHY_POPUP_FRAME_ITEMS_PLACEHOLDER, !is_framed); + + has_background = ephy_embed_event_has_property (p->priv->event, + "background_image"); + ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(p->priv->ui_component), + EPHY_POPUP_SAVE_BG_PATH, !has_background); +} + +void +ephy_embed_popup_set_event (EphyEmbedPopup *p, + EphyEmbedEvent *event) +{ + EmbedEventContext context; + + if (p->priv->event) + { + g_object_unref (G_OBJECT (p->priv->event)); + } + + ephy_embed_event_get_context (event, &context); + + p->priv->context = context; + + p->priv->event = event; + g_object_ref (G_OBJECT(event)); + + if ((p->priv->context & EMBED_CONTEXT_LINK) || + (p->priv->context & EMBED_CONTEXT_EMAIL_LINK) || + (p->priv->context & EMBED_CONTEXT_IMAGE)) + { + setup_element_menu (p); + p->priv->popup_type = EMBED_POPUP_ELEMENT; + } + else if (p->priv->context & EMBED_CONTEXT_INPUT) + { + p->priv->popup_type = EMBED_POPUP_INPUT; + } + else + { + setup_document_menu (p); + p->priv->popup_type = EMBED_POPUP_DOCUMENT; + } +} + +void +ephy_embed_popup_set_embed (EphyEmbedPopup *p, + EphyEmbed *e) +{ + p->priv->embed = e; +} + +EphyEmbed * +ephy_embed_popup_get_embed (EphyEmbedPopup *p) +{ + return p->priv->embed; +} + +void +ephy_embed_popup_show (EphyEmbedPopup *p, + EphyEmbed *embed) +{ + EphyEmbedPopupClass *klass = EPHY_EMBED_POPUP_GET_CLASS (p); + return klass->show (p, embed); + +} + +void +ephy_embed_popup_connect_verbs (EphyEmbedPopup *p, + BonoboUIComponent *ui_component) +{ + + p->priv->ui_component = BONOBO_UI_COMPONENT (ui_component); + + bonobo_ui_component_add_verb_list_with_data (BONOBO_UI_COMPONENT(ui_component), + embed_popup_verbs, + p); +} + +EphyEmbedEvent * +ephy_embed_popup_get_event (EphyEmbedPopup *p) +{ + g_return_val_if_fail (IS_EPHY_EMBED_POPUP (p), NULL); + + return p->priv->event; +} + +static void +embed_popup_copy_location_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + char *location; + ephy_embed_get_location (popup->priv->embed, FALSE, + FALSE, &location); + embed_popup_copy_to_clipboard (popup, location); + g_free (location); +} + +static void +embed_popup_copy_email_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + EphyEmbedEvent *info; + const char *location; + GValue *value; + + info = ephy_embed_popup_get_event (popup); + ephy_embed_event_get_property (info, "email", &value); + location = g_value_get_string (value); + embed_popup_copy_to_clipboard (popup, location); +} + +static void +embed_popup_copy_link_location_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + EphyEmbedEvent *info; + const char *location; + GValue *value; + + info = ephy_embed_popup_get_event (popup); + ephy_embed_event_get_property (info, "link", &value); + location = g_value_get_string (value); + embed_popup_copy_to_clipboard (popup, location); +} + +static void +save_property_url (EphyEmbedPopup *popup, + gboolean ask_dest, + gboolean show_progress, + const char *property) +{ + EphyEmbedEvent *info; + const char *location; + GValue *value; + GtkWidget *widget; + GtkWidget *window; + EphyEmbedPersist *persist; + + info = ephy_embed_popup_get_event (popup); + ephy_embed_event_get_property (info, property, &value); + location = g_value_get_string (value); + + widget = GTK_WIDGET (popup->priv->embed); + window = gtk_widget_get_toplevel (widget); + + persist = ephy_embed_persist_new (popup->priv->embed); + + ephy_embed_persist_set_source (persist, location); + + if (show_progress) + { + ephy_embed_persist_set_flags (persist, + EMBED_PERSIST_SHOW_PROGRESS); + } + + ephy_embed_utils_save (window, + CONF_STATE_DOWNLOADING_DIR, + ask_dest, + FALSE, + persist); +} + +const char * +ephy_embed_popup_get_popup_path (EphyEmbedPopup *p) +{ + const char *result = NULL; + + switch (p->priv->popup_type) + { + case EMBED_POPUP_INPUT: + result = INPUT_POPUP_PATH; + break; + case EMBED_POPUP_ELEMENT: + result = ELEMENT_POPUP_PATH; + break; + case EMBED_POPUP_DOCUMENT: + result = DOCUMENT_POPUP_PATH; + break; + } + + return result; +} + +/* commands */ + +static void +embed_popup_download_link_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + save_property_url (popup, + eel_gconf_get_boolean + (CONF_STATE_DOWNLOADING_DIR), + TRUE, "link"); +} + +static void +embed_popup_save_image_as_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + save_property_url (popup, TRUE, FALSE, "image"); +} + +#define CONF_DESKTOP_BG_PICTURE "/desktop/gnome/background/picture_filename" +#define CONF_DESKTOP_BG_TYPE "/desktop/gnome/background/picture_options" + +static void +background_download_completed (EphyEmbedPersist *persist, + gpointer data) +{ + const char *bg; + char *type; + + ephy_embed_persist_get_dest (persist, &bg); + eel_gconf_set_string (CONF_DESKTOP_BG_PICTURE, bg); + + type = eel_gconf_get_string (CONF_DESKTOP_BG_TYPE); + if (type || strcmp (type, "none") == 0) + { + eel_gconf_set_string (CONF_DESKTOP_BG_TYPE, + "wallpaper"); + } + + g_free (type); + + g_object_unref (persist); +} + +static void +embed_popup_set_image_as_background_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + EphyEmbedEvent *info; + const char *location; + char *dest, *base; + GValue *value; + EphyEmbedPersist *persist; + + info = ephy_embed_popup_get_event (popup); + ephy_embed_event_get_property (info, "image", &value); + location = g_value_get_string (value); + + persist = ephy_embed_persist_new (popup->priv->embed); + + base = g_path_get_basename (location); + dest = g_build_filename (ephy_dot_dir (), + base, NULL); + + ephy_embed_persist_set_source (persist, location); + ephy_embed_persist_set_dest (persist, dest); + + ephy_embed_persist_save (persist); + + g_signal_connect (persist, "completed", + G_CALLBACK (background_download_completed), + NULL); + + g_free (dest); + g_free (base); +} + +static void +embed_popup_copy_image_location_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + EphyEmbedEvent *info; + const char *location; + GValue *value; + + info = ephy_embed_popup_get_event (popup); + ephy_embed_event_get_property (info, "image", &value); + location = g_value_get_string (value); + embed_popup_copy_to_clipboard (popup, location); +} + +static void +save_url (EphyEmbedPopup *popup, + gboolean ask_dest, + gboolean show_progress, + const char *url) +{ + GtkWidget *widget; + GtkWidget *window; + EphyEmbedPersist *persist; + + widget = GTK_WIDGET (popup->priv->embed); + window = gtk_widget_get_toplevel (widget); + + persist = ephy_embed_persist_new (popup->priv->embed); + ephy_embed_persist_set_source (persist, url); + + if (show_progress) + { + ephy_embed_persist_set_flags (persist, + EMBED_PERSIST_SHOW_PROGRESS); + } + + ephy_embed_utils_save (window, + CONF_STATE_DOWNLOADING_DIR, + ask_dest, + FALSE, + persist); +} + +static void +embed_popup_save_page_as_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + char *location; + + ephy_embed_get_location (popup->priv->embed, + FALSE, FALSE, &location); + save_url (popup, TRUE, FALSE, location); + g_free (location); +} + +static void +embed_popup_save_background_as_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + save_property_url (popup, TRUE, FALSE, "background_image"); +} + +static void +embed_popup_open_frame_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + char *location; + + ephy_embed_get_location (popup->priv->embed, + FALSE, FALSE, &location); + + ephy_embed_load_url (popup->priv->embed, location); +} + +static void +embed_popup_reload_frame_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + /* FIXME implement */ +} + +static void +embed_popup_open_image_cmd (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + EphyEmbedEvent *info; + const char *location; + GValue *value; + + info = ephy_embed_popup_get_event (popup); + ephy_embed_event_get_property (info, "image", &value); + location = g_value_get_string (value); + + ephy_embed_load_url (popup->priv->embed, location); +} + +static void +embed_popup_copy_to_clipboard (EphyEmbedPopup *popup, const char *text) +{ + gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), + text, -1); + gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY), + text, -1); +} diff --git a/embed/ephy-embed-popup.h b/embed/ephy-embed-popup.h new file mode 100644 index 000000000..6416bdfcd --- /dev/null +++ b/embed/ephy-embed-popup.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_EMBED_POPUP_H +#define EPHY_EMBED_POPUP_H + +#include "ephy-embed.h" +#include <glib-object.h> +#include <bonobo/bonobo-ui-component.h> + +G_BEGIN_DECLS + +typedef struct EphyEmbedPopupClass EphyEmbedPopupClass; + +#define EPHY_EMBED_POPUP_TYPE (ephy_embed_popup_get_type ()) +#define EPHY_EMBED_POPUP(obj) (GTK_CHECK_CAST ((obj), EPHY_EMBED_POPUP_TYPE, EphyEmbedPopup)) +#define EPHY_EMBED_POPUP_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_EMBED_POPUP_TYPE, EphyEmbedPopupClass)) +#define IS_EPHY_EMBED_POPUP(obj) (GTK_CHECK_TYPE ((obj), EPHY_EMBED_POPUP_TYPE)) +#define IS_EPHY_EMBED_POPUP_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_EMBED_POPUP)) +#define EPHY_EMBED_POPUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EPHY_EMBED_POPUP_TYPE, EphyEmbedPopupClass)) + +typedef struct EphyEmbedPopup EphyEmbedPopup; +typedef struct EphyEmbedPopupPrivate EphyEmbedPopupPrivate; + +struct EphyEmbedPopup +{ + GObject parent; + EphyEmbedPopupPrivate *priv; +}; + +struct EphyEmbedPopupClass +{ + GObjectClass parent_class; + + void (*show) (EphyEmbedPopup *p, + EphyEmbed *embed); +}; + + + +/* this class is abstract, don't look for the constructor */ + +GType ephy_embed_popup_get_type (void); +void ephy_embed_popup_connect_verbs (EphyEmbedPopup *p, + BonoboUIComponent *ui_component); +void ephy_embed_popup_set_embed (EphyEmbedPopup *p, + EphyEmbed *e); +EphyEmbed * ephy_embed_popup_get_embed (EphyEmbedPopup *p); +void ephy_embed_popup_set_event (EphyEmbedPopup *p, + EphyEmbedEvent *event); +EphyEmbedEvent * ephy_embed_popup_get_event (EphyEmbedPopup *p); +void ephy_embed_popup_show (EphyEmbedPopup *p, + EphyEmbed *embed); +const char * ephy_embed_popup_get_popup_path (EphyEmbedPopup *p); + +G_END_DECLS + +#endif diff --git a/embed/ephy-embed-prefs.h b/embed/ephy-embed-prefs.h new file mode 100644 index 000000000..8caa14b07 --- /dev/null +++ b/embed/ephy-embed-prefs.h @@ -0,0 +1,46 @@ +#define CONF_NETWORK_SOCKS_PROXY_VERSION "/apps/epiphany/network/socks_proxy_version" +#define CONF_NETWORK_NO_PROXIES_FOR "/apps/epiphany/network/no_proxies_for" +#define CONF_NETWORK_DISK_CACHE "/apps/epiphany/network/disk_cache_size" +#define CONF_NETWORK_MEMORY_CACHE "/apps/epiphany/network/mem_cache_size" +#define CONF_NETWORK_CACHE_COMPARE "/apps/epiphany/network/cache_compare" +#define CONF_NETWORK_USER_AGENT "/apps/epiphany/network/user_agent" +#define CONF_RENDERING_FONT "/apps/epiphany/rendering/font" +#define CONF_RENDERING_FONT_VAR_SIZE "/apps/epiphany/rendering/font_var_size" +#define CONF_RENDERING_FONT_FIXED_SIZE "/apps/epiphany/rendering/font_fixed_size" +#define CONF_RENDERING_FONT_MIN_SIZE "/apps/epiphany/rendering/font_min_size" +#define CONF_RENDERING_LANGUAGE "/apps/epiphany/rendering/lang" +#define CONF_RENDERING_USE_OWN_COLORS "/apps/epiphany/rendering/use_own_colors" +#define CONF_RENDERING_USE_SYSTEM_COLORS "/apps/epiphany/rendering/use_system_colors" +#define CONF_RENDERING_USE_OWN_FONTS "/apps/epiphany/rendering/use_own_fonts" +#define CONF_RENDERING_BG_COLOR "/apps/epiphany/rendering/background_color" +#define CONF_RENDERING_TEXT_COLOR "/apps/epiphany/rendering/text_color" +#define CONF_RENDERING_VISITED_LINKS "/apps/epiphany/rendering/visited_link_color" +#define CONF_RENDERING_UNVISITED_LINKS "/apps/epiphany/rendering/unvisited_link_color" +#define CONF_RENDERING_UNDERLINE_LINKS "/apps/epiphany/rendering/underline_links" +#define CONF_FILTERING_ALLOW_POPUPS "/apps/epiphany/filtering/allow_popups" +#define CONF_FILTERING_IMAGE_LOADING_TYPE "/apps/epiphany/filtering/image_loading_type" +#define CONF_FILTERING_ANIMATE_TYPE "/apps/epiphany/filtering/animate_type" +#define CONF_FILTERING_STATUSBAR_REWRITE "/apps/epiphany/filtering/statusbar_rewrite" +#define CONF_FILTERING_JAVA_ENABLED "/apps/epiphany/filtering/java_enabled" +#define CONF_FILTERING_JAVASCRIPT_ENABLED "/apps/epiphany/filtering/javascript_enabled" +#define CONF_PERSISTENT_COOKIES_BEHAVIOR "/apps/epiphany/filtering/cookie_behavior" +#define CONF_PERSISTENT_COOKIE_WARN "/apps/epiphany/filterin/cookie_warn" +#define CONF_PERSISTENT_COOKIE_LIFETIME "/apps/epiphany/filtering/cookie_lifetime" +#define CONF_PERSISTENT_PASSWORDS_SAVE "/apps/epiphany/filtering/passwords_save" +#define CONF_LANGUAGE_AUTODETECT_CHARSET "/apps/epiphany/rendering/autodetect_charset" +#define CONF_LANGUAGE_DEFAULT_CHARSET "/apps/epiphany/rendering/default_charset" +#define CONF_RENDERING_DEFAULT_FONT "/apps/epiphany/rendering/default_font" +#define CONF_FILTERING_DEFAULT_STATUSBAR "/apps/epiphany/filtering/default_allow_statusbar" + +/* These are defined gnome wide now */ +#define CONF_NETWORK_PROXY_MODE "/system/proxy/mode" +#define CONF_NETWORK_HTTP_PROXY "/system/http_proxy/host" +#define CONF_NETWORK_SSL_PROXY "/system/proxy/secure_host" +#define CONF_NETWORK_FTP_PROXY "/system/proxy/ftp_host" +#define CONF_NETWORK_SOCKS_PROXY "/system/proxy/socks_host" +#define CONF_NETWORK_HTTP_PROXY_PORT "/system/http_proxy/port" +#define CONF_NETWORK_SSL_PROXY_PORT "/system/proxy/secure_port" +#define CONF_NETWORK_FTP_PROXY_PORT "/system/proxy/ftp_port" +#define CONF_NETWORK_SOCKS_PROXY_PORT "/system/proxy/socks_port" +#define CONF_NETWORK_PROXY_AUTO_URL "/system/proxy/autoconfig_url" + diff --git a/embed/ephy-embed-shell.c b/embed/ephy-embed-shell.c new file mode 100644 index 000000000..541e48007 --- /dev/null +++ b/embed/ephy-embed-shell.c @@ -0,0 +1,507 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <config.h> + +#include "ephy-embed-shell.h" +#include "ephy-marshal.h" +#include "ephy-favicon-cache.h" + +#include "mozilla-embed-shell.h" + +#include <string.h> + +enum +{ + NEW_WINDOW, + LAST_SIGNAL +}; + +struct EphyEmbedShellPrivate +{ + EphyHistory *global_history; + DownloaderView *downloader_view; + GList *embeds; + EphyFaviconCache *favicon_cache; +}; + +static void +ephy_embed_shell_class_init (EphyEmbedShellClass *klass); +static void +ephy_embed_shell_init (EphyEmbedShell *ges); +static void +ephy_embed_shell_finalize (GObject *object); +static void +ephy_embed_shell_finalize (GObject *object); + +static EphyHistory * +impl_get_global_history (EphyEmbedShell *shell); +static DownloaderView * +impl_get_downloader_view (EphyEmbedShell *shell); + +static GObjectClass *parent_class = NULL; +static guint ephy_embed_shell_signals[LAST_SIGNAL] = { 0 }; + +EphyEmbedShell *embed_shell; + +GType +ephy_embed_shell_get_type (void) +{ + static GType ephy_embed_shell_type = 0; + + if (ephy_embed_shell_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyEmbedShellClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_embed_shell_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EphyEmbedShell), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_embed_shell_init + }; + + ephy_embed_shell_type = g_type_register_static (G_TYPE_OBJECT, + "EphyEmbedShell", + &our_info, 0); + } + + return ephy_embed_shell_type; +} + +static void +ephy_embed_shell_class_init (EphyEmbedShellClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = (GObjectClass *) g_type_class_peek_parent (klass); + + object_class->finalize = ephy_embed_shell_finalize; + klass->get_downloader_view = impl_get_downloader_view; + klass->get_global_history = impl_get_global_history; + + ephy_embed_shell_signals[NEW_WINDOW] = + g_signal_new ("new_window_orphan", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyEmbedShellClass, new_window), + NULL, NULL, + ephy_marshal_VOID__POINTER_INT, + G_TYPE_NONE, + 2, + G_TYPE_POINTER, + G_TYPE_INT); +} + +static void +ephy_embed_shell_init (EphyEmbedShell *ges) +{ + + /* Singleton, globally accessible */ + embed_shell = ges; + + ges->priv = g_new0 (EphyEmbedShellPrivate, 1); + + ges->priv->global_history = NULL; + ges->priv->downloader_view = NULL; + ges->priv->embeds = NULL; + + ges->priv->favicon_cache = NULL; +} + +static void +ephy_embed_shell_finalize (GObject *object) +{ + EphyEmbedShell *ges; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_EPHY_EMBED_SHELL (object)); + + ges = EPHY_EMBED_SHELL (object); + + g_return_if_fail (ges->priv != NULL); + + if (ges->priv->global_history) + { + g_object_unref (ges->priv->global_history); + } + + if (ges->priv->downloader_view) + { + g_object_remove_weak_pointer + (G_OBJECT(ges->priv->downloader_view), + (gpointer *)&ges->priv->downloader_view); + g_object_unref (ges->priv->downloader_view); + } + + if (ges->priv->favicon_cache) + { + g_object_unref (G_OBJECT (ges->priv->favicon_cache)); + } + + g_free (ges->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +EphyEmbedShell * +ephy_embed_shell_new (const char *type) +{ + if (strcmp (type, "mozilla") == 0) + { + return EPHY_EMBED_SHELL (g_object_new + (MOZILLA_EMBED_SHELL_TYPE, NULL)); + } + + g_assert_not_reached (); + return NULL; +} + +const char *supported_embeds [] = { +#ifdef ENABLE_MOZILLA_EMBED + "mozilla", +#endif +#ifdef ENABLE_GTKHTML_EMBED + "gtkhtml", +#endif + NULL }; + +const char ** +ephy_embed_shell_get_supported (void) +{ + return supported_embeds; +} + +/** + * ephy_embed_shell_get_favicon_cache: + * @gs: a #EphyShell + * + * Returns the favicons cache. + * + * Return value: the favicons cache + **/ +EphyFaviconCache * +ephy_embed_shell_get_favicon_cache (EphyEmbedShell *ees) +{ + if (ees->priv->favicon_cache == NULL) + { + EphyHistory *history; + + history = ephy_embed_shell_get_global_history (ees); + ees->priv->favicon_cache = ephy_favicon_cache_new (history); + } + + return ees->priv->favicon_cache; +} + +void +ephy_embed_shell_add_embed (EphyEmbedShell *ges, + EphyEmbed *embed) +{ + ges->priv->embeds = g_list_append (ges->priv->embeds, embed); +} + +void +ephy_embed_shell_remove_embed (EphyEmbedShell *ges, + EphyEmbed *embed) +{ + ges->priv->embeds = g_list_remove (ges->priv->embeds, embed); +} + +EphyEmbed * +ephy_embed_shell_get_active_embed (EphyEmbedShell *ges) +{ + GList *list = ges->priv->embeds; + + g_return_val_if_fail (ges->priv->embeds != NULL, NULL); + + return EPHY_EMBED (list->data); +} + +GList * +ephy_embed_shell_get_embeds (EphyEmbedShell *ges) +{ + return ges->priv->embeds; +} + +void +ephy_embed_shell_get_capabilities (EphyEmbedShell *shell, + EmbedShellCapabilities *caps) +{ + EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell); + return klass->get_capabilities (shell, caps); +} + +EphyHistory * +ephy_embed_shell_get_global_history (EphyEmbedShell *shell) +{ + EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell); + return klass->get_global_history (shell); +} + +DownloaderView * +ephy_embed_shell_get_downloader_view (EphyEmbedShell *shell) +{ + EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell); + return klass->get_downloader_view (shell); +} + +gresult +ephy_embed_shell_clear_cache (EphyEmbedShell *shell, + CacheType type) +{ + EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell); + return klass->clear_cache (shell, type); +} + +gresult +ephy_embed_shell_set_offline_mode (EphyEmbedShell *shell, + gboolean offline) +{ + EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell); + return klass->set_offline_mode (shell, offline); +} + +gresult +ephy_embed_shell_load_proxy_autoconf (EphyEmbedShell *shell, + const char* url) +{ + EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell); + return klass->load_proxy_autoconf (shell, url); +} + +gresult +ephy_embed_shell_get_charset_titles (EphyEmbedShell *shell, + const char *group, + GList **charsets) +{ + EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell); + return klass->get_charset_titles (shell, group, charsets); +} + +gresult +ephy_embed_shell_get_charset_groups (EphyEmbedShell *shell, + GList **groups) +{ + EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell); + return klass->get_charset_groups (shell, groups); +} + +gresult +ephy_embed_shell_get_font_list (EphyEmbedShell *shell, + const char *langGroup, + const char *fontType, + GList **fontList, + char **default_font) +{ + EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell); + return klass->get_font_list (shell, langGroup, fontType, fontList, + default_font); +} + +gresult +ephy_embed_shell_set_permission (EphyEmbedShell *shell, + const char *url, + PermissionType type, + gboolean allow) +{ + EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell); + return klass->set_permission (shell, url, type, allow); +} + +gresult +ephy_embed_shell_list_permissions (EphyEmbedShell *shell, + PermissionType type, + GList **permissions) +{ + EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell); + return klass->list_permissions (shell, type, permissions); +} + +gresult +ephy_embed_shell_remove_permissions (EphyEmbedShell *shell, + PermissionType type, + GList *permissions) +{ + EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell); + return klass->remove_permissions (shell, type, permissions); +} + +gresult +ephy_embed_shell_list_cookies (EphyEmbedShell *shell, + GList **cookies) +{ + EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell); + return klass->list_cookies (shell, cookies); +} + +gresult +ephy_embed_shell_remove_cookies (EphyEmbedShell *shell, + GList *cookies) +{ + EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell); + return klass->remove_cookies (shell, cookies); +} + +gresult +ephy_embed_shell_list_passwords (EphyEmbedShell *shell, + PasswordType type, + GList **passwords) +{ + EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell); + return klass->list_passwords (shell, type, passwords); +} + +gresult +ephy_embed_shell_remove_passwords (EphyEmbedShell *shell, + GList *passwords, + PasswordType type) +{ + EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell); + return klass->remove_passwords (shell, passwords, type); +} + +/** + * show_file_picker: Shows a file picker. Can be configured to select a + * file or a directory. + * @parentWidget: Parent Widget for file picker. + * @title: Title for file picker. + * @directory: Initial directory to start in. + * @file: Initial filename to show in filepicker. + * @mode: Mode to run filepicker in (modeOpen, modeSave, modeGetFolder) + * @ret_fullpath: On a successful return, will hold the full path to selected + * file or directory. + * @file_formats: an array of FileFormat structures to fill the format chooser + * optionmenu. NULL if not needed. The last item must have + * description == NULL. + * @ret_file_format: where to store the index of the format selected (can be + * NULL) + * returns: TRUE for success, FALSE for failure. + */ + +gresult +ephy_embed_shell_show_file_picker (EphyEmbedShell *shell, + GtkWidget *parentWidget, + const char *title, + const char *directory, + const char *file, + FilePickerMode mode, + char **ret_fullpath, + gboolean *ret_save_content, + FileFormat *file_formats, + int *ret_file_format) +{ + EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell); + return klass->show_file_picker (shell, parentWidget, title, + directory, file, mode, + ret_fullpath, ret_save_content, + file_formats, ret_file_format); +} + +static EphyHistory * +impl_get_global_history (EphyEmbedShell *shell) +{ + if (!shell->priv->global_history) + { + shell->priv->global_history = ephy_history_new (); + } + + return shell->priv->global_history; +} + +static DownloaderView * +impl_get_downloader_view (EphyEmbedShell *shell) +{ + if (!shell->priv->downloader_view) + { + shell->priv->downloader_view = downloader_view_new (); + g_object_add_weak_pointer + (G_OBJECT(shell->priv->downloader_view), + (gpointer *)&shell->priv->downloader_view); + } + + return shell->priv->downloader_view; +} + +gresult +ephy_embed_shell_free_permissions (EphyEmbedShell *shell, + GList *permissions) +{ + GList *l; + + for (l = permissions; l != NULL; l = l->next) + { + PermissionInfo *info = (PermissionInfo *)l->data; + + g_free (info->type); + g_free (info->domain); + g_free (info); + } + + g_list_free (permissions); + + return G_OK; +} + +gresult +ephy_embed_shell_free_cookies (EphyEmbedShell *shell, + GList *cookies) +{ + GList *l; + + for (l = cookies; l != NULL; l = l->next) + { + CookieInfo *info = (CookieInfo *)l->data; + + g_free (info->base.type); + g_free (info->base.domain); + g_free (info->name); + g_free (info->value); + g_free (info->path); + g_free (info->secure); + g_free (info->expire); + g_free (info); + } + + g_list_free (cookies); + + return G_OK; +} + +gresult +ephy_embed_shell_free_passwords (EphyEmbedShell *shell, + GList *passwords) +{ + GList *l; + + for (l = passwords; l != NULL; l = l->next) + { + PasswordInfo *info = (PasswordInfo *)l->data; + g_free (info->host); + g_free (info->username); + g_free (info); + } + + g_list_free (passwords); + + return G_OK; +} + diff --git a/embed/ephy-embed-shell.h b/embed/ephy-embed-shell.h new file mode 100644 index 000000000..3c3b11603 --- /dev/null +++ b/embed/ephy-embed-shell.h @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_EMBED_SHELL_H +#define EPHY_EMBED_SHELL_H + +#include "ephy-embed.h" +#include "ephy-favicon-cache.h" +#include "ephy-history.h" +#include "downloader-view.h" + +#include <glib-object.h> +#include <glib.h> + +G_BEGIN_DECLS + +typedef struct EphyEmbedShellClass EphyEmbedShellClass; + +#define EPHY_EMBED_SHELL_TYPE (ephy_embed_shell_get_type ()) +#define EPHY_EMBED_SHELL(obj) (GTK_CHECK_CAST ((obj), EPHY_EMBED_SHELL_TYPE, EphyEmbedShell)) +#define EPHY_EMBED_SHELL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_EMBED_SHELL_TYPE, EphyEmbedShellClass)) +#define IS_EPHY_EMBED_SHELL(obj) (GTK_CHECK_TYPE ((obj), EPHY_EMBED_SHELL_TYPE)) +#define IS_EPHY_EMBED_SHELL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_EMBED_SHELL)) +#define EPHY_EMBED_SHELL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EPHY_EMBED_SHELL_TYPE, EphyEmbedShellClass)) + +typedef struct EphyEmbedShell EphyEmbedShell; +typedef struct EphyEmbedShellPrivate EphyEmbedShellPrivate; + +extern EphyEmbedShell *embed_shell; + +/** + * FilePickerMode: What mode FilePicker should run in + */ + +typedef enum +{ + modeOpen = 0, + modeSave = 1, + modeGetFolder =2 +} FilePickerMode; + +typedef struct +{ + /* description of the file format */ + gchar *description; + /* tipical sufixes, NULL terminated */ + gchar **extensions; +} FileFormat; + +/** + * BlockedHost: a blocked host + */ +typedef struct +{ + gchar *type; + gchar *domain; +} PermissionInfo; + +/** + * Cookie: the type of cookies + */ +typedef struct +{ + PermissionInfo base; + gchar *name; + gchar *value; + gchar *path; + gchar *secure; + gchar *expire; +} CookieInfo; + +/** + * Password: a password manager entry + */ +typedef struct +{ + gchar *host; + gchar *username; +} PasswordInfo; + +typedef struct +{ + const char *name; + const char *title; +} CharsetInfo; + +/** + * PasswordType: To distinguish actual passwords from blocked password sites + */ +typedef enum +{ + PASSWORD_PASSWORD, + PASSWORD_REJECT +} PasswordType; + +typedef enum +{ + COOKIES_PERMISSION, + IMAGES_PERMISSION +} PermissionType; + +typedef enum +{ + DISK_CACHE = 2, + MEMORY_CACHE = 1 +} CacheType; + +typedef enum +{ + CACHE_CLEAR_CAP = 1 << 0, + OFFLINE_CAP = 1 << 1, + PROXY_AUTOCONF_CAP = 1 << 2, + JAVA_CONSOLE_CAP = 1 << 3, + JS_CONSOLE_CAP = 1 << 4, + CHARSETS_CAP = 1 << 5, + PERMISSIONS_CAP = 1 << 6, + COOKIES_CAP = 1 << 7, + PASSWORDS_CAP = 1 << 8, + FILEPICKER_CAP = 1 << 9 +} EmbedShellCapabilities; + +struct EphyEmbedShell +{ + GObject parent; + EphyEmbedShellPrivate *priv; +}; + +struct EphyEmbedShellClass +{ + GObjectClass parent_class; + + void (* new_window) (EphyEmbedShell *shell, + EphyEmbed **new_embed, + EmbedChromeMask chromemask); + + /* Methods */ + + void (* get_capabilities) (EphyEmbedShell *shell, + EmbedShellCapabilities *caps); + EphyHistory * (* get_global_history) (EphyEmbedShell *shell); + DownloaderView* (* get_downloader_view) (EphyEmbedShell *shell); + gresult (* clear_cache) (EphyEmbedShell *shell, + CacheType type); + gresult (* set_offline_mode) (EphyEmbedShell *shell, + gboolean offline); + gresult (* load_proxy_autoconf) (EphyEmbedShell *shell, + const char* url); + gresult (* show_java_console) (EphyEmbedShell *shell); + gresult (* show_js_console) (EphyEmbedShell *shell); + gresult (* get_charset_groups) (EphyEmbedShell *shell, + GList **groups); + gresult (* get_charset_titles) (EphyEmbedShell *shell, + const char *group, + GList **charsets); + gresult (* get_font_list) (EphyEmbedShell *shell, + const char *langGroup, + const char *fontType, + GList **fontList, + char **default_font); + gresult (* set_permission) (EphyEmbedShell *shell, + const char *url, + PermissionType type, + gboolean allow); + gresult (* list_permissions) (EphyEmbedShell *shell, + PermissionType type, + GList **permissions); + gresult (* remove_permissions) (EphyEmbedShell *shell, + PermissionType type, + GList *permissions); + gresult (* list_cookies) (EphyEmbedShell *shell, + GList **cokies); + gresult (* remove_cookies) (EphyEmbedShell *shell, + GList *cookies); + gresult (* list_passwords) (EphyEmbedShell *shell, + PasswordType type, + GList **passwords); + gresult (* remove_passwords) (EphyEmbedShell *shell, + GList *passwords, + PasswordType type); + gresult (* show_file_picker) (EphyEmbedShell *shell, + GtkWidget *parentWidget, + const char* title, + const char* directory, + const char* file, + FilePickerMode mode, + char **ret_fullpath, + gboolean *ret_save_content, + FileFormat *file_formats, + gint *ret_file_format); +}; + +GType ephy_embed_shell_get_type (void); + +EphyEmbedShell *ephy_embed_shell_new (const char *type); + +EphyFaviconCache *ephy_embed_shell_get_favicon_cache (EphyEmbedShell *ges); + +void ephy_embed_shell_add_embed (EphyEmbedShell *ges, + EphyEmbed *embed); + +void ephy_embed_shell_remove_embed (EphyEmbedShell *ges, + EphyEmbed *embed); + +EphyEmbed *ephy_embed_shell_get_active_embed (EphyEmbedShell *ges); + +GList *ephy_embed_shell_get_embeds (EphyEmbedShell *ges); + +const char **ephy_embed_shell_get_supported (void); + +void ephy_embed_shell_get_capabilities (EphyEmbedShell *shell, + EmbedShellCapabilities *caps); + +EphyHistory *ephy_embed_shell_get_global_history (EphyEmbedShell *shell); + +DownloaderView *ephy_embed_shell_get_downloader_view (EphyEmbedShell *shell); + +gresult ephy_embed_shell_clear_cache (EphyEmbedShell *shell, + CacheType type); + +gresult ephy_embed_shell_set_offline_mode (EphyEmbedShell *shell, + gboolean offline); + +gresult ephy_embed_shell_load_proxy_autoconf (EphyEmbedShell *shell, + const char* url); + +/* Charsets */ +gresult ephy_embed_shell_get_charset_groups (EphyEmbedShell *shell, + GList **groups); + +gresult ephy_embed_shell_get_charset_titles (EphyEmbedShell *shell, + const char *group, + GList **charsets); + +gresult ephy_embed_shell_get_font_list (EphyEmbedShell *shell, + const char *langGroup, + const char *fontType, + GList **fontList, + char **default_font); + +/* Permissions */ +gresult ephy_embed_shell_set_permission (EphyEmbedShell *shell, + const char *url, + PermissionType type, + gboolean allow); + +gresult ephy_embed_shell_list_permissions (EphyEmbedShell *shell, + PermissionType type, + GList **permissions); + +gresult ephy_embed_shell_free_permissions (EphyEmbedShell *shell, + GList *permissions); + +gresult ephy_embed_shell_remove_permissions (EphyEmbedShell *shell, + PermissionType type, + GList *permissions); + +/* Cookies */ +gresult ephy_embed_shell_list_cookies (EphyEmbedShell *shell, + GList **cookies); + +gresult ephy_embed_shell_remove_cookies (EphyEmbedShell *shell, + GList *cookies); + +gresult ephy_embed_shell_free_cookies (EphyEmbedShell *shell, + GList *cookies); + +/* Passwords */ +gresult ephy_embed_shell_list_passwords (EphyEmbedShell *shell, + PasswordType type, + GList **passwords); + +gresult ephy_embed_shell_free_passwords (EphyEmbedShell *shell, + GList *passwords); + +gresult ephy_embed_shell_remove_passwords (EphyEmbedShell *shell, + GList *passwords, + PasswordType type); + +gresult ephy_embed_shell_show_file_picker (EphyEmbedShell *shell, + GtkWidget *parentWidget, + const char *title, + const char *directory, + const char *file, + FilePickerMode mode, + char **ret_fullpath, + gboolean *ret_save_content, + FileFormat *file_formats, + int *ret_file_format); + +G_END_DECLS + +#endif diff --git a/embed/ephy-embed-types.h b/embed/ephy-embed-types.h new file mode 100644 index 000000000..adf32cc6f --- /dev/null +++ b/embed/ephy-embed-types.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef GALEON_EMBED_TYPES_H +#define GALEON_EMBED_TYPES_H + +#include "ephy-types.h" + +G_BEGIN_DECLS + +typedef enum +{ + EMBED_CHROME_NONE = 0, + EMBED_CHROME_DEFAULT = 1 << 0, + EMBED_CHROME_MENUBARON = 1 << 1, + EMBED_CHROME_TOOLBARON = 1 << 2, + EMBED_CHROME_PERSONALTOOLBARON = 1 << 3, + EMBED_CHROME_STATUSBARON = 1 << 4, + EMBED_CHROME_WINDOWRAISED = 1 << 5, + EMBED_CHROME_WINDOWLOWERED = 1 << 6, + EMBED_CHROME_CENTERSCREEN = 1 << 7, + EMBED_CHROME_OPENASDIALOG = 1 << 8, + EMBED_CHROME_OPENASCHROME = 1 << 9, + EMBED_CHROME_OPENASPOPUP = 1 << 10, + EMBED_CHROME_OPENASFULLSCREEN = 1 << 11, + EMBED_CHROME_PPVIEWTOOLBARON = 1 << 12, + EMBED_CHROME_SIDEBARON = 1 << 13 +} EmbedChromeMask; + +G_END_DECLS + +#endif diff --git a/embed/ephy-embed-utils.c b/embed/ephy-embed-utils.c new file mode 100644 index 000000000..0d94e5374 --- /dev/null +++ b/embed/ephy-embed-utils.c @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "eel-gconf-extensions.h" +#include "ephy-embed-utils.h" +#include "ephy-embed-shell.h" +#include "ephy-bonobo-extensions.h" +#include "ephy-gui.h" + +#include <gtk/gtkdialog.h> +#include <gtk/gtkmessagedialog.h> +#include <bonobo/bonobo-i18n.h> +#include <bonobo/bonobo-ui-util.h> +#include <libgnomevfs/gnome-vfs-uri.h> +#include <string.h> + +/** + * ephy_embed_utils_save: + * @window: the referrer window. Used to parent the dialogs. + * @default_dir_pref: the gconf path to persist the directory selected by the user. + * @ask_dest: ask the user the destination path + * @ask_content: show the user an option to save the content + * of the web page (images, javascript...) + * @persist: the #GaleonEmbedPersist referring to the url + * + * Download a save an url asking a location to the user when requested + **/ +void +ephy_embed_utils_save (GtkWidget *window, + const char *default_dir_pref, + gboolean ask_dest, gboolean ask_content, + EphyEmbedPersist *persist) +{ + GnomeVFSURI *uri; + char *retPath = NULL; + char *fileName = NULL; + char *dirName = NULL; + char *retDir; + char *target; + const char *source; + gresult ret; + EphyEmbed *embed; + EmbedPersistFlags flags; + gboolean content; + + g_object_ref (G_OBJECT(persist)); + + ephy_embed_persist_get_flags (persist, &flags); + + ephy_embed_persist_get_source (persist, &source); + + if (source) + { + target = g_strdup (source); + } + else + { + ephy_embed_persist_get_embed (persist, &embed); + g_return_if_fail (embed != NULL); + + ephy_embed_get_location (embed, + flags & + EMBED_PERSIST_MAINDOC, + FALSE, + &target); + } + + /* Get a filename from the target url */ + uri = gnome_vfs_uri_new (target); + if (uri) + { + fileName = gnome_vfs_uri_extract_short_name (uri); + gnome_vfs_uri_unref (uri); + } + + dirName = eel_gconf_get_string (default_dir_pref); + if (dirName && dirName[0] == '\0') + { + g_free (dirName); + dirName = NULL; + } + + if (!dirName || strcmp (dirName,"~") == 0) + { + g_free (dirName); + dirName = g_strdup(g_get_home_dir ()); + } + + /* If we aren't asking for downloading dir, check that we aren't + * overwriting anything. If we are, pop up a warning dialog and show + * the filepicker if the user doesn't want to overwrite the file. + */ + ret = G_FAILED; + if (!ask_dest) + { + retPath = g_build_filename (dirName, fileName, NULL); + if (ephy_gui_confirm_overwrite_file (window, retPath)) + { + ret = G_OK; + } + else + { + g_free (retPath); + ask_dest = TRUE; + } + } + + if (ask_dest) + { + /* show the file picker */ + ret = ephy_embed_shell_show_file_picker + (embed_shell, window, + _("Select the destination filename"), + dirName, fileName, modeSave, &retPath, + ask_content ? &content : NULL, + NULL, NULL); + } + + if (ret == G_OK) + { + uri = gnome_vfs_uri_new (retPath); + g_return_if_fail (uri != NULL); + + retDir = gnome_vfs_uri_extract_dirname (uri); + + if (ask_content && content) + { + flags |= EMBED_PERSIST_SAVE_CONTENT; + ephy_embed_persist_set_flags (persist, + flags); + } + + ephy_embed_persist_set_dest (persist, retPath); + + ephy_embed_persist_save (persist); + + /* set default save dir */ + eel_gconf_set_string (default_dir_pref, + retDir); + + g_free (retDir); + gnome_vfs_uri_unref (uri); + } + + g_object_unref (G_OBJECT(persist)); + + g_free (dirName); + g_free (fileName); + g_free (retPath); +} + +static void +build_group (GString *xml_string, const char *group, int index) +{ + char *tmp; + + tmp = g_strdup_printf ("<submenu label=\"%s\" name=\"CharsetGroup%d\">\n", + group, index); + xml_string = g_string_append (xml_string, tmp); + g_free (tmp); +} + +static void +build_charset (GString *xml_string, CharsetInfo *info, int index) +{ + char *tmp; + char *verb; + + verb = g_strdup_printf ("Charset%d", index); + tmp = g_strdup_printf ("<menuitem label=\"%s\" name=\"%s\" verb=\"%s\"/>\n", + info->title, verb, verb); + xml_string = g_string_append (xml_string, tmp); + + g_free (tmp); + g_free (verb); +} + +static void +add_verbs (BonoboUIComponent *ui_component, + BonoboUIVerbFn fn, GList *verbs) +{ + GList *l; + char verb[15]; + int charset_index = 0; + + for (l = verbs; l != NULL; l = l->next) + { + EncodingMenuData *edata = (EncodingMenuData *)l->data; + + sprintf (verb, "Charset%d", charset_index); + charset_index++; + bonobo_ui_component_add_verb_full + (ui_component, verb, + g_cclosure_new (G_CALLBACK (fn), edata, + (GClosureNotify)g_free)); + } +} + +/** + * ephy_embed_utils_build_charsets_submenu: + * @ui_component: the parent #BonoboUIComponent + * @path: the bonoboui path where to create the submenu. + * It's recommended to use a <placeholder/> + * @fn: callback to report the selected charsets + * @data: the data passed to the callback + * + * Create a charset submenu using bonobo ui. + **/ +void +ephy_embed_utils_build_charsets_submenu (BonoboUIComponent *ui_component, + const char *path, + BonoboUIVerbFn fn, + gpointer data) +{ + GList *groups; + GString *xml_string; + GList *verbs = NULL; + int group_index = 0; + int charset_index = 0; + +#ifdef DEBUG_MARCO + GTimer *timer; + gulong s; + + timer = g_timer_new (); + g_timer_start(timer); +#endif + + g_return_if_fail (ephy_embed_shell_get_charset_groups (embed_shell, &groups) == G_OK); + + xml_string = g_string_new (NULL); + g_string_append (xml_string, "<submenu name=\"Encoding\" _label=\"_Encoding\">"); + + for (; groups != NULL; groups = groups->next) + { + GList *charsets; + const char *group = (const char *)groups->data; + + build_group (xml_string, group, group_index); + + ephy_embed_shell_get_charset_titles (embed_shell, + group, + &charsets); + + for (; charsets != NULL; charsets = charsets->next) + { + CharsetInfo *info = (CharsetInfo *) charsets->data; + EncodingMenuData *edata; + + edata = g_new0 (EncodingMenuData, 1); + edata->encoding = info->name; + edata->data = data; + verbs = g_list_append (verbs, edata); + + build_charset (xml_string, info, charset_index); + charset_index++; + } + + + g_list_free (charsets); + g_string_append (xml_string, "</submenu>"); + group_index++; + } + + g_string_append (xml_string, "</submenu>"); + + bonobo_ui_component_set_translate (ui_component, path, + xml_string->str, NULL); + add_verbs (ui_component, fn, verbs); + + g_list_free (verbs); + g_list_free (groups); + g_string_free (xml_string, TRUE); + +#ifdef DEBUG_MARCO + g_timer_stop (timer); + g_timer_elapsed (timer, &s); + g_print ("Time to build charset menu: %f\n", (double)(s)/1000000); +#endif +} + +/** + * ephy_embed_utils_handlernotfound_dialog_run: + * @parent: the dialog parent window + * + * Show a dialog to warn the user that no application capable + * to open the specified file are found. Used in the downloader + * and in the mime type dialog. + **/ +void +ephy_embed_utils_nohandler_dialog_run (GtkWidget *parent) +{ + GtkWidget *dialog; + + /* FIXME mime db shortcut */ + + dialog = gtk_message_dialog_new + (GTK_WINDOW(parent), + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("No available applications to open " + "the specified file.")); + gtk_dialog_run (GTK_DIALOG(dialog)); + gtk_widget_destroy (dialog); +} diff --git a/embed/ephy-embed-utils.h b/embed/ephy-embed-utils.h new file mode 100644 index 000000000..19f7b72f1 --- /dev/null +++ b/embed/ephy-embed-utils.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_EMBED_UTILS_H +#define EPHY_EMBED_UTILS_H + +#include "ephy-embed-persist.h" + +#include <gtk/gtkwidget.h> +#include <bonobo/bonobo-ui-component.h> + +G_BEGIN_DECLS + +typedef struct +{ + const char *encoding; + gpointer data; +} EncodingMenuData; + +void ephy_embed_utils_save (GtkWidget *window, + const char *default_dir_pref, + gboolean ask_dest, + gboolean ask_content, + EphyEmbedPersist *persist); + +void ephy_embed_utils_build_charsets_submenu (BonoboUIComponent *ui_component, + const char *path, + BonoboUIVerbFn fn, + gpointer data); + +void ephy_embed_utils_nohandler_dialog_run (GtkWidget *parent); + +G_END_DECLS + +#endif diff --git a/embed/ephy-embed.c b/embed/ephy-embed.c new file mode 100644 index 000000000..cb513f95c --- /dev/null +++ b/embed/ephy-embed.c @@ -0,0 +1,608 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "ephy-marshal.h" +#include "ephy-embed.h" + +#include "mozilla-embed.h" +#include "mozilla-embed-shell.h" + +enum +{ + NEW_WINDOW, + LINK_MESSAGE, + FAVICON, + JS_STATUS, + LOCATION, + TITLE, + PROGRESS, + NET_STATE, + VISIBILITY, + DESTROY_BRSR, + OPEN_URI, + SIZE_TO, + DOM_MOUSE_CLICK, + DOM_MOUSE_DOWN, + SECURITY_CHANGE, + ZOOM_CHANGE, + LAST_SIGNAL +}; + +static void +ephy_embed_base_init (gpointer base_class); + +struct EphyEmbedPrivate +{ + gpointer dummy; +}; + +static guint ephy_embed_signals[LAST_SIGNAL] = { 0 }; + +GType +ephy_embed_get_type (void) +{ + static GType ephy_embed_type = 0; + + if (ephy_embed_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyEmbedClass), + ephy_embed_base_init, + NULL, + }; + + ephy_embed_type = g_type_register_static (G_TYPE_INTERFACE, + "EphyEmbed", + &our_info, + (GTypeFlags)0); + } + + return ephy_embed_type; +} + +static void +ephy_embed_base_init (gpointer g_class) +{ + static gboolean initialized = FALSE; + + if (! initialized) + { + ephy_embed_signals[NEW_WINDOW] = + g_signal_new ("ge_new_window", + EPHY_EMBED_TYPE, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EphyEmbedClass, new_window), + NULL, NULL, + ephy_marshal_VOID__POINTER_INT, + G_TYPE_NONE, + 2, + G_TYPE_POINTER, + G_TYPE_INT); + ephy_embed_signals[LINK_MESSAGE] = + g_signal_new ("ge_link_message", + EPHY_EMBED_TYPE, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EphyEmbedClass, link_message), + NULL, NULL, + ephy_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + ephy_embed_signals[FAVICON] = + g_signal_new ("ge_favicon", + EPHY_EMBED_TYPE, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EphyEmbedClass, favicon), + NULL, NULL, + ephy_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + ephy_embed_signals[JS_STATUS] = + g_signal_new ("ge_js_status", + EPHY_EMBED_TYPE, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EphyEmbedClass, js_status), + NULL, NULL, + ephy_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + ephy_embed_signals[LOCATION] = + g_signal_new ("ge_location", + EPHY_EMBED_TYPE, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EphyEmbedClass, location), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + ephy_embed_signals[TITLE] = + g_signal_new ("ge_title", + EPHY_EMBED_TYPE, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EphyEmbedClass, title), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + ephy_embed_signals[PROGRESS] = + g_signal_new ("ge_progress", + EPHY_EMBED_TYPE, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EphyEmbedClass, progress), + NULL, NULL, + ephy_marshal_VOID__STRING_INT_INT, + G_TYPE_NONE, + 3, + G_TYPE_STRING, + G_TYPE_INT, + G_TYPE_INT); + ephy_embed_signals[NET_STATE] = + g_signal_new ("ge_net_state", + EPHY_EMBED_TYPE, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EphyEmbedClass, net_state), + NULL, NULL, + ephy_marshal_VOID__STRING_INT, + G_TYPE_NONE, + 2, + G_TYPE_STRING, + G_TYPE_INT); + ephy_embed_signals[VISIBILITY] = + g_signal_new ("ge_visibility", + EPHY_EMBED_TYPE, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EphyEmbedClass, visibility), + NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, + 1, + G_TYPE_BOOLEAN); + ephy_embed_signals[DESTROY_BRSR] = + g_signal_new ("ge_destroy_brsr", + EPHY_EMBED_TYPE, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EphyEmbedClass, destroy_brsr), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + ephy_embed_signals[OPEN_URI] = + g_signal_new ("ge_open_uri", + EPHY_EMBED_TYPE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyEmbedClass, open_uri), + NULL, NULL, + ephy_marshal_INT__STRING, + G_TYPE_INT, + 1, + G_TYPE_STRING); + ephy_embed_signals[SIZE_TO] = + g_signal_new ("ge_size_to", + EPHY_EMBED_TYPE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyEmbedClass, size_to), + NULL, NULL, + ephy_marshal_VOID__INT_INT, + G_TYPE_NONE, + 2, + G_TYPE_INT, + G_TYPE_INT); + ephy_embed_signals[DOM_MOUSE_DOWN] = + g_signal_new ("ge_dom_mouse_down", + EPHY_EMBED_TYPE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyEmbedClass, dom_mouse_down), + NULL, NULL, + ephy_marshal_INT__OBJECT, + G_TYPE_INT, + 1, + G_TYPE_POINTER); + ephy_embed_signals[DOM_MOUSE_CLICK] = + g_signal_new ("ge_dom_mouse_click", + EPHY_EMBED_TYPE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyEmbedClass, dom_mouse_click), + NULL, NULL, + ephy_marshal_INT__OBJECT, + G_TYPE_INT, + 1, + G_TYPE_POINTER); + ephy_embed_signals[SECURITY_CHANGE] = + g_signal_new ("ge_security_change", + EPHY_EMBED_TYPE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyEmbedClass, security_change), + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, + 1, + G_TYPE_INT); + ephy_embed_signals[ZOOM_CHANGE] = + g_signal_new ("ge_zoom_change", + EPHY_EMBED_TYPE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyEmbedClass, zoom_change), + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, + 1, + G_TYPE_INT); + } +} + +EphyEmbed * +ephy_embed_new (GObject *shell) +{ + if (IS_MOZILLA_EMBED_SHELL (shell)) + { + return EPHY_EMBED (g_object_new + (MOZILLA_EMBED_TYPE, NULL)); + } + + g_assert_not_reached (); + + return NULL; +} + +void +ephy_embed_get_capabilities (EphyEmbed *embed, + EmbedCapabilities *caps) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + klass->get_capabilities (embed, caps); +} + +gresult +ephy_embed_load_url (EphyEmbed *embed, + const char *url) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->load_url (embed, url); +} + +gresult +ephy_embed_stop_load (EphyEmbed *embed) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->stop_load (embed); +} + +gresult +ephy_embed_can_go_back (EphyEmbed *embed) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->can_go_back (embed); +} + +gresult +ephy_embed_can_go_forward (EphyEmbed *embed) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->can_go_forward (embed); +} + +gresult +ephy_embed_can_go_up (EphyEmbed *embed) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->can_go_up (embed); +} + +gresult +ephy_embed_get_go_up_list (EphyEmbed *embed, GSList **l) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->get_go_up_list (embed, l); +} + +gresult +ephy_embed_go_back (EphyEmbed *embed) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->go_back (embed); +} + +gresult +ephy_embed_go_forward (EphyEmbed *embed) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->go_forward (embed); +} + +gresult +ephy_embed_go_up (EphyEmbed *embed) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->go_up (embed); +} + +gresult +ephy_embed_render_data (EphyEmbed *embed, + const char *data, + guint32 len, + const char *base_uri, + const char *mime_type) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->render_data (embed, data, len, base_uri, mime_type); +} + +gresult +ephy_embed_open_stream (EphyEmbed *embed, + const char *base_uri, + const char *mime_type) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->open_stream (embed, base_uri, mime_type); +} + +gresult +ephy_embed_append_data (EphyEmbed *embed, + const char *data, + guint32 len) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->append_data (embed, data, len); +} + +gresult +ephy_embed_close_stream (EphyEmbed *embed) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->close_stream (embed); +} + +gresult +ephy_embed_get_title (EphyEmbed *embed, + char **title) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->get_title (embed, title); +} + +gresult +ephy_embed_get_location (EphyEmbed *embed, + gboolean toplevel, + gboolean requested, + char **location) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->get_location (embed, toplevel, requested, location); +} + +gresult +ephy_embed_reload (EphyEmbed *embed, + EmbedReloadFlags flags) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->reload (embed, flags); +} + +gresult +ephy_embed_copy_page (EphyEmbed *dest, + EphyEmbed *source, + EmbedDisplayType display_type) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (dest); + return klass->copy_page (dest, source, display_type); +} + +gresult +ephy_embed_grab_focus (EphyEmbed *embed) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->grab_focus (embed); +} + +gresult +ephy_embed_get_link_tags (EphyEmbed *embed, + const char *link_type, + GList **tags) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->get_link_tags (embed, link_type, tags); +} + +gresult +ephy_embed_zoom_set (EphyEmbed *embed, + int zoom, + gboolean reflow) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->zoom_set (embed, zoom, reflow); +} + +gresult +ephy_embed_zoom_get (EphyEmbed *embed, + int *zoom) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->zoom_get (embed, zoom); +} + +gresult +ephy_embed_selection_can_cut (EphyEmbed *embed) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->selection_can_cut (embed); +} + +gresult +ephy_embed_selection_can_copy (EphyEmbed *embed) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->selection_can_copy (embed); +} + +gresult +ephy_embed_can_paste (EphyEmbed *embed) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->can_paste (embed); +} + +gresult +ephy_embed_select_all (EphyEmbed *embed) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->select_all (embed); +} + +gresult +ephy_embed_selection_cut (EphyEmbed *embed) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->selection_cut (embed); +} + +gresult +ephy_embed_selection_copy (EphyEmbed *embed) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->selection_copy (embed); +} + +gresult +ephy_embed_paste (EphyEmbed *embed) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->paste (embed); +} + +gresult +ephy_embed_shistory_count (EphyEmbed *embed, + int *count) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->shistory_count (embed, count); +} + +gresult +ephy_embed_shistory_get_nth (EphyEmbed *embed, + int nth, + gboolean is_relative, + char **url, + char **title) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->shistory_get_nth (embed, nth, is_relative, url, title); +} + +gresult +ephy_embed_shistory_get_pos (EphyEmbed *embed, + int *pos) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->shistory_get_pos (embed, pos); +} + +gresult +ephy_embed_shistory_go_nth (EphyEmbed *embed, + int nth) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->shistory_go_nth (embed, nth); +} + +gboolean +ephy_embed_shistory_copy (EphyEmbed *source, + EphyEmbed *dest) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (source); + return klass->shistory_copy (source, dest); +} + +gresult +ephy_embed_scroll (EphyEmbed *embed, + EmbedScrollDirection direction) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->scroll (embed, direction); +} + +gresult +ephy_embed_fine_scroll (EphyEmbed *embed, + int horiz, int vert) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->fine_scroll (embed, horiz, vert); +} + +gresult +ephy_embed_get_security_level (EphyEmbed *embed, + EmbedSecurityLevel *level, + char **description) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->get_security_level (embed, level, description); +} + +gresult +ephy_embed_find (EphyEmbed *embed, + EmbedFindInfo *info) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->find (embed, info); +} + +gresult +ephy_embed_set_charset (EphyEmbed *embed, + const char *charset) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->set_charset (embed, charset); +} + +gresult +ephy_embed_print (EphyEmbed *embed, + EmbedPrintInfo *info) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->print (embed, info); +} + +gresult +ephy_embed_print_preview_close (EphyEmbed *embed) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->print_preview_close (embed); +} + +gresult +ephy_embed_print_preview_num_pages (EphyEmbed *embed, gint *retNum) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->print_preview_num_pages (embed, retNum); +} + +gresult +ephy_embed_print_preview_navigate (EphyEmbed *embed, + EmbedPrintPreviewNavType navType, + gint pageNum) +{ + EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed); + return klass->print_preview_navigate (embed, navType, pageNum); +} + diff --git a/embed/ephy-embed.h b/embed/ephy-embed.h new file mode 100644 index 000000000..1de35d7aa --- /dev/null +++ b/embed/ephy-embed.h @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_EMBED_H +#define EPHY_EMBED_H + +#include "ephy-embed-types.h" +#include "ephy-embed-event.h" + +#include <glib-object.h> +#include <glib.h> +#include <gtk/gtkwidget.h> + +G_BEGIN_DECLS + +typedef struct EphyEmbedClass EphyEmbedClass; + +#define EPHY_EMBED_TYPE (ephy_embed_get_type ()) +#define EPHY_EMBED(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPHY_EMBED_TYPE, EphyEmbed)) +#define EPHY_EMBED_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), EPHY_EMBED_TYPE, EphyEmbedClass)) +#define IS_EPHY_EMBED(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_EMBED_TYPE)) +#define IS_EPHY_EMBED_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), EPHY_EMBED_TYPE)) +#define EPHY_EMBED_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), EPHY_EMBED_TYPE, EphyEmbedClass)) + +typedef struct _EphyEmbed EphyEmbed; + +typedef enum +{ + EMBED_STATE_UNKNOWN = 0, + EMBED_STATE_START = 1 << 0, + EMBED_STATE_REDIRECTING = 1 << 1, + EMBED_STATE_TRANSFERRING = 1 << 2, + EMBED_STATE_NEGOTIATING = 1 << 3, + EMBED_STATE_STOP = 1 << 4, + + EMBED_STATE_IS_REQUEST = 1 << 5, + EMBED_STATE_IS_DOCUMENT = 1 << 6, + EMBED_STATE_IS_NETWORK = 1 << 7, + EMBED_STATE_IS_WINDOW = 1 << 8 +} EmbedState; + +typedef enum +{ + EMBED_CLIPBOARD_CAP = 1 << 0, + EMBED_COOKIES_CAP = 1 << 1, + EMBED_LINKS_CAP = 1 << 2, + EMBED_ZOOM_CAP = 1 << 3, + EMBED_PRINT_CAP = 1 << 6, + EMBED_FIND_CAP = 1 << 7, + EMBED_SCROLL_CAP = 1 << 8, + EMBED_SECURITY_CAP = 1 << 9, + EMBED_CHARSET_CAP = 1 << 10, + EMBED_SHISTORY_CAP = 1 << 11, + EMBED_FINE_SCROLL_CAP = 1 << 12 +} EmbedCapabilities; + +typedef struct +{ + char *modification_date; + + /* lists of hashtables with gvalues */ + GList *images; /* url, alt, title, width, height */ + GList *forms; /* action, type */ + GList *links; /* url, title, type */ + GList *stylesheets; /* url, title */ +} EmbedPageInfo; + +typedef enum +{ + EMBED_RELOAD_NORMAL = 1 << 1, + EMBED_RELOAD_BYPASSCACHE = 1 << 2, + EMBED_RELOAD_BYPASSPROXY = 1 << 3 +} EmbedReloadFlags; + +typedef enum +{ + DISPLAY_AS_SOURCE = 1U, + DISPLAY_NORMAL = 2U +} EmbedDisplayType; + +typedef struct +{ + gchar *search_string; + gboolean backwards; + gboolean wrap; + gboolean entire_word; + gboolean match_case; + gboolean search_frames; + gboolean interactive; +} EmbedFindInfo; + +typedef struct +{ + gboolean print_to_file; + gchar *printer; + gchar *file; + gint paper; + gdouble top_margin; + gdouble bottom_margin; + gdouble left_margin; + gdouble right_margin; + gint pages; + gint from_page; + gint to_page; + gint frame_type; + gint orientation; + gboolean print_color; + + /* + * &T - title + * &U - Document URL + * &D - Date/Time + * &P - Page Number + * &PT - Page Number with total Number of Pages (example: 1 of 34) + * + * So, if headerLeftStr = "&T" the title and the document URL + * will be printed out on the top left-hand side of each page. + */ + gchar *header_left_string; + gchar *header_center_string; + gchar *header_right_string; + gchar *footer_left_string; + gchar *footer_center_string; + gchar *footer_right_string; + + gboolean preview; +} +EmbedPrintInfo; + +typedef enum +{ + PRINTPREVIEW_GOTO_PAGENUM = 0, + PRINTPREVIEW_PREV_PAGE = 1, + PRINTPREVIEW_NEXT_PAGE = 2, + PRINTPREVIEW_HOME = 3, + PRINTPREVIEW_END = 4 +} EmbedPrintPreviewNavType; + +typedef enum +{ + EMBED_SCROLL_UP, + EMBED_SCROLL_DOWN, + EMBED_SCROLL_LEFT, + EMBED_SCROLL_RIGHT +} EmbedScrollDirection; + +typedef enum +{ + STATE_IS_UNKNOWN, + STATE_IS_INSECURE, + STATE_IS_BROKEN, + STATE_IS_SECURE_MED, + STATE_IS_SECURE_LOW, + STATE_IS_SECURE_HIGH +} EmbedSecurityLevel; + +struct EphyEmbedClass +{ + GTypeInterface base_iface; + + void (* favicon) (EphyEmbed *embed, + const char *location); + void (* link_message) (EphyEmbed *embed, + const char *link); + void (* js_status) (EphyEmbed *embed, + const char *status); + void (* location) (EphyEmbed *embed); + void (* title) (EphyEmbed *embed); + void (* progress) (EphyEmbed *embed, + const char *uri, + gint curprogress, + gint maxprogress); + void (* net_state) (EphyEmbed *embed, + const char *uri, + EmbedState state); + void (* new_window) (EphyEmbed *embed, + EphyEmbed **new_embed, + EmbedChromeMask chromemask); + void (* visibility) (EphyEmbed *embed, + gboolean visibility); + void (* destroy_brsr) (EphyEmbed *embed); + gint (* open_uri) (EphyEmbed *embed, + const char *uri); + void (* size_to) (EphyEmbed *embed, + gint width, + gint height); + gint (* dom_mouse_click) (EphyEmbed *embed, + EphyEmbedEvent *event); + gint (* dom_mouse_down) (EphyEmbed *embed, + EphyEmbedEvent *event); + void (* security_change) (EphyEmbed *embed, + EmbedSecurityLevel level); + void (* zoom_change) (EphyEmbed *embed, + guint new_zoom); + + /* Methods */ + void (* get_capabilities) (EphyEmbed *embed, + EmbedCapabilities *caps); + gresult (* load_url) (EphyEmbed *embed, + const char *url); + gresult (* stop_load) (EphyEmbed *embed); + gresult (* can_go_back) (EphyEmbed *embed); + gresult (* can_go_forward) (EphyEmbed *embed); + gresult (* can_go_up) (EphyEmbed *embed); + gresult (* get_go_up_list) (EphyEmbed *embed, GSList **l); + gresult (* go_back) (EphyEmbed *embed); + gresult (* go_forward) (EphyEmbed *embed); + gresult (* go_up) (EphyEmbed *embed); + gresult (* render_data) (EphyEmbed *embed, + const char *data, + guint32 len, + const char *base_uri, + const char *mime_type); + gresult (* open_stream) (EphyEmbed *embed, + const char *base_uri, + const char *mime_type); + gresult (* append_data) (EphyEmbed *embed, + const char *data, + guint32 len); + gresult (* close_stream) (EphyEmbed *embed); + gresult (* get_title) (EphyEmbed *embed, + char **title); + gresult (* get_location) (EphyEmbed *embed, + gboolean toplevel, + gboolean requested, + char **location); + gresult (* reload) (EphyEmbed *embed, + EmbedReloadFlags flags); + gresult (* copy_page) (EphyEmbed *dest, + EphyEmbed *source, + EmbedDisplayType display_type); + gresult (* grab_focus) (EphyEmbed *embed); + gresult (* get_link_tags) (EphyEmbed *embed, + const char *link_type, + GList **tags); + gresult (* zoom_set) (EphyEmbed *embed, + int zoom, + gboolean reflow); + gresult (* zoom_get) (EphyEmbed *embed, + int *zoom); + gresult (* selection_can_cut) (EphyEmbed *embed); + gresult (* selection_can_copy) (EphyEmbed *embed); + gresult (* can_paste) (EphyEmbed *embed); + gresult (* selection_cut) (EphyEmbed *embed); + gresult (* selection_copy) (EphyEmbed *embed); + gresult (* paste) (EphyEmbed *embed); + gresult (* select_all) (EphyEmbed *embed); + gresult (* shistory_count) (EphyEmbed *embed, + int *count); + gresult (* shistory_get_nth) (EphyEmbed *embed, + int nth, + gboolean is_relative, + char **url, + char **title); + gresult (* shistory_get_pos) (EphyEmbed *embed, + int *pos); + gresult (* shistory_go_nth) (EphyEmbed *embed, + int nth); + gboolean (* shistory_copy) (EphyEmbed *source, + EphyEmbed *dest); + gresult (* scroll) (EphyEmbed *embed, + EmbedScrollDirection direction); + gresult (* fine_scroll) (EphyEmbed *embed, + int horiz, int vert); + gresult (* get_security_level) (EphyEmbed *embed, + EmbedSecurityLevel *level, + char **description); + gresult (* find) (EphyEmbed *embed, + EmbedFindInfo *find); + gresult (* print) (EphyEmbed *embed, + EmbedPrintInfo *info); + gresult (* print_preview_close) (EphyEmbed *embed); + gresult (* print_preview_num_pages) (EphyEmbed *embed, + gint *retNum); + gresult (* print_preview_navigate) (EphyEmbed *embed, + EmbedPrintPreviewNavType navType, + gint pageNum); + gresult (* set_charset) (EphyEmbed *embed, + const char *charset); +}; + +GType ephy_embed_get_type (void); + +/* Base */ + +EphyEmbed *ephy_embed_new (GObject *shell); + +void ephy_embed_get_capabilities (EphyEmbed *embed, + EmbedCapabilities *caps); + +gresult ephy_embed_load_url (EphyEmbed *embed, + const char *url); + +gresult ephy_embed_stop_load (EphyEmbed *embed); + +gresult ephy_embed_can_go_back (EphyEmbed *embed); + +gresult ephy_embed_can_go_forward (EphyEmbed *embed); + +gresult ephy_embed_can_go_up (EphyEmbed *embed); + +gresult ephy_embed_get_go_up_list (EphyEmbed *embed, + GSList **l); + +gresult ephy_embed_go_back (EphyEmbed *embed); + +gresult ephy_embed_go_forward (EphyEmbed *embed); + +gresult ephy_embed_go_up (EphyEmbed *embed); + +gresult ephy_embed_render_data (EphyEmbed *embed, + const char *data, + guint32 len, + const char *base_uri, + const char *mime_type); + +gresult ephy_embed_open_stream (EphyEmbed *embed, + const char *base_uri, + const char *mime_type); + +gresult ephy_embed_append_data (EphyEmbed *embed, + const char *data, + guint32 len); + +gresult ephy_embed_close_stream (EphyEmbed *embed); + +gresult ephy_embed_get_title (EphyEmbed *embed, + char **title); + +gresult ephy_embed_get_location (EphyEmbed *embed, + gboolean toplevel, + gboolean requested, + char **location); + +gresult ephy_embed_reload (EphyEmbed *embed, + EmbedReloadFlags flags); + +gresult ephy_embed_copy_page (EphyEmbed *dest, + EphyEmbed *source, + EmbedDisplayType display_type); + +gresult ephy_embed_grab_focus (EphyEmbed *embed); + +/* Link */ +gresult ephy_embed_get_favicon_location (EphyEmbed *embed, + char **url); + +gresult ephy_embed_get_link_tags (EphyEmbed *embed, + const char *link_type, + GList **tags); + +/* Zoom */ +gresult ephy_embed_zoom_set (EphyEmbed *embed, + int zoom, + gboolean reflow); + +gresult ephy_embed_zoom_get (EphyEmbed *embed, + int *zoom); + +/* Clipboard */ +gresult ephy_embed_selection_can_cut (EphyEmbed *embed); + +gresult ephy_embed_selection_can_copy (EphyEmbed *embed); + +gresult ephy_embed_can_paste (EphyEmbed *embed); + +gresult ephy_embed_selection_cut (EphyEmbed *embed); + +gresult ephy_embed_selection_copy (EphyEmbed *embed); + +gresult ephy_embed_paste (EphyEmbed *embed); + +gresult ephy_embed_select_all (EphyEmbed *embed); + +/* Session history */ +gresult ephy_embed_shistory_count (EphyEmbed *embed, + int *count); + +gresult ephy_embed_shistory_get_nth (EphyEmbed *embed, + int nth, + gboolean is_relative, + char **url, + char **title); + +gresult ephy_embed_shistory_get_pos (EphyEmbed *embed, + int *pos); + +gresult ephy_embed_shistory_go_nth (EphyEmbed *embed, + int nth); + +gboolean ephy_embed_shistory_copy (EphyEmbed *source, + EphyEmbed *dest); + +/* Utils */ + +gresult ephy_embed_scroll (EphyEmbed *embed, + EmbedScrollDirection direction); + +gresult ephy_embed_fine_scroll (EphyEmbed *embed, + int horiz, int vert); + +gresult ephy_embed_get_security_level (EphyEmbed *embed, + EmbedSecurityLevel *level, + char **description); + +gresult ephy_embed_find (EphyEmbed *embed, + EmbedFindInfo *find); + +gresult ephy_embed_set_charset (EphyEmbed *embed, + const char *charset); + +/* Printing */ + +gresult ephy_embed_print (EphyEmbed *embed, + EmbedPrintInfo *info); + +gresult ephy_embed_print_preview_close (EphyEmbed *embed); + +gresult ephy_embed_print_preview_num_pages (EphyEmbed *embed, + gint *retNum); + +gresult ephy_embed_print_preview_navigate (EphyEmbed *embed, + EmbedPrintPreviewNavType navType, + gint pageNum); + +G_END_DECLS + +#endif diff --git a/embed/ephy-favicon-cache.c b/embed/ephy-favicon-cache.c new file mode 100644 index 000000000..fd3c4192b --- /dev/null +++ b/embed/ephy-favicon-cache.c @@ -0,0 +1,367 @@ +/* + * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <libgnomevfs/gnome-vfs-uri.h> +#include <libxml/tree.h> +#include <string.h> +#include <gtk/gtktoolbar.h> +#include <gtk/gtkstock.h> +#include <sys/stat.h> + +#include "ephy-embed-persist.h" +#include "ephy-file-helpers.h" +#include "ephy-favicon-cache.h" + +static void ephy_favicon_cache_class_init (EphyFaviconCacheClass *klass); +static void ephy_favicon_cache_init (EphyFaviconCache *ma); +static void ephy_favicon_cache_finalize (GObject *object); +static void ephy_favicon_cache_insert (EphyFaviconCache *cache, + const char *url, + const char *pixbuf_location); +static char *ephy_favicon_cache_dest (EphyFaviconCache *cache, + const char *url); +static void favicon_download_completed_cb (EphyEmbedPersist *persist, + EphyFaviconCache *cache); + +struct EphyFaviconCachePrivate +{ + char *directory; + + GdkPixbuf *default_pixbuf; + EphyHistory *history; +}; + +enum +{ + CHANGED, + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_HISTORY +}; + +enum +{ + EPHY_NODE_PAGE_PROP_FAVICON = 100 +}; + +static guint ephy_favicon_cache_signals[LAST_SIGNAL] = { 0 }; + +static GObjectClass *parent_class = NULL; + +GType +ephy_favicon_cache_get_type (void) +{ + static GType ephy_favicon_cache_type = 0; + + if (ephy_favicon_cache_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyFaviconCacheClass), + NULL, + NULL, + (GClassInitFunc) ephy_favicon_cache_class_init, + NULL, + NULL, + sizeof (EphyFaviconCache), + 0, + (GInstanceInitFunc) ephy_favicon_cache_init + }; + + ephy_favicon_cache_type = g_type_register_static (G_TYPE_OBJECT, + "EphyFaviconCache", + &our_info, 0); + } + + return ephy_favicon_cache_type; +} + +static void +ephy_favicon_cache_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyFaviconCache *cache = EPHY_FAVICON_CACHE (object); + + switch (prop_id) + { + case PROP_HISTORY: + cache->priv->history = g_value_get_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ephy_favicon_cache_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyFaviconCache *cache = EPHY_FAVICON_CACHE (object); + + switch (prop_id) + { + case PROP_HISTORY: + g_value_set_object (value, cache->priv->history); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} +static void +ephy_favicon_cache_class_init (EphyFaviconCacheClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_favicon_cache_finalize; + object_class->set_property = ephy_favicon_cache_set_property; + object_class->get_property = ephy_favicon_cache_get_property; + + g_object_class_install_property (object_class, + PROP_HISTORY, + g_param_spec_object ("History", + "Source history", + "Source history", + EPHY_HISTORY_TYPE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + + ephy_favicon_cache_signals[CHANGED] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyFaviconCacheClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); +} + +static void +ephy_favicon_cache_init (EphyFaviconCache *cache) +{ + GtkWidget *dummy; + + cache->priv = g_new0 (EphyFaviconCachePrivate, 1); + + cache->priv->directory = g_build_filename (ephy_dot_dir (), + "favicon_cache/", + NULL); + + if (g_file_test (cache->priv->directory, G_FILE_TEST_IS_DIR) == FALSE) + { + if (g_file_test (cache->priv->directory, G_FILE_TEST_EXISTS)) + { + g_error ("Please remove %s to continue.", cache->priv->directory); + } + + if (mkdir (cache->priv->directory, 488) != 0) + { + g_error ("Couldn't mkdir %s.", cache->priv->directory); + } + } + + dummy = gtk_toolbar_new (); + cache->priv->default_pixbuf = gtk_widget_render_icon (dummy, + GTK_STOCK_JUMP_TO, + GTK_ICON_SIZE_MENU, NULL); + gtk_widget_destroy (dummy); +} + +static void +ephy_favicon_cache_finalize (GObject *object) +{ + EphyFaviconCache *cache; + + g_return_if_fail (object != NULL); + g_return_if_fail (EPHY_IS_FAVICON_CACHE (object)); + + cache = EPHY_FAVICON_CACHE (object); + + g_return_if_fail (cache->priv != NULL); + + g_object_unref (G_OBJECT (cache->priv->default_pixbuf)); + + g_object_unref (cache->priv->history); + + g_free (cache->priv->directory); + + g_free (cache->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +EphyFaviconCache * +ephy_favicon_cache_new (EphyHistory *history) +{ + EphyFaviconCache *cache; + + cache = EPHY_FAVICON_CACHE (g_object_new (EPHY_TYPE_FAVICON_CACHE, + "History", history, + NULL)); + + g_return_val_if_fail (cache->priv != NULL, NULL); + + return cache; +} + +GdkPixbuf * +ephy_favicon_cache_lookup (EphyFaviconCache *cache, + const char *url) +{ + GdkPixbuf *ret; + + g_return_val_if_fail (EPHY_IS_FAVICON_CACHE (cache), NULL); + + if (url == NULL) + { + return cache->priv->default_pixbuf; + } + + ret = ephy_favicon_cache_lookup_direct (cache, url); + + if (ret == NULL) + { + return cache->priv->default_pixbuf; + } + + return ret; +} + +GdkPixbuf * +ephy_favicon_cache_lookup_direct (EphyFaviconCache *cache, + const char *cache_url) +{ + GdkPixbuf *pixbuf; + EphyNode *node; + const char *pix_file; + + node = ephy_history_get_page (cache->priv->history, cache_url); + if (node == NULL) return NULL; + + pix_file = ephy_node_get_property_string + (node, EPHY_NODE_PAGE_PROP_FAVICON); + if (pix_file == NULL) return NULL; + + pixbuf = gdk_pixbuf_new_from_file (pix_file, NULL); + g_return_val_if_fail (pixbuf != NULL, NULL); + + if (gdk_pixbuf_get_width (pixbuf) > 16 || + gdk_pixbuf_get_height (pixbuf) > 16) + { + GdkPixbuf *scaled = gdk_pixbuf_scale_simple (pixbuf, 16, 16, + GDK_INTERP_NEAREST); + g_object_unref (G_OBJECT (pixbuf)); + pixbuf = scaled; + } + + return pixbuf; +} + +static void +ephy_favicon_cache_insert (EphyFaviconCache *cache, + const char *url, + const char *pixbuf_location) +{ + EphyNode *node; + GValue value = { 0, }; + + node = ephy_history_get_page (cache->priv->history, url); + g_return_if_fail (node != NULL); + + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, pixbuf_location); + ephy_node_set_property (node, EPHY_NODE_PAGE_PROP_FAVICON, + &value); + g_value_unset (&value); + + g_signal_emit (G_OBJECT (cache), ephy_favicon_cache_signals[CHANGED], 0, url); +} + +static char * +ephy_favicon_cache_dest (EphyFaviconCache *cache, const char *url) +{ + char *slashpos, *dest, *my_url; + + my_url = g_strdup (url); + + while ((slashpos = strstr (my_url, "/")) != NULL) + *slashpos = '_'; + + dest = g_build_filename (cache->priv->directory, my_url, NULL); + + g_free (my_url); + + return dest; +} + +void +ephy_favicon_cache_insert_from_url (EphyFaviconCache *cache, + const char *url, + const char *favicon_url) +{ + EphyEmbedPersist *persist; + char *dest; + + g_return_if_fail (EPHY_IS_FAVICON_CACHE (cache)); + g_return_if_fail (url != NULL); + g_return_if_fail (favicon_url != NULL); + + dest = ephy_favicon_cache_dest (cache, favicon_url); + g_return_if_fail (dest != NULL); + + persist = ephy_embed_persist_new (NULL); + + ephy_embed_persist_set_max_size (persist, 100); + ephy_embed_persist_set_flags (persist, EMBED_PERSIST_BYPASSCACHE); + ephy_embed_persist_set_source (persist, favicon_url); + ephy_embed_persist_set_dest (persist, dest); + + g_object_set_data_full (G_OBJECT (persist), "url", g_strdup (url), g_free); + g_object_set_data_full (G_OBJECT (persist), "favicon", dest, g_free); + + g_signal_connect (G_OBJECT (persist), + "completed", + G_CALLBACK (favicon_download_completed_cb), + cache); + + ephy_embed_persist_save (persist); +} + +static void +favicon_download_completed_cb (EphyEmbedPersist *persist, + EphyFaviconCache *cache) +{ + ephy_favicon_cache_insert (cache, + g_object_get_data (G_OBJECT (persist), "url"), + g_object_get_data (G_OBJECT (persist), "favicon")); + + g_object_unref (G_OBJECT (persist)); +} diff --git a/embed/ephy-favicon-cache.h b/embed/ephy-favicon-cache.h new file mode 100644 index 000000000..ff4ebcd56 --- /dev/null +++ b/embed/ephy-favicon-cache.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-history.h" + +#include <glib-object.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#ifndef __EPHY_FAVICON_CACHE_H +#define __EPHY_FAVICON_CACHE_H + +G_BEGIN_DECLS + +#define EPHY_TYPE_FAVICON_CACHE (ephy_favicon_cache_get_type ()) +#define EPHY_FAVICON_CACHE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_FAVICON_CACHE, EphyFaviconCache)) +#define EPHY_FAVICON_CACHE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EPHY_TYPE_FAVICON_CACHE, EphyFaviconCacheClass)) +#define EPHY_IS_FAVICON_CACHE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_FAVICON_CACHE)) +#define EPHY_IS_FAVICON_CACHE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_FAVICON_CACHE)) +#define EPHY_FAVICON_CACHE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_FAVICON_CACHE, EphyFaviconCacheClass)) + +typedef struct EphyFaviconCachePrivate EphyFaviconCachePrivate; + +typedef struct +{ + GObject parent; + + EphyFaviconCachePrivate *priv; +} EphyFaviconCache; + +typedef struct +{ + GObjectClass parent_class; + + void (*changed) (EphyFaviconCache *cache, const char *url); +} EphyFaviconCacheClass; + +GType ephy_favicon_cache_get_type (void); + +EphyFaviconCache *ephy_favicon_cache_new (EphyHistory *history); + +GdkPixbuf *ephy_favicon_cache_lookup (EphyFaviconCache *cache, + const char *url); + +GdkPixbuf *ephy_favicon_cache_lookup_direct (EphyFaviconCache *cache, + const char *cache_url); + +void ephy_favicon_cache_insert_from_url (EphyFaviconCache *cache, + const char *url, + const char *favicon_url); + +G_END_DECLS + +#endif /* __EPHY_FAVICON_CACHE_H */ diff --git a/embed/ephy-favicon.c b/embed/ephy-favicon.c new file mode 100644 index 000000000..6670c20ab --- /dev/null +++ b/embed/ephy-favicon.c @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <gtk/gtkwidget.h> +#include <string.h> + +#include "ephy-favicon.h" +#include "ephy-embed-shell.h" + +static void ephy_favicon_class_init (EphyFaviconClass *klass); +static void ephy_favicon_init (EphyFavicon *ma); +static void ephy_favicon_finalize (GObject *object); +static void ephy_favicon_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ephy_favicon_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void ephy_favicon_update_image (EphyFavicon *favicon); +static void cache_changed_cb (EphyFaviconCache *cache, + const char *url, + EphyFavicon *favicon); + +struct EphyFaviconPrivate +{ + EphyFaviconCache *cache; + + char *url; +}; + +enum +{ + PROP_0, + PROP_CACHE, + PROP_URL +}; + +enum +{ + CHANGED, + LAST_SIGNAL +}; + +static guint ephy_favicon_signals[LAST_SIGNAL] = { 0 }; + +static GObjectClass *parent_class = NULL; + +GType +ephy_favicon_get_type (void) +{ + static GType ephy_favicon_type = 0; + + if (ephy_favicon_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyFaviconClass), + NULL, + NULL, + (GClassInitFunc) ephy_favicon_class_init, + NULL, + NULL, + sizeof (EphyFavicon), + 0, + (GInstanceInitFunc) ephy_favicon_init + }; + + ephy_favicon_type = g_type_register_static (GTK_TYPE_IMAGE, + "EphyFavicon", + &our_info, 0); + } + + return ephy_favicon_type; +} + +static void +ephy_favicon_class_init (EphyFaviconClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_favicon_finalize; + + object_class->set_property = ephy_favicon_set_property; + object_class->get_property = ephy_favicon_get_property; + + g_object_class_install_property (object_class, + PROP_CACHE, + g_param_spec_object ("cache", + "Favicon cache", + "Favicon cache", + EPHY_TYPE_FAVICON_CACHE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, + PROP_URL, + g_param_spec_string ("url", + "Associated URL", + "Associated URL", + NULL, + G_PARAM_READWRITE)); + + ephy_favicon_signals[CHANGED] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyFaviconClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +static void +ephy_favicon_init (EphyFavicon *ma) +{ + ma->priv = g_new0 (EphyFaviconPrivate, 1); + + gtk_widget_set_size_request (GTK_WIDGET (ma), 16, 16); +} + +static void +ephy_favicon_finalize (GObject *object) +{ + EphyFavicon *ma; + + g_return_if_fail (object != NULL); + g_return_if_fail (EPHY_IS_FAVICON (object)); + + ma = EPHY_FAVICON (object); + + g_return_if_fail (ma->priv != NULL); + + g_free (ma->priv->url); + + g_free (ma->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +ephy_favicon_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyFavicon *favicon = EPHY_FAVICON (object); + + switch (prop_id) + { + case PROP_CACHE: + favicon->priv->cache = g_value_get_object (value); + + g_signal_connect_object (G_OBJECT (favicon->priv->cache), + "changed", + G_CALLBACK (cache_changed_cb), + favicon, + 0); + + ephy_favicon_update_image (favicon); + break; + case PROP_URL: + g_free (favicon->priv->url); + favicon->priv->url = g_strdup (g_value_get_string (value)); + + ephy_favicon_update_image (favicon); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ephy_favicon_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyFavicon *favicon = EPHY_FAVICON (object); + + switch (prop_id) + { + case PROP_CACHE: + g_value_set_object (value, favicon->priv->cache); + break; + case PROP_URL: + g_value_set_string (value, favicon->priv->url); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +GtkWidget * +ephy_favicon_new (const char *url) +{ + EphyFavicon *favicon; + EphyFaviconCache *cache = ephy_embed_shell_get_favicon_cache (embed_shell); + + g_return_val_if_fail (EPHY_IS_FAVICON_CACHE (cache), NULL); + + favicon = EPHY_FAVICON (g_object_new (EPHY_TYPE_FAVICON, + "cache", cache, + "url", url, + NULL)); + + g_return_val_if_fail (favicon->priv != NULL, NULL); + + return GTK_WIDGET (favicon); +} + +void +ephy_favicon_set_url (EphyFavicon *favicon, + const char *url) +{ + g_return_if_fail (EPHY_IS_FAVICON (favicon)); + + g_object_set (G_OBJECT (favicon), + "url", url, + NULL); +} + +const char * +ephy_favicon_get_url (EphyFavicon *favicon) +{ + char *url; + + g_return_val_if_fail (EPHY_IS_FAVICON (favicon), NULL); + + g_object_get (G_OBJECT (favicon), + "url", &url, + NULL); + + return (const char *) url; +} + +static void +cache_changed_cb (EphyFaviconCache *cache, + const char *url, + EphyFavicon *favicon) +{ + if (strcmp (url, favicon->priv->url) == 0) + { + ephy_favicon_update_image (favicon); + } +} + +static void +ephy_favicon_update_image (EphyFavicon *favicon) +{ + GdkPixbuf *pixbuf; + + g_return_if_fail (EPHY_IS_FAVICON_CACHE (favicon->priv->cache)); + + pixbuf = ephy_favicon_cache_lookup (favicon->priv->cache, + favicon->priv->url); + + gtk_image_set_from_pixbuf (GTK_IMAGE (favicon), pixbuf); + + g_signal_emit (G_OBJECT (favicon), ephy_favicon_signals[CHANGED], 0); +} diff --git a/embed/ephy-favicon.h b/embed/ephy-favicon.h new file mode 100644 index 000000000..97206cde5 --- /dev/null +++ b/embed/ephy-favicon.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <glib-object.h> +#include <gtk/gtkimage.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "ephy-favicon-cache.h" + +#ifndef __EPHY_FAVICON_H +#define __EPHY_FAVICON_H + +G_BEGIN_DECLS + +#define EPHY_TYPE_FAVICON (ephy_favicon_get_type ()) +#define EPHY_FAVICON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_FAVICON, EphyFavicon)) +#define EPHY_FAVICON_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EPHY_TYPE_FAVICON, EphyFaviconClass)) +#define EPHY_IS_FAVICON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_FAVICON)) +#define EPHY_IS_FAVICON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_FAVICON)) +#define EPHY_FAVICON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_FAVICON, EphyFaviconClass)) + +typedef struct EphyFaviconPrivate EphyFaviconPrivate; + +typedef struct +{ + GtkImage parent; + + EphyFaviconPrivate *priv; +} EphyFavicon; + +typedef struct +{ + GtkImageClass parent_class; + + void (*changed) (EphyFavicon *favicon); +} EphyFaviconClass; + +GType ephy_favicon_get_type (void); + +GtkWidget *ephy_favicon_new (const char *url); + +void ephy_favicon_set_url (EphyFavicon *favicon, + const char *url); + +const char *ephy_favicon_get_url (EphyFavicon *favicon); + +G_END_DECLS + +#endif /* __EPHY_FAVICON_H */ diff --git a/embed/ephy-history.c b/embed/ephy-history.c new file mode 100644 index 000000000..c106b274a --- /dev/null +++ b/embed/ephy-history.c @@ -0,0 +1,644 @@ +/* + * Copyright (C) 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-history.h" +#include "ephy-file-helpers.h" +#include "ephy-autocompletion-source.h" + +#include <time.h> +#include <string.h> +#include <libgnome/gnome-i18n.h> +#include <libgnomevfs/gnome-vfs-uri.h> + +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +#define EPHY_HISTORY_XML_VERSION "0.1" + +struct EphyHistoryPrivate +{ + char *xml_file; + EphyNode *hosts; + EphyNode *pages; + EphyNode *last_page; + GHashTable *hosts_hash; + GStaticRWLock *hosts_hash_lock; + GHashTable *pages_hash; + GStaticRWLock *pages_hash_lock; +}; + +enum +{ + ADD, + UPDATE, + REMOVE, + VISITED, + LAST_SIGNAL +}; + +static void +ephy_history_class_init (EphyHistoryClass *klass); +static void +ephy_history_init (EphyHistory *tab); +static void +ephy_history_finalize (GObject *object); +static void +ephy_history_autocompletion_source_init (EphyAutocompletionSourceIface *iface); + +static GObjectClass *parent_class = NULL; + +static guint ephy_history_signals[LAST_SIGNAL] = { 0 }; + +GType +ephy_history_get_type (void) +{ + static GType ephy_history_type = 0; + + if (ephy_history_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyHistoryClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_history_class_init, + NULL, + NULL, /* class_data */ + sizeof (EphyHistory), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_history_init + }; + + static const GInterfaceInfo autocompletion_source_info = + { + (GInterfaceInitFunc) ephy_history_autocompletion_source_init, + NULL, + NULL + }; + + ephy_history_type = g_type_register_static (G_TYPE_OBJECT, + "EphyHistory", + &our_info, 0); + + g_type_add_interface_static (ephy_history_type, + EPHY_TYPE_AUTOCOMPLETION_SOURCE, + &autocompletion_source_info); + } + + return ephy_history_type; +} + +static void +ephy_history_autocompletion_source_set_basic_key (EphyAutocompletionSource *source, + const gchar *basic_key) +{ + /* nothing to do here */ +} + +static void +ephy_history_autocompletion_source_foreach (EphyAutocompletionSource *source, + const gchar *current_text, + EphyAutocompletionSourceForeachFunc func, + gpointer data) +{ + GPtrArray *children; + int i; + EphyHistory *eb = EPHY_HISTORY (source); + + children = ephy_node_get_children (eb->priv->pages); + for (i = 0; i < children->len; i++) + { + EphyNode *kid; + const char *url, *title; + + kid = g_ptr_array_index (children, i); + url = ephy_node_get_property_string + (kid, EPHY_NODE_PAGE_PROP_LOCATION); + title = ephy_node_get_property_string + (kid, EPHY_NODE_PAGE_PROP_TITLE); + + func (source, url, + url, url, FALSE, + FALSE, 0, data); + } + ephy_node_thaw (eb->priv->pages); +} + +static void +ephy_history_emit_data_changed (EphyHistory *eb) +{ + g_signal_emit_by_name (eb, "data-changed"); +} + +static void +ephy_history_autocompletion_source_init (EphyAutocompletionSourceIface *iface) +{ + iface->foreach = ephy_history_autocompletion_source_foreach; + iface->set_basic_key = ephy_history_autocompletion_source_set_basic_key; +} + +static void +ephy_history_class_init (EphyHistoryClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_history_finalize; + + ephy_history_signals[VISITED] = + g_signal_new ("visited", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EphyHistoryClass, visited), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); +} + +static void +ephy_history_load (EphyHistory *eb) +{ + xmlDocPtr doc; + xmlNodePtr root, child; + char *tmp; + + if (g_file_test (eb->priv->xml_file, G_FILE_TEST_EXISTS) == FALSE) + return; + + doc = xmlParseFile (eb->priv->xml_file); + g_assert (doc != NULL); + + root = xmlDocGetRootElement (doc); + + tmp = xmlGetProp (root, "version"); + g_assert (tmp != NULL && strcmp (tmp, EPHY_HISTORY_XML_VERSION) == 0); + g_free (tmp); + + for (child = root->children; child != NULL; child = child->next) + { + EphyNode *node; + + node = ephy_node_new_from_xml (child); + } + + xmlFreeDoc (doc); +} + +static void +ephy_history_save (EphyHistory *eb) +{ + xmlDocPtr doc; + xmlNodePtr root; + GPtrArray *children; + int i; + + DEBUG_MSG (("Saving history\n")); + + /* save nodes to xml */ + xmlIndentTreeOutput = TRUE; + doc = xmlNewDoc ("1.0"); + + root = xmlNewDocNode (doc, NULL, "ephy_history", NULL); + xmlSetProp (root, "version", EPHY_HISTORY_XML_VERSION); + xmlDocSetRootElement (doc, root); + + children = ephy_node_get_children (eb->priv->hosts); + for (i = 0; i < children->len; i++) + { + EphyNode *kid; + + kid = g_ptr_array_index (children, i); + + ephy_node_save_to_xml (kid, root); + } + ephy_node_thaw (eb->priv->hosts); + + children = ephy_node_get_children (eb->priv->pages); + for (i = 0; i < children->len; i++) + { + EphyNode *kid; + + kid = g_ptr_array_index (children, i); + + ephy_node_save_to_xml (kid, root); + } + ephy_node_thaw (eb->priv->pages); + + xmlSaveFormatFile (eb->priv->xml_file, doc, 1); +} + +static void +hosts_added_cb (EphyNode *node, + EphyNode *child, + EphyHistory *eb) +{ + g_static_rw_lock_writer_lock (eb->priv->hosts_hash_lock); + + g_hash_table_insert (eb->priv->hosts_hash, + (char *) ephy_node_get_property_string (child, EPHY_NODE_PAGE_PROP_TITLE), + child); + + g_static_rw_lock_writer_unlock (eb->priv->hosts_hash_lock); +} + +static void +hosts_removed_cb (EphyNode *node, + EphyNode *child, + EphyHistory *eb) +{ + g_static_rw_lock_writer_lock (eb->priv->hosts_hash_lock); + + g_hash_table_remove (eb->priv->hosts_hash, + ephy_node_get_property_string (child, EPHY_NODE_PAGE_PROP_TITLE)); + + g_static_rw_lock_writer_unlock (eb->priv->hosts_hash_lock); +} + +static void +pages_added_cb (EphyNode *node, + EphyNode *child, + EphyHistory *eb) +{ + g_static_rw_lock_writer_lock (eb->priv->pages_hash_lock); + + g_hash_table_insert (eb->priv->pages_hash, + (char *) ephy_node_get_property_string (child, EPHY_NODE_PAGE_PROP_LOCATION), + child); + + g_static_rw_lock_writer_unlock (eb->priv->pages_hash_lock); +} + +static void +pages_removed_cb (EphyNode *node, + EphyNode *child, + EphyHistory *eb) +{ + g_static_rw_lock_writer_lock (eb->priv->pages_hash_lock); + + g_hash_table_remove (eb->priv->pages_hash, + ephy_node_get_property_string (child, EPHY_NODE_PAGE_PROP_LOCATION)); + + g_static_rw_lock_writer_unlock (eb->priv->pages_hash_lock); +} + +static void +ephy_history_init (EphyHistory *eb) +{ + eb->priv = g_new0 (EphyHistoryPrivate, 1); + + eb->priv->xml_file = g_build_filename (ephy_dot_dir (), + "ephy-history.xml", + NULL); + + ephy_node_system_init (); + + eb->priv->pages_hash = g_hash_table_new (g_str_hash, + g_str_equal); + eb->priv->pages_hash_lock = g_new0 (GStaticRWLock, 1); + g_static_rw_lock_init (eb->priv->pages_hash_lock); + + eb->priv->hosts_hash = g_hash_table_new (g_str_hash, + g_str_equal); + eb->priv->hosts_hash_lock = g_new0 (GStaticRWLock, 1); + g_static_rw_lock_init (eb->priv->hosts_hash_lock); + + /* Bookmarks */ + eb->priv->pages = ephy_node_new (); + ephy_node_ref (eb->priv->pages); + g_signal_connect_object (G_OBJECT (eb->priv->pages), + "child_added", + G_CALLBACK (pages_added_cb), + G_OBJECT (eb), + 0); + g_signal_connect_object (G_OBJECT (eb->priv->pages), + "child_removed", + G_CALLBACK (pages_removed_cb), + G_OBJECT (eb), + 0); + + /* Hosts */ + eb->priv->hosts = ephy_node_new (); + ephy_node_ref (eb->priv->hosts); + g_signal_connect_object (G_OBJECT (eb->priv->hosts), + "child_added", + G_CALLBACK (hosts_added_cb), + G_OBJECT (eb), + 0); + g_signal_connect_object (G_OBJECT (eb->priv->hosts), + "child_removed", + G_CALLBACK (hosts_removed_cb), + G_OBJECT (eb), + 0); + + ephy_history_load (eb); + ephy_history_emit_data_changed (eb); +} + +static void +ephy_history_finalize (GObject *object) +{ + EphyHistory *eb; + + g_return_if_fail (IS_EPHY_HISTORY (object)); + + eb = EPHY_HISTORY (object); + + g_return_if_fail (eb->priv != NULL); + + ephy_history_save (eb); + + ephy_node_unref (eb->priv->pages); + ephy_node_unref (eb->priv->hosts); + + g_hash_table_destroy (eb->priv->pages_hash); + g_static_rw_lock_free (eb->priv->pages_hash_lock); + g_hash_table_destroy (eb->priv->hosts_hash); + g_static_rw_lock_free (eb->priv->hosts_hash_lock); + + g_free (eb->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +EphyHistory * +ephy_history_new () +{ + EphyHistory *tab; + + tab = EPHY_HISTORY (g_object_new (EPHY_HISTORY_TYPE, NULL)); + + return tab; +} + +static EphyNode * +ephy_history_add_host (EphyHistory *eh, const char *url) +{ + EphyNode *host; + GnomeVFSURI *vfs_uri = NULL; + const char *host_name = NULL; + char *host_location = NULL; + GTime now; + GValue value = { 0, }; + int visits; + + now = time (NULL); + + /* Build an host name */ + if (!g_ascii_strncasecmp (url, "file://", 7)) + { + host_name = _("Local files"); + host_location = g_strdup ("file://"); + } + else + { + vfs_uri = gnome_vfs_uri_new (url); + if (vfs_uri != NULL) + { + host_name = gnome_vfs_uri_get_host_name (vfs_uri); + host_location = gnome_vfs_uri_to_string + (vfs_uri, GNOME_VFS_URI_HIDE_FRAGMENT_IDENTIFIER); + } + + if (host_name == NULL) + { + host_name = _("Other"); + host_location = g_strdup ("about:blank"); + } + } + + g_static_rw_lock_reader_lock (eh->priv->hosts_hash_lock); + host = g_hash_table_lookup (eh->priv->hosts_hash, host_name); + g_static_rw_lock_reader_unlock (eh->priv->hosts_hash_lock); + + if (!host) + { + host = ephy_node_new (); + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, host_name); + ephy_node_set_property (host, EPHY_NODE_PAGE_PROP_TITLE, + &value); + g_value_unset (&value); + + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, host_location); + ephy_node_set_property (host, EPHY_NODE_PAGE_PROP_LOCATION, + &value); + g_value_unset (&value); + + g_value_init (&value, G_TYPE_INT); + g_value_set_int (&value, now); + ephy_node_set_property (host, EPHY_NODE_PAGE_PROP_FIRST_VISIT, + &value); + g_value_unset (&value); + + ephy_node_add_child (eh->priv->hosts, host); + } + + visits = ephy_node_get_property_int + (host, EPHY_NODE_PAGE_PROP_VISITS); + if (visits < 0) visits = 0; + visits++; + + g_value_init (&value, G_TYPE_INT); + g_value_set_int (&value, visits); + ephy_node_set_property (host, EPHY_NODE_PAGE_PROP_VISITS, + &value); + g_value_unset (&value); + + g_value_init (&value, G_TYPE_INT); + g_value_set_int (&value, now); + ephy_node_set_property (host, EPHY_NODE_PAGE_PROP_LAST_VISIT, + &value); + g_value_unset (&value); + + if (vfs_uri) + { + gnome_vfs_uri_unref (vfs_uri); + } + + g_free (host_location); + + return host; +} + +static void +ephy_history_visited (EphyHistory *eh, EphyNode *node) +{ + GValue value = { 0, }; + GTime now; + int visits; + const char *url; + + now = time (NULL); + + url = ephy_node_get_property_string + (node, EPHY_NODE_PAGE_PROP_LOCATION); + + visits = ephy_node_get_property_int + (node, EPHY_NODE_PAGE_PROP_VISITS); + if (visits < 0) visits = 0; + visits++; + + g_value_init (&value, G_TYPE_INT); + g_value_set_int (&value, visits); + ephy_node_set_property (node, EPHY_NODE_PAGE_PROP_VISITS, + &value); + g_value_unset (&value); + + g_value_init (&value, G_TYPE_INT); + g_value_set_int (&value, now); + ephy_node_set_property (node, EPHY_NODE_PAGE_PROP_LAST_VISIT, + &value); + if (visits == 1) + { + ephy_node_set_property + (node, EPHY_NODE_PAGE_PROP_FIRST_VISIT, &value); + } + g_value_unset (&value); + + eh->priv->last_page = node; + + g_signal_emit (G_OBJECT (eh), ephy_history_signals[VISITED], 0, url); + ephy_history_emit_data_changed (eh); +} + +int +ephy_history_get_page_visits (EphyHistory *gh, + const char *url) +{ + EphyNode *node; + int visits; + + node = ephy_history_get_page (gh, url); + + visits = ephy_node_get_property_int + (node, EPHY_NODE_PAGE_PROP_VISITS); + if (visits < 0) visits = 0; + visits++; + + return visits; +} + +void +ephy_history_add_page (EphyHistory *eb, + const char *url) +{ + EphyNode *bm, *node, *host; + GValue value = { 0, }; + + node = ephy_history_get_page (eb, url); + if (node) + { + ephy_history_visited (eb, node); + return; + } + + bm = ephy_node_new (); + + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, url); + ephy_node_set_property (bm, EPHY_NODE_PAGE_PROP_LOCATION, + &value); + ephy_node_set_property (bm, EPHY_NODE_PAGE_PROP_TITLE, + &value); + g_value_unset (&value); + + host = ephy_history_add_host (eb, url); + + g_value_init (&value, G_TYPE_INT); + g_value_set_int (&value, ephy_node_get_id (host)); + ephy_node_set_property (bm, EPHY_NODE_PAGE_PROP_HOST_ID, + &value); + g_value_unset (&value); + + ephy_history_visited (eb, bm); + + ephy_node_add_child (host, bm); + ephy_node_add_child (eb->priv->pages, bm); +} + +EphyNode * +ephy_history_get_page (EphyHistory *eb, + const char *url) +{ + EphyNode *node; + + g_static_rw_lock_reader_lock (eb->priv->pages_hash_lock); + node = g_hash_table_lookup (eb->priv->pages_hash, url); + g_static_rw_lock_reader_unlock (eb->priv->pages_hash_lock); + + return node; +} + +gboolean +ephy_history_is_page_visited (EphyHistory *gh, + const char *url) +{ + return (ephy_history_get_page (gh, url) != NULL); +} + +void +ephy_history_set_page_title (EphyHistory *gh, + const char *url, + const char *title) +{ + EphyNode *node; + + node = ephy_history_get_page (gh, url); + if (node) + { + GValue value = { 0, }; + + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, title); + ephy_node_set_property + (node, EPHY_NODE_PAGE_PROP_TITLE, &value); + g_value_unset (&value); + } +} + +void +ephy_history_clear (EphyHistory *gh) +{ + ephy_node_unref (gh->priv->hosts); + ephy_history_save (gh); +} + +EphyNode * +ephy_history_get_hosts (EphyHistory *eb) +{ + return eb->priv->hosts; +} + +EphyNode * +ephy_history_get_pages (EphyHistory *eb) +{ + return eb->priv->pages; +} + +const char * +ephy_history_get_last_page (EphyHistory *gh) +{ + if (gh->priv->last_page == NULL) return NULL; + + return ephy_node_get_property_string + (gh->priv->last_page, EPHY_NODE_PAGE_PROP_LOCATION); +} diff --git a/embed/ephy-history.h b/embed/ephy-history.h new file mode 100644 index 000000000..641ab6d7c --- /dev/null +++ b/embed/ephy-history.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_HISTORY_H +#define EPHY_HISTORY_H + +#include <glib-object.h> + +#include "ephy-node.h" + +G_BEGIN_DECLS + +typedef struct EphyHistoryClass EphyHistoryClass; + +#define EPHY_HISTORY_TYPE (ephy_history_get_type ()) +#define EPHY_HISTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPHY_HISTORY_TYPE, EphyHistory)) +#define EPHY_HISTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EPHY_HISTORY_TYPE, EphyHistoryClass)) +#define IS_EPHY_HISTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_HISTORY_TYPE)) +#define IS_EPHY_HISTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EPHY_HISTORY_TYPE)) + +typedef struct EphyHistory EphyHistory; +typedef struct EphyHistoryPrivate EphyHistoryPrivate; + +enum +{ + EPHY_NODE_PAGE_PROP_TITLE = 2, + EPHY_NODE_PAGE_PROP_LOCATION = 3, + EPHY_NODE_PAGE_PROP_VISITS = 4, + EPHY_NODE_PAGE_PROP_LAST_VISIT = 5, + EPHY_NODE_PAGE_PROP_FIRST_VISIT = 6, + EPHY_NODE_PAGE_PROP_HOST_ID = 7 +}; + +struct EphyHistory +{ + GObject parent; + EphyHistoryPrivate *priv; +}; + +struct EphyHistoryClass +{ + GObjectClass parent_class; + + void (* visited) (const char *url); +}; + +GType ephy_history_get_type (void); + +EphyHistory *ephy_history_new (void); + +EphyNode *ephy_history_get_hosts (EphyHistory *gh); + +EphyNode *ephy_history_get_pages (EphyHistory *gh); + +EphyNode *ephy_history_get_page (EphyHistory *gh, + const char *url); + +void ephy_history_add_page (EphyHistory *gh, + const char *url); + +gboolean ephy_history_is_page_visited (EphyHistory *gh, + const char *url); + +int ephy_history_get_page_visits (EphyHistory *gh, + const char *url); + +void ephy_history_set_page_title (EphyHistory *gh, + const char *url, + const char *title); + +const char *ephy_history_get_last_page (EphyHistory *gh); + +void ephy_history_clear (EphyHistory *gh); + +G_END_DECLS + +#endif diff --git a/embed/find-dialog.c b/embed/find-dialog.c new file mode 100755 index 000000000..7b96e86c1 --- /dev/null +++ b/embed/find-dialog.c @@ -0,0 +1,431 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "find-dialog.h" +#include "ephy-prefs.h" +#include "ephy-embed.h" + +#define CONF_FIND_MATCH_CASE "/apps/epiphany/find/match_case" +#define CONF_FIND_AUTOWRAP "/apps/epiphany/find/autowrap" +#define CONF_FIND_WORD "/apps/epiphany/find/word" + +static void find_dialog_class_init (FindDialogClass *klass); +static void find_dialog_init (FindDialog *dialog); +static void find_dialog_finalize (GObject *object); + +static void +impl_construct (EphyDialog *dialog, + const EphyDialogProperty *properties, + const char *file, + const char *name); +static void +impl_destruct (EphyDialog *dialog); +static void +impl_show (EphyDialog *dialog); + + +/* Glade callbacks */ +void find_close_button_clicked_cb (GtkWidget *button, EphyDialog *dialog); +void find_next_button_clicked_cb (GtkWidget *button, EphyDialog *dialog); +void find_prev_button_clicked_cb (GtkWidget *button, EphyDialog *dialog); +void find_entry_activate_cb (GtkWidget *editable, EphyDialog *dialog); +void find_entry_changed_cb (GtkWidget *editable, EphyDialog *dialog); +void find_check_toggled_cb (GtkWidget *toggle, EphyDialog *dialog); + +static GObjectClass *parent_class = NULL; + +struct FindDialogPrivate +{ + EmbedFindInfo *properties; + gboolean can_go_prev; + gboolean can_go_next; + gboolean constructed; +}; + +enum +{ + SEARCH, + LAST_SIGNAL +}; + +enum +{ + MATCH_CASE_PROP, + AUTOWRAP_PROP, + WORD_PROP, + BACK_BUTTON, + FORWARD_BUTTON +}; + +static const +EphyDialogProperty properties [] = +{ + { MATCH_CASE_PROP, "case_check", CONF_FIND_MATCH_CASE, PT_NORMAL, NULL }, + { AUTOWRAP_PROP, "wrap_check", CONF_FIND_AUTOWRAP, PT_NORMAL, NULL }, + { WORD_PROP, "find_entry", CONF_FIND_WORD, PT_NORMAL, NULL }, + { BACK_BUTTON, "back_button", NULL, PT_NORMAL, NULL }, + { FORWARD_BUTTON, "forward_button", NULL, PT_NORMAL, NULL }, + { -1, NULL, NULL } +}; + +static guint find_dialog_signals[LAST_SIGNAL] = { 0 }; + +GType +find_dialog_get_type (void) +{ + static GType find_dialog_type = 0; + + if (find_dialog_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (FindDialogClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) find_dialog_class_init, + NULL, + NULL, /* class_data */ + sizeof (FindDialog), + 0, /* n_preallocs */ + (GInstanceInitFunc) find_dialog_init + }; + + find_dialog_type = g_type_register_static (EPHY_EMBED_DIALOG_TYPE, + "FindDialog", + &our_info, 0); + } + + return find_dialog_type; + +} + +static void +find_dialog_class_init (FindDialogClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + EphyDialogClass *ephy_dialog_class; + + parent_class = g_type_class_peek_parent (klass); + ephy_dialog_class = EPHY_DIALOG_CLASS (klass); + + object_class->finalize = find_dialog_finalize; + + ephy_dialog_class->construct = impl_construct; + ephy_dialog_class->destruct = impl_destruct; + ephy_dialog_class->show = impl_show; + + find_dialog_signals[SEARCH] = + g_signal_new ("search", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (FindDialogClass, search), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +static void +find_update_nav (EphyDialog *dialog) +{ + GtkWidget *forward_button; + GtkWidget *back_button; + + g_signal_emit (G_OBJECT (dialog), find_dialog_signals[SEARCH], 0); + + if (!FIND_DIALOG(dialog)->priv->constructed) return; + + forward_button = ephy_dialog_get_control (dialog, FORWARD_BUTTON); + gtk_widget_set_sensitive (forward_button, + FIND_DIALOG(dialog)->priv->can_go_next); + + back_button = ephy_dialog_get_control (dialog, BACK_BUTTON); + gtk_widget_set_sensitive (back_button, + FIND_DIALOG(dialog)->priv->can_go_prev); +} + +void static +ensure_constructed (FindDialog *dialog) +{ + if (!dialog->priv->constructed) + { + ephy_dialog_construct (EPHY_DIALOG(dialog), + properties, + "epiphany.glade", + "find_dialog"); + } +} + +static void +find_dialog_init (FindDialog *dialog) +{ + dialog->priv = g_new0 (FindDialogPrivate, 1); + + dialog->priv->properties = NULL; + dialog->priv->can_go_prev = TRUE; + dialog->priv->can_go_next = TRUE; + dialog->priv->constructed = FALSE; + + ensure_constructed (dialog); +} + +static void +impl_construct (EphyDialog *dialog, + const EphyDialogProperty *properties, + const char *file, + const char *name) +{ + FIND_DIALOG(dialog)->priv->constructed = TRUE; + + EPHY_DIALOG_CLASS (parent_class)->construct (dialog, properties, file, name); +} + +static void +impl_destruct (EphyDialog *dialog) +{ + FIND_DIALOG(dialog)->priv->constructed = FALSE; + + EPHY_DIALOG_CLASS (parent_class)->destruct (dialog); +} + +static void +impl_show (EphyDialog *dialog) +{ + FindDialog *find_dialog = FIND_DIALOG(dialog); + ensure_constructed (find_dialog); + + find_dialog->priv->can_go_prev = TRUE; + find_dialog->priv->can_go_next = TRUE; + find_update_nav (dialog); + + /* Focus the text entry. This will correctly select or leave + * unselected the existing text in the entry depending on the + * 'gtk-entry-select-on-focus = 0 / 1' setting in user's gtkrc. + */ + gtk_widget_grab_focus (ephy_dialog_get_control (dialog, WORD_PROP)); + + EPHY_DIALOG_CLASS (parent_class)->show (dialog); +} + +static void +find_dialog_finalize (GObject *object) +{ + FindDialog *dialog; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_FIND_DIALOG (object)); + + dialog = FIND_DIALOG (object); + + g_return_if_fail (dialog->priv != NULL); + + g_free (dialog->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +EphyDialog * +find_dialog_new (EphyEmbed *embed) +{ + FindDialog *dialog; + + dialog = FIND_DIALOG (g_object_new (FIND_DIALOG_TYPE, + "EphyEmbed", embed, + NULL)); + + return EPHY_DIALOG(dialog); +} + +EphyDialog * +find_dialog_new_with_parent (GtkWidget *window, + EphyEmbed *embed) +{ + FindDialog *dialog; + + dialog = FIND_DIALOG (g_object_new (FIND_DIALOG_TYPE, + "EphyEmbed", embed, + "ParentWindow", window, + NULL)); + + return EPHY_DIALOG(dialog); +} + +gboolean +find_dialog_can_go_next (FindDialog *dialog) +{ + return dialog->priv->can_go_next; +} + +gboolean +find_dialog_can_go_prev (FindDialog *dialog) +{ + return dialog->priv->can_go_prev; +} + +void +find_dialog_go_next (FindDialog *dialog, + gboolean interactive) +{ + gresult result; + EphyEmbed *embed; + + if (!find_dialog_can_go_next (dialog)) return; + + dialog->priv->properties->backwards = FALSE; + dialog->priv->properties->interactive = interactive; + + embed = ephy_embed_dialog_get_embed (EPHY_EMBED_DIALOG(dialog)); + g_return_if_fail (embed != NULL); + + result = ephy_embed_find (embed, + dialog->priv->properties); + + dialog->priv->can_go_prev = TRUE; + if (result != G_OK) + { + dialog->priv->can_go_next = FALSE; + } + + find_update_nav (EPHY_DIALOG(dialog)); +} + +void +find_dialog_go_prev (FindDialog *dialog, + gboolean interactive) +{ + gresult result; + EphyEmbed *embed; + + if (!find_dialog_can_go_prev (dialog)) return; + + dialog->priv->properties->backwards = TRUE; + dialog->priv->properties->interactive = interactive; + + embed = ephy_embed_dialog_get_embed (EPHY_EMBED_DIALOG(dialog)); + g_return_if_fail (embed != NULL); + + result = ephy_embed_find (embed, + dialog->priv->properties); + + dialog->priv->can_go_next = TRUE; + if (result != G_OK) + { + dialog->priv->can_go_prev = FALSE; + } + + find_update_nav (EPHY_DIALOG(dialog)); +} + +static void +find_get_info (EphyDialog *dialog) +{ + EmbedFindInfo *properties; + char *search_string; + GValue word = {0, }; + GValue match_case = {0, }; + GValue wrap = {0, }; + FindDialog *find_dialog = FIND_DIALOG(dialog); + + /* get the search string from the entry field */ + ephy_dialog_get_value (dialog, WORD_PROP, &word); + search_string = g_strdup(g_value_get_string (&word)); + + /* don't do null searches */ + if (search_string[0] == '\0') + { + return; + } + + if (find_dialog->priv->properties != NULL) + { + g_free (find_dialog->priv->properties->search_string); + g_free (find_dialog->priv->properties); + } + + /* build search structure */ + properties = g_new0 (EmbedFindInfo,1); + properties->search_string = search_string; + + ephy_dialog_get_value (dialog, MATCH_CASE_PROP, &match_case); + properties->match_case = g_value_get_boolean (&match_case); + + ephy_dialog_get_value (dialog, AUTOWRAP_PROP, &wrap); + properties->wrap = g_value_get_boolean (&wrap); + + properties->entire_word = FALSE; + properties->search_frames = TRUE; + + find_dialog->priv->properties = properties; +} + +void +find_close_button_clicked_cb (GtkWidget *button, + EphyDialog *dialog) +{ + ephy_dialog_destruct (dialog); + g_object_unref (dialog); +} + +void find_next_button_clicked_cb (GtkWidget *button, + EphyDialog *dialog) +{ + find_dialog_go_next (FIND_DIALOG(dialog), TRUE); +} + +void +find_prev_button_clicked_cb (GtkWidget *button, + EphyDialog *dialog) +{ + find_dialog_go_prev (FIND_DIALOG(dialog), TRUE); +} + +void +find_entry_activate_cb (GtkWidget *editable, + EphyDialog *dialog) +{ + find_dialog_go_next (FIND_DIALOG(dialog), TRUE); + find_update_nav (dialog); +} + +void +find_entry_changed_cb (GtkWidget *editable, + EphyDialog *dialog) +{ + FindDialog *find_dialog = FIND_DIALOG(dialog); + + find_dialog->priv->can_go_prev = TRUE; + find_dialog->priv->can_go_next = TRUE; + + find_get_info (dialog); + + find_update_nav (dialog); +} + +void +find_check_toggled_cb (GtkWidget *toggle, + EphyDialog *dialog) +{ + FindDialog *find_dialog = FIND_DIALOG(dialog); + + find_dialog->priv->can_go_prev = TRUE; + find_dialog->priv->can_go_next = TRUE; + + find_get_info (dialog); + + find_update_nav (dialog); +} diff --git a/embed/find-dialog.h b/embed/find-dialog.h new file mode 100644 index 000000000..325f8a7b7 --- /dev/null +++ b/embed/find-dialog.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef FIND_DIALOG_H +#define FIND_DIALOG_H + +#include "ephy-embed-dialog.h" + +#include <glib-object.h> +#include <glib.h> + +G_BEGIN_DECLS + +typedef struct FindDialog FindDialog; +typedef struct FindDialogClass FindDialogClass; + +#define FIND_DIALOG_TYPE (find_dialog_get_type ()) +#define FIND_DIALOG(obj) (GTK_CHECK_CAST ((obj), FIND_DIALOG_TYPE, FindDialog)) +#define FIND_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), FIND_DIALOG, FindDialogClass)) +#define IS_FIND_DIALOG(obj) (GTK_CHECK_TYPE ((obj), FIND_DIALOG_TYPE)) +#define IS_FIND_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), FIND_DIALOG)) + +typedef struct FindDialogPrivate FindDialogPrivate; + +struct FindDialog +{ + EphyEmbedDialog parent; + FindDialogPrivate *priv; +}; + +struct FindDialogClass +{ + EphyEmbedDialogClass parent_class; + + void (* search) (FindDialog *dialog); +}; + +GType find_dialog_get_type (void); + +EphyDialog *find_dialog_new (EphyEmbed *embed); + +EphyDialog *find_dialog_new_with_parent (GtkWidget *window, + EphyEmbed *embed); + + +gboolean find_dialog_can_go_next (FindDialog *dialog); + +gboolean find_dialog_can_go_prev (FindDialog *dialog); + +void find_dialog_go_next (FindDialog *dialog, + gboolean interactive); + +void find_dialog_go_prev (FindDialog *dialog, + gboolean interactive); + +G_END_DECLS + +#endif + diff --git a/embed/mozilla/.cvsignore b/embed/mozilla/.cvsignore new file mode 100644 index 000000000..20e4cb0c8 --- /dev/null +++ b/embed/mozilla/.cvsignore @@ -0,0 +1,6 @@ +Makefile +Makefile.in +*.lo +.deps +.libs +*.la diff --git a/embed/mozilla/BaseProtocolContentHandler.cpp b/embed/mozilla/BaseProtocolContentHandler.cpp new file mode 100644 index 000000000..741d21722 --- /dev/null +++ b/embed/mozilla/BaseProtocolContentHandler.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "nsCOMPtr.h" +#include "nsIURI.h" +#include "nsIChannel.h" +#include "nsIStorageStream.h" +#include "nsIInputStream.h" +#include "nsIOutputStream.h" +#include "nsNetUtil.h" +#include "nsIExternalProtocolService.h" +#include "nsCExternalHandlerService.h" + +#include "BaseProtocolContentHandler.h" + +/* Implementation file */ +NS_IMPL_ISUPPORTS2 (GBaseProtocolContentHandler, nsIProtocolHandler, nsIContentHandler) + +GBaseProtocolContentHandler::GBaseProtocolContentHandler(const char *aScheme) : + GBaseProtocolHandler(aScheme) +{ + NS_INIT_ISUPPORTS(); + /* member initializers and constructor code */ + mMimeType = NS_LITERAL_CSTRING("application-x-gnome-") + mScheme; +} + +GBaseProtocolContentHandler::~GBaseProtocolContentHandler() +{ + /* destructor code */ +} + +/* nsIChannel newChannel (in nsIURI aURI); */ +NS_IMETHODIMP GBaseProtocolContentHandler::NewChannel(nsIURI *aURI, + nsIChannel **_retval) +{ + nsCOMPtr<nsIStorageStream> sStream; + nsresult rv = NS_NewStorageStream(1, 16, getter_AddRefs(sStream)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr<nsIOutputStream> oStream; + rv = sStream->GetOutputStream(0, getter_AddRefs(oStream)); + + PRUint32 bytes; + oStream->Write("Dummy stream\0", 13, &bytes); + + nsCOMPtr<nsIInputStream> iStream; + rv = sStream->NewInputStream(0, getter_AddRefs(iStream)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr<nsIChannel> channel; + rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aURI, + iStream, mMimeType, NS_LITERAL_CSTRING(""), 0); + if (NS_FAILED(rv)) return rv; + + NS_IF_ADDREF (*_retval = channel); + return rv; +} + +NS_IMETHODIMP GBaseProtocolContentHandler::HandleContent ( + const char * aContentType, + const char * aCommand, + nsISupports * aWindowContext, + nsIRequest *aRequest) +{ + nsresult rv = NS_OK; + if (!aRequest) + return NS_ERROR_NULL_POINTER; + // First of all, get the content type and make sure it is a + // content type we know how to handle! + if (mMimeType.Equals(aContentType)) + { + nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest); + if(!channel) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIURI> uri; + rv = channel->GetURI(getter_AddRefs(uri)); + if (NS_FAILED(rv)) return rv; + + aRequest->Cancel(NS_BINDING_ABORTED); + if (uri) + { + nsCOMPtr<nsIExternalProtocolService> ps = + do_GetService (NS_EXTERNALPROTOCOLSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv) || !ps) return NS_ERROR_FAILURE; + ps->LoadUrl (uri); + } + } + return rv; +} diff --git a/embed/mozilla/BaseProtocolContentHandler.h b/embed/mozilla/BaseProtocolContentHandler.h new file mode 100644 index 000000000..b1f5c1e71 --- /dev/null +++ b/embed/mozilla/BaseProtocolContentHandler.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _BaseProtocolContentHandler_h_ +#define _BaseProtocolContentHandler_h_ + +#include "BaseProtocolHandler.h" +#include "nsIContentHandler.h" + +#include "nsString.h" + +class GBaseProtocolContentHandler : public GBaseProtocolHandler, + public nsIContentHandler +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_NSICONTENTHANDLER + + NS_IMETHODIMP NewChannel(nsIURI *aURI, nsIChannel **_retval); + + GBaseProtocolContentHandler (const char *aScheme); + virtual ~GBaseProtocolContentHandler(); + /* additional members */ + protected: + nsCString mMimeType; +}; + +#endif //_BaseProtocolContentHandler_h_ diff --git a/embed/mozilla/BaseProtocolHandler.cpp b/embed/mozilla/BaseProtocolHandler.cpp new file mode 100644 index 000000000..728465a15 --- /dev/null +++ b/embed/mozilla/BaseProtocolHandler.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "nsCOMPtr.h" +#include "nsIComponentManager.h" +#include "nsIURI.h" +#include "nsNetCID.h" + +#include "BaseProtocolHandler.h" + +static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID); + +/* Implementation file */ +NS_IMPL_ISUPPORTS1 (GBaseProtocolHandler, nsIProtocolHandler) + +GBaseProtocolHandler::GBaseProtocolHandler(const char *aScheme) +{ + NS_INIT_ISUPPORTS(); + /* member initializers and constructor code */ + mScheme.Assign(aScheme); +} + +GBaseProtocolHandler::~GBaseProtocolHandler() +{ + /* destructor code */ +} + +/* readonly attribute string scheme; */ +NS_IMETHODIMP GBaseProtocolHandler::GetScheme(nsACString &aScheme) +{ + aScheme = mScheme; + return NS_OK; +} + +/* readonly attribute long defaultPort; */ +NS_IMETHODIMP GBaseProtocolHandler::GetDefaultPort(PRInt32 *aDefaultPort) +{ + if (aDefaultPort) + *aDefaultPort = -1; + else + return NS_ERROR_NULL_POINTER; + return NS_OK; +} + +/* readonly attribute short protocolFlags; */ +NS_IMETHODIMP GBaseProtocolHandler::GetProtocolFlags(PRUint32 *aProtocolFlags) +{ + if (aProtocolFlags) + *aProtocolFlags = nsIProtocolHandler::URI_STD; + else + return NS_ERROR_NULL_POINTER; + return NS_OK; +} + +/* nsIURI newURI (in string aSpec, in nsIURI aBaseURI); */ +NS_IMETHODIMP GBaseProtocolHandler::NewURI(const nsACString &aSpec, + const char *aOriginCharset, nsIURI *aBaseURI, + nsIURI **_retval) +{ + nsresult rv = NS_OK; + nsCOMPtr <nsIURI> newUri; + + rv = nsComponentManager::CreateInstance(kSimpleURICID, nsnull, + NS_GET_IID(nsIURI), + getter_AddRefs(newUri)); + + if (NS_SUCCEEDED(rv)) + { + newUri->SetSpec(aSpec); + rv = newUri->QueryInterface(NS_GET_IID(nsIURI), + (void **) _retval); + } + return rv; + +} + +/* nsIChannel newChannel (in nsIURI aURI); */ +NS_IMETHODIMP GBaseProtocolHandler::NewChannel(nsIURI *aURI, + nsIChannel **_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* boolean allowPort (in long port, in string scheme); */ +NS_IMETHODIMP GBaseProtocolHandler::AllowPort(PRInt32 port, const char *scheme, + PRBool *_retval) +{ + *_retval = PR_FALSE; + return NS_OK; +} + diff --git a/embed/mozilla/BaseProtocolHandler.h b/embed/mozilla/BaseProtocolHandler.h new file mode 100644 index 000000000..ab25a680d --- /dev/null +++ b/embed/mozilla/BaseProtocolHandler.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _BaseProtocolHandler_h_ +#define _BaseProtocolHandler_h_ + +#include "nsIProtocolHandler.h" + +#include "nsString.h" + +class GBaseProtocolHandler : public nsIProtocolHandler +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPROTOCOLHANDLER + + GBaseProtocolHandler (const char *aScheme); + virtual ~GBaseProtocolHandler(); + /* additional members */ + protected: + nsCString mScheme; +}; + +#endif //_BaseProtocolHandler_h_ diff --git a/embed/mozilla/ContentHandler.cpp b/embed/mozilla/ContentHandler.cpp new file mode 100644 index 000000000..9476a2f72 --- /dev/null +++ b/embed/mozilla/ContentHandler.cpp @@ -0,0 +1,671 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * The functioning of the download architecture, as described by Philip + * on 28 May 2001 and updated on 28 June 2001: + * + * When mozilla runs into a file it cannot render internally or that it + * does not have a plugin for, it calls the + * nsIExternalHelperAppService. This service will then either attempt to + * save the file or run it with a helper app depending on what the + * mozilla mime database returns. + * + * nsIExternalHelperAppService then calls out to the nsIHelperAppDialog + * interface which handles the UI for the service. This is the interface + * which we have reimplemented. Therefore, with a major caveat, we have + * put a GNOME/GTK frontend on an unmodified mozilla backend. + * + * Now for the caveat. With respect to saving files to disk, the mozilla + * backend works exactly the same as it does in + * mozilla-the-browser. However, for dealing with helper apps, we do not + * use the mozilla backend at all. This is because we want to use the + * gnome-vfs database to retrieve helper-app info, rather than the + * mozilla helper app database. + * + * How it works: + * + * a) The user clicks on a link or follows a redirect to a file of a type + * that mozilla cannot handle. Mozilla passes the link to the + * ExternalHelperAppService which in turn calls the Show() method of + * nsIHelperAppDialog. + * + * b) In our implementation of Show() we first compare the passed mime + * type to epiphany's mime list. If the mime type is in the list, we then + * lookup the Action associated with the mime type. Currently, the + * possible mime-actions are: + * + * Save to Disk + * Run with Helper App + * Ask User + * + * The default action is Ask User, and if the mime-type is not in our + * list, this is what will be assumed. + * + * c) If Ask User is the chosen action, a dialog will be shown to the + * user allowing the user to choose from the other two possible actions + * as well as a checkbox to let the user set the default action to the + * chosen action for the future. + * + * d-1) The "Save to Disk" action. We first check epiphany preferences to + * see if the user wants to use the built-in mozilla downloader, gtm or + * a command-line executed downloader. + * + * d-2a) The built-in downloader. This action is handled by the mozilla + * backend. Our nsIHelperAppDialog does the same thing that the + * mozilla-the-browser one does, which is to call the SaveToDisk() method + * of nsIExternalHelperAppService. This in turn calls the + * PromptForSaveToFile() method of nsIHelperAppDialog putting the ball + * back in our court. + * + * d-2b) Now, if epiphany is configured to always ask for a download + * directory, it will pop up a file selector so that the user can select + * the directory and filename to save the file to. Otherwise, it will + * use epiphany's default download directory and proceed without + * interaction. + * + * d-2c) When PromptForSaveToFile() returns, nsIExternalHelperAppService + * will then call the ShowProgressDialog() method of + * nsIHelperAppDialog. This progress dialog, obviously, tracks the + * progress of the download. It is worth noting that mozilla starts the + * actual download as soon as the user clicks on the link or follows the + * redirect. While the user is deciding what action to take, the file is + * downloading. Often, for small files, the file is already downloaded + * when the user decides what directory to put it in. The progress dialog + * does not appear in these cases. Also, we currently have a small + * problem where our progress dialog times the download from the point + * the dialog appears, not from the time the download starts. This is due + * to the timestamp that is passed to us is just plain weird, and I + * haven't worked out how to turn it into a useable time. The fact that + * the download starts early means that the file is actually downloaded + * to a temp file and only at the end is it moved to it's final location. + * + * d-3a) The two external downloader options. These options are + * handled completely by epiphany. The first thing that we do is call the + * Cancel() method of nsIExternalHelperAppService to cancel the mozilla + * download. We then pass the url to our own LaunchExternalDownloader() + * method. This method will ask for a download directory as appropriate + * as with the "Save to disk" action. + * + * d-3b) Finally, depending on whether GTM or a command line handler was + * selected in prefs, the external handler will be called with the url + * passed and the directory selected. + * + * e-1) The "Run with Helper App" action. This action is currently only + * working with a minimal implementation. First, we explicitly call + * ShowProgressDialog() so the user knows that the file is being + * downloaded. We also need this so that we only run the helper after the + * file is completely downloaded. The file will download to temp location + * that it would be moved from if the action was "Save to Disk". We have + * to call ShowProgressDialog() ourselves because we are not using + * mozilla's helper mechanism which would usually make the call for us. + * + * e-2) If there is a default helper app in our mime database and alwaysAsk + * is false, epiphany will run the default helper automatically. Otherwise it + * will pop up a helper chooser dialog which lists the helpers that gnome-vfs + * knows about as well as providing a GnomeFileEntry to allow the user to + * select and arbitrary application. The default value of the GnomeFileEntry + * is the helper stored in our database if one exits. + * + * f) General notes. We cannot use this infrastructure to override + * native mozilla types. mozilla will attempt to render these types and + * never call out to us. We are at the end of the chain as the handler of + * last resort, so native and plugin types will never reach us. This also + * means that a file with an incorrect mime-type ( eg: .tar.bz2 marked as + * text/plain ) will be incorrectly rendered by mozilla. We cannot help + * this. + * + * Despite the apparent user-side similarity with explicit downloads by + * a shift-click or context-menu item, there is actually none at all. + * Explicit downloads are handled by the nsIStreamTransfer manager which + * we use as is. Currently the progress dialog for the stream transfer + * manager is un-overridable, so it appears in XUL. This will change in + * due course. + * + * Matt would like the modifiy the progress dialog so each file currently + * being downloaded becomes a clist entry in a master dialog rather than + * causing a separate progress dialog. a lot of progress dialogs gets + * really messy. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +extern "C" { +#include "libgnomevfs/gnome-vfs-mime-handlers.h" +} + +#include "ephy-embed-shell.h" +#include "ephy-prefs.h" +#include "eel-gconf-extensions.h" +#include "ephy-glade.h" +#include "ephy-string.h" +#include "ephy-gui.h" +#include "ephy-embed-utils.h" +#include "ephy-file-helpers.h" +#include "ProgressListener.h" +#include "ContentHandler.h" + +#include <gtk/gtkentry.h> +#include <gtk/gtktogglebutton.h> +#include <gtk/gtkprogress.h> +#include <gtk/gtkoptionmenu.h> +#include <libgnome/gnome-exec.h> +#include <libgnome/gnome-i18n.h> +#include <libgnome/gnome-config.h> +#include <libgnome/gnome-util.h> +#include <libgnomevfs/gnome-vfs-mime.h> + +#include "FilePicker.h" +#include "MozillaPrivate.h" + +#include "nsCRT.h" +#include "nsCOMPtr.h" +#include "nsIFactory.h" +#include "nsISupportsArray.h" +#include "nsIServiceManager.h" +#include "nsWeakReference.h" +#include "nsXPComFactory.h" + +#include "nsString.h" +#include "nsIURI.h" +#include "nsIURL.h" +#include "nsIMIMEInfo.h" +#include "nsIChannel.h" +#include "nsIFTPChannel.h" +#include "nsILocalFile.h" +#include "nsIPrefService.h" +#include "nsIDOMWindow.h" +#include "nsIDOMWindowInternal.h" + +class GContentHandler; +class GDownloadProgressListener; +struct MimeAskActionDialog; +struct HelperAppChooserDialog; + +extern "C" +void mime_ask_dialog_save_clicked_cb (GtkButton *button, + MimeAskActionDialog *dialog); +extern "C" +void mime_ask_dialog_open_clicked_cb (GtkButton *button, + MimeAskActionDialog *dialog); +extern "C" +gint mime_ask_dialog_cancel_clicked_cb (GtkButton *button, + MimeAskActionDialog *dialog); + +/* + * MimeAskActionDialog: the representation of dialogs used to ask + * about actions on MIME types + */ +struct MimeAskActionDialog +{ + MimeAskActionDialog(GContentHandler *aContentHandler, + GtkWidget *aParentWidget, + const char *aMimeType); + ~MimeAskActionDialog(); + + GContentHandler *mContentHandler; + GladeXML *mGXml; + GtkWidget *mParent; + GtkWidget *mAppMenu; + + GnomeVFSMimeApplication *mDefaultApp; +}; + +/* Implementation file */ +NS_IMPL_ISUPPORTS1(GContentHandler, nsIHelperAppLauncherDialog) + +GContentHandler::GContentHandler() : mUri(nsnull), + mMimeType(nsnull), + mDownloadCanceled(PR_FALSE), + mHelperProgress(PR_FALSE) +{ + NS_INIT_ISUPPORTS(); + /* member initializers and constructor code */ +} + +GContentHandler::~GContentHandler() +{ + /* destructor code */ + g_free (mUri); + g_free (mMimeType); +} + +//////////////////////////////////////////////////////////////////////////////// +// begin nsIHelperAppLauncher impl +//////////////////////////////////////////////////////////////////////////////// + +/* void show (in nsIHelperAppLauncher aLauncher, in nsISupports aContext); */ +NS_IMETHODIMP GContentHandler::Show(nsIHelperAppLauncher *aLauncher, + nsISupports *aContext) +{ + nsresult rv; + + mLauncher = aLauncher; + mContext = aContext; + rv = Init (); + + MIMEAskAction (); + + return NS_OK; +} + +/* nsILocalFile promptForSaveToFile (in nsISupports aWindowContext, in wstring aDefaultFile, in wstring aSuggestedFileExtension); */ +NS_IMETHODIMP GContentHandler:: + PromptForSaveToFile(nsISupports *aWindowContext, + const PRUnichar *aDefaultFile, + const PRUnichar *aSuggestedFileExtension, + nsILocalFile **_retval) +{ + nsresult rv; + + mContext = aWindowContext; + + nsCOMPtr<nsIDOMWindowInternal> windowInternal = + do_QueryInterface (aWindowContext); + + nsCOMPtr<nsILocalFile> saveDir; + char *dirName; + + /* FIXME persist download dir */ + dirName = g_strdup (g_get_home_dir()); + + saveDir = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID); + saveDir->InitWithPath (NS_ConvertUTF8toUCS2(dirName)); + g_free (dirName); + + nsCOMPtr <nsILocalFile> saveFile (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + + PRInt16 okToSave = nsIFilePicker::returnCancel; + + if (okToSave == nsIFilePicker::returnCancel) + { + nsCOMPtr<nsIFilePicker> filePicker = + do_CreateInstance (G_FILEPICKER_CONTRACTID); + + const nsAString &title = NS_ConvertUTF8toUCS2(_("Select the destination filename")); + + filePicker->Init (windowInternal, + PromiseFlatString(title).get(), + nsIFilePicker::modeSave); + filePicker->SetDefaultString (aDefaultFile); + filePicker->SetDisplayDirectory (saveDir); + + filePicker->Show (&okToSave); + + if (okToSave == nsIFilePicker::returnOK) + { + filePicker->GetFile (getter_AddRefs(saveFile)); + } + } + + if (okToSave == nsIFilePicker::returnCancel) + return NS_ERROR_FAILURE; + else + { + nsCOMPtr<nsIFile> directory; + rv = saveFile->GetParent (getter_AddRefs(directory)); + + NS_IF_ADDREF (*_retval = saveFile); + return NS_OK; + } +} + +/* void showProgressDialog (in nsIHelperAppLauncher aLauncher, in nsISupports aContext); */ +NS_METHOD GContentHandler::ShowProgressDialog(nsIHelperAppLauncher *aLauncher, + nsISupports *aContext) +{ + g_print ("GContentHandler::ShowProgressDialog is depreciated!\n"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +//////////////////////////////////////////////////////////////////////////////// +// begin local public methods impl +//////////////////////////////////////////////////////////////////////////////// + +NS_METHOD GContentHandler::FindHelperApp (void) +{ + if (mUrlHelper) + { + return LaunchHelperApp (); + } + else + { + if (NS_SUCCEEDED(SynchroniseMIMEInfo())) + { + return mLauncher->LaunchWithApplication(nsnull, PR_FALSE); + } + else + { + return NS_ERROR_FAILURE; + } + } +} + +NS_METHOD GContentHandler::LaunchHelperApp (void) +{ + if (mMimeType) + { + nsresult rv; + nsCOMPtr<nsIExternalHelperAppService> helperService = + do_GetService (NS_EXTERNALHELPERAPPSERVICE_CONTRACTID); + + nsCOMPtr<nsPIExternalAppLauncher> appLauncher = + do_QueryInterface (helperService, &rv); + if (NS_SUCCEEDED(rv)) + { + appLauncher->DeleteTemporaryFileOnExit(mTempFile); + } + + nsString uFileName; + mTempFile->GetPath(uFileName); + const nsCString &aFileName = NS_ConvertUCS2toUTF8(uFileName); + + const nsCString &document = (mUrlHelper) ? mUrl : aFileName; + + char *param = g_strdup (document.get()); + ephy_file_launch_application (mHelperApp->command, + param, + mHelperApp->requires_terminal); + + if(mUrlHelper) mLauncher->Cancel(); + + g_free (param); + } + else + { + mLauncher->Cancel (); + } + + return NS_OK; +} + +NS_METHOD GContentHandler::ShowHelperProgressDialog (void) +{ + mHelperProgress = PR_TRUE; + return ShowProgressDialog (mLauncher,mContext); +} + +NS_METHOD GContentHandler::GetLauncher (nsIHelperAppLauncher * *_retval) +{ + NS_IF_ADDREF (*_retval = mLauncher); + return NS_OK; +} + +NS_METHOD GContentHandler::GetContext (nsISupports * *_retval) +{ + NS_IF_ADDREF (*_retval = mContext); + return NS_OK; +} + +static gboolean +application_support_scheme (GnomeVFSMimeApplication *app, const nsCString &aScheme) +{ + GList *l; + + g_return_val_if_fail (app != NULL, FALSE); + g_return_val_if_fail (!aScheme.IsEmpty(), FALSE); + + if (app->expects_uris != GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_URIS) + return FALSE; + + for (l = app->supported_uri_schemes; l != NULL; l = l->next) + { + char *uri_scheme = (char *)l->data; + g_return_val_if_fail (uri_scheme != NULL, FALSE); + if (aScheme.Equals(uri_scheme)) return TRUE; + } + + return FALSE; +} + +NS_METHOD GContentHandler::SetHelperApp(GnomeVFSMimeApplication *aHelperApp, + PRBool alwaysUse) +{ + mHelperApp = aHelperApp; + mUrlHelper = application_support_scheme (aHelperApp, mScheme); + + return NS_OK; +} + +NS_METHOD GContentHandler::SynchroniseMIMEInfo (void) +{ + nsresult rv; + nsCOMPtr<nsIMIMEInfo> mimeInfo; + rv = mLauncher->GetMIMEInfo(getter_AddRefs(mimeInfo)); + if(NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCOMPtr<nsILocalFile> helperFile; + rv = NS_NewNativeLocalFile(nsDependentCString(mHelperApp->command), + PR_TRUE, + getter_AddRefs(helperFile)); + if(NS_FAILED(rv)) return NS_ERROR_FAILURE; + + rv = mimeInfo->SetPreferredApplicationHandler(helperFile); + if(NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsMIMEInfoHandleAction mimeInfoAction; + mimeInfoAction = nsIMIMEInfo::alwaysAsk; + + if(mHelperApp->requires_terminal) //Information passing kludge! + { + rv = mimeInfo->SetApplicationDescription + (NS_LITERAL_STRING("runInTerminal").get()); + if(NS_FAILED(rv)) return NS_ERROR_FAILURE; + } + + rv = mimeInfo->SetPreferredAction(mimeInfoAction); + if(NS_FAILED(rv)) return NS_ERROR_FAILURE; + + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// +// begin local private methods impl +//////////////////////////////////////////////////////////////////////////////// +NS_METHOD GContentHandler::Init (void) +{ + nsresult rv; + + nsCOMPtr<nsIMIMEInfo> MIMEInfo; + rv = mLauncher->GetMIMEInfo (getter_AddRefs(MIMEInfo)); + rv = MIMEInfo->GetMIMEType (&mMimeType); + + rv = mLauncher->GetDownloadInfo(getter_AddRefs(mUri), + &mTimeDownloadStarted, + getter_AddRefs(mTempFile)); + rv = mUri->GetSpec (mUrl); + rv = mUri->GetScheme (mScheme); +#if 0 + /* GetSource seems redundant and isn't in 0.9 This code is here while + it remains unclear what GetSource is for. --phil */ + nsCOMPtr<nsIURI> uri; + rv = mLauncher->GetSource(getter_AddRefs(uri)); + rv = uri->GetSpec (mUrl); +#endif + ProcessMimeInfo (); + + return NS_OK; +} + +NS_METHOD GContentHandler::ProcessMimeInfo (void) +{ + if (mMimeType == NULL || + !nsCRT::strcmp(mMimeType, "application/octet-stream")) + { + nsresult rv; + nsCOMPtr<nsIURL> url = do_QueryInterface(mUri, &rv); + if (NS_SUCCEEDED(rv) && url) + { + nsCAutoString uriFileName; + url->GetFileName(uriFileName); + mMimeType = g_strdup + (gnome_vfs_mime_type_from_name + (uriFileName.get())); + } + else + mMimeType = g_strdup ("application/octet-stream"); + } + + return NS_OK; +} + +NS_METHOD GContentHandler::MIMEAskAction (void) +{ + nsCOMPtr<nsIDOMWindow> parent = do_QueryInterface (mContext); + GtkWidget *parentWidget = MozillaFindGtkParent (parent); + + new MimeAskActionDialog(this, parentWidget, mMimeType); + + return NS_OK; +} + +//------------------------------------------------------------------------------ + +NS_DEF_FACTORY (GContentHandler, GContentHandler); + +/** + * NS_NewContentHandlerFactory: + */ +nsresult NS_NewContentHandlerFactory(nsIFactory** aFactory) +{ + NS_ENSURE_ARG_POINTER(aFactory); + *aFactory = nsnull; + + nsGContentHandlerFactory *result = new nsGContentHandlerFactory; + if (result == NULL) + { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(result); + *aFactory = result; + + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// +// begin MIMEAskActionDialog methods. +//////////////////////////////////////////////////////////////////////////////// + +MimeAskActionDialog::MimeAskActionDialog(GContentHandler *aContentHandler, + GtkWidget *aParentWidget, + const char *aMimeType) : + mContentHandler(aContentHandler), + mParent(aParentWidget) +{ + GtkWidget *label; + GtkWidget *dialogWidget; + const char *description; + char ltext[255]; //philipl: Fixed length buffer == potential security problem... + + mGXml = ephy_glade_widget_new ("epiphany.glade", "mime_ask_action_dialog", + &dialogWidget, this); + mAppMenu = glade_xml_get_widget (mGXml, "mime_ask_dialog_app_menu"); + + mDefaultApp = gnome_vfs_mime_get_default_application(aMimeType); + + GtkWidget *aMimeIcon = glade_xml_get_widget (mGXml, + "mime_ask_action_icon"); + gtk_image_set_from_file(GTK_IMAGE(aMimeIcon), + gnome_vfs_mime_get_icon(aMimeType)); + + description = gnome_vfs_mime_get_description (aMimeType); + if (!description) description = aMimeType; + + g_snprintf (ltext, 255, "<b>%s</b>", description); + label = glade_xml_get_widget (mGXml, "mime_ask_action_description"); + gtk_label_set_markup (GTK_LABEL (label), ltext); + + gtk_window_set_transient_for (GTK_WINDOW (dialogWidget), + GTK_WINDOW (aParentWidget)); + + gtk_widget_show(dialogWidget); +} + +MimeAskActionDialog::~MimeAskActionDialog() +{ +#if 0 + if(mApps) + gnome_vfs_mime_application_list_free(mApps); +#endif + + gtk_widget_destroy(glade_xml_get_widget(mGXml, "mime_ask_action_dialog")); + g_object_unref(G_OBJECT(mGXml)); +} + +//////////////////////////////////////////////////////////////////////////////// +// begin MIMEAskActionDialog callbacks. +//////////////////////////////////////////////////////////////////////////////// + +extern "C" void +mime_ask_dialog_save_clicked_cb (GtkButton *button, MimeAskActionDialog *dialog) +{ + gtk_widget_hide (glade_xml_get_widget (dialog->mGXml, + "mime_ask_action_dialog")); + + nsresult rv; + nsCOMPtr<nsIHelperAppLauncher> launcher; + rv = dialog->mContentHandler->GetLauncher (getter_AddRefs(launcher)); + + launcher->SaveToDisk (nsnull,PR_FALSE); + + delete dialog; +} + +static void +mime_ask_dialog_download_cancel (MimeAskActionDialog *dialog) +{ + nsresult rv; + nsCOMPtr<nsIHelperAppLauncher> launcher; + rv = dialog->mContentHandler->GetLauncher (getter_AddRefs(launcher)); + + launcher->Cancel (); + + delete dialog; +} + +extern "C" void +mime_ask_dialog_open_clicked_cb (GtkButton *button, MimeAskActionDialog *dialog) +{ + nsresult rv; + nsCOMPtr<nsIHelperAppLauncher> launcher; + rv = dialog->mContentHandler->GetLauncher (getter_AddRefs(launcher)); + GnomeVFSMimeApplication *app = dialog->mDefaultApp; + + if (app) + { + dialog->mContentHandler->SetHelperApp (app, FALSE); + dialog->mContentHandler->FindHelperApp (); + delete dialog; + } + else + { + mime_ask_dialog_download_cancel (dialog); + ephy_embed_utils_nohandler_dialog_run (dialog->mParent); + } +} + +extern "C" gint +mime_ask_dialog_cancel_clicked_cb (GtkButton *button, + MimeAskActionDialog *dialog) +{ + mime_ask_dialog_download_cancel (dialog); + return 0; /* FIXME: philipl, is this the right thing to return? */ +} diff --git a/embed/mozilla/ContentHandler.h b/embed/mozilla/ContentHandler.h new file mode 100644 index 000000000..6ae61f657 --- /dev/null +++ b/embed/mozilla/ContentHandler.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2000 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ContentHandler_h +#define __ContentHandler_h + +#include "mozilla-embed-shell.h" + +#include <libgnomevfs/gnome-vfs-mime-handlers.h> +#include "nsIHelperAppLauncherDialog.h" +#include "nsIExternalHelperAppService.h" +#include "nsCExternalHandlerService.h" +#include "nsIWebProgressListener.h" + +#include "nsString.h" +#include "nsIURI.h" +#include "nsILocalFile.h" + +#include "nsCOMPtr.h" +#include "nsISupports.h" +#include "nsError.h" + +typedef enum +{ + ACTION_NONE, + ACTION_SAVEFORHELPER, + ACTION_OBJECT_NOTIFY +} DownloadAction; + +#define G_CONTENTHANDLER_CID \ +{ /* 16072c4a-23a6-4996-9beb-9335c06bbeae */ \ + 0x16072c4a, \ + 0x23a6, \ + 0x4996, \ + {0x9b, 0xeb, 0x93, 0x35, 0xc0, 0x6b, 0xbe, 0xae} \ +} + +class nsIFactory; + +class GContentHandler : public nsIHelperAppLauncherDialog +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIHELPERAPPLAUNCHERDIALOG + + GContentHandler(); + virtual ~GContentHandler(); + + NS_METHOD FindHelperApp (void); + NS_METHOD LaunchHelperApp (void); + NS_METHOD ShowHelperProgressDialog (void); + + NS_METHOD GetLauncher (nsIHelperAppLauncher * *_retval); + NS_METHOD GetContext (nsISupports * *_retval); + NS_METHOD SetHelperApp(GnomeVFSMimeApplication *mHelperApp, + PRBool alwaysUse); + NS_METHOD SynchroniseMIMEInfo (void); + + private: + /* additional members */ + NS_METHOD Init (void); + NS_METHOD ProcessMimeInfo (void); + NS_METHOD MIMEAskAction (void); + + nsCOMPtr<nsIHelperAppLauncher> mLauncher; + nsCOMPtr<nsISupports> mContext; + + nsCOMPtr<nsIURI> mUri; + PRInt64 mTimeDownloadStarted; + nsCOMPtr<nsIFile> mTempFile; + + char *mMimeType; + PRBool mUrlHelper; + GnomeVFSMimeApplication *mHelperApp; + + nsCString mUrl; + nsCString mScheme; + + PRBool mDownloadCanceled; + PRBool mHelperProgress; + + nsCOMPtr<nsIWebProgressListener> mListener; +}; + +extern nsresult NS_NewContentHandlerFactory(nsIFactory** aFactory); + +#endif diff --git a/embed/mozilla/EphyEventListener.cpp b/embed/mozilla/EphyEventListener.cpp new file mode 100644 index 000000000..de696bf1e --- /dev/null +++ b/embed/mozilla/EphyEventListener.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2000 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <nsCOMPtr.h> + +#include "EphyEventListener.h" +#include "nsIDOMNode.h" +#include "nsIDOMElement.h" +#include "nsString.h" +#include "nsUnicharUtils.h" +#include "nsIDOMDocument.h" +#include "nsIURI.h" +#include "nsIDocument.h" +#include "nsIDOMEventTarget.h" +#include "nsIDOMEvent.h" + +EphyEventListener::EphyEventListener(void) +{ + NS_INIT_ISUPPORTS(); + mOwner = nsnull; +} + +EphyEventListener::~EphyEventListener() +{ +} + +NS_IMPL_ISUPPORTS1(EphyEventListener, nsIDOMEventListener) + +nsresult +EphyEventListener::Init(EphyEmbed *aOwner) +{ + mOwner = aOwner; + return NS_OK; +} + +nsresult +EphyEventListener::HandleFaviconLink (nsIDOMNode *node) +{ + nsresult result; + + nsCOMPtr<nsIDOMElement> linkElement; + linkElement = do_QueryInterface (node); + if (!linkElement) return NS_ERROR_FAILURE; + + NS_NAMED_LITERAL_STRING(attr_rel, "rel"); + nsAutoString value; + result = linkElement->GetAttribute (attr_rel, value); + if (NS_FAILED(result)) return NS_ERROR_FAILURE; + + if (value.Equals(NS_LITERAL_STRING("SHORTCUT ICON"), + nsCaseInsensitiveStringComparator()) || + value.Equals(NS_LITERAL_STRING("ICON"), + nsCaseInsensitiveStringComparator())) + { + NS_NAMED_LITERAL_STRING(attr_href, "href"); + nsAutoString value; + result = linkElement->GetAttribute (attr_href, value); + if (NS_FAILED (result) || value.IsEmpty()) + return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMDocument> domDoc; + result = node->GetOwnerDocument(getter_AddRefs(domDoc)); + if (NS_FAILED(result) || !domDoc) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDocument> doc = do_QueryInterface (domDoc); + if(!doc) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIURI> uri; + result = doc->GetDocumentURL(getter_AddRefs(uri)); + if (NS_FAILED (result)) return NS_ERROR_FAILURE; + + const nsACString &link = NS_ConvertUCS2toUTF8(value); + nsCAutoString favicon_url; + result = uri->Resolve (link, favicon_url); + if (NS_FAILED (result)) return NS_ERROR_FAILURE; + + char *url = g_strdup (favicon_url.get()); + g_signal_emit_by_name (mOwner, "ge_favicon", url); + g_free (url); + } + + return NS_OK; +} + +NS_IMETHODIMP +EphyEventListener::HandleEvent(nsIDOMEvent* aDOMEvent) +{ + nsCOMPtr<nsIDOMEventTarget> eventTarget; + + aDOMEvent->GetTarget(getter_AddRefs(eventTarget)); + + nsresult result; + nsCOMPtr<nsIDOMNode> node = do_QueryInterface(eventTarget, &result); + if (NS_FAILED(result) || !node) return NS_ERROR_FAILURE; + + HandleFaviconLink (node); + + return NS_OK; +} diff --git a/embed/mozilla/EphyEventListener.h b/embed/mozilla/EphyEventListener.h new file mode 100644 index 000000000..32f84e904 --- /dev/null +++ b/embed/mozilla/EphyEventListener.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2000 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_EVENT_LISTENER_H +#define EPHY_EVENT_LISTENER_H + +#include "ephy-embed.h" + +#include <nsIDOMEventListener.h> + +class EphyEventListener : public nsIDOMEventListener +{ +public: + EphyEventListener(); + virtual ~EphyEventListener(); + + nsresult Init(EphyEmbed *aOwner); + + NS_DECL_ISUPPORTS + + // nsIDOMEventListener + + NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent); + +private: + EphyEmbed *mOwner; + + nsresult HandleFaviconLink (nsIDOMNode *node); +}; + +#endif diff --git a/embed/mozilla/EphyWrapper.cpp b/embed/mozilla/EphyWrapper.cpp new file mode 100644 index 000000000..ade9e67b2 --- /dev/null +++ b/embed/mozilla/EphyWrapper.cpp @@ -0,0 +1,1384 @@ +/* + * Copyright (C) 2000 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "EphyWrapper.h" +#include "GlobalHistory.h" +#include "ProgressListener.h" +#include "PrintProgressListener.h" +#include "ephy-embed.h" +#include "ephy-string.h" + +#include <gtkmozembed_internal.h> +#include <unistd.h> + +#include "nsIContentViewer.h" +#include "nsIPermissionManager.h" +#include "nsIGlobalHistory.h" +#include "nsIDocShellHistory.h" +#include "nsIWebBrowserFind.h" +#include "nsIWebBrowserFocus.h" +#include "nsIDocument.h" +#include "nsISHEntry.h" +#include "nsISHistoryInternal.h" +#include "nsIHistoryEntry.h" +#include "nsIWebBrowserPrint.h" +#include "nsIURI.h" +#include "nsIPresShell.h" +#include "nsIMarkupDocumentViewer.h" +#include "nsIComponentManager.h" +#include "nsIDOMElement.h" +#include "nsIDOMNodeList.h" +#include "nsIScriptGlobalObject.h" +#include "nsIScriptContext.h" + +#include "nsIDOMWindowInternal.h" +#include "nsICharsetConverterManager.h" +#include "nsICharsetConverterManager2.h" +#include "nsIInterfaceRequestor.h" +#include "nsIFocusController.h" +#include "nsIWebBrowserPersist.h" +#include "nsCWebBrowserPersist.h" +#include "nsNetUtil.h" +#include "nsIChromeEventHandler.h" +#include "nsIClipboardCommands.h" +#include "nsIDOMDocumentStyle.h" +#include "nsIDocShellTreeItem.h" +#include "nsIDocShellTreeNode.h" +#include "nsIDocShellTreeOwner.h" +#include "nsIHTMLContentContainer.h" +#include "nsICSSLoader.h" +#include "nsICSSStyleSheet.h" +#include "nsICSSLoaderObserver.h" +#include "nsIStyleSet.h" +#include "nsIDocumentObserver.h" +#include "nsCWebBrowser.h" +#include "nsReadableUtils.h" +#include "nsUnicharUtils.h" +#include "nsIDOMNSHTMLDocument.h" +#include "nsIDOMHTMLDocument.h" +#include "nsIDOMHTMLCollection.h" +#include "nsIDOMHTMLElement.h" +#include "nsIDOMHTMLImageElement.h" +#include "nsIDOMHTMLFormElement.h" +#include "nsIDOMHTMLAnchorElement.h" +#include "caps/nsIPrincipal.h" +#include "nsIDeviceContext.h" +#include "nsIPresContext.h" +#include "ContentHandler.h" +#include "nsITypeAheadFind.h" +#include "nsSupportsPrimitives.h" +#include "EphyEventListener.h" + +EphyWrapper::EphyWrapper () +{ +} + +EphyWrapper::~EphyWrapper () +{ +} + +nsresult EphyWrapper::Init (GtkMozEmbed *mozembed) +{ + nsresult result; + + gtk_moz_embed_get_nsIWebBrowser (mozembed, + getter_AddRefs(mWebBrowser)); + if (!mWebBrowser) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDocShell> DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDocShellHistory> dsHistory = do_QueryInterface (DocShell); + if (!dsHistory) return NS_ERROR_FAILURE; + + static NS_DEFINE_CID(kGlobalHistoryCID, GALEON_GLOBALHISTORY_CID); + + nsCOMPtr<nsIFactory> GHFactory; + result = NS_NewGlobalHistoryFactory(getter_AddRefs(GHFactory)); + if (NS_FAILED(result)) return NS_ERROR_FAILURE; + + result = nsComponentManager::RegisterFactory(kGlobalHistoryCID, + "Global history", + NS_GLOBALHISTORY_CONTRACTID, + GHFactory, + PR_TRUE); + + nsCOMPtr<nsIGlobalHistory> inst = + do_GetService(NS_GLOBALHISTORY_CONTRACTID, &result); + + mEventListener = new EphyEventListener(); + mEventListener->Init (EPHY_EMBED (mozembed)); + GetListener(); + AttachListeners(); + + return dsHistory->SetGlobalHistory(inst); +} + +void +EphyWrapper::GetListener (void) +{ + if (mEventReceiver) return; + + nsCOMPtr<nsIDOMWindow> domWindowExternal; + mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindowExternal)); + + nsCOMPtr<nsIDOMWindowInternal> domWindow; + domWindow = do_QueryInterface(domWindowExternal); + + nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(domWindow)); + if (!piWin) return; + + nsCOMPtr<nsIChromeEventHandler> chromeHandler; + piWin->GetChromeEventHandler(getter_AddRefs(chromeHandler)); + + mEventReceiver = do_QueryInterface(chromeHandler); +} + +void +EphyWrapper::AttachListeners(void) +{ + if (!mEventReceiver || mListenersAttached) + return; + + nsCOMPtr<nsIDOMEventTarget> target; + target = do_QueryInterface (mEventReceiver); + + target->AddEventListener(NS_LITERAL_STRING("DOMLinkAdded"), mEventListener, PR_FALSE); + + mListenersAttached = PR_TRUE; +} + +void +EphyWrapper::DetachListeners(void) +{ + if (!mListenersAttached || !mEventReceiver) + return; + + nsCOMPtr<nsIDOMEventTarget> target; + target = do_QueryInterface (mEventReceiver); + + target->RemoveEventListener(NS_LITERAL_STRING("DOMLinkAdded"), mEventListener, PR_FALSE); +} + +nsresult EphyWrapper::GetDocShell (nsIDocShell **aDocShell) +{ + nsCOMPtr<nsIDocShellTreeItem> browserAsItem; + browserAsItem = do_QueryInterface(mWebBrowser); + if (!browserAsItem) return NS_ERROR_FAILURE; + + // get the owner for that item + nsCOMPtr<nsIDocShellTreeOwner> treeOwner; + browserAsItem->GetTreeOwner(getter_AddRefs(treeOwner)); + if (!treeOwner) return NS_ERROR_FAILURE; + + // get the primary content shell as an item + nsCOMPtr<nsIDocShellTreeItem> contentItem; + treeOwner->GetPrimaryContentShell(getter_AddRefs(contentItem)); + if (!contentItem) return NS_ERROR_FAILURE; + + // QI that back to a docshell + nsCOMPtr<nsIDocShell> DocShell; + DocShell = do_QueryInterface(contentItem); + if (!DocShell) return NS_ERROR_FAILURE; + + *aDocShell = DocShell.get(); + + NS_IF_ADDREF(*aDocShell); + + return NS_OK; +} +nsresult EphyWrapper::Print (nsIPrintSettings *options, PRBool preview) +{ + nsresult result; + + nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(mWebBrowser, &result)); + if (NS_FAILED(result) || !print) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMWindow> DOMWindow; + result = mWebBrowser->GetContentDOMWindow (getter_AddRefs(DOMWindow)); + if (NS_FAILED(result) || !DOMWindow) return NS_ERROR_FAILURE; + + if (!preview) + { + GPrintListener *listener = new GPrintListener(); + result = print->Print (options, listener); + } + else + { + result = print->PrintPreview(options, nsnull, nsnull); + } + + return result; +} + +nsresult EphyWrapper::PrintPreviewClose (void) +{ + nsresult rv; + PRBool isPreview = PR_FALSE; + + nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(mWebBrowser, &rv)); + if (NS_FAILED(rv) || !print) return NS_ERROR_FAILURE; + + rv = print->GetDoingPrintPreview(&isPreview); + if (isPreview == PR_TRUE) + { + rv = print->ExitPrintPreview(); + } + + return rv; +} + +nsresult EphyWrapper::PrintPreviewNumPages (int *numPages) +{ + nsresult rv; + + nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(mWebBrowser, &rv)); + if (NS_FAILED(rv) || !print) return NS_ERROR_FAILURE; + + rv = print->GetPrintPreviewNumPages(numPages); + return rv; +} + +nsresult EphyWrapper::PrintPreviewNavigate(PRInt16 navType, PRInt32 pageNum) +{ + nsresult rv; + + nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(mWebBrowser, &rv)); + if (NS_FAILED(rv) || !print) return NS_ERROR_FAILURE; + + rv = print->PrintPreviewNavigate(navType, pageNum); + return rv; +} + +nsresult EphyWrapper::GetPrintSettings (nsIPrintSettings **options) +{ + nsresult result; + nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(mWebBrowser, &result)); + if (NS_FAILED(result) || !print) return NS_ERROR_FAILURE; + + return print->GetGlobalPrintSettings(options); +} + +nsresult EphyWrapper::GetSHistory (nsISHistory **aSHistory) +{ + nsresult result; + + nsCOMPtr<nsIDocShell> DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIWebNavigation> ContentNav = do_QueryInterface (DocShell, + &result); + if (!ContentNav) return NS_ERROR_FAILURE; + + nsCOMPtr<nsISHistory> SessionHistory; + result = ContentNav->GetSessionHistory (getter_AddRefs (SessionHistory)); + if (!SessionHistory) return NS_ERROR_FAILURE; + + *aSHistory = SessionHistory.get(); + NS_IF_ADDREF (*aSHistory); + + return NS_OK; +} + +nsresult EphyWrapper::Destroy () +{ + DetachListeners (); + + mWebBrowser = nsnull; + mChromeNav = nsnull; + + return NS_OK; +} + +nsresult EphyWrapper::GoToHistoryIndex (PRInt16 index) +{ + nsresult result; + + nsCOMPtr<nsIDocShell> DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIWebNavigation> ContentNav = do_QueryInterface (DocShell, + &result); + if (!ContentNav) return NS_ERROR_FAILURE; + + return ContentNav->GotoIndex (index); +} + +nsresult EphyWrapper::SetZoom (float aZoom, PRBool reflow) +{ + nsresult result; + + nsCOMPtr<nsIDocShell> DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + if (reflow) + { + nsCOMPtr<nsIContentViewer> contentViewer; + result = DocShell->GetContentViewer (getter_AddRefs(contentViewer)); + if (!NS_SUCCEEDED (result) || !contentViewer) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(contentViewer, + &result); + if (NS_FAILED(result) || !mdv) return NS_ERROR_FAILURE; + + return mdv->SetTextZoom (aZoom); + } + else + { + SetZoomOnDocshell (aZoom, DocShell); + + nsCOMPtr<nsIDocShellTreeNode> docShellNode(do_QueryInterface(DocShell)); + if (docShellNode) + { + PRInt32 i; + PRInt32 n; + docShellNode->GetChildCount(&n); + for (i=0; i < n; i++) + { + nsCOMPtr<nsIDocShellTreeItem> child; + docShellNode->GetChildAt(i, getter_AddRefs(child)); + nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child)); + if (childAsShell) + { + return SetZoomOnDocshell (aZoom, childAsShell); + } + } + } + } + + return NS_OK; +} + +nsresult EphyWrapper::SetZoomOnDocshell (float aZoom, nsIDocShell *DocShell) +{ + nsresult result; + + nsCOMPtr<nsIPresContext> PresContext; + result = DocShell->GetPresContext (getter_AddRefs(PresContext)); + if (NS_FAILED(result)) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDeviceContext> DeviceContext; + result = PresContext->GetDeviceContext (getter_AddRefs(DeviceContext)); + + return DeviceContext->SetTextZoom (aZoom); +} + +nsresult EphyWrapper::GetZoom (float *aZoom) +{ + nsresult result; + + nsCOMPtr<nsIDocShell> DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIContentViewer> contentViewer; + result = DocShell->GetContentViewer (getter_AddRefs(contentViewer)); + if (!NS_SUCCEEDED (result) || !contentViewer) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(contentViewer, + &result); + if (NS_FAILED(result) || !mdv) return NS_ERROR_FAILURE; + + return mdv->GetTextZoom (aZoom); +} + +nsresult EphyWrapper::GetFocusedDOMWindow (nsIDOMWindow **aDOMWindow) +{ + nsresult rv; + + nsCOMPtr<nsIWebBrowserFocus> focus = do_GetInterface(mWebBrowser, &rv); + if (NS_FAILED(rv) || !focus) return NS_ERROR_FAILURE; + + rv = focus->GetFocusedWindow (aDOMWindow); + if (NS_FAILED(rv)) + rv = mWebBrowser->GetContentDOMWindow (aDOMWindow); + return rv; +} + +nsresult EphyWrapper::GetDOMWindow (nsIDOMWindow **aDOMWindow) +{ + nsresult rv; + + rv = mWebBrowser->GetContentDOMWindow (aDOMWindow); + + return rv; +} + +nsresult EphyWrapper::GetDOMDocument (nsIDOMDocument **aDOMDocument) +{ + nsresult result; + + /* Use the current target document */ + if (mTargetDocument) + { + *aDOMDocument = mTargetDocument.get(); + + NS_IF_ADDREF(*aDOMDocument); + + return NS_OK; + } + + /* Use the focused document */ + nsCOMPtr<nsIDOMWindow> DOMWindow; + result = GetFocusedDOMWindow (getter_AddRefs(DOMWindow)); + if (NS_SUCCEEDED(result) && DOMWindow) + { + return DOMWindow->GetDocument (aDOMDocument); + } + + /* Use the main document */ + return GetMainDOMDocument (aDOMDocument); +} + +nsresult EphyWrapper::GetMainDOMDocument (nsIDOMDocument **aDOMDocument) +{ + nsresult result; + + nsCOMPtr<nsIDocShell> DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIContentViewer> contentViewer; + result = DocShell->GetContentViewer (getter_AddRefs(contentViewer)); + if (!NS_SUCCEEDED (result) || !contentViewer) return NS_ERROR_FAILURE; + + return contentViewer->GetDOMDocument (aDOMDocument); +} + +nsresult EphyWrapper::GetSHInfo (PRInt32 *count, PRInt32 *index) +{ + nsresult result; + + nsCOMPtr<nsISHistory> SessionHistory; + result = GetSHistory (getter_AddRefs(SessionHistory)); + if (NS_FAILED(result) || ! SessionHistory) return NS_ERROR_FAILURE; + + SessionHistory->GetCount (count); + SessionHistory->GetIndex (index); + + return NS_OK; +} + +nsresult EphyWrapper::GetSHTitleAtIndex (PRInt32 index, PRUnichar **title) +{ + nsresult result; + + nsCOMPtr<nsISHistory> SessionHistory; + result = GetSHistory (getter_AddRefs(SessionHistory)); + if (NS_FAILED(result) || ! SessionHistory) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIHistoryEntry> he; + result = SessionHistory->GetEntryAtIndex (index, PR_FALSE, + getter_AddRefs (he)); + if (!NS_SUCCEEDED(result) || (!he)) return NS_ERROR_FAILURE; + + result = he->GetTitle (title); + if (!NS_SUCCEEDED(result) || (!title)) return NS_ERROR_FAILURE; + + return NS_OK; +} + +nsresult EphyWrapper::GetSHUrlAtIndex (PRInt32 index, nsCString &url) +{ + nsresult result; + + nsCOMPtr<nsISHistory> SessionHistory; + result = GetSHistory (getter_AddRefs(SessionHistory)); + if (NS_FAILED(result) || ! SessionHistory) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIHistoryEntry> he; + result = SessionHistory->GetEntryAtIndex (index, PR_FALSE, + getter_AddRefs (he)); + if (NS_FAILED(result) || (!he)) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIURI> uri; + result = he->GetURI (getter_AddRefs(uri)); + if (NS_FAILED(result) || (!uri)) return NS_ERROR_FAILURE; + + result = uri->GetSpec(url); + if (NS_FAILED(result) || url.IsEmpty()) return NS_ERROR_FAILURE; + + return NS_OK; +} + +nsresult EphyWrapper::Find (const PRUnichar *search_string, + PRBool interactive, + PRBool matchcase, PRBool search_backwards, + PRBool search_wrap_around, + PRBool search_for_entire_word, + PRBool search_in_frames, + PRBool *didFind) +{ + if (!interactive) + { + nsresult rv; + nsCOMPtr<nsITypeAheadFind> tAFinder + (do_GetService(NS_TYPEAHEADFIND_CONTRACTID, &rv)); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr<nsIDOMWindow> aFocusedWindow; + rv = GetFocusedDOMWindow(getter_AddRefs(aFocusedWindow)); + if (NS_SUCCEEDED(rv)) + { + nsSupportsInterfacePointerImpl windowPtr; + windowPtr.SetData(aFocusedWindow); + + tAFinder->FindNext(search_backwards, &windowPtr); + + nsCOMPtr<nsISupports> retValue; + rv = windowPtr.GetData(getter_AddRefs(retValue)); + if (NS_SUCCEEDED(rv) && !retValue) + { + *didFind = PR_TRUE; + return NS_OK; + } + } + } + + } + + nsCOMPtr<nsIWebBrowserFind> finder (do_GetInterface(mWebBrowser)); + + finder->SetSearchString (search_string); + finder->SetFindBackwards (search_backwards); + finder->SetWrapFind (search_wrap_around); + finder->SetEntireWord (search_for_entire_word); + finder->SetMatchCase (matchcase); + finder->SetSearchFrames (search_in_frames); + return finder->FindNext(didFind); +} + +nsresult EphyWrapper::GetWebNavigation(nsIWebNavigation **aWebNavigation) +{ + nsresult result; + + nsCOMPtr<nsIDOMWindow> DOMWindow; + result = GetFocusedDOMWindow (getter_AddRefs(DOMWindow)); + if (NS_FAILED(result) || !DOMWindow) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIScriptGlobalObject> scriptGlobal = do_QueryInterface(DOMWindow); + if (!scriptGlobal) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDocShell> docshell; + if (NS_FAILED(scriptGlobal->GetDocShell(getter_AddRefs(docshell)))) + return NS_ERROR_FAILURE; + + nsCOMPtr<nsIWebNavigation> wn = do_QueryInterface (docshell, &result); + if (!wn || !NS_SUCCEEDED (result)) return NS_ERROR_FAILURE; + + NS_IF_ADDREF(*aWebNavigation = wn); + return NS_OK; +} + +nsresult EphyWrapper::ReloadDocument () +{ + nsresult result; + + nsCOMPtr<nsIWebNavigation> wn; + result = GetWebNavigation(getter_AddRefs(wn)); + if (!wn || !NS_SUCCEEDED (result)) return NS_ERROR_FAILURE; + + result = wn->Reload (nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE | + nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY); + if (!NS_SUCCEEDED (result)) return NS_ERROR_FAILURE; + + return NS_OK; +} + +nsresult EphyWrapper::LoadDocument(nsISupports *aPageDescriptor, + PRUint32 aDisplayType) +{ + nsresult rv; + + nsCOMPtr<nsIWebNavigation> wn; + rv = GetWebNavigation(getter_AddRefs(wn)); + if (!wn || !NS_SUCCEEDED(rv)) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIWebPageDescriptor> wpd = do_QueryInterface(wn, &rv); + if (!wpd || !NS_SUCCEEDED(rv)) return NS_ERROR_FAILURE; + + return wpd->LoadPage(aPageDescriptor, aDisplayType); +} + +nsresult EphyWrapper::GetPageDescriptor(nsISupports **aPageDescriptor) +{ + nsresult rv; + + nsCOMPtr<nsIWebNavigation> wn; + rv = GetWebNavigation(getter_AddRefs(wn)); + if (!wn || !NS_SUCCEEDED(rv)) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIWebPageDescriptor> wpd = do_QueryInterface(wn, &rv); + if (!wpd || !NS_SUCCEEDED(rv)) return NS_ERROR_FAILURE; + + return wpd->GetCurrentDescriptor(aPageDescriptor); +} + +nsresult EphyWrapper::GetMainDocumentUrl (nsCString &url) +{ + nsresult result; + + nsCOMPtr<nsIDOMDocument> DOMDocument; + + result = GetMainDOMDocument (getter_AddRefs(DOMDocument)); + if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDocument> doc = do_QueryInterface(DOMDocument); + if(!doc) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIURI> uri; + doc->GetDocumentURL(getter_AddRefs(uri)); + + return uri->GetSpec (url); +} + +nsresult EphyWrapper::GetDocumentUrl (nsCString &url) +{ + nsresult result; + + nsCOMPtr<nsIDOMDocument> DOMDocument; + + result = GetDOMDocument (getter_AddRefs(DOMDocument)); + if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDocument> doc = do_QueryInterface(DOMDocument); + if(!doc) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIURI> uri; + doc->GetDocumentURL(getter_AddRefs(uri)); + + uri->GetSpec (url); + + return NS_OK; +} + +nsresult EphyWrapper::GetDocumentTitle (char **title) +{ + nsresult result; + + nsCOMPtr<nsIDOMDocument> DOMDocument; + + result = GetDOMDocument (getter_AddRefs(DOMDocument)); + if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDocument> doc = do_QueryInterface(DOMDocument); + if(!doc) return NS_ERROR_FAILURE; + + const nsString* t; + t = doc->GetDocumentTitle(); + + *title = g_strdup (NS_ConvertUCS2toUTF8(*t).get()); + + return NS_OK; +} + +nsresult EphyWrapper::CopyHistoryTo (EphyWrapper *dest) +{ + nsresult result; + int count,index; + + nsCOMPtr<nsIDocShell> DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIWebNavigation> wn_src = do_QueryInterface (DocShell, + &result); + if (!wn_src) return NS_ERROR_FAILURE; + + nsCOMPtr<nsISHistory> h_src; + result = wn_src->GetSessionHistory (getter_AddRefs (h_src)); + if (!NS_SUCCEEDED(result) || (!h_src)) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDocShell> destDocShell; + result = dest->GetDocShell (getter_AddRefs(destDocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIWebNavigation> wn_dest = do_QueryInterface (destDocShell, + &result); + if (!wn_dest) return NS_ERROR_FAILURE; + + nsCOMPtr<nsISHistory> h_dest; + result = wn_dest->GetSessionHistory (getter_AddRefs (h_dest)); + if (!NS_SUCCEEDED (result) || (!h_dest)) return NS_ERROR_FAILURE; + + nsCOMPtr<nsISHistoryInternal> hi_dest = do_QueryInterface (h_dest); + if (!hi_dest) return NS_ERROR_FAILURE; + + h_src->GetCount (&count); + h_src->GetIndex (&index); + + if (count) { + nsCOMPtr<nsIHistoryEntry> he; + nsCOMPtr<nsISHEntry> she; + + for (PRInt32 i = 0; i < count; i++) { + + result = h_src->GetEntryAtIndex (i, PR_FALSE, + getter_AddRefs (he)); + if (!NS_SUCCEEDED(result) || (!he)) + return NS_ERROR_FAILURE; + + she = do_QueryInterface (he); + if (!she) return NS_ERROR_FAILURE; + + result = hi_dest->AddEntry (she, PR_TRUE); + if (!NS_SUCCEEDED(result) || (!she)) + return NS_ERROR_FAILURE; + } + + result = wn_dest->GotoIndex(index); + if (!NS_SUCCEEDED(result)) return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +nsresult EphyWrapper::ForceCharacterSet (char *charset) +{ + nsresult result; + + nsCOMPtr<nsIDocShell> DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIContentViewer> contentViewer; + result = DocShell->GetContentViewer (getter_AddRefs(contentViewer)); + if (!NS_SUCCEEDED (result) || !contentViewer) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(contentViewer, + &result); + if (NS_FAILED(result) || !mdv) return NS_ERROR_FAILURE; + + result = mdv->SetForceCharacterSet (NS_ConvertUTF8toUCS2(charset).get()); + + return result; +} + +nsresult EphyWrapper::CanCutSelection(PRBool *result) +{ + nsCOMPtr<nsIClipboardCommands> clipboard (do_GetInterface(mWebBrowser)); + return clipboard->CanCutSelection (result); +} + +nsresult EphyWrapper::CanCopySelection(PRBool *result) +{ + nsCOMPtr<nsIClipboardCommands> clipboard (do_GetInterface(mWebBrowser)); + return clipboard->CanCopySelection (result); +} + +nsresult EphyWrapper::CanPaste(PRBool *result) +{ + nsCOMPtr<nsIClipboardCommands> clipboard (do_GetInterface(mWebBrowser)); + return clipboard->CanPaste (result); +} + +nsresult EphyWrapper::CutSelection(void) +{ + nsCOMPtr<nsIClipboardCommands> clipboard (do_GetInterface(mWebBrowser)); + return clipboard->CutSelection (); +} + +nsresult EphyWrapper::CopySelection(void) +{ + nsCOMPtr<nsIClipboardCommands> clipboard (do_GetInterface(mWebBrowser)); + return clipboard->CopySelection (); +} + +nsresult EphyWrapper::Paste(void) +{ + nsCOMPtr<nsIClipboardCommands> clipboard (do_GetInterface(mWebBrowser)); + return clipboard->Paste (); +} + +nsresult EphyWrapper::GetLinkInterfaceItems (GList **list) +{ +#ifdef NOT_PORTED + nsresult result; + PRUint32 links_count; + + /* we accept these rel=.. elements, specified by the w3c */ + const gchar *rel_types[] = { + "START", "NEXT", "PREV", "PREVIOUS", "CONTENTS", "TOC", "INDEX", + "GLOSSARY", "COPYRIGHT", "CHAPTER", "SECTION", + "SUBSECTION", "APPENDIX", "HELP", "TOP", "SEARCH", "MADE", + "BOOKMARK", "HOME", + NULL /* terminator, must be last */ + }; + + nsCOMPtr<nsIDOMDocument> DOMDocument; + result = GetMainDOMDocument (getter_AddRefs(DOMDocument)); + if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE; + + /* get list of link elements*/ + NS_NAMED_LITERAL_STRING(strname, "LINK"); + + nsCOMPtr<nsIDOMNodeList> links; + result = aDOMDocument->GetElementsByTagName (strname, + getter_AddRefs (links)); + if (NS_FAILED (result)) return NS_ERROR_FAILURE; + + result = links->GetLength (&links_count); + if (NS_FAILED (result)) return NS_ERROR_FAILURE; + + for (PRUint32 i = 0; i < links_count; i++) + { + /* get to the link element */ + nsCOMPtr<nsIDOMNode> link; + result = links->Item (i, getter_AddRefs (link)); + if (NS_FAILED (result)) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMElement> linkElement; + linkElement = do_QueryInterface (aLink); + if (!linkElement) return NS_ERROR_FAILURE; + + /* get rel=.. element */ + NS_NAMED_LITERAL_STRING(attr_rel, "rel"); + nsAutoString value; + linkElement->GetAttribute (attr_rel, value); + + if (value.IsEmpty()) + { + NS_NAMED_LITERAL_STRING(attr_rev, "rev"); + linkElement->GetAttribute (attr_rev, value); + if (value.IsEmpty()) continue; + } + + nsCString relstr = NS_ConvertUCS2toUTF8(value); + ToUpperCase(relstr); + + /* check for elements we want */ + for (gint j = 0; (rel_types[j] != NULL); j++) + { + if (strcmp (relstr.get(), rel_types[j]) == 0) + { + /* found one! */ + LinkInterfaceItem *lti = + g_new0 (LinkInterfaceItem, 1); + + /* fill in struct */ + lti->type = (LinkInterfaceItemType) j; + + /* get href=.. element */ + NS_NAMED_LITERAL_STRING(attr_href, "href"); + nsAutoString value; + linkElement->GetAttribute (attr_href, value); + + if (value.IsEmpty()) + { + g_free (lti); + continue; + } + + /* resolve uri */ + nsCOMPtr<nsIDocument> doc = + do_QueryInterface (aDOMDocument); + if(!doc) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIURI> uri; + doc->GetDocumentURL(getter_AddRefs(uri)); + + const nsACString &link = NS_ConvertUCS2toUTF8(value); + nsCAutoString href; + result = uri->Resolve (link, href); + if (NS_FAILED (result)) return NS_ERROR_FAILURE; + lti->href = g_strdup (href.get()); + + /* append to list of items */ + *list = g_list_append (*list, lti); + + /* get optional title=... element */ + NS_NAMED_LITERAL_STRING(attr_title, "title"); + linkElement->GetAttribute (attr_title, value); + if (value.IsEmpty()) continue; + + const nsACString &title = NS_ConvertUCS2toUTF8 (value); + lti->title = gul_string_strip_newline (PromiseFlatCString(title).get()); + } + } + } +#endif + return NS_OK; +} + +nsresult EphyWrapper::GetRealURL (nsCString &ret) +{ + nsresult result; + + nsCOMPtr<nsIDocShell> DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIWebNavigation> ContentNav = do_QueryInterface (DocShell, + &result); + if (!ContentNav) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIURI> uri; + result = ContentNav->GetCurrentURI (getter_AddRefs(uri)); + if (!NS_SUCCEEDED(result) || (!uri)) return NS_ERROR_FAILURE; + + result = uri->GetSpec(ret); + if (!NS_SUCCEEDED(result) || ret.IsEmpty()) return NS_ERROR_FAILURE; + + return NS_OK; +} + +nsresult EphyWrapper::SelectAll (void) +{ + nsCOMPtr<nsIClipboardCommands> clipboard (do_GetInterface(mWebBrowser)); + return clipboard->SelectAll (); +} + +nsresult EphyWrapper::ScrollUp (void) +{ + nsresult result; + + nsCOMPtr<nsIDOMWindow> DOMWindow; + result = GetFocusedDOMWindow (getter_AddRefs(DOMWindow)); + if (NS_FAILED(result) || !DOMWindow) return NS_ERROR_FAILURE; + + DOMWindow->ScrollByLines(-1); + + return NS_OK; +} + +nsresult EphyWrapper::ScrollDown (void) +{ + nsresult result; + + nsCOMPtr<nsIDOMWindow> DOMWindow; + result = GetFocusedDOMWindow (getter_AddRefs(DOMWindow)); + if (NS_FAILED(result) || !DOMWindow) return NS_ERROR_FAILURE; + + DOMWindow->ScrollByLines(1); + + return NS_OK; +} + +nsresult EphyWrapper::ScrollLeft (void) +{ + nsresult result; + + nsCOMPtr<nsIDOMWindow> DOMWindow; + result = GetFocusedDOMWindow (getter_AddRefs(DOMWindow)); + if (NS_FAILED(result) || !DOMWindow) return NS_ERROR_FAILURE; + + DOMWindow->ScrollBy(-16, 0); + + return NS_OK; +} + +nsresult EphyWrapper::ScrollRight (void) +{ + nsresult result; + + nsCOMPtr<nsIDOMWindow> DOMWindow; + result = GetFocusedDOMWindow (getter_AddRefs(DOMWindow)); + if (NS_FAILED(result) || !DOMWindow) return NS_ERROR_FAILURE; + + DOMWindow->ScrollBy(16, 0); + + return NS_OK; +} + +nsresult EphyWrapper::FineScroll (int horiz, int vert) +{ + nsresult result; + + nsCOMPtr<nsIDOMWindow> DOMWindow; + result = GetFocusedDOMWindow (getter_AddRefs(DOMWindow)); + if (NS_FAILED(result) || !DOMWindow) return NS_ERROR_FAILURE; + + DOMWindow->ScrollBy(horiz, vert); + + return NS_OK; +} + +nsresult EphyWrapper::GetLastModified (gchar **ret) +{ + nsresult result; + + nsCOMPtr<nsIDOMDocument> DOMDocument; + + result = GetDOMDocument (getter_AddRefs(DOMDocument)); + if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMNSHTMLDocument> doc = do_QueryInterface(DOMDocument); + if(!doc) return NS_ERROR_FAILURE; + + nsAutoString value; + doc->GetLastModified(value); + + *ret = g_strdup (NS_ConvertUCS2toUTF8(value).get()); + + return NS_OK; +} + +nsresult EphyWrapper::GetImages (GList **ret) +{ +#ifdef NOT_PORTED + nsresult result; + GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal); + + nsCOMPtr<nsIDOMDocument> DOMDocument; + + result = GetDOMDocument (getter_AddRefs(DOMDocument)); + if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMHTMLDocument> doc = do_QueryInterface(DOMDocument); + if(!doc) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMHTMLCollection> col; + doc->GetImages(getter_AddRefs(col)); + + PRUint32 count, i; + col->GetLength(&count); + for (i = 0; i < count; i++) + { + nsCOMPtr<nsIDOMNode> node; + col->Item(i, getter_AddRefs(node)); + if (!node) continue; + + nsCOMPtr<nsIDOMHTMLElement> element; + element = do_QueryInterface(node); + if (!element) continue; + + nsCOMPtr<nsIDOMHTMLImageElement> img; + img = do_QueryInterface(element); + if (!img) continue; + + ImageListItem *item = g_new0 (ImageListItem, 1); + + nsAutoString tmp; + result = img->GetSrc (tmp); + if (NS_SUCCEEDED(result)) + { + const nsACString &c = NS_ConvertUCS2toUTF8(tmp); + if (g_hash_table_lookup (hash, PromiseFlatCString(c).get())) + { + g_free (item); + continue; + } + item->url = g_strdup (c.get()); + g_hash_table_insert (hash, item->url, + GINT_TO_POINTER (TRUE)); + } + result = img->GetAlt (tmp); + if (NS_SUCCEEDED(result)) + { + const nsACString &c = NS_ConvertUCS2toUTF8(tmp); + item->alt = gul_string_strip_newline (PromiseFlatCString(c).get()); + } + result = element->GetTitle (tmp); + if (NS_SUCCEEDED(result)) + { + const nsACString &c = NS_ConvertUCS2toUTF8(tmp); + item->title = gul_string_strip_newline (PromiseFlatCString(c).get()); + } + result = img->GetWidth (&(item->width)); + result = img->GetHeight (&(item->height)); + + *ret = g_list_append (*ret, item); + } + + g_hash_table_destroy (hash); +#endif + return NS_OK; +} + +nsresult EphyWrapper::GetForms (GList **ret) +{ +#ifdef NOT_PORTED + nsresult result; + + nsCOMPtr<nsIDOMDocument> DOMDocument; + + result = GetDOMDocument (getter_AddRefs(DOMDocument)); + if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMHTMLDocument> doc = do_QueryInterface(DOMDocument); + if(!doc) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMHTMLCollection> col; + doc->GetForms(getter_AddRefs(col)); + + PRUint32 count, i; + col->GetLength(&count); + for (i = 0; i < count; i++) + { + nsCOMPtr<nsIDOMNode> node; + col->Item(i, getter_AddRefs(node)); + if (!node) continue; + + nsCOMPtr<nsIDOMHTMLElement> element; + element = do_QueryInterface(node); + if (!element) continue; + + nsCOMPtr<nsIDOMHTMLFormElement> form; + form = do_QueryInterface(element); + if (!form) continue; + + FormListItem *item = g_new0 (FormListItem, 1); + + nsAutoString tmp; + result = form->GetAction (tmp); + if (NS_SUCCEEDED(result)) + { + nsCOMPtr<nsIDocument> doc = + do_QueryInterface (aDOMDocument); + if(!doc) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIURI> uri; + doc->GetDocumentURL(getter_AddRefs(uri)); + + const nsACString &s = NS_ConvertUTF8toUCS2(tmp); + nsCAutoString c; + result = uri->Resolve (c, s); + + item->action = s.Length() ? g_strdup (s.get()) : g_strdup (c.get()); + } + result = form->GetMethod (tmp); + if (NS_SUCCEEDED(result)) + { + const nsACString &c = NS_ConvertUTF8toUCS2(tmp); + item->method = g_strdup (PromiseFlatCString(c).get()); + } + result = form->GetName (tmp); + if (NS_SUCCEEDED(result)) + { + const nsACString &c = NS_ConvertUTF8toUCS2(tmp); + item->name = g_strdup (PromiseFlatCString(c).get()); + } + + *ret = g_list_append (*ret, item); + } +#endif + return NS_OK; +} + +nsresult EphyWrapper::GetLinks (GList **ret) +{ +#ifdef NOT_PORTED + nsresult result; + + nsCOMPtr<nsIDOMDocument> DOMDocument; + result = GetMainDOMDocument (getter_AddRefs(DOMDocument)); + if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE; + + /* first, get a list of <link> elements */ + PRUint32 links_count; + + NS_NAMED_LITERAL_STRING(strname, "LINK"); + + nsCOMPtr<nsIDOMNodeList> links; + result = DOMDocument->GetElementsByTagName (strname, + getter_AddRefs (links)); + if (NS_FAILED (result)) return NS_ERROR_FAILURE; + + result = aLinks->GetLength (&links_count); + if (NS_FAILED (result)) return NS_ERROR_FAILURE; + + for (PRUint32 i = 0; i < links_count; i++) + { + nsCOMPtr<nsIDOMNode> link; + result = links->Item (i, getter_AddRefs (link)); + if (NS_FAILED (result)) continue; + + nsCOMPtr<nsIDOMElement> linkElement; + linkElement = do_QueryInterface (link); + if (!linkElement) continue; + + NS_NAMED_LITERAL_STRING(attr_href, "href"); + nsAutoString value; + linkElement->GetAttribute (attr_href, value); + if (value.IsEmpty()) continue; + + const nsACString &link = NS_ConvertUCS2toUTF8(value); + + if (link.IsEmpty()) continue; + + nsCOMPtr<nsIDocument> doc = + do_QueryInterface (aDOMDocument); + if(!doc) continue; + + nsCOMPtr<nsIURI> uri; + doc->GetDocumentURL(getter_AddRefs(uri)); + + nsCAutoString tmp; + result = uri->Resolve (link, tmp); + + LinkListItem *i = g_new0 (LinkListItem, 1); + + if (!tmp.IsEmpty()) + { + i->url = g_strdup (tmp.get()); + } + else + { + i->url = g_strdup (link.get()); + } + + NS_NAMED_LITERAL_STRING(attr_title, "title"); + linkElement->GetAttribute (attr_title, value); + if (!value.IsEmpty()) + { + const nsACString &s = NS_ConvertUCS2toUTF8(value); + i->title = gul_string_strip_newline (PromiseFlatCString(s).get()); + } + + NS_NAMED_LITERAL_STRING(attr_rel, "rel"); + linkElement->GetAttribute (attr_rel, value); + if (!value.IsEmpty()) + { + const nsACString &s = NS_ConvertUCS2toUTF8(value); + i->rel = g_strdup (PromiseFlatCString(s).get()); + g_strdown (i->rel); + } + if (!i->rel || strlen (i->rel) == 0) + { + NS_NAMED_LITERAL_STRING(attr_rev, "rev"); + linkElement->GetAttribute (attr_rev, value); + if (!value.IsEmpty()) + { + const nsACString &s = NS_ConvertUCS2toUTF8(value); + i->rel = g_strdup (PromiseFlatCString(s).get()); + g_strdown (i->rel); + } + } + + *ret = g_list_append (*ret, i); + } + + /* next, get a list of anchors */ + nsCOMPtr<nsIDOMHTMLDocument> doc = do_QueryInterface(aDOMDocument); + if(!doc) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMHTMLCollection> col; + doc->GetLinks(getter_AddRefs(col)); + + PRUint32 count, i; + col->GetLength(&count); + for (i = 0; i < count; i++) + { + nsCOMPtr<nsIDOMNode> node; + col->Item(i, getter_AddRefs(node)); + if (!node) continue; + + nsCOMPtr<nsIDOMHTMLElement> element; + element = do_QueryInterface(node); + if (!element) continue; + + nsCOMPtr<nsIDOMHTMLAnchorElement> lnk; + lnk = do_QueryInterface(element); + if (!lnk) continue; + + LinkListItem *i = g_new0 (LinkListItem, 1); + + nsAutoString tmp; + + result = lnk->GetHref (tmp); + if (NS_SUCCEEDED(result)) + { + const nsACString &c = NS_ConvertUCS2toUTF8(tmp); + i->url = g_strdup (PromiseFlatCString(c).get()); + } + + result = lnk->GetRel (tmp); + if (NS_SUCCEEDED(result)) + { + const nsACString &c = NS_ConvertUCS2toUTF8(tmp); + i->rel = g_strdup (PromiseFlatCString(c).get()); + g_strdown (i->rel); + } + + if (!i->rel || strlen (i->rel) == 0) + { + result = lnk->GetRev (tmp); + if (NS_SUCCEEDED(result)) + { + const nsACString &c = NS_ConvertUCS2toUTF8(tmp); + i->rel = g_strdup (PromiseFlatCString(c).get()); + g_strdown (i->rel); + } + } + + i->title = mozilla_get_link_text (node); + if (i->title == NULL) + { + result = element->GetTitle (tmp); + if (NS_SUCCEEDED(result)) + { + const nsACString &c = NS_ConvertUCS2toUTF8(tmp); + i->title = gul_string_strip_newline (PromiseFlatCString(c).get()); + } + } + + + *ret = g_list_append (*ret, i); + } +#endif + return NS_OK; +} + +nsresult EphyWrapper::EvaluateJS (char *script) +{ + nsresult rv; + + nsCOMPtr<nsIDOMWindow> DOMWindow; + rv = mWebBrowser->GetContentDOMWindow(getter_AddRefs(DOMWindow)); + + nsCOMPtr<nsIScriptGlobalObject> globalObject; + globalObject = do_QueryInterface (DOMWindow); + if (!globalObject) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIScriptContext> context; + rv = globalObject->GetContext(getter_AddRefs(context)); + if (NS_FAILED(rv) || !context) { + return NS_ERROR_FAILURE; + } + + context->SetProcessingScriptTag(PR_TRUE); + + PRBool isUndefined; + nsAutoString ret; + const nsAString &aScript = NS_ConvertUTF8toUCS2(script); + context->EvaluateString(aScript, nsnull, nsnull, nsnull, + 0, nsnull, + ret, &isUndefined); + + context->SetProcessingScriptTag(PR_FALSE); + + return NS_OK; +} + +nsresult EphyWrapper::PushTargetDocument (nsIDOMDocument *domDoc) +{ + mTargetDocument = domDoc; + + return NS_OK; +} + +nsresult EphyWrapper::PopTargetDocument () +{ + mTargetDocument = nsnull; + + return NS_OK; +} diff --git a/embed/mozilla/EphyWrapper.h b/embed/mozilla/EphyWrapper.h new file mode 100644 index 000000000..04379546c --- /dev/null +++ b/embed/mozilla/EphyWrapper.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2000 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_WRAPPER_H +#define EPHY_WRAPPER_H + +#include "nsIDocShell.h" +#include "ProgressListener.h" +#include "nsIWebNavigation.h" +#include "nsIWebPageDescriptor.h" +#include "nsISHistory.h" +#include "nsIWebBrowser.h" +#include "nsIWebProgressListener.h" +#include "nsCOMPtr.h" +#include "nsIDOMEventReceiver.h" +#include "nsIDOMDocument.h" +#include "nsPIDOMWindow.h" +#include <gtkmozembed.h> + +#include "nsIPrintSettings.h" + +class EphyEventListener; + +class EphyWrapper +{ +public: + EphyWrapper(); + ~EphyWrapper(); + + nsresult Init (GtkMozEmbed *mozembed); + nsresult Destroy (void); + + nsresult SetZoom (float aTextZoom, PRBool reflow); + nsresult GetZoom (float *aTextZoom); + + nsresult Print (nsIPrintSettings *options, PRBool preview); + nsresult GetPrintSettings (nsIPrintSettings * *options); + nsresult PrintPreviewClose (void); + nsresult PrintPreviewNumPages (int *numPages); + nsresult PrintPreviewNavigate(PRInt16 navType, PRInt32 pageNum); + + nsresult Find (const PRUnichar *search_string, + PRBool matchcase, PRBool interactive, + PRBool search_backwards, PRBool search_wrap_around, + PRBool search_for_entire_word, PRBool search_in_frames, + PRBool *didFind); + + nsresult GetMainDocumentUrl (nsCString &url); + nsresult GetDocumentUrl (nsCString &url); + nsresult GetDocumentTitle (char **title); + + nsresult ReloadDocument (); + nsresult LoadDocument(nsISupports *aPageDescriptor, PRUint32 aDisplayType); + nsresult GetPageDescriptor(nsISupports **aPageDescriptor); + + nsresult GetSHInfo (PRInt32 *count, PRInt32 *index); + nsresult GetSHTitleAtIndex (PRInt32 index, PRUnichar **title); + nsresult GetSHUrlAtIndex (PRInt32 index, nsCString &url); + + nsresult CopyHistoryTo (EphyWrapper *embed); + + nsresult GoToHistoryIndex (PRInt16 index); + + nsresult ForceCharacterSet (char *charset); + + nsresult CanCutSelection(PRBool *result); + + nsresult CanCopySelection(PRBool *result); + + nsresult CanPaste(PRBool *result); + + nsresult CutSelection(void); + + nsresult CopySelection(void); + + nsresult Paste(void); + + nsresult Activate (); + nsresult Deactivate (); + + nsresult GetMainDOMDocument (nsIDOMDocument **aDOMDocument); + + nsresult GetLinkInterfaceItems (GList **list); + + nsresult GetRealURL (nsCString &ret); + + nsresult SelectAll (void); + + nsresult ScrollUp (void); + nsresult ScrollDown (void); + nsresult ScrollLeft (void); + nsresult ScrollRight (void); + + nsresult FineScroll (int horiz, int vert); + + nsresult GetLastModified (gchar **ret); + nsresult GetImages (GList **ret); + nsresult GetForms (GList **ret); + nsresult GetLinks (GList **ret); + nsresult EvaluateJS (char *script); + + nsresult PushTargetDocument (nsIDOMDocument *domDoc); + nsresult PopTargetDocument (); + + nsresult GetDOMDocument (nsIDOMDocument **aDOMDocument); + nsresult GetDOMWindow (nsIDOMWindow **aDOMWindow); + + nsCOMPtr<nsIWebBrowser> mWebBrowser; + + nsCOMPtr<nsIWebNavigation> mChromeNav; + + GtkMozEmbed *mGtkMozEmbed; +private: + nsCOMPtr<nsIDOMDocument> mTargetDocument; + nsCOMPtr<nsIWebProgressListener> mProgress; + nsCOMPtr<nsIDOMEventReceiver> mEventReceiver; + EphyEventListener *mEventListener; + PRBool mListenersAttached; + + void GetListener (void); + void AttachListeners (void); + void DetachListeners (void); + nsresult SetZoomOnDocshell (float aZoom, nsIDocShell *DocShell); + nsresult GetDocShell (nsIDocShell **aDocShell); + nsresult GetCSSBackground (nsIDOMNode *node, nsAutoString& url); + nsresult GetFocusedDOMWindow (nsIDOMWindow **aDOMWindow); + nsresult GetSHistory (nsISHistory **aSHistory); + nsresult GetPIDOMWindow(nsPIDOMWindow **aPIWin); + nsresult GetWebNavigation(nsIWebNavigation **aWebNavigation); +}; + +#endif diff --git a/embed/mozilla/EventContext.cpp b/embed/mozilla/EventContext.cpp new file mode 100644 index 000000000..9d4e312b6 --- /dev/null +++ b/embed/mozilla/EventContext.cpp @@ -0,0 +1,669 @@ +/* + * Copyright (C) 2000 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "EventContext.h" +#include "nsIDOMEventTarget.h" +#include "nsIDocument.h" +#include "nsIDOMHTMLInputElement.h" +#include "nsIDOMHTMLObjectElement.h" +#include "nsIInterfaceRequestor.h" +#include "nsIDOMHTMLImageElement.h" +#include "nsIDOMElement.h" +#include "nsIDOMXULDocument.h" +#include "nsIURI.h" +#include "nsIDOMNSDocument.h" +#include "nsReadableUtils.h" +#include "nsUnicharUtils.h" +#include "nsGUIEvent.h" +#include "nsIDOMNSEvent.h" +#include "nsIDOMCharacterData.h" +#include "nsIDOMHTMLButtonElement.h" +#include "nsIDOMHTMLLabelElement.h" +#include "nsIDOMHTMLLegendElement.h" +#include "nsIDOMHTMLTextAreaElement.h" +#include <gdk/gdkkeysyms.h> +#include "nsIPrivateDOMEvent.h" +#include "nsIDOMNSUIEvent.h" + +#define KEY_CODE 256 + +EventContext::EventContext () +{ +} + +EventContext::~EventContext () +{ +} + +nsresult EventContext::Init (nsIDOMEvent *event, EphyWrapper *wrapper) +{ + mEvent = event; + mWrapper = wrapper; + mDOMDocument = nsnull; + + return NS_OK; +} + +nsresult EventContext::GetEventContext (nsIDOMEventTarget *EventTarget, + EphyEmbedEvent *info) +{ + nsresult rv; + + mEmbedEvent = info; + + info->context = EMBED_CONTEXT_DOCUMENT; + + nsCOMPtr<nsIDOMNode> node = do_QueryInterface(EventTarget, &rv); + if (NS_FAILED(rv) || !node) return NS_ERROR_FAILURE; + + /* Is page xul ? then do not display context menus + * FIXME I guess there is an easier way ... */ + /* From philipl: This test needs to be here otherwise we + * arrogantly assume we can QI to a HTMLElement, which is + * not true for xul content. */ + + nsCOMPtr<nsIDOMDocument> domDoc; + rv = node->GetOwnerDocument(getter_AddRefs(domDoc)); + if (NS_FAILED(rv) || !domDoc) return NS_ERROR_FAILURE; + + mDOMDocument = domDoc; + + nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc, &rv); + if (NS_FAILED(rv) || !doc) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMXULDocument> xul_document = do_QueryInterface(domDoc); + if (xul_document) + { + info->context = EMBED_CONTEXT_NONE; + return NS_ERROR_FAILURE; + } + + // Now we know that the page isn't a xul window, we can try and + // do something useful with it. + + PRUint16 type; + rv = node->GetNodeType(&type); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMHTMLElement> element = do_QueryInterface(node); + if ((nsIDOMNode::ELEMENT_NODE == type) && element) + { + nsAutoString tag; + rv = element->GetTagName(tag); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + if (tag.Equals(NS_LITERAL_STRING("img"), + nsCaseInsensitiveStringComparator())) + { + info->context |= EMBED_CONTEXT_IMAGE; + + nsAutoString img; + nsCOMPtr <nsIDOMHTMLImageElement> image = + do_QueryInterface(node, &rv); + if (NS_FAILED(rv) || !image) return NS_ERROR_FAILURE; + + rv = image->GetSrc (img); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + SetStringProperty ("image", img); + + rv = image->GetAlt (img); + if (NS_SUCCEEDED(rv)) + { + SetStringProperty ("image_alt", img); + } + + rv = image->GetLongDesc (img); + if (NS_SUCCEEDED(rv) && !img.IsEmpty()) + { + nsCAutoString imglongdesc; + const nsACString &src = NS_ConvertUCS2toUTF8(img); + + nsCOMPtr<nsIURI> uri; + doc->GetDocumentURL(getter_AddRefs(uri)); + + rv = uri->Resolve (src, imglongdesc); + + SetStringProperty ("image_long_desc", + NS_ConvertUTF8toUCS2(imglongdesc)); + } + + int imgwidth, imgheight; + rv = image->GetWidth (&imgwidth); + rv = image->GetHeight (&imgheight); + SetIntProperty ("image_width", imgwidth); + SetIntProperty ("image_height", imgheight); + + rv = element->GetTitle (img); + if (NS_SUCCEEDED(rv)) + { + SetStringProperty ("image_title", + img); + } + } + else if (tag.Equals(NS_LITERAL_STRING("input"), + nsCaseInsensitiveStringComparator())) + { + nsCOMPtr<nsIDOMElement> element; + element = do_QueryInterface (node); + if (!element) return NS_ERROR_FAILURE; + + NS_NAMED_LITERAL_STRING(attr, "type"); + nsAutoString value; + element->GetAttribute (attr, value); + + if (value.Equals(NS_LITERAL_STRING("image"), + nsCaseInsensitiveStringComparator())) + { + info->context |= EMBED_CONTEXT_IMAGE; + nsCOMPtr<nsIDOMHTMLInputElement> input; + input = do_QueryInterface (node); + if (!input) return NS_ERROR_FAILURE; + + nsAutoString img; + rv = input->GetSrc (img); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCAutoString cImg; + const nsACString &src = NS_ConvertUCS2toUTF8(img); + + nsCOMPtr<nsIURI> uri; + doc->GetDocumentURL(getter_AddRefs(uri)); + rv = uri->Resolve (src, cImg); + SetStringProperty ("image", + NS_ConvertUTF8toUCS2(cImg)); + + if (NS_FAILED (rv)) return NS_ERROR_FAILURE; + } + else if (!value.Equals(NS_LITERAL_STRING("radio"), + nsCaseInsensitiveStringComparator()) && + !value.Equals(NS_LITERAL_STRING("submit"), + nsCaseInsensitiveStringComparator()) && + !value.Equals(NS_LITERAL_STRING("reset"), + nsCaseInsensitiveStringComparator()) && + !value.Equals(NS_LITERAL_STRING("hidden"), + nsCaseInsensitiveStringComparator()) && + !value.Equals(NS_LITERAL_STRING("button"), + nsCaseInsensitiveStringComparator()) && + !value.Equals(NS_LITERAL_STRING("checkbox"), + nsCaseInsensitiveStringComparator())) + { + info->context |= EMBED_CONTEXT_INPUT; + } + } + else if (tag.Equals(NS_LITERAL_STRING("textarea"), + nsCaseInsensitiveStringComparator())) + { + info->context |= EMBED_CONTEXT_INPUT; + } + else if (tag.Equals(NS_LITERAL_STRING("object"), + nsCaseInsensitiveStringComparator())) + { + nsCOMPtr<nsIDOMHTMLObjectElement> object; + object = do_QueryInterface (node); + if (!element) return NS_ERROR_FAILURE; + + nsAutoString value; + object->GetType(value); + + //Forming a substring and confirming it's contents + //is quicker than doing a Find on the full string + //and then checking that "image/" is at the beginning + if (Substring(value, 0, 6).Equals(NS_LITERAL_STRING("image/"), + nsCaseInsensitiveStringComparator())) + { + info->context |= EMBED_CONTEXT_IMAGE; + + nsAutoString img; + + rv = object->GetData (img); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCAutoString cImg; + const nsACString &src = NS_ConvertUCS2toUTF8(img); + + nsCOMPtr<nsIURI> uri; + doc->GetDocumentURL(getter_AddRefs(uri)); + rv = uri->Resolve (src, cImg); + SetStringProperty ("image", + NS_ConvertUTF8toUCS2(cImg)); + + if (NS_FAILED (rv)) return NS_ERROR_FAILURE; + } + else + { + info->context = EMBED_CONTEXT_NONE; + return NS_OK; + } + } + } + + /* Is page framed ? */ + PRBool framed; + IsPageFramed (node, &framed); + SetIntProperty ("framed_page", framed); + + /* Bubble out, looking for items of interest */ + while (node) + { + nsCOMPtr <nsIDOMElement> dom_elem = do_QueryInterface(node); + if (dom_elem) + { + NS_NAMED_LITERAL_STRING(nspace, "http://www.w3.org/1999/xlink"); + NS_NAMED_LITERAL_STRING(localname_type, "type"); + + nsAutoString value; + dom_elem->GetAttributeNS (nspace, localname_type, value); + + if (value.Equals(NS_LITERAL_STRING("simple"), + nsCaseInsensitiveStringComparator())) + { + info->context |= EMBED_CONTEXT_LINK; + NS_NAMED_LITERAL_STRING (localname_href, "href"); + dom_elem->GetAttributeNS (nspace, localname_href, value); + + SetStringProperty ("link", value); + } + } + + PRUint16 type; + rv = node->GetNodeType(&type); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + element = do_QueryInterface(node); + if ((nsIDOMNode::ELEMENT_NODE == type) && element) + { + nsAutoString tag; + rv = element->GetTagName(tag); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + /* Link */ + if (tag.Equals(NS_LITERAL_STRING("a"), + nsCaseInsensitiveStringComparator())) + { + nsCOMPtr <nsIDOMHTMLAnchorElement> anchor = + do_QueryInterface(node); + nsAutoString tmp; + rv = anchor->GetHref (tmp); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + if (Substring(tmp, 0, 7).Equals(NS_LITERAL_STRING("mailto:"), + nsCaseInsensitiveStringComparator())) + { + info->context |= EMBED_CONTEXT_EMAIL_LINK; + const nsAString &address = Substring(tmp, 7, tmp.Length()-7); + SetStringProperty ("email", address); + } + + if (anchor && !tmp.IsEmpty()) + { + info->context |= EMBED_CONTEXT_LINK; + + SetStringProperty ("link", tmp); + rv = anchor->GetHreflang (tmp); + if (NS_SUCCEEDED(rv)) + SetStringProperty ("link_lang", tmp); + rv = anchor->GetTarget (tmp); + if (NS_SUCCEEDED(rv)) + SetStringProperty ("link_target", tmp); + rv = anchor->GetRel (tmp); + if (NS_SUCCEEDED(rv)) + SetStringProperty ("link_rel", tmp); + rv = anchor->GetRev (tmp); + if (NS_SUCCEEDED(rv)) + SetStringProperty ("link_rev", tmp); + rv = element->GetTitle (tmp); + if (NS_SUCCEEDED(rv)) + SetStringProperty ("link_title", tmp); + rv = anchor->GetType (tmp); + if (NS_SUCCEEDED(rv)) + SetStringProperty ("link_type", tmp); + + if (tmp.Equals(NS_LITERAL_STRING("text/smartbookmark"), + nsCaseInsensitiveStringComparator())) + { + SetIntProperty ("link_is_smart", TRUE); + + nsCOMPtr<nsIDOMNode> childNode; + node->GetFirstChild (getter_AddRefs(childNode)); + if (childNode) + { + nsCOMPtr <nsIDOMHTMLImageElement> image = + do_QueryInterface(childNode, &rv); + + if (image) + { + nsAutoString img; + rv = image->GetSrc (img); + if (!NS_FAILED(rv)) + { + SetStringProperty ("image", img); + } + } + } + } +#ifdef NOT_PORTED + /* Get the text of the link */ + info->linktext = mozilla_get_link_text (node); +#endif + } + + } + else if (tag.Equals(NS_LITERAL_STRING("option"), + nsCaseInsensitiveStringComparator())) + { + info->context = EMBED_CONTEXT_NONE; + return NS_OK; + } + if (tag.Equals(NS_LITERAL_STRING("area"), + nsCaseInsensitiveStringComparator())) + { + info->context |= EMBED_CONTEXT_LINK; + nsCOMPtr <nsIDOMHTMLAreaElement> area = + do_QueryInterface(node, &rv); + if (NS_SUCCEEDED(rv) && area) + { + nsAutoString href; + rv = area->GetHref (href); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + SetStringProperty ("link", href); + } + } + else if (tag.Equals(NS_LITERAL_STRING("textarea"), + nsCaseInsensitiveStringComparator()) || + tag.Equals(NS_LITERAL_STRING("input"), + nsCaseInsensitiveStringComparator())) + { + info->context |= EMBED_CONTEXT_INPUT; + } + + nsCOMPtr<nsIDOMElement> domelement; + domelement = do_QueryInterface (node); + if (!domelement) return NS_ERROR_FAILURE; + + PRBool has_background = PR_FALSE; + + NS_NAMED_LITERAL_STRING(attr, "background"); + nsAutoString value; + domelement->GetAttribute (attr, value); + + if (!value.IsEmpty()) + { + nsCAutoString bgimg; + const nsACString &tmp = + NS_ConvertUCS2toUTF8(value); + + nsCOMPtr<nsIURI> uri; + doc->GetDocumentURL(getter_AddRefs(uri)); + rv = uri->Resolve (tmp, bgimg); + if (NS_FAILED (rv)) + return NS_ERROR_FAILURE; + SetStringProperty ("background_image", + NS_ConvertUTF8toUCS2(bgimg)); + } + else + { + nsCOMPtr<nsIDOMHTMLBodyElement> bgelement; + bgelement = do_QueryInterface (node); + if (bgelement) + { + nsAutoString value; + bgelement->GetBackground (value); + + if (!value.IsEmpty()) + { + nsCAutoString bgimg; + const nsACString &tmp = + NS_ConvertUCS2toUTF8(value); + + nsIURI *uri; + doc->GetBaseURL(uri); + rv = uri->Resolve + (tmp, bgimg); + SetStringProperty ("background_image", + NS_ConvertUTF8toUCS2(bgimg)); + if (NS_FAILED (rv)) + return NS_ERROR_FAILURE; + has_background = PR_TRUE; + } + } + } + + if (!has_background) + { + nsAutoString cssurl; + rv = GetCSSBackground (node, cssurl); + if (NS_SUCCEEDED (rv)) + { + nsCAutoString bgimg; + const nsACString &tmp = + NS_ConvertUCS2toUTF8(cssurl); + + nsIURI *uri; + doc->GetBaseURL(uri); + rv = uri->Resolve + (tmp, bgimg); + SetStringProperty ("background_image", + NS_ConvertUTF8toUCS2(bgimg)); + if (NS_FAILED (rv)) + return NS_ERROR_FAILURE; + } + } + } + + nsCOMPtr<nsIDOMNode> parentNode; + node->GetParentNode (getter_AddRefs(parentNode)); + node = parentNode; + } + + return NS_OK; +} + +nsresult EventContext::GetCSSBackground (nsIDOMNode *node, nsAutoString& url) +{ + nsresult result; + + nsCOMPtr<nsIDOMElementCSSInlineStyle> style; + style = do_QueryInterface (node); + if (!style) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMCSSStyleDeclaration> decl; + result = style->GetStyle (getter_AddRefs(decl)); + if (NS_FAILED(result)) return NS_ERROR_FAILURE; + + nsAutoString value; + NS_NAMED_LITERAL_STRING(prop_bgi, "background-image"); + decl->GetPropertyValue (prop_bgi, value); + + if (value.IsEmpty()) + { + NS_NAMED_LITERAL_STRING(prop_bg, "background"); + decl->GetPropertyValue (prop_bg, value); + if (value.IsEmpty()) + { + NS_NAMED_LITERAL_STRING(prop_bgr, "background-repeat"); + decl->GetPropertyValue (prop_bgr, value); + if (value.IsEmpty()) + return NS_ERROR_FAILURE; + } + } + + PRInt32 start, end; + nsAutoString cssurl; + + NS_NAMED_LITERAL_STRING(startsub, "url("); + NS_NAMED_LITERAL_STRING(endsub, ")"); + + start = value.Find (startsub) + 4; + end = value.Find (endsub); + + if (start == -1 || end == -1) + return NS_ERROR_FAILURE; + + url.Assign(Substring (value, start, end - start)); + + return NS_OK; +} + +nsresult EventContext::GetMouseEventInfo (EphyEmbedEvent *info) +{ + nsresult result; + DOMTimeStamp ts; + nsIDOMMouseEvent *aMouseEvent = (nsIDOMMouseEvent*)mEvent; + + aMouseEvent->GetButton ((PRUint16*)&info->mouse_button); + aMouseEvent->GetScreenX ((PRInt32*)&info->mouse_x); + aMouseEvent->GetScreenY ((PRInt32*)&info->mouse_y); + + aMouseEvent->GetTimeStamp(&ts); + info->timestamp = ts; + + /* be sure we are not clicking on the scroolbars */ + + nsCOMPtr<nsIDOMNSEvent> nsEvent = do_QueryInterface(aMouseEvent, &result); + if (NS_FAILED(result) || !nsEvent) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMEventTarget> OriginalTarget; + result = nsEvent->GetOriginalTarget(getter_AddRefs(OriginalTarget)); + if (NS_FAILED(result) || !OriginalTarget) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMNode> OriginalNode = do_QueryInterface(OriginalTarget); + if (!OriginalNode) return NS_ERROR_FAILURE; + + nsAutoString nodename; + OriginalNode->GetNodeName(nodename); + + if (nodename.Equals(NS_LITERAL_STRING("xul:scrollbarbutton"), + nsCaseInsensitiveStringComparator()) || + nodename.Equals(NS_LITERAL_STRING("xul:thumb"), + nsCaseInsensitiveStringComparator()) || + nodename.Equals(NS_LITERAL_STRING("xul:vbox"), + nsCaseInsensitiveStringComparator()) || + nodename.Equals(NS_LITERAL_STRING("xul:spacer"), + nsCaseInsensitiveStringComparator()) || + nodename.Equals(NS_LITERAL_STRING("xul:slider"), + nsCaseInsensitiveStringComparator())) + return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMEventTarget> EventTarget; + result = aMouseEvent->GetTarget(getter_AddRefs(EventTarget)); + if (NS_FAILED(result) || !EventTarget) return NS_ERROR_FAILURE; + + result = GetEventContext (EventTarget, info); + if (NS_FAILED(result)) return result; + + /* Get the modifier */ + + PRBool mod_key; + + info->modifier = 0; + + aMouseEvent->GetAltKey(&mod_key); + if (mod_key) info->modifier |= GDK_MOD1_MASK; + + aMouseEvent->GetShiftKey(&mod_key); + if (mod_key) info->modifier |= GDK_SHIFT_MASK; + + aMouseEvent->GetMetaKey(&mod_key); + if (mod_key) info->modifier |= GDK_Meta_L; + + aMouseEvent->GetCtrlKey(&mod_key); + if (mod_key) info->modifier |= GDK_CONTROL_MASK; + + return NS_OK; +} + +nsresult EventContext::IsPageFramed (nsIDOMNode *node, PRBool *Framed) +{ + nsresult result; + + nsCOMPtr<nsIDOMDocument> mainDocument; + result = mWrapper->GetMainDOMDocument (getter_AddRefs(mainDocument)); + if (NS_FAILED(result) || !mainDocument) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMDocument> nodeDocument; + result = node->GetOwnerDocument (getter_AddRefs(nodeDocument)); + if (NS_FAILED(result) || !nodeDocument) return NS_ERROR_FAILURE; + + *Framed = (mainDocument != nodeDocument); + + return NS_OK; +} + +nsresult EventContext::GetTargetDocument (nsIDOMDocument **domDoc) +{ + if (!mDOMDocument) return NS_ERROR_FAILURE; + + *domDoc = mDOMDocument.get(); + + NS_IF_ADDREF(*domDoc); + + return NS_OK; +} + +nsresult EventContext::SetIntProperty (const char *name, int value) +{ + + GValue *val = g_new0 (GValue, 1); + + g_value_init (val, G_TYPE_INT); + + g_value_set_int (val, value); + + ephy_embed_event_set_property (mEmbedEvent, + g_strdup (name), + val); + + return NS_OK; +} + +nsresult EventContext::SetStringProperty (const char *name, const char *value) +{ + GValue *val = g_new0 (GValue, 1); + + g_value_init (val, G_TYPE_STRING); + + g_value_set_string (val, value); + + ephy_embed_event_set_property (mEmbedEvent, + g_strdup (name), + val); + + return NS_OK; +} + +nsresult EventContext::SetStringProperty (const char *name, const nsAString &value) +{ + GValue *val = g_new0 (GValue, 1);; + char *tmp; + + tmp = ToNewCString (NS_ConvertUCS2toUTF8(value)); + + g_value_init (val, G_TYPE_STRING); + + g_value_set_string (val, tmp); + + ephy_embed_event_set_property (mEmbedEvent, + g_strdup (name), + val); + nsMemory::Free (tmp); + + return NS_OK; +} diff --git a/embed/mozilla/EventContext.h b/embed/mozilla/EventContext.h new file mode 100644 index 000000000..432bd1f53 --- /dev/null +++ b/embed/mozilla/EventContext.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2000 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EVENT_CONTEXT_H +#define EVENT_CONTEXT_H + +#include "nsIDOMMouseEvent.h" +#include "nsIDOMKeyEvent.h" +#include "nsIDOMEvent.h" +#include "nsIDOMNode.h" +#include "nsString.h" +#include "nsIDOMHTMLAnchorElement.h" +#include "nsIDOMNSHTMLElement.h" +#include "nsIDOMHTMLAreaElement.h" +#include "nsIDOMHTMLBodyElement.h" +#include "nsIDOMElementCSSInlineStyle.h" +#include "nsIDOMCSSStyleDeclaration.h" +#include "nsIDOMDocument.h" +#include "EphyWrapper.h" + +#include "ephy-embed.h" +#include "ephy-embed-event.h" + +class EventContext +{ +public: + EventContext(); + ~EventContext(); + + nsresult Init (nsIDOMEvent *event, EphyWrapper *wrapper); + + nsresult GetMouseEventInfo (EphyEmbedEvent *info); + nsresult GetTargetDocument (nsIDOMDocument **domDoc); + +private: + nsIDOMEvent *mEvent; + EphyWrapper *mWrapper; + nsCOMPtr<nsIDOMDocument> mDOMDocument; + + nsresult GetEventContext (nsIDOMEventTarget *EventTarget, + EphyEmbedEvent *info); + nsresult GetCSSBackground (nsIDOMNode *node, nsAutoString& url); + nsresult IsPageFramed (nsIDOMNode *node, PRBool *Framed); + nsresult SetIntProperty (const char *name, int value); + nsresult SetStringProperty (const char *name, const char *value); + nsresult SetStringProperty (const char *name, const nsAString &value); + EphyEmbedEvent *mEmbedEvent; +}; + +#endif diff --git a/embed/mozilla/ExternalProtocolService.cpp b/embed/mozilla/ExternalProtocolService.cpp new file mode 100644 index 000000000..728cd0f5c --- /dev/null +++ b/embed/mozilla/ExternalProtocolService.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <gtk/gtk.h> +#include <libgnome/gnome-exec.h> +#include <libgnome/gnome-i18n.h> +#include <libgnome/gnome-url.h> + +#include <nsString.h> +#include <nsXPIDLString.h> +#include <nsCOMPtr.h> +#include <nsIURI.h> +#include <nsIDOMWindow.h> +#include <nsIWindowWatcher.h> +#include <nsIServiceManager.h> +#include <nsXPComFactory.h> + +#include "ephy-prefs.h" +#include "eel-gconf-extensions.h" + +#include "ExternalProtocolService.h" + +#define WINDOWWATCHER_CONTRACTID "@mozilla.org/embedcomp/window-watcher;1" + +/* Implementation file */ +NS_IMPL_ISUPPORTS1(GExternalProtocolService, nsIExternalProtocolService) + +GExternalProtocolService::GExternalProtocolService() +{ + NS_INIT_ISUPPORTS(); + /* member initializers and constructor code */ +} + +GExternalProtocolService::~GExternalProtocolService() +{ + /* destructor code */ +} + +/* boolean externalProtocolHandlerExists (in string aProtocolScheme); */ +NS_IMETHODIMP GExternalProtocolService:: + ExternalProtocolHandlerExists(const char *aProtocolScheme, + PRBool *_retval) +{ + /* build the config key */ + char *key = g_strconcat ("/desktop/gnome/url-handlers/", + aProtocolScheme, + "/command", NULL); + + char *tmp = eel_gconf_get_string(key); + g_free (key); + + *_retval = (tmp != NULL); + g_free (tmp); + + return NS_OK; +} + +/* void loadUrl (in nsIURI aURL); */ +NS_IMETHODIMP GExternalProtocolService::LoadUrl(nsIURI *aURL) +{ + nsCAutoString cSpec; + aURL->GetSpec (cSpec); + nsCAutoString cScheme; + aURL->GetScheme (cScheme); + + if (cScheme.Equals("http")) + { + nsresult rv; + nsCOMPtr<nsIWindowWatcher> ww; + ww = do_GetService(WINDOWWATCHER_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr<nsIDOMWindow> newWin; + rv = ww->OpenWindow(nsnull, cSpec.get(), + nsnull, nsnull, nsnull, + getter_AddRefs(newWin)); + if (NS_SUCCEEDED(rv)) return NS_OK; + } + } + + /* build the config key */ + const nsCAutoString key(NS_LITERAL_CSTRING("/desktop/gnome/url-handlers/") + + cScheme + NS_LITERAL_CSTRING("/command")); + + /* find it */ + char *result = eel_gconf_get_string(key.get()); + if (result) + { + gnome_url_show(cSpec.get(), NULL); + g_free (result); + return NS_OK; + } + + /* no luck, so offer the user the option of trying the + * default handler -- we don't do this automatically in + * case the default handler is erroneously set to epiphany */ + result = eel_gconf_get_string("/desktop/gnome/url-handlers/unknown/command"); + + /* check there is a default */ + { + GtkWidget *dialog; + + /* throw the error */ + dialog = gtk_message_dialog_new (NULL, (GtkDialogFlags)0, + GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, + _("Galeon cannot handle this protocol,\n" + "and no GNOME default handler is set")); + gtk_dialog_run (GTK_DIALOG(dialog)); + gtk_widget_destroy (dialog); + + /* don't let mozilla try blindly */ + return NS_ERROR_FAILURE; + } + g_free (result); + + /* offer the choice */ + GtkWidget *dialog = gtk_message_dialog_new (NULL, (GtkDialogFlags)0, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_YES_NO, + _("The protocol specified " + "is not recognised.\n\n" + "Would you like to try " + "the GNOME default?")); + + int ret = gtk_dialog_run (GTK_DIALOG(dialog)); + gtk_widget_destroy (dialog); + + if (ret == 0) + { + gnome_url_show(cSpec.get(), NULL); + return NS_OK; + } + else + { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +NS_DEF_FACTORY (GExternalProtocolService, GExternalProtocolService); + +/** + * NS_NewExternalProtocolServiceFactory: + */ +nsresult NS_NewExternalProtocolServiceFactory(nsIFactory** aFactory) +{ + NS_ENSURE_ARG_POINTER(aFactory); + *aFactory = nsnull; + + nsGExternalProtocolServiceFactory *result = new nsGExternalProtocolServiceFactory; + if (result == NULL) + { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(result); + *aFactory = result; + + return NS_OK; +} diff --git a/embed/mozilla/ExternalProtocolService.h b/embed/mozilla/ExternalProtocolService.h new file mode 100644 index 000000000..3c49d61e7 --- /dev/null +++ b/embed/mozilla/ExternalProtocolService.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ExternalProtocolService_h__ +#define __ExternalProtocolService_h__ + +#include "nsError.h" +#include "nsCExternalHandlerService.h" +#include "nsIExternalProtocolService.h" + +class GExternalProtocolService : public nsIExternalProtocolService +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIEXTERNALPROTOCOLSERVICE + + GExternalProtocolService(); + virtual ~GExternalProtocolService(); + /* additional members */ +}; + +#define G_EXTERNALPROTOCOLSERVICE_CID \ +{ /* d2a2f743-f126-4f1f-8921-d4e50490f112 */ \ + 0xd2a2f743, \ + 0xf126, \ + 0x4f1f, \ + {0x89, 0x21, 0xd4, 0xe5, 0x04, 0x90, 0xf1, 0x12} \ +} +#define G_EXTERNALPROTOCOLSERVICE_CLASSNAME "Galeon's ExternalProtocolService" + +class nsIFactory; + +extern nsresult NS_NewExternalProtocolServiceFactory(nsIFactory** aFactory); + +#endif // __ExternalProtocolService_h__ diff --git a/embed/mozilla/FilePicker.cpp b/embed/mozilla/FilePicker.cpp new file mode 100644 index 000000000..baae069ef --- /dev/null +++ b/embed/mozilla/FilePicker.cpp @@ -0,0 +1,505 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Things to be aware of: + * + * This filepicker, like the mozilla one, does not make an attempt + * to verify the validity of the initial directory you pass it. + * It does check that the user doesn't give it a garbage path + * during use, but it is the caller's responsibility to give a + * sensible initial path. + * + * At the current moment, we instantiate the filepicker directly + * in our contenthandler where there is path verification code + * and else where through our C wrapper, which also does verification. + * If, at a future date, you need to instantiate filepicker without + * using the C wrapper, please verify the initial path. See + * ContentHandler for a way to do this. + */ + +#include "ephy-string.h" +#include "ephy-gui.h" +#include "eel-gconf-extensions.h" + +#include <gtk/gtkmain.h> +#include <gtk/gtksignal.h> +#include <gtk/gtkmenu.h> +#include <gtk/gtkmenuitem.h> +#include <gtk/gtkcheckbutton.h> +#include <gtk/gtktogglebutton.h> +#include <gtk/gtkfilesel.h> +#include <gtk/gtkhbbox.h> +#include <gtk/gtkoptionmenu.h> +#include <gtk/gtkmessagedialog.h> +#include <libgnome/gnome-i18n.h> + +#include "nsIFilePicker.h" + +#include "nsCRT.h" +#include "nsCOMPtr.h" +#include "nsIFactory.h" +#include "nsISupportsArray.h" +#include "nsIServiceManager.h" +#include "nsXPComFactory.h" + +#include "nsString.h" +#include "nsXPIDLString.h" +#include "nsIPrefService.h" +#include "nsIURI.h" +#include "nsIFileURL.h" +#include "nsIChannel.h" +#include "nsIFileChannel.h" +#include "nsNetCID.h" +#include "nsILocalFile.h" +#include "nsIPromptService.h" +#include "nsReadableUtils.h" + +#include <libgnome/gnome-util.h> + +#include "FilePicker.h" +#include "MozillaPrivate.h" + +void filePicker_save_content_cb(GtkToggleButton *aButton, + GFilePicker *aFilePicker); + +/* Implementation file */ +NS_IMPL_ISUPPORTS1(GFilePicker, nsIFilePicker) + +GFilePicker::GFilePicker(PRBool showContentCheck, FileFormat *fileFormats) : + mSaveContent(PR_FALSE) +{ + NS_INIT_ISUPPORTS(); + /* member initializers and constructor code */ + + mShowContentCheck = showContentCheck; + mFileFormats = fileFormats; + mFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID); + mDisplayDirectory = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID); + mDisplayDirectory->InitWithNativePath(nsDependentCString(g_get_home_dir())); +} + +GFilePicker::~GFilePicker() +{ + /* destructor code */ +} + +//////////////////////////////////////////////////////////////////////////////// +// begin nsIFilePicker impl +//////////////////////////////////////////////////////////////////////////////// + +/* void init (in nsIDOMWindowInternal parent, in wstring title, in short mode); */ +NS_IMETHODIMP GFilePicker::Init(nsIDOMWindowInternal *aParent, + const PRUnichar *aTitle, PRInt16 aMode) +{ + mParent = do_QueryInterface(aParent); + mParentWidget = MozillaFindGtkParent(mParent); + mTitle = NS_ConvertUCS2toUTF8(aTitle); + mMode = aMode; + + return NS_OK; +} + +/* void appendFilters (in long filterMask); */ +NS_IMETHODIMP GFilePicker::AppendFilters(PRInt32 aFilterMask) +{ + //This function cannot be implemented due to the crippled + //nature of GtkFileSelection, but NS_ERROR_NOT_IMPLEMENTED + //is interpreted as a terminal error by some callers. + return NS_OK; +} + +/* void appendFilter (in wstring title, in wstring filter); */ +NS_IMETHODIMP GFilePicker::AppendFilter(const PRUnichar *aTitle, + const PRUnichar *aFilter) +{ + //GtkFileSelection is crippled, so we can't provide a short-list + //of filters to choose from. We provide minimal functionality + //by using the most recent AppendFilter call as the active filter. + mFilter = NS_ConvertUCS2toUTF8(aFilter); + return NS_OK; +} + +/* attribute long filterIndex; */ +NS_IMETHODIMP GFilePicker::GetFilterIndex(PRInt32 *aFilterIndex) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP GFilePicker::SetFilterIndex(PRInt32 aFilterIndex) +{ + return NS_OK; +} + +/* attribute wstring defaultString; */ +NS_IMETHODIMP GFilePicker::GetDefaultString(PRUnichar * *aDefaultString) +{ + *aDefaultString = ToNewUnicode(NS_ConvertUTF8toUCS2(mDefaultString)); + return NS_OK; +} +NS_IMETHODIMP GFilePicker::SetDefaultString(const PRUnichar *aDefaultString) +{ + if (aDefaultString) + mDefaultString = NS_ConvertUCS2toUTF8(aDefaultString); + else + mDefaultString = ""; + return NS_OK; +} + +/* attribute wstring defaultExtension; */ +// Again, due to the crippled file selector, we can't really +// do anything here. +NS_IMETHODIMP GFilePicker::GetDefaultExtension(PRUnichar * *aDefaultExtension) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP GFilePicker::SetDefaultExtension(const PRUnichar *aDefaultExtension) +{ + return NS_OK; +} + +/* attribute nsILocalFile displayDirectory; */ +NS_IMETHODIMP GFilePicker::GetDisplayDirectory(nsILocalFile * *aDisplayDirectory) +{ + NS_IF_ADDREF(*aDisplayDirectory = mDisplayDirectory); + return NS_OK; +} +NS_IMETHODIMP GFilePicker::SetDisplayDirectory(nsILocalFile * aDisplayDirectory) +{ + mDisplayDirectory = aDisplayDirectory; + return NS_OK; +} + +/* readonly attribute nsILocalFile file; */ +NS_IMETHODIMP GFilePicker::GetFile(nsILocalFile * *aFile) +{ + NS_IF_ADDREF(*aFile = mFile); + return NS_OK; +} + +/* readonly attribute nsIFileURL fileURL; */ +NS_IMETHODIMP GFilePicker::GetFileURL(nsIFileURL * *aFileURL) +{ + nsCOMPtr<nsIFileURL> fileURL = + do_CreateInstance(NS_STANDARDURL_CONTRACTID); + fileURL->SetFile(mFile); + NS_IF_ADDREF(*aFileURL = fileURL); + return NS_OK; +} + +/* readonly attribute nsISimpleEnumerator files; */ +NS_IMETHODIMP GFilePicker::GetFiles(nsISimpleEnumerator * *aFiles) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* short show (); */ +NS_IMETHODIMP GFilePicker::Show(PRInt16 *_retval) +{ + mFileSelector = gtk_file_selection_new(mTitle.get()); + + nsCAutoString cFileName; + if(mMode == nsIFilePicker::modeGetFolder) + cFileName.Assign(""); + else + cFileName = mDefaultString; + + nsCAutoString cDirName; + mDisplayDirectory->GetNativePath(cDirName); + + nsCAutoString cFullPath; + cFullPath.Assign(cDirName + NS_LITERAL_CSTRING("/") + cFileName); + gtk_file_selection_set_filename(GTK_FILE_SELECTION(mFileSelector), + cFullPath.get()); + + if (!mFilter.IsEmpty()) + { + gtk_file_selection_complete(GTK_FILE_SELECTION(mFileSelector), + mFilter.get()); + } + + if (mParentWidget) + gtk_window_set_transient_for(GTK_WINDOW(mFileSelector), + GTK_WINDOW(mParentWidget)); + + if (mShowContentCheck) + { + GtkWidget *bbox = gtk_hbutton_box_new (); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), + GTK_BUTTONBOX_END); + gtk_box_set_spacing(GTK_BOX(bbox), 0); + gtk_box_pack_end(GTK_BOX(GTK_FILE_SELECTION(mFileSelector)->action_area), + bbox, TRUE, TRUE, 0); + + GtkWidget *saveContent = + gtk_check_button_new_with_label(_("Save with content")); + g_signal_connect(G_OBJECT(saveContent), + "clicked", + G_CALLBACK(filePicker_save_content_cb), + (gpointer)this); + + gtk_box_pack_start(GTK_BOX(bbox), saveContent, + FALSE, FALSE, 0); + + gtk_widget_show_all(bbox); + } + + if (mFileFormats) + { + mFormatChooser = gtk_option_menu_new(); + GtkMenu *options = GTK_MENU(gtk_menu_new()); + + FileFormat *current = mFileFormats; + while (current->description != NULL) + { + /* FIXME: the label should include the extensions too */ + gchar *label = current->description; + GtkWidget *item = gtk_menu_item_new_with_label(label); + gtk_widget_show(item); + gtk_menu_shell_append(GTK_MENU_SHELL(options), item); + current++; + } + gtk_option_menu_set_menu(GTK_OPTION_MENU(mFormatChooser), + GTK_WIDGET(options)); + gtk_widget_show(mFormatChooser); + gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION (mFileSelector)->action_area), + mFormatChooser, + FALSE, TRUE, 0); + } + else + { + mFormatChooser = NULL; + } + + if (mMode == nsIFilePicker::modeGetFolder) + { + gtk_widget_set_sensitive(GTK_FILE_SELECTION(mFileSelector) + ->file_list, FALSE); + } + + gtk_window_set_modal(GTK_WINDOW(mFileSelector), TRUE); + + gint retVal = gtk_dialog_run(GTK_DIALOG(mFileSelector)); + + if (retVal == GTK_RESPONSE_OK) + { + HandleFilePickerResult(_retval); + } + else + { + *_retval = returnCancel; + } + + gtk_widget_hide(mFileSelector); + gtk_widget_destroy(mFileSelector); + + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// +// begin local public methods impl +//////////////////////////////////////////////////////////////////////////////// + +NS_METHOD GFilePicker::InitWithGtkWidget (GtkWidget *aParentWidget, + const char *aTitle, PRInt16 aMode) +{ + mParentWidget = aParentWidget; + + mTitle = nsDependentCString(aTitle); + + mMode = mMode; + + mFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID); + + return NS_OK; +} + +NS_METHOD GFilePicker::SanityCheck (PRBool *retIsSane) +{ + *retIsSane = PR_TRUE; + + PRBool dirExists, fileExists = PR_TRUE; + + if (mDisplayDirectory) + { + mDisplayDirectory->Exists (&dirExists); + } + else + { + dirExists = PR_FALSE; + } + + if (mMode == nsIFilePicker::modeOpen) + { + mFile->Exists (&fileExists); + } + + if (!dirExists || !fileExists) + { + GtkWidget *errorDialog = gtk_message_dialog_new ( + NULL, + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("The specified path does not exist.")); + + if (mParentWidget) + gtk_window_set_transient_for(GTK_WINDOW(errorDialog), + GTK_WINDOW(mFileSelector)); + + gtk_window_set_modal (GTK_WINDOW(errorDialog), TRUE); + gtk_dialog_run (GTK_DIALOG(errorDialog)); + *retIsSane = PR_FALSE; + return NS_OK; + } + + PRBool correctType; + char *errorText; + if (mMode == nsIFilePicker::modeGetFolder) + { + mDisplayDirectory->IsDirectory (&correctType); + errorText = g_strdup (_("A file was selected when a " + "folder was expected.")); + } + else + { + mFile->IsFile (&correctType); + errorText = g_strdup (_("A folder was selected when a " + "file was expected.")); + } + + if(!correctType) + { + GtkWidget *errorDialog = gtk_message_dialog_new ( + NULL, + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + errorText); + + if (mParentWidget) + gtk_window_set_transient_for(GTK_WINDOW(errorDialog), + GTK_WINDOW(mFileSelector)); + + gtk_window_set_modal (GTK_WINDOW(errorDialog), TRUE); + gtk_dialog_run (GTK_DIALOG(errorDialog)); + *retIsSane = PR_FALSE; + } + g_free (errorText); + + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// +// begin local private methods impl +//////////////////////////////////////////////////////////////////////////////// + +NS_METHOD GFilePicker::HandleFilePickerResult(PRInt16 *retval) +{ + *retval = returnCancel; + nsresult rv; + + const char *fileName = gtk_file_selection_get_filename(GTK_FILE_SELECTION(mFileSelector)); + + if (!fileName || strlen(fileName) == 0) return NS_ERROR_FAILURE; + + if (mMode == nsIFilePicker::modeSave) + { + if (!ephy_gui_confirm_overwrite_file (mFileSelector, + fileName)) + { + return NS_OK; + } + } + + const nsACString &cFileName = nsDependentCString(fileName); + mFile->InitWithNativePath(cFileName); + + if (mMode == nsIFilePicker::modeGetFolder) + { + mDisplayDirectory->InitWithNativePath(cFileName); + mDefaultString = ""; + } + else + { + nsCOMPtr<nsIFile> directory; + mFile->GetParent(getter_AddRefs(directory)); + mDisplayDirectory = do_QueryInterface(directory); + mFile->GetNativeLeafName(mDefaultString); + } + + PRBool passesSanityCheck; + rv = SanityCheck(&passesSanityCheck); + if (NS_SUCCEEDED(rv) && !passesSanityCheck) return NS_ERROR_FAILURE; + + if (mFormatChooser) + { + gint i = 0; + GtkWidget *menu = gtk_option_menu_get_menu + (GTK_OPTION_MENU(mFormatChooser)); + GList *iterator = GTK_MENU_SHELL(menu)->children; + GtkWidget *selected = gtk_menu_get_active (GTK_MENU(menu)); + + while (iterator) + { + if (iterator->data == selected) + { + mSelectedFileFormat = i; + break; + } + iterator = iterator->next; + i++; + } + } + + *retval = mSaveContent ? returnOKSaveContent : returnOK; + return NS_OK; +} + +//------------------------------------------------------------------------------ + +NS_DEF_FACTORY (GFilePicker, GFilePicker); + +/** + * NS_NewFilePickerFactory: + */ +nsresult NS_NewFilePickerFactory(nsIFactory** aFactory) +{ + NS_ENSURE_ARG_POINTER(aFactory); + *aFactory = nsnull; + + nsGFilePickerFactory *result = new nsGFilePickerFactory; + if (result == NULL) + { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(result); + *aFactory = result; + + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// +// begin FileSelector callbacks. +//////////////////////////////////////////////////////////////////////////////// + +void filePicker_save_content_cb(GtkToggleButton *aButton, + GFilePicker *aFilePicker) +{ + aFilePicker->mSaveContent = gtk_toggle_button_get_active (aButton) ? + PR_TRUE : PR_FALSE; +} diff --git a/embed/mozilla/FilePicker.h b/embed/mozilla/FilePicker.h new file mode 100644 index 000000000..93c025637 --- /dev/null +++ b/embed/mozilla/FilePicker.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef FILE_PICKER_H +#define FILE_PICKER_H + +#include "nsIFilePicker.h" +#include "nsError.h" +#include "nsIDOMWindow.h" +#include "nsIDOMWindowInternal.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsILocalFile.h" +#include <gtk/gtktogglebutton.h> +#include "ephy-embed-shell.h" + +#define G_FILEPICKER_CID \ +{ /* 3636dc79-0b42-4bad-8a3f-ae15d3671d17 */ \ + 0x3636dc79, \ + 0x0b42, \ + 0x4bad, \ + {0x8a, 0x3f, 0xae, 0x15, 0xd3, 0x67, 0x1d, 0x17} \ +} + +#define G_FILEPICKER_CONTRACTID "@mozilla.org/filepicker;1" +#define G_FILEPICKER_CLASSNAME "Galeon's File Picker Implementation" + +class nsIFactory; + +extern nsresult NS_NewFilePickerFactory(nsIFactory** aFactory); + +/* Header file */ +class GFilePicker : public nsIFilePicker +{ + friend void filePicker_save_content_cb(GtkToggleButton *aButton, + GFilePicker *aFilePicker); + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIFILEPICKER + enum { returnOK = nsIFilePicker::returnOK, + returnCancel = nsIFilePicker::returnCancel, + returnReplace = nsIFilePicker::returnReplace, + returnOKSaveContent = 256 }; + + GFilePicker(PRBool aShowContentCheck = PR_FALSE, FileFormat *aFileFormats = NULL); + virtual ~GFilePicker(); + + /* additional members */ + NS_METHOD InitWithGtkWidget(GtkWidget *aParentWidget, + const char *aTitle, PRInt16 aMode); + NS_METHOD SanityCheck(PRBool *retIsSane); + + PRInt16 mSelectedFileFormat; + + private: + NS_METHOD HandleFilePickerResult(PRInt16 *retval); + + nsCOMPtr<nsIDOMWindow> mParent; + + nsCString mTitle; + nsCString mFilter; + nsCString mDefaultString; + + nsCOMPtr<nsILocalFile> mFile; + nsCOMPtr<nsILocalFile> mDisplayDirectory; + + PRInt16 mMode; + + PRBool mShowContentCheck; + PRBool mSaveContent; + + GtkWidget *mParentWidget; + GtkWidget *mFileSelector; + GtkWidget *mFormatChooser; + + FileFormat *mFileFormats; +}; + +#endif diff --git a/embed/mozilla/FtpProtocolHandler.cpp b/embed/mozilla/FtpProtocolHandler.cpp new file mode 100644 index 000000000..a9b299095 --- /dev/null +++ b/embed/mozilla/FtpProtocolHandler.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "nsIFactory.h" +#include "nsXPComFactory.h" + +#include "BaseProtocolContentHandler.h" + +class GFtpProtocolHandler : public GBaseProtocolContentHandler +{ + public: + NS_DECL_ISUPPORTS + GFtpProtocolHandler() : GBaseProtocolContentHandler("ftp") + {NS_INIT_ISUPPORTS();}; + virtual ~GFtpProtocolHandler() {}; + /* additional members */ +}; + +/* Implementation file */ +NS_IMPL_ISUPPORTS2 (GFtpProtocolHandler, nsIProtocolHandler, nsIContentHandler) + +NS_DEF_FACTORY (GFtpProtocolHandler, GFtpProtocolHandler); + +/** + * NS_NewFtpHandlerFactory: + */ +nsresult NS_NewFtpHandlerFactory(nsIFactory** aFactory) +{ + NS_ENSURE_ARG_POINTER(aFactory); + *aFactory = nsnull; + + nsGFtpProtocolHandlerFactory *result = + new nsGFtpProtocolHandlerFactory; + if (result == NULL) + { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(result); + *aFactory = result; + + return NS_OK; +} diff --git a/embed/mozilla/FtpProtocolHandler.h b/embed/mozilla/FtpProtocolHandler.h new file mode 100644 index 000000000..d305501d5 --- /dev/null +++ b/embed/mozilla/FtpProtocolHandler.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __FtpProtocolHandler_h__ +#define __FtpProtocolHandler_h__ + +#include "nsError.h" +#include "nsIProtocolHandler.h" +#include "nsCURILoader.h" + +#define G_FTP_PROTOCOL_CID \ +{ /* 5a48bdf4-a422-4eb4-b073-0fc3bee8e670 */ \ + 0x5a48bdf4, \ + 0xa422, \ + 0x4eb4, \ + {0xb0, 0x73, 0x0f, 0xc3, 0xbe, 0xe8, 0xe6, 0x70} \ +} +#define G_FTP_PROTOCOL_CONTRACTID NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ftp" +#define G_FTP_PROTOCOL_CLASSNAME "Galeon's FTP Protocol Handler" +#define G_FTP_CONTENT_CONTRACTID NS_CONTENT_HANDLER_CONTRACTID_PREFIX \ + "application-x-gnome-ftp" +#define G_FTP_CONTENT_CLASSNAME "Galeon's FTP Content Handler" + +#define NS_FTPPROTOCOLHANDLER_CID \ +{ \ + 0x25029490, \ + 0xf132, \ + 0x11d2, \ + {0x95, 0x88, 0x0, 0x80, 0x5f, 0x36, 0x9f, 0x95} \ +} +#define NS_FTPPROTOCOLHANDLER_CLASSNAME "The FTP Protocol Handler" + +class nsIFactory; + +extern nsresult NS_NewFtpHandlerFactory(nsIFactory** aFactory); + +#endif // __FtpProtocolHandler_h__ diff --git a/embed/mozilla/GlobalHistory.cpp b/embed/mozilla/GlobalHistory.cpp new file mode 100644 index 000000000..a559dbc10 --- /dev/null +++ b/embed/mozilla/GlobalHistory.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "mozilla-embed-shell.h" + +#include "nsCOMPtr.h" +#include "nsISupportsArray.h" +#include "nsIFactory.h" +#include "nsIServiceManager.h" +#include "nsXPComFactory.h" +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsIGlobalHistory.h" +#include "nsIBrowserHistory.h" +#include "nsIRequestObserver.h" + +/** + * class GlobalHistory: + * + */ +class MozGlobalHistory: public nsIGlobalHistory, + public nsIBrowserHistory +{ + public: + MozGlobalHistory (); + virtual ~MozGlobalHistory(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIGLOBALHISTORY + NS_DECL_NSIBROWSERHISTORY + + private: + EphyHistory *mGlobalHistory; +}; + +NS_IMPL_ADDREF(MozGlobalHistory) +NS_IMPL_RELEASE(MozGlobalHistory) +NS_INTERFACE_MAP_BEGIN(MozGlobalHistory) + NS_INTERFACE_MAP_ENTRY(nsIGlobalHistory) + NS_INTERFACE_MAP_ENTRY(nsIBrowserHistory) +NS_INTERFACE_MAP_END + +MozGlobalHistory::MozGlobalHistory () +{ + NS_INIT_ISUPPORTS(); + + mGlobalHistory = ephy_embed_shell_get_global_history (embed_shell); +} + +MozGlobalHistory::~MozGlobalHistory () +{ +} + +/* void addPage (in string aURL); */ +NS_IMETHODIMP MozGlobalHistory::AddPage (const char *aURL) +{ + ephy_history_add_page (mGlobalHistory, aURL); + + return NS_OK; +} + +/* boolean isVisited (in string aURL); */ +NS_IMETHODIMP MozGlobalHistory::IsVisited (const char *aURL, PRBool *_retval) +{ + *_retval = ephy_history_is_page_visited (mGlobalHistory, aURL); + + return NS_OK; +} + +/* void setPageTitle (in string aURL, in wstring aTitle); */ +NS_IMETHODIMP MozGlobalHistory::SetPageTitle (const char *aURL, + const PRUnichar *aTitle) +{ + const nsACString &title = NS_ConvertUCS2toUTF8 (aTitle); + + ephy_history_set_page_title (mGlobalHistory, aURL, PromiseFlatCString(title).get()); + + /* done */ + return NS_OK; +} + +/* void removePage (in string aURL); */ +NS_IMETHODIMP MozGlobalHistory::RemovePage(const char *aURL) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void removePagesFromHost (in string aHost, in boolean aEntireDomain); */ +NS_IMETHODIMP MozGlobalHistory::RemovePagesFromHost(const char *aHost, + PRBool aEntireDomain) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void removeAllPages (); */ +NS_IMETHODIMP MozGlobalHistory::RemoveAllPages() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* readonly attribute string lastPageVisited; */ +NS_IMETHODIMP MozGlobalHistory::GetLastPageVisited(char **aLastPageVisited) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP MozGlobalHistory::HidePage(const char *url) +{ + return NS_ERROR_NOT_IMPLEMENTED; + +} + +/* readonly attribute PRUint32 count; */ +NS_IMETHODIMP MozGlobalHistory::GetCount(PRUint32 *aCount) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void startBatchUpdate (); */ +NS_IMETHODIMP MozGlobalHistory::StartBatchUpdate() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void endBatchUpdate (); */ +NS_IMETHODIMP MozGlobalHistory::EndBatchUpdate() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void markPageAsTyped (in string url); */ +NS_IMETHODIMP MozGlobalHistory::MarkPageAsTyped(const char *url) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_DEF_FACTORY (MozGlobalHistory, MozGlobalHistory); + +nsresult NS_NewGlobalHistoryFactory(nsIFactory** aFactory) +{ + NS_ENSURE_ARG_POINTER(aFactory); + *aFactory = nsnull; + + nsMozGlobalHistoryFactory *result = new nsMozGlobalHistoryFactory; + if (result == NULL) + { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(result); + *aFactory = result; + + return NS_OK; +} diff --git a/embed/mozilla/GlobalHistory.h b/embed/mozilla/GlobalHistory.h new file mode 100644 index 000000000..5b2e615a1 --- /dev/null +++ b/embed/mozilla/GlobalHistory.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GlobalHistory_h +#define __GlobalHistory_h + +#include "nsError.h" + +#define GALEON_GLOBALHISTORY_CID \ + { 0xbe0c42c1, 0x39d4, 0x4271, { 0xb7, 0x9e, 0xf7, 0xaa, 0x49, 0xeb, 0x6a, 0x15}} + +class nsIFactory; + +extern nsresult NS_NewGlobalHistoryFactory(nsIFactory** aFactory); + +#endif diff --git a/embed/mozilla/IRCProtocolHandler.cpp b/embed/mozilla/IRCProtocolHandler.cpp new file mode 100644 index 000000000..b1c4d7f68 --- /dev/null +++ b/embed/mozilla/IRCProtocolHandler.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "nsIFactory.h" +#include "nsXPComFactory.h" + +#include "BaseProtocolContentHandler.h" + +class GIRCProtocolHandler : public GBaseProtocolContentHandler +{ + public: + NS_DECL_ISUPPORTS + GIRCProtocolHandler() : GBaseProtocolContentHandler("irc") + {NS_INIT_ISUPPORTS();}; + virtual ~GIRCProtocolHandler() {}; + /* additional members */ +}; + +/* Implementation file */ +NS_IMPL_ISUPPORTS2 (GIRCProtocolHandler, nsIProtocolHandler, nsIContentHandler) + +NS_DEF_FACTORY (GIRCProtocolHandler, GIRCProtocolHandler); + +/** + * NS_NewIRCHandlerFactory: + */ +nsresult NS_NewIRCHandlerFactory(nsIFactory** aFactory) +{ + NS_ENSURE_ARG_POINTER(aFactory); + *aFactory = nsnull; + + nsGIRCProtocolHandlerFactory *result = + new nsGIRCProtocolHandlerFactory; + if (result == NULL) + { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(result); + *aFactory = result; + + return NS_OK; +} diff --git a/embed/mozilla/IRCProtocolHandler.h b/embed/mozilla/IRCProtocolHandler.h new file mode 100644 index 000000000..149daa121 --- /dev/null +++ b/embed/mozilla/IRCProtocolHandler.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __IRCProtocolHandler_h__ +#define __IRCProtocolHandler_h__ + +#include "nsError.h" +#include "nsIProtocolHandler.h" +#include "nsCURILoader.h" + +#define G_IRC_PROTOCOL_CID \ +{ /* aabe33d3-7455-4d8f-87e7-43e4541ace4e */ \ + 0xaabe33d3, \ + 0x7455, \ + 0x4d8f, \ + {0x87, 0xe7, 0x43, 0xe4, 0x54, 0x1a, 0xce, 0x4e} \ +} +#define G_IRC_PROTOCOL_CONTRACTID NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "irc" +#define G_IRC_PROTOCOL_CLASSNAME "Galeon's irc Protocol Handler" +#define G_IRC_CONTENT_CONTRACTID NS_CONTENT_HANDLER_CONTRACTID_PREFIX \ + "application-x-gnome-irc" +#define G_IRC_CONTENT_CLASSNAME "Galeon's irc Content Handler" + +class nsIFactory; + +extern nsresult NS_NewIRCHandlerFactory(nsIFactory** aFactory); + +#endif // __IRCProtocolHandler_h__ diff --git a/embed/mozilla/MailtoProtocolHandler.cpp b/embed/mozilla/MailtoProtocolHandler.cpp new file mode 100644 index 000000000..946f14aff --- /dev/null +++ b/embed/mozilla/MailtoProtocolHandler.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "nsIFactory.h" +#include "nsXPComFactory.h" +#include "nsString.h" +#include "nsIURI.h" +#include "nsNetUtil.h" +#include "nsIExternalProtocolService.h" +#include "nsCExternalHandlerService.h" +#include "nsCRT.h" + +#include "BaseProtocolContentHandler.h" + +class GMailtoProtocolHandler : public GBaseProtocolContentHandler +{ + public: + NS_DECL_ISUPPORTS + GMailtoProtocolHandler() : GBaseProtocolContentHandler("mailto") + {NS_INIT_ISUPPORTS();}; + virtual ~GMailtoProtocolHandler() {}; + private: +}; + +/* Implementation file */ +NS_IMPL_ISUPPORTS2 (GMailtoProtocolHandler, nsIProtocolHandler, nsIContentHandler) + +NS_DEF_FACTORY (GMailtoProtocolHandler, GMailtoProtocolHandler); + +/** + * NS_NewMailtoHandlerFactory: + */ +nsresult NS_NewMailtoHandlerFactory(nsIFactory** aFactory) +{ + NS_ENSURE_ARG_POINTER(aFactory); + *aFactory = nsnull; + + nsGMailtoProtocolHandlerFactory *result = + new nsGMailtoProtocolHandlerFactory; + if (result == NULL) + { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(result); + *aFactory = result; + + return NS_OK; +} diff --git a/embed/mozilla/MailtoProtocolHandler.h b/embed/mozilla/MailtoProtocolHandler.h new file mode 100644 index 000000000..961f42c42 --- /dev/null +++ b/embed/mozilla/MailtoProtocolHandler.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __MailtoProtocolHandler_h__ +#define __MailtoProtocolHandler_h__ + +#include "nsError.h" +#include "nsIProtocolHandler.h" +#include "nsCURILoader.h" + +#define G_MAILTO_PROTOCOL_CID \ +{ /* aabe33d3-7455-4d8f-87e7-43e4541ace4d */ \ + 0xaabe33d3, \ + 0x7455, \ + 0x4d8f, \ + {0x87, 0xe7, 0x43, 0xe4, 0x54, 0x1a, 0xce, 0x4d} \ +} +#define G_MAILTO_PROTOCOL_CONTRACTID NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "mailto" +#define G_MAILTO_PROTOCOL_CLASSNAME "Galeon's mailto Protocol Handler" +#define G_MAILTO_CONTENT_CONTRACTID NS_CONTENT_HANDLER_CONTRACTID_PREFIX \ + "application-x-gnome-mailto" +#define G_MAILTO_CONTENT_CLASSNAME "Galeon's mailto Content Handler" + +class nsIFactory; + +extern nsresult NS_NewMailtoHandlerFactory(nsIFactory** aFactory); + +#endif // __MailtoProtocolHandler_h__ diff --git a/embed/mozilla/Makefile.am b/embed/mozilla/Makefile.am new file mode 100644 index 000000000..ef7ef9dfa --- /dev/null +++ b/embed/mozilla/Makefile.am @@ -0,0 +1,108 @@ +#MOZILLA_ACDEFINES = -include $(MOZILLA_INCLUDE_ROOT)/mozilla-config.h +MOZILLA_ACDEFINES=-DNEW_H=\<new\> + +INCLUDES = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/embed \ + -I$(top_srcdir) \ + $(WARN_CFLAGS) \ + $(MOZILLA_COMPONENT_CFLAGS) \ + -I$(MOZILLA_INCLUDE_ROOT) \ + -I$(MOZILLA_INCLUDE_ROOT)/appcomps \ + -I$(MOZILLA_INCLUDE_ROOT)/content \ + -I$(MOZILLA_INCLUDE_ROOT)/cookie \ + -I$(MOZILLA_INCLUDE_ROOT)/docshell \ + -I$(MOZILLA_INCLUDE_ROOT)/dom \ + -I$(MOZILLA_INCLUDE_ROOT)/exthandler \ + -I$(MOZILLA_INCLUDE_ROOT)/find \ + -I$(MOZILLA_INCLUDE_ROOT)/gfx \ + -I$(MOZILLA_INCLUDE_ROOT)/helperAppDlg \ + -I$(MOZILLA_INCLUDE_ROOT)/java \ + -I$(MOZILLA_INCLUDE_ROOT)/jsconsole \ + -I$(MOZILLA_INCLUDE_ROOT)/layout \ + -I$(MOZILLA_INCLUDE_ROOT)/mimetype \ + -I$(MOZILLA_INCLUDE_ROOT)/mozxfer \ + -I$(MOZILLA_INCLUDE_ROOT)/necko \ + -I$(MOZILLA_INCLUDE_ROOT)/necko2 \ + -I$(MOZILLA_INCLUDE_ROOT)/nkcache \ + -I$(MOZILLA_INCLUDE_ROOT)/oji \ + -I$(MOZILLA_INCLUDE_ROOT)/pref \ + -I$(MOZILLA_INCLUDE_ROOT)/progressDlg \ + -I$(MOZILLA_INCLUDE_ROOT)/sidebar \ + -I$(MOZILLA_INCLUDE_ROOT)/shistory \ + -I$(MOZILLA_INCLUDE_ROOT)/uconv \ + -I$(MOZILLA_INCLUDE_ROOT)/uriloader \ + -I$(MOZILLA_INCLUDE_ROOT)/unicharutil \ + -I$(MOZILLA_INCLUDE_ROOT)/wallet \ + -I$(MOZILLA_INCLUDE_ROOT)/webbrowserpersist \ + -I$(MOZILLA_INCLUDE_ROOT)/webbrwsr \ + -I$(MOZILLA_INCLUDE_ROOT)/webshell \ + -I$(MOZILLA_INCLUDE_ROOT)/widget \ + -I$(MOZILLA_INCLUDE_ROOT)/windowwatcher \ + -I$(MOZILLA_INCLUDE_ROOT)/typeaheadfind \ + $(GCONF_CFLAGS) \ + $(EPIPHANY_DEPENDENCY_CFLAGS) \ + -DLIB_DIR=\"$(pkglibdir)\" \ + -DG_DISABLE_DEPRECATED \ + -DGDK_DISABLE_DEPRECATED \ + -DGTK_DISABLE_DEPRECATED \ + -DGDK_PIXBUF_DISABLE_DEPRECATED \ + -DGNOME_DISABLE_DEPRECATED \ + -DSHARE_DIR=\"$(pkgdatadir)\" \ + $(MOZILLA_ACDEFINES) + +noinst_LTLIBRARIES = libephymozillaembed.la + +libephymozillaembed_la_SOURCES = \ + mozilla-embed.cpp \ + mozilla-embed.h \ + mozilla-embed-shell.cpp \ + mozilla-embed-shell.h \ + mozilla-embed-persist.cpp \ + mozilla-embed-persist.h \ + mozilla-prefs.cpp \ + mozilla-prefs.h \ + mozilla-notifiers.cpp \ + mozilla-notifiers.h \ + mozilla-i18n.c \ + mozilla-i18n.h \ + BaseProtocolHandler.cpp \ + BaseProtocolHandler.h \ + BaseProtocolContentHandler.cpp \ + BaseProtocolContentHandler.h \ + ContentHandler.cpp \ + ContentHandler.h \ + EventContext.cpp \ + EventContext.h \ + FilePicker.cpp \ + FilePicker.h \ + FtpProtocolHandler.cpp \ + FtpProtocolHandler.h \ + EphyWrapper.cpp \ + EphyWrapper.h \ + GlobalHistory.cpp \ + GlobalHistory.h \ + IRCProtocolHandler.cpp \ + IRCProtocolHandler.h \ + MailtoProtocolHandler.cpp \ + MailtoProtocolHandler.h \ + MozillaPrivate.cpp \ + MozillaPrivate.h \ + MozRegisterComponents.cpp \ + MozRegisterComponents.h \ + PrintingPromptService.cpp \ + PrintingPromptService.h \ + PrintProgressListener.cpp \ + PrintProgressListener.h \ + PromptService.cpp \ + PromptService.h \ + ProgressListener.cpp \ + ProgressListener.h \ + nsUnicharUtils.cpp \ + nsUnicharUtils.h \ + ExternalProtocolService.cpp \ + ExternalProtocolService.h \ + StartHereProtocolHandler.cpp \ + StartHereProtocolHandler.h \ + EphyEventListener.cpp \ + EphyEventListener.h diff --git a/embed/mozilla/MozRegisterComponents.cpp b/embed/mozilla/MozRegisterComponents.cpp new file mode 100644 index 000000000..3c5e64be7 --- /dev/null +++ b/embed/mozilla/MozRegisterComponents.cpp @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "StartHereProtocolHandler.h" +#include "ContentHandler.h" +#include "ExternalProtocolService.h" +#include "FilePicker.h" +#include "FtpProtocolHandler.h" +#include "IRCProtocolHandler.h" +#include "MailtoProtocolHandler.h" +#include "PromptService.h" +#include "PrintingPromptService.h" +#include "ProgressListener.h" + +#include <nsIFactory.h> +#include <nsIComponentManager.h> +#include <nsCOMPtr.h> +#include <nsILocalFile.h> + +#include <glib.h> + +static NS_DEFINE_CID(kContentHandlerCID, G_CONTENTHANDLER_CID); +static NS_DEFINE_CID(kProtocolServiceCID, G_EXTERNALPROTOCOLSERVICE_CID); +static NS_DEFINE_CID(kFilePickerCID, G_FILEPICKER_CID); +static NS_DEFINE_CID(kStartHereProcotolHandlerCID, G_START_HERE_PROTOCOLHANDLER_CID); +static NS_DEFINE_CID(knsFtpProtocolHandlerCID, NS_FTPPROTOCOLHANDLER_CID); +static NS_DEFINE_CID(kFtpHandlerCID, G_FTP_PROTOCOL_CID); +static NS_DEFINE_CID(kIRCHandlerCID, G_IRC_PROTOCOL_CID); +static NS_DEFINE_CID(kMailtoHandlerCID, G_MAILTO_PROTOCOL_CID); +static NS_DEFINE_CID(kPromptServiceCID, G_PROMPTSERVICE_CID); +static NS_DEFINE_CID(kPrintingPromptServiceCID, G_PRINTINGPROMPTSERVICE_CID); +static NS_DEFINE_CID(kProgressDialogCID, G_PROGRESSDIALOG_CID); + +//RegisterFactory is local +NS_METHOD RegisterFactory (nsresult (aFactoryFunc)(nsIFactory** aFactory), + const nsCID & aClass, const char *aClassName, + const char *aContractID, PRBool aReplace); + +NS_METHOD RegisterComponent (const nsCID & aClass, const char *aClassName, + const char *aContractID, const char *aDLLPath, + PRBool aReplace); + +//Annoying globals to track the mozilla ftp handler so it can be restored. +static PRBool ftpRegistered = PR_FALSE; +static nsCOMPtr<nsIFactory> nsFtpFactory; + +/* FIXME why we need to use "C" here ???? */ + +extern "C" gboolean +mozilla_register_components (void) +{ + gboolean ret = TRUE; + nsresult rv; + + rv = RegisterFactory (NS_NewProgressListenerFactory, kProgressDialogCID, + G_PROGRESSDIALOG_CLASSNAME, + NS_DOWNLOAD_CONTRACTID, PR_TRUE); + if (NS_FAILED(rv)) ret = FALSE; + + rv = RegisterFactory (NS_NewContentHandlerFactory, kContentHandlerCID, + NS_IHELPERAPPLAUNCHERDLG_CLASSNAME, + NS_IHELPERAPPLAUNCHERDLG_CONTRACTID, PR_TRUE); + if (NS_FAILED(rv)) ret = FALSE; + + rv = RegisterFactory (NS_NewExternalProtocolServiceFactory, + kProtocolServiceCID, + G_EXTERNALPROTOCOLSERVICE_CLASSNAME, + NS_EXTERNALPROTOCOLSERVICE_CONTRACTID, + PR_TRUE); + if (NS_FAILED(rv)) ret = FALSE; + + rv = RegisterFactory (NS_NewFilePickerFactory, kFilePickerCID, + G_FILEPICKER_CLASSNAME, G_FILEPICKER_CONTRACTID, + PR_TRUE); + if (NS_FAILED(rv)) ret = FALSE; + + rv = RegisterFactory (NS_NewStartHereHandlerFactory, + kStartHereProcotolHandlerCID, + G_START_HERE_PROTOCOLHANDLER_CLASSNAME, + G_START_HERE_PROTOCOLHANDLER_CONTRACTID, + PR_TRUE); + if (NS_FAILED(rv)) ret = FALSE; + + rv = RegisterFactory (NS_NewFtpHandlerFactory, kFtpHandlerCID, + G_FTP_CONTENT_CLASSNAME, G_FTP_CONTENT_CONTRACTID, + PR_TRUE); + if (NS_FAILED(rv)) ret = FALSE; + + rv = RegisterFactory (NS_NewIRCHandlerFactory, kIRCHandlerCID, + G_IRC_PROTOCOL_CLASSNAME, + G_IRC_PROTOCOL_CONTRACTID, PR_TRUE); + if (NS_FAILED(rv)) ret = FALSE; + + rv = RegisterFactory (NS_NewIRCHandlerFactory, kIRCHandlerCID, + G_IRC_CONTENT_CLASSNAME, + G_IRC_CONTENT_CONTRACTID, PR_TRUE); + if (NS_FAILED(rv)) ret = FALSE; + + rv = RegisterFactory (NS_NewPromptServiceFactory, kPromptServiceCID, + G_PROMPTSERVICE_CLASSNAME, + G_PROMPTSERVICE_CONTRACTID, PR_TRUE); + if (NS_FAILED(rv)) ret = FALSE; + + rv = RegisterFactory (NS_NewPrintingPromptServiceFactory, + kPrintingPromptServiceCID, + G_PRINTINGPROMPTSERVICE_CLASSNAME, + G_PRINTINGPROMPTSERVICE_CONTRACTID, PR_TRUE); + if (NS_FAILED(rv)) ret = FALSE; + + return ret; +} + +NS_METHOD RegisterFactory (nsresult (aFactoryFunc)(nsIFactory** aFactory), + const nsCID & aClass, const char *aClassName, + const char *aContractID, PRBool aReplace) +{ + nsresult rv = NS_OK; + + nsCOMPtr<nsIFactory> factory; + rv = aFactoryFunc(getter_AddRefs(factory)); + if (NS_FAILED(rv)) return rv; + rv = nsComponentManager::RegisterFactory(aClass, aClassName, + aContractID, + factory, aReplace); + return rv; +} + +NS_METHOD RegisterComponent (const nsCID & aClass, const char *aClassName, + const char *aContractID, const char *aDLLPath, + PRBool aReplace) +{ + nsresult rv = NS_OK; + + nsCOMPtr<nsILocalFile> dllFile; + rv = NS_NewLocalFile (NS_ConvertUTF8toUCS2(aDLLPath), PR_TRUE, getter_AddRefs (dllFile)); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + rv = nsComponentManager::RegisterComponentSpec (aClass, + aClassName, + aContractID, + dllFile, + aReplace, + PR_FALSE); + return rv; +} + +/** + * mozilla_register_FtpProtocolHandler: Register Ftp Protocol Handler + */ +extern "C" gboolean +mozilla_register_FtpProtocolHandler (void) +{ + if (ftpRegistered == PR_TRUE) return TRUE; + + nsresult rv = NS_OK; + + rv = nsComponentManager::FindFactory (knsFtpProtocolHandlerCID, + getter_AddRefs(nsFtpFactory)); + if (NS_FAILED(rv)) return FALSE; + + rv = RegisterFactory (NS_NewFtpHandlerFactory, kFtpHandlerCID, + G_FTP_PROTOCOL_CLASSNAME, + G_FTP_PROTOCOL_CONTRACTID, PR_TRUE); + + if (NS_FAILED(rv)) return FALSE; + + ftpRegistered = PR_TRUE; + return NS_SUCCEEDED (rv) ? TRUE : FALSE; +} + +/** + * mozilla_unregister_FtpProtocolHandler: Unregister Ftp Protocol Handler + */ +extern "C" gboolean +mozilla_unregister_FtpProtocolHandler (void) +{ + if (ftpRegistered == PR_FALSE) return FALSE; + + nsresult rv = NS_OK; + + rv = nsComponentManager::RegisterFactory(knsFtpProtocolHandlerCID, + NS_FTPPROTOCOLHANDLER_CLASSNAME, + G_FTP_PROTOCOL_CONTRACTID, + nsFtpFactory, PR_TRUE); + + ftpRegistered = PR_FALSE; + return NS_SUCCEEDED (rv) ? TRUE : FALSE; +} + +/** + * mozilla_register_MailtoProtocolHandler: Register Mailto Protocol Handler + */ +extern "C" gboolean +mozilla_register_MailtoProtocolHandler (void) +{ + nsresult rv = NS_OK; + + rv = RegisterFactory (NS_NewMailtoHandlerFactory, kMailtoHandlerCID, + G_MAILTO_PROTOCOL_CLASSNAME, + G_MAILTO_PROTOCOL_CONTRACTID, PR_TRUE); + if (NS_FAILED(rv)) return FALSE; + + rv = RegisterFactory (NS_NewMailtoHandlerFactory, kMailtoHandlerCID, + G_MAILTO_CONTENT_CLASSNAME, + G_MAILTO_CONTENT_CONTRACTID, PR_TRUE); + return NS_SUCCEEDED (rv) ? TRUE : FALSE; +} diff --git a/embed/mozilla/MozRegisterComponents.h b/embed/mozilla/MozRegisterComponents.h new file mode 100644 index 000000000..a263d9b74 --- /dev/null +++ b/embed/mozilla/MozRegisterComponents.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __MozRegisterComponents_h +#define __MozRegisterComponents_h + +#include <glib.h> + +G_BEGIN_DECLS + +gboolean mozilla_register_components (void); +gboolean mozilla_register_FtpProtocolHandler (void); +gboolean mozilla_unregister_FtpProtocolHandler (void); +gboolean mozilla_register_MailtoProtocolHandler (void); + +G_END_DECLS + +#endif // __MozRegisterComponents_h diff --git a/embed/mozilla/MozillaPrivate.cpp b/embed/mozilla/MozillaPrivate.cpp new file mode 100644 index 000000000..a7bc50a6c --- /dev/null +++ b/embed/mozilla/MozillaPrivate.cpp @@ -0,0 +1,105 @@ +#include "MozillaPrivate.h" + +#include <nsIServiceManagerUtils.h> +#include <nsIWindowWatcher.h> +#include <nsIEmbeddingSiteWindow.h> +#include <nsIWebBrowserChrome.h> +#include <gtkmozembed.h> + +GtkWidget *MozillaFindGtkParent (nsIDOMWindow *aDOMWindow) +{ + nsresult result; + + nsCOMPtr<nsIWindowWatcher> wwatch + (do_GetService("@mozilla.org/embedcomp/window-watcher;1")); + if (!wwatch) return nsnull; + + nsCOMPtr<nsIDOMWindow> domWindow(aDOMWindow); + if (!domWindow) + { + result = wwatch->GetActiveWindow(getter_AddRefs(domWindow)); + if (NS_FAILED(result) || !domWindow) return nsnull; + } + + nsCOMPtr<nsIWebBrowserChrome> windowChrome; + result = wwatch->GetChromeForWindow (domWindow, + getter_AddRefs(windowChrome)); + if (NS_FAILED(result)) return nsnull; + + nsCOMPtr<nsIEmbeddingSiteWindow> window + (do_QueryInterface(windowChrome, &result)); + if (NS_FAILED(result)) return nsnull; + + GtkWidget *mozembed; + result = window->GetSiteWindow ((void **)&mozembed); + if (NS_FAILED(result)) return nsnull; + + return gtk_widget_get_toplevel (GTK_WIDGET(mozembed)); +} + + +NS_METHOD MozillaCollatePrintSettings (const EmbedPrintInfo *info, + nsIPrintSettings *options) +{ + const static int frame_types[] = { + nsIPrintSettings::kFramesAsIs, + nsIPrintSettings::kSelectedFrame, + nsIPrintSettings::kEachFrameSep + }; + /* these should match the order of the radiobuttons in the dialog + * and the paper names in the default print provider PS*/ + const static char *PaperSizeNames[] = { + "Letter","Legal","Executive","A4" + }; + + + switch (info->pages) + { + case 0: + break; + case 1: + options->SetPrintRange (nsIPrintSettings::kRangeSpecifiedPageRange); + options->SetStartPageRange (info->from_page); + options->SetEndPageRange (info->to_page); + break; + case 2: + options->SetPrintRange (nsIPrintSettings::kRangeSelection); + break; + } + + options->SetMarginTop (info->top_margin); + options->SetMarginBottom (info->bottom_margin); + options->SetMarginLeft (info->left_margin); + options->SetMarginRight (info->right_margin); + + options->SetPrinterName(NS_LITERAL_STRING("PostScript/default").get()); + + options->SetHeaderStrLeft(NS_ConvertUTF8toUCS2(info->header_left_string).get()); + + options->SetHeaderStrCenter(NS_ConvertUTF8toUCS2(info->header_center_string).get()); + + options->SetHeaderStrRight(NS_ConvertUTF8toUCS2(info->header_right_string).get()); + + options->SetFooterStrLeft(NS_ConvertUTF8toUCS2(info->footer_left_string).get()); + + options->SetFooterStrCenter(NS_ConvertUTF8toUCS2(info->footer_center_string).get()); + + options->SetFooterStrRight(NS_ConvertUTF8toUCS2(info->footer_right_string).get()); + + options->SetToFileName (NS_ConvertUTF8toUCS2(info->file).get()); + + options->SetPrintCommand (NS_ConvertUTF8toUCS2(info->printer).get()); + + options->SetPrintToFile (info->print_to_file); + + /* native paper size formats. Our dialog does not support custom yet */ + options->SetPaperSize (nsIPrintSettings::kPaperSizeNativeData); + int tps = (info->paper >= 0 || info->paper < 4) ? info->paper : 0; + options->SetPaperName (NS_ConvertUTF8toUCS2(PaperSizeNames[tps]).get()); + + options->SetPrintInColor (info->print_color); + options->SetOrientation (info->orientation); + options->SetPrintFrameType (frame_types[info->frame_type]); + + return NS_OK; +} diff --git a/embed/mozilla/MozillaPrivate.h b/embed/mozilla/MozillaPrivate.h new file mode 100644 index 000000000..be9ab4905 --- /dev/null +++ b/embed/mozilla/MozillaPrivate.h @@ -0,0 +1,9 @@ +#include <nsIPrintSettings.h> +#include <nsIDOMWindow.h> + +#include "ephy-embed.h" + +GtkWidget *MozillaFindGtkParent (nsIDOMWindow *aDOMWindow); + +NS_METHOD MozillaCollatePrintSettings (const EmbedPrintInfo *info, + nsIPrintSettings *settings); diff --git a/embed/mozilla/PrintProgressListener.cpp b/embed/mozilla/PrintProgressListener.cpp new file mode 100644 index 000000000..b4cf7b701 --- /dev/null +++ b/embed/mozilla/PrintProgressListener.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2002 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "libgnomevfs/gnome-vfs-mime-handlers.h" + +/* see the FIXME below */ +#include <locale.h> + +#include <libgnome/gnome-exec.h> + +#include "PrintProgressListener.h" + + +NS_IMPL_ISUPPORTS1(GPrintListener, nsIWebProgressListener) + +GPrintListener::GPrintListener() +{ + NS_INIT_ISUPPORTS(); + mFilename = NULL; +} + +GPrintListener::GPrintListener(char *filename) +{ + GPrintListener (); + mFilename = filename ? g_strdup (filename) : NULL; +} + +GPrintListener::~GPrintListener() +{ + g_free (mFilename); +} + +/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aStateFlags, in unsigned long aStatus); */ +NS_IMETHODIMP GPrintListener::OnStateChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRUint32 aStateFlags, + PRUint32 aStatus) +{ + if (aStateFlags & nsIWebProgressListener::STATE_STOP) + { + GnomeVFSMimeApplication *app; + gchar *command; + + /* FIXME(MOZILLA) ugly workaround for a mozilla problem with + * reseting the LC_* environment when printing */ + setlocale(LC_ALL,""); + if (!mFilename) return NS_OK; + + /* get the postscript handler */ + app = gnome_vfs_mime_get_default_application + ("application/postscript"); + if (app) + { + command = g_strconcat (app->command, " ", + mFilename, NULL); + gnome_execute_shell (g_get_home_dir(), command); + gnome_vfs_mime_application_free (app); + g_free (command); + } + else return NS_ERROR_FAILURE; + } + return NS_OK; +} + +/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */ +NS_IMETHODIMP GPrintListener::OnProgressChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRInt32 aCurSelfProgress, + PRInt32 aMaxSelfProgress, + PRInt32 aCurTotalProgress, + PRInt32 aMaxTotalProgress) +{ + return NS_OK; +} + +/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */ +NS_IMETHODIMP GPrintListener::OnLocationChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + nsIURI *location) +{ + return NS_OK; +} + +/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */ +NS_IMETHODIMP GPrintListener::OnStatusChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + nsresult aStatus, + const PRUnichar *aMessage) +{ + return NS_OK; +} + +/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long state); */ +NS_IMETHODIMP GPrintListener::OnSecurityChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRUint32 state) +{ + return NS_OK; +} + + diff --git a/embed/mozilla/PrintProgressListener.h b/embed/mozilla/PrintProgressListener.h new file mode 100644 index 000000000..82577d8ea --- /dev/null +++ b/embed/mozilla/PrintProgressListener.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2002 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PrintProgressListener_h_ +#define __PrintProgressListener_h_ + +#include "nsIWebProgressListener.h" + +class GPrintListener : public nsIWebProgressListener +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIWEBPROGRESSLISTENER + + GPrintListener(); + GPrintListener(char *filename); + virtual ~GPrintListener(); + +private: + char *mFilename; +}; + +#endif //__PrintProgressListener_h_ diff --git a/embed/mozilla/PrintingPromptService.cpp b/embed/mozilla/PrintingPromptService.cpp new file mode 100644 index 000000000..6d1430ddc --- /dev/null +++ b/embed/mozilla/PrintingPromptService.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2002 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gtk/gtkdialog.h> + +#include "print-dialog.h" +#include "ephy-embed.h" +#include "MozillaPrivate.h" + +#include <nsIPrintSettings.h> +#include <nsCOMPtr.h> +#include <nsIFactory.h> +#include <nsString.h> +#include <nsIServiceManager.h> +#include <nsXPComFactory.h> + +#include <nsIPrintingPromptService.h> + +/* Header file */ +class GPrintingPromptService : public nsIPrintingPromptService +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPRINTINGPROMPTSERVICE + + GPrintingPromptService(); + virtual ~GPrintingPromptService(); + /* additional members */ +}; + +/* Implementation file */ +NS_IMPL_ISUPPORTS1(GPrintingPromptService, nsIPrintingPromptService) + +GPrintingPromptService::GPrintingPromptService() +{ + NS_INIT_ISUPPORTS(); + /* member initializers and constructor code */ +} + +GPrintingPromptService::~GPrintingPromptService() +{ + /* destructor code */ +} + +/* void showPrintDialog (in nsIDOMWindow parent, in nsIWebBrowserPrint webBrowserPrint, in nsIPrintSettings printSettings); */ +NS_IMETHODIMP GPrintingPromptService::ShowPrintDialog(nsIDOMWindow *parent, nsIWebBrowserPrint *webBrowserPrint, nsIPrintSettings *printSettings) +{ + EphyDialog *dialog; + EmbedPrintInfo *info; + + GtkWidget *gtkParent = MozillaFindGtkParent(parent); + + dialog = print_dialog_new_with_parent (gtkParent, NULL, &info); + ephy_dialog_set_modal (dialog, TRUE); + + gint ret = ephy_dialog_run (dialog); + if(ret == GTK_RESPONSE_OK) + { + MozillaCollatePrintSettings(info, printSettings); + print_free_info(info); + + return NS_OK; + } + else + return NS_ERROR_FAILURE; +} + +/* void showProgress (in nsIDOMWindow parent, in nsIWebBrowserPrint webBrowserPrint, in nsIPrintSettings printSettings, in nsIObserver openDialogObserver, in boolean isForPrinting, out nsIWebProgressListener webProgressListener, out nsIPrintProgressParams printProgressParams, out boolean notifyOnOpen); */ +NS_IMETHODIMP GPrintingPromptService::ShowProgress(nsIDOMWindow *parent, nsIWebBrowserPrint *webBrowserPrint, nsIPrintSettings *printSettings, nsIObserver *openDialogObserver, PRBool isForPrinting, nsIWebProgressListener **webProgressListener, nsIPrintProgressParams **printProgressParams, PRBool *notifyOnOpen) +{ + printf("GPrintingPromptService::ShowProgress called\n"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void showPageSetup (in nsIDOMWindow parent, in nsIPrintSettings printSettings, in nsIObserver printObserver); */ +NS_IMETHODIMP GPrintingPromptService::ShowPageSetup(nsIDOMWindow *parent, nsIPrintSettings *printSettings, + nsIObserver *printObserver) +{ + printf("GPrintingPromptService::ShowPageSetup called\n"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void showPrinterProperties (in nsIDOMWindow parent, in wstring printerName, in nsIPrintSettings printSettings); */ +NS_IMETHODIMP GPrintingPromptService::ShowPrinterProperties(nsIDOMWindow *parent, const PRUnichar *printerName, nsIPrintSettings *printSettings) +{ + printf("GPrintingPromptService::ShowPrinterProperties called\n"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_DEF_FACTORY (GPrintingPromptService, GPrintingPromptService); + +/** + * NS_NewPromptServiceFactory: + */ +nsresult NS_NewPrintingPromptServiceFactory(nsIFactory** aFactory) +{ + NS_ENSURE_ARG_POINTER(aFactory); + *aFactory = nsnull; + + nsGPrintingPromptServiceFactory *result = new nsGPrintingPromptServiceFactory; + if (result == NULL) + { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(result); + *aFactory = result; + + return NS_OK; +} diff --git a/embed/mozilla/PrintingPromptService.h b/embed/mozilla/PrintingPromptService.h new file mode 100644 index 000000000..08024c632 --- /dev/null +++ b/embed/mozilla/PrintingPromptService.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2000 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PrintingPromptService_h +#define __PrintingPromptService_h + +#include "nsError.h" + +#define G_PRINTINGPROMPTSERVICE_CID \ +{ /* 5998a2d3-88ea-4c52-b4bb-4e7abd0d35e0 */ \ + 0x5998a2d3, \ + 0x88ea, \ + 0x4c52, \ + {0xb4, 0xbb, 0x4e, 0x7a, 0xbd, 0x0d, 0x35, 0xe0} \ +} + +#define G_PRINTINGPROMPTSERVICE_CLASSNAME "Galeon's Printing Prompt Service" +#define G_PRINTINGPROMPTSERVICE_CONTRACTID "@mozilla.org/embedcomp/printingprompt-service;1" +class nsIFactory; + +extern nsresult NS_NewPrintingPromptServiceFactory(nsIFactory** aFactory); + +#endif diff --git a/embed/mozilla/ProgressListener.cpp b/embed/mozilla/ProgressListener.cpp new file mode 100644 index 000000000..aed42d97a --- /dev/null +++ b/embed/mozilla/ProgressListener.cpp @@ -0,0 +1,718 @@ +/* + * Copyright (C) 2001 Philip Langdale, Matthew Aubury + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "ProgressListener.h" + +#include "eel-gconf-extensions.h" +#include "ephy-file-helpers.h" + +#include <unistd.h> +#include <libgnome/gnome-exec.h> +#include <libgnome/gnome-i18n.h> + +#include "nsXPIDLString.h" +#include "nsIChannel.h" +#include "nsIFTPChannel.h" +#include "nsIFactory.h" +#include "nsXPComFactory.h" +#include "nsIMIMEInfo.h" +#include "nsCOMPtr.h" + +static void +download_remove_cb (DownloaderView *dv, GProgressListener *Progress); +static void +download_resume_cb (DownloaderView *dv, GProgressListener *Progress); +static void +download_pause_cb (DownloaderView *dv, GProgressListener *Progress); + +NS_IMPL_ISUPPORTS4 (GProgressListener, nsIDownload, nsIWebProgressListener, + nsIProgressDialog, nsISupportsWeakReference) + +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- + +GProgressListener::GProgressListener () : mLauncher(nsnull), + mPersist(nsnull), + mHandler(nsnull), + mObserver(nsnull), + mMIMEInfo(nsnull), + mPercentComplete(0) +{ + NS_INIT_ISUPPORTS (); +} + +GProgressListener::~GProgressListener () +{ + /* destructor code */ +} + +NS_METHOD GProgressListener::InitForPersist (nsIWebBrowserPersist *aPersist, + nsIDOMWindow *aParent, + nsIURI *aURI, + nsIFile *aFile, + DownloadAction aAction, + EphyEmbedPersist *ephyPersist, + PRBool noDialog, + PRInt64 aTimeDownloadStarted) +{ + nsresult rv; + + /* fill in download details */ + mAction = aAction; + mParent = aParent; + mNoDialog = noDialog; + mUri = aURI; + mFile = aFile; + mPersist = aPersist; + mTimeDownloadStarted = aTimeDownloadStarted; + mEphyPersist = ephyPersist; + + /* do remaining init */ + rv = PrivateInit (); + + /* pick up progress messages */ + mPersist->SetProgressListener (this); + + /* done */ + return rv; +} + +NS_METHOD GProgressListener::InitForDownload (nsIHelperAppLauncher *aLauncher, + nsISupports *aContext, + GContentHandler *aHandler, + DownloadAction aAction) +{ + nsresult rv; + + mNoDialog = 0; + + /* fill in download details */ + mAction = aAction; + mParent = do_QueryInterface (aContext); + mNoDialog = PR_TRUE; + mHandler = aHandler; + mLauncher = aLauncher; + rv = mLauncher->GetDownloadInfo (getter_AddRefs (mUri), + &mTimeDownloadStarted, + getter_AddRefs (mFile)); + + /* do remaining init */ + rv = PrivateInit (); + + /* pick up progress messages */ + mLauncher->SetWebProgressListener (this); + + /* done */ + return rv; +} + +NS_METHOD GProgressListener::PrivateInit (void) +{ + nsresult rv; + + /* setup this download */ + mInterval = 500000; /* in microsecs == 500ms == 0.5s */ + mPriorKRate = 0; + mRateChanges = 0; + mRateChangeLimit = 2; /* only update rate every second */ + mCheckedCanPause = PR_FALSE; + mCanPause = PR_FALSE; + mIsPaused = PR_FALSE; + mAbort = PR_FALSE; + PRInt64 now = PR_Now (); + mLastUpdate = now; + +// mStartTime = (mTimeDownloadStarted != 0 ? +// mTimeDownloadStarted : now); + mStartTime = now; //Stupid mozilla race condition + + mElapsed = now - mStartTime; + + if (!mNoDialog) + { + gchar *filename, *source, *dest; + nsAutoString uTmp; + nsCAutoString cTmp; + + rv = mFile->GetLeafName (uTmp); + filename = g_strdup (NS_ConvertUCS2toUTF8(uTmp).get()); + + rv = mFile->GetPath (uTmp); + dest = g_strdup (NS_ConvertUCS2toUTF8(uTmp).get()); + + rv = mUri->GetSpec (cTmp); + source = g_strdup (cTmp.get()); + DownloaderView *dv; + dv = ephy_embed_shell_get_downloader_view (embed_shell); + downloader_view_add_download (dv, filename, source, dest, (gpointer)this); + g_signal_connect (G_OBJECT (dv), + "download_remove", + G_CALLBACK (download_remove_cb), + this); + g_signal_connect (G_OBJECT (dv), + "download_pause", + G_CALLBACK (download_pause_cb), + this); + g_signal_connect (G_OBJECT (dv), + "download_resume", + G_CALLBACK (download_resume_cb), + this); + mDownloaderView = dv; + } + + /* done */ + return NS_OK; +} + +NS_IMETHODIMP GProgressListener::Init(nsIURI *aSource, + nsILocalFile *aTarget, + const PRUnichar *aDisplayName, + nsIMIMEInfo *aMIMEInfo, + PRInt64 aStartTime, + nsIWebBrowserPersist *aPersist) +{ + mUri = aSource; + mFile = aTarget; + mTimeDownloadStarted = aStartTime; + mStartTime = aStartTime; + mPersist = aPersist; + mMIMEInfo = aMIMEInfo; + mAction = ACTION_NONE; + if(mMIMEInfo) + { + nsMIMEInfoHandleAction mimeAction; + if(NS_SUCCEEDED(mMIMEInfo->GetPreferredAction(&mimeAction))) + { + mAction = (mimeAction == nsIMIMEInfo::useHelperApp) ? + ACTION_SAVEFORHELPER : ACTION_NONE; + } + } + mNoDialog = 0; + + return PrivateInit(); +} + +NS_IMETHODIMP GProgressListener::Open(nsIDOMWindow *aParent) +{ + mParent = aParent; + mNoDialog = 0; + + return NS_OK; +} + +/* attribute long long startTime; */ +NS_IMETHODIMP GProgressListener::GetStartTime(PRInt64 *aStartTime) +{ + *aStartTime = mStartTime; + return NS_OK; +} + +/* attribute nsIURI source; */ +NS_IMETHODIMP GProgressListener::GetSource(nsIURI * *aSource) +{ + NS_IF_ADDREF(*aSource = mUri); + return NS_OK; +} + +/* attribute nsILocalFile target; */ +NS_IMETHODIMP GProgressListener::GetTarget(nsILocalFile * *aTarget) +{ + nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(mFile); + NS_IF_ADDREF(*aTarget = localFile); + return NS_OK; +} + +NS_IMETHODIMP GProgressListener::GetMIMEInfo(nsIMIMEInfo * *aMIMEInfo) +{ + NS_IF_ADDREF(*aMIMEInfo = mMIMEInfo); + return NS_OK; +} + +/* attribute nsIObserver observer; */ +NS_IMETHODIMP GProgressListener::GetObserver(nsIObserver * *aObserver) +{ + NS_IF_ADDREF(*aObserver = mObserver); + return NS_OK; +} +NS_IMETHODIMP GProgressListener::SetObserver(nsIObserver * aObserver) +{ + mObserver = aObserver; + return NS_OK; +} + +/* attribute nsIWebProgressListener listener; */ +NS_IMETHODIMP GProgressListener::GetListener(nsIWebProgressListener * *aListener) +{ + *aListener = nsnull; + return NS_OK; +} +NS_IMETHODIMP GProgressListener::SetListener(nsIWebProgressListener * aListener) +{ + return NS_OK; +} + +/* readonly attribute PRInt32 percentComplete; */ +NS_IMETHODIMP GProgressListener::GetPercentComplete(PRInt32 *aPercentComplete) +{ + return *aPercentComplete = mPercentComplete; +} + +/* attribute wstring displayName; */ +NS_IMETHODIMP GProgressListener::GetDisplayName(PRUnichar * *aDisplayName) +{ + *aDisplayName = nsnull; + return NS_OK; +} +NS_IMETHODIMP GProgressListener::SetDisplayName(const PRUnichar * aDisplayName) +{ + return NS_OK; +} + +NS_IMETHODIMP GProgressListener::GetPersist(nsIWebBrowserPersist * *aPersist) +{ + NS_IF_ADDREF(*aPersist = mPersist); + return NS_OK; +} + +NS_IMETHODIMP GProgressListener::SetDialog(nsIDOMWindow *aDialog) +{ + return NS_OK; +} + +NS_IMETHODIMP GProgressListener::GetDialog(nsIDOMWindow * *aDialog) +{ + *aDialog = nsnull; + return NS_OK; +} + +/* attribute PRBool cancelDownloadOnClose; */ +NS_IMETHODIMP GProgressListener::GetCancelDownloadOnClose(PRBool *aCancelDownloadOnClose) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP GProgressListener::SetCancelDownloadOnClose(PRBool aCancelDownloadOnClose) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP GProgressListener::LaunchHandler (PersistHandlerInfo *handler) +{ + nsresult rv; + nsCOMPtr<nsIExternalHelperAppService> helperService = + do_GetService (NS_EXTERNALHELPERAPPSERVICE_CONTRACTID); + + nsCOMPtr<nsPIExternalAppLauncher> appLauncher = + do_QueryInterface (helperService, &rv); + if (NS_SUCCEEDED(rv)) + { + appLauncher->DeleteTemporaryFileOnExit(mFile); + } + + nsAutoString uFileName; + + mFile->GetPath(uFileName); + const nsACString &cFileName = NS_ConvertUCS2toUTF8(uFileName); + + char *fname = g_strdup(PromiseFlatCString(cFileName).get()); + ephy_file_launch_application (handler->command, + fname, + handler->need_terminal); + g_free (fname); + + return NS_OK; +} + +/* + * void onStateChange (in nsIWebProgress aWebProgress, + * in nsIRequest aRequest, + * in long aStateFlags, + * in unsigned long aStatus); + */ +NS_IMETHODIMP GProgressListener::OnStateChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRUint32 aStateFlags, + PRUint32 aStatus) +{ + if (mAbort) return NS_ERROR_FAILURE; + + if (aStateFlags & nsIWebProgressListener::STATE_STOP) + { + switch (mAction) + { + case ACTION_SAVEFORHELPER: + LaunchHelperApp(); + break; + + case ACTION_NONE: + if (mLauncher) + { + mLauncher->CloseProgressWindow (); + } + break; + case ACTION_OBJECT_NOTIFY: + + g_return_val_if_fail (IS_EPHY_EMBED_PERSIST (mEphyPersist), + NS_ERROR_FAILURE); + + PersistHandlerInfo *handler; + + g_object_get (mEphyPersist, + "handler", &handler, + NULL); + + if (handler) + { + LaunchHandler (handler); + } + + g_signal_emit_by_name (mEphyPersist, "completed"); + } + + if (!mNoDialog) + { + downloader_view_set_download_status (mDownloaderView, + DOWNLOAD_STATUS_COMPLETED, + (gpointer)this); + } + } + + /* done */ + return NS_OK; +} + +/* + * void onProgressChange (in nsIWebProgress aWebProgress, + * in nsIRequest aRequest, + * in long aCurSelfProgress, + * in long aMaxSelfProgress, + * in long aCurTotalProgress, + * in long aMaxTotalProgress); + */ +NS_IMETHODIMP GProgressListener:: + OnProgressChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRInt32 aCurSelfProgress, + PRInt32 aMaxSelfProgress, + PRInt32 aCurTotalProgress, + PRInt32 aMaxTotalProgress) +{ + if (mAbort) return NS_ERROR_FAILURE; + + /* FIXME maxsize check here */ + + if (mNoDialog) return NS_OK; + + if (!mCheckedCanPause) + { + mCheckedCanPause = PR_TRUE; + + nsresult rv; + nsCOMPtr<nsIFTPChannel> channel = + do_QueryInterface (aRequest, &rv); + + mCanPause = (NS_SUCCEEDED (rv) ? PR_TRUE : PR_FALSE); + } + mRequest = aRequest; + + PRInt64 now = PR_Now (); + + /* get out if we're updating too quickly */ + if ((now - mLastUpdate < mInterval) && + (aMaxTotalProgress != -1) && + (aCurTotalProgress < aMaxTotalProgress)) + { + return NS_OK; + } + + /* compute elapsed time */ + mLastUpdate = now; + mElapsed = now - mStartTime; + + /* compute size done */ + PRInt32 currentKBytes = (PRInt32)(aCurTotalProgress / 1024.0 + 0.5); + + /* compute total size */ + PRInt32 totalKBytes = (PRInt32)(aMaxTotalProgress / 1024.0 + 0.5); + + /* compute progress value */ + gfloat progress = -1; + if (aMaxTotalProgress > 0) + { + progress = (gfloat)aCurTotalProgress / + (gfloat)aMaxTotalProgress; + } + + /* compute download rate */ + gfloat speed = -1; + PRInt64 currentRate; + if (mElapsed) + { + currentRate = ((PRInt64)(aCurTotalProgress)) * 1000000 / + mElapsed; + } + else + { + currentRate = 0; + } + + if (!mIsPaused) + { + if (currentRate) + { + PRFloat64 currentKRate = ((PRFloat64)currentRate)/1024; + if (currentKRate != mPriorKRate) + { + if (mRateChanges++ == mRateChangeLimit) + { + mPriorKRate = currentKRate; + mRateChanges = 0; + } + else + { + currentKRate = mPriorKRate; + } + } + else + { + mRateChanges = 0; + } + + speed = currentKRate; + } + } + + /* compute time remaining */ + gint remaining = -1; + if (currentRate && (aMaxTotalProgress > 0)) + { + remaining = + (gint)((aMaxTotalProgress - aCurTotalProgress) + /currentRate +.5); + } + + downloader_view_set_download_progress (mDownloaderView, + mElapsed, + remaining, + speed, + totalKBytes, + currentKBytes, + progress, + mCanPause, + (gpointer)this); + + /* done */ + return NS_OK; +} + +/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */ +NS_IMETHODIMP GProgressListener:: + OnLocationChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, nsIURI *location) +{ + return NS_OK; +} + +/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */ +NS_IMETHODIMP GProgressListener:: + OnStatusChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, nsresult aStatus, + const PRUnichar *aMessage) +{ + return NS_OK; +} + +/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long state); */ +NS_IMETHODIMP GProgressListener:: + OnSecurityChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRUint32 state) +{ + return NS_OK; +} + +//--------------------------------------------------------------------------- + +NS_METHOD GProgressListener::LaunchHelperApp (void) +{ + if (!mMIMEInfo) + return NS_ERROR_FAILURE; + + nsresult rv; + + nsCOMPtr<nsIFile> helperFile; + rv = mMIMEInfo->GetPreferredApplicationHandler(getter_AddRefs(helperFile)); + if(NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCAutoString helperFileName; + rv = helperFile->GetNativePath(helperFileName); + if(NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsMIMEInfoHandleAction mimeAction; + rv = mMIMEInfo->GetPreferredAction(&mimeAction); + if(NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIExternalHelperAppService> helperService = + do_GetService (NS_EXTERNALHELPERAPPSERVICE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr<nsPIExternalAppLauncher> appLauncher = + do_QueryInterface (helperService, &rv); + if (NS_SUCCEEDED(rv)) + { + appLauncher->DeleteTemporaryFileOnExit(mFile); + } + } + + nsCAutoString cFileName; + mFile->GetNativePath(cFileName); + if(NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsXPIDLString helperDesc; + rv = mMIMEInfo->GetApplicationDescription(getter_Copies(helperDesc)); + if(NS_FAILED(rv)) return NS_ERROR_FAILURE; + + gboolean terminalHelper = + helperDesc.Equals(NS_LITERAL_STRING("runInTerminal")) ? + TRUE : FALSE; + + ephy_file_launch_application (helperFileName.get(), + cFileName.get(), + terminalHelper); + + return NS_OK; +} + +nsresult GProgressListener::Pause (void) +{ + nsresult rv; + + if (mCanPause && !mIsPaused) + { + rv = mRequest->Suspend (); + if (NS_SUCCEEDED (rv)) + { + mIsPaused = PR_TRUE; + } + } + else + { + rv = NS_ERROR_FAILURE; + } + + return rv; +} + +nsresult GProgressListener::Resume (void) +{ + nsresult rv; + + if (mCanPause && mIsPaused) + { + rv = mRequest->Resume (); + if (NS_SUCCEEDED (rv)) + { + mIsPaused = PR_FALSE; + } + } + else + { + rv = NS_ERROR_FAILURE; + } + + return rv; +} + +nsresult GProgressListener::Abort (void) +{ + mAction = ACTION_NONE; + + if (mIsPaused) + { + Resume (); + } + + mAbort = PR_TRUE; + + if (mObserver) + { + mObserver->Observe(NS_ISUPPORTS_CAST(nsIProgressDialog*, this), + "oncancel", nsnull); + OnStateChange(nsnull, nsnull, + nsIWebProgressListener::STATE_STOP, 0); + } + + if (mPersist) + { + return mPersist->CancelSave (); + } + + if (mLauncher) + { + return mLauncher->Cancel (); + } + else + { + return NS_ERROR_FAILURE; + } +} + +NS_DEF_FACTORY (GProgressListener, GProgressListener); + +/** + * NS_NewProgressListenerFactory: + */ +nsresult NS_NewProgressListenerFactory(nsIFactory** aFactory) +{ + NS_ENSURE_ARG_POINTER(aFactory); + *aFactory = nsnull; + + nsGProgressListenerFactory *result = new nsGProgressListenerFactory; + if (result == NULL) + { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(result); + *aFactory = result; + + return NS_OK; +} + +static void +download_remove_cb (DownloaderView *dv, GProgressListener *Progress) +{ + Progress->Abort(); +} + +static void +download_resume_cb (DownloaderView *dv, GProgressListener *Progress) +{ + Progress->Resume(); +} + +static void +download_pause_cb (DownloaderView *dv, GProgressListener *Progress) +{ + Progress->Pause(); +} diff --git a/embed/mozilla/ProgressListener.h b/embed/mozilla/ProgressListener.h new file mode 100644 index 000000000..459643194 --- /dev/null +++ b/embed/mozilla/ProgressListener.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2001 Philip Langdale, Matthew Aubury + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PROGRESSLISTENER2_H__ +#define PROGRESSLISTENER2_H__ + +#include "downloader-view.h" +#include "ephy-embed-persist.h" +#include "ephy-embed-shell.h" + +#include <gtk/gtkwidget.h> +#include "nsIWebProgressListener.h" +#include "nsIHelperAppLauncherDialog.h" +#include "nsIExternalHelperAppService.h" +#include "nsCExternalHandlerService.h" +#include "nsIWebBrowserPersist.h" +#include "nsCOMPtr.h" +#include "nsWeakReference.h" +#include "nsIURI.h" +#include "nsILocalFile.h" +#include "nsIDOMWindow.h" +#include "nsIRequest.h" +#include "nsIMIMEInfo.h" +#include "nsIDownload.h" +#include "nsIObserver.h" +#include "nsIProgressDialog.h" + +#include "ContentHandler.h" + +#define G_PROGRESSDIALOG_CID \ +{ /* d2a2f743-f126-4f1f-1234-d4e50490f112 */ \ + 0xd2a2f743, \ + 0xf126, \ + 0x4f1f, \ + {0x12, 0x34, 0xd4, 0xe5, 0x04, 0x90, 0xf1, 0x12} \ +} + +#define G_PROGRESSDIALOG_CLASSNAME "Ephy's Download Progress Dialog" +#define G_PROGRESSDIALOG_CONTRACTID "@mozilla.org/progressdialog;1" + +class GProgressListener : public nsIProgressDialog, + public nsIWebProgressListener, + public nsSupportsWeakReference +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIWEBPROGRESSLISTENER + NS_DECL_NSIPROGRESSDIALOG + NS_DECL_NSIDOWNLOAD + + GProgressListener (); + virtual ~GProgressListener (); + + NS_METHOD InitForPersist (nsIWebBrowserPersist *aPersist, + nsIDOMWindow *aParent, nsIURI *aURI, + nsIFile *aFile, + DownloadAction aAction, + EphyEmbedPersist *ephyPersist, + PRBool noDialog, + PRInt64 aTimeDownloadStarted = 0); + NS_METHOD InitForDownload (nsIHelperAppLauncher *aLauncher, + nsISupports *aContext, + GContentHandler *aHandler, + DownloadAction aDownload); + + nsresult Pause (void); + nsresult Resume (void); + nsresult Abort (void); + + GTimer *mTimer; + + private: + NS_METHOD PrivateInit (void); + NS_METHOD LaunchHelperApp (void); + + NS_METHOD LaunchHandler (PersistHandlerInfo *handler); + + nsCOMPtr<nsIHelperAppLauncher> mLauncher; + nsCOMPtr<nsIWebBrowserPersist> mPersist; + nsCOMPtr<GContentHandler> mHandler; + nsCOMPtr<nsIDOMWindow> mParent; + nsCOMPtr<nsIRequest> mRequest; + + EphyEmbedPersist *mEphyPersist; + + nsCOMPtr<nsIURI> mUri; + PRInt64 mTimeDownloadStarted; + nsCOMPtr<nsIFile> mFile; + + PRInt64 mStartTime; + PRInt64 mElapsed; + + PRInt64 mLastUpdate; + PRInt32 mInterval; + + PRFloat64 mPriorKRate; + PRInt32 mRateChanges; + PRInt32 mRateChangeLimit; + + PRBool mCheckedCanPause; + PRBool mCanPause; + PRBool mIsPaused; + gboolean mNoDialog; + PRBool mAbort; + + DownloadAction mAction; + + DownloaderView *mDownloaderView; + + EphyEmbedShell *ephy_shell; + + guint mTimeoutFunc; + + nsCOMPtr<nsIObserver> mObserver; + + nsCOMPtr<nsIMIMEInfo> mMIMEInfo; + + PRInt32 mPercentComplete; +}; + +extern nsresult NS_NewProgressListenerFactory(nsIFactory** aFactory); + +#endif // PROGRESSLISTENER2_H__ + diff --git a/embed/mozilla/PromptService.cpp b/embed/mozilla/PromptService.cpp new file mode 100644 index 000000000..c9244dd32 --- /dev/null +++ b/embed/mozilla/PromptService.cpp @@ -0,0 +1,769 @@ +/* + * Copyright (C) 2000 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-glade.h" +#include "PromptService.h" + +#include "nsCOMPtr.h" +#include "nsIFactory.h" +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsIServiceManager.h" +#include "nsXPComFactory.h" +#include "MozillaPrivate.h" + +#include "nsIPromptService.h" +#include "nsIUnicodeEncoder.h" + +#include <gtk/gtkentry.h> +#include <gtk/gtktogglebutton.h> +#include <gtk/gtklist.h> +#include <libgnomeui/gnome-dialog.h> +#include <libgnome/gnome-i18n.h> +#include <libgnome/gnome-triggers.h> + +/* local function prototypes */ +static void set_title (GtkWidget *dialog, const PRUnichar *title); +static void set_label_text (GtkWidget *label, const PRUnichar *text); +static void set_check_button_text (GtkWidget *check_button, + const PRUnichar *text); +static void set_check_button (GtkWidget *button, PRBool *value); +static void set_check_button_size_to_label (GtkWidget *check_button, + GtkWidget *label); +static void set_editable (GtkWidget *entry, PRUnichar **text); +static void get_check_button (GtkWidget *button, PRBool *value); +static void get_editable (GtkWidget *editable, PRUnichar **text); + +/** + * class CPromptService: an GNOME implementation of prompt dialogs for + * Mozilla + */ +class CPromptService: public nsIPromptService +{ + public: + CPromptService(); + virtual ~CPromptService(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIPROMPTSERVICE + private: + nsresult AddButton (GtkWidget *dialog, + char type, + const PRUnichar *title, + int id); +}; + +NS_IMPL_ISUPPORTS1 (CPromptService, nsIPromptService) + +/** + * CPromptService::CPromptService: constructor + */ +CPromptService::CPromptService () +{ + NS_INIT_ISUPPORTS(); +} + +/** + * CPromptService::~CPromptService: destructor + */ +CPromptService::~CPromptService () +{ +} + +/** + * CPromptService::Alert: show an alert box + */ +NS_IMETHODIMP CPromptService::Alert (nsIDOMWindow *parent, + const PRUnichar *dialogTitle, + const PRUnichar *text) +{ + GtkWidget *dialog; + GtkWidget *gparent; + + gparent = MozillaFindGtkParent (parent); + const nsACString &msg = NS_ConvertUCS2toUTF8 (text); + dialog = gtk_message_dialog_new (GTK_WINDOW(gparent), + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK, + "%s", + PromiseFlatCString(msg).get ()); + set_title (dialog, dialogTitle); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + return NS_OK; +} + +/** + * CPromptService::AlertCheck: show an alert box with a checkbutton, + * (typically for things like "dont show this warning again") + */ +NS_IMETHODIMP CPromptService::AlertCheck (nsIDOMWindow *parent, + const PRUnichar *dialogTitle, + const PRUnichar *text, + const PRUnichar *checkMsg, + PRBool *checkValue) +{ + GtkWidget *dialog; + GtkWidget *gparent; + GtkWidget *check_button; + + gparent = MozillaFindGtkParent (parent); + const nsACString &msg = NS_ConvertUCS2toUTF8 (text); + dialog = gtk_message_dialog_new (GTK_WINDOW(gparent), + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK, + "%s", + PromiseFlatCString(msg).get ()); + + check_button = gtk_check_button_new_with_label (""); + gtk_widget_show (check_button); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->vbox), + check_button, FALSE, FALSE, 5); + set_check_button_text (check_button, checkMsg); + set_check_button (check_button, checkValue); + + set_title (dialog, dialogTitle); + + gtk_dialog_run (GTK_DIALOG (dialog)); + get_check_button (check_button, checkValue); + gtk_widget_destroy (dialog); + + return NS_OK; +} + +/** + * CPromptService::Confirm: for simple yes/no dialogs + */ +NS_IMETHODIMP CPromptService::Confirm (nsIDOMWindow *parent, + const PRUnichar *dialogTitle, + const PRUnichar *text, + PRBool *_retval) +{ + GtkWidget *dialog; + GtkWidget *gparent; + int res; + + gparent = MozillaFindGtkParent (parent); + const nsACString &msg = NS_ConvertUCS2toUTF8 (text); + dialog = gtk_message_dialog_new (GTK_WINDOW(gparent), + GTK_DIALOG_MODAL, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_YES_NO, + "%s", PromiseFlatCString(msg).get ()); + set_title (dialog, dialogTitle); + + res = gtk_dialog_run (GTK_DIALOG (dialog)); + *_retval = (res == GTK_RESPONSE_YES); + gtk_widget_destroy (dialog); + + return NS_OK; +} + +/** + * CPromptService::Confirm: for simple yes/no dialogs, with an additional + * check button + */ +NS_IMETHODIMP CPromptService::ConfirmCheck (nsIDOMWindow *parent, + const PRUnichar *dialogTitle, + const PRUnichar *text, + const PRUnichar *checkMsg, + PRBool *checkValue, + PRBool *_retval) +{ + GtkWidget *dialog; + GtkWidget *gparent; + GtkWidget *check_button; + int res; + + gparent = MozillaFindGtkParent (parent); + const nsACString &msg = NS_ConvertUCS2toUTF8 (text); + dialog = gtk_message_dialog_new (GTK_WINDOW(gparent), + GTK_DIALOG_MODAL, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_YES_NO, + "%s", PromiseFlatCString(msg).get ()); + + check_button = gtk_check_button_new_with_label (""); + gtk_widget_show (check_button); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->vbox), + check_button, FALSE, FALSE, 5); + set_check_button_text (check_button, checkMsg); + set_check_button (check_button, checkValue); + + set_title (dialog, dialogTitle); + + res = gtk_dialog_run (GTK_DIALOG (dialog)); + *_retval = (res == GTK_RESPONSE_YES); + get_check_button (check_button, checkValue); + gtk_widget_destroy (dialog); + + return NS_OK; +} + +NS_IMETHODIMP CPromptService::AddButton (GtkWidget *dialog, + char type, + const PRUnichar *title, + int id) +{ + const char *btitle; + const nsACString &utf8string = NS_ConvertUCS2toUTF8 (title); + + g_print ("%d", type); + + switch (type) + { + case BUTTON_TITLE_OK: + btitle = GTK_STOCK_OK; + break; + case BUTTON_TITLE_CANCEL: + btitle = GTK_STOCK_CANCEL; + break; + case BUTTON_TITLE_YES: + btitle = GTK_STOCK_YES; + break; + case BUTTON_TITLE_NO: + btitle = GTK_STOCK_NO; + break; + case BUTTON_TITLE_SAVE: + btitle = _("Save"); + break; + case BUTTON_TITLE_REVERT: + btitle = _("Revert"); + break; + case BUTTON_TITLE_DONT_SAVE: + btitle = _("Don't save"); + break; + case BUTTON_TITLE_IS_STRING: + btitle = NULL; + break; + + default: + return NS_ERROR_FAILURE; + } + + gtk_dialog_add_button (GTK_DIALOG(dialog), + btitle ? btitle : + PromiseFlatCString(utf8string).get(), + id); + + return NS_OK; +} + +/** + * CPromptService::ConfirmEx: For fancy confirmation dialogs + */ +NS_IMETHODIMP CPromptService::ConfirmEx (nsIDOMWindow *parent, + const PRUnichar *dialogTitle, + const PRUnichar *text, + PRUint32 buttonFlags, + const PRUnichar *button0Title, + const PRUnichar *button1Title, + const PRUnichar *button2Title, + const PRUnichar *checkMsg, + PRBool *checkValue, + PRInt32 *buttonPressed) +{ + GtkWidget *dialog; + GtkWidget *gparent; + GtkWidget *check_button = NULL; + int ret; + + gparent = MozillaFindGtkParent (parent); + const nsACString &msg = NS_ConvertUCS2toUTF8 (text); + dialog = gtk_message_dialog_new (GTK_WINDOW(gparent), + GTK_DIALOG_MODAL, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + "%s", PromiseFlatCString(msg).get ()); + + set_title (dialog, dialogTitle); + + if (checkMsg) + { + check_button = gtk_check_button_new_with_label (""); + gtk_widget_show (check_button); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->vbox), + check_button, FALSE, FALSE, 5); + + set_check_button_text (check_button, checkMsg); + set_check_button (check_button, checkValue); + } + + AddButton (dialog, (buttonFlags >> 16) & 0xFF, + button2Title, 2); + AddButton (dialog, (buttonFlags >> 8) & 0xFF, + button1Title, 1); + AddButton (dialog, buttonFlags & 0xFF, + button0Title, 0); + + gtk_dialog_set_default_response (GTK_DIALOG(dialog), 0); + + /* make a suitable sound */ + gnome_triggers_vdo ("", "generic", NULL); + + /* run dialog and capture return values */ + ret = gtk_dialog_run (GTK_DIALOG (dialog)); + + /* handle return values */ + if (checkMsg) + { + get_check_button (check_button, checkValue); + } + + *buttonPressed = ret; + + /* done */ + gtk_widget_destroy (dialog); + return NS_OK; +} + +/** + * CPromptService::Prompt: show a prompt for text, with a checkbutton + */ +NS_IMETHODIMP CPromptService::Prompt (nsIDOMWindow *parent, + const PRUnichar *dialogTitle, + const PRUnichar *text, + PRUnichar **value, + const PRUnichar *checkMsg, + PRBool *checkValue, + PRBool *_retval) +{ + GtkWidget *dialog; + GtkWidget *entry; + GtkWidget *label; + GtkWidget *check_button; + GtkWidget *gparent; + GladeXML *gxml; + gint ret; + + /* build and show the dialog */ + gxml = ephy_glade_widget_new ("prompts.glade", "prompt_dialog", + &dialog, NULL); + entry = glade_xml_get_widget (gxml, "entry"); + label = glade_xml_get_widget (gxml, "label"); + check_button = glade_xml_get_widget (gxml, "check_button"); + g_object_unref (G_OBJECT (gxml)); + + /* parent the dialog */ + gparent = MozillaFindGtkParent (parent); + gtk_window_set_transient_for (GTK_WINDOW (dialog), + GTK_WINDOW (gparent)); + + /* set dynamic attributes */ + set_title (dialog, dialogTitle); + set_label_text (label, text); + set_check_button_text (check_button, checkMsg); + set_editable (entry, value); + set_check_button (check_button, checkValue); + set_check_button_size_to_label (check_button, label); + + /* make a suitable sound */ + /* NB: should be question, but this is missing in many + * of the current gnome sound packages that I've tried... */ + gnome_triggers_vdo ("", "generic", NULL); + + /* run dialog and capture return values */ + ret = gtk_dialog_run (GTK_DIALOG (dialog)); + + /* handle return values */ + get_check_button (check_button, checkValue); + get_editable (entry, value); + *_retval = (ret == GTK_RESPONSE_OK); + + /* done */ + gtk_widget_destroy (dialog); + return NS_OK; +} + +/** + * CPromptService::PromptUsernameAndPassword: show a prompt for username + * and password with an additional check button. + */ +NS_IMETHODIMP CPromptService::PromptUsernameAndPassword + (nsIDOMWindow *parent, + const PRUnichar *dialogTitle, + const PRUnichar *text, + PRUnichar **username, + PRUnichar **password, + const PRUnichar *checkMsg, + PRBool *checkValue, + PRBool *_retval) +{ + GtkWidget *dialog; + GtkWidget *check_button; + GtkWidget *label; + GtkWidget *username_entry; + GtkWidget *password_entry; + GtkWidget *gparent; + GladeXML *gxml; + gint ret; + + /* build and show the dialog */ + gxml = ephy_glade_widget_new ("prompts.glade", "prompt_user_pass_dialog", + &dialog, NULL); + check_button = glade_xml_get_widget (gxml, "check_button"); + label = glade_xml_get_widget (gxml, "label"); + username_entry = glade_xml_get_widget (gxml, "username_entry"); + password_entry = glade_xml_get_widget (gxml, "password_entry"); + g_object_unref (G_OBJECT (gxml)); + + /* parent the dialog */ + gparent = MozillaFindGtkParent (parent); + gtk_window_set_transient_for (GTK_WINDOW (dialog), + GTK_WINDOW (gparent)); + + /* set dynamic attributes */ + set_title (dialog, dialogTitle); + set_check_button_text (check_button, checkMsg); + set_editable (username_entry, username); + set_editable (password_entry, password); + set_check_button (check_button, checkValue); + set_label_text (label, text); + set_check_button_size_to_label (check_button, label); + + /* make a suitable sound */ + gnome_triggers_vdo ("", "question", NULL); + + /* run dialog and capture return values */ + ret = gtk_dialog_run (GTK_DIALOG (dialog)); + + /* handle return values */ + get_check_button (check_button, checkValue); + get_editable (username_entry, username); + get_editable (password_entry, password); + *_retval = (ret == GTK_RESPONSE_OK); + + /* done */ + gtk_widget_destroy (dialog); + return NS_OK; +} + +/** + * CPromptService::PromptPassword: show a prompt for just + * a password with an additional check button. + */ +NS_IMETHODIMP CPromptService::PromptPassword (nsIDOMWindow *parent, + const PRUnichar *dialogTitle, + const PRUnichar *text, + PRUnichar **password, + const PRUnichar *checkMsg, + PRBool *checkValue, + PRBool *_retval) +{ + GtkWidget *dialog; + GtkWidget *label; + GtkWidget *check_button; + GtkWidget *password_entry; + GtkWidget *gparent; + GladeXML *gxml; + gint ret; + + /* build and show the dialog */ + gxml = ephy_glade_widget_new ("prompts.glade", "prompt_pass_dialog", + &dialog, NULL); + check_button = glade_xml_get_widget (gxml, "check_button"); + label = glade_xml_get_widget (gxml, "label"); + password_entry = glade_xml_get_widget (gxml, "password_entry"); + g_object_unref (G_OBJECT (gxml)); + + /* parent the dialog */ + gparent = MozillaFindGtkParent (parent); + gtk_window_set_transient_for (GTK_WINDOW (dialog), + GTK_WINDOW (gparent)); + + /* set dynamic attributes */ + set_title (dialog, dialogTitle); + set_check_button_text (check_button, checkMsg); + set_editable (password_entry, password); + set_check_button (check_button, checkValue); + set_label_text (label, text); + set_check_button_size_to_label (check_button, label); + + /* make a suitable sound */ + gnome_triggers_vdo ("", "question", NULL); + + /* run dialog and capture return values */ + ret = gtk_dialog_run (GTK_DIALOG (dialog)); + + /* handle return values */ + get_check_button (check_button, checkValue); + get_editable (password_entry, password); + *_retval = (ret == GTK_RESPONSE_OK); + + /* done */ + gtk_widget_destroy (dialog); + return NS_OK; +} + + +/** + * CPromptService::Select: + */ +NS_IMETHODIMP CPromptService::Select (nsIDOMWindow *parent, + const PRUnichar *dialogTitle, + const PRUnichar *text, PRUint32 count, + const PRUnichar **selectList, + PRInt32 *outSelection, + PRBool *_retval) +{ + GtkWidget *dialog; + GtkWidget *gparent; + GtkWidget *label; + GladeXML *gxml; + GtkWidget *treeview; + gint ret; + + /* build and show the dialog */ + gxml = ephy_glade_widget_new ("prompts.glade", "select_dialog", + &dialog, NULL); + treeview = glade_xml_get_widget (gxml, "treeview"); + label = glade_xml_get_widget (gxml, "label"); + g_object_unref (G_OBJECT (gxml)); + + /* parent the dialog */ + gparent = MozillaFindGtkParent (parent); + gtk_window_set_transient_for (GTK_WINDOW (dialog), + GTK_WINDOW (gparent)); + + /* set dynamic attributes */ + set_title (dialog, dialogTitle); + set_label_text (label, text); + + /* setup treeview */ + GtkCellRenderer *renderer; + GtkListStore *liststore; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + + gtk_tree_view_set_reorderable (GTK_TREE_VIEW(treeview), TRUE); + + liststore = gtk_list_store_new (2, + G_TYPE_STRING, + G_TYPE_INT); + + model = GTK_TREE_MODEL (liststore); + + gtk_tree_view_set_model (GTK_TREE_VIEW(treeview), + model); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), + FALSE); + + renderer = gtk_cell_renderer_text_new (); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview), + 0, "Items", + renderer, + "text", 0, + NULL); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(treeview)); + + for (PRUint32 i = 0 ; i < count ; i++) + { + char *itemText = + ToNewCString(NS_ConvertUCS2toUTF8 (selectList[i])); + gtk_list_store_append (GTK_LIST_STORE (model), + &iter); + gtk_list_store_set (GTK_LIST_STORE (model), + &iter, + 0, itemText, + 1, i, + -1); + nsMemory::Free(itemText); + } + + gtk_tree_model_get_iter_first (model, &iter); + gtk_tree_selection_select_iter (selection, &iter); + + /* make a suitable sound */ + gnome_triggers_vdo ("", "question", NULL); + + /* run dialog and capture return values */ + ret = gtk_dialog_run (GTK_DIALOG (dialog)); + + /* handle return values */ + if (gtk_tree_selection_get_selected (selection, + &model, + &iter)) + { + GValue val = {0, }; + gtk_tree_model_get_value (model, &iter, 1, &val); + *outSelection = g_value_get_int (&val); + + *_retval = (ret == GTK_RESPONSE_OK) ? PR_TRUE : PR_FALSE; + } + else + { + *_retval = PR_FALSE; + } + + gtk_widget_destroy (dialog); + + return NS_OK; +} + +NS_DEF_FACTORY (CPromptService, CPromptService); + +/** + * NS_NewPromptServiceFactory: + */ +nsresult NS_NewPromptServiceFactory(nsIFactory** aFactory) +{ + NS_ENSURE_ARG_POINTER(aFactory); + *aFactory = nsnull; + + nsCPromptServiceFactory *result = new nsCPromptServiceFactory; + if (result == NULL) + { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(result); + *aFactory = result; + + return NS_OK; +} + +/** + * set_title: set a dialog title to a unicode string + */ +static void +set_title (GtkWidget *dialog, const PRUnichar *title) +{ + const nsACString &utf8string = NS_ConvertUCS2toUTF8 (title); + + /* set it */ + gtk_window_set_title (GTK_WINDOW (dialog), + (title == NULL ? N_("Galeon") : + PromiseFlatCString(utf8string).get())); +} + +/** + * set_label_text: set a labels text to a unicode string + */ +static void +set_label_text (GtkWidget *label, const PRUnichar *text) +{ + const nsACString &utf8string = NS_ConvertUCS2toUTF8 (text); + + /* set it */ + gtk_label_set_text (GTK_LABEL (label), + PromiseFlatCString(utf8string).get()); +} + +/** + * set_check_button_text: set a check buttons text to a unicode string + */ +static void +set_check_button_text (GtkWidget *check_button, const PRUnichar *text) +{ + const nsACString &utf8string = NS_ConvertUCS2toUTF8 (text); + + /* set it */ + gtk_label_set_text (GTK_LABEL (GTK_BIN (check_button)->child), + PromiseFlatCString(utf8string).get()); +} + +/** + * set_check_button: set a togglebutton to an initial state + */ +static void +set_check_button (GtkWidget *button, PRBool *value) +{ + /* check pointer is valid */ + if (value == NULL) + { + gtk_widget_hide (GTK_WIDGET (button)); + return; + } + + /* set the value of the check button */ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), *value); +} + +/** + * se_check_button_size_to_label: sync text widgets sizes + */ +static void +set_check_button_size_to_label (GtkWidget *check_button, + GtkWidget *label) +{ + GtkRequisition r, label_r; + + gtk_widget_size_request (check_button, &r); + gtk_widget_size_request (label, &label_r); + + if (r.width <= label_r.width) return; + + gtk_widget_set_size_request (label, r.width, 0); +} + +/** + * set_editable: set an editable to a unicode string + */ +static void +set_editable (GtkWidget *entry, PRUnichar **text) +{ + const nsACString &utf8string = NS_ConvertUCS2toUTF8 (*text); + + /* set this string value in the widget */ + gtk_entry_set_text (GTK_ENTRY (entry), + PromiseFlatCString(utf8string).get()); +} + +/** + * get_check_button: get value of a toggle button and store it in a PRBool + */ +static void +get_check_button (GtkWidget *button, PRBool *value) +{ + /* check we can write */ + if (value == NULL) + { + return; + } + + /* set the value from the check button */ + *value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); +} + +/** + * get_editable: get a string from an editable and store it as unicode + */ +static void +get_editable (GtkWidget *editable, PRUnichar **text) +{ + char *edited; + + /* check we can write */ + if (text == NULL) + { + return; + } + + /* get the text */ + edited = gtk_editable_get_chars (GTK_EDITABLE (editable), 0, -1); + + /* decode and set it as the return value */ + *text = ToNewUnicode(NS_ConvertUTF8toUCS2(edited)); +} diff --git a/embed/mozilla/PromptService.h b/embed/mozilla/PromptService.h new file mode 100644 index 000000000..98d8d0c46 --- /dev/null +++ b/embed/mozilla/PromptService.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2000 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PromptService_h +#define __PromptService_h + +#include "nsError.h" + +#define G_PROMPTSERVICE_CID \ +{ /* c5a77759-a07a-4025-8f74-ae89153ee6c2 */ \ + 0xc5a77759, \ + 0xa07a, \ + 0x4025, \ + {0x8f, 0x74, 0xae, 0x89, 0x15, 0x3e, 0xe6, 0xc2} \ +} + +#define G_PROMPTSERVICE_CLASSNAME "Galeon's Prompt Service" +#define G_PROMPTSERVICE_CONTRACTID "@mozilla.org/embedcomp/prompt-service;1" + +class nsIFactory; + +extern nsresult NS_NewPromptServiceFactory(nsIFactory** aFactory); + +#endif diff --git a/embed/mozilla/StartHereProtocolHandler.cpp b/embed/mozilla/StartHereProtocolHandler.cpp new file mode 100644 index 000000000..47a1af310 --- /dev/null +++ b/embed/mozilla/StartHereProtocolHandler.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2001 Matt Aubury, Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-file-helpers.h" + +#include "nsCOMPtr.h" +#include "nsIFactory.h" +#include "nsIIOService.h" +#include "nsIServiceManager.h" +#include "nsIURI.h" +#include "nsNetCID.h" +#include "nsNetUtil.h" +#include "nsXPComFactory.h" + +static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID); + +class GStartHereProtocolHandler : public nsIProtocolHandler +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPROTOCOLHANDLER + + GStartHereProtocolHandler (void); + virtual ~GStartHereProtocolHandler(); + + nsCOMPtr<nsIChannel> mChannel; + nsCOMPtr<nsIURI> mURI; +}; + +/* Implementation file */ +NS_IMPL_ISUPPORTS1 (GStartHereProtocolHandler, nsIProtocolHandler) + +GStartHereProtocolHandler::GStartHereProtocolHandler (void) +{ + NS_INIT_ISUPPORTS(); + +} + +GStartHereProtocolHandler::~GStartHereProtocolHandler() +{ + /* destructor code */ +} + +/* readonly attribute string scheme; */ +NS_IMETHODIMP GStartHereProtocolHandler::GetScheme(nsACString &aScheme) +{ + aScheme = NS_LITERAL_CSTRING("start-here"); + return NS_OK; +} + +/* readonly attribute long defaultPort; */ +NS_IMETHODIMP GStartHereProtocolHandler::GetDefaultPort(PRInt32 *aDefaultPort) +{ + nsresult rv = NS_OK; + if (aDefaultPort) + *aDefaultPort = -1; + else + rv = NS_ERROR_NULL_POINTER; + return rv; +} + +/* readonly attribute short protocolFlags; */ +NS_IMETHODIMP GStartHereProtocolHandler::GetProtocolFlags(PRUint32 *aProtocolFlags) +{ + if (aProtocolFlags) + *aProtocolFlags = nsIProtocolHandler::URI_STD; + else + return NS_ERROR_NULL_POINTER; + return NS_OK; +} + +/* nsIURI newURI (in string aSpec, in nsIURI aBaseURI); */ +NS_IMETHODIMP GStartHereProtocolHandler::NewURI(const nsACString &aSpec, + const char *aOriginCharset, + nsIURI *aBaseURI, + nsIURI **_retval) +{ + nsresult rv = NS_OK; + nsCOMPtr <nsIURI> newUri; + + rv = nsComponentManager::CreateInstance(kSimpleURICID, NULL, + NS_GET_IID(nsIURI), + getter_AddRefs(newUri)); + + if (NS_SUCCEEDED(rv)) + { + newUri->SetSpec(aSpec); + rv = newUri->QueryInterface(NS_GET_IID(nsIURI), + (void **) _retval); + } + return rv; +} + +/* nsIChannel newChannel (in nsIURI aURI); */ +NS_IMETHODIMP GStartHereProtocolHandler::NewChannel(nsIURI *aURI, + nsIChannel **_retval) +{ + nsresult rv; + + nsCAutoString path; + rv = aURI->GetPath(path); + if (NS_FAILED(rv)) return rv; + + char *httpSpec = g_strconcat ("file:///", + ephy_file ("start_here.html"), + NULL); + + if (!httpSpec) return NS_ERROR_OUT_OF_MEMORY; + + nsCOMPtr<nsIIOService> serv(do_GetIOService(&rv)); + if (NS_FAILED(rv)) return rv; + + // now we have an HTTP url, give the user an HTTP channel + rv = serv->NewChannel(nsDependentCString(httpSpec), nsnull, nsnull, _retval); + + return rv; +} + +/* boolean allowPort (in long port, in string scheme); */ +NS_IMETHODIMP GStartHereProtocolHandler::AllowPort(PRInt32 port, const char *scheme, + PRBool *_retval) +{ + *_retval = PR_FALSE; + return NS_OK; +} + +NS_DEF_FACTORY (GStartHereProtocolHandler, GStartHereProtocolHandler); + +/** + * NS_NewStartHereProtocolHandlerFactory: + */ +nsresult NS_NewStartHereHandlerFactory(nsIFactory** aFactory) +{ + NS_ENSURE_ARG_POINTER(aFactory); + *aFactory = nsnull; + + nsGStartHereProtocolHandlerFactory *result = new nsGStartHereProtocolHandlerFactory; + if (result == NULL) + { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(result); + *aFactory = result; + + return NS_OK; +} diff --git a/embed/mozilla/StartHereProtocolHandler.h b/embed/mozilla/StartHereProtocolHandler.h new file mode 100644 index 000000000..82c74774b --- /dev/null +++ b/embed/mozilla/StartHereProtocolHandler.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2001 Philip Langdale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef StartHereProtocolHandler_h__ +#define StartHereProtocolHandler_h__ + +#include "nsError.h" + +#define G_START_HERE_PROTOCOLHANDLER_CID \ +{ /* a3a7b6e5-7a92-431d-87e6-3bef8e7ada51*/ \ + 0xa3a7b6e5, \ + 0x7a92, \ + 0x431d, \ + {0x87, 0xe6, 0x3b, 0xef, 0x8e, 0x7a, 0xda, 0x51} \ +} +#define G_START_HERE_PROTOCOLHANDLER_CONTRACTID NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "start-here" +#define G_START_HERE_PROTOCOLHANDLER_CLASSNAME "Galeon's start here protocol handler" + +class nsIFactory; + +extern nsresult NS_NewStartHereHandlerFactory(nsIFactory** aFactory); + +#endif // MyportalProtocolHandler_h__ diff --git a/embed/mozilla/mozilla-embed-persist.cpp b/embed/mozilla/mozilla-embed-persist.cpp new file mode 100644 index 000000000..abfcacd57 --- /dev/null +++ b/embed/mozilla/mozilla-embed-persist.cpp @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ProgressListener.h" +#include "EphyWrapper.h" +#include "mozilla-embed.h" +#include "mozilla-embed-persist.h" + +#include <stddef.h> +#include <nsIWebBrowserPersist.h> +#include <nsString.h> +#include <nsCWebBrowserPersist.h> +#include <nsNetUtil.h> + +static void +mozilla_embed_persist_class_init (MozillaEmbedPersistClass *klass); +static void +mozilla_embed_persist_init (MozillaEmbedPersist *ges); +static void +mozilla_embed_persist_finalize (GObject *object); + +static gresult +impl_save (EphyEmbedPersist *persist); + +struct MozillaEmbedPersistPrivate +{ + gpointer dummy; +}; + +static GObjectClass *parent_class = NULL; + +GType +mozilla_embed_persist_get_type (void) +{ + static GType mozilla_embed_persist_type = 0; + + if (mozilla_embed_persist_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (MozillaEmbedPersistClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) mozilla_embed_persist_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (MozillaEmbedPersist), + 0, /* n_preallocs */ + (GInstanceInitFunc) mozilla_embed_persist_init + }; + + mozilla_embed_persist_type = + g_type_register_static (EPHY_EMBED_PERSIST_TYPE, + "MozillaEmbedPersist", + &our_info, (GTypeFlags)0); + } + + return mozilla_embed_persist_type; +} + +static void +mozilla_embed_persist_class_init (MozillaEmbedPersistClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + EphyEmbedPersistClass *persist_class; + + parent_class = (GObjectClass *) g_type_class_peek_parent (klass); + persist_class = EPHY_EMBED_PERSIST_CLASS (klass); + + object_class->finalize = mozilla_embed_persist_finalize; + + persist_class->save = impl_save; +} + +static void +mozilla_embed_persist_init (MozillaEmbedPersist *persist) +{ + persist->priv = g_new0 (MozillaEmbedPersistPrivate, 1); +} + +static void +mozilla_embed_persist_finalize (GObject *object) +{ + MozillaEmbedPersist *persist; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_MOZILLA_EMBED_PERSIST (object)); + + persist = MOZILLA_EMBED_PERSIST (object); + + g_return_if_fail (persist->priv != NULL); + + g_free (persist->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gresult +impl_save (EphyEmbedPersist *persist) +{ + nsresult rv; + nsAutoString s; + char *filename; + char *uri; + int max_size; + EphyEmbed *embed; + EmbedPersistFlags flags; + EphyWrapper *wrapper = NULL; + + g_object_get (persist, + "source", &uri, + "dest", &filename, + "flags", &flags, + "embed", &embed, + "max_size", &max_size, + NULL); + + g_return_val_if_fail (filename != NULL, G_FAILED); + + nsCOMPtr<nsIURI> linkURI; + linkURI = nsnull; + if (uri) + { + s.AssignWithConversion(uri); + rv = NS_NewURI(getter_AddRefs(linkURI), s); + if (NS_FAILED(rv) || !linkURI) return G_FAILED; + } + + nsCOMPtr<nsIWebBrowserPersist> bpersist = + do_CreateInstance(NS_WEBBROWSERPERSIST_CONTRACTID, &rv); + if (NS_FAILED(rv) || !persist) return G_FAILED; + + nsCOMPtr<nsILocalFile> file; + NS_NewLocalFile(NS_ConvertUTF8toUCS2(filename), PR_TRUE, getter_AddRefs(file)); + if (NS_FAILED(rv) || !file) return G_FAILED; + + nsCOMPtr<nsILocalFile> path; + if (flags & EMBED_PERSIST_SAVE_CONTENT) + { + char *datapath; + datapath = g_strconcat (filename, "content", NULL); + NS_NewLocalFile(NS_ConvertUTF8toUCS2(datapath), PR_TRUE, getter_AddRefs(path)); + g_free (datapath); + } + else + { + path = nsnull; + } + + nsCOMPtr<nsIDOMWindow> parent; + parent = nsnull; + + if (embed) + { + wrapper = (EphyWrapper *) mozilla_embed_get_galeon_wrapper (MOZILLA_EMBED(embed)); + wrapper->GetDOMWindow (getter_AddRefs (parent)); + } + + size_t len = strlen(filename); + if((filename[len-1] == 'z' && filename[len-2] == 'g') || + (filename[len-1] == 'Z' && filename[len-2] == 'G')) + { + bpersist->SetPersistFlags (nsIWebBrowserPersist::PERSIST_FLAGS_NO_CONVERSION); + } + else + { + bpersist->SetPersistFlags (nsIWebBrowserPersist::PERSIST_FLAGS_NONE); + } + + if (flags & EMBED_PERSIST_BYPASSCACHE) + { + bpersist->SetPersistFlags (nsIWebBrowserPersist::PERSIST_FLAGS_BYPASS_CACHE); + } + + if (flags & EMBED_PERSIST_FROMCACHE) + { + bpersist->SetPersistFlags (nsIWebBrowserPersist::PERSIST_FLAGS_FROM_CACHE); + } + + GProgressListener *aProgress = new GProgressListener (); + + if (uri == NULL) + { + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + nsCOMPtr<nsIDOMDocument> DOMDocument; + + if (flags & EMBED_PERSIST_MAINDOC) + { + rv = wrapper->GetMainDOMDocument (getter_AddRefs(DOMDocument)); + } + else + { + rv = wrapper->GetDOMDocument (getter_AddRefs(DOMDocument)); + } + if (NS_FAILED(rv) || !DOMDocument) return G_FAILED; + + nsCOMPtr<nsIDocument> document = + do_QueryInterface (DOMDocument, &rv); + if (NS_FAILED(rv) || !document) return G_FAILED; + + nsCOMPtr<nsIURI> uri; + rv = document->GetDocumentURL (getter_AddRefs(uri)); + if (NS_FAILED(rv) || !uri) return G_FAILED; + + aProgress->InitForPersist (bpersist, parent, + uri, file, + ACTION_OBJECT_NOTIFY, + persist, + !(flags & EMBED_PERSIST_SHOW_PROGRESS)); + + rv = bpersist->SaveDocument (DOMDocument, file, path, nsnull, 0, 0); + if (NS_FAILED(rv)) return G_FAILED; + } + else + { + aProgress->InitForPersist (bpersist, parent, + linkURI, file, + ACTION_OBJECT_NOTIFY, + persist, + !(flags & EMBED_PERSIST_SHOW_PROGRESS)); + + rv = bpersist->SaveURI (linkURI, nsnull, file); + if (NS_FAILED(rv)) return G_FAILED; + } + + return G_OK; +} + diff --git a/embed/mozilla/mozilla-embed-persist.h b/embed/mozilla/mozilla-embed-persist.h new file mode 100644 index 000000000..bcd073ca3 --- /dev/null +++ b/embed/mozilla/mozilla-embed-persist.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef MOZILLA_EMBED_PERSIST_H +#define MOZILLA_EMBED_PERSIST_H + +#include "ephy-embed-persist.h" + +#include <glib-object.h> +#include <glib.h> + +G_BEGIN_DECLS + +typedef struct MozillaEmbedPersistClass MozillaEmbedPersistClass; + +#define MOZILLA_EMBED_PERSIST_TYPE (mozilla_embed_persist_get_type ()) +#define MOZILLA_EMBED_PERSIST(obj) (GTK_CHECK_CAST ((obj), MOZILLA_EMBED_PERSIST_TYPE, MozillaEmbedPersist)) +#define MOZILLA_EMBED_PERSIST_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), MOZILLA_EMBED_PERSIST_TYPE, MozillaEmbedPersistClass)) +#define IS_MOZILLA_EMBED_PERSIST(obj) (GTK_CHECK_TYPE ((obj), MOZILLA_EMBED_PERSIST_TYPE)) +#define IS_MOZILLA_EMBED_PERSIST_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), MOZILLA_EMBED_PERSIST)) +#define MOZILLA_EMBED_PERSIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOZILLA_EMBED_PERSIST_TYPE, MozillaEmbedPersistClass)) + +typedef struct MozillaEmbedPersist MozillaEmbedPersist; +typedef struct MozillaEmbedPersistPrivate MozillaEmbedPersistPrivate; + +struct MozillaEmbedPersist +{ + EphyEmbedPersist parent; + MozillaEmbedPersistPrivate *priv; +}; + +struct MozillaEmbedPersistClass +{ + EphyEmbedPersistClass parent_class; +}; + +GType mozilla_embed_persist_get_type (void); + +G_END_DECLS + +#endif diff --git a/embed/mozilla/mozilla-embed-shell.cpp b/embed/mozilla/mozilla-embed-shell.cpp new file mode 100644 index 000000000..00b3c390d --- /dev/null +++ b/embed/mozilla/mozilla-embed-shell.cpp @@ -0,0 +1,1106 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "glib.h" +#include "ephy-string.h" +#include "gtkmozembed.h" +#include "mozilla-embed-shell.h" +#include "mozilla-prefs.h" +#include "ephy-prefs.h" +#include "ephy-file-helpers.h" +#include "mozilla-notifiers.h" +#include "mozilla-i18n.h" +#include "eel-gconf-extensions.h" +#include "ephy-embed-prefs.h" +#include "MozRegisterComponents.h" +#include "FilePicker.h" + +#include <time.h> +#include <libgnome/gnome-i18n.h> +#include <string.h> +#include <nsICacheService.h> +#include <nsCOMPtr.h> +#include <nsNetCID.h> +#include <nsIServiceManager.h> +#include <nsIIOService.h> +#include <nsIProtocolProxyService.h> +#include <nsIJVMManager.h> +#include <nsIAtom.h> +#include <nsICharsetConverterManager.h> +#include <nsICharsetConverterManager2.h> +#include <nsIFontList.h> +#include <nsISupportsPrimitives.h> +#include <nsReadableUtils.h> +#include <nsIPermissionManager.h> +#include <nsICookieManager.h> +#include <nsIPermission.h> +#include <nsIPasswordManager.h> +#include <nsIPassword.h> +#include <nsICookie.h> +#include <nsCCookieManager.h> +#include <nsCPasswordManager.h> + +#define MOZILLA_PROFILE_DIR "/mozilla" +#define MOZILLA_PROFILE_NAME "epiphany" +#define MOZILLA_PROFILE_FILE "prefs.js" + +static void +mozilla_embed_shell_class_init (MozillaEmbedShellClass *klass); +static void +mozilla_embed_shell_init (MozillaEmbedShell *ges); +static void +mozilla_embed_shell_finalize (GObject *object); + +static void +impl_get_capabilities (EphyEmbedShell *shell, + EmbedShellCapabilities *caps); +static gresult +impl_clear_cache (EphyEmbedShell *shell, + CacheType type); +static gresult +impl_set_offline_mode (EphyEmbedShell *shell, + gboolean offline); +static gresult +impl_load_proxy_autoconf (EphyEmbedShell *shell, + const char* url); +static gresult +impl_get_charset_titles (EphyEmbedShell *shell, + const char *group, + GList **charsets); +static gresult +impl_get_charset_groups (EphyEmbedShell *shell, + GList **groups); +static gresult +impl_get_font_list (EphyEmbedShell *shell, + const char *langGroup, + const char *fontType, + GList **fontList, + char **default_font); +static gresult +impl_set_permission (EphyEmbedShell *shell, + const char *url, + PermissionType type, + gboolean allow); +static gresult +impl_list_permissions (EphyEmbedShell *shell, + PermissionType type, + GList **permissions); +static gresult +impl_remove_permissions (EphyEmbedShell *shell, + PermissionType type, + GList *permissions); +static gresult +impl_list_cookies (EphyEmbedShell *shell, + GList **cookies); +static gresult +impl_remove_cookies (EphyEmbedShell *shell, + GList *cookies); +static gresult +impl_list_passwords (EphyEmbedShell *shell, + PasswordType type, + GList **passwords); +static gresult +impl_remove_passwords (EphyEmbedShell *shell, + GList *passwords, + PasswordType type); +static gresult +impl_show_file_picker (EphyEmbedShell *shell, + GtkWidget *parentWidget, + const char *title, + const char *directory, + const char *file, + FilePickerMode mode, + char **ret_fullpath, + gboolean *ret_save_content, + FileFormat *file_formats, + int *ret_file_format); + +static void mozilla_embed_shell_new_window_orphan_cb (GtkMozEmbedSingle *embed, + GtkMozEmbed **retval, + guint chrome_mask, + EphyEmbedShell *shell); + +struct MozillaEmbedShellPrivate +{ + GHashTable *charsets_hash; + GList *sorted_charsets_titles; +}; + +static NS_DEFINE_CID(kJVMManagerCID, NS_JVMMANAGER_CID); + +static GObjectClass *parent_class = NULL; + +GType +mozilla_embed_shell_get_type (void) +{ + static GType mozilla_embed_shell_type = 0; + + if (mozilla_embed_shell_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (MozillaEmbedShellClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) mozilla_embed_shell_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (MozillaEmbedShell), + 0, /* n_preallocs */ + (GInstanceInitFunc) mozilla_embed_shell_init + }; + + mozilla_embed_shell_type = g_type_register_static (EPHY_EMBED_SHELL_TYPE, + "MozillaEmbedShell", + &our_info, (GTypeFlags)0); + } + + return mozilla_embed_shell_type; +} + +static void +mozilla_embed_shell_class_init (MozillaEmbedShellClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + EphyEmbedShellClass *shell_class; + + parent_class = (GObjectClass *) g_type_class_peek_parent (klass); + shell_class = EPHY_EMBED_SHELL_CLASS (klass); + + object_class->finalize = mozilla_embed_shell_finalize; + + shell_class->get_capabilities = impl_get_capabilities; + shell_class->clear_cache = impl_clear_cache; + shell_class->set_offline_mode = impl_set_offline_mode; + shell_class->load_proxy_autoconf = impl_load_proxy_autoconf; + shell_class->get_charset_titles = impl_get_charset_titles; + shell_class->get_charset_groups = impl_get_charset_groups; + shell_class->get_font_list = impl_get_font_list; + shell_class->set_permission = impl_set_permission; + shell_class->list_permissions = impl_list_permissions; + shell_class->remove_permissions = impl_remove_permissions; + shell_class->list_cookies = impl_list_cookies; + shell_class->remove_cookies = impl_remove_cookies; + shell_class->list_passwords = impl_list_passwords; + shell_class->remove_passwords = impl_remove_passwords; + shell_class->show_file_picker = impl_show_file_picker; +} + +static void +mozilla_load_proxy_prefs (MozillaEmbedShell *shell) +{ + char *tmp; + int i, mozilla_mode = 0; + + /* Proxy mode */ + tmp = eel_gconf_get_string (CONF_NETWORK_PROXY_MODE); + g_return_if_fail (tmp != NULL); + + if (strcmp (tmp, "manual") == 0) + { + mozilla_mode = 1; + } + else if (strcmp (tmp, "auto") == 0) + { + mozilla_mode = 2; + } + + mozilla_prefs_set_int ("network.proxy.type", mozilla_mode); + g_free (tmp); + + /* Http proxy */ + tmp = eel_gconf_get_string (CONF_NETWORK_HTTP_PROXY); + g_return_if_fail (tmp != NULL); + mozilla_prefs_set_string ("network.proxy.http", tmp); + g_free (tmp); + + i = eel_gconf_get_integer (CONF_NETWORK_HTTP_PROXY_PORT); + mozilla_prefs_set_int ("network.proxy.http_port", i); + + /* Ftp proxy */ + tmp = eel_gconf_get_string (CONF_NETWORK_FTP_PROXY); + g_return_if_fail (tmp != NULL); + mozilla_prefs_set_string ("network.proxy.ftp", tmp); + g_free (tmp); + + i = eel_gconf_get_integer (CONF_NETWORK_FTP_PROXY_PORT); + mozilla_prefs_set_int ("network.proxy.ftp_port", i); + + /* Secure proxy */ + tmp = eel_gconf_get_string (CONF_NETWORK_SSL_PROXY); + g_return_if_fail (tmp != NULL); + mozilla_prefs_set_string ("network.proxy.ssl", tmp); + g_free (tmp); + + i = eel_gconf_get_integer (CONF_NETWORK_SSL_PROXY_PORT); + mozilla_prefs_set_int ("network.proxy.ssl_port", i); + + /* Socks proxy */ + tmp = eel_gconf_get_string (CONF_NETWORK_SOCKS_PROXY); + g_return_if_fail (tmp != NULL); + mozilla_prefs_set_string ("network.proxy.socks", tmp); + g_free (tmp); + + i = eel_gconf_get_integer (CONF_NETWORK_SOCKS_PROXY_PORT); + mozilla_prefs_set_int ("network.proxy.socks_port", i); + + /* Autoconfiguration */ + tmp = eel_gconf_get_string (CONF_NETWORK_PROXY_AUTO_URL); + g_return_if_fail (tmp != NULL); + ephy_embed_shell_load_proxy_autoconf + (EPHY_EMBED_SHELL (shell), tmp); + g_free (tmp); +} + +static void +mozilla_set_default_prefs (void) +{ + mozilla_prefs_set_boolean ("mozilla.widget.raise-on-setfocus", + FALSE); + mozilla_prefs_set_boolean ("browser.display.use_system_colors", + FALSE); + + /* set default search engine */ + mozilla_prefs_set_string ("keyword.URL",_("http://www.google.com/search?q=")); + mozilla_prefs_set_boolean ("keyword.enabled", TRUE); + mozilla_prefs_set_boolean ("security.checkloaduri", FALSE); + + /* while we have no UI */ + mozilla_prefs_set_boolean ("wallet.captureForms", FALSE); + + /* deactivate mailcap and mime.types support */ + mozilla_prefs_set_string ("helpers.global_mime_types_file", ""); + mozilla_prefs_set_string ("helpers.global_mailcap_file", ""); + mozilla_prefs_set_string ("helpers.private_mime_types_file", ""); + mozilla_prefs_set_string ("helpers.private_mailcap_file", ""); + + /* dont allow xpi installs from epiphany, there are crashes */ + mozilla_prefs_set_boolean ("xpinstall.enabled", FALSE); + + /* disable sucky XUL ftp view, have nice ns4-like html page instead */ + mozilla_prefs_set_boolean ("network.dir.generate_html", TRUE); + + /* set the right accept encoding flags */ + mozilla_prefs_set_string ("network.http.accept-encoding" , + "gzip, deflate, compress;q=0.9"); + + mozilla_prefs_save (); +} + +static void +mozilla_init_single (MozillaEmbedShell *mes) +{ + GtkMozEmbedSingle *single; + + /* get single */ + single = gtk_moz_embed_single_get (); + if (single == NULL) + { + g_warning ("Failed to get singleton embed object!\n"); + } + + /* allow creation of orphan windows */ + g_signal_connect (G_OBJECT (single), "new_window_orphan", + GTK_SIGNAL_FUNC (mozilla_embed_shell_new_window_orphan_cb), + mes); +} + +static void +mozilla_init_home (void) +{ + char *mozilla_five_home; + mozilla_five_home = g_strdup (g_getenv ("MOZILLA_FIVE_HOME")); + gtk_moz_embed_set_comp_path (mozilla_five_home); + g_free (mozilla_five_home); +} + +void +mozilla_init_profile (void) +{ + char *profile_path; + profile_path = g_build_filename (ephy_dot_dir (), + MOZILLA_PROFILE_DIR, + NULL); + gtk_moz_embed_set_profile_path (profile_path, MOZILLA_PROFILE_NAME); + g_free (profile_path); +} + +static gboolean +is_new_build (void) +{ + gboolean new_build = FALSE; + char *mozprefs, *build_test; + + mozprefs = g_build_filename (ephy_dot_dir (), + MOZILLA_PROFILE_DIR, + MOZILLA_PROFILE_NAME, + MOZILLA_PROFILE_FILE, + NULL); + + /* no mozilla prefs ? or new epiphany build */ + build_test = eel_gconf_get_string ("/apps/epiphany/gconf_test"); + if (!g_file_test(mozprefs, G_FILE_TEST_EXISTS) || + build_test == NULL || + strncmp (build_test, __TIME__, 8) != 0) + { + new_build = TRUE; + eel_gconf_set_string ("/apps/epiphany/gconf_test", __TIME__); + } + + g_free (mozprefs); + g_free (build_test); + + return new_build; +} + +static void +mozilla_init_prefs (void) +{ + mozilla_set_default_prefs (); + mozilla_notifiers_set_defaults (); +} + +static gboolean +have_gnome_url_handler (const gchar *protocol) +{ + gchar *key, *cmd; + gboolean rv; + + key = g_strdup_printf ("/desktop/gnome/url-handlers/%s/command", + protocol); + cmd = eel_gconf_get_string (key); + g_free (key); + + rv = (cmd != NULL); + g_free (cmd); + + if (!rv) return rv; + + key = g_strdup_printf ("/desktop/gnome/url-handlers/%s/enabled", + protocol); + rv = eel_gconf_get_boolean (key); + g_free (key); + + return rv; +} + +static void +mozilla_register_external_protocols (void) +{ + /* FIXME register only when needed */ + if (have_gnome_url_handler ("ftp")) + { + mozilla_register_FtpProtocolHandler (); + } + else + { + mozilla_unregister_FtpProtocolHandler (); + } + + mozilla_register_MailtoProtocolHandler (); +} + +static void +mozilla_embed_shell_init (MozillaEmbedShell *mes) +{ + gboolean new_build; + + mes->priv = g_new0 (MozillaEmbedShellPrivate, 1); + + mes->priv->charsets_hash = NULL; + mes->priv->sorted_charsets_titles = NULL; + + new_build = is_new_build (); + + /* Pre initialization */ + mozilla_notifiers_init (mes); + mozilla_init_home (); + mozilla_init_profile (); + + /* Fire up the best */ + gtk_moz_embed_push_startup (); + + /* Post initialization */ + if (new_build) + { + mozilla_init_prefs (); + } + + mozilla_load_proxy_prefs (mes); + + mozilla_init_single (mes); + + mozilla_register_components (); + + mozilla_register_external_protocols (); + + /* FIXME alert if fails */ +} + +static void +mozilla_embed_shell_new_window_orphan_cb (GtkMozEmbedSingle *embed, + GtkMozEmbed **retval, + guint chrome_mask, + EphyEmbedShell *shell) +{ + /* FIXME conversion duped in mozilla_embed */ + EphyEmbed *new_embed; + int i; + EmbedChromeMask mask = EMBED_CHROME_OPENASPOPUP; + + struct + { + guint chromemask; + EmbedChromeMask embed_mask; + } + conversion_map [] = + { + { GTK_MOZ_EMBED_FLAG_DEFAULTCHROME, EMBED_CHROME_DEFAULT }, + { GTK_MOZ_EMBED_FLAG_MENUBARON, EMBED_CHROME_MENUBARON }, + { GTK_MOZ_EMBED_FLAG_TOOLBARON, EMBED_CHROME_TOOLBARON }, + { GTK_MOZ_EMBED_FLAG_STATUSBARON, EMBED_CHROME_STATUSBARON }, + { GTK_MOZ_EMBED_FLAG_WINDOWRAISED, EMBED_CHROME_WINDOWRAISED }, + { GTK_MOZ_EMBED_FLAG_WINDOWLOWERED, EMBED_CHROME_WINDOWLOWERED }, + { GTK_MOZ_EMBED_FLAG_CENTERSCREEN, EMBED_CHROME_CENTERSCREEN }, + { GTK_MOZ_EMBED_FLAG_OPENASDIALOG, EMBED_CHROME_OPENASDIALOG }, + { GTK_MOZ_EMBED_FLAG_OPENASCHROME, EMBED_CHROME_OPENASCHROME }, + { 0, EMBED_CHROME_NONE } + }; + + for (i = 0; conversion_map[i].chromemask != 0; i++) + { + if (chrome_mask & conversion_map[i].chromemask) + { + mask = (EmbedChromeMask) (mask | conversion_map[i].embed_mask); + } + } + + g_signal_emit_by_name (shell, "new_window_orphan", &new_embed, mask); + + g_assert (new_embed != NULL); + + *retval = GTK_MOZ_EMBED(EPHY_EMBED(new_embed)); +} + +static void +mozilla_embed_shell_finalize (GObject *object) +{ + MozillaEmbedShell *mes; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_MOZILLA_EMBED_SHELL (object)); + + mes = MOZILLA_EMBED_SHELL (object); + + g_return_if_fail (mes->priv != NULL); + + mozilla_notifiers_free (); + + mozilla_prefs_save (); + + gtk_moz_embed_pop_startup (); + + g_free (mes->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +impl_get_capabilities (EphyEmbedShell *shell, + EmbedShellCapabilities *caps) +{ + EmbedShellCapabilities mycaps; + + mycaps = (EmbedShellCapabilities) + (CACHE_CLEAR_CAP | + OFFLINE_CAP | + PROXY_AUTOCONF_CAP | + JAVA_CONSOLE_CAP | + JS_CONSOLE_CAP | + CHARSETS_CAP | + PERMISSIONS_CAP | + COOKIES_CAP | + PASSWORDS_CAP); + + *caps = mycaps; +} + +static gresult +impl_clear_cache (EphyEmbedShell *shell, + CacheType type) +{ + nsresult rv; + + nsCOMPtr<nsICacheService> CacheService = + do_GetService (NS_CACHESERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) return G_FAILED; + + CacheService->EvictEntries((guint)type); + + return G_OK; +} + +static gresult +impl_set_offline_mode (EphyEmbedShell *shell, + gboolean offline) +{ + nsresult rv; + + nsCOMPtr<nsIIOService> io = do_GetService(NS_IOSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) + return G_FAILED; + + rv = io->SetOffline(offline); + if (NS_SUCCEEDED(rv)) return G_FAILED; + + return G_OK; +} + +static gresult +impl_load_proxy_autoconf (EphyEmbedShell *shell, + const char* url) +{ + nsresult rv; + + nsCOMPtr<nsIProtocolProxyService> pps = + do_GetService ("@mozilla.org/network/protocol-proxy-service;1", + &rv); + if (NS_FAILED(rv) || !pps) return G_FAILED; + + rv = pps->ConfigureFromPAC (url); + if (NS_FAILED(rv)) return G_FAILED; + + return G_OK; +} + +static gresult +fill_charsets_lists (MozillaEmbedShellPrivate *priv) +{ + nsresult rv; + char *tmp; + PRUint32 cscount; + PRUint32 translated_cscount = get_translated_cscount (); + char *charset_str, *charset_title_str; + + nsCOMPtr<nsIAtom> docCharsetAtom; + nsCOMPtr<nsICharsetConverterManager2> ccm2 = + do_GetService (NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); + if (!NS_SUCCEEDED(rv)) return G_FAILED; + + nsCOMPtr <nsISupportsArray> cs_list; + rv = ccm2->GetDecoderList (getter_AddRefs(cs_list)); + if (!NS_SUCCEEDED(rv)) return G_FAILED; + + rv = cs_list->Count(&cscount); + priv->charsets_hash = g_hash_table_new (g_str_hash, g_str_equal); + for (PRUint32 i = 0; i < cscount; i++) + { + nsCOMPtr<nsISupports> cssupports = + (dont_AddRef)(cs_list->ElementAt(i)); + nsCOMPtr<nsIAtom> csatom ( do_QueryInterface(cssupports) ); + nsAutoString charset_ns, charset_title_ns; + + /* charset name */ + rv = csatom->ToString(charset_ns); + tmp = ToNewCString (charset_ns); + if (tmp == NULL || strlen (tmp) == 0) + { + continue; + } + charset_str = g_strdup (tmp); + nsMemory::Free (tmp); + tmp = nsnull; + + /* charset readable title */ + rv = ccm2->GetCharsetTitle2(csatom, &charset_title_ns); + tmp = ToNewCString (charset_title_ns); + if (tmp == NULL || + strlen (tmp) == 0) + { + if (tmp) nsMemory::Free (tmp); + charset_title_str = g_strdup (charset_str); + } + else + { + charset_title_str = g_strdup (tmp); + nsMemory::Free (tmp); + tmp = nsnull; + } + + for (PRUint32 j = 0; j < translated_cscount; j++) + { + if (g_ascii_strcasecmp ( + charset_str, + charset_trans_array[j].charset_name) == 0) + { + g_free (charset_title_str); + charset_title_str = (char *) + _(charset_trans_array[j].charset_title); + break; + } + } + + /* fill the hash and the sorted list */ + g_hash_table_insert (priv->charsets_hash, charset_title_str, charset_str); + priv->sorted_charsets_titles = + g_list_insert_sorted (priv->sorted_charsets_titles, + (gpointer)charset_title_str, + (GCompareFunc)g_ascii_strcasecmp); + } + + return G_OK; +} + +static void +ensure_charsets_tables (MozillaEmbedShell *shell) +{ + if (!shell->priv->charsets_hash) + { + fill_charsets_lists (shell->priv); + } +} + +static gresult +impl_get_charset_titles (EphyEmbedShell *shell, + const char *group, + GList **charsets) +{ + MozillaEmbedShell *mshell = MOZILLA_EMBED_SHELL(shell); + int count = get_translated_cscount (); + GList *l = NULL; + int j; + + ensure_charsets_tables (mshell); + g_return_val_if_fail (mshell->priv->charsets_hash != NULL, G_FAILED); + + for (j = 0; j < count; j++) + { + if (group == NULL || + strcmp (group, lgroups[charset_trans_array[j].lgroup]) == 0) + { + CharsetInfo *info; + info = g_new0 (CharsetInfo, 1); + info->name = charset_trans_array[j].charset_name; + info->title = charset_trans_array[j].charset_title; + l = g_list_append (l, info); + + /* FIXME check that the encoding exists in mozilla before + * adding it */ + } + } + + *charsets = l; + + return G_OK; +} + +static gresult +impl_get_charset_groups (EphyEmbedShell *shell, + GList **groups) +{ + GList *l = NULL; + int i; + + for (i = 0; lgroups[i] != NULL; i++) + { + l = g_list_append (l, (gpointer)lgroups[i]); + } + + *groups = l; + + return G_OK; +} + +static gresult +impl_get_font_list (EphyEmbedShell *shell, + const char *langGroup, + const char *fontType, + GList **fontList, + char **default_font) +{ + nsresult rv; + + nsCOMPtr<nsIFontList> mozFontList; + mozFontList = do_CreateInstance("@mozilla.org/gfx/fontlist;1", &rv); + if(NS_FAILED(rv)) return G_FAILED; + + nsCOMPtr<nsISimpleEnumerator> fontEnum; + mozFontList->AvailableFonts(NS_ConvertUTF8toUCS2(langGroup).get(), + NS_ConvertUTF8toUCS2(fontType).get(), + getter_AddRefs(fontEnum)); + if(NS_FAILED(rv)) return G_FAILED; + + GList *l = NULL; + PRBool enumResult; + for(fontEnum->HasMoreElements(&enumResult) ; + enumResult == PR_TRUE; + fontEnum->HasMoreElements(&enumResult)) + { + nsCOMPtr<nsISupportsString> fontName; + fontEnum->GetNext(getter_AddRefs(fontName)); + if(NS_FAILED(rv)) return G_FAILED; + + nsString fontString; + fontName->GetData(fontString); + + char *gFontString; + gFontString = g_strdup(NS_ConvertUCS2toUTF8(fontString).get()); + l = g_list_append(l, gFontString); + } + *fontList = l; + + if (default_font != NULL) + { + char key [255]; + + sprintf (key, "font.name.%s.%s", fontType, langGroup); + + *default_font = mozilla_prefs_get_string (key); + } + + return G_OK; +} + +static gresult +impl_set_permission (EphyEmbedShell *shell, + const char *url, + PermissionType type, + gboolean allow) +{ + nsresult rv; + nsCOMPtr<nsIPermissionManager> permissionManager = + do_CreateInstance (NS_PERMISSIONMANAGER_CONTRACTID); + + rv = permissionManager->Add (nsDependentCString(url), + allow ? PR_TRUE : PR_FALSE, type); + if (NS_FAILED(rv)) return G_FAILED; + + return G_OK; +} + +static gresult +impl_list_permissions (EphyEmbedShell *shell, + PermissionType type, + GList **permissions) +{ + nsresult result; + + *permissions = NULL; + + nsCOMPtr<nsIPermissionManager> permissionManager = + do_CreateInstance (NS_PERMISSIONMANAGER_CONTRACTID); + nsCOMPtr<nsISimpleEnumerator> permissionEnumerator; + result = permissionManager->GetEnumerator (getter_AddRefs(permissionEnumerator)); + if (NS_FAILED(result)) return G_FAILED; + + PRBool enumResult; + for (permissionEnumerator->HasMoreElements(&enumResult) ; + enumResult == PR_TRUE ; + permissionEnumerator->HasMoreElements(&enumResult)) + { + nsCOMPtr<nsIPermission> nsPermission; + result = permissionEnumerator->GetNext (getter_AddRefs(nsPermission)); + if (NS_FAILED(result)) return G_FAILED; + + PRInt32 cType; + nsPermission->GetType (&cType); + if (cType == type) + { + PermissionInfo *b = g_new0 (PermissionInfo, 1); + gchar *tmp = NULL; + + nsPermission->GetHost (&tmp); + b->domain = g_strdup (tmp); + nsMemory::Free (tmp); + + PRBool cap; + nsPermission->GetCapability (&cap); + if (cap == PR_TRUE) + b->type = g_strdup (_("Allowed")); + else + b->type = g_strdup (_("Blocked")); + + *permissions = g_list_prepend (*permissions, b); + } + } + + *permissions = g_list_reverse (*permissions); + + return G_OK; +} + +static gresult +impl_remove_permissions (EphyEmbedShell *shell, + PermissionType type, + GList *permissions) +{ + nsresult result; + nsCOMPtr<nsIPermissionManager> permissionManager = + do_CreateInstance (NS_PERMISSIONMANAGER_CONTRACTID); + + for (GList *permissions = g_list_first(permissions); permissions != NULL; + permissions = g_list_next(permissions)) + { + PermissionInfo *b = (PermissionInfo *)permissions->data; + result = permissionManager->Remove (nsDependentCString(b->domain), + type); + if (NS_FAILED(result)) return G_FAILED; + }; + + return G_OK; +} + +static gresult +impl_list_cookies (EphyEmbedShell *shell, + GList **cookies) +{ + nsresult result; + + nsCOMPtr<nsICookieManager> cookieManager = + do_CreateInstance (NS_COOKIEMANAGER_CONTRACTID); + nsCOMPtr<nsISimpleEnumerator> cookieEnumerator; + result = + cookieManager->GetEnumerator (getter_AddRefs(cookieEnumerator)); + if (NS_FAILED(result)) return G_FAILED; + + PRBool enumResult; + for (cookieEnumerator->HasMoreElements(&enumResult) ; + enumResult == PR_TRUE ; + cookieEnumerator->HasMoreElements(&enumResult)) + { + CookieInfo *c; + + nsCOMPtr<nsICookie> nsCookie; + result = cookieEnumerator->GetNext (getter_AddRefs(nsCookie)); + if (NS_FAILED(result)) return G_FAILED; + + c = g_new0 (CookieInfo, 1); + + nsCAutoString transfer; + + nsCookie->GetHost (transfer); + c->base.domain = g_strdup (transfer.get()); + nsCookie->GetName (transfer); + c->name = g_strdup (transfer.get()); + nsCookie->GetValue (transfer); + c->value = g_strdup (transfer.get()); + nsCookie->GetPath (transfer); + c->path = g_strdup (transfer.get()); + + PRBool isSecure; + nsCookie->GetIsSecure (&isSecure); + if (isSecure == PR_TRUE) + c->secure = g_strdup (_("Yes")); + else + c->secure = g_strdup (_("No")); + + PRUint64 dateTime; + nsCookie->GetExpires (&dateTime); + if(dateTime == 0) + c->expire = g_strdup (_("End of current session")); + else + c->expire = g_strdup_printf ("%s",ctime((time_t*)&dateTime)); + + *cookies = g_list_prepend (*cookies, c); + } + + *cookies = g_list_reverse (*cookies); + + return G_OK; +} + +static gresult +impl_remove_cookies (EphyEmbedShell *shell, + GList *cookies) +{ + nsresult result; + GList *cl; + nsCOMPtr<nsICookieManager> cookieManager = + do_CreateInstance (NS_COOKIEMANAGER_CONTRACTID); + + for (cl = g_list_first(cookies) ; cl != NULL ; + cl = g_list_next (cl)) + { + CookieInfo *c = (CookieInfo *)cl->data; + + result = cookieManager->Remove (NS_LITERAL_CSTRING(c->base.domain), + NS_LITERAL_CSTRING(c->name), + NS_LITERAL_CSTRING(c->path), + PR_FALSE); + if (NS_FAILED(result)) return G_FAILED; + }; + + return G_OK; +} + +static gresult +impl_list_passwords (EphyEmbedShell *shell, + PasswordType type, + GList **passwords) +{ + nsresult result = NS_ERROR_FAILURE; + + nsCOMPtr<nsIPasswordManager> passwordManager = + do_CreateInstance (NS_PASSWORDMANAGER_CONTRACTID); + nsCOMPtr<nsISimpleEnumerator> passwordEnumerator; + if (type == PASSWORD_PASSWORD) + result = passwordManager->GetEnumerator + (getter_AddRefs(passwordEnumerator)); + else if (type == PASSWORD_REJECT) + result = passwordManager->GetRejectEnumerator + (getter_AddRefs(passwordEnumerator)); + if (NS_FAILED(result)) return G_FAILED; + + PRBool enumResult; + for (passwordEnumerator->HasMoreElements(&enumResult) ; + enumResult == PR_TRUE ; + passwordEnumerator->HasMoreElements(&enumResult)) + { + nsCOMPtr<nsIPassword> nsPassword; + result = passwordEnumerator->GetNext + (getter_AddRefs(nsPassword)); + if (NS_FAILED(result)) return G_FAILED; + + PasswordInfo *p = g_new0 (PasswordInfo, 1); + + nsCAutoString transfer; + nsPassword->GetHost (transfer); + p->host = g_strdup (transfer.get()); + + if (type == PASSWORD_PASSWORD) + { + nsAutoString unicodeName; + nsPassword->GetUser (unicodeName); + p->username = g_strdup(NS_ConvertUCS2toUTF8(unicodeName).get()); + } + + *passwords = g_list_prepend (*passwords, p); + } + + *passwords = g_list_reverse (*passwords); + + return G_OK; +} + +static gresult +impl_remove_passwords (EphyEmbedShell *shell, + GList *passwords, + PasswordType type) +{ + nsresult result = NS_ERROR_FAILURE; + nsCOMPtr<nsIPasswordManager> passwordManager = + do_CreateInstance (NS_PASSWORDMANAGER_CONTRACTID); + + for (GList *l = g_list_first(passwords) ; l !=NULL ; + l = g_list_next(l)) + { + PasswordInfo *p = (PasswordInfo *)l->data; + if (type == PASSWORD_PASSWORD) + { + result = passwordManager->RemoveUser (NS_LITERAL_CSTRING(p->host), + NS_ConvertUTF8toUCS2(nsDependentCString(p->username))); + } + else if (type == PASSWORD_REJECT) + { + result = passwordManager->RemoveReject + (nsDependentCString(p->host)); + }; + + if (NS_FAILED(result)) return G_FAILED; + }; + + return G_OK; +} + +static gresult +impl_show_file_picker (EphyEmbedShell *shell, + GtkWidget *parentWidget, + const char *title, + const char *directory, + const char *file, + FilePickerMode mode, + char **ret_fullpath, + gboolean *ret_save_content, + FileFormat *file_formats, + int *ret_file_format) +{ + PRBool showContentCheck; + gchar *expanded_directory; + + if (ret_save_content == NULL) + showContentCheck = PR_FALSE; + else + showContentCheck = PR_TRUE; + + GFilePicker *filePicker = new GFilePicker (showContentCheck, + file_formats); + + /* FIXME sane path: expand tilde ... */ + expanded_directory = g_strdup (directory); + + /* make sure the directory exists, and use the home directory + * otherwise */ + if (!expanded_directory || + !g_file_test (expanded_directory, G_FILE_TEST_IS_DIR)) + { + if (expanded_directory) g_free (expanded_directory); + expanded_directory = g_strdup (g_get_home_dir()); + } + + nsCOMPtr<nsILocalFile> dir = + do_CreateInstance (NS_LOCAL_FILE_CONTRACTID); + dir->InitWithPath (NS_ConvertUTF8toUCS2(expanded_directory)); + g_free (expanded_directory); + + filePicker->InitWithGtkWidget (parentWidget, title, mode); + filePicker->SetDefaultString (NS_ConvertUTF8toUCS2(file).get()); + filePicker->SetDisplayDirectory (dir); + + PRInt16 retval; + filePicker->Show (&retval); + + if (ret_save_content != NULL) + { + if (retval == GFilePicker::returnOKSaveContent) + *ret_save_content = TRUE; + else + *ret_save_content = FALSE; + } + if (ret_file_format != NULL) + { + *ret_file_format = filePicker->mSelectedFileFormat; + } + + if (retval == nsIFilePicker::returnCancel) + { + delete filePicker; + return G_FAILED; + } + else + { + if (*ret_fullpath) + g_free (*ret_fullpath); + nsCOMPtr<nsILocalFile> file; + filePicker->GetFile (getter_AddRefs(file)); + nsAutoString tempFullPathStr; + file->GetPath (tempFullPathStr); + *ret_fullpath = g_strdup (NS_ConvertUCS2toUTF8(tempFullPathStr).get()); + delete filePicker; + return G_OK; + } +} diff --git a/embed/mozilla/mozilla-embed-shell.h b/embed/mozilla/mozilla-embed-shell.h new file mode 100644 index 000000000..daedb2948 --- /dev/null +++ b/embed/mozilla/mozilla-embed-shell.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef MOZILLA_EMBED_SHELL_H +#define MOZILLA_EMBED_SHELL_H + +#include "glib.h" +#include "ephy-embed-shell.h" +#include <glib-object.h> + +G_BEGIN_DECLS + +#define MOZILLA_EMBED_SHELL_TYPE (mozilla_embed_shell_get_type ()) +#define MOZILLA_EMBED_SHELL(obj) (GTK_CHECK_CAST ((obj), MOZILLA_EMBED_SHELL_TYPE, MozillaEmbedShell)) +#define MOZILLA_EMBED_SHELL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), MOZILLA_EMBED_SHELL_TYPE, MozillaEmbedShellClass)) +#define IS_MOZILLA_EMBED_SHELL(obj) (GTK_CHECK_TYPE ((obj), MOZILLA_EMBED_SHELL_TYPE)) +#define IS_MOZILLA_EMBED_SHELL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), MOZILLA_EMBED_SHELL)) +#define MOZILLA_EMBED_SHELL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOZILLA_EMBED_SHELL_TYPE, MozillaEmbedShellClass)) + +typedef struct MozillaEmbedShell MozillaEmbedShell; +typedef struct MozillaEmbedShellPrivate MozillaEmbedShellPrivate; + +extern GObject *mozilla_js_console; + +struct MozillaEmbedShell +{ + EphyEmbedShell parent; + MozillaEmbedShellPrivate *priv; +}; + +struct MozillaEmbedShellClass +{ + EphyEmbedShellClass parent_class; +}; + +GType mozilla_embed_shell_get_type (void); + +G_END_DECLS + +#endif diff --git a/embed/mozilla/mozilla-embed.cpp b/embed/mozilla/mozilla-embed.cpp new file mode 100644 index 000000000..d3d2277b0 --- /dev/null +++ b/embed/mozilla/mozilla-embed.cpp @@ -0,0 +1,1585 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "gtkmozembed.h" +#include "gtkmozembed_internal.h" +#include "ephy-string.h" +#include "ephy-embed.h" +#include "mozilla-embed.h" +#include "MozillaPrivate.h" +#include "EphyWrapper.h" +#include "EventContext.h" +#include "nsIWindowWatcher.h" + +#include <nsIURI.h> +#include <nsIURL.h> +#include <nsNetUtil.h> +#include <nsString.h> +#include <nsIRequest.h> +#include <nsIWebProgressListener.h> +#include <nsITransportSecurityInfo.h> +#include <nsIPrintOptions.h> +#include <nsGfxCIID.h> + +#include <math.h> + +static void +mozilla_embed_class_init (MozillaEmbedClass *klass); +static void +mozilla_embed_init (MozillaEmbed *gs); +static void +mozilla_embed_finalize (GObject *object); +static void +mozilla_embed_destroy (GtkObject *object); +static void +ephy_embed_init (EphyEmbedClass *embed_class); + +static void +impl_get_capabilities (EphyEmbed *embed, + EmbedCapabilities *caps); +static gresult +impl_load_url (EphyEmbed *embed, + const char *url); +static gresult +impl_stop_load (EphyEmbed *embed); +static gresult +impl_can_go_back (EphyEmbed *embed); +static gresult +impl_can_go_forward (EphyEmbed *embed); +static gresult +impl_can_go_up (EphyEmbed *embed); +static gresult +impl_get_go_up_list (EphyEmbed *embed, GSList **l); +static gresult +impl_go_back (EphyEmbed *embed); +static gresult +impl_go_forward (EphyEmbed *embed); +static gresult +impl_go_up (EphyEmbed *embed); +static gresult +impl_render_data (EphyEmbed *embed, + const char *data, + guint32 len, + const char *base_uri, + const char *mime_type); +static gresult +impl_open_stream (EphyEmbed *embed, + const char *base_uri, + const char *mime_type); +static gresult +impl_append_data (EphyEmbed *embed, + const char *data, + guint32 len); +static gresult +impl_close_stream (EphyEmbed *embed); +static gresult +impl_get_title (EphyEmbed *embed, + char **title); +static gresult +impl_get_location (EphyEmbed *embed, + gboolean toplevel, + gboolean requested, + char **location); +static gresult +impl_reload (EphyEmbed *embed, + EmbedReloadFlags flags); +static gresult +impl_copy_page (EphyEmbed *dest, + EphyEmbed *source, + EmbedDisplayType display_type); +static gresult +impl_grab_focus (EphyEmbed *embed); +static gresult +impl_get_link_tags (EphyEmbed *embed, + const char *link_type, + GList **tags); +static gresult +impl_zoom_set (EphyEmbed *embed, + int zoom, + gboolean reflow); +static gresult +impl_zoom_get (EphyEmbed *embed, + int *zoom); +static gresult +impl_selection_can_cut (EphyEmbed *embed); +static gresult +impl_selection_can_copy (EphyEmbed *embed); +static gresult +impl_can_paste (EphyEmbed *embed); +static gresult +impl_select_all (EphyEmbed *embed); +static gresult +impl_selection_cut (EphyEmbed *embed); +static gresult +impl_selection_copy (EphyEmbed *embed); +static gresult +impl_paste (EphyEmbed *embed); +static gresult +impl_shistory_count (EphyEmbed *embed, + int *count); +static gresult +impl_shistory_get_nth (EphyEmbed *embed, + int nth, + gboolean is_relative, + char **url, + char **title); +static gresult +impl_shistory_get_pos (EphyEmbed *embed, + int *pos); +static gresult +impl_shistory_go_nth (EphyEmbed *embed, + int nth); +static gboolean +impl_shistory_copy (EphyEmbed *source, + EphyEmbed *dest); +static gresult +impl_scroll (EphyEmbed *embed, + EmbedScrollDirection direction); +static gresult +impl_fine_scroll (EphyEmbed *embed, + int horiz, int vert); +static gresult +impl_get_security_level (EphyEmbed *embed, + EmbedSecurityLevel *level, + char **description); +static gresult +impl_find (EphyEmbed *embed, + EmbedFindInfo *info); + +static gresult +impl_set_charset (EphyEmbed *embed, + const char *charset); + +static gresult +impl_print (EphyEmbed *embed, + EmbedPrintInfo *info); + +static gresult +impl_print_preview_close (EphyEmbed *embed); + +static gresult +impl_print_preview_num_pages (EphyEmbed *embed, + gint *retNum); +static gresult +impl_print_preview_navigate (EphyEmbed *embed, + EmbedPrintPreviewNavType navType, + gint pageNum); + +static void +mozilla_embed_connect_signals (MozillaEmbed *membed); +static char * +mozilla_embed_get_uri_parent (const char *uri); +static void +mozilla_embed_location_changed_cb (GtkMozEmbed *embed, MozillaEmbed *membed); +static void +mozilla_embed_title_changed_cb (GtkMozEmbed *embed, MozillaEmbed *membed); +static void +mozilla_embed_net_state_all_cb (GtkMozEmbed *embed, const char *aURI, + gint state, guint status, MozillaEmbed *membed); +static void +mozilla_embed_progress_cb (GtkMozEmbed *embed, const char *aURI, + gint curprogress, gint maxprogress, MozillaEmbed *membed); +static void +mozilla_embed_link_message_cb (GtkMozEmbed *embed, MozillaEmbed *membed); +static void +mozilla_embed_js_status_cb (GtkMozEmbed *embed, MozillaEmbed *membed); +static void +mozilla_embed_visibility_cb (GtkMozEmbed *embed, gboolean visibility, MozillaEmbed *membed); +static void +mozilla_embed_destroy_brsr_cb (GtkMozEmbed *embed, MozillaEmbed *embed); +static gint +mozilla_embed_dom_mouse_click_cb (GtkMozEmbed *embed, gpointer dom_event, MozillaEmbed *membed); +static gint +mozilla_embed_dom_mouse_down_cb (GtkMozEmbed *embed, gpointer dom_event, + MozillaEmbed *membed); +static void +mozilla_embed_size_to_cb (GtkMozEmbed *embed, gint width, gint height, MozillaEmbed *membed); +static void +mozilla_embed_new_window_cb (GtkMozEmbed *embed, + GtkMozEmbed **newEmbed, + guint chromemask, MozillaEmbed *membed); +static void +mozilla_embed_security_change_cb (GtkMozEmbed *embed, + gpointer request, + guint state, MozillaEmbed *membed); +static EmbedSecurityLevel +mozilla_embed_security_level (MozillaEmbed *membed); + +/* signals to connect on each embed widget */ +static const struct +{ + char *event; + void *func; /* should be a GtkSignalFunc or similar */ +} +signal_connections[] = +{ + { "location", (void *) mozilla_embed_location_changed_cb }, + { "title", (void *) mozilla_embed_title_changed_cb }, + { "net_state_all", (void *) mozilla_embed_net_state_all_cb }, + { "progress_all", (void *) mozilla_embed_progress_cb }, + { "link_message", (void *) mozilla_embed_link_message_cb }, + { "js_status", (void *) mozilla_embed_js_status_cb }, + { "visibility", (void *) mozilla_embed_visibility_cb }, + { "destroy_browser", (void *) mozilla_embed_destroy_brsr_cb }, + { "dom_mouse_click", (void *) mozilla_embed_dom_mouse_click_cb }, + { "dom_mouse_down", (void *) mozilla_embed_dom_mouse_down_cb }, + { "size_to", (void *) mozilla_embed_size_to_cb }, + { "new_window", (void *) mozilla_embed_new_window_cb }, + { "security_change", (void *) mozilla_embed_security_change_cb }, + + /* terminator -- must be last in the list! */ + { NULL, NULL } +}; + +struct MozillaEmbedPrivate +{ + MozillaEmbedPrivate() : wrapper(NULL), security_state(-1), no_page(1) + { /* nothing */ } + + EphyWrapper *wrapper; + nsCOMPtr<nsIRequest> request; + gint security_state; + + /* HACK 1: No page loaded, 0: Loading an empty page, -1: Page loaded */ + gint no_page; +}; + +#define WINDOWWATCHER_CONTRACTID "@mozilla.org/embedcomp/window-watcher;1" + +static NS_DEFINE_CID(kPrintOptionsCID, NS_PRINTOPTIONS_CID); + +static GObjectClass *parent_class = NULL; + +GType +mozilla_embed_get_type (void) +{ + static GType mozilla_embed_type = 0; + + if (mozilla_embed_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (MozillaEmbedClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) mozilla_embed_class_init, + NULL, + NULL, /* class_data */ + sizeof (MozillaEmbed), + 0, /* n_preallocs */ + (GInstanceInitFunc) mozilla_embed_init + }; + + static const GInterfaceInfo embed_info = + { + (GInterfaceInitFunc) ephy_embed_init, /* interface_init */ + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; + + mozilla_embed_type = g_type_register_static (GTK_TYPE_MOZ_EMBED, + "MozillaEmbed", + &our_info, + (GTypeFlags)0); + g_type_add_interface_static (mozilla_embed_type, + EPHY_EMBED_TYPE, + &embed_info); + } + + return mozilla_embed_type; +} + +static void +ephy_embed_init (EphyEmbedClass *embed_class) +{ + embed_class->get_capabilities = impl_get_capabilities; + embed_class->load_url = impl_load_url; + embed_class->stop_load = impl_stop_load; + embed_class->can_go_back = impl_can_go_back; + embed_class->can_go_forward =impl_can_go_forward; + embed_class->can_go_up = impl_can_go_up; + embed_class->get_go_up_list = impl_get_go_up_list; + embed_class->go_back = impl_go_back; + embed_class->go_forward = impl_go_forward; + embed_class->go_up = impl_go_up; + embed_class->render_data = impl_render_data; + embed_class->open_stream = impl_open_stream; + embed_class->append_data = impl_append_data; + embed_class->close_stream = impl_close_stream; + embed_class->get_title = impl_get_title; + embed_class->get_location = impl_get_location; + embed_class->reload = impl_reload; + embed_class->copy_page = impl_copy_page; + embed_class->grab_focus = impl_grab_focus; + embed_class->get_link_tags = impl_get_link_tags; + embed_class->zoom_set = impl_zoom_set; + embed_class->zoom_get = impl_zoom_get; + embed_class->selection_can_cut = impl_selection_can_cut; + embed_class->selection_can_copy = impl_selection_can_copy; + embed_class->can_paste = impl_can_paste; + embed_class->selection_cut = impl_selection_cut; + embed_class->selection_copy = impl_selection_copy; + embed_class->paste = impl_paste; + embed_class->shistory_count = impl_shistory_count; + embed_class->shistory_get_nth = impl_shistory_get_nth; + embed_class->shistory_get_pos = impl_shistory_get_pos; + embed_class->shistory_go_nth = impl_shistory_go_nth; + embed_class->shistory_copy = impl_shistory_copy; + embed_class->scroll = impl_scroll; + embed_class->fine_scroll = impl_fine_scroll; + embed_class->get_security_level = impl_get_security_level; + embed_class->find = impl_find; + embed_class->set_charset = impl_set_charset; + embed_class->select_all = impl_select_all; + embed_class->print = impl_print; + embed_class->print_preview_close = impl_print_preview_close; + embed_class->print_preview_num_pages = impl_print_preview_num_pages; + embed_class->print_preview_navigate = impl_print_preview_navigate; +} + +static void +mozilla_embed_class_init (MozillaEmbedClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (klass); + parent_class = (GObjectClass *) g_type_class_peek_parent (klass); + + gtk_object_class->destroy = mozilla_embed_destroy; + object_class->finalize = mozilla_embed_finalize; +} + +static void +mozilla_embed_init (MozillaEmbed *embed) +{ + embed->priv = new MozillaEmbedPrivate; + + mozilla_embed_connect_signals (embed); +} + +gpointer +mozilla_embed_get_galeon_wrapper (MozillaEmbed *embed) +{ + g_return_val_if_fail (embed->priv->wrapper != NULL, NULL); + + return embed->priv->wrapper; +} + +static void +mozilla_embed_connect_signals (MozillaEmbed *embed) +{ + gint i; + EphyEmbed *gembed; + + gembed = EPHY_EMBED (embed); + + /* connect signals */ + for (i = 0; signal_connections[i].event != NULL; i++) + { + g_signal_connect (G_OBJECT(embed), + signal_connections[i].event, + G_CALLBACK(signal_connections[i].func), + embed); + } +} + +static void +mozilla_embed_destroy (GtkObject *object) +{ + int i; + + for (i = 0; signal_connections[i].event != NULL; i++) + { + g_signal_handlers_disconnect_by_func + (G_OBJECT(object), + (gpointer)signal_connections[i].func, + (void *)object); + } + + GTK_OBJECT_CLASS (parent_class)->destroy (object); +} + +static void +mozilla_embed_finalize (GObject *object) +{ + MozillaEmbed *embed; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_MOZILLA_EMBED (object)); + + embed = MOZILLA_EMBED (object); + + g_return_if_fail (embed->priv != NULL); + + if (embed->priv->wrapper) + { + embed->priv->wrapper->Destroy(); + delete embed->priv->wrapper; + embed->priv->wrapper = NULL; + } + + delete embed->priv; + + G_OBJECT_CLASS (parent_class)->finalize (object); + +#ifdef DEBUG_MARCO + g_print ("MozillaEmbed finalized %p\n", embed); +#endif +} + +gpointer +mozilla_embed_get_ephy_wrapper (MozillaEmbed *embed) +{ + g_return_val_if_fail (embed->priv->wrapper != NULL, NULL); + + return embed->priv->wrapper; +} + +static void +impl_get_capabilities (EphyEmbed *embed, + EmbedCapabilities *caps) +{ + EmbedCapabilities mozilla_caps; + + mozilla_caps = (EmbedCapabilities) ( + EMBED_CLIPBOARD_CAP | + EMBED_COOKIES_CAP | + EMBED_LINKS_CAP | + EMBED_ZOOM_CAP | + EMBED_PRINT_CAP | + EMBED_FIND_CAP | + EMBED_SCROLL_CAP | + EMBED_FINE_SCROLL_CAP | + EMBED_SECURITY_CAP | + EMBED_CHARSET_CAP | + EMBED_SHISTORY_CAP ); + + *caps = mozilla_caps; +} + +static gresult +impl_load_url (EphyEmbed *embed, + const char *url) +{ + gtk_moz_embed_load_url (GTK_MOZ_EMBED(embed), + url); + + return G_OK; +} + +static gresult +impl_stop_load (EphyEmbed *embed) +{ + gtk_moz_embed_stop_load (GTK_MOZ_EMBED(embed)); + + return G_OK; +} + +static gresult +impl_can_go_back (EphyEmbed *embed) +{ + if (gtk_moz_embed_can_go_back (GTK_MOZ_EMBED(embed))) + { + return G_OK; + } + else + { + return G_FAILED; + } +} + +static gresult +impl_can_go_forward (EphyEmbed *embed) +{ + if (gtk_moz_embed_can_go_forward (GTK_MOZ_EMBED(embed))) + { + return G_OK; + } + else + { + return G_FAILED; + } + +} + +static gresult +impl_can_go_up (EphyEmbed *embed) +{ + char *location; + char *s; + gresult result; + + if (ephy_embed_get_location (embed, TRUE, FALSE, &location) != G_OK) + return G_FAILED; + g_return_val_if_fail (location != NULL, G_FAILED); + if ((s = mozilla_embed_get_uri_parent (location)) != NULL) + { + g_free (s); + result = G_OK; + } + else + { + result = G_FAILED; + } + + g_free (location); + + return result; +} + +static gresult +impl_get_go_up_list (EphyEmbed *embed, GSList **l) +{ + char *location; + char *s; + + if (ephy_embed_get_location (embed, TRUE, FALSE, &location) != G_OK) + return G_FAILED; + g_return_val_if_fail (location != NULL, G_FAILED); + + *l = NULL; + s = location; + while ((s = mozilla_embed_get_uri_parent (s)) != NULL) + { + *l = g_slist_prepend (*l, s); + } + + g_free (location); + *l = g_slist_reverse (*l); + + return G_OK; +} + +static gresult +impl_go_back (EphyEmbed *embed) +{ + gtk_moz_embed_go_back (GTK_MOZ_EMBED(embed)); + + return G_OK; +} + +static gresult +impl_go_forward (EphyEmbed *embed) +{ + gtk_moz_embed_go_forward (GTK_MOZ_EMBED(embed)); + + return G_OK; +} + +static gresult +impl_go_up (EphyEmbed *embed) +{ + char *uri; + char *parent_uri; + + ephy_embed_get_location (embed, TRUE, FALSE, &uri); + g_return_val_if_fail (uri != NULL, G_FAILED); + + parent_uri = mozilla_embed_get_uri_parent (uri); + g_return_val_if_fail (parent_uri != NULL, G_FAILED); + + ephy_embed_load_url (embed, parent_uri); + + g_free (parent_uri); + + return G_OK; +} + +static char * +mozilla_embed_get_uri_parent (const char *aUri) +{ + nsresult rv; + + nsCOMPtr<nsIURI> uri; + rv = NS_NewURI (getter_AddRefs(uri), aUri); + if (NS_FAILED(rv) || !uri) return NULL; + + nsCOMPtr<nsIURL> url = do_QueryInterface(uri, &rv); + if (NS_FAILED(rv) || !url) return NULL; + + nsCAutoString dirPath; + rv = url->GetDirectory (dirPath); + if (NS_FAILED(rv) || !dirPath.Length()) return NULL; + + nsCAutoString filePath; + rv = url->GetFilePath (filePath); + if (NS_FAILED(rv) || !filePath.Length()) return NULL; + + PRInt32 pathLength = filePath.Length(); + PRInt32 trailingSlash = filePath.RFind("/"); + + if(pathLength < 2 || trailingSlash == -1) + { + return NULL; + } + + if(trailingSlash != (pathLength-1)) + { + uri->SetPath(dirPath); + } + else + { + PRInt32 nextSlash = filePath.RFind("/",PR_FALSE,trailingSlash-1); + nsCAutoString parentPath; + filePath.Left(parentPath, nextSlash); + uri->SetPath(parentPath); + } + + nsCAutoString spec; + uri->GetSpec(spec); + + return !spec.IsEmpty() ? g_strdup(spec.get()) : NULL; +} + +static gresult +impl_render_data (EphyEmbed *embed, + const char *data, + guint32 len, + const char *base_uri, + const char *mime_type) +{ + gtk_moz_embed_render_data (GTK_MOZ_EMBED(embed), + data, + len, + base_uri, + mime_type); + + return G_OK; +} + +static gresult +impl_open_stream (EphyEmbed *embed, + const char *base_uri, + const char *mime_type) +{ + gtk_moz_embed_open_stream (GTK_MOZ_EMBED(embed), + base_uri, mime_type); + + return G_OK; +} + +static gresult +impl_append_data (EphyEmbed *embed, + const char *data, + guint32 len) +{ + gtk_moz_embed_append_data (GTK_MOZ_EMBED(embed), + data, len); + + return G_OK; +} + +static gresult +impl_close_stream (EphyEmbed *embed) +{ + gtk_moz_embed_close_stream (GTK_MOZ_EMBED(embed)); + + return G_OK; +} + +static gresult +impl_get_title (EphyEmbed *embed, + char **title) +{ + nsXPIDLString uTitle; + + *getter_Copies(uTitle) = + gtk_moz_embed_get_title_unichar (GTK_MOZ_EMBED(embed)); + + *title = g_strdup (NS_ConvertUCS2toUTF8(uTitle).get()); + + return G_OK; +} + +static gresult +impl_get_location (EphyEmbed *embed, + gboolean toplevel, + gboolean requested, + char **location) +{ + char *l; + nsresult rv; + nsCAutoString url; + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + + /* if the wrapper is NULL than we have no location, + * in fact the wrapper is initialized on net start */ + if (!wrapper) + { + *location = NULL; + return G_FAILED; + } + + /* FIXME !toplevel requested not implemented */ + + if (toplevel) + { + l = gtk_moz_embed_get_location + (GTK_MOZ_EMBED(embed)); + } + else if (!toplevel) + { + rv = wrapper->GetDocumentUrl (url); + l = (NS_SUCCEEDED (rv) && !url.IsEmpty()) ? + g_strdup (url.get()) : NULL; + } + else if (requested) + { + rv = wrapper->GetRealURL (url); + l = (NS_SUCCEEDED (rv) && !url.IsEmpty()) ? + g_strdup (url.get()) : NULL; + } + + *location = l; + + return G_OK; +} + +static gresult +impl_reload (EphyEmbed *embed, + EmbedReloadFlags flags) +{ + guint32 mflags; + + mflags = GTK_MOZ_EMBED_FLAG_RELOADNORMAL; + + if ((flags & EMBED_RELOAD_BYPASSCACHE) && + (flags & EMBED_RELOAD_BYPASSPROXY)) + { + mflags = GTK_MOZ_EMBED_FLAG_RELOADBYPASSPROXYANDCACHE; + } + else if (flags & EMBED_RELOAD_BYPASSCACHE) + { + mflags = GTK_MOZ_EMBED_FLAG_RELOADBYPASSCACHE; + } + else if (flags & EMBED_RELOAD_BYPASSPROXY) + { + mflags = GTK_MOZ_EMBED_FLAG_RELOADBYPASSPROXY; + } + + gtk_moz_embed_reload (GTK_MOZ_EMBED(embed), + mflags); + + return G_OK; +} + +static gresult +impl_copy_page (EphyEmbed *dest, + EphyEmbed *source, + EmbedDisplayType display_type) +{ + EphyWrapper *dWrapper; + dWrapper = MOZILLA_EMBED(dest)->priv->wrapper; + g_return_val_if_fail (dWrapper != NULL, G_FAILED); + + EphyWrapper *sWrapper; + sWrapper = MOZILLA_EMBED(source)->priv->wrapper; + g_return_val_if_fail (sWrapper != NULL, G_FAILED); + + nsresult rv; + + nsCOMPtr<nsISupports> pageDescriptor; + rv = sWrapper->GetPageDescriptor(getter_AddRefs(pageDescriptor)); + if (!pageDescriptor || NS_FAILED(rv)) return G_FAILED; + + rv = dWrapper->LoadDocument(pageDescriptor, static_cast<PRUint32>(display_type)); + if (NS_FAILED(rv)) return G_FAILED; + + return G_OK; +} + +static gresult +impl_grab_focus (EphyEmbed *embed) +{ + gtk_widget_grab_focus (GTK_BIN (embed)->child); + + return G_OK; +} + +static gresult +impl_get_link_tags (EphyEmbed *embed, + const char *link_type, + GList **tags) +{ + return G_NOT_IMPLEMENTED; +} + +static gresult +impl_zoom_set (EphyEmbed *embed, + int zoom, + gboolean reflow) +{ + EphyWrapper *wrapper; + nsresult result; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + result = wrapper->SetZoom ((float)(zoom) / 100, reflow); + + if (NS_SUCCEEDED (result)) + { + g_signal_emit_by_name (embed, "ge_zoom_change", zoom); + } + + return NS_SUCCEEDED(result) ? G_OK : G_FAILED; +} + +static gresult +impl_zoom_get (EphyEmbed *embed, + int *zoom) +{ + float f; + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + if (!wrapper) + { + *zoom = 100; + return G_OK; + } + + nsresult result = wrapper->GetZoom (&f); + + if (NS_SUCCEEDED (result)) + { + *zoom = (int) rint (f * 100); + + return G_OK; + } + else + { + return G_FAILED; + } +} + +static gresult +impl_selection_can_cut (EphyEmbed *embed) +{ + gboolean result; + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + wrapper->CanCutSelection (&result); + + return result ? G_OK : G_FAILED; +} + +static gresult +impl_selection_can_copy (EphyEmbed *embed) +{ + gboolean result; + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + wrapper->CanCopySelection (&result); + + return result ? G_OK : G_FAILED; +} + +static gresult +impl_can_paste (EphyEmbed *embed) +{ + gboolean result; + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + wrapper->CanPaste (&result); + + return result ? G_OK : G_FAILED; +} + +static gresult +impl_select_all (EphyEmbed *embed) +{ + nsresult result; + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + result = wrapper->SelectAll (); + + return result ? G_OK : G_FAILED; +} + +static gresult +impl_selection_cut (EphyEmbed *embed) +{ + nsresult rv; + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + rv = wrapper->CutSelection (); + + return NS_SUCCEEDED(rv) ? G_OK : G_FAILED; +} + +static gresult +impl_selection_copy (EphyEmbed *embed) +{ + nsresult rv; + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + rv = wrapper->CopySelection (); + + return NS_SUCCEEDED(rv) ? G_OK : G_FAILED; +} + +static gresult +impl_paste (EphyEmbed *embed) +{ + nsresult rv; + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + rv = wrapper->Paste (); + + return NS_SUCCEEDED(rv) ? G_OK : G_FAILED; +} + +static gresult +impl_shistory_count (EphyEmbed *embed, + int *count) +{ + nsresult rv; + EphyWrapper *wrapper; + int c, index; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + rv = wrapper->GetSHInfo (&c, &index); + + *count = c; + + return NS_SUCCEEDED(rv) ? G_OK : G_FAILED; +} + +static gresult +impl_shistory_get_nth (EphyEmbed *embed, + int nth, + gboolean is_relative, + char **aUrl, + char **aTitle) +{ + nsresult rv; + nsCAutoString url; + PRUnichar *title; + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + if (is_relative) + { + int pos; + + if (ephy_embed_shistory_get_pos + (EPHY_EMBED(embed), &pos) == G_OK) + { + pos += nth; + } + else + { + return G_FAILED; + } + } + + rv = wrapper->GetSHUrlAtIndex(nth, url); + + *aUrl = (NS_SUCCEEDED (rv) && !url.IsEmpty()) ? g_strdup(url.get()) : NULL; + + rv = wrapper->GetSHTitleAtIndex(nth, &title); + + *aTitle = g_strdup (NS_ConvertUCS2toUTF8(title).get()); + + return G_OK; +} + +static gresult +impl_shistory_get_pos (EphyEmbed *embed, + int *pos) +{ + nsresult rv; + EphyWrapper *wrapper; + int count, index; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + rv = wrapper->GetSHInfo (&count, &index); + + *pos = index; + + return NS_SUCCEEDED(rv) ? G_OK : G_FAILED; +} + +static gresult +impl_shistory_go_nth (EphyEmbed *embed, + int nth) +{ + nsresult rv; + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + rv = wrapper->GoToHistoryIndex (nth); + + return NS_SUCCEEDED(rv) ? G_OK : G_FAILED; +} + +static gboolean +impl_shistory_copy (EphyEmbed *source, + EphyEmbed *dest) +{ + nsresult rv; + EphyWrapper *s_wrapper; + EphyWrapper *d_wrapper; + + s_wrapper = MOZILLA_EMBED(source)->priv->wrapper; + g_return_val_if_fail (s_wrapper != NULL, G_FAILED); + + d_wrapper = MOZILLA_EMBED(dest)->priv->wrapper; + g_return_val_if_fail (d_wrapper != NULL, G_FAILED); + + rv = s_wrapper->CopyHistoryTo (d_wrapper); + + return NS_SUCCEEDED(rv) ? G_OK : G_FAILED; +} + +static gresult +impl_scroll (EphyEmbed *embed, + EmbedScrollDirection direction) +{ + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + switch (direction) + { + case EMBED_SCROLL_UP: + wrapper->ScrollUp (); + break; + case EMBED_SCROLL_DOWN: + wrapper->ScrollDown (); + break; + case EMBED_SCROLL_LEFT: + wrapper->ScrollLeft (); + break; + case EMBED_SCROLL_RIGHT: + wrapper->ScrollRight (); + break; + } + + return G_OK; +} + +static gresult +impl_fine_scroll (EphyEmbed *embed, int horiz, int vert) +{ + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + wrapper->FineScroll (horiz, vert); + + return G_OK; +} + +static gresult +impl_get_security_level (EphyEmbed *embed, + EmbedSecurityLevel *level, + char **description) +{ + nsresult result; + + nsCOMPtr<nsIChannel> channel; + channel = do_QueryInterface (MOZILLA_EMBED(embed)->priv->request, + &result); + if (NS_FAILED (result)) return G_FAILED; + + nsCOMPtr<nsISupports> info; + result = channel->GetSecurityInfo(getter_AddRefs(info)); + if (NS_FAILED (result)) return G_FAILED; + + *description = NULL; + if (info) + { + nsCOMPtr<nsITransportSecurityInfo> secInfo(do_QueryInterface(info)); + if (!secInfo) return G_FAILED; + + nsXPIDLString tooltip; + result = secInfo->GetShortSecurityDescription(getter_Copies(tooltip)); + if (NS_FAILED (result)) return G_FAILED; + + if (tooltip) + { + const nsString &string = nsString(tooltip); + char *tmp; + tmp = ToNewCString (string); + + *description = g_strdup (tmp); + + nsMemory::Free (tmp); + } + } + + *level = mozilla_embed_security_level (MOZILLA_EMBED (embed)); + return G_OK; +} + +static gresult +impl_print (EphyEmbed *embed, + EmbedPrintInfo *info) +{ + nsresult result = NS_OK; + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + nsCOMPtr<nsIPrintSettings> options; + result = wrapper->GetPrintSettings(getter_AddRefs(options)); + g_assert (NS_SUCCEEDED (result)); + + MozillaCollatePrintSettings(info, options); + + options->SetPrintSilent (PR_TRUE); + + result = wrapper->Print(options, info->preview); + + return NS_SUCCEEDED (result) ? G_OK : G_FAILED; +} + +static gresult +impl_print_preview_close (EphyEmbed *embed) +{ + nsresult result = NS_OK; + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + result = wrapper->PrintPreviewClose(); + return NS_SUCCEEDED(result) ? G_OK : G_FAILED; +} + +static gresult +impl_print_preview_num_pages (EphyEmbed *embed, + gint *retNum) +{ + nsresult result = NS_OK; + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + result = wrapper->PrintPreviewNumPages(retNum); + return NS_SUCCEEDED(result) ? G_OK : G_FAILED; +} + +static gresult +impl_print_preview_navigate (EphyEmbed *embed, + EmbedPrintPreviewNavType navType, + gint pageNum) +{ + nsresult result = NS_OK; + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + result = wrapper->PrintPreviewNavigate(navType, pageNum); + return NS_SUCCEEDED(result) ? G_OK : G_FAILED; +} + +static gresult +impl_find (EphyEmbed *embed, + EmbedFindInfo *info) +{ + nsresult result = NS_OK; + EphyWrapper *wrapper; + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + PRBool didFind; + + result = wrapper->Find ((NS_ConvertUTF8toUCS2(info->search_string)).get(), + info->interactive, + info->match_case, + info->backwards, info->wrap, + info->entire_word, info->search_frames, + &didFind); + + return didFind ? G_OK : G_FAILED; +} + +static gresult +impl_set_charset (EphyEmbed *embed, + const char *charset) +{ + nsresult result = NS_OK; + EphyWrapper *wrapper; + char *cset; + + cset = g_strdup (charset); + + wrapper = MOZILLA_EMBED(embed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + wrapper->ForceCharacterSet (cset); + + g_free (cset); + + return NS_SUCCEEDED(result) ? G_OK : G_FAILED; +} + +static void +mozilla_embed_location_changed_cb (GtkMozEmbed *embed, + MozillaEmbed *membed) +{ + /* Do not emit signal if we are loading the + * fallback about:blank. We dont want the user + * to know about it. */ + if (membed->priv->no_page != 0) + { + g_signal_emit_by_name (membed, "ge_location"); + } + + membed->priv->no_page = -1; +} + +static void +mozilla_embed_title_changed_cb (GtkMozEmbed *embed, + MozillaEmbed *membed) +{ + g_return_if_fail (IS_MOZILLA_EMBED (membed)); + g_return_if_fail (GTK_IS_WIDGET (embed)); + g_signal_emit_by_name (membed, "ge_title"); +} + +static void +mozilla_embed_net_state_all_cb (GtkMozEmbed *embed, const char *aURI, + gint state, guint status, + MozillaEmbed *membed) +{ + EmbedState estate = EMBED_STATE_UNKNOWN; + int i; + + struct + { + guint state; + EmbedState embed_state; + } + conversion_map [] = + { + { GTK_MOZ_EMBED_FLAG_START, EMBED_STATE_START }, + { GTK_MOZ_EMBED_FLAG_STOP, EMBED_STATE_STOP }, + { GTK_MOZ_EMBED_FLAG_REDIRECTING, EMBED_STATE_REDIRECTING }, + { GTK_MOZ_EMBED_FLAG_TRANSFERRING, EMBED_STATE_TRANSFERRING }, + { GTK_MOZ_EMBED_FLAG_NEGOTIATING, EMBED_STATE_NEGOTIATING }, + { GTK_MOZ_EMBED_FLAG_IS_REQUEST, EMBED_STATE_IS_REQUEST }, + { GTK_MOZ_EMBED_FLAG_IS_DOCUMENT, EMBED_STATE_IS_DOCUMENT }, + { GTK_MOZ_EMBED_FLAG_IS_NETWORK, EMBED_STATE_IS_NETWORK }, + { 0, EMBED_STATE_UNKNOWN } + }; + + /* No page loaded, default to about:blank */ + if (membed->priv->no_page > 0 && + (state & GTK_MOZ_EMBED_FLAG_STOP) && + (state & GTK_MOZ_EMBED_FLAG_IS_DOCUMENT)) + { + ephy_embed_load_url (EPHY_EMBED(membed), "about:blank"); + membed->priv->no_page = 0; + } + + if (!membed->priv->wrapper) + { + membed->priv->wrapper = new EphyWrapper (); + + nsresult result; + result = membed->priv->wrapper->Init (GTK_MOZ_EMBED(embed)); + if (NS_FAILED(result)) + { + g_warning ("Wrapper initialization failed"); + } + } + + for (i = 0; conversion_map[i].state != 0; i++) + { + if (state & conversion_map[i].state) + { + estate = (EmbedState) (estate | conversion_map[i].embed_state); + } + } + + g_signal_emit_by_name (membed, "ge_net_state", aURI, estate); +} + +static void +mozilla_embed_progress_cb (GtkMozEmbed *embed, const char *aURI, + gint curprogress, gint maxprogress, + MozillaEmbed *membed) +{ + g_signal_emit_by_name (membed, "ge_progress", aURI, + curprogress, maxprogress); +} + +static void +mozilla_embed_link_message_cb (GtkMozEmbed *embed, + MozillaEmbed *membed) +{ + nsXPIDLString message; + + *getter_Copies(message) = gtk_moz_embed_get_link_message_unichar (embed); + + g_signal_emit_by_name (membed, "ge_link_message", + g_strdup(NS_ConvertUCS2toUTF8(message).get())); +} + +static void +mozilla_embed_js_status_cb (GtkMozEmbed *embed, + MozillaEmbed *membed) +{ + nsXPIDLString status; + + *getter_Copies(status) = gtk_moz_embed_get_js_status_unichar (embed); + + g_signal_emit_by_name (membed, "ge_js_status", + g_strdup(NS_ConvertUCS2toUTF8(status).get())); +} + +static void +mozilla_embed_visibility_cb (GtkMozEmbed *embed, gboolean visibility, + MozillaEmbed *membed) +{ + g_signal_emit_by_name (membed, "ge_visibility", visibility); + + nsresult rv; + nsCOMPtr<nsIWindowWatcher> wwatch + (do_GetService(WINDOWWATCHER_CONTRACTID, &rv)); + if (NS_FAILED(rv) || !wwatch) return; + + EphyWrapper *wrapper = (EphyWrapper *)mozilla_embed_get_galeon_wrapper(membed); + if(!wrapper) return; + + nsCOMPtr<nsIDOMWindow> domWindow; + rv = wrapper->GetDOMWindow(getter_AddRefs(domWindow)); + if(NS_FAILED(rv) || !domWindow) return; + + rv = wwatch->SetActiveWindow(domWindow); +} + +static void +mozilla_embed_destroy_brsr_cb (GtkMozEmbed *embed, + MozillaEmbed *membed) +{ + g_signal_emit_by_name (membed, "ge_destroy_brsr"); +} + +static gint +mozilla_embed_dom_mouse_click_cb (GtkMozEmbed *embed, gpointer dom_event, + MozillaEmbed *membed) +{ + EphyEmbedEvent *info; + EventContext event_context; + gint return_value = 0; + EphyWrapper *wrapper; + nsresult result; + + info = ephy_embed_event_new (); + + wrapper = MOZILLA_EMBED(membed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + event_context.Init ((nsIDOMEvent*)dom_event, wrapper); + result = event_context.GetMouseEventInfo (info); + + nsCOMPtr<nsIDOMDocument> domDoc; + result = event_context.GetTargetDocument (getter_AddRefs(domDoc)); + if (NS_SUCCEEDED(result)) + { + result = wrapper->PushTargetDocument (domDoc); + } + + g_signal_emit_by_name (membed, "ge_dom_mouse_click", info, &return_value); + + wrapper->PopTargetDocument (); + + g_object_unref (info); + + return return_value; +} + +static gint +mozilla_embed_dom_mouse_down_cb (GtkMozEmbed *embed, gpointer dom_event, + MozillaEmbed *membed) +{ + EphyEmbedEvent *info; + EventContext event_context; + gint return_value = 0; + EphyWrapper *wrapper; + nsresult result; + + info = ephy_embed_event_new (); + + wrapper = MOZILLA_EMBED(membed)->priv->wrapper; + g_return_val_if_fail (wrapper != NULL, G_FAILED); + + event_context.Init ((nsIDOMEvent*)dom_event, wrapper); + result = event_context.GetMouseEventInfo (info); + if (NS_SUCCEEDED(result)) + { + nsCOMPtr<nsIDOMDocument> domDoc; + result = event_context.GetTargetDocument (getter_AddRefs(domDoc)); + if (NS_SUCCEEDED(result)) + { + result = wrapper->PushTargetDocument (domDoc); + if (NS_SUCCEEDED(result)) + { + g_signal_emit_by_name (membed, "ge_dom_mouse_down", + info, &return_value); + wrapper->PopTargetDocument (); + } + } + + } + + g_object_unref (info); + + return return_value; +} + +static void +mozilla_embed_size_to_cb (GtkMozEmbed *embed, gint width, gint height, + MozillaEmbed *membed) +{ + g_signal_emit_by_name (membed, "ge_size_to", width, height); +} + +static void +mozilla_embed_new_window_cb (GtkMozEmbed *embed, + GtkMozEmbed **newEmbed, + guint chromemask, + MozillaEmbed *membed) +{ + int i; + EmbedChromeMask mask = EMBED_CHROME_OPENASPOPUP; + EphyEmbed *new_embed = NULL; + + struct + { + guint chromemask; + EmbedChromeMask embed_mask; + } + conversion_map [] = + { + { GTK_MOZ_EMBED_FLAG_DEFAULTCHROME, EMBED_CHROME_DEFAULT }, + { GTK_MOZ_EMBED_FLAG_MENUBARON, EMBED_CHROME_MENUBARON }, + { GTK_MOZ_EMBED_FLAG_TOOLBARON, EMBED_CHROME_TOOLBARON }, + { GTK_MOZ_EMBED_FLAG_PERSONALTOOLBARON, EMBED_CHROME_PERSONALTOOLBARON }, + { GTK_MOZ_EMBED_FLAG_STATUSBARON, EMBED_CHROME_STATUSBARON }, + { GTK_MOZ_EMBED_FLAG_WINDOWRAISED, EMBED_CHROME_WINDOWRAISED }, + { GTK_MOZ_EMBED_FLAG_WINDOWLOWERED, EMBED_CHROME_WINDOWLOWERED }, + { GTK_MOZ_EMBED_FLAG_CENTERSCREEN, EMBED_CHROME_CENTERSCREEN }, + { GTK_MOZ_EMBED_FLAG_OPENASDIALOG, EMBED_CHROME_OPENASDIALOG }, + { GTK_MOZ_EMBED_FLAG_OPENASCHROME, EMBED_CHROME_OPENASCHROME }, + { 0, EMBED_CHROME_NONE } + }; + + for (i = 0; conversion_map[i].chromemask != 0; i++) + { + if (chromemask & conversion_map[i].chromemask) + { + mask = (EmbedChromeMask) (mask | conversion_map[i].embed_mask); + } + } + + g_signal_emit_by_name (membed, "ge_new_window", &new_embed, mask); + + g_assert (new_embed != NULL); + + *newEmbed = GTK_MOZ_EMBED(new_embed); +} + +static void +mozilla_embed_security_change_cb (GtkMozEmbed *embed, + gpointer request, + guint state, + MozillaEmbed *membed) +{ + EmbedSecurityLevel level; + + membed->priv->request = (nsIRequest *) request; + membed->priv->security_state = state; + level = mozilla_embed_security_level (membed); + + g_signal_emit_by_name (membed, "ge_security_change", level); +} + +static EmbedSecurityLevel +mozilla_embed_security_level (MozillaEmbed *membed) +{ + EmbedSecurityLevel level; + + switch (membed->priv->security_state) + { + case nsIWebProgressListener::STATE_IS_INSECURE: + level = STATE_IS_INSECURE; + break; + case nsIWebProgressListener::STATE_IS_BROKEN: + level = STATE_IS_BROKEN; + break; + case nsIWebProgressListener::STATE_IS_SECURE| + nsIWebProgressListener::STATE_SECURE_HIGH: + level = STATE_IS_SECURE_HIGH; + break; + case nsIWebProgressListener::STATE_IS_SECURE| + nsIWebProgressListener::STATE_SECURE_MED: + level = STATE_IS_SECURE_MED; + break; + case nsIWebProgressListener::STATE_IS_SECURE| + nsIWebProgressListener::STATE_SECURE_LOW: + level = STATE_IS_SECURE_LOW; + break; + default: + level = STATE_IS_UNKNOWN; + break; + } + return level; +} + diff --git a/embed/mozilla/mozilla-embed.h b/embed/mozilla/mozilla-embed.h new file mode 100644 index 000000000..b8ebca4c8 --- /dev/null +++ b/embed/mozilla/mozilla-embed.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef MOZILLA_EMBED_H +#define MOZILLA_EMBED_H + +#include "ephy-embed-types.h" +#include "ephy-embed.h" + +#include <gtkmozembed.h> + +#include <glib-object.h> +#include <glib.h> + +G_BEGIN_DECLS + +typedef struct MozillaEmbedClass MozillaEmbedClass; + +#define MOZILLA_EMBED_TYPE (mozilla_embed_get_type ()) +#define MOZILLA_EMBED(obj) (GTK_CHECK_CAST ((obj), MOZILLA_EMBED_TYPE, MozillaEmbed)) +#define MOZILLA_EMBED_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), MOZILLA_EMBED_TYPE, MozillaEmbedClass)) +#define IS_MOZILLA_EMBED(obj) (GTK_CHECK_TYPE ((obj), MOZILLA_EMBED_TYPE)) +#define IS_MOZILLA_EMBED_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), MOZILLA_EMBED)) +#define MOZILLA_EMBED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOZILLA_EMBED_TYPE, MozillaEmbedClass)) + +typedef struct MozillaEmbed MozillaEmbed; +typedef struct MozillaEmbedPrivate MozillaEmbedPrivate; + +struct MozillaEmbed +{ + GtkMozEmbed parent; + MozillaEmbedPrivate *priv; +}; + +struct MozillaEmbedClass +{ + GtkMozEmbedClass parent_class; +}; + +GType mozilla_embed_get_type (void); + +gpointer mozilla_embed_get_galeon_wrapper (MozillaEmbed *embed); + +G_END_DECLS + +#endif diff --git a/embed/mozilla/mozilla-i18n.c b/embed/mozilla/mozilla-i18n.c new file mode 100644 index 000000000..c974d9765 --- /dev/null +++ b/embed/mozilla/mozilla-i18n.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2000 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "mozilla-i18n.h" + +#include <libgnome/gnome-i18n.h> + +const char *lgroups[] = { + N_("Arabic"), + N_("Baltic"), + N_("Central European"), + N_("Chinese"), + N_("Cyrillic"), + N_("Greek"), + N_("Hebrew"), + N_("Indian"), + N_("Japanese"), + N_("Korean"), + N_("Turkish"), + N_("Unicode"), + N_("Vietnamese"), + N_("Western"), + N_("Other"), + NULL +}; + +const CharsetInfoPriv charset_trans_array[] = { + {N_("Arabic (IBM-864)"), "IBM864", LG_ARABIC}, + {N_("Arabic (IBM-864-I)"), "IBM864i", LG_ARABIC}, + {N_("Arabic (ISO-8859-6)"), "ISO-8859-6", LG_ARABIC}, + {N_("Arabic (ISO-8859-6-E)"), "ISO-8859-6-E", LG_ARABIC}, + {N_("Arabic (ISO-8859-6-I)"), "ISO-8859-6-I", LG_ARABIC}, + {N_("Arabic (MacArabic)"), "x-mac-arabic", LG_ARABIC}, + {N_("Arabic (Windows-1256)"), "windows-1256", LG_ARABIC}, + {N_("Armenian (ARMSCII-8)"), "armscii-8", LG_OTHER}, + {N_("Baltic (ISO-8859-13)"), "ISO-8859-13", LG_BALTIC}, + {N_("Baltic (ISO-8859-4)"), "ISO-8859-4", LG_BALTIC}, + {N_("Baltic (Windows-1257)"), "windows-1257", LG_BALTIC}, + {N_("Celtic (ISO-8859-14)"), "ISO-8859-14", LG_OTHER}, + {N_("Central European (IBM-852)"), "IBM852", LG_CENTRAL_EUROPEAN}, + {N_("Central European (ISO-8859-2)"), "ISO-8859-2", LG_CENTRAL_EUROPEAN}, + {N_("Central European (MacCE)"), "x-mac-ce", LG_CENTRAL_EUROPEAN}, + {N_("Central European (Windows-1250)"), "windows-1250", LG_CENTRAL_EUROPEAN}, + {N_("Chinese Simplified (GB18030)"), "gb18030", LG_CHINESE}, + {N_("Chinese Simplified (GB2312)"), "GB2312", LG_CHINESE}, + {N_("Chinese Simplified (GBK)"), "x-gbk", LG_CHINESE}, + {N_("Chinese Simplified (HZ)"), "HZ-GB-2312", LG_CHINESE}, + {N_("Chinese Simplified (Windows-936)"), "windows-936", LG_CHINESE}, + {N_("Chinese Traditional (Big5)"), "Big5", LG_CHINESE}, + {N_("Chinese Traditional (Big5-HKSCS)"), "Big5-HKSCS", LG_CHINESE}, + {N_("Chinese Traditional (EUC-TW)"), "x-euc-tw", LG_CHINESE}, + {N_("Croatian (MacCroatian)"), "x-mac-croatian", LG_CENTRAL_EUROPEAN}, + {N_("Cyrillic (IBM-855)"), "IBM855", LG_CYRILLIC}, + {N_("Cyrillic (ISO-8859-5)"), "ISO-8859-5", LG_CYRILLIC}, + {N_("Cyrillic (ISO-IR-111)"), "ISO-IR-111", LG_CYRILLIC}, + {N_("Cyrillic (KOI8-R)"), "KOI8-R", LG_CYRILLIC}, + {N_("Cyrillic (MacCyrillic)"), "x-mac-cyrillic", LG_CYRILLIC}, + {N_("Cyrillic (Windows-1251)"), "windows-1251", LG_CYRILLIC}, + {N_("Cyrillic/Russian (CP-866)"), "IBM866", LG_CYRILLIC}, + {N_("Cyrillic/Ukrainian (KOI8-U)"), "KOI8-U", LG_CYRILLIC}, + {N_("Cyrillic/Ukrainian (MacUkrainian)"), "x-mac-ukrainian", LG_CYRILLIC}, + {N_("English (US-ASCII)"), "us-ascii", LG_WESTERN}, + {N_("Farsi (MacFarsi)"), "x-mac-farsi", LG_OTHER}, + {N_("Georgian (GEOSTD8)"), "geostd8", LG_OTHER}, + {N_("Greek (ISO-8859-7)"), "ISO-8859-7", LG_GREEK}, + {N_("Greek (MacGreek)"), "x-mac-greek", LG_GREEK}, + {N_("Greek (Windows-1253)"), "windows-1253", LG_GREEK}, + {N_("Gujarati (MacGujarati)"), "x-mac-gujarati", LG_INDIAN}, + {N_("Gurmukhi (MacGurmukhi)"), "x-mac-gurmukhi", LG_INDIAN}, + {N_("Hebrew (IBM-862)"), "IBM862", LG_HEBREW}, + {N_("Hebrew (ISO-8859-8-E)"), "ISO-8859-8-E", LG_HEBREW}, + {N_("Hebrew (ISO-8859-8-I)"), "ISO-8859-8-I", LG_HEBREW}, + {N_("Hebrew (MacHebrew)"), "x-mac-hebrew", LG_HEBREW}, + {N_("Hebrew (Windows-1255)"), "windows-1255", LG_HEBREW}, + {N_("Hindi (MacDevanagari)"), "x-mac-devanagari", LG_INDIAN}, + {N_("Icelandic (MacIcelandic)"), "x-mac-icelandic", LG_OTHER}, + {N_("Japanese (EUC-JP)"), "EUC-JP", LG_JAPANESE}, + {N_("Japanese (ISO-2022-JP)"), "ISO-2022-JP", LG_JAPANESE}, + {N_("Japanese (Shift_JIS)"), "Shift_JIS", LG_JAPANESE}, + {N_("Korean (EUC-KR)"), "EUC-KR", LG_KOREAN}, + {N_("Korean (ISO-2022-KR)"), "ISO-2022-KR", LG_KOREAN}, + {N_("Korean (JOHAB)"), "x-johab", LG_KOREAN}, + {N_("Korean (UHC)"), "x-windows-949", LG_KOREAN}, + {N_("Nordic (ISO-8859-10)"), "ISO-8859-10", LG_OTHER}, + {N_("Romanian (MacRomanian)"), "x-mac-romanian", LG_OTHER}, + {N_("Romanian (ISO-8859-16)"), "ISO-8859-16", LG_OTHER}, + {N_("South European (ISO-8859-3)"), "ISO-8859-3", LG_OTHER}, + {N_("Thai (TIS-620)"), "TIS-620", LG_OTHER}, + {N_("Turkish (IBM-857)"), "IBM857", LG_TURKISH}, + {N_("Turkish (ISO-8859-9)"), "ISO-8859-9", LG_TURKISH}, + {N_("Turkish (MacTurkish)"), "x-mac-turkish", LG_TURKISH}, + {N_("Turkish (Windows-1254)"), "windows-1254", LG_TURKISH}, + {N_("Unicode (UTF-7)"), "UTF-7", LG_UNICODE}, + {N_("Unicode (UTF-8)"), "UTF-8", LG_UNICODE}, + {N_("Unicode (UTF-16BE)"), "UTF-16BE", LG_UNICODE}, + {N_("Unicode (UTF-16LE)"), "UTF-16LE", LG_UNICODE}, + {N_("Unicode (UTF-32BE)"), "UTF-32BE", LG_UNICODE}, + {N_("Unicode (UTF-32LE)"), "UTF-32LE", LG_UNICODE}, + {N_("User Defined"), "x-user-defined", LG_OTHER}, + {N_("Vietnamese (TCVN)"), "x-viet-tcvn5712", LG_VIETNAMESE}, + {N_("Vietnamese (VISCII)"), "VISCII", LG_VIETNAMESE}, + {N_("Vietnamese (VPS)"), "x-viet-vps", LG_VIETNAMESE}, + {N_("Vietnamese (Windows-1258)"), "windows-1258", LG_VIETNAMESE}, + {N_("Visual Hebrew (ISO-8859-8)"), "ISO-8859-8", LG_HEBREW}, + {N_("Western (IBM-850)"), "IBM850", LG_WESTERN}, + {N_("Western (ISO-8859-1)"), "ISO-8859-1", LG_WESTERN}, + {N_("Western (ISO-8859-15)"), "ISO-8859-15", LG_WESTERN}, + {N_("Western (MacRoman)"), "x-mac-roman", LG_WESTERN}, + {N_("Western (Windows-1252)"), "windows-1252", LG_WESTERN}, + /* charsets whithout posibly translatable names */ + {"T61.8bit", "T61.8bit", LG_OTHER}, + {"x-imap4-modified-utf7", "x-imap4-modified-utf7", LG_UNICODE}, + {"x-u-escaped", "x-u-escaped", LG_OTHER} +}; + +const gchar *lang_encode_item[LANG_ENC_NUM] = +{ + "x-western", + "x-central-euro", + "ja", + "zh-TW", + "zh-CN", + "ko", + "x-cyrillic", + "x-baltic", + "el", + "tr", + "x-unicode", + "th", + "he", + "ar" +}; + +const gchar *font_types[] = +{ + "serif", + "sans-serif", + "cursive", + "fantasy", + "monospace" +}; + +extern gint +get_translated_cscount(void) +{ + return sizeof (charset_trans_array) / sizeof ((charset_trans_array)[0]); +} diff --git a/embed/mozilla/mozilla-i18n.h b/embed/mozilla/mozilla-i18n.h new file mode 100644 index 000000000..5b5dbc321 --- /dev/null +++ b/embed/mozilla/mozilla-i18n.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2000 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <glib.h> + +G_BEGIN_DECLS + +#define LANG_ENC_NUM 14 + +typedef enum { + LG_ARABIC, + LG_BALTIC, + LG_CENTRAL_EUROPEAN, + LG_CHINESE, + LG_CYRILLIC, + LG_GREEK, + LG_HEBREW, + LG_INDIAN, + LG_JAPANESE, + LG_KOREAN, + LG_TURKISH, + LG_UNICODE, + LG_VIETNAMESE, + LG_WESTERN, + LG_OTHER +} LanguageGroup; + +typedef struct { + char *charset_title; + char *charset_name; + LanguageGroup lgroup; +} CharsetInfoPriv; + +/* language groups names */ +extern const char *lgroups[]; +/* translated charset titles */ +extern const CharsetInfoPriv charset_trans_array[]; + +/* FIXME */ +extern const char *lang_encode_name[LANG_ENC_NUM]; +extern const char *lang_encode_item[LANG_ENC_NUM]; + +gint get_translated_cscount (void); + +G_END_DECLS diff --git a/embed/mozilla/mozilla-notifiers.cpp b/embed/mozilla/mozilla-notifiers.cpp new file mode 100644 index 000000000..24dfbb7a5 --- /dev/null +++ b/embed/mozilla/mozilla-notifiers.cpp @@ -0,0 +1,710 @@ +/* + * Copyright (C) 2000 Nate Case + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, OR (AT YOUR OPTION) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ephy-embed-shell.h" +#include "mozilla-notifiers.h" +#include "eel-gconf-extensions.h" +#include "mozilla-prefs.h" +#include "MozRegisterComponents.h" +#include "ephy-prefs.h" +#include "ephy-embed-prefs.h" +#include "mozilla-i18n.h" + +#include <stdio.h> +#include <string.h> +#include <locale.h> +#include <libgnome/gnome-i18n.h> +#include <stdlib.h> +#include <sys/utsname.h> +#include "nsBuildID.h" + +static void +mozilla_own_colors_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data); +static void +mozilla_own_fonts_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data); + +static void +mozilla_animate_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data); +static void +generic_mozilla_string_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + const char *pref_name); +static void +generic_mozilla_int_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + const char *pref_name); +static void +generic_mozilla_bool_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + const char *pref_name); +static void +mozilla_allow_popups_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data); + +static void +mozilla_language_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data); + +static void +mozilla_autodetect_charset_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + EphyEmbedShell *shell); + +static void +mozilla_default_font_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data); + +static void +mozilla_proxy_mode_notifier (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + char *pref); +static void +mozilla_proxy_autoconfig_notifier (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + char *pref); + +static void +mozilla_user_agent_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data); + +static void +mozilla_default_charset_notifier (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + EphyEmbedShell *shell); +static void +mozilla_socks_version_notifier (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data); + +/* Keeps the list of the notifiers we installed for mozilla prefs */ +/* to be able to remove them when exiting */ +GList *mozilla_notifiers = NULL; +GList *font_infos = NULL; + +enum +{ + BOOL_PREF, + INT_PREF, + STRING_PREF +}; + +static const struct +{ + char *gconf_key; + guint pref_type; + const char *mozilla_key; +} +conversion_table [] = +{ + { CONF_FILTERING_JAVA_ENABLED, BOOL_PREF, "security.enable_java"}, + { CONF_FILTERING_JAVASCRIPT_ENABLED, BOOL_PREF, "javascript.enabled"}, + { CONF_FILTERING_IMAGE_LOADING_TYPE, INT_PREF, "network.image.imageBehavior"}, + { CONF_RENDERING_BG_COLOR, STRING_PREF, "browser.display.background_color"}, + { CONF_RENDERING_TEXT_COLOR, STRING_PREF, "browser.display.foreground_color"}, + { CONF_RENDERING_UNVISITED_LINKS, STRING_PREF, "browser.anchor_color"}, + { CONF_RENDERING_VISITED_LINKS, STRING_PREF, "browser.visited_color"}, + { CONF_RENDERING_UNDERLINE_LINKS, BOOL_PREF, "browser.underline_anchors"}, + { CONF_NETWORK_PROXY_AUTO_URL, STRING_PREF, "network.proxy.autoconfig_url"}, + { CONF_NETWORK_HTTP_PROXY, STRING_PREF, "network.proxy.http"}, + { CONF_NETWORK_FTP_PROXY, STRING_PREF, "network.proxy.ftp"}, + { CONF_NETWORK_SSL_PROXY, STRING_PREF, "network.proxy.ssl"}, + { CONF_NETWORK_SOCKS_PROXY, STRING_PREF, "network.proxy.socks"}, + { CONF_NETWORK_HTTP_PROXY_PORT, INT_PREF, "network.proxy.http_port"}, + { CONF_NETWORK_FTP_PROXY_PORT, INT_PREF, "network.proxy.ftp_port"}, + { CONF_NETWORK_SSL_PROXY_PORT, INT_PREF, "network.proxy.ssl_port"}, + { CONF_NETWORK_SOCKS_PROXY_PORT, INT_PREF, "network.proxy.socks_port"}, + { CONF_NETWORK_NO_PROXIES_FOR, STRING_PREF, "network.proxy.no_proxies_on"}, + { CONF_NETWORK_MEMORY_CACHE, INT_PREF, "browser.cache.memory.capacity"}, + { CONF_NETWORK_DISK_CACHE, INT_PREF, "browser.cache.disk.capacity"}, + { CONF_NETWORK_CACHE_COMPARE, INT_PREF, "browser.cache.check_doc_frequency"}, + { CONF_PERSISTENT_COOKIE_WARN, BOOL_PREF, "network.cookie.warnAboutCookies"}, + { CONF_PERSISTENT_COOKIES_BEHAVIOR, INT_PREF, "network.cookie.cookieBehavior"}, + { CONF_PERSISTENT_COOKIE_LIFETIME, BOOL_PREF, "network.cookie.lifetime.enabled"}, + { CONF_PERSISTENT_PASSWORDS_SAVE, BOOL_PREF, "signon.rememberSignons"}, + { CONF_RENDERING_USE_SYSTEM_COLORS, BOOL_PREF, "browser.display.use_system_colors"}, + { NULL, 0, NULL } +}; + +static const struct +{ + const char *gconf_key; + GConfClientNotifyFunc func; +} +custom_notifiers [] = +{ + { CONF_NETWORK_USER_AGENT, + (GConfClientNotifyFunc) mozilla_user_agent_notifier }, + { CONF_FILTERING_ANIMATE_TYPE, + (GConfClientNotifyFunc) mozilla_animate_notifier }, + { CONF_RENDERING_USE_OWN_COLORS, + (GConfClientNotifyFunc) mozilla_own_colors_notifier }, + { CONF_RENDERING_USE_OWN_FONTS, + (GConfClientNotifyFunc) mozilla_own_fonts_notifier }, + { CONF_FILTERING_ALLOW_POPUPS, + (GConfClientNotifyFunc) mozilla_allow_popups_notifier }, + { CONF_LANGUAGE_DEFAULT_CHARSET, + (GConfClientNotifyFunc) mozilla_default_charset_notifier }, + { CONF_RENDERING_LANGUAGE, + (GConfClientNotifyFunc) mozilla_language_notifier }, + { CONF_LANGUAGE_AUTODETECT_CHARSET, + (GConfClientNotifyFunc) mozilla_autodetect_charset_notifier }, + { CONF_RENDERING_DEFAULT_FONT, + (GConfClientNotifyFunc) mozilla_default_font_notifier }, + { CONF_NETWORK_SOCKS_PROXY_VERSION, + (GConfClientNotifyFunc) mozilla_socks_version_notifier }, + { CONF_NETWORK_PROXY_MODE, + (GConfClientNotifyFunc) mozilla_proxy_mode_notifier }, + { CONF_NETWORK_PROXY_AUTO_URL, + (GConfClientNotifyFunc) mozilla_proxy_autoconfig_notifier }, + {NULL, NULL} +}; + +static void +mozilla_font_size_notifier (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + char *pref) +{ + char key[255]; + + sprintf (key, "font.%s", pref); + + mozilla_prefs_set_int (key, gconf_value_get_int(entry->value)); +} + +static void +mozilla_proxy_mode_notifier (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + char *pref) +{ + const char *mode; + int mozilla_mode = 0; + + mode = gconf_value_get_string(entry->value); + + if (strcmp (mode, "manual") == 0) + { + mozilla_mode = 1; + } + else if (strcmp (mode, "auto") == 0) + { + mozilla_mode = 2; + } + + mozilla_prefs_set_int ("network.proxy.type", mozilla_mode); +} + +static void +mozilla_font_notifier (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + char *pref) +{ + char key[255]; + + sprintf (key, "font.name.%s", pref); + + mozilla_prefs_set_string (key, gconf_value_get_string(entry->value)); +} + +static void +mozilla_proxy_autoconfig_notifier (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + char *pref) +{ + ephy_embed_shell_load_proxy_autoconf + (embed_shell, gconf_value_get_string(entry->value)); +} + +void +mozilla_notifiers_init(MozillaEmbedShell *shell) +{ + int i; + + for (i = 0; conversion_table[i].gconf_key != NULL; i++) + { + GConfClientNotifyFunc func = NULL; + + switch (conversion_table[i].pref_type) + { + case INT_PREF: + func = (GConfClientNotifyFunc) generic_mozilla_int_notifier; + break; + case BOOL_PREF: + func = (GConfClientNotifyFunc) generic_mozilla_bool_notifier; + break; + case STRING_PREF: + func = (GConfClientNotifyFunc) generic_mozilla_string_notifier; + break; + } + + g_assert (func != NULL); + + ephy_notification_add( + conversion_table[i].gconf_key, + func, + (gpointer)conversion_table[i].mozilla_key, + &mozilla_notifiers); + } + + for (i = 0; custom_notifiers[i].gconf_key != NULL; i++) + { + ephy_notification_add( + custom_notifiers[i].gconf_key, + custom_notifiers[i].func, + (gpointer)shell, + &mozilla_notifiers); + } + + /* fonts notifiers */ + for (i = 0; i < LANG_ENC_NUM; i++) + { + int k; + char *types [] = { "serif", "sans-serif", "cursive", "fantasy", "monospace" }; + char key[255]; + char *info; + + for (k = 0; k < 5; k++) + { + info = g_strconcat (types[k], ".", lang_encode_item[i], NULL); + + sprintf (key, "%s_%s_%s", CONF_RENDERING_FONT, + types[k], + lang_encode_item[i]); + ephy_notification_add (key, + (GConfClientNotifyFunc)mozilla_font_notifier, + info, + &mozilla_notifiers); + font_infos = g_list_append (font_infos, info); + } + + sprintf (key, "%s_%s", CONF_RENDERING_FONT_MIN_SIZE, lang_encode_item[i]); + info = g_strconcat ("minimum-size", ".", lang_encode_item[i], NULL); + ephy_notification_add (key, + (GConfClientNotifyFunc)mozilla_font_size_notifier, + info, + &mozilla_notifiers); + font_infos = g_list_append (font_infos, info); + + sprintf (key, "%s_%s", CONF_RENDERING_FONT_FIXED_SIZE, lang_encode_item[i]); + info = g_strconcat ("size.fixed", ".", lang_encode_item[i], NULL); + ephy_notification_add (key, + (GConfClientNotifyFunc)mozilla_font_size_notifier, + info, + &mozilla_notifiers); + font_infos = g_list_append (font_infos, info); + + sprintf (key, "%s_%s", CONF_RENDERING_FONT_VAR_SIZE, lang_encode_item[i]); + info = g_strconcat ("size.variable", ".", lang_encode_item[i], NULL); + ephy_notification_add (key, + (GConfClientNotifyFunc)mozilla_font_size_notifier, + info, + &mozilla_notifiers); + font_infos = g_list_append (font_infos, info); + } +} + +void +mozilla_notifiers_free (void) +{ + GList *l; + + ephy_notification_remove (&mozilla_notifiers); + + for (l = font_infos; l != NULL; l = l->next) + { + g_free (l->data); + } + + g_list_free (font_infos); +} + +void +mozilla_notifiers_set_defaults(void) +{ + GConfClient* client = eel_gconf_client_get_global(); + GConfValue* value; + int i; + + for (i = 0; conversion_table[i].gconf_key != NULL; i++) + { + value = gconf_client_get + (client, conversion_table[i].gconf_key, NULL); + if (value) + { + gconf_client_set (client, + conversion_table[i].gconf_key, + value, NULL); + gconf_value_free (value); + } + } + + for (i = 0; custom_notifiers[i].gconf_key != NULL; i++) + { + value = gconf_client_get + (client, custom_notifiers[i].gconf_key, NULL); + if (value) + { + gconf_client_set (client, + custom_notifiers[i].gconf_key, + value, NULL); + gconf_value_free (value); + } + } +} + +/** + * generic_mozilla_string_notify: update mozilla pref to match epiphany prefs. + * user_data should match the mozilla key + */ +static void +generic_mozilla_string_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + const char *pref_name) +{ + const gchar *value; + + /* determine type of gconf key, in order of likelyhood */ + switch (entry->value->type) + { + case GCONF_VALUE_STRING: + value = gconf_value_get_string(entry->value); + if (value) + { + mozilla_prefs_set_string + (pref_name, + gconf_value_get_string(entry->value)); + } + break; + + default: + g_warning("Unsupported variable type"); + } +} + + +/** + * generic_mozilla_int_notify: update mozilla pref to match epiphany prefs. + * user_data should match the mozilla key + */ +static void +generic_mozilla_int_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + const char *pref_name) +{ + /* determine type of gconf key, in order of likelyhood */ + switch (entry->value->type) + { + case GCONF_VALUE_INT: mozilla_prefs_set_int(pref_name, + gconf_value_get_int(entry->value)); + break; + case GCONF_VALUE_BOOL: mozilla_prefs_set_boolean(pref_name, + gconf_value_get_bool(entry->value)); + break; + case GCONF_VALUE_STRING: mozilla_prefs_set_string(pref_name, + gconf_value_get_string(entry->value)); + break; + default: g_warning("Unsupported variable type"); + } +} + + +/** + * generic_mozilla_bool_notify: update mozilla pref to match epiphany prefs. + * user_data should match the mozilla key + */ +static void +generic_mozilla_bool_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + const char *pref_name) +{ + /* determine type of gconf key, in order of likelyhood */ + switch (entry->value->type) + { + case GCONF_VALUE_BOOL: mozilla_prefs_set_boolean(pref_name, + gconf_value_get_bool(entry->value)); + break; + case GCONF_VALUE_INT: mozilla_prefs_set_int(pref_name, + gconf_value_get_int(entry->value)); + break; + default: g_warning("Unsupported variable type"); + } +} + +static void +mozilla_default_charset_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + EphyEmbedShell *shell) +{ + /* FIXME */ +} + + +static void +mozilla_own_colors_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) +{ + mozilla_prefs_set_boolean("browser.display.use_document_colors", + !gconf_value_get_bool(entry->value)); +} + +static void +mozilla_own_fonts_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) +{ + mozilla_prefs_set_int("browser.display.use_document_fonts", + !gconf_value_get_bool(entry->value)); +} + +static void +mozilla_animate_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) +{ + static const gchar *type[] = + { + "normal", + "once", + "none" + }; + + mozilla_prefs_set_string ("image.animation_mode", + type[gconf_value_get_int(entry->value)]); +} + +static void +mozilla_allow_popups_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) +{ + gboolean new_val = eel_gconf_get_boolean(CONF_FILTERING_ALLOW_POPUPS); + mozilla_prefs_set_boolean ("dom.disable_open_during_load", + !new_val); +} + +static void +mozilla_language_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) +{ + gchar *languages; + GSList *language_list ,*cur_lang_list; + + language_list = eel_gconf_get_string_list (CONF_RENDERING_LANGUAGE); + + languages = NULL; + cur_lang_list = language_list; + while (cur_lang_list != NULL) { + char *lang, *tmp; + + lang = g_strdup((char *)cur_lang_list->data); + + if (languages == NULL) + languages = lang; + else { + tmp = languages; + languages = g_strconcat(languages, ",", lang, NULL); + g_free(lang); + g_free(tmp); + } + g_free(cur_lang_list->data); + cur_lang_list = cur_lang_list->next; + } + + if (languages == NULL) + { + languages = g_strdup (""); + } + + mozilla_prefs_set_string ("intl.accept_languages", languages); + g_free (languages); + + g_slist_free(language_list); +} + +static char *autodetect_charset_prefs[] = +{ + "", + "zh_parallel_state_machine", + "cjk_parallel_state_machine", + "ja_parallel_state_machine", + "ko_parallel_state_machine", + "ruprob", + "zhcn_parallel_state_machine", + "zhtw_parallel_state_machine", + "ukprob" +}; + +static void +mozilla_autodetect_charset_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + EphyEmbedShell *shell) +{ + int charset = eel_gconf_get_integer (CONF_LANGUAGE_AUTODETECT_CHARSET); + if (charset < 0 || + charset >= (int)(sizeof(autodetect_charset_prefs) + / sizeof(autodetect_charset_prefs[0]))) + { + g_warning ("mozilla_autodetect_charset_notifier: " + "unsupported value: %d", charset); + return; + } + mozilla_prefs_set_string ("intl.charset.detector", + autodetect_charset_prefs[charset]); +} + +static void +mozilla_default_font_notifier(GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) +{ + const gchar *font_types [] = {"serif","sans-serif"}; + int default_font; + + default_font = eel_gconf_get_integer (CONF_RENDERING_DEFAULT_FONT); + if (default_font < 0 || + default_font >= (int)(sizeof(font_types) / sizeof(font_types[0]))) + { + g_warning ("mozilla_default_font_notifier: " + "unsupported value: %d", default_font); + return; + } + mozilla_prefs_set_string ("font.default", font_types[default_font]); +} + +static void +mozilla_prefs_set_user_agent () +{ + static gchar *default_user_agent = NULL; + gchar *value; + gchar *user_agent = NULL; + struct utsname name; + gchar *system; + + if (!default_user_agent) + { + if (uname (&name) == 0) + { + system = g_strdup_printf ("%s %s", + name.sysname, + name.machine); + } + else + { + system = g_strdup ("Unknown"); + } + + default_user_agent = g_strdup_printf + ("Mozilla/5.0 Ephy/" VERSION " (X11; %s; U;) Gecko/%d", + system, + NS_BUILD_ID/100); + + g_free (system); + } + + value = eel_gconf_get_string (CONF_NETWORK_USER_AGENT); + + /* now, build a valid user agent string */ + if (!value || !strcmp ("", value) + || !strcmp ("default", value) + || !strcmp ("Ephy", value) + || !strcmp (_("Default (recommended)"), value) + || !strcmp ("Default (recommended)", value)) + { + user_agent = g_strdup (default_user_agent); + } + else + { + user_agent = g_strdup (value); + } + + mozilla_prefs_set_string ("general.useragent.override", user_agent); + g_free (user_agent); +} + +static void +mozilla_user_agent_notifier (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) +{ + switch (entry->value->type) + { + case GCONF_VALUE_STRING: + mozilla_prefs_set_user_agent (); + break; + + default: + g_warning ("Unsupported variable type"); + break; + } +} + +static void +mozilla_socks_version_notifier (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) +{ + int version; + version = gconf_value_get_int(entry->value) + 4; + mozilla_prefs_set_int ("network.proxy.socks_version", + version); +} diff --git a/embed/mozilla/mozilla-notifiers.h b/embed/mozilla/mozilla-notifiers.h new file mode 100644 index 000000000..6718365f7 --- /dev/null +++ b/embed/mozilla/mozilla-notifiers.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2000 Nate Case + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef MOZILLA_NOTIFIERS_H +#define MOZILLA_NOTIFIERS_H + +#include "mozilla-embed-shell.h" + +void mozilla_notifiers_init (MozillaEmbedShell *shell); + +void mozilla_notifiers_set_defaults (void); + +void mozilla_notifiers_free (void); + +#endif diff --git a/embed/mozilla/mozilla-prefs.cpp b/embed/mozilla/mozilla-prefs.cpp new file mode 100644 index 000000000..e5b8c68e2 --- /dev/null +++ b/embed/mozilla/mozilla-prefs.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2000-2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "mozilla-prefs.h" + +#include <nsCOMPtr.h> +#include <nsIPrefService.h> +#include <nsIServiceManager.h> +#include <nsMemory.h> +#include <glib/gmessages.h> +#include <glib/gstrfuncs.h> + +gboolean +mozilla_prefs_save (void) +{ + nsCOMPtr<nsIPrefService> prefService = + do_GetService (NS_PREFSERVICE_CONTRACTID); + g_return_val_if_fail (prefService != nsnull, FALSE); + + nsresult rv = prefService->SavePrefFile (nsnull); + return NS_SUCCEEDED (rv) ? TRUE : FALSE; +} + +gboolean +mozilla_prefs_set_string(const char *preference_name, const char *new_value) +{ + g_return_val_if_fail (preference_name != NULL, FALSE); + g_return_val_if_fail (new_value != NULL, FALSE); + nsCOMPtr<nsIPrefService> prefService = + do_GetService (NS_PREFSERVICE_CONTRACTID); + nsCOMPtr<nsIPrefBranch> pref; + prefService->GetBranch ("", getter_AddRefs(pref)); + + if (pref) + { + nsresult rv = pref->SetCharPref (preference_name, new_value); + return NS_SUCCEEDED (rv) ? TRUE : FALSE; + } + + return FALSE; +} + +gboolean +mozilla_prefs_set_boolean (const char *preference_name, + gboolean new_boolean_value) +{ + g_return_val_if_fail (preference_name != NULL, FALSE); + + nsCOMPtr<nsIPrefService> prefService = + do_GetService (NS_PREFSERVICE_CONTRACTID); + nsCOMPtr<nsIPrefBranch> pref; + prefService->GetBranch ("", getter_AddRefs(pref)); + + if (pref) + { + nsresult rv = pref->SetBoolPref (preference_name, + new_boolean_value ? PR_TRUE : PR_FALSE); + return NS_SUCCEEDED (rv) ? TRUE : FALSE; + } + return FALSE; +} + +gboolean +mozilla_prefs_set_int (const char *preference_name, int new_int_value) +{ + g_return_val_if_fail (preference_name != NULL, FALSE); + + nsCOMPtr<nsIPrefService> prefService = + do_GetService (NS_PREFSERVICE_CONTRACTID); + nsCOMPtr<nsIPrefBranch> pref; + prefService->GetBranch ("", getter_AddRefs(pref)); + + if (pref) + { + nsresult rv = pref->SetIntPref (preference_name, new_int_value); + return NS_SUCCEEDED (rv) ? TRUE : FALSE; + } + + return FALSE; +} + +gboolean +mozilla_prefs_get_boolean (const char *preference_name, + gboolean default_value) +{ + PRBool value; + + g_return_val_if_fail (preference_name != NULL, FALSE); + + nsCOMPtr<nsIPrefService> prefService = + do_GetService (NS_PREFSERVICE_CONTRACTID); + nsCOMPtr<nsIPrefBranch> pref; + prefService->GetBranch ("", getter_AddRefs(pref)); + + if (pref) + { + nsresult result; + + result = pref->GetBoolPref (preference_name, &value); + if (NS_FAILED (result)) return default_value; + } + + return (value == PR_TRUE) ? TRUE : FALSE; +} + +gint +mozilla_prefs_get_int (const char *preference_name) +{ + int value = -1; + + g_return_val_if_fail (preference_name != NULL, FALSE); + + nsCOMPtr<nsIPrefService> prefService = + do_GetService (NS_PREFSERVICE_CONTRACTID); + nsCOMPtr<nsIPrefBranch> pref; + prefService->GetBranch ("", getter_AddRefs(pref)); + + if (pref) + { + pref->GetIntPref (preference_name, &value); + } + + return value; +} + +gchar * +mozilla_prefs_get_string(const char *preference_name) +{ + gchar *value = NULL; + gchar *result = NULL; + + g_return_val_if_fail (preference_name != NULL, FALSE); + nsCOMPtr<nsIPrefService> prefService = + do_GetService (NS_PREFSERVICE_CONTRACTID); + nsCOMPtr<nsIPrefBranch> pref; + prefService->GetBranch ("", getter_AddRefs(pref)); + + if (pref) + { + pref->GetCharPref (preference_name, &value); + } + + /* it's allocated by mozilla, so I could not g_free it */ + if (value) + { + result = g_strdup (value); + nsMemory::Free (value); + } + + return result; +} + +gboolean +mozilla_prefs_remove (const char *preference_name) +{ + g_return_val_if_fail (preference_name != NULL, FALSE); + + nsCOMPtr<nsIPrefService> prefService = + do_GetService (NS_PREFSERVICE_CONTRACTID); + nsCOMPtr<nsIPrefBranch> pref; + prefService->GetBranch ("", getter_AddRefs(pref)); + + if (pref) + { + nsresult rv = pref->ClearUserPref (preference_name); + return NS_SUCCEEDED (rv) ? TRUE : FALSE; + } + + return FALSE; +} diff --git a/embed/mozilla/mozilla-prefs.h b/embed/mozilla/mozilla-prefs.h new file mode 100644 index 000000000..82055c4a7 --- /dev/null +++ b/embed/mozilla/mozilla-prefs.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2000-2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef MOZILLA_PREFS_H +#define MOZILLA_PREFS_H + +#include "glib/gtypes.h" + +gboolean mozilla_prefs_save (void); + +gboolean mozilla_prefs_set_string (const char *preference_name, + const char *new_value); + +gboolean mozilla_prefs_set_boolean (const char *preference_name, + gboolean new_boolean_value); + +gboolean mozilla_prefs_set_int (const char *preference_name, + int new_int_value); + +gboolean mozilla_prefs_get_boolean (const char *preference_name, + gboolean default_value); + +int mozilla_prefs_get_int (const char *preference_name); + +gchar *mozilla_prefs_get_string (const char *preference_name); + +gboolean mozilla_prefs_remove (const char *preference_name); + +#endif diff --git a/embed/mozilla/nsUnicharUtils.cpp b/embed/mozilla/nsUnicharUtils.cpp new file mode 100644 index 000000000..d70619303 --- /dev/null +++ b/embed/mozilla/nsUnicharUtils.cpp @@ -0,0 +1,344 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Unicode case conversion helpers. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp.. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett <alecf@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsString.h" +#include "nsUnicharUtils.h" +#include "nsReadableUtils.h" +#include "nsUnicharUtilCIID.h" +#include "nsICaseConversion.h" +#include "nsIServiceManager.h" +#include "nsCRT.h" + +#include "nsIObserver.h" +#include "nsIObserverService.h" + +// global cache of the case conversion service +static nsICaseConversion *gCaseConv = nsnull; + +class nsShutdownObserver : public nsIObserver +{ +public: + nsShutdownObserver() { NS_INIT_ISUPPORTS(); } + virtual ~nsShutdownObserver() {} + NS_DECL_ISUPPORTS + + NS_IMETHOD Observe(nsISupports *aSubject, const char *aTopic, + const PRUnichar *aData) + { + if (nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)==0) { + NS_IF_RELEASE(gCaseConv); + } + + return NS_OK; + } + +}; + +NS_IMPL_ISUPPORTS1(nsShutdownObserver, nsIObserver) + +static nsresult NS_InitCaseConversion() { + if (gCaseConv) return NS_OK; + + nsresult rv; + + rv = CallGetService(NS_UNICHARUTIL_CONTRACTID, &gCaseConv); + + if (NS_SUCCEEDED(rv)) { + nsCOMPtr<nsIObserverService> obs = + do_GetService("@mozilla.org/observer-service;1", &rv); + if (NS_SUCCEEDED(rv)) { + nsShutdownObserver *observer = new nsShutdownObserver(); + if (observer) + obs->AddObserver(observer, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE); + } + } + + return NS_OK; +} + +class ConvertToLowerCase +{ +public: + typedef PRUnichar value_type; + + ConvertToLowerCase() + { + NS_InitCaseConversion(); + } + + PRUint32 write( const PRUnichar* aSource, PRUint32 aSourceLength) + { + if (gCaseConv) + gCaseConv->ToLower(aSource, NS_CONST_CAST(PRUnichar*,aSource), aSourceLength); + else + NS_WARNING("No case converter: no conversion done"); + + return aSourceLength; + } +}; + +void +ToLowerCase( nsAString& aString ) + { + nsAString::iterator fromBegin, fromEnd; + ConvertToLowerCase converter; + copy_string(aString.BeginWriting(fromBegin), aString.EndWriting(fromEnd), converter); + } + +void +ToLowerCase( nsASingleFragmentString& aString ) + { + ConvertToLowerCase converter; + PRUnichar* start; + converter.write(aString.BeginWriting(start), aString.Length()); + } + +void +ToLowerCase( nsString& aString ) + { + ConvertToLowerCase converter; + converter.write(aString.mUStr, aString.mLength); + } + +class CopyToLowerCase + { + public: + typedef PRUnichar value_type; + + CopyToLowerCase( nsAString::iterator& aDestIter ) + : mIter(aDestIter) + { + NS_InitCaseConversion(); + } + + PRUint32 write( const PRUnichar* aSource, PRUint32 aSourceLength ) + { + PRUint32 len = PR_MIN(PRUint32(mIter.size_forward()), aSourceLength); + PRUnichar* dest = NS_CONST_CAST(PRUnichar*, mIter.get()); + if (gCaseConv) + gCaseConv->ToLower(aSource, dest, len); + else { + NS_WARNING("No case converter: only copying"); + memcpy((void*)aSource, (void*)dest, len * sizeof(*aSource)); + } + mIter.advance(len); + return len; + } + + protected: + nsAString::iterator& mIter; + }; + +void +ToLowerCase( const nsAString& aSource, nsAString& aDest ) + { + nsAString::const_iterator fromBegin, fromEnd; + nsAString::iterator toBegin; + aDest.SetLength(aSource.Length()); + CopyToLowerCase converter(aDest.BeginWriting(toBegin)); + copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter); + } + +class ConvertToUpperCase +{ +public: + typedef PRUnichar value_type; + + ConvertToUpperCase() + { + NS_InitCaseConversion(); + } + + PRUint32 write( const PRUnichar* aSource, PRUint32 aSourceLength) + { + if (gCaseConv) + gCaseConv->ToUpper(aSource, NS_CONST_CAST(PRUnichar*,aSource), aSourceLength); + else + NS_WARNING("No case converter: no conversion done"); + + return aSourceLength; + } +}; + +void +ToUpperCase( nsAString& aString ) + { + nsAString::iterator fromBegin, fromEnd; + ConvertToUpperCase converter; + copy_string(aString.BeginWriting(fromBegin), aString.EndWriting(fromEnd), converter); + } + +void +ToUpperCase( nsASingleFragmentString& aString ) + { + ConvertToUpperCase converter; + PRUnichar* start; + converter.write(aString.BeginWriting(start), aString.Length()); + } + +void +ToUpperCase( nsString& aString ) + { + ConvertToUpperCase converter; + converter.write(aString.mUStr, aString.mLength); + } + +class CopyToUpperCase + { + public: + typedef PRUnichar value_type; + + CopyToUpperCase( nsAString::iterator& aDestIter ) + : mIter(aDestIter) + { + NS_InitCaseConversion(); + } + + PRUint32 write( const PRUnichar* aSource, PRUint32 aSourceLength ) + { + PRUint32 len = PR_MIN(PRUint32(mIter.size_forward()), aSourceLength); + PRUnichar* dest = NS_CONST_CAST(PRUnichar*, mIter.get()); + if (gCaseConv) + gCaseConv->ToUpper(aSource, dest, len); + else { + NS_WARNING("No case converter: only copying"); + memcpy((void*)aSource, (void*)dest, len * sizeof(*aSource)); + } + mIter.advance(len); + return len; + } + + protected: + nsAString::iterator& mIter; + }; + +void +ToUpperCase( const nsAString& aSource, nsAString& aDest ) + { + nsAString::const_iterator fromBegin, fromEnd; + nsAString::iterator toBegin; + aDest.SetLength(aSource.Length()); + CopyToUpperCase converter(aDest.BeginWriting(toBegin)); + copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter); + } + +PRBool +CaseInsensitiveFindInReadable( const nsAString& aPattern, nsAString::const_iterator& aSearchStart, nsAString::const_iterator& aSearchEnd ) +{ + return FindInReadable(aPattern, aSearchStart, aSearchEnd, nsCaseInsensitiveStringComparator()); +} + + +int +nsCaseInsensitiveStringComparator::operator()( const PRUnichar* lhs, const PRUnichar* rhs, PRUint32 aLength ) const + { + NS_InitCaseConversion(); + PRInt32 result; + if (gCaseConv) { + gCaseConv->CaseInsensitiveCompare(lhs, rhs, aLength, &result); + } + else { + NS_WARNING("No case converter: using default"); + nsDefaultStringComparator comparator; + result = comparator(lhs, rhs, aLength); + } + return result; + } + +int +nsCaseInsensitiveStringComparator::operator()( PRUnichar lhs, PRUnichar rhs ) const + { + // see if they're an exact match first + if (lhs == rhs) return 0; + + NS_InitCaseConversion(); + + if (gCaseConv) { + gCaseConv->ToLower(lhs, &lhs); + gCaseConv->ToLower(rhs, &rhs); + } else { + if (lhs < 256) + lhs = tolower(char(lhs)); + if (rhs < 256) + rhs = tolower(char(rhs)); + NS_WARNING("No case converter: no conversion done"); + } + + if (lhs == rhs) return 0; + if (lhs < rhs) return -1; + return 1; + } + +PRUnichar +ToLowerCase(PRUnichar aChar) +{ + PRUnichar result; + if (NS_FAILED(NS_InitCaseConversion())) + return aChar; + + if (gCaseConv) + gCaseConv->ToLower(aChar, &result); + else { + NS_WARNING("No case converter: no conversion done"); + if (aChar < 256) + result = tolower(char(aChar)); + else + result = aChar; + } + return result; +} + +PRUnichar +ToUpperCase(PRUnichar aChar) +{ + PRUnichar result; + if (NS_FAILED(NS_InitCaseConversion())) + return aChar; + + if (gCaseConv) + gCaseConv->ToUpper(aChar, &result); + else { + NS_WARNING("No case converter: no conversion done"); + if (aChar < 256) + result = toupper(char(aChar)); + else + result = aChar; + } + return result; +} + diff --git a/embed/mozilla/nsUnicharUtils.h b/embed/mozilla/nsUnicharUtils.h new file mode 100644 index 000000000..6ae9a238d --- /dev/null +++ b/embed/mozilla/nsUnicharUtils.h @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Unicode case conversion helpers. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp.. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett <alecf@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsUnicharUtils_h__ +#define nsUnicharUtils_h__ +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + +class nsASingleFragmentString; +class nsString; + +void ToLowerCase( nsAString& ); +void ToUpperCase( nsAString& ); + +void ToLowerCase( nsASingleFragmentString& ); +void ToUpperCase( nsASingleFragmentString& ); + +void ToLowerCase( nsString& ); +void ToUpperCase( nsString& ); + +void ToLowerCase( const nsAString& aSource, nsAString& aDest ); +void ToUpperCase( const nsAString& aSource, nsAString& aDest ); + +PRBool CaseInsensitiveFindInReadable( const nsAString& aPattern, nsAString::const_iterator&, nsAString::const_iterator& ); + +class nsCaseInsensitiveStringComparator + : public nsStringComparator + { + public: + virtual int operator()( const PRUnichar*, const PRUnichar*, PRUint32 aLength ) const; + virtual int operator()( PRUnichar, PRUnichar ) const; + }; + + +PRUnichar ToUpperCase(PRUnichar); +PRUnichar ToLowerCase(PRUnichar); + +inline PRBool IsUpperCase(PRUnichar c) { + return ToLowerCase(c) != c; +} + +inline PRBool IsLowerCase(PRUnichar c) { + return ToUpperCase(c) != c; +} + +#define IS_HIGH_SURROGATE(u) ((PRUnichar)(u) >= (PRUnichar)0xd800 && (PRUnichar)(u) <= (PRUnichar)0xdbff) +#define IS_LOW_SURROGATE(u) ((PRUnichar)(u) >= (PRUnichar)0xdc00 && (PRUnichar)(u) <= (PRUnichar)0xdfff) + +#define SURROGATE_TO_UCS4(h, l) ((((PRUint32)(h)-(PRUint32)0xd800) << 10) + \ + (PRUint32)(l) - (PRUint32)(0xdc00) + 0x10000) + +/* (0x3131u <= (u) && (u) <= 0x318eu) => Hangul Compatibility Jamo */ +/* (0xac00u <= (u) && (u) <= 0xd7a3u) => Hangul Syllables */ +#define IS_CJ_CHAR(u) \ + ((0x2e80u <= (u) && (u) <= 0x312fu) || \ + (0x3190u <= (u) && (u) <= 0xabffu) || \ + (0xf900u <= (u) && (u) <= 0xfaffu) || \ + (0xff00u <= (u) && (u) <= 0xffffu) ) + +#endif /* nsUnicharUtils_h__ */ diff --git a/embed/print-dialog.c b/embed/print-dialog.c new file mode 100755 index 000000000..09929376c --- /dev/null +++ b/embed/print-dialog.c @@ -0,0 +1,402 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "print-dialog.h" +#include "ephy-prefs.h" +#include <gtk/gtkdialog.h> + +#define CONF_PRINT_BOTTOM_MARGIN "/apps/epiphany/print/bottom_margin" +#define CONF_PRINT_TOP_MARGIN "/apps/epiphany/print/top_margin" +#define CONF_PRINT_LEFT_MARGIN "/apps/epiphany/print/left_margin" +#define CONF_PRINT_RIGHT_MARGIN "/apps/epiphany/print/right_margin" +#define CONF_PRINT_PAGE_TITLE "/apps/epiphany/print/page_title_toggle" +#define CONF_PRINT_PAGE_URL "/apps/epiphany/print/page_url_toggle" +#define CONF_PRINT_DATE "/apps/epiphany/print/date_toggle" +#define CONF_PRINT_PAGE_NUMBERS "/apps/epiphany/print/page_numbers_toggle" +#define CONF_PRINT_PRINTER "/apps/epiphany/print/printer" +#define CONF_PRINT_FILE "/apps/epiphany/print/file" +#define CONF_PRINT_PRINTON "/apps/epiphany/print/printon" +#define CONF_PRINT_PAPER "/apps/epiphany/print/paper" +#define CONF_PRINT_ALL_PAGES "/apps/epiphany/print/all_pages" +#define CONF_PRINT_START_FROM_LAST "/apps/epiphany/print/start_from_last" +#define CONF_PRINT_COLOR "/apps/epiphany/print/color" +#define CONF_PRINT_ORIENTATION "/apps/epiphany/print/orientation" + +static void print_dialog_class_init (PrintDialogClass *klass); +static void print_dialog_init (PrintDialog *dialog); +static void print_dialog_finalize (GObject *object); + +/* Glade callbacks */ +void +print_cancel_button_cb (GtkWidget *widget, + EphyDialog *dialog); +void +print_ok_button_cb (GtkWidget *widget, + EphyDialog *dialog); +void +print_preview_button_cb (GtkWidget *widget, + EphyDialog *dialog); + +static GObjectClass *parent_class = NULL; + +struct PrintDialogPrivate +{ + gpointer dummy; +}; + +enum +{ + PRINTON_PROP, + PRINTER_PROP, + FILE_PROP, + PAPER_PROP, + TOP_PROP, + BOTTOM_PROP, + LEFT_PROP, + RIGHT_PROP, + PAGE_TITLE_PROP, + PAGE_URL_PROP, + PAGE_NUMBERS_PROP, + DATE_PROP, + ALL_PAGES_PROP, + TO_PROP, + FROM_PROP, + COLOR_PROP, + ORIENTATION_PROP +}; + +enum +{ + PREVIEW, + LAST_SIGNAL +}; + +static const +EphyDialogProperty properties [] = +{ + { PRINTON_PROP, "printer_radiobutton", CONF_PRINT_PRINTON, PT_NORMAL, NULL }, + { PRINTER_PROP, "printer_entry", CONF_PRINT_PRINTER, PT_NORMAL, NULL }, + { FILE_PROP, "file_entry", CONF_PRINT_FILE, PT_NORMAL, NULL }, + { PAPER_PROP,"letter_radiobutton", CONF_PRINT_PAPER, PT_NORMAL, NULL }, + { TOP_PROP, "top_spinbutton", CONF_PRINT_TOP_MARGIN, PT_NORMAL, NULL }, + { BOTTOM_PROP, "bottom_spinbutton", CONF_PRINT_BOTTOM_MARGIN, PT_NORMAL, NULL }, + { LEFT_PROP,"left_spinbutton", CONF_PRINT_LEFT_MARGIN, PT_NORMAL, NULL }, + { RIGHT_PROP, "right_spinbutton", CONF_PRINT_RIGHT_MARGIN, PT_NORMAL, NULL }, + { PAGE_TITLE_PROP, "print_page_title_checkbutton", CONF_PRINT_PAGE_TITLE, PT_NORMAL, NULL }, + { PAGE_URL_PROP, "print_page_url_checkbutton", CONF_PRINT_PAGE_URL, PT_NORMAL, NULL }, + { PAGE_NUMBERS_PROP, "print_page_numbers_checkbutton", CONF_PRINT_PAGE_NUMBERS, PT_NORMAL, NULL }, + { DATE_PROP, "print_date_checkbutton", CONF_PRINT_DATE, PT_NORMAL, NULL }, + { ALL_PAGES_PROP, "all_pages_radiobutton", CONF_PRINT_ALL_PAGES, PT_NORMAL, NULL }, + { TO_PROP, "to_spinbutton", NULL, PT_NORMAL, NULL }, + { FROM_PROP, "from_spinbutton", NULL, PT_NORMAL, NULL }, + { COLOR_PROP, "print_color_radiobutton", CONF_PRINT_COLOR, PT_NORMAL, NULL }, + { ORIENTATION_PROP, "orient_p_radiobutton", CONF_PRINT_ORIENTATION, PT_NORMAL, NULL }, + + { -1, NULL, NULL } +}; + +static guint print_dialog_signals[LAST_SIGNAL] = { 0 }; + +GType +print_dialog_get_type (void) +{ + static GType print_dialog_type = 0; + + if (print_dialog_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (PrintDialogClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) print_dialog_class_init, + NULL, + NULL, /* class_data */ + sizeof (PrintDialog), + 0, /* n_preallocs */ + (GInstanceInitFunc) print_dialog_init + }; + + print_dialog_type = g_type_register_static (EPHY_EMBED_DIALOG_TYPE, + "PrintDialog", + &our_info, 0); + } + + return print_dialog_type; + +} + +static void +print_dialog_class_init (PrintDialogClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = print_dialog_finalize; + + print_dialog_signals[PREVIEW] = + g_signal_new ("preview", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (PrintDialogClass, preview), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +static void +print_dialog_init (PrintDialog *dialog) +{ + dialog->priv = g_new0 (PrintDialogPrivate, 1); + + dialog->only_collect_info = FALSE; + + dialog->ret_info = NULL; + + ephy_dialog_construct (EPHY_DIALOG(dialog), + properties, + "print.glade", "print_dialog"); +} + +static void +print_dialog_finalize (GObject *object) +{ + PrintDialog *dialog; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_PRINT_DIALOG (object)); + + dialog = PRINT_DIALOG (object); + + g_return_if_fail (dialog->priv != NULL); + + g_free (dialog->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +EphyDialog * +print_dialog_new (EphyEmbed *embed, + EmbedPrintInfo **ret_info) +{ + PrintDialog *dialog; + + dialog = PRINT_DIALOG (g_object_new (PRINT_DIALOG_TYPE, + "EphyEmbed", embed, + NULL)); + + if (!embed) dialog->only_collect_info = TRUE; + dialog->ret_info = ret_info; + + return EPHY_DIALOG(dialog); +} + +EphyDialog * +print_dialog_new_with_parent (GtkWidget *window, + EphyEmbed *embed, + EmbedPrintInfo **ret_info) +{ + PrintDialog *dialog; + + dialog = PRINT_DIALOG (g_object_new (PRINT_DIALOG_TYPE, + "EphyEmbed", embed, + "ParentWindow", window, + NULL)); + + if (!embed) dialog->only_collect_info = TRUE; + dialog->ret_info = ret_info; + + return EPHY_DIALOG(dialog); +} + +void +print_free_info (EmbedPrintInfo *info) +{ + g_free (info->printer); + g_free (info->file); + g_free (info->header_left_string); + g_free (info->header_right_string); + g_free (info->footer_left_string); + g_free (info->footer_right_string); + g_free (info); +} + +static EmbedPrintInfo * +print_get_info (EphyDialog *dialog) +{ + EmbedPrintInfo *info; + GValue print_to_file = {0, }; + GValue printer = {0, }; + GValue file = {0, }; + GValue top_margin = {0, }; + GValue bottom_margin = {0, }; + GValue left_margin = {0, }; + GValue right_margin = {0, }; + GValue from_page = {0, }; + GValue to_page = {0, }; + GValue paper = {0, }; + GValue pages = {0, }; + GValue print_color = {0, }; + GValue orientation = {0, }; + GValue page_title = {0, }; + GValue page_url = {0, }; + GValue date = {0, }; + GValue page_numbers = {0, }; + + info = g_new0 (EmbedPrintInfo, 1); + + ephy_dialog_get_value (dialog, PRINTON_PROP, &print_to_file); + info->print_to_file = g_value_get_int (&print_to_file); + + ephy_dialog_get_value (dialog, PRINTER_PROP, &printer); + info->printer = g_strdup (g_value_get_string (&printer)); + + ephy_dialog_get_value (dialog, FILE_PROP, &file); + info->file = g_strdup (g_value_get_string (&file)); + + ephy_dialog_get_value (dialog, BOTTOM_PROP, &bottom_margin); + info->bottom_margin = g_value_get_float (&bottom_margin); + + ephy_dialog_get_value (dialog, LEFT_PROP, &left_margin); + info->left_margin = g_value_get_float (&left_margin); + + ephy_dialog_get_value (dialog, TOP_PROP, &top_margin); + info->top_margin = g_value_get_float (&top_margin); + + ephy_dialog_get_value (dialog, RIGHT_PROP, &right_margin); + info->right_margin = g_value_get_float (&right_margin); + + ephy_dialog_get_value (dialog, FROM_PROP, &from_page); + info->from_page = g_value_get_float (&from_page); + + ephy_dialog_get_value (dialog, TO_PROP, &to_page); + info->to_page = g_value_get_float (&to_page); + + ephy_dialog_get_value (dialog, PAPER_PROP, &paper); + info->paper = g_value_get_int (&paper); + + ephy_dialog_get_value (dialog, ALL_PAGES_PROP, &pages); + info->pages = g_value_get_int (&pages); + + ephy_dialog_get_value (dialog, COLOR_PROP, &print_color); + info->print_color = g_value_get_int (&print_color); + + ephy_dialog_get_value (dialog, ORIENTATION_PROP, &orientation); + info->orientation = g_value_get_int (&orientation); + + info->frame_type = 0; + + ephy_dialog_get_value (dialog, PAGE_TITLE_PROP, &page_title); + info->header_left_string = g_value_get_boolean (&page_title) ? + g_strdup ("&T") : g_strdup (""); + + ephy_dialog_get_value (dialog, PAGE_URL_PROP, &page_url); + info->header_right_string = g_value_get_boolean (&page_url) ? + g_strdup ("&U") : g_strdup (""); + + ephy_dialog_get_value (dialog, PAGE_NUMBERS_PROP, &page_numbers); + info->footer_left_string = g_value_get_boolean (&page_numbers) ? + g_strdup ("&PT") : g_strdup (""); + + ephy_dialog_get_value (dialog, DATE_PROP, &date); + info->footer_right_string = g_value_get_boolean (&date) ? + g_strdup ("&D") : g_strdup (""); + + info->header_center_string = g_strdup(""); + info->footer_center_string = g_strdup(""); + + return info; +} + +static void +print_dialog_print (EphyDialog *dialog) +{ + EmbedPrintInfo *info; + EphyEmbed *embed; + + info = print_get_info (dialog); + + if(PRINT_DIALOG(dialog)->only_collect_info && PRINT_DIALOG(dialog)->ret_info) + { + *(PRINT_DIALOG(dialog)->ret_info) = info; + } + else + { + embed = ephy_embed_dialog_get_embed + (EPHY_EMBED_DIALOG(dialog)); + + info->preview = FALSE; + ephy_embed_print (embed, info); + print_free_info (info); + } + + g_object_unref (G_OBJECT(dialog)); +} + +static void +print_dialog_preview (EphyDialog *dialog) +{ + EmbedPrintInfo *info; + EphyEmbed *embed; + + info = print_get_info (dialog); + + if(PRINT_DIALOG(dialog)->only_collect_info && PRINT_DIALOG(dialog)->ret_info) + { + *(PRINT_DIALOG(dialog)->ret_info) = info; + } + else + { + embed = ephy_embed_dialog_get_embed + (EPHY_EMBED_DIALOG(dialog)); + + info->preview = TRUE; + ephy_embed_print (embed, info); + print_free_info (info); + } + g_signal_emit (G_OBJECT (dialog), print_dialog_signals[PREVIEW], 0); + + g_object_unref (G_OBJECT(dialog)); +} + +void +print_cancel_button_cb (GtkWidget *widget, + EphyDialog *dialog) +{ + g_object_unref (G_OBJECT(dialog)); +} + +void +print_ok_button_cb (GtkWidget *widget, + EphyDialog *dialog) +{ + print_dialog_print (dialog); +} + +void +print_preview_button_cb (GtkWidget *widget, + EphyDialog *dialog) +{ + //FIXME: Don't show preview button at all. + if(!(PRINT_DIALOG(dialog)->only_collect_info)) + print_dialog_preview (dialog); +} + + diff --git a/embed/print-dialog.h b/embed/print-dialog.h new file mode 100644 index 000000000..5342f0223 --- /dev/null +++ b/embed/print-dialog.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PRINT_DIALOG_H +#define PRINT_DIALOG_H + +#include "ephy-embed-dialog.h" +#include "ephy-embed.h" + +#include <glib-object.h> +#include <glib.h> + +G_BEGIN_DECLS + +typedef struct PrintDialog PrintDialog; +typedef struct PrintDialogClass PrintDialogClass; + +#define PRINT_DIALOG_TYPE (print_dialog_get_type ()) +#define PRINT_DIALOG(obj) (GTK_CHECK_CAST ((obj), PRINT_DIALOG_TYPE, PrintDialog)) +#define PRINT_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), PRINT_DIALOG, PrintDialogClass)) +#define IS_PRINT_DIALOG(obj) (GTK_CHECK_TYPE ((obj), PRINT_DIALOG_TYPE)) +#define IS_PRINT_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), PRINT_DIALOG)) + +typedef struct PrintDialogPrivate PrintDialogPrivate; + +struct PrintDialog +{ + EphyEmbedDialog parent; + PrintDialogPrivate *priv; + //FIXME: These should be gobject properties + gboolean only_collect_info; + EmbedPrintInfo **ret_info; +}; + +struct PrintDialogClass +{ + EphyEmbedDialogClass parent_class; + + void (* preview) (PrintDialog *dialog); +}; + +GType print_dialog_get_type (void); + +EphyDialog *print_dialog_new (EphyEmbed *embed, + EmbedPrintInfo **ret_info); + +EphyDialog *print_dialog_new_with_parent (GtkWidget *window, + EphyEmbed *embed, + EmbedPrintInfo **ret_info); + +gboolean print_dialog_is_preview (PrintDialog *dialog); + +void print_free_info (EmbedPrintInfo *info); + +G_END_DECLS + +#endif + diff --git a/idl/EphyAutomation.idl b/idl/EphyAutomation.idl new file mode 100644 index 000000000..090fd51f3 --- /dev/null +++ b/idl/EphyAutomation.idl @@ -0,0 +1,27 @@ +#include <Bonobo.idl> + +module GNOME { + + interface EphyAutomation : Bonobo::Unknown { + boolean loadurl (in string url, + in string geometry, + in boolean fullscreen, + in boolean open_in_existing_tab, + in boolean open_in_new_tab, + in boolean open_in_new_window, + in boolean raise); + + boolean addBookmark (in string url); + + /** + * Closes all opened windows. + * if disableServer is true, + * server mode is disbaled + * (and Galeon exits) + */ + boolean quit (in boolean disableServer); + + boolean loadSession (in string filename); + }; +}; + diff --git a/lib/.cvsignore b/lib/.cvsignore new file mode 100644 index 000000000..20e4cb0c8 --- /dev/null +++ b/lib/.cvsignore @@ -0,0 +1,6 @@ +Makefile +Makefile.in +*.lo +.deps +.libs +*.la diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 000000000..60092472f --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,73 @@ +SUBDIRS = widgets toolbar + +INCLUDES = \ + $(WARN_CFLAGS) \ + $(EPIPHANY_DEPENDENCY_CFLAGS) \ + -DSHARE_DIR=\"$(pkgdatadir)\" \ + -DG_DISABLE_DEPRECATED \ + -DGDK_DISABLE_DEPRECATED \ + -DGTK_DISABLE_DEPRECATED \ + -DGDK_PIXBUF_DISABLE_DEPRECATED \ + -DGNOME_DISABLE_DEPRECATED + +noinst_LTLIBRARIES = libephy.la + +libephy_la_SOURCES = \ + ephy-types.h \ + ephy-prefs.h \ + ephy-gobject-misc.h \ + eel-gconf-extensions.c \ + eel-gconf-extensions.h \ + ephy-dialog.c \ + ephy-dialog.h \ + ephy-dnd.c \ + ephy-dnd.h \ + ephy-marshal.c \ + ephy-marshal.h \ + ephy-types.h \ + ephy-bonobo-extensions.h \ + ephy-bonobo-extensions.c \ + ephy-file-helpers.c \ + ephy-file-helpers.h \ + ephy-glade.c \ + ephy-glade.h \ + ephy-gui.c \ + ephy-gui.h \ + ephy-prefs-utils.c \ + ephy-prefs-utils.h \ + ephy-state.c \ + ephy-state.h \ + ephy-string.c \ + ephy-string.h \ + ephy-autocompletion.c \ + ephy-autocompletion.h \ + ephy-autocompletion-source.c \ + ephy-autocompletion-source.h \ + ephy-stock-icons.c \ + ephy-stock-icons.h \ + ephy-filesystem-autocompletion.c \ + ephy-filesystem-autocompletion.h \ + ephy-thread-helpers.c \ + ephy-thread-helpers.h \ + ephy-node.c \ + ephy-node.h \ + ephy-node-filter.c \ + ephy-node-filter.h + +libephy_la_LIBADD = \ + $(top_builddir)/lib/widgets/libephywidgets.la \ + $(top_builddir)/lib/toolbar/libephytoolbar.la + +BUILT_SOURCES=ephy-marshal.c ephy-marshal.h + +CLEAN_FILES = $(BUILT_SOURCES) + +ephy-marshal.c: ephy-marshal.list + @GLIB_GENMARSHAL@ --prefix=ephy_marshal $(srcdir)/ephy-marshal.list --header --body > ephy-marshal.c + +ephy-marshal.h: ephy-marshal.list + @GLIB_GENMARSHAL@ --prefix=ephy_marshal $(srcdir)/ephy-marshal.list --header > ephy-marshal.h + +EXTRA_DIST = \ + ephy-marshal.list + diff --git a/lib/eel-gconf-extensions.c b/lib/eel-gconf-extensions.c new file mode 100644 index 000000000..e6593219a --- /dev/null +++ b/lib/eel-gconf-extensions.c @@ -0,0 +1,556 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-gconf-extensions.c - Stuff to make GConf easier to use. + + Copyright (C) 2000, 2001 Eazel, Inc. + + The Gnome Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <ramiro@eazel.com> +*/ + +#include <stdlib.h> +#include <config.h> +#include "eel-gconf-extensions.h" + +#include <gconf/gconf-client.h> +#include <gconf/gconf.h> +#include <gtk/gtkwidget.h> +#include <libgnome/gnome-i18n.h> +#include <gtk/gtkmessagedialog.h> + +static GConfClient *global_gconf_client = NULL; + +static void +global_client_free (void) +{ + if (global_gconf_client == NULL) { + return; + } + + g_object_unref (G_OBJECT (global_gconf_client)); + global_gconf_client = NULL; +} + +/* Public */ +GConfClient * +eel_gconf_client_get_global (void) +{ + /* Initialize gconf if needed */ + if (!gconf_is_initialized ()) { + char *argv[] = { "eel-preferences", NULL }; + GError *error = NULL; + + if (!gconf_init (1, argv, &error)) { + if (eel_gconf_handle_error (&error)) { + return NULL; + } + } + + } + + if (global_gconf_client == NULL) { + global_gconf_client = gconf_client_get_default (); + g_atexit (global_client_free); + } + + return global_gconf_client; +} + +gboolean +eel_gconf_handle_error (GError **error) +{ + g_return_val_if_fail (error != NULL, FALSE); + + if (*error != NULL) { + g_warning (_("GConf error:\n %s"), (*error)->message); + g_error_free (*error); + *error = NULL; + + return TRUE; + } + + return FALSE; +} + +void +eel_gconf_set_boolean (const char *key, + gboolean boolean_value) +{ + GConfClient *client; + GError *error = NULL; + + g_return_if_fail (key != NULL); + + client = eel_gconf_client_get_global (); + g_return_if_fail (client != NULL); + + gconf_client_set_bool (client, key, boolean_value, &error); + eel_gconf_handle_error (&error); +} + +gboolean +eel_gconf_get_boolean (const char *key) +{ + gboolean result; + GConfClient *client; + GError *error = NULL; + + g_return_val_if_fail (key != NULL, FALSE); + + client = eel_gconf_client_get_global (); + g_return_val_if_fail (client != NULL, FALSE); + + result = gconf_client_get_bool (client, key, &error); + + if (eel_gconf_handle_error (&error)) { + result = FALSE; + } + + return result; +} + +void +eel_gconf_set_integer (const char *key, + int int_value) +{ + GConfClient *client; + GError *error = NULL; + + g_return_if_fail (key != NULL); + + client = eel_gconf_client_get_global (); + g_return_if_fail (client != NULL); + + gconf_client_set_int (client, key, int_value, &error); + eel_gconf_handle_error (&error); +} + +int +eel_gconf_get_integer (const char *key) +{ + int result; + GConfClient *client; + GError *error = NULL; + + g_return_val_if_fail (key != NULL, 0); + + client = eel_gconf_client_get_global (); + g_return_val_if_fail (client != NULL, 0); + + result = gconf_client_get_int (client, key, &error); + + if (eel_gconf_handle_error (&error)) { + result = 0; + } + + return result; +} + +void +eel_gconf_set_float (const char *key, + gfloat float_value) +{ + GConfClient *client; + GError *error = NULL; + + g_return_if_fail (key != NULL); + + client = eel_gconf_client_get_global (); + g_return_if_fail (client != NULL); + + gconf_client_set_float (client, key, float_value, &error); + eel_gconf_handle_error (&error); +} + +gfloat +eel_gconf_get_float (const char *key) +{ + gfloat result; + GConfClient *client; + GError *error = NULL; + + g_return_val_if_fail (key != NULL, 0); + + client = eel_gconf_client_get_global (); + g_return_val_if_fail (client != NULL, 0); + + result = gconf_client_get_float (client, key, &error); + + if (eel_gconf_handle_error (&error)) { + result = 0; + } + + return result; +} + +void +eel_gconf_set_string (const char *key, + const char *string_value) +{ + GConfClient *client; + GError *error = NULL; + + g_return_if_fail (key != NULL); + g_return_if_fail (string_value != NULL); + + client = eel_gconf_client_get_global (); + g_return_if_fail (client != NULL); + + gconf_client_set_string (client, key, string_value, &error); + eel_gconf_handle_error (&error); +} + +void +eel_gconf_unset (const char *key) +{ + GConfClient *client; + GError *error = NULL; + + g_return_if_fail (key != NULL); + + client = eel_gconf_client_get_global (); + g_return_if_fail (client != NULL); + + gconf_client_unset (client, key, &error); + eel_gconf_handle_error (&error); +} + +char * +eel_gconf_get_string (const char *key) +{ + char *result; + GConfClient *client; + GError *error = NULL; + + g_return_val_if_fail (key != NULL, NULL); + + client = eel_gconf_client_get_global (); + g_return_val_if_fail (client != NULL, NULL); + + result = gconf_client_get_string (client, key, &error); + + if (eel_gconf_handle_error (&error)) { + result = g_strdup (""); + } + + return result; +} + +void +eel_gconf_set_string_list (const char *key, + const GSList *slist) +{ + GConfClient *client; + GError *error; + + g_return_if_fail (key != NULL); + + client = eel_gconf_client_get_global (); + g_return_if_fail (client != NULL); + + error = NULL; + gconf_client_set_list (client, key, GCONF_VALUE_STRING, + /* Need cast cause of GConf api bug */ + (GSList *) slist, + &error); + eel_gconf_handle_error (&error); +} + +GSList * +eel_gconf_get_string_list (const char *key) +{ + GSList *slist; + GConfClient *client; + GError *error; + + g_return_val_if_fail (key != NULL, NULL); + + client = eel_gconf_client_get_global (); + g_return_val_if_fail (client != NULL, NULL); + + error = NULL; + slist = gconf_client_get_list (client, key, GCONF_VALUE_STRING, &error); + if (eel_gconf_handle_error (&error)) { + slist = NULL; + } + + return slist; +} + +/* This code wasn't part of the original eel-gconf-extensions.c */ +void +eel_gconf_set_integer_list (const char *key, + const GSList *slist) +{ + GConfClient *client; + GError *error; + + g_return_if_fail (key != NULL); + + client = eel_gconf_client_get_global (); + g_return_if_fail (client != NULL); + + error = NULL; + gconf_client_set_list (client, key, GCONF_VALUE_INT, + /* Need cast cause of GConf api bug */ + (GSList *) slist, + &error); + eel_gconf_handle_error (&error); +} + +GSList * +eel_gconf_get_integer_list (const char *key) +{ + GSList *slist; + GConfClient *client; + GError *error; + + g_return_val_if_fail (key != NULL, NULL); + + client = eel_gconf_client_get_global (); + g_return_val_if_fail (client != NULL, NULL); + + error = NULL; + slist = gconf_client_get_list (client, key, GCONF_VALUE_INT, &error); + if (eel_gconf_handle_error (&error)) { + slist = NULL; + } + + return slist; +} +/* End of added code */ + +gboolean +eel_gconf_is_default (const char *key) +{ + gboolean result; + GConfValue *value; + GError *error = NULL; + + g_return_val_if_fail (key != NULL, FALSE); + + value = gconf_client_get_without_default (eel_gconf_client_get_global (), key, &error); + + if (eel_gconf_handle_error (&error)) { + if (value != NULL) { + gconf_value_free (value); + } + return FALSE; + } + + result = (value == NULL); + + if (value != NULL) { + gconf_value_free (value); + } + + + return result; +} + +gboolean +eel_gconf_monitor_add (const char *directory) +{ + GError *error = NULL; + GConfClient *client; + + g_return_val_if_fail (directory != NULL, FALSE); + + client = eel_gconf_client_get_global (); + g_return_val_if_fail (client != NULL, FALSE); + + gconf_client_add_dir (client, + directory, + GCONF_CLIENT_PRELOAD_NONE, + &error); + + if (eel_gconf_handle_error (&error)) { + return FALSE; + } + + return TRUE; +} + +gboolean +eel_gconf_monitor_remove (const char *directory) +{ + GError *error = NULL; + GConfClient *client; + + if (directory == NULL) { + return FALSE; + } + + client = eel_gconf_client_get_global (); + g_return_val_if_fail (client != NULL, FALSE); + + gconf_client_remove_dir (client, + directory, + &error); + + if (eel_gconf_handle_error (&error)) { + return FALSE; + } + + return TRUE; +} + +void +eel_gconf_suggest_sync (void) +{ + GConfClient *client; + GError *error = NULL; + + client = eel_gconf_client_get_global (); + g_return_if_fail (client != NULL); + + gconf_client_suggest_sync (client, &error); + eel_gconf_handle_error (&error); +} + +GConfValue* +eel_gconf_get_value (const char *key) +{ + GConfValue *value = NULL; + GConfClient *client; + GError *error = NULL; + + g_return_val_if_fail (key != NULL, NULL); + + client = eel_gconf_client_get_global (); + g_return_val_if_fail (client != NULL, NULL); + + value = gconf_client_get (client, key, &error); + + if (eel_gconf_handle_error (&error)) { + if (value != NULL) { + gconf_value_free (value); + value = NULL; + } + } + + return value; +} + +void +eel_gconf_set_value (const char *key, GConfValue *value) +{ + GConfClient *client; + GError *error = NULL; + + g_return_if_fail (key != NULL); + + client = eel_gconf_client_get_global (); + g_return_if_fail (client != NULL); + + gconf_client_set (client, key, value, &error); + + if (eel_gconf_handle_error (&error)) { + return; + } +} + +void +eel_gconf_value_free (GConfValue *value) +{ + if (value == NULL) { + return; + } + + gconf_value_free (value); +} + +guint +eel_gconf_notification_add (const char *key, + GConfClientNotifyFunc notification_callback, + gpointer callback_data) +{ + guint notification_id; + GConfClient *client; + GError *error = NULL; + + g_return_val_if_fail (key != NULL, EEL_GCONF_UNDEFINED_CONNECTION); + g_return_val_if_fail (notification_callback != NULL, EEL_GCONF_UNDEFINED_CONNECTION); + + client = eel_gconf_client_get_global (); + g_return_val_if_fail (client != NULL, EEL_GCONF_UNDEFINED_CONNECTION); + + notification_id = gconf_client_notify_add (client, + key, + notification_callback, + callback_data, + NULL, + &error); + + if (eel_gconf_handle_error (&error)) { + if (notification_id != EEL_GCONF_UNDEFINED_CONNECTION) { + gconf_client_notify_remove (client, notification_id); + notification_id = EEL_GCONF_UNDEFINED_CONNECTION; + } + } + + return notification_id; +} + +void +eel_gconf_notification_remove (guint notification_id) +{ + GConfClient *client; + + if (notification_id == EEL_GCONF_UNDEFINED_CONNECTION) { + return; + } + + client = eel_gconf_client_get_global (); + g_return_if_fail (client != NULL); + + gconf_client_notify_remove (client, notification_id); +} + +/* Simple wrapper for eel_gconf_notifier_add which + * adds the notifier id to the GList given as argument + * so that a call to ephy_notification_free can remove the notifiers + */ +void +ephy_notification_add (const char *key, + GConfClientNotifyFunc notification_callback, + gpointer callback_data, + GList **notifiers) +{ + guint id = 0; + + id = eel_gconf_notification_add(key, + notification_callback, + callback_data); + if (notifiers != NULL) { + *notifiers = g_list_append(*notifiers, + (gpointer)id); + } +} + +/* Removes all the notifiers listed in notifiers */ +/* Frees the notifiers list */ +void +ephy_notification_remove (GList **notifiers) +{ + g_list_foreach(*notifiers, + (GFunc)eel_gconf_notification_remove, + NULL); + g_list_free(*notifiers); + *notifiers = NULL; +} + diff --git a/lib/eel-gconf-extensions.h b/lib/eel-gconf-extensions.h new file mode 100644 index 000000000..df51afaa1 --- /dev/null +++ b/lib/eel-gconf-extensions.h @@ -0,0 +1,87 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-gconf-extensions.h - Stuff to make GConf easier to use. + + Copyright (C) 2000, 2001 Eazel, Inc. + + The Gnome Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <ramiro@eazel.com> +*/ + +#ifndef EEL_GCONF_EXTENSIONS_H +#define EEL_GCONF_EXTENSIONS_H + +#include <glib/gerror.h> +#include <gconf/gconf.h> +#include <gconf/gconf-client.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define EEL_GCONF_UNDEFINED_CONNECTION 0 + +GConfClient *eel_gconf_client_get_global (void); +gboolean eel_gconf_handle_error (GError **error); +void eel_gconf_set_boolean (const char *key, + gboolean boolean_value); +gboolean eel_gconf_get_boolean (const char *key); +int eel_gconf_get_integer (const char *key); +void eel_gconf_set_integer (const char *key, + int int_value); +gfloat eel_gconf_get_float (const char *key); +void eel_gconf_set_float (const char *key, + gfloat float_value); +char * eel_gconf_get_string (const char *key); +void eel_gconf_set_string (const char *key, + const char *string_value); +GSList * eel_gconf_get_string_list (const char *key); +void eel_gconf_set_string_list (const char *key, + const GSList *string_list_value); +gboolean eel_gconf_is_default (const char *key); +gboolean eel_gconf_monitor_add (const char *directory); +gboolean eel_gconf_monitor_remove (const char *directory); +void eel_gconf_suggest_sync (void); +GConfValue* eel_gconf_get_value (const char *key); +gboolean eel_gconf_value_is_equal (const GConfValue *a, + const GConfValue *b); +void eel_gconf_set_value (const char *key, GConfValue *value); +void eel_gconf_value_free (GConfValue *value); +void eel_gconf_unset (const char *key); + +/* Functions which weren't part of the eel-gconf-extensions.h file from eel */ +GSList *eel_gconf_get_integer_list (const char *key); +void eel_gconf_set_integer_list (const char *key, + const GSList *slist); +guint eel_gconf_notification_add (const char *key, + GConfClientNotifyFunc notification_callback, + gpointer callback_data); +void eel_gconf_notification_remove (guint notification_id); + +void ephy_notification_add (const char *key, + GConfClientNotifyFunc notification_callback, + gpointer callback_data, + GList **notifiers); + +void ephy_notification_remove (GList **notifiers); + + +#ifdef __cplusplus +} +#endif + +#endif /* EEL_GCONF_EXTENSIONS_H */ diff --git a/lib/ephy-autocompletion-source.c b/lib/ephy-autocompletion-source.c new file mode 100644 index 000000000..717b9924e --- /dev/null +++ b/lib/ephy-autocompletion-source.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2002 Ricardo Fernándezs Pascual <ric@users.sourceforge.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-autocompletion-source.h" +#include "ephy-marshal.h" + +static void ephy_autocompletion_source_base_init (gpointer g_class); + +GType +ephy_autocompletion_source_get_type (void) +{ + static GType autocompletion_source_type = 0; + + if (! autocompletion_source_type) + { + static const GTypeInfo autocompletion_source_info = + { + sizeof (EphyAutocompletionSourceIface), /* class_size */ + ephy_autocompletion_source_base_init, /* base_init */ + NULL, /* base_finalize */ + NULL, + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL + }; + + autocompletion_source_type = g_type_register_static + (G_TYPE_INTERFACE, "EphyAutocompletionSource", &autocompletion_source_info, 0); + g_type_interface_add_prerequisite (autocompletion_source_type, G_TYPE_OBJECT); + } + + return autocompletion_source_type; +} + +static void +ephy_autocompletion_source_base_init (gpointer g_class) +{ + static gboolean initialized = FALSE; + + if (!initialized) + { + g_signal_new ("data-changed", + EPHY_TYPE_AUTOCOMPLETION_SOURCE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyAutocompletionSourceIface, data_changed), + NULL, NULL, + ephy_marshal_VOID__VOID, + G_TYPE_NONE, 0); + initialized = TRUE; + } +} + + +void +ephy_autocompletion_source_foreach (EphyAutocompletionSource *source, + const gchar *basic_key, + EphyAutocompletionSourceForeachFunc func, + gpointer data) +{ + (* EPHY_AUTOCOMPLETION_SOURCE_GET_IFACE (source)->foreach) (source, basic_key, func, data); +} + +void +ephy_autocompletion_source_set_basic_key (EphyAutocompletionSource *source, + const gchar *basic_key) +{ + (* EPHY_AUTOCOMPLETION_SOURCE_GET_IFACE (source)->set_basic_key) (source, basic_key); +} diff --git a/lib/ephy-autocompletion-source.h b/lib/ephy-autocompletion-source.h new file mode 100644 index 000000000..595708b3a --- /dev/null +++ b/lib/ephy-autocompletion-source.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2002 Ricardo Fernándezs Pascual <ric@users.sourceforge.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_AUTOCOMPLETION_SOUCE_H +#define EPHY_AUTOCOMPLETION_SOUCE_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define EPHY_TYPE_AUTOCOMPLETION_SOURCE (ephy_autocompletion_source_get_type ()) +#define EPHY_AUTOCOMPLETION_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + EPHY_TYPE_AUTOCOMPLETION_SOURCE, \ + EphyAutocompletionSource)) +#define EPHY_IS_AUTOCOMPLETION_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + EPHY_TYPE_AUTOCOMPLETION_SOURCE)) +#define EPHY_AUTOCOMPLETION_SOURCE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), \ + EPHY_TYPE_AUTOCOMPLETION_SOURCE, \ + EphyAutocompletionSourceIface)) + + +typedef struct _EphyAutocompletionSource EphyAutocompletionSource; +typedef struct _EphyAutocompletionSourceIface EphyAutocompletionSourceIface; +typedef void (* EphyAutocompletionSourceForeachFunc) (EphyAutocompletionSource *source, + const char *item, + const char *title, + const char *target, + gboolean is_action, + gboolean substring, + guint32 score, + gpointer data); + +struct _EphyAutocompletionSourceIface +{ + GTypeInterface g_iface; + + /* Signals */ + + /** + * Sources MUST emit this signal when theirs data changes, expecially if the + * strings are freed / modified. Otherwise, things will crash. + */ + void (* data_changed) (EphyAutocompletionSource *source); + + /* Virtual Table */ + void (* foreach) (EphyAutocompletionSource *source, + const gchar *basic_key, + EphyAutocompletionSourceForeachFunc func, + gpointer data); + void (* set_basic_key) (EphyAutocompletionSource *source, + const gchar *basic_key); +}; + +GType ephy_autocompletion_source_get_type (void); +void ephy_autocompletion_source_foreach (EphyAutocompletionSource *source, + const gchar *basic_key, + EphyAutocompletionSourceForeachFunc func, + gpointer data); +void ephy_autocompletion_source_set_basic_key (EphyAutocompletionSource *source, + const gchar *basic_key); + +G_END_DECLS + +#endif + diff --git a/lib/ephy-autocompletion.c b/lib/ephy-autocompletion.c new file mode 100644 index 000000000..a3f3348c1 --- /dev/null +++ b/lib/ephy-autocompletion.c @@ -0,0 +1,664 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <string.h> +#include <stdlib.h> + +#include "ephy-autocompletion.h" +#include "ephy-gobject-misc.h" +#include "ephy-marshal.h" + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); + +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +//#define DEBUG_TIME + +#ifdef DEBUG_TIME +#include <glib/gtimer.h> +#endif + +/** + * Private data + */ + +typedef enum { + GAS_NEEDS_REFINE, + GAS_NEEDS_FULL_UPDATE, + GAS_UPDATED +} EphyAutocompletionStatus; + +typedef struct { + EphyAutocompletionMatch *array; + guint num_matches; + guint num_action_matches; + guint array_size; +} ACMatchArray; + +#define ACMA_BASE_SIZE 10240 + +struct _EphyAutocompletionPrivate { + GSList *sources; + + guint nkeys; + gchar **keys; + guint *key_lengths; + gchar **prefixes; + guint *prefix_lengths; + + gchar *common_prefix; + ACMatchArray matches; + EphyAutocompletionStatus status; + gboolean sorted; + gboolean changed; + + gboolean sort_alpha; +}; + +/** + * Private functions, only availble from this file + */ +static void ephy_autocompletion_class_init (EphyAutocompletionClass *klass); +static void ephy_autocompletion_init (EphyAutocompletion *e); +static void ephy_autocompletion_finalize_impl (GObject *o); +static void ephy_autocompletion_reset (EphyAutocompletion *ac); +static void ephy_autocompletion_update_matches (EphyAutocompletion *ac); +static void ephy_autocompletion_update_matches_full (EphyAutocompletion *ac); +static gboolean ephy_autocompletion_sort_by_score (EphyAutocompletion *ac); +static void ephy_autocompletion_data_changed_cb (EphyAutocompletionSource *s, + EphyAutocompletion *ac); + +static void acma_init (ACMatchArray *a); +static void acma_destroy (ACMatchArray *a); +static inline void acma_append (ACMatchArray *a, + EphyAutocompletionMatch *m, + gboolean action); +static void acma_grow (ACMatchArray *a); + + +static gpointer g_object_class; + +/** + * Signals enums and ids + */ +enum EphyAutocompletionSignalsEnum { + EPHY_AUTOCOMPLETION_SOURCES_CHANGED, + EPHY_AUTOCOMPLETION_LAST_SIGNAL +}; +static gint EphyAutocompletionSignals[EPHY_AUTOCOMPLETION_LAST_SIGNAL]; + +/** + * Autocompletion object + */ + +MAKE_GET_TYPE (ephy_autocompletion, "EphyAutocompletion", EphyAutocompletion, + ephy_autocompletion_class_init, ephy_autocompletion_init, G_TYPE_OBJECT); + +static void +ephy_autocompletion_class_init (EphyAutocompletionClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = ephy_autocompletion_finalize_impl; + g_object_class = g_type_class_peek_parent (klass); + + EphyAutocompletionSignals[EPHY_AUTOCOMPLETION_SOURCES_CHANGED] = g_signal_new ( + "sources-changed", G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP, + G_STRUCT_OFFSET (EphyAutocompletionClass, sources_changed), + NULL, NULL, + ephy_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +ephy_autocompletion_init (EphyAutocompletion *ac) +{ + EphyAutocompletionPrivate *p = g_new0 (EphyAutocompletionPrivate, 1); + ac->priv = p; + p->sources = NULL; + p->common_prefix = NULL; + acma_init (&p->matches); + p->status = GAS_NEEDS_FULL_UPDATE; + + p->nkeys = 1; + + p->keys = g_new0 (gchar *, 2); + p->keys[0] = g_strdup (""); + p->key_lengths = g_new0 (guint, 2); + p->key_lengths[0] = 0; + + p->prefixes = g_new0 (gchar *, 2); + p->prefixes[0] = g_strdup (""); + p->prefix_lengths = g_new0 (guint, 2); + p->prefix_lengths[0] = 0; + + p->sort_alpha = TRUE; +} + +static void +ephy_autocompletion_finalize_impl (GObject *o) +{ + EphyAutocompletion *ac = EPHY_AUTOCOMPLETION (o); + EphyAutocompletionPrivate *p = ac->priv; + GSList *li; + + ephy_autocompletion_reset (ac); + + for (li = p->sources; li; li = li->next) + { + g_signal_handlers_disconnect_by_func (li->data, + ephy_autocompletion_data_changed_cb, ac); + g_object_unref (li->data); + } + + g_slist_free (p->sources); + + g_strfreev (p->keys); + g_free (p->key_lengths); + g_strfreev (p->prefixes); + g_free (p->prefix_lengths); + + G_OBJECT_CLASS (g_object_class)->finalize (o); + +} + +static void +ephy_autocompletion_reset (EphyAutocompletion *ac) +{ + EphyAutocompletionPrivate *p = ac->priv; +#ifdef DEBUG_TIME + GTimer *timer = g_timer_new (); + g_timer_start (timer); +#endif + acma_destroy (&p->matches); + g_free (p->common_prefix); + p->common_prefix = NULL; + p->status = GAS_NEEDS_FULL_UPDATE; +#ifdef DEBUG_TIME + DEBUG_MSG (("AC: %f elapsed resetting\n", g_timer_elapsed (timer, NULL))); + g_timer_destroy (timer); +#endif +} + +EphyAutocompletion * +ephy_autocompletion_new (void) +{ + EphyAutocompletion *ret = g_object_new (EPHY_TYPE_AUTOCOMPLETION, NULL); + return ret; +} +void +ephy_autocompletion_add_source (EphyAutocompletion *ac, + EphyAutocompletionSource *s) +{ + EphyAutocompletionPrivate *p = ac->priv; + g_object_ref (G_OBJECT (s)); + p->sources = g_slist_prepend (p->sources, s); + ephy_autocompletion_reset (ac); + g_signal_connect (s, "data-changed", G_CALLBACK (ephy_autocompletion_data_changed_cb), ac); + + g_signal_emit (ac, EphyAutocompletionSignals[EPHY_AUTOCOMPLETION_SOURCES_CHANGED], 0); +} + +void +ephy_autocompletion_set_key (EphyAutocompletion *ac, + const gchar *key) +{ + EphyAutocompletionPrivate *p = ac->priv; + guint i; + guint keylen = strlen (key); + + if (strcmp (key, p->keys[0])) + { + GSList *li; + for (li = p->sources; li; li = li->next) + { + ephy_autocompletion_source_set_basic_key + (EPHY_AUTOCOMPLETION_SOURCE (li->data), key); + } + } + + if (keylen >= p->key_lengths[0] + && !strncmp (p->keys[0], key, p->key_lengths[0])) + { + if (!strcmp (key, p->keys[0])) + { + return; + } + if (p->status != GAS_NEEDS_FULL_UPDATE) + { + p->status = GAS_NEEDS_REFINE; + } + if (p->common_prefix) + { + if (strncmp (p->common_prefix, key, keylen)) + { + g_free (p->common_prefix); + p->common_prefix = NULL; + } + } + } + else + { + p->status = GAS_NEEDS_FULL_UPDATE; + g_free (p->common_prefix); + p->common_prefix = NULL; + } + + for (i = 0; p->prefixes[i]; ++i) + { + g_free (p->keys[i]); + p->keys[i] = g_strconcat (p->prefixes[i], key, NULL); + p->key_lengths[i] = keylen + p->prefix_lengths[i]; + } + +} + +gchar * +ephy_autocompletion_get_common_prefix (EphyAutocompletion *ac) +{ + EphyAutocompletionPrivate *p = ac->priv; + ephy_autocompletion_update_matches (ac); + if (!p->common_prefix) + { + guint common_length = 0; + guint i; +#ifdef DEBUG_TIME + GTimer *timer = g_timer_new (); + g_timer_start (timer); +#endif + for (i = 0; i < p->matches.num_matches; i++) + { + EphyAutocompletionMatch *mi = &p->matches.array[i]; + const gchar *realmatch = mi->title + mi->offset; + if (!p->common_prefix) + { + p->common_prefix = g_strdup (realmatch); + common_length = strlen (p->common_prefix); + continue; + } + else if (!strncmp (realmatch, p->common_prefix, common_length)) + { + continue; + } + else + { + common_length = 0; + while (realmatch[common_length] + && realmatch[common_length] == p->common_prefix[common_length]) + { + ++common_length; + } + g_free (p->common_prefix); + p->common_prefix = g_strndup (realmatch, common_length); + } + } +#ifdef DEBUG_TIME + DEBUG_MSG (("AC: %f elapsed calculating common prefix\n", g_timer_elapsed (timer, NULL))); + g_timer_destroy (timer); +#endif + } + return g_strdup (p->common_prefix); +} + +const EphyAutocompletionMatch * +ephy_autocompletion_get_matches (EphyAutocompletion *ac) +{ + ephy_autocompletion_update_matches (ac); + return ac->priv->matches.array; +} + +const EphyAutocompletionMatch * +ephy_autocompletion_get_matches_sorted_by_score (EphyAutocompletion *ac, + gboolean *changed) +{ + *changed = ephy_autocompletion_sort_by_score (ac); + return ac->priv->matches.array; +} + +guint +ephy_autocompletion_get_num_matches (EphyAutocompletion *ac) +{ + ephy_autocompletion_update_matches (ac); + + return ac->priv->matches.num_matches; +} + +guint +ephy_autocompletion_get_num_action_matches (EphyAutocompletion *ac) +{ + return ac->priv->matches.num_matches - + ac->priv->matches.num_action_matches; +} + +static void +ephy_autocompletion_refine_matches (EphyAutocompletion *ac) +{ + EphyAutocompletionPrivate *p = ac->priv; + ACMatchArray oldmatches = p->matches; + ACMatchArray newmatches; + guint i; + gchar *key0 = p->keys[0]; + guint key0l = p->key_lengths[0]; +#ifdef DEBUG_TIME + GTimer *timer = g_timer_new (); +#endif + DEBUG_MSG (("AC: refining\n")); + +#ifdef DEBUG_TIME + g_timer_start (timer); +#endif + acma_init (&newmatches); + + p->changed = FALSE; + + for (i = 0; i < oldmatches.num_matches; i++) + { + EphyAutocompletionMatch *mi = &oldmatches.array[i]; + if (mi->is_action || + (mi->substring && g_strrstr (mi->match, p->keys[0])) || + !strncmp (key0, mi->title + mi->offset, key0l)) + { + acma_append (&newmatches, mi, mi->is_action); + } + else + { + p->changed = TRUE; + } + } + + acma_destroy (&oldmatches); + p->matches = newmatches; + +#ifdef DEBUG_TIME + DEBUG_MSG (("AC: %f elapsed refining\n", g_timer_elapsed (timer, NULL))); + g_timer_destroy (timer); +#endif + DEBUG_MSG (("AC: %d matches\n", p->matches.num_matches)); +} + +static void +ephy_autocompletion_update_matches (EphyAutocompletion *ac) +{ + EphyAutocompletionPrivate *p = ac->priv; + if (p->status == GAS_UPDATED) + { + return; + } + if (p->status == GAS_NEEDS_FULL_UPDATE) + { + ephy_autocompletion_update_matches_full (ac); + } + if (p->status == GAS_NEEDS_REFINE) + { + /* FIXME we do full update for now */ + ephy_autocompletion_refine_matches (ac); + } + + g_free (p->common_prefix); + p->common_prefix = NULL; + p->status = GAS_UPDATED; +} + +static void +ephy_autocompletion_update_matches_full_item (EphyAutocompletionSource *source, + const char *item, + const char *title, + const char *target, + gboolean is_action, + gboolean substring, + guint32 score, + EphyAutocompletionPrivate *p) +{ + if (is_action || + (substring && g_strrstr (item, p->keys[0]))) + { + EphyAutocompletionMatch m; + m.match = item; + m.title = title; + m.target = target; + m.is_action = is_action; + m.substring = substring; + m.offset = 0; + m.score = score; + acma_append (&p->matches, &m, is_action); + } + else + { + guint i; + for (i = 0; p->keys[i]; ++i) + { + if (!strncmp (item, p->keys[i], p->key_lengths[i])) + { + EphyAutocompletionMatch m; + m.match = item; + m.title = title; + m.target = target; + m.is_action = is_action; + m.substring = substring; + m.offset = p->prefix_lengths[i]; + m.score = score; + acma_append (&p->matches, &m, is_action); + } + } + } +} + +static void +ephy_autocompletion_update_matches_full (EphyAutocompletion *ac) +{ + EphyAutocompletionPrivate *p = ac->priv; + GSList *li; +#ifdef DEBUG_TIME + GTimer *timer = g_timer_new (); +#endif + + DEBUG_MSG (("AC: fully updating\n")); + ephy_autocompletion_reset (ac); + +#ifdef DEBUG_TIME + g_timer_start (timer); +#endif + for (li = p->sources; li; li = li->next) + { + EphyAutocompletionSource *s = EPHY_AUTOCOMPLETION_SOURCE (li->data); + g_assert (s); + ephy_autocompletion_source_foreach (s, p->keys[0], + (EphyAutocompletionSourceForeachFunc) + ephy_autocompletion_update_matches_full_item, + p); + } +#ifdef DEBUG_TIME + DEBUG_MSG (("AC: %f elapsed fully updating\n", g_timer_elapsed (timer, NULL))); + g_timer_destroy (timer); +#endif + + p->sorted = FALSE; + p->changed = TRUE; + + DEBUG_MSG (("AC: %d matches, fully updated\n", p->matches.num_matches)); +} + +static gint +ephy_autocompletion_compare_scores (EphyAutocompletionMatch *a, EphyAutocompletionMatch *b) +{ + /* higher scores first */ + return b->score - a->score; +} + +static gint +ephy_autocompletion_compare_scores_and_alpha (EphyAutocompletionMatch *a, EphyAutocompletionMatch *b) +{ + if (a->score == b->score) + { + return strcmp (a->title, b->title); + } + else + { + /* higher scores first */ + return b->score - a->score; + } +} + +static gboolean +ephy_autocompletion_sort_by_score (EphyAutocompletion *ac) +{ + EphyAutocompletionPrivate *p = ac->priv; +#ifdef DEBUG_TIME + GTimer *timer; +#endif + gint (*comparer) (EphyAutocompletionMatch *m1, EphyAutocompletionMatch *m2); + + if (p->sort_alpha) + { + comparer = ephy_autocompletion_compare_scores_and_alpha; + } + else + { + comparer = ephy_autocompletion_compare_scores; + } + + ephy_autocompletion_update_matches (ac); + if (p->changed == FALSE) return FALSE; + + DEBUG_MSG (("AC: sorting\n")); +#ifdef DEBUG_TIME + timer = g_timer_new (); + g_timer_start (timer); +#endif + if (p->matches.num_matches > 0) + { + qsort (p->matches.array, p->matches.num_matches, + sizeof (EphyAutocompletionMatch), + (void *) comparer); + } + + p->sorted = TRUE; + +#ifdef DEBUG_TIME + DEBUG_MSG (("AC: %f elapsed sorting by score\n", g_timer_elapsed (timer, NULL))); + g_timer_destroy (timer); +#endif + return TRUE; +} + +static void +ephy_autocompletion_data_changed_cb (EphyAutocompletionSource *s, + EphyAutocompletion *ac) +{ + DEBUG_MSG (("AC: data changed, reseting\n")); + ephy_autocompletion_reset (ac); + + g_signal_emit (ac, EphyAutocompletionSignals[EPHY_AUTOCOMPLETION_SOURCES_CHANGED], 0); +} + +void +ephy_autocompletion_set_prefixes (EphyAutocompletion *ac, + const gchar **prefixes) +{ + EphyAutocompletionPrivate *p = ac->priv; + guint nprefixes = 0; + gchar *oldkey = g_strdup (p->keys[0]); + guint i; + + /* count prefixes */ + while (prefixes[nprefixes]) + { + ++nprefixes; + } + + nprefixes--; + + g_strfreev (p->keys); + g_free (p->key_lengths); + g_strfreev (p->prefixes); + g_free (p->prefix_lengths); + + p->prefixes = g_new0 (gchar *, nprefixes + 2); + p->prefix_lengths = g_new0 (guint, nprefixes + 2); + p->keys = g_new0 (gchar *, nprefixes + 2); + p->key_lengths = g_new0 (guint, nprefixes + 2); + + p->prefixes[0] = g_strdup (""); + p->prefix_lengths[0] = 0; + p->keys[0] = oldkey; + p->key_lengths[0] = strlen (p->keys[0]); + + for (i = 0; i < nprefixes; ++i) + { + p->prefixes[i + 1] = g_strdup (prefixes[i]); + p->prefix_lengths[i + 1] = strlen (prefixes[i]); + p->keys[i + 1] = g_strconcat (p->prefixes[i + 1], p->keys[0], NULL); + p->key_lengths[i + 1] = p->prefix_lengths[i + 1] + p->key_lengths[0]; + } + + p->nkeys = nprefixes; +} + + +/* ACMatchArray */ + +static void +acma_init (ACMatchArray *a) +{ + a->array = NULL; + a->array_size = 0; + a->num_matches = 0; +} + +/** + * Does not free the struct itself, only its contents + */ +static void +acma_destroy (ACMatchArray *a) +{ + g_free (a->array); + a->array = NULL; + a->array_size = 0; + a->num_matches = 0; + a->num_action_matches = 0; +} + +static inline void +acma_append (ACMatchArray *a, + EphyAutocompletionMatch *m, + gboolean action) +{ + if (a->array_size == a->num_matches) + { + acma_grow (a); + } + + a->array[a->num_matches] = *m; + a->num_matches++; + if (action) a->num_action_matches++; +} + +static void +acma_grow (ACMatchArray *a) +{ + gint new_size; + EphyAutocompletionMatch *new_array; + + new_size = a->array_size + ACMA_BASE_SIZE; + new_array = g_renew (EphyAutocompletionMatch, a->array, new_size); + + a->array_size = new_size; + a->array = new_array; +} + + diff --git a/lib/ephy-autocompletion.h b/lib/ephy-autocompletion.h new file mode 100644 index 000000000..06dcc71dc --- /dev/null +++ b/lib/ephy-autocompletion.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_AUTOCOMPLETION_H +#define EPHY_AUTOCOMPLETION_H + +#include <glib-object.h> +#include "ephy-autocompletion-source.h" + +G_BEGIN_DECLS + +/* object forward declarations */ + +typedef struct _EphyAutocompletion EphyAutocompletion; +typedef struct _EphyAutocompletionClass EphyAutocompletionClass; +typedef struct _EphyAutocompletionPrivate EphyAutocompletionPrivate; +typedef struct _EphyAutocompletionMatch EphyAutocompletionMatch; + +/** + * EphyAutocompletion object + */ + +#define EPHY_TYPE_AUTOCOMPLETION (ephy_autocompletion_get_type()) +#define EPHY_AUTOCOMPLETION(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \ + EPHY_TYPE_AUTOCOMPLETION,\ + EphyAutocompletion)) +#define EPHY_AUTOCOMPLETION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \ + EPHY_TYPE_AUTOCOMPLETION,\ + EphyAutocompletionClass)) +#define EPHY_IS_AUTOCOMPLETION(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \ + EPHY_TYPE_AUTOCOMPLETION)) +#define EPHY_IS_AUTOCOMPLETION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \ + EPHY_TYPE_AUTOCOMPLETION)) +#define EPHY_AUTOCOMPLETION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ + EPHY_TYPE_AUTOCOMPLETION,\ + EphyAutocompletionClass)) + +struct _EphyAutocompletionClass +{ + GObjectClass parent_class; + + /* signals */ + void (*sources_changed) (EphyAutocompletion *ac); +}; + +/* Remember: fields are public read-only */ +struct _EphyAutocompletion +{ + GObject parent_object; + + EphyAutocompletionPrivate *priv; +}; + +struct _EphyAutocompletionMatch +{ + const char *match; + const char *title; + const char *target; + guint offset; + gint32 score; + gboolean is_action; + gboolean substring; +}; + +/* this is a set of usual prefixes for web browsing */ +#define EPHY_AUTOCOMPLETION_USUAL_WEB_PREFIXES \ + "http://www.", \ + "http://", \ + "https://www.", \ + "https://", \ + "file://", \ + "www." + +GType ephy_autocompletion_get_type (void); +EphyAutocompletion * ephy_autocompletion_new (void); +void ephy_autocompletion_add_source (EphyAutocompletion *ac, + EphyAutocompletionSource *s); +void ephy_autocompletion_set_prefixes (EphyAutocompletion *ac, + const gchar **prefixes); +void ephy_autocompletion_set_key (EphyAutocompletion *ac, + const gchar *key); +gchar * ephy_autocompletion_get_common_prefix (EphyAutocompletion *ac); +const EphyAutocompletionMatch *ephy_autocompletion_get_matches (EphyAutocompletion *ac); +const EphyAutocompletionMatch *ephy_autocompletion_get_matches_sorted_by_score + (EphyAutocompletion *ac, + gboolean *changed); +guint ephy_autocompletion_get_num_matches (EphyAutocompletion *ac); +guint ephy_autocompletion_get_num_action_matches (EphyAutocompletion *ac); + +G_END_DECLS + +#endif diff --git a/lib/ephy-bonobo-extensions.c b/lib/ephy-bonobo-extensions.c new file mode 100644 index 000000000..e40b377cd --- /dev/null +++ b/lib/ephy-bonobo-extensions.c @@ -0,0 +1,679 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* gul-bonobo-extensions.c - implementation of new functions that conceptually + belong in bonobo. Perhaps some of these will be + actually rolled into bonobo someday. + + This file is based on nautilus-bonobo-extensions.c from + libnautilus-private. + + Copyright (C) 2000, 2001 Eazel, Inc. + + The Gnome Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: John Sullivan <sullivan@eazel.com> + Darin Adler <darin@bentspoon.com> +*/ + +#include <config.h> + +#include "ephy-bonobo-extensions.h" +#include "ephy-string.h" +#include <string.h> + +#include <bonobo/bonobo-ui-util.h> +#include <gtk/gtkmain.h> +#include <libgnomevfs/gnome-vfs-utils.h> +#include <bonobo/bonobo-control.h> + +typedef enum { + NUMBERED_MENU_ITEM_PLAIN, + NUMBERED_MENU_ITEM_TOGGLE, + NUMBERED_MENU_ITEM_RADIO +} NumberedMenuItemType; + +void +ephy_bonobo_set_accelerator (BonoboUIComponent *ui, + const char *path, + const char *accelerator) +{ + if (bonobo_ui_component_get_container (ui)) /* should not do this here... */ + { + bonobo_ui_component_set_prop (ui, path, "accel", accelerator, NULL); + } +} + +void +ephy_bonobo_set_label (BonoboUIComponent *ui, + const char *path, + const char *label) +{ + if (bonobo_ui_component_get_container (ui)) /* should not do this here... */ + { + bonobo_ui_component_set_prop (ui, path, "label", label, NULL); + } +} + +void +ephy_bonobo_set_tip (BonoboUIComponent *ui, + const char *path, + const char *tip) +{ + if (bonobo_ui_component_get_container (ui)) /* should not do this here... */ + { + bonobo_ui_component_set_prop (ui, path, "tip", tip, NULL); + } +} + +void +ephy_bonobo_set_sensitive (BonoboUIComponent *ui, + const char *path, + gboolean sensitive) +{ + if (bonobo_ui_component_get_container (ui)) /* should not do this here... */ + { + bonobo_ui_component_set_prop (ui, path, "sensitive", sensitive ? "1" : "0", NULL); + } +} + +void +ephy_bonobo_set_toggle_state (BonoboUIComponent *ui, + const char *path, + gboolean state) +{ + if (bonobo_ui_component_get_container (ui)) /* should not do this here... */ + { + bonobo_ui_component_set_prop (ui, path, "state", state ? "1" : "0", NULL); + } +} + +void +ephy_bonobo_set_hidden (BonoboUIComponent *ui, + const char *path, + gboolean hidden) +{ + if (bonobo_ui_component_get_container (ui)) /* should not do this here... */ + { + bonobo_ui_component_set_prop (ui, path, "hidden", hidden ? "1" : "0", NULL); + } +} + +char * +ephy_bonobo_get_label (BonoboUIComponent *ui, + const char *path) +{ + if (bonobo_ui_component_get_container (ui)) /* should not do this here... */ + { + return bonobo_ui_component_get_prop (ui, path, "label", NULL); + } + else + { + return NULL; + } +} + +gboolean +ephy_bonobo_get_hidden (BonoboUIComponent *ui, + const char *path) +{ + char *value; + gboolean hidden; + CORBA_Environment ev; + + g_return_val_if_fail (BONOBO_IS_UI_COMPONENT (ui), FALSE); + g_return_val_if_fail (path != NULL, FALSE); + + CORBA_exception_init (&ev); + value = bonobo_ui_component_get_prop (ui, path, "hidden", &ev); + CORBA_exception_free (&ev); + + if (value == NULL) { + /* No hidden attribute means not hidden. */ + hidden = FALSE; + } else { + /* Anything other than "0" counts as TRUE */ + hidden = strcmp (value, "0") != 0; + g_free (value); + } + + return hidden; +} + +static char * +get_numbered_menu_item_name (guint index) +{ + return g_strdup_printf ("%u", index); +} + +char * +ephy_bonobo_get_numbered_menu_item_path (BonoboUIComponent *ui, + const char *container_path, + guint index) +{ + char *item_name; + char *item_path; + + g_return_val_if_fail (BONOBO_IS_UI_COMPONENT (ui), NULL); + g_return_val_if_fail (container_path != NULL, NULL); + + item_name = get_numbered_menu_item_name (index); + item_path = g_strconcat (container_path, "/", item_name, NULL); + g_free (item_name); + + return item_path; +} + +char * +ephy_bonobo_get_numbered_menu_item_command (BonoboUIComponent *ui, + const char *container_path, + guint index) +{ + char *command_name; + char *path; + + g_return_val_if_fail (BONOBO_IS_UI_COMPONENT (ui), NULL); + g_return_val_if_fail (container_path != NULL, NULL); + + path = ephy_bonobo_get_numbered_menu_item_path (ui, container_path, index); + command_name = gnome_vfs_escape_string (path); + g_free (path); + + return command_name; +} + +guint +ephy_bonobo_get_numbered_menu_item_index_from_command (const char *command) +{ + char *path; + char *index_string; + int index; + gboolean got_index; + + path = gnome_vfs_unescape_string (command, NULL); + index_string = strrchr (path, '/'); + + if (index_string == NULL) { + got_index = FALSE; + } else { + got_index = ephy_str_to_int (index_string + 1, &index); + } + g_free (path); + + g_return_val_if_fail (got_index, 0); + + return index; +} + +char * +ephy_bonobo_get_numbered_menu_item_container_path_from_command (const char *command) +{ + char *path; + char *index_string; + char *container_path; + + path = gnome_vfs_unescape_string (command, NULL); + index_string = strrchr (path, '/'); + + container_path = index_string == NULL + ? NULL + : g_strndup (path, index_string - path); + g_free (path); + + return container_path; +} + +static char * +ephy_bonobo_add_numbered_menu_item_internal (BonoboUIComponent *ui, + const char *container_path, + guint index, + const char *label, + NumberedMenuItemType type, + GdkPixbuf *pixbuf, + const char *radio_group_name) +{ + char *xml_item, *xml_command; + char *command_name; + char *item_name, *pixbuf_data; + char *path; + + g_assert (BONOBO_IS_UI_COMPONENT (ui)); + g_assert (container_path != NULL); + g_assert (label != NULL); + g_assert (type == NUMBERED_MENU_ITEM_PLAIN || pixbuf == NULL); + g_assert (type == NUMBERED_MENU_ITEM_RADIO || radio_group_name == NULL); + g_assert (type != NUMBERED_MENU_ITEM_RADIO || radio_group_name != NULL); + + item_name = get_numbered_menu_item_name (index); + command_name = ephy_bonobo_get_numbered_menu_item_command + (ui, container_path, index); + + switch (type) { + case NUMBERED_MENU_ITEM_TOGGLE: + xml_item = g_strdup_printf ("<menuitem name=\"%s\" id=\"%s\" type=\"toggle\"/>\n", + item_name, command_name); + break; + case NUMBERED_MENU_ITEM_RADIO: + xml_item = g_strdup_printf ("<menuitem name=\"%s\" id=\"%s\" " + "type=\"radio\" group=\"%s\"/>\n", + item_name, command_name, radio_group_name); + break; + case NUMBERED_MENU_ITEM_PLAIN: + if (pixbuf != NULL) { + pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf); + xml_item = g_strdup_printf ("<menuitem name=\"%s\" verb=\"%s\" " + "pixtype=\"pixbuf\" pixname=\"%s\"/>\n", + item_name, command_name, pixbuf_data); + g_free (pixbuf_data); + } else { + xml_item = g_strdup_printf ("<menuitem name=\"%s\" verb=\"%s\"/>\n", + item_name, command_name); + } + break; + default: + g_assert_not_reached (); + xml_item = NULL; /* keep compiler happy */ + } + + g_free (item_name); + + bonobo_ui_component_set (ui, container_path, xml_item, NULL); + + g_free (xml_item); + + path = ephy_bonobo_get_numbered_menu_item_path (ui, container_path, index); + ephy_bonobo_set_label (ui, path, label); + g_free (path); + + /* Make the command node here too, so callers can immediately set + * properties on it (otherwise it doesn't get created until some + * time later). + */ + xml_command = g_strdup_printf ("<cmd name=\"%s\"/>\n", command_name); + bonobo_ui_component_set (ui, "/commands", xml_command, NULL); + g_free (xml_command); + + g_free (command_name); + + return item_name; +} + +/* Add a menu item specified by number into a given path. Used for + * dynamically creating a related series of menu items. Each index + * must be unique (normal use is to call this in a loop, and + * increment the index for each item). + */ +void +ephy_bonobo_add_numbered_menu_item (BonoboUIComponent *ui, + const char *container_path, + guint index, + const char *label, + GdkPixbuf *pixbuf) +{ + g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui)); + g_return_if_fail (container_path != NULL); + g_return_if_fail (label != NULL); + + ephy_bonobo_add_numbered_menu_item_internal (ui, container_path, index, label, + NUMBERED_MENU_ITEM_PLAIN, pixbuf, NULL); +} + +/* Add a menu item specified by number into a given path. Used for + * dynamically creating a related series of toggle menu items. Each index + * must be unique (normal use is to call this in a loop, and + * increment the index for each item). + */ +void +ephy_bonobo_add_numbered_toggle_menu_item (BonoboUIComponent *ui, + const char *container_path, + guint index, + const char *label) +{ + g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui)); + g_return_if_fail (container_path != NULL); + g_return_if_fail (label != NULL); + + ephy_bonobo_add_numbered_menu_item_internal (ui, container_path, index, label, + NUMBERED_MENU_ITEM_TOGGLE, NULL, NULL); +} + +/* Add a menu item specified by number into a given path. Used for + * dynamically creating a related series of radio menu items. Each index + * must be unique (normal use is to call this in a loop, and + * increment the index for each item). + */ +void +ephy_bonobo_add_numbered_radio_menu_item (BonoboUIComponent *ui, + const char *container_path, + guint index, + const char *label, + const char *radio_group_name) +{ + g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui)); + g_return_if_fail (container_path != NULL); + g_return_if_fail (label != NULL); + + ephy_bonobo_add_numbered_menu_item_internal (ui, container_path, index, label, + NUMBERED_MENU_ITEM_RADIO, NULL, radio_group_name); +} + +void +ephy_bonobo_add_numbered_submenu (BonoboUIComponent *ui, + const char *container_path, + guint index, + const char *label, + GdkPixbuf *pixbuf) +{ + char *xml_string, *item_name, *pixbuf_data, *submenu_path, *command_name; + + g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui)); + g_return_if_fail (container_path != NULL); + g_return_if_fail (label != NULL); + g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf)); + + item_name = get_numbered_menu_item_name (index); + command_name = ephy_bonobo_get_numbered_menu_item_command (ui, container_path, index); + + if (pixbuf != NULL) { + pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf); + xml_string = g_strdup_printf ("<submenu name=\"%s\" pixtype=\"pixbuf\" pixname=\"%s\" " + "verb=\"%s\"/>\n", + item_name, pixbuf_data, command_name); + g_free (pixbuf_data); + } else { + xml_string = g_strdup_printf ("<submenu name=\"%s\" verb=\"%s\"/>\n", item_name, + command_name); + } + + bonobo_ui_component_set (ui, container_path, xml_string, NULL); + + g_free (xml_string); + + submenu_path = ephy_bonobo_get_numbered_menu_item_path (ui, container_path, index); + ephy_bonobo_set_label (ui, submenu_path, label); + g_free (submenu_path); + + g_free (item_name); + g_free (command_name); +} + +void +ephy_bonobo_add_numbered_submenu_no_verb (BonoboUIComponent *ui, + const char *container_path, + guint index, + const char *label, + GdkPixbuf *pixbuf) +{ + char *xml_string, *item_name, *pixbuf_data, *submenu_path; + + g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui)); + g_return_if_fail (container_path != NULL); + g_return_if_fail (label != NULL); + g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf)); + + item_name = get_numbered_menu_item_name (index); + + if (pixbuf != NULL) { + pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf); + xml_string = g_strdup_printf ("<submenu name=\"%s\" pixtype=\"pixbuf\" pixname=\"%s\" " + "/>\n", + item_name, pixbuf_data); + g_free (pixbuf_data); + } else { + xml_string = g_strdup_printf ("<submenu name=\"%s\"/>\n", item_name); + } + + bonobo_ui_component_set (ui, container_path, xml_string, NULL); + + g_free (xml_string); + + submenu_path = ephy_bonobo_get_numbered_menu_item_path (ui, container_path, index); + ephy_bonobo_set_label (ui, submenu_path, label); + g_free (submenu_path); + + g_free (item_name); +} + +void +ephy_bonobo_add_submenu (BonoboUIComponent *ui, + const char *path, + const char *label, + GdkPixbuf *pixbuf) +{ + char *xml_string, *name, *pixbuf_data, *submenu_path; + + g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui)); + g_return_if_fail (path != NULL); + g_return_if_fail (label != NULL); + g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf)); + + /* Labels may contain characters that are illegal in names. So + * we create the name by URI-encoding the label. + */ + name = gnome_vfs_escape_string (label); + + if (pixbuf != NULL) { + pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf); + xml_string = g_strdup_printf ("<submenu name=\"%s\" pixtype=\"pixbuf\" pixname=\"%s\"/>\n", + name, pixbuf_data); + g_free (pixbuf_data); + } else { + xml_string = g_strdup_printf ("<submenu name=\"%s\"/>\n", name); + } + + bonobo_ui_component_set (ui, path, xml_string, NULL); + + g_free (xml_string); + + submenu_path = g_strconcat (path, "/", name, NULL); + ephy_bonobo_set_label (ui, submenu_path, label); + g_free (submenu_path); + + g_free (name); +} + +void +ephy_bonobo_add_menu_separator (BonoboUIComponent *ui, const char *path) +{ + static gint hack = 0; + gchar *xml; + + g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui)); + g_return_if_fail (path != NULL); + + xml = g_strdup_printf ("<separator name=\"sep%d\"/>", ++hack); + bonobo_ui_component_set (ui, path, xml, NULL); + g_free (xml); +} + +static void +remove_commands (BonoboUIComponent *ui, const char *container_path) +{ + BonoboUINode *path_node; + BonoboUINode *child_node; + char *verb_name; + char *id_name; + + path_node = bonobo_ui_component_get_tree (ui, container_path, TRUE, NULL); + if (path_node == NULL) { + return; + } + + bonobo_ui_component_freeze (ui, NULL); + + for (child_node = bonobo_ui_node_children (path_node); + child_node != NULL; + child_node = bonobo_ui_node_next (child_node)) { + verb_name = bonobo_ui_node_get_attr (child_node, "verb"); + if (verb_name != NULL) { + bonobo_ui_component_remove_verb (ui, verb_name); + bonobo_ui_node_free_string (verb_name); + } else { + /* Only look for an id if there's no verb */ + id_name = bonobo_ui_node_get_attr (child_node, "id"); + if (id_name != NULL) { + bonobo_ui_component_remove_listener (ui, id_name); + bonobo_ui_node_free_string (id_name); + } + } + } + + bonobo_ui_component_thaw (ui, NULL); + + bonobo_ui_node_free (path_node); +} + +/** + * ephy_bonobo_remove_menu_items_and_verbs + * + * Removes all menu items contained in a menu or placeholder, and + * their verbs. + * + * @uih: The BonoboUIHandler for this menu item. + * @container_path: The standard bonobo-style path specifier for this placeholder or submenu. + */ +void +ephy_bonobo_remove_menu_items_and_commands (BonoboUIComponent *ui, + const char *container_path) +{ + char *remove_wildcard; + + g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui)); + g_return_if_fail (container_path != NULL); + + remove_commands (ui, container_path); + + /* For speed, remove menu items themselves all in one fell swoop, + * though we removed the verbs one-by-one. + */ + remove_wildcard = g_strdup_printf ("%s/*", container_path); + bonobo_ui_component_rm (ui, remove_wildcard, NULL); + g_free (remove_wildcard); +} + +/* Call to set the user-visible label of a menu item to a string + * containing an underscore accelerator. The underscore is stripped + * off before setting the label of the command, because pop-up menu + * and toolbar button labels shouldn't have the underscore. + */ +void +ephy_bonobo_set_label_for_menu_item_and_command (BonoboUIComponent *ui, + const char *menu_item_path, + const char *command_path, + const char *label_with_underscore) +{ + char *label_no_underscore; + + g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui)); + g_return_if_fail (menu_item_path != NULL); + g_return_if_fail (command_path != NULL); + g_return_if_fail (label_with_underscore != NULL); + + label_no_underscore = ephy_str_strip_chr (label_with_underscore, '_'); + ephy_bonobo_set_label (ui, + menu_item_path, + label_with_underscore); + ephy_bonobo_set_label (ui, + command_path, + label_no_underscore); + + g_free (label_no_underscore); +} + +gchar * +ephy_bonobo_add_dockitem (BonoboUIComponent *uic, + const char *name, + int band_num) +{ + gchar *xml; + gchar *sname; + gchar *path; + + sname = gnome_vfs_escape_string (name); + xml = g_strdup_printf ("<dockitem name=\"%s\" band_num=\"%d\" " + "config=\"0\" behavior=\"exclusive\"/>", + sname, band_num); + path = g_strdup_printf ("/%s", sname); + bonobo_ui_component_set (uic, "", xml, NULL); + + g_free (sname); + g_free (xml); + return path; +} + +BonoboControl * +ephy_bonobo_add_numbered_control (BonoboUIComponent *uic, GtkWidget *w, + guint index, const char *container_path) +{ + BonoboControl *control; + char *xml_string, *item_name, *control_path; + + g_return_val_if_fail (BONOBO_IS_UI_COMPONENT (uic), NULL); + g_return_val_if_fail (container_path != NULL, NULL); + + item_name = get_numbered_menu_item_name (index); + xml_string = g_strdup_printf ("<control name=\"%s\"/>", item_name); + + bonobo_ui_component_set (uic, container_path, xml_string, NULL); + + g_free (xml_string); + + control_path = ephy_bonobo_get_numbered_menu_item_path (uic, container_path, index); + + control = bonobo_control_new (w); + bonobo_ui_component_object_set (uic, control_path, BONOBO_OBJREF (control), NULL); + bonobo_object_unref (control); + + g_free (control_path); + g_free (item_name); + + return control; +} + +void +ephy_bonobo_replace_path (BonoboUIComponent *uic, const gchar *path_src, + const char *path_dst) +{ + BonoboUINode *node; + const char *name; + char *path_dst_folder; + + name = strrchr (path_dst, '/'); + g_return_if_fail (name != NULL); + path_dst_folder = g_strndup (path_dst, name - path_dst); + name++; + + node = bonobo_ui_component_get_tree (uic, path_src, TRUE, NULL); + bonobo_ui_node_set_attr (node, "name", name); + + ephy_bonobo_clear_path (uic, path_dst); + + bonobo_ui_component_set_tree (uic, path_dst_folder, node, NULL); + + g_free (path_dst_folder); + bonobo_ui_node_free (node); +} + +void +ephy_bonobo_clear_path (BonoboUIComponent *uic, + const gchar *path) +{ + if (bonobo_ui_component_path_exists (uic, path, NULL)) + { + char *remove_wildcard = g_strdup_printf ("%s/*", path); + bonobo_ui_component_rm (uic, remove_wildcard, NULL); + g_free (remove_wildcard); + } +} diff --git a/lib/ephy-bonobo-extensions.h b/lib/ephy-bonobo-extensions.h new file mode 100644 index 000000000..86bb977f9 --- /dev/null +++ b/lib/ephy-bonobo-extensions.h @@ -0,0 +1,121 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* gul-bonobo-extensions.h - interface for new functions that conceptually + belong in bonobo. Perhaps some of these will be + actually rolled into bonobo someday. + + + This file is based on nautilus-bonobo-extensions.h from + libnautilus-private. + + + Copyright (C) 2000 Eazel, Inc. + + The Gnome Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: John Sullivan <sullivan@eazel.com> +*/ + +#ifndef EPHY_BONOBO_EXTENSIONS_H +#define EPHY_BONOBO_EXTENSIONS_H + +#include <bonobo/bonobo-ui-component.h> +#include <bonobo/bonobo-control.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gtk/gtkwidget.h> + +void ephy_bonobo_set_accelerator (BonoboUIComponent *ui, + const char *path, + const char *accelerator); +char *ephy_bonobo_get_label (BonoboUIComponent *ui, + const char *path); +void ephy_bonobo_set_label (BonoboUIComponent *ui, + const char *path, + const char *label); +void ephy_bonobo_set_tip (BonoboUIComponent *ui, + const char *path, + const char *tip); +void ephy_bonobo_set_sensitive (BonoboUIComponent *ui, + const char *path, + gboolean sensitive); +void ephy_bonobo_set_toggle_state (BonoboUIComponent *ui, + const char *path, + gboolean state); +void ephy_bonobo_set_hidden (BonoboUIComponent *ui, + const char *path, + gboolean hidden); +gboolean ephy_bonobo_get_hidden (BonoboUIComponent *ui, + const char *path); +void ephy_bonobo_add_numbered_menu_item (BonoboUIComponent *ui, + const char *container_path, + guint index, + const char *label, + GdkPixbuf *pixbuf); +void ephy_bonobo_add_numbered_toggle_menu_item (BonoboUIComponent *ui, + const char *container_path, + guint index, + const char *label); +void ephy_bonobo_add_numbered_radio_menu_item (BonoboUIComponent *ui, + const char *container_path, + guint index, + const char *label, + const char *radio_group_name); +char *ephy_bonobo_get_numbered_menu_item_command (BonoboUIComponent *ui, + const char *container_path, + guint index); +char *ephy_bonobo_get_numbered_menu_item_path (BonoboUIComponent *ui, + const char *container_path, + guint index); +guint ephy_bonobo_get_numbered_menu_item_index_from_command (const char *command); +char *ephy_bonobo_get_numbered_menu_item_container_path_from_command (const char *command); +void ephy_bonobo_add_submenu (BonoboUIComponent *ui, + const char *container_path, + const char *label, + GdkPixbuf *pixbuf); +void ephy_bonobo_add_numbered_submenu (BonoboUIComponent *ui, + const char *container_path, + guint index, + const char *label, + GdkPixbuf *pixbuf); +void ephy_bonobo_add_numbered_submenu_no_verb (BonoboUIComponent *ui, + const char *container_path, + guint index, + const char *label, + GdkPixbuf *pixbuf); +void ephy_bonobo_add_menu_separator (BonoboUIComponent *ui, + const char *path); +void ephy_bonobo_remove_menu_items_and_commands (BonoboUIComponent *ui, + const char *container_path); +void ephy_bonobo_set_label_for_menu_item_and_command (BonoboUIComponent *ui, + const char *menu_item_path, + const char *command_path, + const char *label_with_underscore); +void ephy_bonobo_set_icon (BonoboUIComponent *ui, + const char *path, + const char *icon_relative_path); +gchar *ephy_bonobo_add_dockitem (BonoboUIComponent *uic, + const char *name, + int band_num); +BonoboControl *ephy_bonobo_add_numbered_control (BonoboUIComponent *uic, + GtkWidget *w, guint index, + const char *path); +void ephy_bonobo_clear_path (BonoboUIComponent *uic, + const gchar *path); +void ephy_bonobo_replace_path (BonoboUIComponent *uic, + const gchar *path_src, + const char *path_dst); + +#endif /* EPHY_BONOBO_EXTENSIONS_H */ diff --git a/lib/ephy-dialog.c b/lib/ephy-dialog.c new file mode 100644 index 000000000..8c8344dda --- /dev/null +++ b/lib/ephy-dialog.c @@ -0,0 +1,943 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-dialog.h" +#include "ephy-glade.h" +#include "ephy-state.h" +#include "ephy-prefs-utils.h" +#include "ephy-gui.h" + +#include <string.h> +#include <gtk/gtktogglebutton.h> + +static void +ephy_dialog_class_init (EphyDialogClass *klass); +static void +ephy_dialog_init (EphyDialog *window); +static void +ephy_dialog_finalize (GObject *object); +static void +ephy_dialog_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void +ephy_dialog_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); + +static void +ephy_dialog_set_parent (EphyDialog *dialog, + GtkWidget *parent); + +static void +impl_construct (EphyDialog *dialog, + const EphyDialogProperty *properties, + const char *file, + const char *name); + +static void +impl_destruct (EphyDialog *dialog); + +static GtkWidget * +impl_get_control (EphyDialog *dialog, + int property_id); +static void +impl_get_value (EphyDialog *dialog, + int property_id, + GValue *value); +static gint +impl_run (EphyDialog *dialog); +static void +impl_show (EphyDialog *dialog); +void +ephy_dialog_destroy_cb (GtkWidget *widget, + EphyDialog *dialog); + +enum +{ + PROP_0, + PROP_PARENT_WINDOW, + PROP_MODAL +}; + +typedef enum +{ + PT_TOGGLEBUTTON, + PT_RADIOBUTTON, + PT_SPINBUTTON, + PT_COLOR, + PT_OPTIONMENU, + PT_ENTRY, + PT_UNKNOWN +} PrefType; + +typedef struct +{ + int id; + GtkWidget *widget; + const char *pref; + int *sg; + PropertyType type; +} PropertyInfo; + +struct EphyDialogPrivate +{ + GtkWidget *parent; + GtkWidget *dialog; + GtkWidget *container; + PropertyInfo *props; + gboolean modal; + char *name; + + int spin_item_id; + GTimer *spin_timer; +}; + +#define SPIN_DELAY 0.20 + +static GObjectClass *parent_class = NULL; + +GType +ephy_dialog_get_type (void) +{ + static GType ephy_dialog_type = 0; + + if (ephy_dialog_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyDialogClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_dialog_class_init, + NULL, + NULL, /* class_data */ + sizeof (EphyDialog), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_dialog_init + }; + + ephy_dialog_type = g_type_register_static (G_TYPE_OBJECT, + "EphyDialog", + &our_info, 0); + } + + return ephy_dialog_type; +} + +static void +ephy_dialog_class_init (EphyDialogClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_dialog_finalize; + object_class->set_property = ephy_dialog_set_property; + object_class->get_property = ephy_dialog_get_property; + + klass->construct = impl_construct; + klass->get_control = impl_get_control; + klass->get_value = impl_get_value; + klass->run = impl_run; + klass->show = impl_show; + klass->destruct = impl_destruct; + + g_object_class_install_property (object_class, + PROP_PARENT_WINDOW, + g_param_spec_object ("ParentWindow", + "ParentWindow", + "Parent window", + GTK_TYPE_WIDGET, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_MODAL, + g_param_spec_boolean ("Modal", + "Modal", + "Modal dialog", + FALSE, + G_PARAM_READWRITE)); +} + +static PrefType +get_pref_type_from_widget (GtkWidget *widget) +{ + if (GTK_IS_OPTION_MENU (widget)) + { + return PT_OPTIONMENU; + } + else if (GTK_IS_SPIN_BUTTON (widget)) + { + return PT_SPINBUTTON; + } + else if (GTK_IS_RADIO_BUTTON (widget)) + { + return PT_RADIOBUTTON; + } + else if (GTK_IS_TOGGLE_BUTTON (widget)) + { + return PT_TOGGLEBUTTON; + } + else if (GTK_IS_ENTRY (widget)) + { + return PT_ENTRY; + } + else if (GNOME_IS_COLOR_PICKER (widget)) + { + return PT_COLOR; + } + + return PT_UNKNOWN; +} + +static int * +set_controls_sensitivity (EphyDialog *dialog, + int *sg, gboolean s) +{ + GtkWidget *widget; + + while (*sg != SY_END_GROUP) + { + widget = ephy_dialog_get_control (dialog, + *sg); + gtk_widget_set_sensitive (widget, s); + + sg++; + } + + return sg; +} + +static void +prefs_set_group_sensitivity (GtkWidget *widget, + PrefType type, int *sg) +{ + int group = -1; + EphyDialog *dialog; + int i = 0; + + if (sg == NULL) return; + + dialog = EPHY_DIALOG (g_object_get_data + (G_OBJECT(widget), "dialog")); + + if (GTK_IS_RADIO_BUTTON (widget)) + { + group = ephy_gui_gtk_radio_button_get + (GTK_RADIO_BUTTON(widget)); + } + else if (GTK_IS_TOGGLE_BUTTON (widget)) + { + group = !gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(widget)); + } + else + { + g_assert (FALSE); + } + + while (*sg != SY_END) + { + if ((*sg == SY_BEGIN_GROUP) || + (*sg == SY_BEGIN_GROUP_INVERSE)) + { + gboolean b; + + b = (i == group); + if (*sg == SY_BEGIN_GROUP_INVERSE) b = !b; + + sg++; + sg = set_controls_sensitivity + (dialog, sg, b); + } + + i++; + sg++; + } +} + +static void +prefs_togglebutton_clicked_cb (GtkWidget *widget, PropertyInfo *pi) +{ + if (pi->type == PT_AUTOAPPLY) + { + ephy_pu_set_config_from_togglebutton (widget, pi->pref); + } + + prefs_set_group_sensitivity (widget, pi->type, pi->sg); +} + +static void +prefs_radiobutton_clicked_cb (GtkWidget *widget, PropertyInfo *pi) +{ + if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget))) + { + return; + } + + if (pi->type == PT_AUTOAPPLY) + { + ephy_pu_set_config_from_radiobuttongroup (widget, pi->pref); + } + + prefs_set_group_sensitivity (widget, pi->type, pi->sg); +} + +static gint +prefs_spinbutton_timeout_cb (EphyDialog *dialog) +{ + PropertyInfo pi = dialog->priv->props[dialog->priv->spin_item_id]; + + /* timer still valid? */ + if (dialog->priv->spin_timer == NULL) + { + return FALSE; + } + + /* okay, we're ready to set */ + if (g_timer_elapsed (dialog->priv->spin_timer, NULL) >= SPIN_DELAY) + { + /* kill off the timer */ + g_timer_destroy (dialog->priv->spin_timer); + dialog->priv->spin_timer = NULL; + + /* HACK update the spinbutton here so that the + * changes made directly in the entry are accepted + * and set in the pref. Otherwise the old value is used */ + gtk_spin_button_update (GTK_SPIN_BUTTON(pi.widget)); + + /* set */ + ephy_pu_set_config_from_spin_button (pi.widget, + pi.pref); + + /* done now */ + return FALSE; + } + + /* call me again */ + return TRUE; +} + +static void +prefs_spinbutton_changed_cb (GtkWidget *widget, PropertyInfo *pi) +{ + EphyDialog *dialog; + + if (pi->type != PT_AUTOAPPLY) return; + + dialog = EPHY_DIALOG (g_object_get_data + (G_OBJECT(widget), "dialog")); + + dialog->priv->spin_item_id = pi->id; + + /* destroy any existing timer */ + if (dialog->priv->spin_timer != NULL) + { + g_timer_destroy (dialog->priv->spin_timer); + } + + /* start the new one */ + dialog->priv->spin_timer = g_timer_new(); + g_timer_start (dialog->priv->spin_timer); + g_timeout_add (50, (GSourceFunc) prefs_spinbutton_timeout_cb, + dialog); +} + +static void +prefs_color_changed_cb (GtkWidget *widget, guint r, guint g, + guint b, guint a, const PropertyInfo *pi) +{ + if (pi->type == PT_AUTOAPPLY) + { + ephy_pu_set_config_from_color (widget, pi->pref); + } +} + +static void +prefs_entry_changed_cb (GtkWidget *widget, PropertyInfo *pi) +{ + if (pi->type == PT_AUTOAPPLY) + { + ephy_pu_set_config_from_editable (widget, pi->pref); + } +} + +static void +prefs_optionmenu_selected_cb (GtkWidget *widget, PropertyInfo *pi) +{ + if (pi->type == PT_AUTOAPPLY) + { + ephy_pu_set_config_from_optionmenu (widget, pi->pref); + } +} + +static void +prefs_connect_signals (EphyDialog *dialog) +{ + int i; + GSList *list; + PropertyInfo *props = dialog->priv->props; + + for (i = 0; props[i].widget != NULL; i++) + { + PrefType type; + PropertyInfo *info; + + if ((props[i].type != PT_AUTOAPPLY) && + (props[i].sg == NULL)) + continue; + + info = &dialog->priv->props[i]; + type = get_pref_type_from_widget + (dialog->priv->props[i].widget); + + switch (type) + { + case PT_TOGGLEBUTTON: + g_object_set_data (G_OBJECT(info->widget), "dialog", dialog); + g_signal_connect (G_OBJECT (info->widget), "clicked", + G_CALLBACK(prefs_togglebutton_clicked_cb), + (gpointer)info); + break; + case PT_RADIOBUTTON: + list = gtk_radio_button_get_group + (GTK_RADIO_BUTTON(info->widget)); + for (; list != NULL; list = list->next) + { + g_object_set_data (G_OBJECT(list->data), + "dialog", dialog); + g_signal_connect + (G_OBJECT (list->data), "clicked", + G_CALLBACK(prefs_radiobutton_clicked_cb), + (gpointer)info); + } + break; + case PT_SPINBUTTON: + g_object_set_data (G_OBJECT(info->widget), "dialog", dialog); + g_signal_connect (G_OBJECT (info->widget), "changed", + G_CALLBACK(prefs_spinbutton_changed_cb), + (gpointer)info); + break; + case PT_COLOR: + g_signal_connect (G_OBJECT (info->widget), "color_set", + G_CALLBACK(prefs_color_changed_cb), + (gpointer)info); + break; + case PT_OPTIONMENU: + g_signal_connect (G_OBJECT (info->widget), + "changed", + G_CALLBACK(prefs_optionmenu_selected_cb), + (gpointer)info); + break; + case PT_ENTRY: + g_signal_connect (G_OBJECT (info->widget), "changed", + G_CALLBACK(prefs_entry_changed_cb), + (gpointer)info); + break; + case PT_UNKNOWN: + break; + } + } +} + +static void +ephy_dialog_init (EphyDialog *dialog) +{ + dialog->priv = g_new0 (EphyDialogPrivate, 1); + + dialog->priv->parent = NULL; + dialog->priv->dialog = NULL; + dialog->priv->props = NULL; + dialog->priv->spin_timer = NULL; + dialog->priv->name = NULL; +} + +static void +prefs_set_sensitivity (PropertyInfo *props) +{ + int i; + + for (i=0 ; props[i].id >= 0; i++) + { + if (props[i].sg == NULL) continue; + + g_return_if_fail (props[i].widget != NULL); + + if (GTK_IS_RADIO_BUTTON(props[i].widget) || + GTK_IS_TOGGLE_BUTTON(props[i].widget)) + { + prefs_set_group_sensitivity (props[i].widget, + props[i].type, + props[i].sg); + } + } +} + +static void +load_props (PropertyInfo *props) +{ + int i; + + for (i=0 ; props[i].id >= 0; i++) + { + if (props[i].pref == NULL) continue; + + g_return_if_fail (props[i].widget != NULL); + + if (GTK_IS_SPIN_BUTTON(props[i].widget)) + { + ephy_pu_set_spin_button_from_config (props[i].widget, + props[i].pref); + } + else if (GTK_IS_RADIO_BUTTON(props[i].widget)) + { + ephy_pu_set_radiobuttongroup_from_config (props[i].widget, + props[i].pref); + } + else if (GTK_IS_TOGGLE_BUTTON(props[i].widget)) + { + ephy_pu_set_togglebutton_from_config (props[i].widget, + props[i].pref); + } + else if (GTK_IS_EDITABLE(props[i].widget)) + { + ephy_pu_set_editable_from_config (props[i].widget, + props[i].pref); + } + else if (GTK_IS_OPTION_MENU(props[i].widget)) + { + ephy_pu_set_optionmenu_from_config (props[i].widget, + props[i].pref); + } + else if (GNOME_IS_COLOR_PICKER(props[i].widget)) + { + ephy_pu_set_color_from_config (props[i].widget, + props[i].pref); + } + } + +} + +static void +save_props (PropertyInfo *props) +{ + int i; + + for (i=0 ; props[i].id >= 0; i++) + { + if ((props[i].pref == NULL) || + (props[i].type != PT_NORMAL)) continue; + g_return_if_fail (props[i].widget != NULL); + + if (GTK_IS_SPIN_BUTTON(props[i].widget)) + { + ephy_pu_set_config_from_spin_button (props[i].widget, + props[i].pref); + } + else if (GTK_IS_RADIO_BUTTON(props[i].widget)) + { + ephy_pu_set_config_from_radiobuttongroup (props[i].widget, + props[i].pref); + } + else if (GTK_IS_TOGGLE_BUTTON(props[i].widget)) + { + ephy_pu_set_config_from_togglebutton (props[i].widget, + props[i].pref); + } + else if (GTK_IS_EDITABLE(props[i].widget)) + { + ephy_pu_set_config_from_editable (props[i].widget, + props[i].pref); + } + else if (GTK_IS_OPTION_MENU(props[i].widget)) + { + ephy_pu_set_config_from_optionmenu (props[i].widget, + props[i].pref); + } + else if (GNOME_IS_COLOR_PICKER(props[i].widget)) + { + ephy_pu_set_config_from_color (props[i].widget, + props[i].pref); + } + } +} + +static void +ephy_dialog_finalize (GObject *object) +{ + EphyDialog *dialog; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_EPHY_DIALOG (object)); + + dialog = EPHY_DIALOG (object); + + g_return_if_fail (dialog->priv != NULL); + + if (dialog->priv->dialog) + { + ephy_dialog_destruct (dialog); + } + + g_free (dialog->priv->name); + g_free (dialog->priv->props); + g_free (dialog->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +ephy_dialog_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyDialog *d = EPHY_DIALOG (object); + + switch (prop_id) + { + case PROP_PARENT_WINDOW: + ephy_dialog_set_parent (d, g_value_get_object (value)); + break; + case PROP_MODAL: + ephy_dialog_set_modal (d, g_value_get_boolean (value)); + break; + } +} + +static void +ephy_dialog_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyDialog *d = EPHY_DIALOG (object); + + switch (prop_id) + { + case PROP_PARENT_WINDOW: + g_value_set_object (value, d->priv->parent); + break; + case PROP_MODAL: + g_value_set_boolean (value, d->priv->modal); + } +} + +static void +ephy_dialog_set_parent (EphyDialog *dialog, + GtkWidget *parent) +{ + g_return_if_fail (dialog->priv->parent == NULL); + g_return_if_fail (GTK_IS_WINDOW(parent)); + g_return_if_fail (GTK_IS_WINDOW(dialog->priv->dialog)); + + dialog->priv->parent = parent; + + gtk_window_set_transient_for (GTK_WINDOW (dialog->priv->dialog), + GTK_WINDOW (parent)); +} + +EphyDialog * +ephy_dialog_new (void) +{ + return EPHY_DIALOG (g_object_new (EPHY_DIALOG_TYPE, NULL)); +} + +EphyDialog * +ephy_dialog_new_with_parent (GtkWidget *parent_window) +{ + return EPHY_DIALOG (g_object_new (EPHY_DIALOG_TYPE, + "ParentWindow", parent_window, + NULL)); +} + +void ephy_dialog_show_embedded (EphyDialog *dialog, + GtkWidget *container) +{ + dialog->priv->container = container; + gtk_container_add (GTK_CONTAINER(container), + dialog->priv->dialog); + gtk_widget_show (dialog->priv->dialog); +} + +void +ephy_dialog_remove_embedded (EphyDialog *dialog) +{ + g_object_ref (G_OBJECT(dialog->priv->dialog)); + gtk_container_remove (GTK_CONTAINER(dialog->priv->container), + dialog->priv->dialog); +} + +static PropertyInfo * +init_props (const EphyDialogProperty *properties, GladeXML *gxml) +{ + PropertyInfo *props; + int i; + + for (i=0 ; properties[i].control_name != NULL; i++); + + props = g_new0 (PropertyInfo, i+1); + + for (i=0 ; properties[i].control_name != NULL; i++) + { + props[i].id = properties[i].id; + props[i].widget = glade_xml_get_widget + (gxml, properties[i].control_name); + props[i].pref = properties[i].state_pref; + props[i].sg = properties[i].sg; + props[i].type = properties[i].type; + } + + props[i].id = -1; + props[i].widget = NULL; + props[i].pref = NULL; + props[i].sg = NULL; + props[i].type = 0; + + return props; +} + +static void +dialog_destruction_notify (EphyDialog *dialog, + GObject *where_the_object_was) +{ + dialog->priv->dialog = NULL; + ephy_dialog_destruct (dialog); + g_object_unref (dialog); +} + +static void +dialog_destroy_cb (GtkWidget *widget, EphyDialog *dialog) +{ + if (dialog->priv->props && + dialog->priv->dialog) + { + save_props (dialog->priv->props); + } +} + +static void +impl_construct (EphyDialog *dialog, + const EphyDialogProperty *properties, + const char *file, + const char *name) +{ + GladeXML *gxml; + + gxml = ephy_glade_widget_new + (file, name, &(dialog->priv->dialog), dialog); + + if (dialog->priv->name == NULL) + { + dialog->priv->name = g_strdup (name); + } + + if (properties) + { + dialog->priv->props = init_props (properties, gxml); + } + + g_signal_connect (dialog->priv->dialog, + "destroy", + G_CALLBACK(dialog_destroy_cb), + dialog); + + g_object_unref (gxml); + + g_object_weak_ref (G_OBJECT(dialog->priv->dialog), + (GWeakNotify)dialog_destruction_notify, + dialog); + + if (dialog->priv->props) + { + load_props (dialog->priv->props); + prefs_connect_signals (dialog); + prefs_set_sensitivity (dialog->priv->props); + } +} + +static void +impl_destruct (EphyDialog *dialog) +{ + if (dialog->priv->dialog) + { + g_object_weak_unref (G_OBJECT(dialog->priv->dialog), + (GWeakNotify)dialog_destruction_notify, + dialog); + gtk_widget_destroy (dialog->priv->dialog); + dialog->priv->dialog = NULL; + } +} + +static GtkWidget * +impl_get_control (EphyDialog *dialog, + int property_id) +{ + return dialog->priv->props[property_id].widget; +} + +static void +impl_get_value (EphyDialog *dialog, + int property_id, + GValue *value) +{ + GtkWidget *widget = ephy_dialog_get_control (dialog, + property_id); + + if (GTK_IS_SPIN_BUTTON (widget)) + { + float val; + g_value_init (value, G_TYPE_FLOAT); + val = gtk_spin_button_get_value (GTK_SPIN_BUTTON(widget)); + g_value_set_float (value, val); + } + else if (GTK_IS_RADIO_BUTTON (widget)) + { + int val; + g_value_init (value, G_TYPE_INT); + val = ephy_gui_gtk_radio_button_get (GTK_RADIO_BUTTON(widget)); + g_value_set_int (value, val); + } + else if (GTK_IS_TOGGLE_BUTTON (widget)) + { + g_value_init (value, G_TYPE_BOOLEAN); + g_value_set_boolean (value, gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(widget))); + } + else if (GTK_IS_EDITABLE (widget)) + { + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, gtk_editable_get_chars + (GTK_EDITABLE (widget), 0, -1)); + } + else if (GTK_IS_OPTION_MENU (widget)) + { + int val; + g_value_init (value, G_TYPE_INT); + val = gtk_option_menu_get_history (GTK_OPTION_MENU(widget)); + g_value_set_int (value, val); + } +} + +static gboolean +ephy_dialog_configure_event_cb (GtkWidget *widget, + GdkEventConfigure *event, + EphyDialog *dialog) +{ + ephy_state_save_window (widget, dialog->priv->name); + + return FALSE; +} + +static void +setup_default_size (EphyDialog *dialog) +{ + ephy_state_load_window (dialog->priv->dialog, + dialog->priv->name, -1, -1, FALSE); + + g_signal_connect (dialog->priv->dialog, + "configure_event", + G_CALLBACK (ephy_dialog_configure_event_cb), + dialog); +} + +static gint +impl_run (EphyDialog *dialog) +{ + setup_default_size (dialog); + + return gtk_dialog_run (GTK_DIALOG(dialog->priv->dialog)); +} + +static void +impl_show (EphyDialog *dialog) +{ + setup_default_size (dialog); + + if (dialog->priv->parent) + { + /* make the dialog transient again, because it seems to get + * forgotten after gtk_widget_hide + */ + gtk_window_set_transient_for (GTK_WINDOW (dialog->priv->dialog), + GTK_WINDOW (dialog->priv->parent)); + } + gtk_window_present (GTK_WINDOW(dialog->priv->dialog)); +} + +void +ephy_dialog_set_modal (EphyDialog *dialog, + gboolean is_modal) +{ + dialog->priv->modal = is_modal; + + gtk_window_set_modal (GTK_WINDOW(dialog->priv->dialog), + is_modal); +} + +void +ephy_dialog_construct (EphyDialog *dialog, + const EphyDialogProperty *properties, + const char *file, + const char *name) +{ + EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog); + return klass->construct (dialog, properties, file, name); +} + +void +ephy_dialog_destruct (EphyDialog *dialog) +{ + EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog); + klass->destruct (dialog); +} + +gint +ephy_dialog_run (EphyDialog *dialog) +{ + EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog); + return klass->run (dialog); +} + +void +ephy_dialog_show (EphyDialog *dialog) +{ + EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog); + klass->show (dialog); +} + +GtkWidget * +ephy_dialog_get_control (EphyDialog *dialog, + int property_id) +{ + EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog); + return klass->get_control (dialog, property_id); +} + +void +ephy_dialog_get_value (EphyDialog *dialog, + int property_id, + GValue *value) +{ + EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog); + return klass->get_value (dialog, property_id, value); +} + diff --git a/lib/ephy-dialog.h b/lib/ephy-dialog.h new file mode 100644 index 000000000..24cb2cf5c --- /dev/null +++ b/lib/ephy-dialog.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_DIALOG_H +#define EPHY_DIALOG_H + +#include <glib-object.h> +#include <glib.h> +#include <gtk/gtkwidget.h> + +G_BEGIN_DECLS + +typedef struct EphyDialogClass EphyDialogClass; + +#define EPHY_DIALOG_TYPE (ephy_dialog_get_type ()) +#define EPHY_DIALOG(obj) (GTK_CHECK_CAST ((obj), EPHY_DIALOG_TYPE, EphyDialog)) +#define EPHY_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_DIALOG_TYPE, EphyDialogClass)) +#define IS_EPHY_DIALOG(obj) (GTK_CHECK_TYPE ((obj), EPHY_DIALOG_TYPE)) +#define IS_EPHY_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_DIALOG)) +#define EPHY_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EPHY_DIALOG_TYPE, EphyDialogClass)) + +typedef struct EphyDialog EphyDialog; +typedef struct EphyDialogPrivate EphyDialogPrivate; + +#define SY_BEGIN_GROUP -20 +#define SY_END_GROUP -21 +#define SY_END -22 +#define SY_BEGIN_GROUP_INVERSE -23 + +struct EphyDialog +{ + GObject parent; + EphyDialogPrivate *priv; +}; + +typedef enum +{ + PT_NORMAL, + PT_AUTOAPPLY +} PropertyType; + +typedef struct +{ + int id; + const char *control_name; + const char *state_pref; + PropertyType type; + int *sg; +} EphyDialogProperty; + +struct EphyDialogClass +{ + GObjectClass parent_class; + + void (* construct) (EphyDialog *dialog, + const EphyDialogProperty *properties, + const char *file, + const char *name); + void (* destruct) (EphyDialog *dialog); + gint (* run) (EphyDialog *dialog); + void (* show) (EphyDialog *dialog); + GtkWidget * (* get_control) (EphyDialog *dialog, + int property_id); + void (* get_value) (EphyDialog *dialog, + int property_id, + GValue *value); +}; + +GType ephy_dialog_get_type (void); + +EphyDialog *ephy_dialog_new (void); + +EphyDialog *ephy_dialog_new_with_parent (GtkWidget *parent_window); + +void ephy_dialog_construct (EphyDialog *dialog, + const EphyDialogProperty *properties, + const char *file, + const char *name); + +void ephy_dialog_destruct (EphyDialog *dialog); + +gint ephy_dialog_run (EphyDialog *dialog); + +void ephy_dialog_show (EphyDialog *dialog); + +void ephy_dialog_show_embedded (EphyDialog *dialog, + GtkWidget *container); + +void ephy_dialog_remove_embedded (EphyDialog *dialog); + +void ephy_dialog_set_modal (EphyDialog *dialog, + gboolean is_modal); + +GtkWidget *ephy_dialog_get_control (EphyDialog *dialog, + int property_id); + +void ephy_dialog_get_value (EphyDialog *dialog, + int property_id, + GValue *value); + +G_END_DECLS + +#endif + diff --git a/lib/ephy-dnd.c b/lib/ephy-dnd.c new file mode 100644 index 000000000..b70fa284a --- /dev/null +++ b/lib/ephy-dnd.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-dnd.h" + +#include <gtk/gtkselection.h> +#include <gtk/gtktreeview.h> + +static GtkTargetEntry url_drag_types [] = +{ + { EPHY_DND_URI_LIST_TYPE, 0, EPHY_DND_URI_LIST }, + { EPHY_DND_TEXT_TYPE, 0, EPHY_DND_TEXT }, + { EPHY_DND_URL_TYPE, 0, EPHY_DND_URL } +}; + +/* Encode a "_NETSCAPE_URL_" selection. + * As far as I can tell, Netscape is expecting a single + * URL to be returned. I cannot discover a way to construct + * a list to be returned that Netscape can understand. + * GMC also fails to do this as well. + */ +static void +add_one_netscape_url (const char *url, int x, int y, int w, int h, gpointer data) +{ + GString *result; + + result = (GString *) data; + if (result->len == 0) { + g_string_append (result, url); + } +} + +static void +add_one_uri (const char *uri, int x, int y, int w, int h, gpointer data) +{ + GString *result; + + result = (GString *) data; + + g_string_append (result, uri); + g_string_append (result, "\r\n"); +} + +gboolean +ephy_dnd_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint32 time, + gpointer container_context, + EphyDragEachSelectedItemIterator each_selected_item_iterator) +{ + GString *result; + + switch (info) { + case EPHY_DND_URI_LIST: + case EPHY_DND_TEXT: + result = g_string_new (NULL); + (* each_selected_item_iterator) (add_one_uri, container_context, result); + break; + case EPHY_DND_URL: + result = g_string_new (NULL); + (* each_selected_item_iterator) (add_one_netscape_url, container_context, result); + break; + default: + return FALSE; + } + + gtk_selection_data_set (selection_data, + selection_data->target, + 8, result->str, result->len); + + return TRUE; +} + +void +ephy_dnd_url_drag_source_set (GtkWidget *widget) +{ + gtk_drag_source_set (widget, + GDK_BUTTON1_MASK, + url_drag_types, + G_N_ELEMENTS (url_drag_types), + GDK_ACTION_COPY); +} + +void +ephy_dnd_enable_model_drag_source (GtkWidget *treeview) +{ + gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (treeview), + GDK_BUTTON1_MASK, + url_drag_types, G_N_ELEMENTS (url_drag_types), + GDK_ACTION_COPY); +} + diff --git a/lib/ephy-dnd.h b/lib/ephy-dnd.h new file mode 100644 index 000000000..87b6008d9 --- /dev/null +++ b/lib/ephy-dnd.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_DND_H +#define EPHY_DND_H + +#include <glib.h> +#include <gtk/gtkwidget.h> +#include <gtk/gtkdnd.h> + +G_BEGIN_DECLS + +#define EPHY_DND_NODE_PROPERTY 3 + +/* Drag & Drop target names. */ +#define EPHY_DND_URI_LIST_TYPE "text/uri-list" +#define EPHY_DND_TEXT_TYPE "text/plain" +#define EPHY_DND_URL_TYPE "_NETSCAPE_URL" +#define EPHY_DND_EPHY_URL_TYPE "EPHY_URL" +#define EPHY_DND_EPHY_BOOKMARK_TYPE "EPHY_BOOKMARK" + +/* Standard Drag & Drop types. */ +typedef enum { + EPHY_DND_URI_LIST, + EPHY_DND_URL, + EPHY_DND_TEXT, +} EphyIconDndTargetType; + +typedef void (* EphyDragEachSelectedItemDataGet) (const char *url, + int x, int y, int w, int h, + gpointer data); + +typedef void (* EphyDragEachSelectedItemIterator) (EphyDragEachSelectedItemDataGet iteratee, + gpointer iterator_context, + gpointer data); + +gboolean ephy_dnd_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint32 time, + gpointer container_context, + EphyDragEachSelectedItemIterator each_selected_item_iterator); + +void ephy_dnd_url_drag_source_set (GtkWidget *widget); + +void ephy_dnd_enable_model_drag_source (GtkWidget *treeview); + + +G_END_DECLS + +#endif diff --git a/lib/ephy-file-helpers.c b/lib/ephy-file-helpers.c new file mode 100644 index 000000000..2e867e3f5 --- /dev/null +++ b/lib/ephy-file-helpers.c @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> +#include <glib.h> +#include <libgnome/gnome-i18n.h> +#include <libgnome/gnome-init.h> +#include <libgnome/gnome-exec.h> + +#include "ephy-file-helpers.h" + +static GHashTable *files = NULL; + +static char *dot_dir = NULL; + +char * +ephy_file_tmp_filename (const char *base, + const char *extension) +{ + int fd; + char *name = g_strdup (base); + + fd = mkstemp (name); + + if (fd != -1) + { + unlink (name); + close (fd); + } + else + { + return NULL; + } + + if (extension) + { + char *tmp; + tmp = g_strconcat (name, ".", + extension, NULL); + g_free (name); + name = tmp; + } + + return name; +} + +const char * +ephy_file (const char *filename) +{ + char *ret; + int i; + + static char *paths[] = + { + SHARE_DIR "/", + SHARE_DIR "/glade/", + SHARE_DIR "/art/", + SHARE_UNINSTALLED_DIR "/", + SHARE_UNINSTALLED_DIR "/glade/", + SHARE_UNINSTALLED_DIR "/art/" + }; + + g_assert (files != NULL); + + ret = g_hash_table_lookup (files, filename); + if (ret != NULL) + return ret; + + for (i = 0; i < (int) G_N_ELEMENTS (paths); i++) + { + ret = g_strconcat (paths[i], filename, NULL); + if (g_file_test (ret, G_FILE_TEST_EXISTS) == TRUE) + { + g_hash_table_insert (files, g_strdup (filename), ret); + return (const char *) ret; + } + g_free (ret); + } + + g_warning (_("Failed to find %s"), filename); + + return NULL; +} + +const char * +ephy_dot_dir (void) +{ + if (dot_dir == NULL) + { + dot_dir = g_build_filename (g_get_home_dir (), + GNOME_DOT_GNOME, + "epiphany", + NULL); + } + + return dot_dir; +} + +void +ephy_file_helpers_init (void) +{ + files = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_free); +} + +void +ephy_file_helpers_shutdown (void) +{ + g_hash_table_destroy (files); + + g_free (dot_dir); +} + +static void +gul_general_gnome_shell_execute (const char *command) +{ + GError *error = NULL; + if (!g_spawn_command_line_async (command, &error)) { + g_warning ("Error starting command '%s': %s\n", command, error->message); + g_error_free (error); + } +} + +/* Return a command string containing the path to a terminal on this system. */ + +static char * +try_terminal_command (const char *program, + const char *args) +{ + char *program_in_path, *quoted, *result; + + if (program == NULL) { + return NULL; + } + + program_in_path = g_find_program_in_path (program); + if (program_in_path == NULL) { + return NULL; + } + + quoted = g_shell_quote (program_in_path); + if (args == NULL || args[0] == '\0') { + return quoted; + } + result = g_strconcat (quoted, " ", args, NULL); + g_free (quoted); + return result; +} + +static char * +try_terminal_command_argv (int argc, + char **argv) +{ + GString *string; + int i; + char *quoted, *result; + + if (argc == 0) { + return NULL; + } + + if (argc == 1) { + return try_terminal_command (argv[0], NULL); + } + + string = g_string_new (argv[1]); + for (i = 2; i < argc; i++) { + quoted = g_shell_quote (argv[i]); + g_string_append_c (string, ' '); + g_string_append (string, quoted); + g_free (quoted); + } + result = try_terminal_command (argv[0], string->str); + g_string_free (string, TRUE); + + return result; +} + +static char * +get_terminal_command_prefix (gboolean for_command) +{ + int argc; + char **argv; + char *command; + guint i; + static const char *const commands[][3] = { + { "gnome-terminal", "-x", "" }, + { "dtterm", "-e", "-ls" }, + { "nxterm", "-e", "-ls" }, + { "color-xterm", "-e", "-ls" }, + { "rxvt", "-e", "-ls" }, + { "xterm", "-e", "-ls" }, + }; + + /* Try the terminal from preferences. Use without any + * arguments if we are just doing a standalone terminal. + */ + argc = 0; + argv = g_new0 (char *, 1); + gnome_prepend_terminal_to_vector (&argc, &argv); + + command = NULL; + if (argc != 0) { + if (for_command) { + command = try_terminal_command_argv (argc, argv); + } else { + /* Strip off the arguments in a lame attempt + * to make it be an interactive shell. + */ + command = try_terminal_command (argv[0], NULL); + } + } + + while (argc != 0) { + g_free (argv[--argc]); + } + g_free (argv); + + if (command != NULL) { + return command; + } + + /* Try well-known terminal applications in same order that gmc did. */ + for (i = 0; i < G_N_ELEMENTS (commands); i++) { + command = try_terminal_command (commands[i][0], + commands[i][for_command ? 1 : 2]); + if (command != NULL) { + break; + } + } + + return command; +} + +static char * +gul_general_gnome_make_terminal_command (const char *command) +{ + char *prefix, *quoted, *terminal_command; + + if (command == NULL) { + return get_terminal_command_prefix (FALSE); + } + prefix = get_terminal_command_prefix (TRUE); + quoted = g_shell_quote (command); + terminal_command = g_strconcat (prefix, " /bin/sh -c ", quoted, NULL); + g_free (prefix); + g_free (quoted); + return terminal_command; +} + +static void +gul_general_gnome_open_terminal (const char *command) +{ + char *command_line; + + command_line = gul_general_gnome_make_terminal_command (command); + if (command_line == NULL) { + g_message ("Could not start a terminal"); + return; + } + gul_general_gnome_shell_execute (command_line); + g_free (command_line); +} + +void +ephy_file_launch_application (const char *command_string, + const char *parameter, + gboolean use_terminal) +{ + char *full_command; + char *quoted_parameter; + + if (parameter != NULL) { + quoted_parameter = g_shell_quote (parameter); + full_command = g_strconcat (command_string, " ", quoted_parameter, NULL); + g_free (quoted_parameter); + } else { + full_command = g_strdup (command_string); + } + + if (use_terminal) { + gul_general_gnome_open_terminal (full_command); + } else { + gul_general_gnome_shell_execute (full_command); + } + + g_free (full_command); +} + +void +ephy_ensure_dir_exists (const char *dir) +{ + if (g_file_test (dir, G_FILE_TEST_IS_DIR) == FALSE) + { + if (g_file_test (dir, G_FILE_TEST_EXISTS) == TRUE) + g_error (_("%s exists, please move it out of the way."), dir); + + if (mkdir (dir, 488) != 0) + g_error (_("Failed to create directory %s."), dir); + } +} diff --git a/lib/ephy-file-helpers.h b/lib/ephy-file-helpers.h new file mode 100644 index 000000000..75f6a0e9e --- /dev/null +++ b/lib/ephy-file-helpers.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef EPHY_FILE_HELPERS_H +#define EPHY_FILE_HELPERS_H + +#include <glib.h> + +G_BEGIN_DECLS + +const char *ephy_file (const char *filename); + +const char *ephy_dot_dir (void); + +void ephy_file_helpers_init (void); + +void ephy_file_helpers_shutdown (void); + +void ephy_file_launch_application (const char *command_string, + const char *parameter, + gboolean use_terminal); + +char *ephy_file_tmp_filename (const char *base, + const char *extension); + +void ephy_ensure_dir_exists (const char *dir); + + +G_END_DECLS + +#endif /* EPHY_FILE_HELPERS_H */ diff --git a/lib/ephy-filesystem-autocompletion.c b/lib/ephy-filesystem-autocompletion.c new file mode 100644 index 000000000..8b1cb84fb --- /dev/null +++ b/lib/ephy-filesystem-autocompletion.c @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ephy-autocompletion-source.h" +#include "ephy-filesystem-autocompletion.h" +#include "ephy-gobject-misc.h" +#include <string.h> + +#include <libgnomevfs/gnome-vfs-async-ops.h> + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); + +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +/** + * Private data + */ +struct _EphyFilesystemAutocompletionPrivate { + gchar *current_dir; + gchar *base_dir; + GnomeVFSURI *base_dir_uri; + gchar *basic_key; + gchar *basic_key_dir; + GSList *files; + + guint score; + GnomeVFSAsyncHandle *load_handle; +}; + +/** + * Private functions, only availble from this file + */ +static void ephy_filesystem_autocompletion_class_init (EphyFilesystemAutocompletionClass *klass); +static void ephy_filesystem_autocompletion_init (EphyFilesystemAutocompletion *as); +static void ephy_filesystem_autocompletion_finalize_impl (GObject *o); +static void ephy_filesystem_autocompletion_autocompletion_source_init (EphyAutocompletionSourceIface *iface); +static void ephy_filesystem_autocompletion_autocompletion_source_foreach (EphyAutocompletionSource *source, + const gchar *current_text, + EphyAutocompletionSourceForeachFunc func, + gpointer data); +void ephy_filesystem_autocompletion_autocompletion_source_set_basic_key (EphyAutocompletionSource *source, + const gchar *basic_key); +static void ephy_filesystem_autocompletion_emit_autocompletion_source_data_changed (EphyFilesystemAutocompletion *gh); +static void ephy_filesystem_autocompletion_set_current_dir (EphyFilesystemAutocompletion *fa, const gchar *d); + + +static gpointer g_object_class; + +/** + * FilesystemAutocompletion object + */ +MAKE_GET_TYPE_IFACE (ephy_filesystem_autocompletion, "EphyFilesystemAutocompletion", EphyFilesystemAutocompletion, + ephy_filesystem_autocompletion_class_init, ephy_filesystem_autocompletion_init, G_TYPE_OBJECT, + ephy_filesystem_autocompletion_autocompletion_source_init, EPHY_TYPE_AUTOCOMPLETION_SOURCE); + +static void +ephy_filesystem_autocompletion_autocompletion_source_init (EphyAutocompletionSourceIface *iface) +{ + iface->foreach = ephy_filesystem_autocompletion_autocompletion_source_foreach; + iface->set_basic_key = ephy_filesystem_autocompletion_autocompletion_source_set_basic_key; +} + +static void +ephy_filesystem_autocompletion_class_init (EphyFilesystemAutocompletionClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = ephy_filesystem_autocompletion_finalize_impl; + + g_object_class = g_type_class_peek_parent (klass); +} + +static void +ephy_filesystem_autocompletion_init (EphyFilesystemAutocompletion *e) +{ + EphyFilesystemAutocompletionPrivate *p = g_new0 (EphyFilesystemAutocompletionPrivate, 1); + e->priv = p; + + p->score = G_MAXINT / 2; + p->base_dir = g_strdup (""); +} + +static void +ephy_filesystem_autocompletion_finalize_impl (GObject *o) +{ + EphyFilesystemAutocompletion *as = GUL_FILESYSTEM_AUTOCOMPLETION (o); + EphyFilesystemAutocompletionPrivate *p = as->priv; + + DEBUG_MSG (("in ephy_filesystem_autocompletion_finalize_impl\n")); + + g_free (p->basic_key); + g_free (p->basic_key_dir); + g_free (p->current_dir); + g_free (p->base_dir); + if (p->base_dir_uri) + { + gnome_vfs_uri_unref (p->base_dir_uri); + } + + g_free (p); + + G_OBJECT_CLASS (g_object_class)->finalize (o); +} + +EphyFilesystemAutocompletion * +ephy_filesystem_autocompletion_new (void) +{ + EphyFilesystemAutocompletion *ret = g_object_new (GUL_TYPE_FILESYSTEM_AUTOCOMPLETION, NULL); + return ret; +} + + +static gchar * +gfa_get_nearest_dir (const gchar *path) +{ + gchar *ret; + const gchar *lastslash = rindex (path, '/'); + + if (lastslash) + { + if (!strcmp (path, "file://")) + { + /* without this, gnome-vfs does not recognize it as a dir */ + ret = g_strdup ("file:///"); + } + else + { + ret = g_strndup (path, lastslash - path + 1); + } + } + else + { + ret = g_strdup (""); + } + + return ret; +} + +static void +ephy_filesystem_autocompletion_autocompletion_source_foreach (EphyAutocompletionSource *source, + const gchar *basic_key, + EphyAutocompletionSourceForeachFunc func, + gpointer data) +{ + EphyFilesystemAutocompletion *fa = GUL_FILESYSTEM_AUTOCOMPLETION (source); + EphyFilesystemAutocompletionPrivate *p = fa->priv; + GSList *li; + + ephy_filesystem_autocompletion_autocompletion_source_set_basic_key (source, basic_key); + + for (li = p->files; li; li = li->next) + { + func (source, li->data, li->data, li->data, FALSE, FALSE, p->score, data); + } + +} + +static void +ephy_filesystem_autocompletion_emit_autocompletion_source_data_changed (EphyFilesystemAutocompletion *fa) +{ + g_signal_emit_by_name (fa, "data-changed"); +} + +static void +gfa_load_directory_cb (GnomeVFSAsyncHandle *handle, + GnomeVFSResult result, + GList *list, + guint entries_read, + gpointer callback_data) +{ + EphyFilesystemAutocompletion *fa = callback_data; + EphyFilesystemAutocompletionPrivate *p = fa->priv; + GList *li; + gchar *cd; + + g_return_if_fail (p->load_handle == handle); + + DEBUG_MSG (("gfa_load_directory_cb, entries_read == %d\n", entries_read)); + + if (entries_read <= 0) + { + return; + } + + if (p->basic_key_dir[strlen (p->basic_key_dir) - 1] == G_DIR_SEPARATOR + || p->basic_key_dir[0] == '\0') + { + cd = g_strdup (p->basic_key_dir); + } + else + { + cd = g_strconcat (p->basic_key_dir, G_DIR_SEPARATOR_S, NULL); + } + + for (li = list; li; li = li->next) + { + GnomeVFSFileInfo *i = li->data; + if (!(i->name[0] == '.' + && (i->name[1] == '\0' + || (i->name[1] == '.' + && i->name[2] == '\0')))) + { + gchar *f = g_strconcat (cd, i->name, NULL); + p->files = g_slist_prepend (p->files, f); + + DEBUG_MSG (("+ %s\n", f)); + } + } + + g_free (cd); + + ephy_filesystem_autocompletion_emit_autocompletion_source_data_changed (fa); +} + +static void +ephy_filesystem_autocompletion_set_current_dir (EphyFilesystemAutocompletion *fa, const gchar *d) +{ + EphyFilesystemAutocompletionPrivate *p = fa->priv; + GnomeVFSURI *cd_uri; + + if (p->base_dir_uri) + { + cd_uri = gnome_vfs_uri_append_path (p->base_dir_uri, d); + } + else + { + cd_uri = gnome_vfs_uri_new (d); + } + + if (p->load_handle) + { + gnome_vfs_async_cancel (p->load_handle); + p->load_handle = NULL; + } + + if (p->files) + { + g_slist_foreach (p->files, (GFunc) g_free, NULL); + g_slist_free (p->files); + p->files = NULL; + + ephy_filesystem_autocompletion_emit_autocompletion_source_data_changed (fa); + } + + if (!cd_uri) + { + DEBUG_MSG (("Can't load dir %s\n", d)); + return; + } + + g_free (p->current_dir); + p->current_dir = gnome_vfs_uri_to_string (cd_uri, GNOME_VFS_URI_HIDE_NONE); + + DEBUG_MSG (("Loading dir: %s\n", p->current_dir)); + + gnome_vfs_async_load_directory_uri (&p->load_handle, + cd_uri, + GNOME_VFS_FILE_INFO_DEFAULT, + 100, + 0, + gfa_load_directory_cb, + fa); + + gnome_vfs_uri_unref (cd_uri); +} + +void +ephy_filesystem_autocompletion_autocompletion_source_set_basic_key (EphyAutocompletionSource *source, + const gchar *basic_key) +{ + EphyFilesystemAutocompletion *fa = GUL_FILESYSTEM_AUTOCOMPLETION (source); + EphyFilesystemAutocompletionPrivate *p = fa->priv; + gchar *new_basic_key_dir; + + if (p->basic_key && !strcmp (p->basic_key, basic_key)) + { + return; + } + + g_free (p->basic_key); + p->basic_key = g_strdup (basic_key); + + new_basic_key_dir = gfa_get_nearest_dir (basic_key); + if (p->basic_key_dir && !strcmp (p->basic_key_dir, new_basic_key_dir)) + { + g_free (new_basic_key_dir); + } + else + { + g_free (p->basic_key_dir); + p->basic_key_dir = new_basic_key_dir; + ephy_filesystem_autocompletion_set_current_dir (fa, p->basic_key_dir); + } +} + +void +ephy_filesystem_autocompletion_set_base_dir (EphyFilesystemAutocompletion *fa, const gchar *d) +{ + EphyFilesystemAutocompletionPrivate *p = fa->priv; + + g_free (p->base_dir); + p->base_dir = g_strdup (d); + + if (p->base_dir_uri) + { + gnome_vfs_uri_unref (p->base_dir_uri); + } + + if (p->base_dir[0]) + { + p->base_dir_uri = gnome_vfs_uri_new (p->base_dir); + } + else + { + p->base_dir_uri = NULL; + } + + if (p->base_dir_uri) + { + gchar *t = gnome_vfs_uri_to_string (p->base_dir_uri, GNOME_VFS_URI_HIDE_NONE); + DEBUG_MSG (("base_dir: %s\n", t)); + g_free (t); + } +} + diff --git a/lib/ephy-filesystem-autocompletion.h b/lib/ephy-filesystem-autocompletion.h new file mode 100644 index 000000000..ec047282f --- /dev/null +++ b/lib/ephy-filesystem-autocompletion.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_FILESYSTEM_AUTOCOMPLETION_H +#define EPHY_FILESYSTEM_AUTOCOMPLETION_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +/* object forward declarations */ + +typedef struct _EphyFilesystemAutocompletion EphyFilesystemAutocompletion; +typedef struct _EphyFilesystemAutocompletionClass EphyFilesystemAutocompletionClass; +typedef struct _EphyFilesystemAutocompletionPrivate EphyFilesystemAutocompletionPrivate; + +/** + * FilesystemAutocompletion object + */ + +#define GUL_TYPE_FILESYSTEM_AUTOCOMPLETION (ephy_filesystem_autocompletion_get_type()) +#define GUL_FILESYSTEM_AUTOCOMPLETION(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \ + GUL_TYPE_FILESYSTEM_AUTOCOMPLETION,\ + EphyFilesystemAutocompletion)) +#define GUL_FILESYSTEM_AUTOCOMPLETION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \ + GUL_TYPE_FILESYSTEM_AUTOCOMPLETION,\ + EphyFilesystemAutocompletionClass)) +#define GUL_IS_FILESYSTEM_AUTOCOMPLETION(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \ + GUL_TYPE_FILESYSTEM_AUTOCOMPLETION)) +#define GUL_IS_FILESYSTEM_AUTOCOMPLETION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \ + GUL_TYPE_FILESYSTEM_AUTOCOMPLETION)) +#define GUL_FILESYSTEM_AUTOCOMPLETION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GUL_TYPE_FILESYSTEM_AUTOCOMPLETION,\ + EphyFilesystemAutocompletionClass)) + +struct _EphyFilesystemAutocompletionClass +{ + GObjectClass parent_class; + +}; + +struct _EphyFilesystemAutocompletion +{ + GObject parent_object; + EphyFilesystemAutocompletionPrivate *priv; +}; + +GType ephy_filesystem_autocompletion_get_type (void); +EphyFilesystemAutocompletion * ephy_filesystem_autocompletion_new (void); +void ephy_filesystem_autocompletion_set_base_dir (EphyFilesystemAutocompletion *fa, + const gchar *d); + +G_END_DECLS + +#endif diff --git a/lib/ephy-glade.c b/lib/ephy-glade.c new file mode 100644 index 000000000..beb91827f --- /dev/null +++ b/lib/ephy-glade.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2000 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-glade.h" +#include "ephy-file-helpers.h" + +#include <glade/glade-xml.h> +#include <gtk/gtkmenu.h> +#include <gmodule.h> + +static void +glade_signal_connect_func (const gchar *cb_name, GObject *obj, + const gchar *signal_name, const gchar *signal_data, + GObject *conn_obj, gboolean conn_after, + gpointer user_data); + +/** + * ephy_widget_new: build a new widget of the provided name, with all + * signals attached and data set to the provided parameter. + */ +GladeXML * +ephy_glade_widget_new (const char *file, const char *widget_name, + GtkWidget **root, gpointer data) +{ + GladeXML *gxml; + const char *glade_file; + + glade_file = ephy_file (file); + g_return_val_if_fail (glade_file != NULL, NULL); + + /* build the widget */ + /* note that libglade automatically caches the parsed file, + * so we don't need to worry about the efficiency of this */ + gxml = glade_xml_new (glade_file, widget_name, NULL); + g_return_val_if_fail (gxml != NULL, NULL); + + /* lookup the root widget if requested */ + if (root != NULL) + { + *root = glade_xml_get_widget (gxml, widget_name); + } + + /* connect signals and data */ + glade_xml_signal_autoconnect_full + (gxml, (GladeXMLConnectFunc)glade_signal_connect_func, data); + + /* return xml document for subsequent widget lookups */ + return gxml; +} + +/* + * glade_signal_connect_func: used by glade_xml_signal_autoconnect_full + */ +static void +glade_signal_connect_func (const gchar *cb_name, GObject *obj, + const gchar *signal_name, const gchar *signal_data, + GObject *conn_obj, gboolean conn_after, + gpointer user_data) +{ + /** Module with all the symbols of the program */ + static GModule *mod_self = NULL; + gpointer handler_func; + + /* initialize gmodule */ + if (mod_self == NULL) + { + mod_self = g_module_open (NULL, 0); + g_assert (mod_self != NULL); + } + + /*g_print( "glade_signal_connect_func: cb_name = '%s', signal_name = '%s', signal_data = '%s'\n", + cb_name, signal_name, signal_data ); */ + + if (g_module_symbol (mod_self, cb_name, &handler_func)) + { + /* found callback */ + if (conn_obj) + { + if (conn_after) + { + g_signal_connect_object + (obj, signal_name, + handler_func, conn_obj, + G_CONNECT_AFTER); + } + else + { + g_signal_connect_object + (obj, signal_name, + handler_func, conn_obj, + G_CONNECT_SWAPPED); + } + } + else + { + /* no conn_obj; use standard connect */ + gpointer data = NULL; + + data = user_data; + + if (conn_after) + { + g_signal_connect_after + (obj, signal_name, + handler_func, data); + } + else + { + g_signal_connect + (obj, signal_name, + handler_func, data); + } + } + } + else + { + g_warning("callback function not found: %s", cb_name); + } +} diff --git a/lib/ephy-glade.h b/lib/ephy-glade.h new file mode 100644 index 000000000..cccf22f24 --- /dev/null +++ b/lib/ephy-glade.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2000 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_GLADE_H +#define EPHY_GLADE_H + +#include <glib.h> +#include <gtk/gtk.h> +#include <glade/glade-xml.h> + +typedef struct +{ + const gchar *name; + GtkWidget **ptr; +} WidgetLookup; + +G_BEGIN_DECLS + +GladeXML *ephy_glade_widget_new (const char *file, + const char *widget_name, + GtkWidget **root, + gpointer data); + +G_END_DECLS + +#endif diff --git a/lib/ephy-gobject-misc.h b/lib/ephy-gobject-misc.h new file mode 100644 index 000000000..c14ef1ae7 --- /dev/null +++ b/lib/ephy-gobject-misc.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#define MAKE_GET_TYPE(l,str,t,ci,i,parent) \ +GType l##_get_type(void)\ +{\ + static GType type = 0; \ + if (!type) { \ + static GTypeInfo const object_info = { \ + sizeof (t##Class), \ + \ + (GBaseInitFunc) NULL, \ + (GBaseFinalizeFunc) NULL, \ + \ + (GClassInitFunc) ci, \ + (GClassFinalizeFunc) NULL, \ + NULL, /* class_data */ \ + \ + sizeof (t), \ + 0, /* n_preallocs */ \ + (GInstanceInitFunc) i, \ + }; \ + type = g_type_register_static (parent, str, &object_info, 0); \ + } \ + return type; \ +} + +#define MAKE_GET_TYPE_IFACE(l,str,t,ci,i,parent,ii,iparent) \ +GType l##_get_type(void)\ +{\ + static GType type = 0; \ + if (!type) { \ + static GTypeInfo const object_info = { \ + sizeof (t##Class), \ + \ + (GBaseInitFunc) NULL, \ + (GBaseFinalizeFunc) NULL, \ + \ + (GClassInitFunc) ci, \ + (GClassFinalizeFunc) NULL, \ + NULL, /* class_data */ \ + \ + sizeof (t), \ + 0, /* n_preallocs */ \ + (GInstanceInitFunc) i, \ + }; \ + \ + static const GInterfaceInfo iface_info = { \ + (GInterfaceInitFunc) ii, \ + NULL, \ + NULL \ + }; \ + \ + type = g_type_register_static (parent, str, &object_info, (GTypeFlags)0); \ + \ + g_type_add_interface_static (type, \ + iparent, \ + &iface_info); \ + } \ + return type; \ +} + diff --git a/lib/ephy-gui.c b/lib/ephy-gui.c new file mode 100644 index 000000000..fe4018d38 --- /dev/null +++ b/lib/ephy-gui.c @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-gui.h" +#include "eel-gconf-extensions.h" + +#include <ctype.h> +#include <string.h> +#include <libgnome/gnome-i18n.h> +#include <gtk/gtktreemodel.h> + +/* Styles for tab labels */ +GtkStyle *loading_text_style = NULL; +GtkStyle *new_text_style = NULL; + +/** + * gul_gui_menu_position_under_widget: + */ +void +ephy_gui_menu_position_under_widget (GtkMenu *menu, + gint *x, + gint *y, + gboolean *push_in, + gpointer user_data) +{ + GtkWidget *w = GTK_WIDGET (user_data); + gint width, height; + gint screen_width, screen_height; + GtkRequisition requisition; + + gdk_drawable_get_size (w->window, &width, &height); + gdk_window_get_origin (w->window, x, y); + *y = *y + height; + + gtk_widget_size_request (GTK_WIDGET (menu), &requisition); + + screen_width = gdk_screen_width (); + screen_height = gdk_screen_height (); + + *x = CLAMP (*x, 0, MAX (0, screen_width - requisition.width)); + *y = CLAMP (*y, 0, MAX (0, screen_height - requisition.height)); +} + +/** + * gul_gui_gtk_radio_button_get: get the active member of a radiobutton + * group from one of the buttons in the group. This should be in GTK+! + */ +gint +ephy_gui_gtk_radio_button_get (GtkRadioButton *radio_button) +{ + GtkToggleButton *toggle_button; + gint i, length; + GSList *list; + + /* get group list */ + list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio_button)); + length = g_slist_length (list); + + /* iterate over list to find active button */ + for (i = 0; list != NULL; i++, list = g_slist_next (list)) + { + /* get button and text */ + toggle_button = GTK_TOGGLE_BUTTON (list->data); + if (gtk_toggle_button_get_active (toggle_button)) + { + break; + } + } + + /* check we didn't run off end */ + g_assert (list != NULL); + + /* return index (reverse order!) */ + return (length - 1) - i; +} + +/** + * gul_gui_gtk_radio_button_set: set the active member of a radiobutton + * group from one of the buttons in the group. This should be in GTK+! + */ +void +ephy_gui_gtk_radio_button_set (GtkRadioButton *radio_button, gint index) +{ + GtkToggleButton *button; + GSList *list; + gint length; + + /* get the list */ + list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio_button)); + + /* check out the length */ + length = g_slist_length (list); + + /* new buttons are *preppended* to the list, so button added as first + * has last position in the list */ + index = (length - 1) - index; + + /* find the right button */ + button = GTK_TOGGLE_BUTTON (g_slist_nth_data (list, index)); + + /* set it... this will de-activate the others in the group */ + if (gtk_toggle_button_get_active (button) == FALSE) + { + gtk_toggle_button_set_active (button, TRUE); + } +} + +GtkWidget * +ephy_gui_append_new_menuitem (GtkWidget *menu, + const char *mnemonic, + GCallback callback, + gpointer data) +{ + GtkWidget *menu_item; + + menu_item = gtk_menu_item_new_with_mnemonic (mnemonic); + gtk_widget_show (menu_item); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), + menu_item); + + if (callback) + { + g_signal_connect (G_OBJECT (menu_item), + "activate", + callback, data); + } + + return menu_item; +} + +GtkWidget * +ephy_gui_append_new_menuitem_stock (GtkWidget *menu, + const char *stock_id, + GCallback callback, + gpointer data) +{ + GtkWidget *menu_item; + + menu_item = gtk_image_menu_item_new_from_stock (stock_id, NULL); + gtk_widget_show (menu_item); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), + menu_item); + + if (callback) + { + g_signal_connect (G_OBJECT (menu_item), + "activate", + callback, data); + } + + return menu_item; +} + +GtkWidget * +ephy_gui_append_new_menuitem_stock_icon (GtkWidget *menu, + const char *stock_id, + const char *mnemonic, + GCallback callback, + gpointer data) +{ + GtkWidget *menu_item; + GtkWidget *image; + + menu_item = gtk_image_menu_item_new_with_mnemonic (mnemonic); + image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU); + gtk_widget_show (image); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), image); + + gtk_widget_show (menu_item); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), + menu_item); + + if (callback) + { + g_signal_connect (G_OBJECT (menu_item), + "activate", + callback, data); + } + + return menu_item; +} + +GtkWidget * +ephy_gui_append_new_check_menuitem (GtkWidget *menu, + const char *mnemonic, + gboolean value, + GCallback callback, + gpointer data) +{ + GtkWidget *menu_item; + + menu_item = gtk_check_menu_item_new_with_mnemonic (mnemonic); + gtk_widget_show (menu_item); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), + menu_item); + + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), value); + + if (callback) + { + g_signal_connect (G_OBJECT (menu_item), + "activate", + callback, data); + } + + return menu_item; +} + +GtkWidget * +ephy_gui_append_separator (GtkWidget *menu) +{ + GtkWidget *menu_item; + + menu_item = gtk_menu_item_new (); + gtk_widget_show (menu_item); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), + menu_item); + + return menu_item; +} + +gboolean +ephy_gui_confirm_overwrite_file (GtkWidget *parent, const char *filename) +{ + char *question; + GtkWidget *dialog; + gboolean res; + + if (!g_file_test (filename, G_FILE_TEST_EXISTS)) + { + return TRUE; + } + + question = g_strdup_printf (_("File %s will be overwritten.\n" + "If you choose yes, the contents will be lost.\n\n" + "Do you want to continue?"), filename); + dialog = gtk_message_dialog_new (parent ? GTK_WINDOW(parent) : NULL, + GTK_DIALOG_MODAL, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_YES_NO, + question); + res = (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES); + gtk_widget_destroy (dialog); + g_free (question); + + return res; +} + +static guint32 +shift_color_component (guchar component, float shift_by) +{ + guint32 result; + if (shift_by > 1.0) { + result = component * (2 - shift_by); + } else { + result = 0xff - shift_by * (0xff - component); + } + + return result & 0xff; +} + +/** + * ephy_gui_rgb_shift_color + * @color: A color. + * @shift_by: darken or lighten factor. + * Returns: An darkened or lightened rgb value. + * + * Darkens (@shift_by > 1) or lightens (@shift_by < 1) + * @color. + */ +guint32 +ephy_gui_rgb_shift_color (guint32 color, float shift_by) +{ + guint32 result; + + /* shift red by shift_by */ + result = shift_color_component((color & 0x00ff0000) >> 16, shift_by); + result <<= 8; + /* shift green by shift_by */ + result |= shift_color_component((color & 0x0000ff00) >> 8, shift_by); + result <<= 8; + /* shift blue by shift_by */ + result |= shift_color_component((color & 0x000000ff), shift_by); + + /* alpha doesn't change */ + result |= (0xff000000 & color); + + return result; +} + +static guint32 +rgb16_to_rgb (gushort r, gushort g, gushort b) +{ + guint32 result; + + result = (0xff0000 | (r & 0xff00)); + result <<= 8; + result |= ((g & 0xff00) | (b >> 8)); + + return result; +} + +/** + * ephy_gui_gdk_color_to_rgb + * @color: A GdkColor style color. + * Returns: An rgb value. + * + * Converts from a GdkColor stlye color to a gdk_rgb one. + * Alpha gets set to fully opaque + */ +guint32 +ephy_gui_gdk_color_to_rgb (const GdkColor *color) +{ + return rgb16_to_rgb (color->red, color->green, color->blue); +} + +/** + * ephy_gui_rgb_to_color + * @color: a gdk_rgb style value. + * + * Converts from a gdk_rgb value style to a GdkColor one. + * The gdk_rgb color alpha channel is ignored. + * + * Return value: A GdkColor structure version of the given RGB color. + */ +GdkColor +ephy_gui_gdk_rgb_to_color (guint32 color) +{ + GdkColor result; + + result.red = ((color >> 16) & 0xFF) * 0x101; + result.green = ((color >> 8) & 0xFF) * 0x101; + result.blue = (color & 0xff) * 0x101; + result.pixel = 0; + + return result; +} diff --git a/lib/ephy-gui.h b/lib/ephy-gui.h new file mode 100644 index 000000000..0d736592f --- /dev/null +++ b/lib/ephy-gui.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_GUI_H +#define EPHY_GUI_H + +/* system includes */ +#include <gtk/gtk.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <libgnomeui/gnome-dialog.h> +#include <gnome.h> + +G_BEGIN_DECLS + +void ephy_gui_menu_position_under_widget (GtkMenu *menu, + gint *x, + gint *y, + gboolean *push_in, + gpointer user_data); + +gint ephy_gui_gtk_radio_button_get (GtkRadioButton *radio_button); + +void ephy_gui_gtk_radio_button_set (GtkRadioButton *radio_button, + gint index); + +GList *ephy_gui_treeview_get_selection_refs (GtkTreeView *treeview); + +GtkWidget *ephy_gui_append_new_menuitem (GtkWidget *menu, + const char *mnemonic, + GCallback callback, + gpointer data); + +GtkWidget *ephy_gui_append_new_menuitem_stock (GtkWidget *menu, + const char *stock_id, + GCallback callback, + gpointer data); + +GtkWidget *ephy_gui_append_new_menuitem_stock_icon (GtkWidget *menu, + const char *stock_id, + const char *mnemonic, + GCallback callback, + gpointer data); + +GtkWidget *ephy_gui_append_new_check_menuitem (GtkWidget *menu, + const char *mnemonic, + gboolean value, + GCallback callback, + gpointer data); + +GtkWidget *ephy_gui_append_separator (GtkWidget *menu); + +gboolean ephy_gui_confirm_overwrite_file (GtkWidget *parent, + const char *filename); + +guint32 ephy_gui_rgb_shift_color (guint32 color, + float shift_by); + +guint32 ephy_gui_gdk_color_to_rgb (const GdkColor *color); + +GdkColor ephy_gui_gdk_rgb_to_color (guint32 color); + +G_END_DECLS + +#endif diff --git a/lib/ephy-marshal.list b/lib/ephy-marshal.list new file mode 100644 index 000000000..9082cae25 --- /dev/null +++ b/lib/ephy-marshal.list @@ -0,0 +1,16 @@ +VOID:VOID +VOID:STRING +VOID:OBJECT +VOID:OBJECT,OBJECT,INT +VOID:OBJECT,STRING,INT +VOID:OBJECT,INT +VOID:OBJECT,INT,INT +VOID:POINTER,INT +VOID:STRING,INT,INT +VOID:STRING,INT +VOID:STRING,STRING +INT:STRING +VOID:INT,INT +VOID:INT,INT,INT +INT:OBJECT +VOID:POINTER,POINTER diff --git a/lib/ephy-node-filter.c b/lib/ephy-node-filter.c new file mode 100644 index 000000000..8f0bddbc0 --- /dev/null +++ b/lib/ephy-node-filter.c @@ -0,0 +1,461 @@ +/* + * Copyright (C) 2002 Olivier Martin <omartin@ifrance.com> + * (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include "ephy-node-filter.h" + +static void ephy_node_filter_class_init (EphyNodeFilterClass *klass); +static void ephy_node_filter_init (EphyNodeFilter *node); +static void ephy_node_filter_finalize (GObject *object); +static gboolean ephy_node_filter_expression_evaluate (EphyNodeFilterExpression *expression, + EphyNode *node); + +enum +{ + CHANGED, + LAST_SIGNAL +}; + +struct EphyNodeFilterPrivate +{ + GPtrArray *levels; +}; + +struct EphyNodeFilterExpression +{ + EphyNodeFilterExpressionType type; + + union + { + struct + { + EphyNode *a; + EphyNode *b; + } node_args; + + struct + { + int prop_id; + + union + { + EphyNode *node; + char *string; + int number; + } second_arg; + } prop_args; + } args; +}; + +static GObjectClass *parent_class = NULL; + +static guint ephy_node_filter_signals[LAST_SIGNAL] = { 0 }; + +GType +ephy_node_filter_get_type (void) +{ + static GType ephy_node_filter_type = 0; + + if (ephy_node_filter_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyNodeFilterClass), + NULL, + NULL, + (GClassInitFunc) ephy_node_filter_class_init, + NULL, + NULL, + sizeof (EphyNodeFilter), + 0, + (GInstanceInitFunc) ephy_node_filter_init + }; + + ephy_node_filter_type = g_type_register_static (G_TYPE_OBJECT, + "EphyNodeFilter", + &our_info, 0); + } + + return ephy_node_filter_type; +} + +static void +ephy_node_filter_class_init (EphyNodeFilterClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_node_filter_finalize; + + ephy_node_filter_signals[CHANGED] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyNodeFilterClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +static void +ephy_node_filter_init (EphyNodeFilter *filter) +{ + filter->priv = g_new0 (EphyNodeFilterPrivate, 1); + + filter->priv->levels = g_ptr_array_new (); +} + +static void +ephy_node_filter_finalize (GObject *object) +{ + EphyNodeFilter *filter; + + g_return_if_fail (object != NULL); + g_return_if_fail (EPHY_IS_NODE_FILTER (object)); + + filter = EPHY_NODE_FILTER (object); + + g_return_if_fail (filter->priv != NULL); + + ephy_node_filter_empty (filter); + + g_ptr_array_free (filter->priv->levels, FALSE); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +EphyNodeFilter * +ephy_node_filter_new (void) +{ + EphyNodeFilter *filter; + + filter = EPHY_NODE_FILTER (g_object_new (EPHY_TYPE_NODE_FILTER, + NULL)); + + g_return_val_if_fail (filter->priv != NULL, NULL); + + return filter; +} + +void +ephy_node_filter_add_expression (EphyNodeFilter *filter, + EphyNodeFilterExpression *exp, + int level) +{ + while (level >= filter->priv->levels->len) + g_ptr_array_add (filter->priv->levels, NULL); + + g_ptr_array_index (filter->priv->levels, level) = + g_list_append (g_ptr_array_index (filter->priv->levels, level), exp); +} + +void +ephy_node_filter_empty (EphyNodeFilter *filter) +{ + int i; + + for (i = filter->priv->levels->len - 1; i >= 0; i--) + { + GList *list, *l; + + list = g_ptr_array_index (filter->priv->levels, i); + + for (l = list; l != NULL; l = g_list_next (l)) + { + EphyNodeFilterExpression *exp; + + exp = (EphyNodeFilterExpression *) l->data; + + ephy_node_filter_expression_free (exp); + } + + g_list_free (list); + + g_ptr_array_remove_index (filter->priv->levels, i); + } +} + +void +ephy_node_filter_done_changing (EphyNodeFilter *filter) +{ + g_signal_emit (G_OBJECT (filter), ephy_node_filter_signals[CHANGED], 0); +} + +/* + * We go through each level evaluating the filter expressions. + * Every time we get a match we immediately do a break and jump + * to the next level. We'll return FALSE if we arrive to a level + * without matches, TRUE otherwise. + */ +gboolean +ephy_node_filter_evaluate (EphyNodeFilter *filter, + EphyNode *node) +{ + int i; + + for (i = 0; i < filter->priv->levels->len; i++) { + GList *l, *list; + gboolean handled; + + handled = FALSE; + + list = g_ptr_array_index (filter->priv->levels, i); + + for (l = list; l != NULL; l = g_list_next (l)) { + if (ephy_node_filter_expression_evaluate (l->data, node) == TRUE) { + handled = TRUE; + break; + } + } + + if (handled == FALSE) + return FALSE; + } + + return TRUE; +} + +EphyNodeFilterExpression * +ephy_node_filter_expression_new (EphyNodeFilterExpressionType type, + ...) +{ + EphyNodeFilterExpression *exp; + va_list valist; + + va_start (valist, type); + + exp = g_new0 (EphyNodeFilterExpression, 1); + + exp->type = type; + + switch (type) + { + case EPHY_NODE_FILTER_EXPRESSION_NODE_EQUALS: + exp->args.node_args.a = va_arg (valist, EphyNode *); + exp->args.node_args.b = va_arg (valist, EphyNode *); + break; + case EPHY_NODE_FILTER_EXPRESSION_EQUALS: + case EPHY_NODE_FILTER_EXPRESSION_HAS_PARENT: + case EPHY_NODE_FILTER_EXPRESSION_HAS_CHILD: + exp->args.node_args.a = va_arg (valist, EphyNode *); + break; + case EPHY_NODE_FILTER_EXPRESSION_NODE_PROP_EQUALS: + case EPHY_NODE_FILTER_EXPRESSION_CHILD_PROP_EQUALS: + exp->args.prop_args.prop_id = va_arg (valist, int); + exp->args.prop_args.second_arg.node = va_arg (valist, EphyNode *); + break; + case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS: + case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_EQUALS: + exp->args.prop_args.prop_id = va_arg (valist, int); + exp->args.prop_args.second_arg.string = g_utf8_casefold (va_arg (valist, char *), -1); + break; + case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_CONTAINS: + case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_EQUALS: + { + char *folded; + + exp->args.prop_args.prop_id = va_arg (valist, int); + + folded = g_utf8_casefold (va_arg (valist, char *), -1); + exp->args.prop_args.second_arg.string = g_utf8_collate_key (folded, -1); + g_free (folded); + break; + } + case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_EQUALS: + case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_BIGGER_THAN: + case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_LESS_THAN: + exp->args.prop_args.prop_id = va_arg (valist, int); + exp->args.prop_args.second_arg.number = va_arg (valist, int); + break; + default: + break; + } + + va_end (valist); + + return exp; +} + +void +ephy_node_filter_expression_free (EphyNodeFilterExpression *exp) +{ + switch (exp->type) + { + case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS: + case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_EQUALS: + case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_CONTAINS: + case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_EQUALS: + g_free (exp->args.prop_args.second_arg.string); + break; + default: + break; + } + + g_free (exp); +} + +static gboolean +ephy_node_filter_expression_evaluate (EphyNodeFilterExpression *exp, + EphyNode *node) +{ + switch (exp->type) + { + case EPHY_NODE_FILTER_EXPRESSION_ALWAYS_TRUE: + return TRUE; + case EPHY_NODE_FILTER_EXPRESSION_NODE_EQUALS: + return (exp->args.node_args.a == exp->args.node_args.b); + case EPHY_NODE_FILTER_EXPRESSION_EQUALS: + return (exp->args.node_args.a == node); + case EPHY_NODE_FILTER_EXPRESSION_HAS_PARENT: + return ephy_node_has_child (exp->args.node_args.a, node); + case EPHY_NODE_FILTER_EXPRESSION_HAS_CHILD: + return ephy_node_has_child (node, exp->args.node_args.a); + case EPHY_NODE_FILTER_EXPRESSION_NODE_PROP_EQUALS: + { + EphyNode *prop; + + prop = ephy_node_get_property_node (node, + exp->args.prop_args.prop_id); + + return (prop == exp->args.prop_args.second_arg.node); + } + case EPHY_NODE_FILTER_EXPRESSION_CHILD_PROP_EQUALS: + { + EphyNode *prop; + GPtrArray *children; + int i; + + children = ephy_node_get_children (node); + for (i = 0; i < children->len; i++) + { + EphyNode *child; + + child = g_ptr_array_index (children, i); + prop = ephy_node_get_property_node + (child, exp->args.prop_args.prop_id); + + if (prop == exp->args.prop_args.second_arg.node) + { + ephy_node_thaw (node); + return TRUE; + } + } + + ephy_node_thaw (node); + return FALSE; + } + case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS: + { + const char *prop; + char *folded_case; + gboolean ret; + + prop = ephy_node_get_property_string (node, + exp->args.prop_args.prop_id); + if (prop == NULL) + return FALSE; + + folded_case = g_utf8_casefold (prop, -1); + ret = (strstr (folded_case, exp->args.prop_args.second_arg.string) != NULL); + g_free (folded_case); + + return ret; + } + case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_EQUALS: + { + const char *prop; + char *folded_case; + gboolean ret; + + prop = ephy_node_get_property_string (node, + exp->args.prop_args.prop_id); + + if (prop == NULL) + return FALSE; + + folded_case = g_utf8_casefold (prop, -1); + ret = (strcmp (folded_case, exp->args.prop_args.second_arg.string) == 0); + g_free (folded_case); + + return ret; + } + case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_CONTAINS: + { + const char *prop; + + prop = ephy_node_get_property_string (node, + exp->args.prop_args.prop_id); + + if (prop == NULL) + return FALSE; + + return (strstr (prop, exp->args.prop_args.second_arg.string) != NULL); + } + case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_EQUALS: + { + const char *prop; + + prop = ephy_node_get_property_string (node, + exp->args.prop_args.prop_id); + + if (prop == NULL) + return FALSE; + + return (strcmp (prop, exp->args.prop_args.second_arg.string) == 0); + } + case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_EQUALS: + { + int prop; + + prop = ephy_node_get_property_int (node, + exp->args.prop_args.prop_id); + + return (prop == exp->args.prop_args.second_arg.number); + } + case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_BIGGER_THAN: + { + int prop; + + prop = ephy_node_get_property_int (node, + exp->args.prop_args.prop_id); + + return (prop > exp->args.prop_args.second_arg.number); + } + case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_LESS_THAN: + { + int prop; + + prop = ephy_node_get_property_int (node, + exp->args.prop_args.prop_id); + g_print ("%d %d\n", prop, exp->args.prop_args.second_arg.number); + return (prop < exp->args.prop_args.second_arg.number); + } + default: + break; + } + + return FALSE; +} diff --git a/lib/ephy-node-filter.h b/lib/ephy-node-filter.h new file mode 100644 index 000000000..1aedc16c6 --- /dev/null +++ b/lib/ephy-node-filter.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2002 Olivier Martin <omartin@ifrance.com> + * (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef EPHY_NODE_FILTER_H +#define EPHY_NODE_FILTER_H + +#include <glib-object.h> + +#include "ephy-node.h" + +G_BEGIN_DECLS + +#define EPHY_TYPE_NODE_FILTER (ephy_node_filter_get_type ()) +#define EPHY_NODE_FILTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_NODE_FILTER, EphyNodeFilter)) +#define EPHY_NODE_FILTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_NODE_FILTER, EphyNodeFilterClass)) +#define EPHY_IS_NODE_FILTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_NODE_FILTER)) +#define EPHY_IS_NODE_FILTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_NODE_FILTER)) +#define EPHY_NODE_FILTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_NODE_FILTER, EphyNodeFilterClass)) + +typedef struct EphyNodeFilterPrivate EphyNodeFilterPrivate; + +typedef struct +{ + GObject parent; + + EphyNodeFilterPrivate *priv; +} EphyNodeFilter; + +typedef struct +{ + GObjectClass parent; + + void (*changed) (EphyNodeFilter *filter); +} EphyNodeFilterClass; + +typedef enum +{ + EPHY_NODE_FILTER_EXPRESSION_ALWAYS_TRUE, /* args: none */ + EPHY_NODE_FILTER_EXPRESSION_NODE_EQUALS, /* args: EphyNode *a, EphyNode *b */ + EPHY_NODE_FILTER_EXPRESSION_EQUALS, /* args: EphyNode *node */ + EPHY_NODE_FILTER_EXPRESSION_HAS_PARENT, /* args: EphyNode *parent */ + EPHY_NODE_FILTER_EXPRESSION_HAS_CHILD, /* args: EphyNode *child */ + EPHY_NODE_FILTER_EXPRESSION_NODE_PROP_EQUALS, /* args: int prop_id, EphyNode *node */ + EPHY_NODE_FILTER_EXPRESSION_CHILD_PROP_EQUALS, /* args: int prop_id, EphyNode *node */ + EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS, /* args: int prop_id, const char *string */ + EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_EQUALS, /* args: int prop_id, const char *string */ + EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_CONTAINS, /* args: int prop_id, const char *string */ + EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_EQUALS, /* args: int prop_id, const char *string */ + EPHY_NODE_FILTER_EXPRESSION_INT_PROP_EQUALS, /* args: int prop_id, int int */ + EPHY_NODE_FILTER_EXPRESSION_INT_PROP_BIGGER_THAN, /* args: int prop_id, int int */ + EPHY_NODE_FILTER_EXPRESSION_INT_PROP_LESS_THAN /* args: int prop_id, int int */ +} EphyNodeFilterExpressionType; + +typedef struct EphyNodeFilterExpression EphyNodeFilterExpression; + +/* The filter starts iterating over all expressions at level 0, + * if one of them is TRUE it continues to level 1, etc. + * If it still has TRUE when there are no more expressions at the + * next level, the result is TRUE. Otherwise, it's FALSE. + */ + +GType ephy_node_filter_get_type (void); + +EphyNodeFilter *ephy_node_filter_new (void); + +void ephy_node_filter_add_expression (EphyNodeFilter *filter, + EphyNodeFilterExpression *expression, + int level); + +void ephy_node_filter_empty (EphyNodeFilter *filter); + +void ephy_node_filter_done_changing (EphyNodeFilter *filter); + +gboolean ephy_node_filter_evaluate (EphyNodeFilter *filter, + EphyNode *node); + +EphyNodeFilterExpression *ephy_node_filter_expression_new (EphyNodeFilterExpressionType, + ...); +/* no need to free unless you didn't add the expression to a filter */ +void ephy_node_filter_expression_free (EphyNodeFilterExpression *expression); + +G_END_DECLS + +#endif /* EPHY_NODE_FILTER_H */ diff --git a/lib/ephy-node.c b/lib/ephy-node.c new file mode 100644 index 000000000..b75df9349 --- /dev/null +++ b/lib/ephy-node.c @@ -0,0 +1,1439 @@ +/* + * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include <config.h> +#include <libgnome/gnome-i18n.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <gdk/gdk.h> +#include <time.h> + +#include "ephy-node.h" +#include "ephy-string.h" +#include "ephy-thread-helpers.h" + +static void ephy_node_class_init (EphyNodeClass *klass); +static void ephy_node_init (EphyNode *node); +static void ephy_node_finalize (GObject *object); +static void ephy_node_dispose (GObject *object); +static void ephy_node_set_object_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ephy_node_get_object_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static inline void id_factory_set_to (gulong new_factory_pos); +static inline void real_set_property (EphyNode *node, + guint property_id, + GValue *value); +static inline void real_remove_child (EphyNode *node, + EphyNode *child, + gboolean remove_from_parent, + gboolean remove_from_child); +static inline void real_add_child (EphyNode *node, + EphyNode *child); +static inline void read_lock_to_write_lock (EphyNode *node); +static inline void write_lock_to_read_lock (EphyNode *node); +static inline void lock_gdk (void); +static inline void unlock_gdk (void); +static inline EphyNode *node_from_id_real (gulong id); +static inline int get_child_index_real (EphyNode *node, + EphyNode *child); + +typedef struct +{ + EphyNode *node; + guint index; +} EphyNodeParent; + +struct EphyNodePrivate +{ + GStaticRWLock *lock; + + int ref_count; + + gulong id; + + GPtrArray *properties; + + GHashTable *parents; + GPtrArray *children; +}; + +enum +{ + PROP_0, + PROP_ID +}; + +enum +{ + DESTROYED, + RESTORED, + CHILD_ADDED, + CHILD_CHANGED, + CHILD_REMOVED, + LAST_SIGNAL +}; + +static GObjectClass *parent_class = NULL; + +static guint ephy_node_signals[LAST_SIGNAL] = { 0 }; + +static GMutex *id_factory_lock = NULL; +static long id_factory = 0; + +static GStaticRWLock *id_to_node_lock = NULL; +static GPtrArray *id_to_node; + +GType +ephy_node_get_type (void) +{ + static GType ephy_node_type = 0; + + if (ephy_node_type == 0) { + static const GTypeInfo our_info = { + sizeof (EphyNodeClass), + NULL, + NULL, + (GClassInitFunc) ephy_node_class_init, + NULL, + NULL, + sizeof (EphyNode), + 0, + (GInstanceInitFunc) ephy_node_init + }; + + ephy_node_type = g_type_register_static (G_TYPE_OBJECT, + "EphyNode", + &our_info, 0); + } + + return ephy_node_type; +} + +static void +ephy_node_class_init (EphyNodeClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_node_finalize; + object_class->dispose = ephy_node_dispose; + + object_class->set_property = ephy_node_set_object_property; + object_class->get_property = ephy_node_get_object_property; + + g_object_class_install_property (object_class, + PROP_ID, + g_param_spec_long ("id", + "Node ID", + "Node ID", + 0, G_MAXLONG, 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + ephy_node_signals[DESTROYED] = + g_signal_new ("destroyed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyNodeClass, destroyed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + ephy_node_signals[RESTORED] = + g_signal_new ("restored", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyNodeClass, restored), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + ephy_node_signals[CHILD_ADDED] = + g_signal_new ("child_added", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyNodeClass, child_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + EPHY_TYPE_NODE); + ephy_node_signals[CHILD_CHANGED] = + g_signal_new ("child_changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyNodeClass, child_changed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + EPHY_TYPE_NODE); + ephy_node_signals[CHILD_REMOVED] = + g_signal_new ("child_removed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyNodeClass, child_removed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + EPHY_TYPE_NODE); +} + +static gboolean +int_equal (gconstpointer a, + gconstpointer b) +{ + return GPOINTER_TO_INT (a) == GPOINTER_TO_INT (b); +} + +static guint +int_hash (gconstpointer a) +{ + return GPOINTER_TO_INT (a); +} + +static void +ephy_node_init (EphyNode *node) +{ + node->priv = g_new0 (EphyNodePrivate, 1); + + node->priv->lock = g_new0 (GStaticRWLock, 1); + g_static_rw_lock_init (node->priv->lock); + + node->priv->ref_count = 0; + + node->priv->id = -1; + + node->priv->properties = g_ptr_array_new (); + + node->priv->parents = g_hash_table_new_full (int_hash, + int_equal, + NULL, + g_free); + + node->priv->children = g_ptr_array_new (); +} + +static void +ephy_node_finalize (GObject *object) +{ + EphyNode *node; + guint i; + + g_return_if_fail (object != NULL); + g_return_if_fail (EPHY_IS_NODE (object)); + + node = EPHY_NODE (object); + + g_return_if_fail (node->priv != NULL); + + for (i = 0; i < node->priv->properties->len; i++) { + GValue *val; + + val = g_ptr_array_index (node->priv->properties, i); + + if (val != NULL) { + g_value_unset (val); + g_free (val); + } + } + g_ptr_array_free (node->priv->properties, FALSE); + + g_hash_table_destroy (node->priv->parents); + + g_ptr_array_free (node->priv->children, FALSE); + + g_static_rw_lock_free (node->priv->lock); + + g_free (node->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +remove_child (long id, + EphyNodeParent *node_info, + EphyNode *node) +{ + g_static_rw_lock_writer_lock (node_info->node->priv->lock); + + real_remove_child (node_info->node, node, TRUE, FALSE); + + g_static_rw_lock_writer_unlock (node_info->node->priv->lock); +} + +static void +ephy_node_dispose (GObject *object) +{ + EphyNode *node; + guint i; + + node = EPHY_NODE (object); + + /* remove from id table */ + g_static_rw_lock_writer_lock (id_to_node_lock); + + g_ptr_array_index (id_to_node, node->priv->id) = NULL; + + g_static_rw_lock_writer_unlock (id_to_node_lock); + + lock_gdk (); + + /* remove from DAG */ + g_hash_table_foreach (node->priv->parents, + (GHFunc) remove_child, + node); + + for (i = 0; i < node->priv->children->len; i++) { + EphyNode *child; + + child = g_ptr_array_index (node->priv->children, i); + + g_static_rw_lock_writer_lock (child->priv->lock); + + real_remove_child (node, child, FALSE, TRUE); + + g_static_rw_lock_writer_unlock (child->priv->lock); + } + + g_static_rw_lock_writer_unlock (node->priv->lock); + + g_signal_emit (G_OBJECT (node), ephy_node_signals[DESTROYED], 0); + + unlock_gdk (); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +ephy_node_set_object_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyNode *node = EPHY_NODE (object); + + switch (prop_id) + { + case PROP_ID: + node->priv->id = g_value_get_long (value); + + g_static_rw_lock_writer_lock (id_to_node_lock); + + /* resize array if needed */ + if (node->priv->id >= id_to_node->len) + g_ptr_array_set_size (id_to_node, node->priv->id + 1); + + g_ptr_array_index (id_to_node, node->priv->id) = node; + + g_static_rw_lock_writer_unlock (id_to_node_lock); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ephy_node_get_object_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyNode *node = EPHY_NODE (object); + + switch (prop_id) + { + case PROP_ID: + g_value_set_long (value, node->priv->id); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +EphyNode * +ephy_node_new (void) +{ + EphyNode *node; + + node = EPHY_NODE (g_object_new (EPHY_TYPE_NODE, + "id", ephy_node_new_id (), + NULL)); + + g_return_val_if_fail (node->priv != NULL, NULL); + + return node; +} + +long +ephy_node_get_id (EphyNode *node) +{ + long ret; + + g_return_val_if_fail (EPHY_IS_NODE (node), -1); + + g_static_rw_lock_reader_lock (node->priv->lock); + + ret = node->priv->id; + + g_static_rw_lock_reader_unlock (node->priv->lock); + + return ret; +} + +static inline EphyNode * +node_from_id_real (gulong id) +{ + EphyNode *ret = NULL; + + if (id < id_to_node->len) + ret = g_ptr_array_index (id_to_node, id);; + + return ret; +} + +EphyNode * +ephy_node_get_from_id (gulong id) +{ + EphyNode *ret = NULL; + + g_return_val_if_fail (id > 0, NULL); + + g_static_rw_lock_reader_lock (id_to_node_lock); + + ret = node_from_id_real (id); + + g_static_rw_lock_reader_unlock (id_to_node_lock); + + return ret; +} + +void +ephy_node_ref (EphyNode *node) +{ + g_return_if_fail (EPHY_IS_NODE (node)); + + g_static_rw_lock_writer_lock (node->priv->lock); + + node->priv->ref_count++; + + g_static_rw_lock_writer_unlock (node->priv->lock); +} + +void +ephy_node_unref (EphyNode *node) +{ + g_return_if_fail (EPHY_IS_NODE (node)); + + g_static_rw_lock_writer_lock (node->priv->lock); + + node->priv->ref_count--; + + if (node->priv->ref_count <= 0) { + g_object_unref (G_OBJECT (node)); + } else { + g_static_rw_lock_writer_unlock (node->priv->lock); + } +} + +void +ephy_node_freeze (EphyNode *node) +{ + g_return_if_fail (EPHY_IS_NODE (node)); + + g_static_rw_lock_reader_lock (node->priv->lock); +} + +void +ephy_node_thaw (EphyNode *node) +{ + g_return_if_fail (EPHY_IS_NODE (node)); + + g_static_rw_lock_reader_unlock (node->priv->lock); +} + +static void +child_changed (gulong id, + EphyNodeParent *node_info, + EphyNode *node) +{ + g_static_rw_lock_reader_lock (node_info->node->priv->lock); + + g_signal_emit (G_OBJECT (node_info->node), ephy_node_signals[CHILD_CHANGED], 0, node); + + g_static_rw_lock_reader_unlock (node_info->node->priv->lock); +} + +static inline void +real_set_property (EphyNode *node, + guint property_id, + GValue *value) +{ + GValue *old; + + if (property_id >= node->priv->properties->len) { + g_ptr_array_set_size (node->priv->properties, property_id + 1); + } + + old = g_ptr_array_index (node->priv->properties, property_id); + if (old != NULL) { + g_value_unset (old); + g_free (old); + } + + g_ptr_array_index (node->priv->properties, property_id) = value; +} + +void +ephy_node_set_property (EphyNode *node, + guint property_id, + const GValue *value) +{ + GValue *new; + + g_return_if_fail (EPHY_IS_NODE (node)); + g_return_if_fail (property_id >= 0); + g_return_if_fail (value != NULL); + + lock_gdk (); + + g_static_rw_lock_writer_lock (node->priv->lock); + + new = g_new0 (GValue, 1); + g_value_init (new, G_VALUE_TYPE (value)); + g_value_copy (value, new); + + real_set_property (node, property_id, new); + + write_lock_to_read_lock (node); + + g_hash_table_foreach (node->priv->parents, + (GHFunc) child_changed, + node); + + g_static_rw_lock_reader_unlock (node->priv->lock); + + unlock_gdk (); +} + +gboolean +ephy_node_get_property (EphyNode *node, + guint property_id, + GValue *value) +{ + GValue *ret; + + g_return_val_if_fail (EPHY_IS_NODE (node), FALSE); + g_return_val_if_fail (property_id >= 0, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + g_static_rw_lock_reader_lock (node->priv->lock); + + if (property_id >= node->priv->properties->len) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return FALSE; + } + + ret = g_ptr_array_index (node->priv->properties, property_id); + if (ret == NULL) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return FALSE; + } + + g_value_init (value, G_VALUE_TYPE (ret)); + g_value_copy (ret, value); + + g_static_rw_lock_reader_unlock (node->priv->lock); + + return TRUE; +} + +const char * +ephy_node_get_property_string (EphyNode *node, + guint property_id) +{ + GValue *ret; + const char *retval; + + g_return_val_if_fail (EPHY_IS_NODE (node), NULL); + g_return_val_if_fail (property_id >= 0, NULL); + + g_static_rw_lock_reader_lock (node->priv->lock); + + if (property_id >= node->priv->properties->len) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return NULL; + } + + ret = g_ptr_array_index (node->priv->properties, property_id); + if (ret == NULL) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return NULL; + } + + retval = g_value_get_string (ret); + + g_static_rw_lock_reader_unlock (node->priv->lock); + + return retval; +} + +gboolean +ephy_node_get_property_boolean (EphyNode *node, + guint property_id) +{ + GValue *ret; + gboolean retval; + + g_return_val_if_fail (EPHY_IS_NODE (node), FALSE); + g_return_val_if_fail (property_id >= 0, FALSE); + + g_static_rw_lock_reader_lock (node->priv->lock); + + if (property_id >= node->priv->properties->len) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return FALSE; + } + + ret = g_ptr_array_index (node->priv->properties, property_id); + if (ret == NULL) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return FALSE; + } + + retval = g_value_get_boolean (ret); + + g_static_rw_lock_reader_unlock (node->priv->lock); + + return retval; +} + +long +ephy_node_get_property_long (EphyNode *node, + guint property_id) +{ + GValue *ret; + long retval; + + g_return_val_if_fail (EPHY_IS_NODE (node), -1); + g_return_val_if_fail (property_id >= 0, -1); + + g_static_rw_lock_reader_lock (node->priv->lock); + + if (property_id >= node->priv->properties->len) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return -1; + } + + ret = g_ptr_array_index (node->priv->properties, property_id); + if (ret == NULL) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return -1; + } + + retval = g_value_get_long (ret); + + g_static_rw_lock_reader_unlock (node->priv->lock); + + return retval; +} + +int +ephy_node_get_property_int (EphyNode *node, + guint property_id) +{ + GValue *ret; + int retval; + + g_return_val_if_fail (EPHY_IS_NODE (node), -1); + g_return_val_if_fail (property_id >= 0, -1); + + g_static_rw_lock_reader_lock (node->priv->lock); + + if (property_id >= node->priv->properties->len) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return -1; + } + + ret = g_ptr_array_index (node->priv->properties, property_id); + if (ret == NULL) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return -1; + } + + retval = g_value_get_int (ret); + + g_static_rw_lock_reader_unlock (node->priv->lock); + + return retval; +} + +double +ephy_node_get_property_double (EphyNode *node, + guint property_id) +{ + GValue *ret; + double retval; + + g_return_val_if_fail (EPHY_IS_NODE (node), -1); + g_return_val_if_fail (property_id >= 0, -1); + + g_static_rw_lock_reader_lock (node->priv->lock); + + if (property_id >= node->priv->properties->len) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return -1; + } + + ret = g_ptr_array_index (node->priv->properties, property_id); + if (ret == NULL) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return -1; + } + + retval = g_value_get_double (ret); + + g_static_rw_lock_reader_unlock (node->priv->lock); + + return retval; +} + +float +ephy_node_get_property_float (EphyNode *node, + guint property_id) +{ + GValue *ret; + float retval; + + g_return_val_if_fail (EPHY_IS_NODE (node), -1); + g_return_val_if_fail (property_id >= 0, -1); + + g_static_rw_lock_reader_lock (node->priv->lock); + + if (property_id >= node->priv->properties->len) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return -1; + } + + ret = g_ptr_array_index (node->priv->properties, property_id); + if (ret == NULL) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return -1; + } + + retval = g_value_get_float (ret); + + g_static_rw_lock_reader_unlock (node->priv->lock); + + return retval; +} + +EphyNode * +ephy_node_get_property_node (EphyNode *node, + guint property_id) +{ + GValue *ret; + EphyNode *retval; + + g_return_val_if_fail (EPHY_IS_NODE (node), NULL); + g_return_val_if_fail (property_id >= 0, NULL); + + g_static_rw_lock_reader_lock (node->priv->lock); + + if (property_id >= node->priv->properties->len) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return NULL; + } + + ret = g_ptr_array_index (node->priv->properties, property_id); + if (ret == NULL) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return NULL; + } + + retval = g_value_get_pointer (ret); + + g_static_rw_lock_reader_unlock (node->priv->lock); + + return retval; +} + +char * +ephy_node_get_property_time (EphyNode *node, + guint property_id) +{ + GValue *ret; + long mtime; + char *retval; + + g_return_val_if_fail (EPHY_IS_NODE (node), NULL); + g_return_val_if_fail (property_id >= 0, NULL); + + g_static_rw_lock_reader_lock (node->priv->lock); + + if (property_id >= node->priv->properties->len) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return g_strdup (_("Never")); + } + + ret = g_ptr_array_index (node->priv->properties, property_id); + if (ret == NULL) { + g_static_rw_lock_reader_unlock (node->priv->lock); + return g_strdup (_("Never")); + } + + mtime = g_value_get_long (ret); + + if (retval >= 0) { + GDate *now, *file_date; + guint32 file_date_age; + const char *format = NULL; + + now = g_date_new (); + g_date_set_time (now, time (NULL)); + + file_date = g_date_new (); + g_date_set_time (file_date, mtime); + + file_date_age = (g_date_get_julian (now) - g_date_get_julian (file_date)); + + g_date_free (file_date); + g_date_free (now); + + if (file_date_age == 0) { + format = _("Today at %-H:%M"); + } else if (file_date_age == 1) { + format = _("Yesterday at %-H:%M"); + } else { + format = _("%A, %B %-d %Y at %-H:%M"); + } + + retval = ephy_string_time_to_string (file_date, format); + } else { + retval = g_strdup (_("Never")); + } + + g_static_rw_lock_reader_unlock (node->priv->lock); + + return retval; +} + +static void +save_parent (gulong id, + EphyNodeParent *node_info, + xmlNodePtr xml_node) +{ + xmlNodePtr parent_xml_node; + char *xml; + + parent_xml_node = xmlNewChild (xml_node, NULL, "parent", NULL); + + g_static_rw_lock_reader_lock (node_info->node->priv->lock); + + xml = g_strdup_printf ("%ld", node_info->node->priv->id); + xmlSetProp (parent_xml_node, "id", xml); + g_free (xml); + + g_static_rw_lock_reader_unlock (node_info->node->priv->lock); +} + +void +ephy_node_save_to_xml (EphyNode *node, + xmlNodePtr parent_xml_node) +{ + xmlNodePtr xml_node; + char *xml; + guint i; + + g_return_if_fail (EPHY_IS_NODE (node)); + g_return_if_fail (parent_xml_node != NULL); + + g_static_rw_lock_reader_lock (node->priv->lock); + + xml_node = xmlNewChild (parent_xml_node, NULL, "node", NULL); + + xml = g_strdup_printf ("%ld", node->priv->id); + xmlSetProp (xml_node, "id", xml); + g_free (xml); + + xmlSetProp (xml_node, "type", G_OBJECT_TYPE_NAME (node)); + + for (i = 0; i < node->priv->properties->len; i++) { + GValue *value; + xmlNodePtr value_xml_node; + + value = g_ptr_array_index (node->priv->properties, i); + if (value == NULL) + continue; + + value_xml_node = xmlNewChild (xml_node, NULL, "property", NULL); + + xml = g_strdup_printf ("%d", i); + xmlSetProp (value_xml_node, "id", xml); + g_free (xml); + + xmlSetProp (value_xml_node, "value_type", g_type_name (G_VALUE_TYPE (value))); + + switch (G_VALUE_TYPE (value)) + { + case G_TYPE_STRING: + xml = xmlEncodeEntitiesReentrant (NULL, + g_value_get_string (value)); + xmlNodeSetContent (value_xml_node, xml); + g_free (xml); + break; + case G_TYPE_BOOLEAN: + xml = g_strdup_printf ("%d", g_value_get_boolean (value)); + xmlNodeSetContent (value_xml_node, xml); + g_free (xml); + break; + case G_TYPE_INT: + xml = g_strdup_printf ("%d", g_value_get_int (value)); + xmlNodeSetContent (value_xml_node, xml); + g_free (xml); + break; + case G_TYPE_LONG: + xml = g_strdup_printf ("%ld", g_value_get_long (value)); + xmlNodeSetContent (value_xml_node, xml); + g_free (xml); + break; + case G_TYPE_FLOAT: + xml = g_strdup_printf ("%f", g_value_get_float (value)); + xmlNodeSetContent (value_xml_node, xml); + g_free (xml); + break; + case G_TYPE_DOUBLE: + xml = g_strdup_printf ("%f", g_value_get_double (value)); + xmlNodeSetContent (value_xml_node, xml); + g_free (xml); + break; + case G_TYPE_POINTER: + { + EphyNode *prop_node; + + prop_node = g_value_get_pointer (value); + + g_assert (prop_node != NULL); + + g_static_rw_lock_reader_lock (prop_node->priv->lock); + + xml = g_strdup_printf ("%ld", prop_node->priv->id); + xmlNodeSetContent (value_xml_node, xml); + g_free (xml); + + g_static_rw_lock_reader_unlock (prop_node->priv->lock); + break; + } + default: + g_assert_not_reached (); + break; + } + } + + g_hash_table_foreach (node->priv->parents, + (GHFunc) save_parent, + xml_node); + + g_static_rw_lock_reader_unlock (node->priv->lock); +} + +/* this function assumes it's safe to not lock anything while loading, + * this is at least true for the case where we're loading the library xml file + * from the main loop */ +EphyNode * +ephy_node_new_from_xml (xmlNodePtr xml_node) +{ + EphyNode *node; + xmlNodePtr xml_child; + char *xml; + long id; + GType type; + + g_return_val_if_fail (xml_node != NULL, NULL); + + xml = xmlGetProp (xml_node, "id"); + if (xml == NULL) + return NULL; + id = atol (xml); + g_free (xml); + + id_factory_set_to (id); + + xml = xmlGetProp (xml_node, "type"); + type = g_type_from_name (xml); + g_free (xml); + + node = EPHY_NODE (g_object_new (type, + "id", id, + NULL)); + + g_return_val_if_fail (node->priv != NULL, NULL); + + for (xml_child = xml_node->children; xml_child != NULL; xml_child = xml_child->next) { + if (strcmp (xml_child->name, "parent") == 0) { + EphyNode *parent; + long parent_id; + + xml = xmlGetProp (xml_child, "id"); + g_assert (xml != NULL); + parent_id = atol (xml); + g_free (xml); + + parent = node_from_id_real (parent_id); + + if (parent != NULL) + { + real_add_child (parent, node); + + g_signal_emit (G_OBJECT (parent), ephy_node_signals[CHILD_ADDED], + 0, node); + } + } else if (strcmp (xml_child->name, "property") == 0) { + GType value_type; + GValue *value; + int property_id; + + xml = xmlGetProp (xml_child, "id"); + property_id = atoi (xml); + g_free (xml); + + xml = xmlGetProp (xml_child, "value_type"); + value_type = g_type_from_name (xml); + g_free (xml); + + xml = xmlNodeGetContent (xml_child); + value = g_new0 (GValue, 1); + g_value_init (value, value_type); + + switch (value_type) + { + case G_TYPE_STRING: + g_value_set_string (value, xml); + break; + case G_TYPE_INT: + g_value_set_int (value, atoi (xml)); + break; + case G_TYPE_BOOLEAN: + g_value_set_boolean (value, atoi (xml)); + break; + case G_TYPE_LONG: + g_value_set_long (value, atol (xml)); + break; + case G_TYPE_FLOAT: + g_value_set_float (value, atof (xml)); + break; + case G_TYPE_DOUBLE: + g_value_set_double (value, atof (xml)); + break; + case G_TYPE_POINTER: + { + EphyNode *property_node; + + property_node = node_from_id_real (atol (xml)); + + g_value_set_pointer (value, property_node); + break; + } + default: + g_assert_not_reached (); + break; + } + + real_set_property (node, property_id, value); + + g_free (xml); + } + } + + g_signal_emit (G_OBJECT (node), ephy_node_signals[RESTORED], 0); + + return node; +} + +static inline void +real_add_child (EphyNode *node, + EphyNode *child) +{ + EphyNodeParent *node_info; + + if (g_hash_table_lookup (child->priv->parents, + GINT_TO_POINTER (node->priv->id)) != NULL) { + return; + } + + g_ptr_array_add (node->priv->children, child); + + node_info = g_new0 (EphyNodeParent, 1); + node_info->node = node; + node_info->index = node->priv->children->len - 1; + + g_hash_table_insert (child->priv->parents, + GINT_TO_POINTER (node->priv->id), + node_info); +} + +void +ephy_node_add_child (EphyNode *node, + EphyNode *child) +{ + g_return_if_fail (EPHY_IS_NODE (node)); + g_return_if_fail (EPHY_IS_NODE (child)); + + lock_gdk (); + + g_static_rw_lock_writer_lock (node->priv->lock); + g_static_rw_lock_writer_lock (child->priv->lock); + + real_add_child (node, child); + + write_lock_to_read_lock (node); + write_lock_to_read_lock (child); + + g_signal_emit (G_OBJECT (node), ephy_node_signals[CHILD_ADDED], 0, child); + + g_static_rw_lock_reader_unlock (node->priv->lock); + g_static_rw_lock_reader_unlock (child->priv->lock); + + unlock_gdk (); +} + +static inline void +real_remove_child (EphyNode *node, + EphyNode *child, + gboolean remove_from_parent, + gboolean remove_from_child) +{ + EphyNodeParent *node_info; + + write_lock_to_read_lock (node); + write_lock_to_read_lock (child); + + g_signal_emit (G_OBJECT (node), ephy_node_signals[CHILD_REMOVED], 0, child); + + read_lock_to_write_lock (node); + read_lock_to_write_lock (child); + + node_info = g_hash_table_lookup (child->priv->parents, + GINT_TO_POINTER (node->priv->id)); + + if (remove_from_parent) { + guint i; + + g_ptr_array_remove_index (node->priv->children, + node_info->index); + + /* correct indices on kids */ + for (i = node_info->index; i < node->priv->children->len; i++) { + EphyNode *borked_node; + EphyNodeParent *borked_node_info; + + borked_node = g_ptr_array_index (node->priv->children, i); + + g_static_rw_lock_writer_lock (borked_node->priv->lock); + + borked_node_info = g_hash_table_lookup (borked_node->priv->parents, + GINT_TO_POINTER (node->priv->id)); + borked_node_info->index--; + + g_static_rw_lock_writer_unlock (borked_node->priv->lock); + } + } + + if (remove_from_child) { + g_hash_table_remove (child->priv->parents, + GINT_TO_POINTER (node->priv->id)); + } +} + +void +ephy_node_remove_child (EphyNode *node, + EphyNode *child) +{ + g_return_if_fail (EPHY_IS_NODE (node)); + g_return_if_fail (EPHY_IS_NODE (child)); + + lock_gdk (); + + g_static_rw_lock_writer_lock (node->priv->lock); + g_static_rw_lock_writer_lock (child->priv->lock); + + real_remove_child (node, child, TRUE, TRUE); + + g_static_rw_lock_writer_unlock (node->priv->lock); + g_static_rw_lock_writer_unlock (child->priv->lock); + + unlock_gdk (); +} + +gboolean +ephy_node_has_child (EphyNode *node, + EphyNode *child) +{ + gboolean ret; + + g_return_val_if_fail (EPHY_IS_NODE (node), FALSE); + g_return_val_if_fail (EPHY_IS_NODE (child), FALSE); + + g_static_rw_lock_reader_lock (node->priv->lock); + g_static_rw_lock_reader_lock (child->priv->lock); + + ret = (g_hash_table_lookup (child->priv->parents, + GINT_TO_POINTER (node->priv->id)) != NULL); + + g_static_rw_lock_reader_unlock (node->priv->lock); + g_static_rw_lock_reader_unlock (child->priv->lock); + + return ret; +} + +GPtrArray * +ephy_node_get_children (EphyNode *node) +{ + g_return_val_if_fail (EPHY_IS_NODE (node), NULL); + + g_static_rw_lock_reader_lock (node->priv->lock); + + return node->priv->children; +} + +int +ephy_node_get_n_children (EphyNode *node) +{ + int ret; + + g_return_val_if_fail (EPHY_IS_NODE (node), -1); + + g_static_rw_lock_reader_lock (node->priv->lock); + + ret = node->priv->children->len; + + g_static_rw_lock_reader_unlock (node->priv->lock); + + return ret; +} + +EphyNode * +ephy_node_get_nth_child (EphyNode *node, + guint n) +{ + EphyNode *ret; + + g_return_val_if_fail (EPHY_IS_NODE (node), NULL); + g_return_val_if_fail (n >= 0, NULL); + + g_static_rw_lock_reader_lock (node->priv->lock); + + if (n < node->priv->children->len) { + ret = g_ptr_array_index (node->priv->children, n); + } else { + ret = NULL; + } + + g_static_rw_lock_reader_unlock (node->priv->lock); + + return ret; +} + +static inline int +get_child_index_real (EphyNode *node, + EphyNode *child) +{ + EphyNodeParent *node_info; + + node_info = g_hash_table_lookup (child->priv->parents, + GINT_TO_POINTER (node->priv->id)); + + if (node_info == NULL) + return -1; + + return node_info->index; +} + +int +ephy_node_get_child_index (EphyNode *node, + EphyNode *child) +{ + EphyNodeParent *node_info; + int ret; + + g_return_val_if_fail (EPHY_IS_NODE (node), -1); + g_return_val_if_fail (EPHY_IS_NODE (child), -1); + + g_static_rw_lock_reader_lock (node->priv->lock); + g_static_rw_lock_reader_lock (child->priv->lock); + + node_info = g_hash_table_lookup (child->priv->parents, + GINT_TO_POINTER (node->priv->id)); + + if (node_info == NULL) + return -1; + + ret = node_info->index; + + g_static_rw_lock_reader_unlock (node->priv->lock); + g_static_rw_lock_reader_unlock (child->priv->lock); + + return ret; +} + +EphyNode * +ephy_node_get_next_child (EphyNode *node, + EphyNode *child) +{ + EphyNode *ret; + guint idx; + + g_return_val_if_fail (EPHY_IS_NODE (node), NULL); + g_return_val_if_fail (EPHY_IS_NODE (child), NULL); + + g_static_rw_lock_reader_lock (node->priv->lock); + g_static_rw_lock_reader_lock (child->priv->lock); + + idx = get_child_index_real (node, child); + + if ((idx + 1) < node->priv->children->len) { + ret = g_ptr_array_index (node->priv->children, idx + 1); + } else { + ret = NULL; + } + + g_static_rw_lock_reader_unlock (node->priv->lock); + g_static_rw_lock_reader_unlock (child->priv->lock); + + return ret; +} + +EphyNode * +ephy_node_get_previous_child (EphyNode *node, + EphyNode *child) +{ + EphyNode *ret; + int idx; + + g_return_val_if_fail (EPHY_IS_NODE (node), NULL); + g_return_val_if_fail (EPHY_IS_NODE (child), NULL); + + g_static_rw_lock_reader_lock (node->priv->lock); + g_static_rw_lock_reader_lock (child->priv->lock); + + idx = get_child_index_real (node, child); + + if ((idx - 1) >= 0) { + ret = g_ptr_array_index (node->priv->children, idx - 1); + } else { + ret = NULL; + } + + g_static_rw_lock_reader_unlock (node->priv->lock); + g_static_rw_lock_reader_unlock (child->priv->lock); + + return ret; +} + +void +ephy_node_system_init (void) +{ + /* id to node */ + id_to_node = g_ptr_array_new (); + + id_to_node_lock = g_new0 (GStaticRWLock, 1); + g_static_rw_lock_init (id_to_node_lock); + + /* id factory */ + id_factory = 0; + id_factory_lock = g_mutex_new (); +} + +void +ephy_node_system_shutdown (void) +{ + g_ptr_array_free (id_to_node, FALSE); + + g_static_rw_lock_free (id_to_node_lock); + + g_mutex_free (id_factory_lock); +} + +long +ephy_node_new_id (void) +{ + long ret; + + g_mutex_lock (id_factory_lock); + + id_factory++; + + ret = id_factory; + + g_mutex_unlock (id_factory_lock); + + return ret; +} + +static void +id_factory_set_to (gulong new_factory_pos) +{ + id_factory = new_factory_pos + 1; +} + +/* evillish hacks to temporarily readlock->writelock and v.v. */ +static inline void +write_lock_to_read_lock (EphyNode *node) +{ + g_static_mutex_lock (&node->priv->lock->mutex); + node->priv->lock->read_counter++; + g_static_mutex_unlock (&node->priv->lock->mutex); + + g_static_rw_lock_writer_unlock (node->priv->lock); +} + +static inline void +read_lock_to_write_lock (EphyNode *node) +{ + g_static_mutex_lock (&node->priv->lock->mutex); + node->priv->lock->read_counter--; + g_static_mutex_unlock (&node->priv->lock->mutex); + + g_static_rw_lock_writer_lock (node->priv->lock); +} + +static inline void +lock_gdk (void) +{ + if (ephy_thread_helpers_in_main_thread () == FALSE) + GDK_THREADS_ENTER (); +} + +static inline void +unlock_gdk (void) +{ + if (ephy_thread_helpers_in_main_thread () == FALSE) + GDK_THREADS_LEAVE (); +} diff --git a/lib/ephy-node.h b/lib/ephy-node.h new file mode 100644 index 000000000..2e5f92210 --- /dev/null +++ b/lib/ephy-node.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef EPHY_NODE_H +#define EPHY_NODE_H + +#include <glib-object.h> + +#include <libxml/tree.h> + +G_BEGIN_DECLS + +#define EPHY_TYPE_NODE (ephy_node_get_type ()) +#define EPHY_NODE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_NODE, EphyNode)) +#define EPHY_NODE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_NODE, EphyNodeClass)) +#define EPHY_IS_NODE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_NODE)) +#define EPHY_IS_NODE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_NODE)) +#define EPHY_NODE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_NODE, EphyNodeClass)) + +typedef struct EphyNodePrivate EphyNodePrivate; + +typedef struct +{ + GObject parent; + + EphyNodePrivate *priv; +} EphyNode; + +typedef struct +{ + GObjectClass parent; + + /* signals */ + void (*destroyed) (EphyNode *node); + void (*restored) (EphyNode *node); + + void (*child_added) (EphyNode *node, EphyNode *child); + void (*child_changed) (EphyNode *node, EphyNode *child); + void (*child_reordered) (EphyNode *node, EphyNode *child, + int old_index, int new_index); + void (*child_removed) (EphyNode *node, EphyNode *child); +} EphyNodeClass; + +GType ephy_node_get_type (void); + +EphyNode *ephy_node_new (void); + +/* unique node ID */ +long ephy_node_get_id (EphyNode *node); + +EphyNode *ephy_node_get_from_id (gulong id); + +/* refcounting */ +void ephy_node_ref (EphyNode *node); +void ephy_node_unref (EphyNode *node); + +/* locking */ +void ephy_node_freeze (EphyNode *node); +void ephy_node_thaw (EphyNode *node); + +/* property interface */ +enum +{ + EPHY_NODE_PROP_NAME = 0, + EPHY_NODE_PROP_NAME_SORT_KEY = 1 +}; + +void ephy_node_set_property (EphyNode *node, + guint property_id, + const GValue *value); +gboolean ephy_node_get_property (EphyNode *node, + guint property_id, + GValue *value); + +const char *ephy_node_get_property_string (EphyNode *node, + guint property_id); +gboolean ephy_node_get_property_boolean (EphyNode *node, + guint property_id); +long ephy_node_get_property_long (EphyNode *node, + guint property_id); +int ephy_node_get_property_int (EphyNode *node, + guint property_id); +double ephy_node_get_property_double (EphyNode *node, + guint property_id); +float ephy_node_get_property_float (EphyNode *node, + guint property_id); +EphyNode *ephy_node_get_property_node (EphyNode *node, + guint property_id); +/* free return value */ +char *ephy_node_get_property_time (EphyNode *node, + guint property_id); + +/* xml storage */ +void ephy_node_save_to_xml (EphyNode *node, + xmlNodePtr parent_xml_node); +EphyNode *ephy_node_new_from_xml (xmlNodePtr xml_node); + +/* DAG structure */ +void ephy_node_add_child (EphyNode *node, + EphyNode *child); +void ephy_node_remove_child (EphyNode *node, + EphyNode *child); +gboolean ephy_node_has_child (EphyNode *node, + EphyNode *child); + +/* Note that ephy_node_get_children freezes the node; you'll have to thaw it when done. + * This is to prevent the data getting changed from another thread. */ +GPtrArray *ephy_node_get_children (EphyNode *node); +int ephy_node_get_n_children (EphyNode *node); +EphyNode *ephy_node_get_nth_child (EphyNode *node, + guint n); +int ephy_node_get_child_index (EphyNode *node, + EphyNode *child); +EphyNode *ephy_node_get_next_child (EphyNode *node, + EphyNode *child); +EphyNode *ephy_node_get_previous_child (EphyNode *node, + EphyNode *child); + +/* node id services */ +void ephy_node_system_init (void); +void ephy_node_system_shutdown (void); + +long ephy_node_new_id (void); + +G_END_DECLS + +#endif /* __EPHY_NODE_H */ diff --git a/lib/ephy-prefs-utils.c b/lib/ephy-prefs-utils.c new file mode 100644 index 000000000..0e0cf4a50 --- /dev/null +++ b/lib/ephy-prefs-utils.c @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2000 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-prefs-utils.h" +#include "ephy-gui.h" +#include "eel-gconf-extensions.h" + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <gtk/gtkmenu.h> +#include <gtk/gtkmenushell.h> +#include <gtk/gtkspinbutton.h> +#include <gtk/gtktogglebutton.h> +#include <gtk/gtkoptionmenu.h> +#include <gtk/gtklist.h> +#include <libgnomeui/gnome-color-picker.h> + +void +ephy_pu_set_config_from_editable (GtkWidget *editable, const char *config_name) +{ + GConfValue *gcvalue = eel_gconf_get_value (config_name); + GConfValueType value_type; + char *value; + gint ivalue; + gfloat fvalue; + + if (gcvalue == NULL) { + /* ugly hack around what appears to be a gconf bug + * it returns a NULL GConfValue for a valid string pref + * which is "" by default */ + value_type = GCONF_VALUE_STRING; + } else { + value_type = gcvalue->type; + gconf_value_free (gcvalue); + } + + /* get all the text into a new string */ + value = gtk_editable_get_chars (GTK_EDITABLE(editable), 0, -1); + + switch (value_type) { + case GCONF_VALUE_STRING: + eel_gconf_set_string (config_name, + value); + break; + /* FIXME : handle possible errors in the input for int and float */ + case GCONF_VALUE_INT: + ivalue = atoi (value); + eel_gconf_set_integer (config_name, ivalue); + break; + case GCONF_VALUE_FLOAT: + fvalue = strtod (value, (char**)NULL); + eel_gconf_set_float (config_name, fvalue); + break; + default: + break; + } + + /* free the allocated strings */ + g_free (value); +} + +void +ephy_pu_set_config_from_optionmenu (GtkWidget *optionmenu, const char *config_name) +{ + int index = ephy_pu_get_int_from_optionmenu (optionmenu); + + eel_gconf_set_integer (config_name, index); +} + +void +ephy_pu_set_config_from_radiobuttongroup (GtkWidget *radiobutton, const char *config_name) +{ + gint index; + + /* get value from radio button group */ + index = ephy_gui_gtk_radio_button_get (GTK_RADIO_BUTTON (radiobutton)); + + eel_gconf_set_integer (config_name, index); +} + +void +ephy_pu_set_config_from_spin_button (GtkWidget *spinbutton, const char *config_name) +{ + gdouble value; + gboolean use_int; + + /* read the value as an integer */ + value = gtk_spin_button_get_value (GTK_SPIN_BUTTON(spinbutton)); + + use_int = (gtk_spin_button_get_digits (GTK_SPIN_BUTTON(spinbutton)) == 0); + + if (use_int) + { + eel_gconf_set_integer (config_name, value); + } + else + { + eel_gconf_set_float (config_name, value); + } +} + +void +ephy_pu_set_config_from_togglebutton (GtkWidget *togglebutton, const char *config_name) +{ + gboolean value; + + /* read the value */ + value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(togglebutton)); + + eel_gconf_set_boolean (config_name, value); +} + +void +ephy_pu_set_config_from_color (GtkWidget *colorpicker, const char *config_name) +{ + guint8 r, g, b, a; + gchar color_string[9]; + + /* get color values from color picker */ + gnome_color_picker_get_i8 (GNOME_COLOR_PICKER (colorpicker), + &r, &g, &b, &a); + + /* write into string (bounded size) */ + snprintf (color_string, 9, "#%02X%02X%02X", r, g, b); + + /* set the configuration value */ + eel_gconf_set_string (config_name, color_string); +} + +void +ephy_pu_set_editable_from_config (GtkWidget *editable, const char *config_name) +{ + GConfValue *gcvalue = eel_gconf_get_value (config_name); + GConfValueType value_type; + gchar *value; + + if (gcvalue == NULL) + { + /* ugly hack around what appears to be a gconf bug + * it returns a NULL GConfValue for a valid string pref + * which is "" by default */ + value_type = GCONF_VALUE_STRING; + } + else + { + value_type = gcvalue->type; + gconf_value_free (gcvalue); + } + + switch (value_type) + { + case GCONF_VALUE_STRING: + value = eel_gconf_get_string (config_name); + break; + case GCONF_VALUE_INT: + value = g_strdup_printf ("%d",eel_gconf_get_integer (config_name)); + break; + case GCONF_VALUE_FLOAT: + value = g_strdup_printf ("%.2f",eel_gconf_get_float (config_name)); + break; + default: + value = NULL; + } + + /* set this string value in the widget */ + if (value) + { + gtk_entry_set_text(GTK_ENTRY(editable), value); + } + + /* free the allocated string */ + g_free (value); +} + +void +ephy_pu_set_optionmenu_from_config (GtkWidget *optionmenu, const char *config_name) +{ + gint index; + + /* get the current value from the configuration space */ + index = eel_gconf_get_integer (config_name); + + /* set this option value in the widget */ + gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), index); +} + +void +ephy_pu_set_radiobuttongroup_from_config (GtkWidget *radiobutton, const char *config_name) +{ + gint index; + + /* get the current value from the configuration space */ + index = eel_gconf_get_integer (config_name); + + /* set it (finds the group for us) */ + ephy_gui_gtk_radio_button_set (GTK_RADIO_BUTTON (radiobutton), index); +} + +void +ephy_pu_set_spin_button_from_config (GtkWidget *spinbutton, const char *config_name) +{ + gdouble value; + gint use_int; + + use_int = (gtk_spin_button_get_digits (GTK_SPIN_BUTTON(spinbutton)) == 0); + + if (use_int) + { + /* get the current value from the configuration space */ + value = eel_gconf_get_integer (config_name); + } + else + { + /* get the current value from the configuration space */ + value = eel_gconf_get_float (config_name); + } + + /* set this option value in the widget */ + gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbutton), value); +} + +void +ephy_pu_set_togglebutton_from_config (GtkWidget *togglebutton, const char *config_name) +{ + gboolean value; + + /* get the current value from the configuration space */ + value = eel_gconf_get_boolean (config_name); + + /* set this option value in the widget */ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), value); +} + +void +ephy_pu_set_color_from_config (GtkWidget *colorpicker, const char *config_name) +{ + gchar *color_string; + guint r, g, b; + + /* get the string from config */ + color_string = eel_gconf_get_string (config_name); + + if (color_string) + { + /* parse it and setup the color picker */ + sscanf (color_string, "#%2X%2X%2X", &r, &g, &b); + gnome_color_picker_set_i8 (GNOME_COLOR_PICKER (colorpicker), + r, g, b, 0); + /* free the string */ + g_free (color_string); + } +} + +int +ephy_pu_get_int_from_optionmenu (GtkWidget *optionmenu) +{ + GtkWidget *menu; + GList *list; + gpointer item; + gint index; + + /* extract the selection */ + menu = GTK_OPTION_MENU(optionmenu)->menu; + list = GTK_MENU_SHELL(menu)->children; + item = gtk_menu_get_active (GTK_MENU(menu)); + index = g_list_index (list, item); + + return index; +} diff --git a/lib/ephy-prefs-utils.h b/lib/ephy-prefs-utils.h new file mode 100644 index 000000000..13ac1e4d7 --- /dev/null +++ b/lib/ephy-prefs-utils.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2000 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <gtk/gtkwidget.h> + +G_BEGIN_DECLS + +void ephy_pu_set_config_from_editable (GtkWidget *editable, + const char *config_name); + +void ephy_pu_set_config_from_optionmenu (GtkWidget *optionmenu, + const char *config_name); + +void ephy_pu_set_config_from_radiobuttongroup (GtkWidget *radiobutton, + const char *config_name); + +void ephy_pu_set_config_from_spin_button (GtkWidget *spinbutton, + const char *config_name); + +void ephy_pu_set_config_from_togglebutton (GtkWidget *togglebutton, + const char *config_name); + +void ephy_pu_set_config_from_color (GtkWidget *colorpicker, + const char *config_name); + +void ephy_pu_set_editable_from_config (GtkWidget *editable, + const char *config_name); + +void ephy_pu_set_optionmenu_from_config (GtkWidget *optionmenu, + const char *config_name); + +void ephy_pu_set_radiobuttongroup_from_config (GtkWidget *radiobutton, + const char *config_name); + +void ephy_pu_set_togglebutton_from_config (GtkWidget *togglebutton, + const char *config_name); + +void ephy_pu_set_spin_button_from_config (GtkWidget *spinbutton, + const char *config_name); + +void ephy_pu_set_color_from_config (GtkWidget *colorpicker, + const char *config_name); + +int ephy_pu_get_int_from_optionmenu (GtkWidget *optionmenu); + +G_END_DECLS diff --git a/lib/ephy-prefs.h b/lib/ephy-prefs.h new file mode 100644 index 000000000..3c0562a1f --- /dev/null +++ b/lib/ephy-prefs.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2000-2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_PREFS_H +#define EPHY_PREFS_H + +G_BEGIN_DECLS + +/* General */ +#define CONF_GENERAL_HOMEPAGE "/apps/epiphany/general/start_page" +#define CONF_GENERAL_NEWPAGE_TYPE "/apps/epiphany/general/newpage_type" + +/* Interface */ +#define CONF_TABS_TABBED "/apps/epiphany/interface/open_in_tab" +#define CONF_TABS_TABBED_POPUPS "/apps/epiphany/interface/popups_in_tab" +#define CONF_TABS_TABBED_AUTOJUMP "/apps/epiphany/interface/jumpto_tab" +#define CONF_WINDOWS_SIDEBAR_PAGE "/apps/epiphany/interface/sidebar_page" +#define CONF_WINDOWS_SIDEBAR_SIZE "/apps/epiphany/interface/sidebar_size" +#define CONF_WINDOWS_FS_SHOW_SIDEBAR "/apps/epiphany/interface/show_sidebar_in_fullscreen" +#define CONF_WINDOWS_FS_SHOW_TOOLBARS "/apps/epiphany/interface/show_toolbars_in_fullscreen" +#define CONF_WINDOWS_FS_SHOW_STATUSBAR "/apps/epiphany/interface/show_statusbar_in_fullscreen" +#define CONF_WINDOWS_SHOW_SIDEBAR "/apps/epiphany/interface/show_sidebar" +#define CONF_WINDOWS_SHOW_TOOLBARS "/apps/epiphany/interface/show_toolbars" +#define CONF_WINDOWS_SHOW_STATUSBAR "/apps/epiphany/interface/show_statusbar" +#define CONF_TOOLBAR_SETUP "/apps/epiphany/interface/toolbar_setup" +#define CONF_TOOLBAR_SPINNER_THEME "/apps/epiphany/interface/spinner_theme" + +/* Downloader */ +#define CONF_DOWNLOADING_SHOW_DETAILS "/apps/epiphany/downloader/show_details" + +/* Directories */ +#define CONF_STATE_SAVE_DIR "/apps/epiphany/directories/save" +#define CONF_STATE_SAVE_IMAGE_DIR "/apps/epiphany/directories/saveimage" +#define CONF_STATE_OPEN_DIR "/apps/epiphany/directories/open" +#define CONF_STATE_DOWNLOADING_DIR "/apps/epiphany/directories/downloading" + +/* System prefs */ +#define CONF_DESKTOP_FTP_HANDLER "/desktop/gnome/url-handlers/ftp/command" +#define CONF_DESKTOP_TOOLBAR_STYLE "/desktop/gnome/interface/toolbar_style" + +G_END_DECLS + +#endif diff --git a/lib/ephy-state.c b/lib/ephy-state.c new file mode 100644 index 000000000..245cc38b1 --- /dev/null +++ b/lib/ephy-state.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2001 Matthew Mueller + * (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <gtk/gtkpaned.h> +#include <gtk/gtkwindow.h> +#include <gtk/gtktreeview.h> +#include <libgnomeui/gnome-app.h> +#include <bonobo/bonobo-dock.h> +#include <bonobo/bonobo-dock-layout.h> + +#include "ephy-state.h" +#include "eel-gconf-extensions.h" + +#define CONF_GUL_STATE_PATH "/apps/epiphany/state" + +static void +window_save_size (GtkWidget *window, const gchar *name) +{ + int width, height; + gchar *buf; + + gtk_window_get_size (GTK_WINDOW(window), + &width, &height); + + buf = g_strdup_printf (CONF_GUL_STATE_PATH "/%s/width",name); + eel_gconf_set_integer (buf, width); + g_free (buf); + + buf = g_strdup_printf (CONF_GUL_STATE_PATH "/%s/height",name); + eel_gconf_set_integer (buf, height); + g_free (buf); +} + +/** + * ephy_state_save_window: save the window dimensions + */ +void +ephy_state_save_window (GtkWidget *window, + const gchar *name) +{ + GdkWindowState state; + gboolean maximized; + gchar *buf; + + state = gdk_window_get_state (GTK_WIDGET (window)->window); + maximized = state && GDK_WINDOW_STATE_MAXIMIZED; + + buf = g_strdup_printf (CONF_GUL_STATE_PATH "/%s/maximized",name); + eel_gconf_set_boolean (buf, maximized); + g_free (buf); + + if (!maximized) + { + window_save_size (window, name); + } +} + +/** + * ephy_window_load_state: load the window state + */ +void +ephy_state_load_window (GtkWidget *window, + const gchar *name, + int default_width, + int default_height, + gboolean position) +{ + gchar *buf; + gint width, height; + gboolean maximized; + + buf = g_strdup_printf (CONF_GUL_STATE_PATH "/%s/maximized",name); + maximized = eel_gconf_get_boolean (buf); + g_free (buf); + + buf = g_strdup_printf (CONF_GUL_STATE_PATH "/%s/width",name); + width = eel_gconf_get_integer (buf); + g_free (buf); + + buf = g_strdup_printf (CONF_GUL_STATE_PATH "/%s/height",name); + height = eel_gconf_get_integer (buf); + g_free (buf); + + /* try default size */ + if (width == 0 && height == 0 && + default_width != -1 && default_height != -1) + { + width = default_width; + height = default_height; + } + + if (width != 0 && height != 0) + { + gtk_window_set_default_size + (GTK_WINDOW (window), width, height); + } + + if (maximized) + { + gtk_window_maximize (GTK_WINDOW(window)); + } +} + +/** + * ephy_state_load_pane_pos: load the paned position + */ +void +ephy_state_load_pane_pos (GtkWidget *pane, + const gchar *name) +{ + if (pane != NULL) + { + gint pane_pos; + gchar *buf = g_strdup_printf (CONF_GUL_STATE_PATH "/%s", name); + pane_pos = eel_gconf_get_integer (buf); + g_free (buf); + + if (pane_pos != -1) + gtk_paned_set_position (GTK_PANED (pane), pane_pos); + } +} + +/** + * gul_state_save_pane_pos: save the paned position + */ +void +ephy_state_save_pane_pos (GtkWidget *pane, + const gchar *name) +{ + if (pane != NULL) + { + gchar *buf = g_strdup_printf (CONF_GUL_STATE_PATH "/%s", name); + eel_gconf_set_integer (buf, GTK_PANED (pane)->child1_size); + g_free (buf); + } +} diff --git a/lib/ephy-state.h b/lib/ephy-state.h new file mode 100644 index 000000000..508e986be --- /dev/null +++ b/lib/ephy-state.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2001 Matthew Mueller + * (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef EPHY_STATE_H +#define EPHY_STATE_H + +G_BEGIN_DECLS + +void ephy_state_save_window (GtkWidget *window, + const gchar *name); + +void ephy_state_load_window (GtkWidget *window, + const gchar *name, + int default_width, + int default_heigth, + gboolean position); + +void ephy_state_save_pane_pos (GtkWidget *pane, + const gchar *name); + +void ephy_state_load_pane_pos (GtkWidget *pane, + const gchar *name); + +G_END_DECLS + +#endif /* EPHY_STATE_H */ diff --git a/lib/ephy-stock-icons.c b/lib/ephy-stock-icons.c new file mode 100644 index 000000000..0d9ff902c --- /dev/null +++ b/lib/ephy-stock-icons.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include <gtk/gtk.h> +#include <glib.h> +#include <stdio.h> +#include <string.h> + +#include "ephy-file-helpers.h" +#include "ephy-stock-icons.h" + +void +ephy_stock_icons_init (void) +{ + GtkIconFactory *factory; + int i; + + static const char *items[] = + { + EPHY_STOCK_SECURE, + EPHY_STOCK_UNSECURE + }; + + factory = gtk_icon_factory_new (); + gtk_icon_factory_add_default (factory); + + for (i = 0; i < (int) G_N_ELEMENTS (items); i++) + { + GtkIconSet *icon_set; + GdkPixbuf *pixbuf; + char *fn; + + fn = g_strconcat (items[i], ".png", NULL); + pixbuf = gdk_pixbuf_new_from_file (ephy_file (fn), NULL); + g_free (fn); + + icon_set = gtk_icon_set_new_from_pixbuf (pixbuf); + gtk_icon_factory_add (factory, items[i], icon_set); + gtk_icon_set_unref (icon_set); + + g_object_unref (G_OBJECT (pixbuf)); + } + + g_object_unref (G_OBJECT (factory)); +} diff --git a/lib/ephy-stock-icons.h b/lib/ephy-stock-icons.h new file mode 100644 index 000000000..c68be46c9 --- /dev/null +++ b/lib/ephy-stock-icons.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef EPHY_STOCK_ICONS_H +#define EPHY_STOCK_ICONS_H + +G_BEGIN_DECLS + +#define EPHY_STOCK_SECURE "epiphany-secure" +#define EPHY_STOCK_UNSECURE "epiphany-unsecure" + +void ephy_stock_icons_init (void); + +G_END_DECLS + +#endif /* __RB_STOCK_ICONS_H */ diff --git a/lib/ephy-string.c b/lib/ephy-string.c new file mode 100644 index 000000000..7ca28cf1f --- /dev/null +++ b/lib/ephy-string.c @@ -0,0 +1,446 @@ +/* + * Copyright (C) 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-string.h" + +#include <string.h> +#include <glib.h> +#include <libgnome/libgnome.h> +#include <libgnome/gnome-i18n.h> +#include <libgnomevfs/gnome-vfs-mime.h> +#include <libxml/parser.h> + +/** + * ephy_string_shorten: returns a newly allocated shortened version of str. + * the new string will be no longer than target_length characters, and will + * be of the form "http://blahblah...blahblah.html". + */ +gchar * +ephy_string_shorten (const gchar *str, gint target_length) +{ + gchar *new_str; + gint actual_length, first_length, second_length; + + if (!str) return NULL; + + actual_length = strlen (str); + + /* if the string is already short enough, or if it's too short for + * us to shorten it, return a new copy */ + if (actual_length <= target_length || + actual_length <= 3) + return g_strdup (str); + + /* allocate new string */ + new_str = g_new (gchar, target_length + 1); + + /* calc lengths to take from beginning and ending of str */ + second_length = (target_length - 3) / 2; + first_length = target_length - 3 - second_length; + + /* create string */ + strncpy (new_str, str, first_length); + strncpy (new_str + first_length, "...", 3); + strncpy (new_str + first_length + 3, + str + actual_length - second_length, second_length); + new_str[target_length] = '\0'; + + return new_str; +} + +char * +ephy_string_double_underscores (const char *string) +{ + int underscores; + const char *p; + char *q; + char *escaped; + + if (string == NULL) { + return NULL; + } + + underscores = 0; + for (p = string; *p != '\0'; p++) { + underscores += (*p == '_'); + } + + if (underscores == 0) { + return g_strdup (string); + } + + escaped = g_new (char, strlen (string) + underscores + 1); + for (p = string, q = escaped; *p != '\0'; p++, q++) { + /* Add an extra underscore. */ + if (*p == '_') { + *q++ = '_'; + } + *q = *p; + } + *q = '\0'; + + return escaped; +} + +/** + * ephy_string_store_time_in_string: + * NOTE: str must be at least 256 chars long + */ +void +ephy_string_store_time_in_string (GDate *t, gchar *str, const char *format) +{ + int length; + + if (t > 0) + { + /* format into string */ + /* this is used whenever a brief date is needed, like + * in the history (for last visited, first time visited) */ + length = g_date_strftime (str, 255, + format ? format : _("%Y-%m-%d"), t); + str[length] = '\0'; + } + else + { + str[0] = '\0'; + } +} + +/** + * ephy_string_time_to_string: + */ +gchar * +ephy_string_time_to_string (GDate *t, + const char *format) +{ + gchar str[256]; + + /* write into stack string */ + ephy_string_store_time_in_string (t, str, format); + + /* copy in heap and return */ + return g_strdup (str); +} + +gboolean +ephy_str_to_int (const char *string, int *integer) +{ + long result; + char *parse_end; + + /* Check for the case of an empty string. */ + if (string == NULL || *string == '\0') { + return FALSE; + } + + /* Call the standard library routine to do the conversion. */ + errno = 0; + result = strtol (string, &parse_end, 0); + + /* Check that the result is in range. */ + if ((result == G_MINLONG || result == G_MAXLONG) && errno == ERANGE) { + return FALSE; + } + if (result < G_MININT || result > G_MAXINT) { + return FALSE; + } + + /* Check that all the trailing characters are spaces. */ + while (*parse_end != '\0') { + if (!g_ascii_isspace (*parse_end++)) { + return FALSE; + } + } + + /* Return the result. */ + *integer = result; + return TRUE; +} + +/** + * ephy_str_strip_chr: + * Remove all occurrences of a character from a string. + * + * @source: The string to be stripped. + * @remove_this: The char to remove from @source + * + * Return value: A copy of @source, after removing all occurrences + * of @remove_this. + */ +char * +ephy_str_strip_chr (const char *source, char remove_this) +{ + char *result, *out; + const char *in; + + if (source == NULL) { + return NULL; + } + + result = g_new (char, strlen (source) + 1); + in = source; + out = result; + do { + if (*in != remove_this) { + *out++ = *in; + } + } while (*in++ != '\0'); + + return result; +} + +int +ephy_strcasecmp (const char *string_a, const char *string_b) +{ + return g_ascii_strcasecmp (string_a == NULL ? "" : string_a, + string_b == NULL ? "" : string_b); +} + +int +ephy_strcasecmp_compare_func (gconstpointer string_a, gconstpointer string_b) +{ + return ephy_strcasecmp ((const char *) string_a, + (const char *) string_b); +} + +/** + * like strpbrk but ignores chars preceded by slashes, unless the + * slash is also preceded by a slash unless that later slash is + * preceded by another slash... ;-) + */ +static char * +ephy_strpbrk_unescaped (const char *s, const char *accept) +{ + gchar *ret = strpbrk (s, accept); + + if (!ret || ret == s || *(ret - 1) != '\\') + { + return ret; + } + else + { + gchar *c = ret - 1; + g_assert (*c == '\\'); + + while (c >= s && *c == '\\') c--; + + if ((ret - c) % 2 == 0) + { + return ephy_strpbrk_unescaped (ret + 1, accept); + } + else + { + return ret; + } + } +} + +/** + * like strstr but supports quoting, ignoring matches inside quoted text + */ +static char * +ephy_strstr_with_quotes (const char *haystack, const char *needle, + const char *quotes) +{ + gchar *quot = ephy_strpbrk_unescaped (haystack, quotes); + gchar *ret = strstr (haystack, needle); + + if (!quot || !ret || ret < quot) + { + return ret; + } + + quot = ephy_strpbrk_unescaped (quot + 1, quotes); + + if (quot) + { + return ephy_strstr_with_quotes (quot + 1, needle, quotes); + } + else + { + return NULL; + } +} + +/** + * like strpbrk but supports quoting, ignoring matches inside quoted text + */ +static char * +ephy_strpbrk_with_quotes (const char *haystack, const char *needles, + const char *quotes) +{ + gchar *quot = ephy_strpbrk_unescaped (haystack, quotes); + gchar *ret = strpbrk (haystack, needles); + + if (!quot || !ret || ret < quot) + { + return ret; + } + + quot = ephy_strpbrk_unescaped (quot + 1, quotes); + + if (quot) + { + return ephy_strpbrk_with_quotes (quot + 1, needles, quotes); + } + else + { + return NULL; + } +} + +/** + * Like g_strsplit, but does not split tokens betwen quotes. Ignores + * quotes preceded by '\'. + */ +gchar ** +ephy_strsplit_with_quotes (const gchar *string, + const gchar *delimiter, + gint max_tokens, + const gchar *quotes) +{ + GSList *string_list = NULL, *slist; + gchar **str_array, *s; + guint n = 0; + const gchar *remainder; + + g_return_val_if_fail (string != NULL, NULL); + g_return_val_if_fail (delimiter != NULL, NULL); + g_return_val_if_fail (delimiter[0] != '\0', NULL); + + if (quotes == NULL) + { + return g_strsplit (string, delimiter, max_tokens); + } + + if (max_tokens < 1) + { + max_tokens = G_MAXINT; + } + + remainder = string; + s = ephy_strstr_with_quotes (remainder, delimiter, quotes); + if (s) + { + gsize delimiter_len = strlen (delimiter); + + while (--max_tokens && s) + { + gsize len; + gchar *new_string; + + len = s - remainder; + new_string = g_new (gchar, len + 1); + strncpy (new_string, remainder, len); + new_string[len] = 0; + string_list = g_slist_prepend (string_list, new_string); + n++; + remainder = s + delimiter_len; + s = ephy_strstr_with_quotes (remainder, delimiter, quotes); + } + } + if (*string) + { + n++; + string_list = g_slist_prepend (string_list, g_strdup (remainder)); + } + + str_array = g_new (gchar*, n + 1); + + str_array[n--] = NULL; + for (slist = string_list; slist; slist = slist->next) + { + str_array[n--] = slist->data; + } + + g_slist_free (string_list); + + return str_array; +} + +/** + * like ephy_strsplit_with_quotes, but matches any char in 'delimiters' as delimiter + * and does not return empty tokens + */ +gchar ** +ephy_strsplit_multiple_delimiters_with_quotes (const gchar *string, + const gchar *delimiters, + gint max_tokens, + const gchar *quotes) +{ + GSList *string_list = NULL, *slist; + gchar **str_array, *s; + guint n = 0; + const gchar *remainder; + + g_return_val_if_fail (string != NULL, NULL); + g_return_val_if_fail (delimiters != NULL, NULL); + g_return_val_if_fail (delimiters[0] != '\0', NULL); + + if (quotes == NULL) + { + quotes = ""; + } + + if (max_tokens < 1) + { + max_tokens = G_MAXINT; + } + + remainder = string; + s = ephy_strpbrk_with_quotes (remainder, delimiters, quotes); + if (s) + { + const gsize delimiter_len = 1; /* only chars */ + + while (--max_tokens && s) + { + gsize len; + gchar *new_string; + + len = s - remainder; + if (len > 0) /* ignore empty strings */ + { + new_string = g_new (gchar, len + 1); + strncpy (new_string, remainder, len); + new_string[len] = 0; + string_list = g_slist_prepend (string_list, new_string); + n++; + } + remainder = s + delimiter_len; + s = ephy_strpbrk_with_quotes (remainder, delimiters, quotes); + } + } + if (*string) + { + n++; + string_list = g_slist_prepend (string_list, g_strdup (remainder)); + } + + str_array = g_new (gchar*, n + 1); + + str_array[n--] = NULL; + for (slist = string_list; slist; slist = slist->next) + { + str_array[n--] = slist->data; + } + + g_slist_free (string_list); + + return str_array; +} diff --git a/lib/ephy-string.h b/lib/ephy-string.h new file mode 100644 index 000000000..cc60bd638 --- /dev/null +++ b/lib/ephy-string.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_STRING_H +#define EPHY_STRING_H + +#include <glib.h> + +G_BEGIN_DECLS + +char * ephy_string_double_underscores (const char *string); + +void ephy_string_store_time_in_string (GDate *t, + gchar *str, + const char *format); + +gchar *ephy_string_time_to_string (GDate *t, + const char *format); + +gboolean ephy_str_to_int (const char *string, + int *integer); + +char *ephy_str_strip_chr (const char *source, + char remove_this); + +int ephy_strcasecmp (const char *string_a, + const char *string_b); + +int ephy_strcasecmp_compare_func (gconstpointer string_a, + gconstpointer string_b); + +char **ephy_strsplit_with_quotes (const gchar *string, + const gchar *delimiter, + gint max_tokens, + const gchar *quotes); + +gchar *ephy_string_shorten (const gchar *str, + gint target_length); + +char **ephy_strsplit_multiple_delimiters_with_quotes (const gchar *string, + const gchar *delimiters, + gint max_tokens, + const gchar *quotes); + + +G_END_DECLS + +#endif diff --git a/lib/ephy-thread-helpers.c b/lib/ephy-thread-helpers.c new file mode 100644 index 000000000..720358968 --- /dev/null +++ b/lib/ephy-thread-helpers.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include "ephy-thread-helpers.h" + +static GThread *main_thread = NULL; + +void +ephy_thread_helpers_init (void) +{ + main_thread = g_thread_self (); +} + +gboolean +ephy_thread_helpers_in_main_thread (void) +{ + return (main_thread == g_thread_self ()); +} diff --git a/lib/ephy-thread-helpers.h b/lib/ephy-thread-helpers.h new file mode 100644 index 000000000..2b23156a3 --- /dev/null +++ b/lib/ephy-thread-helpers.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include <glib/gthread.h> + +#ifndef EPHY_THREAD_HELPERS_H +#define EPHY_THREAD_HELPERS_H + +G_BEGIN_DECLS + +void ephy_thread_helpers_init (void); + +gboolean ephy_thread_helpers_in_main_thread (void); + +G_END_DECLS + +#endif /* EPHY_THREAD_HELPERS_H */ diff --git a/lib/ephy-types.h b/lib/ephy-types.h new file mode 100644 index 000000000..70ce681e0 --- /dev/null +++ b/lib/ephy-types.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_TYPES_H +#define EPHY_TYPES_H + +#include <glib.h> + +G_BEGIN_DECLS + +typedef enum +{ + G_OK, + G_FAILED, + G_NOT_IMPLEMENTED +} gresult; + +G_END_DECLS + +#endif diff --git a/lib/toolbar/.cvsignore b/lib/toolbar/.cvsignore new file mode 100644 index 000000000..20e4cb0c8 --- /dev/null +++ b/lib/toolbar/.cvsignore @@ -0,0 +1,6 @@ +Makefile +Makefile.in +*.lo +.deps +.libs +*.la diff --git a/lib/toolbar/Makefile.am b/lib/toolbar/Makefile.am new file mode 100644 index 000000000..a6affaa04 --- /dev/null +++ b/lib/toolbar/Makefile.am @@ -0,0 +1,41 @@ +INCLUDES = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/lib/widgets \ + $(WARN_CFLAGS) \ + $(EPIPHANY_DEPENDENCY_CFLAGS) \ + -DSHARE_DIR=\"$(pkgdatadir)\" \ + -DG_DISABLE_DEPRECATED \ + -DGDK_DISABLE_DEPRECATED \ + -DGTK_DISABLE_DEPRECATED \ + -DGDK_PIXBUF_DISABLE_DEPRECATED \ + -DGNOME_DISABLE_DEPRECATED + +noinst_LTLIBRARIES = libephytoolbar.la + +libephytoolbar_la_SOURCES = \ + ephy-toolbar.h \ + ephy-toolbar.c \ + ephy-toolbar-item.h \ + ephy-toolbar-item.c \ + ephy-toolbar-item-factory.h \ + ephy-toolbar-item-factory.c \ + ephy-tbi-zoom.h \ + ephy-tbi-zoom.c \ + ephy-tbi-separator.h \ + ephy-tbi-separator.c \ + ephy-tbi-favicon.h \ + ephy-tbi-favicon.c \ + ephy-tbi-spinner.h \ + ephy-tbi-spinner.c \ + ephy-tbi-location.h \ + ephy-tbi-location.c \ + ephy-tbi-navigation-history.h \ + ephy-tbi-navigation-history.c \ + ephy-tbi-std-toolitem.h \ + ephy-tbi-std-toolitem.c \ + ephy-toolbar-bonobo-view.c \ + ephy-toolbar-bonobo-view.h \ + ephy-toolbar-tree-model.h \ + ephy-toolbar-tree-model.c \ + ephy-toolbar-editor.h \ + ephy-toolbar-editor.c diff --git a/lib/toolbar/ephy-tbi-favicon.c b/lib/toolbar/ephy-tbi-favicon.c new file mode 100644 index 000000000..d072e3ec6 --- /dev/null +++ b/lib/toolbar/ephy-tbi-favicon.c @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <libgnome/gnome-i18n.h> +#include <gtk/gtkeventbox.h> + +#include "ephy-gobject-misc.h" +#include "ephy-marshal.h" +#include "ephy-bonobo-extensions.h" +#include "ephy-tbi-favicon.h" + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +/** + * Private data + */ +struct _EphyTbiFaviconPrivate +{ + GtkWidget *widget; +}; + +/** + * Private functions, only availble from this file + */ +static void ephy_tbi_favicon_class_init (EphyTbiFaviconClass *klass); +static void ephy_tbi_favicon_init (EphyTbiFavicon *tb); +static void ephy_tbi_favicon_finalize_impl (GObject *o); +static GtkWidget * ephy_tbi_favicon_get_widget_impl (EphyTbItem *i); +static GdkPixbuf * ephy_tbi_favicon_get_icon_impl (EphyTbItem *i); +static gchar * ephy_tbi_favicon_get_name_human_impl (EphyTbItem *i); +static gchar * ephy_tbi_favicon_to_string_impl (EphyTbItem *i); +static gboolean ephy_tbi_favicon_is_unique_impl (EphyTbItem *i); +static EphyTbItem * ephy_tbi_favicon_clone_impl (EphyTbItem *i); +static void ephy_tbi_favicon_parse_properties_impl (EphyTbItem *i, const gchar *props); +static void ephy_tbi_favicon_add_to_bonobo_tb_impl (EphyTbItem *i, + BonoboUIComponent *ui, + const char *container_path, + guint index); + +static gpointer ephy_tb_item_class; + +/** + * TbiFavicon object + */ + +MAKE_GET_TYPE (ephy_tbi_favicon, "EphyTbiFavicon", EphyTbiFavicon, ephy_tbi_favicon_class_init, + ephy_tbi_favicon_init, EPHY_TYPE_TB_ITEM); + +static void +ephy_tbi_favicon_class_init (EphyTbiFaviconClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = ephy_tbi_favicon_finalize_impl; + + EPHY_TB_ITEM_CLASS (klass)->get_widget = ephy_tbi_favicon_get_widget_impl; + EPHY_TB_ITEM_CLASS (klass)->get_icon = ephy_tbi_favicon_get_icon_impl; + EPHY_TB_ITEM_CLASS (klass)->get_name_human = ephy_tbi_favicon_get_name_human_impl; + EPHY_TB_ITEM_CLASS (klass)->to_string = ephy_tbi_favicon_to_string_impl; + EPHY_TB_ITEM_CLASS (klass)->is_unique = ephy_tbi_favicon_is_unique_impl; + EPHY_TB_ITEM_CLASS (klass)->clone = ephy_tbi_favicon_clone_impl; + EPHY_TB_ITEM_CLASS (klass)->parse_properties = ephy_tbi_favicon_parse_properties_impl; + EPHY_TB_ITEM_CLASS (klass)->add_to_bonobo_tb = ephy_tbi_favicon_add_to_bonobo_tb_impl; + + ephy_tb_item_class = g_type_class_peek_parent (klass); +} + +static void +ephy_tbi_favicon_init (EphyTbiFavicon *tb) +{ + EphyTbiFaviconPrivate *p = g_new0 (EphyTbiFaviconPrivate, 1); + tb->priv = p; +} + +EphyTbiFavicon * +ephy_tbi_favicon_new (void) +{ + EphyTbiFavicon *ret = g_object_new (EPHY_TYPE_TBI_FAVICON, NULL); + return ret; +} + +static void +ephy_tbi_favicon_finalize_impl (GObject *o) +{ + EphyTbiFavicon *it = EPHY_TBI_FAVICON (o); + EphyTbiFaviconPrivate *p = it->priv; + + if (p->widget) + { + g_object_unref (p->widget); + } + + g_free (p); + + DEBUG_MSG (("EphyTbiFavicon finalized\n")); + + G_OBJECT_CLASS (ephy_tb_item_class)->finalize (o); +} + +static GtkWidget * +ephy_tbi_favicon_get_widget_impl (EphyTbItem *i) +{ + EphyTbiFavicon *iz = EPHY_TBI_FAVICON (i); + EphyTbiFaviconPrivate *p = iz->priv; + + if (!p->widget) + { + /* here, we create only the event_box. */ + p->widget = gtk_event_box_new (); + g_object_ref (p->widget); + gtk_object_sink (GTK_OBJECT (p->widget)); + } + + return p->widget; +} + +static GdkPixbuf * +ephy_tbi_favicon_get_icon_impl (EphyTbItem *i) +{ + /* need an icon for this */ + return NULL; +} + +static gchar * +ephy_tbi_favicon_get_name_human_impl (EphyTbItem *i) +{ + return g_strdup (_("Drag Handle")); +} + +static gchar * +ephy_tbi_favicon_to_string_impl (EphyTbItem *i) +{ + /* if it had any properties, the string should include them */ + return g_strdup_printf ("%s=favicon", i->id); +} + +static gboolean +ephy_tbi_favicon_is_unique_impl (EphyTbItem *i) +{ + return TRUE; +} + +static EphyTbItem * +ephy_tbi_favicon_clone_impl (EphyTbItem *i) +{ + EphyTbItem *ret = EPHY_TB_ITEM (ephy_tbi_favicon_new ()); + + ephy_tb_item_set_id (ret, i->id); + + /* should copy properties too, if any */ + + return ret; +} + +static void +ephy_tbi_favicon_add_to_bonobo_tb_impl (EphyTbItem *i, BonoboUIComponent *ui, + const char *container_path, guint index) +{ + GtkWidget *w = ephy_tb_item_get_widget (i); + gtk_widget_show (w); + ephy_bonobo_add_numbered_control (ui, w, index, container_path); +} + +static void +ephy_tbi_favicon_parse_properties_impl (EphyTbItem *it, const gchar *props) +{ + /* we have no properties */ +} + diff --git a/lib/toolbar/ephy-tbi-favicon.h b/lib/toolbar/ephy-tbi-favicon.h new file mode 100644 index 000000000..7cea6f634 --- /dev/null +++ b/lib/toolbar/ephy-tbi-favicon.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_TBI_FAVICON_H +#define EPHY_TBI_FAVICON_H + +#include "ephy-toolbar-item.h" + +G_BEGIN_DECLS + +/* object forward declarations */ + +typedef struct _EphyTbiFavicon EphyTbiFavicon; +typedef struct _EphyTbiFaviconClass EphyTbiFaviconClass; +typedef struct _EphyTbiFaviconPrivate EphyTbiFaviconPrivate; + +/** + * TbiFavicon object + */ + +#define EPHY_TYPE_TBI_FAVICON (ephy_tbi_favicon_get_type()) +#define EPHY_TBI_FAVICON(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_TBI_FAVICON,\ + EphyTbiFavicon)) +#define EPHY_TBI_FAVICON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TBI_FAVICON,\ + EphyTbiFaviconClass)) +#define EPHY_IS_TBI_FAVICON(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_TBI_FAVICON)) +#define EPHY_IS_TBI_FAVICON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TBI_FAVICON)) +#define EPHY_TBI_FAVICON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TBI_FAVICON,\ + EphyTbiFaviconClass)) + +struct _EphyTbiFaviconClass +{ + EphyTbItemClass parent_class; +}; + +/* Remember: fields are public read-only */ +struct _EphyTbiFavicon +{ + EphyTbItem parent_object; + + EphyTbiFaviconPrivate *priv; +}; + +/* this class is abstract */ + +GType ephy_tbi_favicon_get_type (void); +EphyTbiFavicon * ephy_tbi_favicon_new (void); + +G_END_DECLS + +#endif diff --git a/lib/toolbar/ephy-tbi-location.c b/lib/toolbar/ephy-tbi-location.c new file mode 100644 index 000000000..0ccbaf83a --- /dev/null +++ b/lib/toolbar/ephy-tbi-location.c @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <libgnome/gnome-i18n.h> +#include "ephy-gobject-misc.h" +#include "ephy-marshal.h" +#include "ephy-bonobo-extensions.h" +#include "ephy-tbi-location.h" +#include "ephy-location-entry.h" + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +/** + * Private data + */ +struct _EphyTbiLocationPrivate +{ + GtkWidget *widget; +}; + +/** + * Private functions, only availble from this file + */ +static void ephy_tbi_location_class_init (EphyTbiLocationClass *klass); +static void ephy_tbi_location_init (EphyTbiLocation *tb); +static void ephy_tbi_location_finalize_impl (GObject *o); +static GtkWidget * ephy_tbi_location_get_widget_impl (EphyTbItem *i); +static GdkPixbuf * ephy_tbi_location_get_icon_impl (EphyTbItem *i); +static gchar * ephy_tbi_location_get_name_human_impl (EphyTbItem *i); +static gchar * ephy_tbi_location_to_string_impl (EphyTbItem *i); +static gboolean ephy_tbi_location_is_unique_impl (EphyTbItem *i); +static EphyTbItem * ephy_tbi_location_clone_impl (EphyTbItem *i); +static void ephy_tbi_location_parse_properties_impl (EphyTbItem *i, const gchar *props); +static void ephy_tbi_location_add_to_bonobo_tb_impl (EphyTbItem *i, + BonoboUIComponent *ui, + const char *container_path, + guint index); + +static gpointer ephy_tb_item_class; + +/** + * TbiLocation object + */ + +MAKE_GET_TYPE (ephy_tbi_location, "EphyTbiLocation", EphyTbiLocation, ephy_tbi_location_class_init, + ephy_tbi_location_init, EPHY_TYPE_TB_ITEM); + +static void +ephy_tbi_location_class_init (EphyTbiLocationClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = ephy_tbi_location_finalize_impl; + + EPHY_TB_ITEM_CLASS (klass)->get_widget = ephy_tbi_location_get_widget_impl; + EPHY_TB_ITEM_CLASS (klass)->get_icon = ephy_tbi_location_get_icon_impl; + EPHY_TB_ITEM_CLASS (klass)->get_name_human = ephy_tbi_location_get_name_human_impl; + EPHY_TB_ITEM_CLASS (klass)->to_string = ephy_tbi_location_to_string_impl; + EPHY_TB_ITEM_CLASS (klass)->is_unique = ephy_tbi_location_is_unique_impl; + EPHY_TB_ITEM_CLASS (klass)->clone = ephy_tbi_location_clone_impl; + EPHY_TB_ITEM_CLASS (klass)->parse_properties = ephy_tbi_location_parse_properties_impl; + EPHY_TB_ITEM_CLASS (klass)->add_to_bonobo_tb = ephy_tbi_location_add_to_bonobo_tb_impl; + + ephy_tb_item_class = g_type_class_peek_parent (klass); +} + +static void +ephy_tbi_location_init (EphyTbiLocation *tb) +{ + EphyTbiLocationPrivate *p = g_new0 (EphyTbiLocationPrivate, 1); + tb->priv = p; +} + +EphyTbiLocation * +ephy_tbi_location_new (void) +{ + EphyTbiLocation *ret = g_object_new (EPHY_TYPE_TBI_LOCATION, NULL); + return ret; +} + +static void +ephy_tbi_location_finalize_impl (GObject *o) +{ + EphyTbiLocation *it = EPHY_TBI_LOCATION (o); + EphyTbiLocationPrivate *p = it->priv; + + if (p->widget) + { + g_object_unref (p->widget); + } + + g_free (p); + + DEBUG_MSG (("EphyTbiLocation finalized\n")); + + G_OBJECT_CLASS (ephy_tb_item_class)->finalize (o); +} + +static GtkWidget * +ephy_tbi_location_get_widget_impl (EphyTbItem *i) +{ + EphyTbiLocation *iz = EPHY_TBI_LOCATION (i); + EphyTbiLocationPrivate *p = iz->priv; + + if (!p->widget) + { + p->widget = GTK_WIDGET (ephy_location_entry_new ()); + g_object_ref (p->widget); + gtk_object_sink (GTK_OBJECT (p->widget)); + } + + return p->widget; +} + +static GdkPixbuf * +ephy_tbi_location_get_icon_impl (EphyTbItem *i) +{ + return NULL; +} + +static gchar * +ephy_tbi_location_get_name_human_impl (EphyTbItem *i) +{ + return g_strdup (_("Location entry")); +} + +static gchar * +ephy_tbi_location_to_string_impl (EphyTbItem *i) +{ + /* if it had any properties, the string should include them */ + return g_strdup_printf ("%s=location", i->id); +} + +static gboolean +ephy_tbi_location_is_unique_impl (EphyTbItem *i) +{ + return TRUE; +} + +static EphyTbItem * +ephy_tbi_location_clone_impl (EphyTbItem *i) +{ + EphyTbItem *ret = EPHY_TB_ITEM (ephy_tbi_location_new ()); + + ephy_tb_item_set_id (ret, i->id); + + /* should copy properties too, if any */ + /* the location value is not copied, not sure if it should... */ + + return ret; +} + +static void +ephy_tbi_location_add_to_bonobo_tb_impl (EphyTbItem *i, BonoboUIComponent *uic, + const char *container_path, guint index) +{ + GtkWidget *w = ephy_tb_item_get_widget (i); + BonoboControl *control; + char *xml_string, *control_path; + + gtk_widget_show (w); + + g_return_if_fail (BONOBO_IS_UI_COMPONENT (uic)); + g_return_if_fail (container_path != NULL); + + xml_string = g_strdup_printf ("<control name=\"location\" behavior=\"expandable\"/>"); + + bonobo_ui_component_set (uic, container_path, xml_string, NULL); + + g_free (xml_string); + + control_path = g_strconcat (container_path, "/location", NULL); + + control = bonobo_control_new (w); + bonobo_ui_component_object_set (uic, control_path, BONOBO_OBJREF (control), NULL); + bonobo_object_unref (control); + + g_free (control_path); +} + +static void +ephy_tbi_location_parse_properties_impl (EphyTbItem *it, const gchar *props) +{ + /* we have no properties */ +} + diff --git a/lib/toolbar/ephy-tbi-location.h b/lib/toolbar/ephy-tbi-location.h new file mode 100644 index 000000000..9188463f6 --- /dev/null +++ b/lib/toolbar/ephy-tbi-location.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_TBI_LOCATION_H +#define EPHY_TBI_LOCATION_H + +#include "ephy-toolbar-item.h" + +G_BEGIN_DECLS + +/* object forward declarations */ + +typedef struct _EphyTbiLocation EphyTbiLocation; +typedef struct _EphyTbiLocationClass EphyTbiLocationClass; +typedef struct _EphyTbiLocationPrivate EphyTbiLocationPrivate; + +/** + * TbiLocation object + */ + +#define EPHY_TYPE_TBI_LOCATION (ephy_tbi_location_get_type()) +#define EPHY_TBI_LOCATION(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_TBI_LOCATION,\ + EphyTbiLocation)) +#define EPHY_TBI_LOCATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TBI_LOCATION,\ + EphyTbiLocationClass)) +#define EPHY_IS_TBI_LOCATION(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_TBI_LOCATION)) +#define EPHY_IS_TBI_LOCATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TBI_LOCATION)) +#define EPHY_TBI_LOCATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TBI_LOCATION,\ + EphyTbiLocationClass)) + +struct _EphyTbiLocationClass +{ + EphyTbItemClass parent_class; +}; + +/* Remember: fields are public read-only */ +struct _EphyTbiLocation +{ + EphyTbItem parent_object; + + EphyTbiLocationPrivate *priv; +}; + +/* this class is abstract */ + +GType ephy_tbi_location_get_type (void); +EphyTbiLocation * ephy_tbi_location_new (void); + +G_END_DECLS + +#endif diff --git a/lib/toolbar/ephy-tbi-navigation-history.c b/lib/toolbar/ephy-tbi-navigation-history.c new file mode 100644 index 000000000..c6edc9865 --- /dev/null +++ b/lib/toolbar/ephy-tbi-navigation-history.c @@ -0,0 +1,342 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <libgnome/gnome-i18n.h> +#include <bonobo/bonobo-ui-toolbar-button-item.h> +#include <bonobo/bonobo-property-bag.h> +#include <gtk/gtktogglebutton.h> +#include <gtk/gtkstock.h> +#include <string.h> + +#include "ephy-tbi-navigation-history.h" +#include "ephy-gobject-misc.h" +#include "ephy-marshal.h" +#include "ephy-bonobo-extensions.h" + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +/** + * Private data + */ +struct _EphyTbiNavigationHistoryPrivate +{ + GtkWidget *widget; + + EphyTbiNavigationHistoryDirection direction; +}; + +enum +{ + TOOLBAR_ITEM_STYLE_PROP, + TOOLBAR_ITEM_ORIENTATION_PROP, + TOOLBAR_ITEM_PRIORITY_PROP +}; + +/** + * Private functions, only availble from this file + */ +static void ephy_tbi_navigation_history_class_init (EphyTbiNavigationHistoryClass *klass); +static void ephy_tbi_navigation_history_init (EphyTbiNavigationHistory *tb); +static void ephy_tbi_navigation_history_finalize_impl (GObject *o); +static GtkWidget * ephy_tbi_navigation_history_get_widget_impl (EphyTbItem *i); +static GdkPixbuf * ephy_tbi_navigation_history_get_icon_impl (EphyTbItem *i); +static gchar * ephy_tbi_navigation_history_get_name_human_impl (EphyTbItem *i); +static gchar * ephy_tbi_navigation_history_to_string_impl (EphyTbItem *i); +static gboolean ephy_tbi_navigation_history_is_unique_impl (EphyTbItem *i); +static EphyTbItem * ephy_tbi_navigation_history_clone_impl (EphyTbItem *i); +static void ephy_tbi_navigation_history_parse_properties_impl (EphyTbItem *i, const gchar *props); +static void ephy_tbi_navigation_history_add_to_bonobo_tb_impl (EphyTbItem *i, + BonoboUIComponent *ui, + const char *container_path, + guint index); + +static gpointer ephy_tb_item_class; + +/** + * TbiNavigationHistory object + */ + +MAKE_GET_TYPE (ephy_tbi_navigation_history, "EphyTbiNavigationHistory", EphyTbiNavigationHistory, + ephy_tbi_navigation_history_class_init, + ephy_tbi_navigation_history_init, EPHY_TYPE_TB_ITEM); + +static void +ephy_tbi_navigation_history_class_init (EphyTbiNavigationHistoryClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = ephy_tbi_navigation_history_finalize_impl; + + EPHY_TB_ITEM_CLASS (klass)->get_widget = ephy_tbi_navigation_history_get_widget_impl; + EPHY_TB_ITEM_CLASS (klass)->get_icon = ephy_tbi_navigation_history_get_icon_impl; + EPHY_TB_ITEM_CLASS (klass)->get_name_human = ephy_tbi_navigation_history_get_name_human_impl; + EPHY_TB_ITEM_CLASS (klass)->to_string = ephy_tbi_navigation_history_to_string_impl; + EPHY_TB_ITEM_CLASS (klass)->is_unique = ephy_tbi_navigation_history_is_unique_impl; + EPHY_TB_ITEM_CLASS (klass)->clone = ephy_tbi_navigation_history_clone_impl; + EPHY_TB_ITEM_CLASS (klass)->parse_properties = ephy_tbi_navigation_history_parse_properties_impl; + EPHY_TB_ITEM_CLASS (klass)->add_to_bonobo_tb = ephy_tbi_navigation_history_add_to_bonobo_tb_impl; + + ephy_tb_item_class = g_type_class_peek_parent (klass); +} + +static void +ephy_tbi_navigation_history_init (EphyTbiNavigationHistory *tb) +{ + EphyTbiNavigationHistoryPrivate *p = g_new0 (EphyTbiNavigationHistoryPrivate, 1); + tb->priv = p; + + p->direction = EPHY_TBI_NAVIGATION_HISTORY_BACK; +} + +EphyTbiNavigationHistory * +ephy_tbi_navigation_history_new (void) +{ + EphyTbiNavigationHistory *ret = g_object_new (EPHY_TYPE_TBI_NAVIGATION_HISTORY, NULL); + return ret; +} + +static void +ephy_tbi_navigation_history_finalize_impl (GObject *o) +{ + EphyTbiNavigationHistory *it = EPHY_TBI_NAVIGATION_HISTORY (o); + EphyTbiNavigationHistoryPrivate *p = it->priv; + + if (p->widget) + { + g_object_unref (p->widget); + } + + g_free (p); + + DEBUG_MSG (("EphyTbiNavigationHistory finalized\n")); + + G_OBJECT_CLASS (ephy_tb_item_class)->finalize (o); +} + +static GtkWidget * +ephy_tbi_navigation_history_get_widget_impl (EphyTbItem *i) +{ + EphyTbiNavigationHistory *iz = EPHY_TBI_NAVIGATION_HISTORY (i); + EphyTbiNavigationHistoryPrivate *p = iz->priv; + + DEBUG_MSG (("in ephy_tbi_navigation_history_get_widget_impl\n")); + if (!p->widget) + { + DEBUG_MSG (("in ephy_tbi_navigation_history_get_widget_impl, really\n")); + + p->widget = gtk_toggle_button_new (); + gtk_button_set_relief (GTK_BUTTON (p->widget), GTK_RELIEF_NONE); + + gtk_container_add (GTK_CONTAINER (p->widget), + gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT)); + + g_object_ref (p->widget); + gtk_object_sink (GTK_OBJECT (p->widget)); + } + + return p->widget; +} + +static GdkPixbuf * +ephy_tbi_navigation_history_get_icon_impl (EphyTbItem *i) +{ + return NULL; +} + +static gchar * +ephy_tbi_navigation_history_get_name_human_impl (EphyTbItem *i) +{ + EphyTbiNavigationHistoryPrivate *p = EPHY_TBI_NAVIGATION_HISTORY (i)->priv; + const gchar *ret; + + switch (p->direction) + { + case EPHY_TBI_NAVIGATION_HISTORY_BACK: + ret = _("Back History"); + break; + case EPHY_TBI_NAVIGATION_HISTORY_FORWARD: + ret = _("Forward History"); + break; + case EPHY_TBI_NAVIGATION_HISTORY_UP: + ret = _("Up Several Levels"); + break; + default: + g_assert_not_reached (); + ret = "unknown"; + } + + return g_strdup (ret); +} + +static gchar * +ephy_tbi_navigation_history_to_string_impl (EphyTbItem *i) +{ + EphyTbiNavigationHistoryPrivate *p = EPHY_TBI_NAVIGATION_HISTORY (i)->priv; + + /* if it had any properties, the string should include them */ + const char *sdir; + + switch (p->direction) + { + case EPHY_TBI_NAVIGATION_HISTORY_BACK: + sdir = "back"; + break; + case EPHY_TBI_NAVIGATION_HISTORY_FORWARD: + sdir = "forward"; + break; + case EPHY_TBI_NAVIGATION_HISTORY_UP: + sdir = "up"; + break; + default: + g_assert_not_reached (); + sdir = "unknown"; + } + + return g_strdup_printf ("%s=navigation_history(direction=%s)", i->id, sdir); +} + +static gboolean +ephy_tbi_navigation_history_is_unique_impl (EphyTbItem *i) +{ + return TRUE; +} + +static EphyTbItem * +ephy_tbi_navigation_history_clone_impl (EphyTbItem *i) +{ + EphyTbiNavigationHistoryPrivate *p = EPHY_TBI_NAVIGATION_HISTORY (i)->priv; + EphyTbItem *ret = EPHY_TB_ITEM (ephy_tbi_navigation_history_new ()); + + ephy_tb_item_set_id (ret, i->id); + + /* should copy properties too, if any */ + ephy_tbi_navigation_history_set_direction (EPHY_TBI_NAVIGATION_HISTORY (ret), p->direction); + + return ret; +} + +static void +ephy_tbi_navigation_history_property_set_cb (BonoboPropertyBag *bag, + const BonoboArg *arg, + guint arg_id, + CORBA_Environment *ev, + gpointer user_data) +{ + BonoboControl *control; + BonoboUIToolbarItem *item; + GtkOrientation orientation; + BonoboUIToolbarItemStyle style; + + control = BONOBO_CONTROL (user_data); + item = BONOBO_UI_TOOLBAR_ITEM (bonobo_control_get_widget (control)); + + switch (arg_id) { + case TOOLBAR_ITEM_ORIENTATION_PROP: + orientation = BONOBO_ARG_GET_INT (arg); + bonobo_ui_toolbar_item_set_orientation (item, orientation); + + if (GTK_WIDGET (item)->parent) { + gtk_widget_queue_resize (GTK_WIDGET (item)->parent); + } + break; + case TOOLBAR_ITEM_STYLE_PROP: + style = BONOBO_ARG_GET_INT (arg); + bonobo_ui_toolbar_item_set_style (item, style); + break; + } +} + +static void +ephy_tbi_navigation_history_add_to_bonobo_tb_impl (EphyTbItem *i, BonoboUIComponent *ui, + const char *container_path, guint index) +{ + BonoboPropertyBag *pb; + BonoboControl *wrapper; + BonoboUIToolbarItem *item; + GtkWidget *button; + + DEBUG_MSG (("in ephy_tbi_navigation_history_add_to_bonobo_tb_impl\n")); + + item = BONOBO_UI_TOOLBAR_ITEM (bonobo_ui_toolbar_item_new ()); + + button = ephy_tb_item_get_widget (i); + gtk_container_add (GTK_CONTAINER (item), button); + gtk_widget_show_all (GTK_WIDGET (item)); + + wrapper = ephy_bonobo_add_numbered_control (ui, GTK_WIDGET (item), index, container_path); + + pb = bonobo_property_bag_new + (NULL, ephy_tbi_navigation_history_property_set_cb, wrapper); + bonobo_property_bag_add (pb, "style", + TOOLBAR_ITEM_STYLE_PROP, + BONOBO_ARG_INT, NULL, NULL, + Bonobo_PROPERTY_WRITEABLE); + bonobo_property_bag_add (pb, "orientation", + TOOLBAR_ITEM_ORIENTATION_PROP, + BONOBO_ARG_INT, NULL, NULL, + Bonobo_PROPERTY_WRITEABLE); + bonobo_control_set_properties (wrapper, BONOBO_OBJREF (pb), NULL); + bonobo_object_unref (pb); +} + +static void +ephy_tbi_navigation_history_parse_properties_impl (EphyTbItem *it, const gchar *props) +{ + EphyTbiNavigationHistory *a = EPHY_TBI_NAVIGATION_HISTORY (it); + + /* yes, this is quite hacky, but works */ + + /* we have aproperty, the direction */ + const gchar *direc_prop; + + direc_prop = strstr (props, "direction="); + if (direc_prop) + { + direc_prop += strlen ("direction="); + if (!strncmp (direc_prop, "back", 4)) + { + ephy_tbi_navigation_history_set_direction (a, EPHY_TBI_NAVIGATION_HISTORY_BACK); + } + else if (!strncmp (direc_prop, "forward", 4)) + { + ephy_tbi_navigation_history_set_direction (a, EPHY_TBI_NAVIGATION_HISTORY_FORWARD); + } + else if (!strncmp (direc_prop, "up", 2)) + { + ephy_tbi_navigation_history_set_direction (a, EPHY_TBI_NAVIGATION_HISTORY_UP); + } + } +} + +void +ephy_tbi_navigation_history_set_direction (EphyTbiNavigationHistory *a, EphyTbiNavigationHistoryDirection d) +{ + EphyTbiNavigationHistoryPrivate *p = a->priv; + + g_return_if_fail (d == EPHY_TBI_NAVIGATION_HISTORY_UP + || d == EPHY_TBI_NAVIGATION_HISTORY_BACK + || d == EPHY_TBI_NAVIGATION_HISTORY_FORWARD); + + p->direction = d; + +} + diff --git a/lib/toolbar/ephy-tbi-navigation-history.h b/lib/toolbar/ephy-tbi-navigation-history.h new file mode 100644 index 000000000..29cb6c32a --- /dev/null +++ b/lib/toolbar/ephy-tbi-navigation-history.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_TBI_NAVIGATION_HISTORY_H +#define EPHY_TBI_NAVIGATION_HISTORY_H + +#include "ephy-toolbar-item.h" + +G_BEGIN_DECLS + +/* object forward declarations */ + +typedef struct _EphyTbiNavigationHistory EphyTbiNavigationHistory; +typedef struct _EphyTbiNavigationHistoryClass EphyTbiNavigationHistoryClass; +typedef struct _EphyTbiNavigationHistoryPrivate EphyTbiNavigationHistoryPrivate; + +/** + * TbiNavigationHistory object + */ + +#define EPHY_TYPE_TBI_NAVIGATION_HISTORY (ephy_tbi_navigation_history_get_type()) +#define EPHY_TBI_NAVIGATION_HISTORY(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \ + EPHY_TYPE_TBI_NAVIGATION_HISTORY,\ + EphyTbiNavigationHistory)) +#define EPHY_TBI_NAVIGATION_HISTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \ + EPHY_TYPE_TBI_NAVIGATION_HISTORY,\ + EphyTbiNavigationHistoryClass)) +#define EPHY_IS_TBI_NAVIGATION_HISTORY(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \ + EPHY_TYPE_TBI_NAVIGATION_HISTORY)) +#define EPHY_IS_TBI_NAVIGATION_HISTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \ + EPHY_TYPE_TBI_NAVIGATION_HISTORY)) +#define EPHY_TBI_NAVIGATION_HISTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ + EPHY_TYPE_TBI_NAVIGATION_HISTORY,\ + EphyTbiNavigationHistoryClass)) +typedef enum +{ + EPHY_TBI_NAVIGATION_HISTORY_UP, + EPHY_TBI_NAVIGATION_HISTORY_BACK, + EPHY_TBI_NAVIGATION_HISTORY_FORWARD +} EphyTbiNavigationHistoryDirection; + + +struct _EphyTbiNavigationHistoryClass +{ + EphyTbItemClass parent_class; +}; + +/* Remember: fields are public read-only */ +struct _EphyTbiNavigationHistory +{ + EphyTbItem parent_object; + + EphyTbiNavigationHistoryPrivate *priv; +}; + +/* this class is abstract */ + +GType ephy_tbi_navigation_history_get_type (void); +EphyTbiNavigationHistory *ephy_tbi_navigation_history_new (void); +void ephy_tbi_navigation_history_set_direction (EphyTbiNavigationHistory *a, + EphyTbiNavigationHistoryDirection d); + +G_END_DECLS + +#endif + diff --git a/lib/toolbar/ephy-tbi-separator.c b/lib/toolbar/ephy-tbi-separator.c new file mode 100644 index 000000000..43f69bd96 --- /dev/null +++ b/lib/toolbar/ephy-tbi-separator.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <libgnome/gnome-i18n.h> +#include <gtk/gtkstock.h> + +#include "ephy-tbi-separator.h" +#include "ephy-gobject-misc.h" +#include "ephy-marshal.h" +#include "ephy-bonobo-extensions.h" + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +/** + * Private data + */ +struct _EphyTbiSeparatorPrivate +{ + GtkWidget *widget; +}; + +/** + * Private functions, only availble from this file + */ +static void ephy_tbi_separator_class_init (EphyTbiSeparatorClass *klass); +static void ephy_tbi_separator_init (EphyTbiSeparator *tb); +static void ephy_tbi_separator_finalize_impl (GObject *o); +static GtkWidget * ephy_tbi_separator_get_widget_impl (EphyTbItem *i); +static GdkPixbuf * ephy_tbi_separator_get_icon_impl (EphyTbItem *i); +static gchar * ephy_tbi_separator_get_name_human_impl (EphyTbItem *i); +static gchar * ephy_tbi_separator_to_string_impl (EphyTbItem *i); +static gboolean ephy_tbi_separator_is_unique_impl (EphyTbItem *i); +static EphyTbItem * ephy_tbi_separator_clone_impl (EphyTbItem *i); +static void ephy_tbi_separator_parse_properties_impl(EphyTbItem *i, const gchar *props); +static void ephy_tbi_separator_add_to_bonobo_tb_impl(EphyTbItem *i, + BonoboUIComponent *ui, + const char *container_path, + guint index); + +static gpointer ephy_tb_item_class; + +/** + * TbiSeparator object + */ + +MAKE_GET_TYPE (ephy_tbi_separator, "EphyTbiSeparator", EphyTbiSeparator, ephy_tbi_separator_class_init, + ephy_tbi_separator_init, EPHY_TYPE_TB_ITEM); + +static void +ephy_tbi_separator_class_init (EphyTbiSeparatorClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = ephy_tbi_separator_finalize_impl; + + EPHY_TB_ITEM_CLASS (klass)->get_widget = ephy_tbi_separator_get_widget_impl; + EPHY_TB_ITEM_CLASS (klass)->get_icon = ephy_tbi_separator_get_icon_impl; + EPHY_TB_ITEM_CLASS (klass)->get_name_human = ephy_tbi_separator_get_name_human_impl; + EPHY_TB_ITEM_CLASS (klass)->to_string = ephy_tbi_separator_to_string_impl; + EPHY_TB_ITEM_CLASS (klass)->is_unique = ephy_tbi_separator_is_unique_impl; + EPHY_TB_ITEM_CLASS (klass)->clone = ephy_tbi_separator_clone_impl; + EPHY_TB_ITEM_CLASS (klass)->parse_properties = ephy_tbi_separator_parse_properties_impl; + EPHY_TB_ITEM_CLASS (klass)->add_to_bonobo_tb = ephy_tbi_separator_add_to_bonobo_tb_impl; + + ephy_tb_item_class = g_type_class_peek_parent (klass); +} + +static void +ephy_tbi_separator_init (EphyTbiSeparator *tb) +{ + EphyTbiSeparatorPrivate *p = g_new0 (EphyTbiSeparatorPrivate, 1); + tb->priv = p; +} + +EphyTbiSeparator * +ephy_tbi_separator_new (void) +{ + EphyTbiSeparator *ret = g_object_new (EPHY_TYPE_TBI_SEPARATOR, NULL); + return ret; +} + +static void +ephy_tbi_separator_finalize_impl (GObject *o) +{ + EphyTbiSeparator *it = EPHY_TBI_SEPARATOR (o); + EphyTbiSeparatorPrivate *p = it->priv; + + if (p->widget) + { + g_object_unref (p->widget); + } + + g_free (p); + + DEBUG_MSG (("EphyTbiSeparator finalized\n")); + + G_OBJECT_CLASS (ephy_tb_item_class)->finalize (o); +} + +static GtkWidget * +ephy_tbi_separator_get_widget_impl (EphyTbItem *i) +{ + return NULL; +} + +static GdkPixbuf * +ephy_tbi_separator_get_icon_impl (EphyTbItem *i) +{ + return NULL; +} + +static gchar * +ephy_tbi_separator_get_name_human_impl (EphyTbItem *i) +{ + return g_strdup (_("Separator")); +} + +static gchar * +ephy_tbi_separator_to_string_impl (EphyTbItem *i) +{ + /* if it had any properties, the string should include them */ + return g_strdup_printf ("%s=separator", i->id); +} + +static gboolean +ephy_tbi_separator_is_unique_impl (EphyTbItem *i) +{ + return FALSE; +} + +static EphyTbItem * +ephy_tbi_separator_clone_impl (EphyTbItem *i) +{ + EphyTbItem *ret = EPHY_TB_ITEM (ephy_tbi_separator_new ()); + + ephy_tb_item_set_id (ret, i->id); + + /* should copy properties too, if any */ + + return ret; +} + +static void +ephy_tbi_separator_add_to_bonobo_tb_impl (EphyTbItem *i, BonoboUIComponent *ui, + const char *container_path, guint index) +{ + static gint hack = 0; + gchar *xml; + + xml = g_strdup_printf ("<separator name=\"sep%d\"/>", ++hack); + bonobo_ui_component_set (ui, container_path, xml, NULL); + g_free (xml); +} + +static void +ephy_tbi_separator_parse_properties_impl (EphyTbItem *it, const gchar *props) +{ + /* we have no properties */ +} + diff --git a/lib/toolbar/ephy-tbi-separator.h b/lib/toolbar/ephy-tbi-separator.h new file mode 100644 index 000000000..754d85fec --- /dev/null +++ b/lib/toolbar/ephy-tbi-separator.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_TBI_SEPARATOR_H +#define EPHY_TBI_SEPARATOR_H + +#include "ephy-toolbar-item.h" + +G_BEGIN_DECLS + +/* object forward declarations */ + +typedef struct _EphyTbiSeparator EphyTbiSeparator; +typedef struct _EphyTbiSeparatorClass EphyTbiSeparatorClass; +typedef struct _EphyTbiSeparatorPrivate EphyTbiSeparatorPrivate; + +/** + * TbiSeparator object + */ + +#define EPHY_TYPE_TBI_SEPARATOR (ephy_tbi_separator_get_type()) +#define EPHY_TBI_SEPARATOR(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \ + EPHY_TYPE_TBI_SEPARATOR,\ + EphyTbiSeparator)) +#define EPHY_TBI_SEPARATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TBI_SEPARATOR,\ + EphyTbiSeparatorClass)) +#define EPHY_IS_TBI_SEPARATOR(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \ + EPHY_TYPE_TBI_SEPARATOR)) +#define EPHY_IS_TBI_SEPARATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TBI_SEPARATOR)) +#define EPHY_TBI_SEPARATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TBI_SEPARATOR,\ + EphyTbiSeparatorClass)) + +struct _EphyTbiSeparatorClass +{ + EphyTbItemClass parent_class; +}; + +/* Remember: fields are public read-only */ +struct _EphyTbiSeparator +{ + EphyTbItem parent_object; + + EphyTbiSeparatorPrivate *priv; +}; + +/* this class is abstract */ + +GType ephy_tbi_separator_get_type (void); +EphyTbiSeparator * ephy_tbi_separator_new (void); + +G_END_DECLS + +#endif diff --git a/lib/toolbar/ephy-tbi-spinner.c b/lib/toolbar/ephy-tbi-spinner.c new file mode 100644 index 000000000..6f37764ec --- /dev/null +++ b/lib/toolbar/ephy-tbi-spinner.c @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <libgnome/gnome-i18n.h> +#include <gtk/gtkhbox.h> + +#include "ephy-tbi-spinner.h" +#include "ephy-gobject-misc.h" +#include "ephy-marshal.h" +#include "ephy-bonobo-extensions.h" + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +/** + * Private data + */ +struct _EphyTbiSpinnerPrivate +{ + GtkWidget *widget; +}; + +/** + * Private functions, only availble from this file + */ +static void ephy_tbi_spinner_class_init (EphyTbiSpinnerClass *klass); +static void ephy_tbi_spinner_init (EphyTbiSpinner *tb); +static void ephy_tbi_spinner_finalize_impl (GObject *o); +static GtkWidget * ephy_tbi_spinner_get_widget_impl (EphyTbItem *i); +static GdkPixbuf * ephy_tbi_spinner_get_icon_impl (EphyTbItem *i); +static gchar * ephy_tbi_spinner_get_name_human_impl (EphyTbItem *i); +static gchar * ephy_tbi_spinner_to_string_impl (EphyTbItem *i); +static gboolean ephy_tbi_spinner_is_unique_impl (EphyTbItem *i); +static EphyTbItem * ephy_tbi_spinner_clone_impl (EphyTbItem *i); +static void ephy_tbi_spinner_parse_properties_impl (EphyTbItem *i, const gchar *props); +static void ephy_tbi_spinner_add_to_bonobo_tb_impl (EphyTbItem *i, + BonoboUIComponent *ui, + const char *container_path, + guint index); + +static gpointer ephy_tb_item_class; + +/** + * TbiSpinner object + */ + +MAKE_GET_TYPE (ephy_tbi_spinner, "EphyTbiSpinner", EphyTbiSpinner, ephy_tbi_spinner_class_init, + ephy_tbi_spinner_init, EPHY_TYPE_TB_ITEM); + +static void +ephy_tbi_spinner_class_init (EphyTbiSpinnerClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = ephy_tbi_spinner_finalize_impl; + + EPHY_TB_ITEM_CLASS (klass)->get_widget = ephy_tbi_spinner_get_widget_impl; + EPHY_TB_ITEM_CLASS (klass)->get_icon = ephy_tbi_spinner_get_icon_impl; + EPHY_TB_ITEM_CLASS (klass)->get_name_human = ephy_tbi_spinner_get_name_human_impl; + EPHY_TB_ITEM_CLASS (klass)->to_string = ephy_tbi_spinner_to_string_impl; + EPHY_TB_ITEM_CLASS (klass)->is_unique = ephy_tbi_spinner_is_unique_impl; + EPHY_TB_ITEM_CLASS (klass)->clone = ephy_tbi_spinner_clone_impl; + EPHY_TB_ITEM_CLASS (klass)->parse_properties = ephy_tbi_spinner_parse_properties_impl; + EPHY_TB_ITEM_CLASS (klass)->add_to_bonobo_tb = ephy_tbi_spinner_add_to_bonobo_tb_impl; + + ephy_tb_item_class = g_type_class_peek_parent (klass); +} + +static void +ephy_tbi_spinner_init (EphyTbiSpinner *tb) +{ + EphyTbiSpinnerPrivate *p = g_new0 (EphyTbiSpinnerPrivate, 1); + tb->priv = p; +} + +EphyTbiSpinner * +ephy_tbi_spinner_new (void) +{ + EphyTbiSpinner *ret = g_object_new (EPHY_TYPE_TBI_SPINNER, NULL); + return ret; +} + +static void +ephy_tbi_spinner_finalize_impl (GObject *o) +{ + EphyTbiSpinner *it = EPHY_TBI_SPINNER (o); + EphyTbiSpinnerPrivate *p = it->priv; + + if (p->widget) + { + g_object_unref (p->widget); + } + + g_free (p); + + DEBUG_MSG (("EphyTbiSpinner finalized\n")); + + G_OBJECT_CLASS (ephy_tb_item_class)->finalize (o); +} + +static GtkWidget * +ephy_tbi_spinner_get_widget_impl (EphyTbItem *i) +{ + EphyTbiSpinner *iz = EPHY_TBI_SPINNER (i); + EphyTbiSpinnerPrivate *p = iz->priv; + + if (!p->widget) + { + /* here, we create only a box */ + p->widget = gtk_hbox_new (FALSE, 0); + g_object_ref (p->widget); + gtk_object_sink (GTK_OBJECT (p->widget)); + } + + return p->widget; +} + +static GdkPixbuf * +ephy_tbi_spinner_get_icon_impl (EphyTbItem *i) +{ + /* need an icon for this */ + return NULL; +} + +static gchar * +ephy_tbi_spinner_get_name_human_impl (EphyTbItem *i) +{ + return g_strdup (_("Spinner")); +} + +static gchar * +ephy_tbi_spinner_to_string_impl (EphyTbItem *i) +{ + /* if it had any properties, the string should include them */ + return g_strdup_printf ("%s=spinner", i->id); +} + +static gboolean +ephy_tbi_spinner_is_unique_impl (EphyTbItem *i) +{ + return TRUE; +} + +static EphyTbItem * +ephy_tbi_spinner_clone_impl (EphyTbItem *i) +{ + EphyTbItem *ret = EPHY_TB_ITEM (ephy_tbi_spinner_new ()); + + ephy_tb_item_set_id (ret, i->id); + + /* should copy properties too, if any */ + + return ret; +} + +static void +ephy_tbi_spinner_add_to_bonobo_tb_impl (EphyTbItem *i, BonoboUIComponent *ui, + const char *container_path, guint index) +{ + GtkWidget *w = ephy_tb_item_get_widget (i); + gtk_widget_show (w); + ephy_bonobo_add_numbered_control (ui, w, index, container_path); +} + +static void +ephy_tbi_spinner_parse_properties_impl (EphyTbItem *it, const gchar *props) +{ + /* we have no properties */ +} + diff --git a/lib/toolbar/ephy-tbi-spinner.h b/lib/toolbar/ephy-tbi-spinner.h new file mode 100644 index 000000000..1bb04f277 --- /dev/null +++ b/lib/toolbar/ephy-tbi-spinner.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_TBI_SPINNER_H +#define EPHY_TBI_SPINNER_H + +#include "ephy-toolbar-item.h" + +G_BEGIN_DECLS + +/* object forward declarations */ + +typedef struct _EphyTbiSpinner EphyTbiSpinner; +typedef struct _EphyTbiSpinnerClass EphyTbiSpinnerClass; +typedef struct _EphyTbiSpinnerPrivate EphyTbiSpinnerPrivate; + +/** + * TbiSpinner object + */ + +#define EPHY_TYPE_TBI_SPINNER (ephy_tbi_spinner_get_type()) +#define EPHY_TBI_SPINNER(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_TBI_SPINNER,\ + EphyTbiSpinner)) +#define EPHY_TBI_SPINNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TBI_SPINNER,\ + EphyTbiSpinnerClass)) +#define EPHY_IS_TBI_SPINNER(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_TBI_SPINNER)) +#define EPHY_IS_TBI_SPINNER_CLASS(klass)(G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TBI_SPINNER)) +#define EPHY_TBI_SPINNER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TBI_SPINNER,\ + EphyTbiSpinnerClass)) + +struct _EphyTbiSpinnerClass +{ + EphyTbItemClass parent_class; +}; + +/* Remember: fields are public read-only */ +struct _EphyTbiSpinner +{ + EphyTbItem parent_object; + + EphyTbiSpinnerPrivate *priv; +}; + +/* this class is abstract */ + +GType ephy_tbi_spinner_get_type (void); +EphyTbiSpinner * ephy_tbi_spinner_new (void); + +G_END_DECLS + +#endif diff --git a/lib/toolbar/ephy-tbi-std-toolitem.c b/lib/toolbar/ephy-tbi-std-toolitem.c new file mode 100644 index 000000000..deb468ecb --- /dev/null +++ b/lib/toolbar/ephy-tbi-std-toolitem.c @@ -0,0 +1,467 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <libgnome/gnome-i18n.h> +#include <bonobo/bonobo-ui-toolbar-button-item.h> +#include <bonobo/bonobo-property-bag.h> +#include <gtk/gtkstock.h> +#include <string.h> + +#include "ephy-tbi-std-toolitem.h" +#include "ephy-gobject-misc.h" +#include "ephy-marshal.h" +#include "ephy-bonobo-extensions.h" + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +/** + * Private data + */ +struct _EphyTbiStdToolitemPrivate +{ + GtkWidget *widget; + + EphyTbiStdToolitemItem item; +}; + + +/** + * Private functions, only availble from this file + */ +static void ephy_tbi_std_toolitem_class_init (EphyTbiStdToolitemClass *klass); +static void ephy_tbi_std_toolitem_init (EphyTbiStdToolitem *tb); +static void ephy_tbi_std_toolitem_finalize_impl (GObject *o); +static GtkWidget * ephy_tbi_std_toolitem_get_widget_impl (EphyTbItem *i); +static GdkPixbuf * ephy_tbi_std_toolitem_get_icon_impl (EphyTbItem *i); +static gchar * ephy_tbi_std_toolitem_get_name_human_impl (EphyTbItem *i); +static gchar * ephy_tbi_std_toolitem_to_string_impl (EphyTbItem *i); +static gboolean ephy_tbi_std_toolitem_is_unique_impl (EphyTbItem *i); +static EphyTbItem * ephy_tbi_std_toolitem_clone_impl (EphyTbItem *i); +static void ephy_tbi_std_toolitem_parse_properties_impl (EphyTbItem *i, const gchar *props); +static void ephy_tbi_std_toolitem_add_to_bonobo_tb_impl (EphyTbItem *i, + BonoboUIComponent *ui, + const char *container_path, + guint index); + +static gpointer ephy_tb_item_class; + +/** + * TbiStdToolitem object + */ + +MAKE_GET_TYPE (ephy_tbi_std_toolitem, "EphyTbiStdToolitem", EphyTbiStdToolitem, + ephy_tbi_std_toolitem_class_init, + ephy_tbi_std_toolitem_init, EPHY_TYPE_TB_ITEM); + +static void +ephy_tbi_std_toolitem_class_init (EphyTbiStdToolitemClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = ephy_tbi_std_toolitem_finalize_impl; + + EPHY_TB_ITEM_CLASS (klass)->get_widget = ephy_tbi_std_toolitem_get_widget_impl; + EPHY_TB_ITEM_CLASS (klass)->get_icon = ephy_tbi_std_toolitem_get_icon_impl; + EPHY_TB_ITEM_CLASS (klass)->get_name_human = ephy_tbi_std_toolitem_get_name_human_impl; + EPHY_TB_ITEM_CLASS (klass)->to_string = ephy_tbi_std_toolitem_to_string_impl; + EPHY_TB_ITEM_CLASS (klass)->is_unique = ephy_tbi_std_toolitem_is_unique_impl; + EPHY_TB_ITEM_CLASS (klass)->clone = ephy_tbi_std_toolitem_clone_impl; + EPHY_TB_ITEM_CLASS (klass)->parse_properties = ephy_tbi_std_toolitem_parse_properties_impl; + EPHY_TB_ITEM_CLASS (klass)->add_to_bonobo_tb = ephy_tbi_std_toolitem_add_to_bonobo_tb_impl; + + ephy_tb_item_class = g_type_class_peek_parent (klass); +} + +static void +ephy_tbi_std_toolitem_init (EphyTbiStdToolitem *tb) +{ + EphyTbiStdToolitemPrivate *p = g_new0 (EphyTbiStdToolitemPrivate, 1); + tb->priv = p; + + p->item = EPHY_TBI_STD_TOOLITEM_BACK; +} + +EphyTbiStdToolitem * +ephy_tbi_std_toolitem_new (void) +{ + EphyTbiStdToolitem *ret = g_object_new (EPHY_TYPE_TBI_STD_TOOLITEM, NULL); + return ret; +} + +static void +ephy_tbi_std_toolitem_finalize_impl (GObject *o) +{ + EphyTbiStdToolitem *it = EPHY_TBI_STD_TOOLITEM (o); + EphyTbiStdToolitemPrivate *p = it->priv; + + if (p->widget) + { + g_object_unref (p->widget); + } + + g_free (p); + + DEBUG_MSG (("EphyTbiStdToolitem finalized\n")); + + G_OBJECT_CLASS (ephy_tb_item_class)->finalize (o); +} + +static GtkWidget * +ephy_tbi_std_toolitem_get_widget_impl (EphyTbItem *i) +{ + /* no widget avaible ... */ + return NULL; +} + +static GdkPixbuf * +ephy_tbi_std_toolitem_get_icon_impl (EphyTbItem *i) +{ + EphyTbiStdToolitemPrivate *p = EPHY_TBI_STD_TOOLITEM (i)->priv; + + static GdkPixbuf *pb_up = NULL; + static GdkPixbuf *pb_back = NULL; + static GdkPixbuf *pb_forward = NULL; + static GdkPixbuf *pb_stop = NULL; + static GdkPixbuf *pb_reload = NULL; + static GdkPixbuf *pb_home = NULL; + static GdkPixbuf *pb_go = NULL; + static GdkPixbuf *pb_new = NULL; + + if (!pb_up) + { + /* what's the easier way? */ + GtkWidget *b = gtk_spin_button_new_with_range (0, 1, 0.5); + pb_up = gtk_widget_render_icon (b, + GTK_STOCK_GO_UP, + GTK_ICON_SIZE_SMALL_TOOLBAR, + NULL); + pb_back = gtk_widget_render_icon (b, + GTK_STOCK_GO_BACK, + GTK_ICON_SIZE_SMALL_TOOLBAR, + NULL); + pb_forward = gtk_widget_render_icon (b, + GTK_STOCK_GO_FORWARD, + GTK_ICON_SIZE_SMALL_TOOLBAR, + NULL); + pb_stop = gtk_widget_render_icon (b, + GTK_STOCK_STOP, + GTK_ICON_SIZE_SMALL_TOOLBAR, + NULL); + pb_reload = gtk_widget_render_icon (b, + GTK_STOCK_REFRESH, + GTK_ICON_SIZE_SMALL_TOOLBAR, + NULL); + pb_home = gtk_widget_render_icon (b, + GTK_STOCK_HOME, + GTK_ICON_SIZE_SMALL_TOOLBAR, + NULL); + pb_go = gtk_widget_render_icon (b, + GTK_STOCK_JUMP_TO, + GTK_ICON_SIZE_SMALL_TOOLBAR, + NULL); + pb_new = gtk_widget_render_icon (b, + GTK_STOCK_NEW, + GTK_ICON_SIZE_SMALL_TOOLBAR, + NULL); + gtk_widget_destroy (b); + } + + switch (p->item) + { + case EPHY_TBI_STD_TOOLITEM_BACK: + return g_object_ref (pb_back); + break; + case EPHY_TBI_STD_TOOLITEM_FORWARD: + return g_object_ref (pb_forward); + break; + case EPHY_TBI_STD_TOOLITEM_UP: + return g_object_ref (pb_up); + break; + case EPHY_TBI_STD_TOOLITEM_STOP: + return g_object_ref (pb_stop); + break; + case EPHY_TBI_STD_TOOLITEM_RELOAD: + return g_object_ref (pb_reload); + break; + case EPHY_TBI_STD_TOOLITEM_HOME: + return g_object_ref (pb_home); + break; + case EPHY_TBI_STD_TOOLITEM_GO: + return g_object_ref (pb_go); + break; + case EPHY_TBI_STD_TOOLITEM_NEW: + return g_object_ref (pb_new); + break; + default: + g_assert_not_reached (); + return NULL; + } +} + +static gchar * +ephy_tbi_std_toolitem_get_name_human_impl (EphyTbItem *i) +{ + EphyTbiStdToolitemPrivate *p = EPHY_TBI_STD_TOOLITEM (i)->priv; + const gchar *ret; + + switch (p->item) + { + case EPHY_TBI_STD_TOOLITEM_BACK: + ret = _("Back"); + break; + case EPHY_TBI_STD_TOOLITEM_FORWARD: + ret = _("Forward"); + break; + case EPHY_TBI_STD_TOOLITEM_UP: + ret = _("Up"); + break; + case EPHY_TBI_STD_TOOLITEM_STOP: + ret = _("Stop"); + break; + case EPHY_TBI_STD_TOOLITEM_RELOAD: + ret = _("Reload"); + break; + case EPHY_TBI_STD_TOOLITEM_HOME: + ret = _("Home"); + break; + case EPHY_TBI_STD_TOOLITEM_GO: + ret = _("Go"); + break; + case EPHY_TBI_STD_TOOLITEM_NEW: + ret = _("New"); + break; + default: + g_assert_not_reached (); + ret = "unknown"; + } + + return g_strdup (ret); +} + +static gchar * +ephy_tbi_std_toolitem_to_string_impl (EphyTbItem *i) +{ + EphyTbiStdToolitemPrivate *p = EPHY_TBI_STD_TOOLITEM (i)->priv; + + /* if it had any properties, the string should include them */ + const char *sitem; + + switch (p->item) + { + case EPHY_TBI_STD_TOOLITEM_BACK: + sitem = "back"; + break; + case EPHY_TBI_STD_TOOLITEM_FORWARD: + sitem = "forward"; + break; + case EPHY_TBI_STD_TOOLITEM_UP: + sitem = "up"; + break; + case EPHY_TBI_STD_TOOLITEM_STOP: + sitem = "stop"; + break; + case EPHY_TBI_STD_TOOLITEM_RELOAD: + sitem = "reload"; + break; + case EPHY_TBI_STD_TOOLITEM_HOME: + sitem = "home"; + break; + case EPHY_TBI_STD_TOOLITEM_GO: + sitem = "go"; + break; + case EPHY_TBI_STD_TOOLITEM_NEW: + sitem = "new"; + break; + default: + g_assert_not_reached (); + sitem = "unknown"; + } + + return g_strdup_printf ("%s=std_toolitem(item=%s)", i->id, sitem); +} + +static gboolean +ephy_tbi_std_toolitem_is_unique_impl (EphyTbItem *i) +{ + return TRUE; +} + +static EphyTbItem * +ephy_tbi_std_toolitem_clone_impl (EphyTbItem *i) +{ + EphyTbiStdToolitemPrivate *p = EPHY_TBI_STD_TOOLITEM (i)->priv; + + EphyTbItem *ret = EPHY_TB_ITEM (ephy_tbi_std_toolitem_new ()); + + ephy_tb_item_set_id (ret, i->id); + + /* should copy properties too, if any */ + ephy_tbi_std_toolitem_set_item (EPHY_TBI_STD_TOOLITEM (ret), p->item); + + return ret; +} + + +static void +ephy_tbi_std_toolitem_add_to_bonobo_tb_impl (EphyTbItem *i, BonoboUIComponent *ui, + const char *container_path, guint index) +{ + EphyTbiStdToolitemPrivate *p = EPHY_TBI_STD_TOOLITEM (i)->priv; + gchar *xml_item; + + switch (p->item) + { + case EPHY_TBI_STD_TOOLITEM_BACK: + xml_item = g_strdup_printf + ("<toolitem name=\"Back\" " + "label=\"%s\" " + "pixtype=\"stock\" pixname=\"gtk-go-back\" " + "priority=\"1\" " + "verb=\"GoBack\"/>", _("Back"));; + break; + case EPHY_TBI_STD_TOOLITEM_FORWARD: + xml_item = g_strdup_printf + ("<toolitem name=\"Forward\" " + "label=\"%s\" " + "pixtype=\"stock\" pixname=\"gtk-go-forward\" " + "verb=\"GoForward\"/>", _("Forward")); + break; + case EPHY_TBI_STD_TOOLITEM_UP: + xml_item = g_strdup_printf + ("<toolitem name=\"Up\" " + "label=\"%s\" " + "pixtype=\"stock\" pixname=\"gtk-go-up\" " + "verb=\"GoUp\"/>", _("Up"));; + break; + case EPHY_TBI_STD_TOOLITEM_STOP: + xml_item = g_strdup_printf + ("<toolitem name=\"Stop\" " + "label=\"%s\" " + "pixtype=\"stock\" pixname=\"gtk-stop\" " + "verb=\"GoStop\"/>", _("Stop")); + break; + case EPHY_TBI_STD_TOOLITEM_RELOAD: + xml_item = g_strdup_printf + ("<toolitem name=\"Reload\" " + "label=\"%s\" " + "pixtype=\"stock\" pixname=\"gtk-refresh\" " + "verb=\"GoReload\"/>", _("Reload")); + break; + case EPHY_TBI_STD_TOOLITEM_HOME: + xml_item = g_strdup_printf + ("<toolitem name=\"Home\" " + "label=\"%s\" " + "pixtype=\"stock\" pixname=\"gtk-home\" " + "priority=\"1\" " + "verb=\"GoHome\"/>", _("Home"));; + break; + case EPHY_TBI_STD_TOOLITEM_GO: + xml_item = g_strdup_printf + ("<toolitem name=\"Go\" " + "label=\"%s\" " + "pixtype=\"stock\" pixname=\"gtk-jump-to\" " + "verb=\"GoGo\"/>", _("Go"));; + break; + case EPHY_TBI_STD_TOOLITEM_NEW: + xml_item = g_strdup_printf + ("<toolitem name=\"New\" " + "label=\"%s\" " + "pixtype=\"stock\" pixname=\"gtk-new\" " + "verb=\"FileNew\"/>", _("New"));; + break; + + default: + g_assert_not_reached (); + xml_item = g_strdup (""); + } + + bonobo_ui_component_set (ui, container_path, xml_item, NULL); + g_free (xml_item); +} + +static void +ephy_tbi_std_toolitem_parse_properties_impl (EphyTbItem *it, const gchar *props) +{ + EphyTbiStdToolitem *a = EPHY_TBI_STD_TOOLITEM (it); + + /* yes, this is quite hacky, but works */ + + /* we have one property */ + const gchar *item_prop; + + item_prop = strstr (props, "item="); + if (item_prop) + { + item_prop += strlen ("item="); + if (!strncmp (item_prop, "back", 4)) + { + ephy_tbi_std_toolitem_set_item (a, EPHY_TBI_STD_TOOLITEM_BACK); + } + else if (!strncmp (item_prop, "forward", 4)) + { + ephy_tbi_std_toolitem_set_item (a, EPHY_TBI_STD_TOOLITEM_FORWARD); + } + else if (!strncmp (item_prop, "up", 2)) + { + ephy_tbi_std_toolitem_set_item (a, EPHY_TBI_STD_TOOLITEM_UP); + } + else if (!strncmp (item_prop, "stop", 4)) + { + ephy_tbi_std_toolitem_set_item (a, EPHY_TBI_STD_TOOLITEM_STOP); + } + else if (!strncmp (item_prop, "home", 4)) + { + ephy_tbi_std_toolitem_set_item (a, EPHY_TBI_STD_TOOLITEM_HOME); + } + else if (!strncmp (item_prop, "go", 2)) + { + ephy_tbi_std_toolitem_set_item (a, EPHY_TBI_STD_TOOLITEM_GO); + } + else if (!strncmp (item_prop, "reload", 6)) + { + ephy_tbi_std_toolitem_set_item (a, EPHY_TBI_STD_TOOLITEM_RELOAD); + } + else if (!strncmp (item_prop, "new", 3)) + { + ephy_tbi_std_toolitem_set_item (a, EPHY_TBI_STD_TOOLITEM_NEW); + } + + } +} + +void +ephy_tbi_std_toolitem_set_item (EphyTbiStdToolitem *a, EphyTbiStdToolitemItem i) +{ + EphyTbiStdToolitemPrivate *p = a->priv; + + g_return_if_fail (i == EPHY_TBI_STD_TOOLITEM_UP + || i == EPHY_TBI_STD_TOOLITEM_BACK + || i == EPHY_TBI_STD_TOOLITEM_FORWARD + || i == EPHY_TBI_STD_TOOLITEM_STOP + || i == EPHY_TBI_STD_TOOLITEM_RELOAD + || i == EPHY_TBI_STD_TOOLITEM_GO + || i == EPHY_TBI_STD_TOOLITEM_HOME + || i == EPHY_TBI_STD_TOOLITEM_NEW); + + p->item = i; +} + diff --git a/lib/toolbar/ephy-tbi-std-toolitem.h b/lib/toolbar/ephy-tbi-std-toolitem.h new file mode 100644 index 000000000..67073041f --- /dev/null +++ b/lib/toolbar/ephy-tbi-std-toolitem.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_TBI_STD_TOOLITEM_H +#define EPHY_TBI_STD_TOOLITEM_H + +#include "ephy-toolbar-item.h" + +G_BEGIN_DECLS + +/* object forward declarations */ + +typedef struct _EphyTbiStdToolitem EphyTbiStdToolitem; +typedef struct _EphyTbiStdToolitemClass EphyTbiStdToolitemClass; +typedef struct _EphyTbiStdToolitemPrivate EphyTbiStdToolitemPrivate; + +/** + * TbiStdToolitem object + */ + +#define EPHY_TYPE_TBI_STD_TOOLITEM (ephy_tbi_std_toolitem_get_type()) +#define EPHY_TBI_STD_TOOLITEM(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \ + EPHY_TYPE_TBI_STD_TOOLITEM,\ + EphyTbiStdToolitem)) +#define EPHY_TBI_STD_TOOLITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \ + EPHY_TYPE_TBI_STD_TOOLITEM,\ + EphyTbiStdToolitemClass)) +#define EPHY_IS_TBI_STD_TOOLITEM(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \ + EPHY_TYPE_TBI_STD_TOOLITEM)) +#define EPHY_IS_TBI_STD_TOOLITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \ + EPHY_TYPE_TBI_STD_TOOLITEM)) +#define EPHY_TBI_STD_TOOLITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ + EPHY_TYPE_TBI_STD_TOOLITEM,\ + EphyTbiStdToolitemClass)) +typedef enum +{ + EPHY_TBI_STD_TOOLITEM_BACK, + EPHY_TBI_STD_TOOLITEM_FORWARD, + EPHY_TBI_STD_TOOLITEM_UP, + EPHY_TBI_STD_TOOLITEM_STOP, + EPHY_TBI_STD_TOOLITEM_RELOAD, + EPHY_TBI_STD_TOOLITEM_HOME, + EPHY_TBI_STD_TOOLITEM_GO, + EPHY_TBI_STD_TOOLITEM_NEW +} EphyTbiStdToolitemItem; + + +struct _EphyTbiStdToolitemClass +{ + EphyTbItemClass parent_class; +}; + +/* Remember: fields are public read-only */ +struct _EphyTbiStdToolitem +{ + EphyTbItem parent_object; + + EphyTbiStdToolitemPrivate *priv; +}; + +/* this class is abstract */ + +GType ephy_tbi_std_toolitem_get_type (void); +EphyTbiStdToolitem * ephy_tbi_std_toolitem_new (void); +void ephy_tbi_std_toolitem_set_item (EphyTbiStdToolitem *sit, + EphyTbiStdToolitemItem it); + +G_END_DECLS + +#endif + diff --git a/lib/toolbar/ephy-tbi-zoom.c b/lib/toolbar/ephy-tbi-zoom.c new file mode 100644 index 000000000..578799b24 --- /dev/null +++ b/lib/toolbar/ephy-tbi-zoom.c @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <libgnome/gnome-i18n.h> +#include <gtk/gtkspinbutton.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkstock.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtkvbox.h> +#include <string.h> + +#include "ephy-tbi-zoom.h" +#include "ephy-prefs.h" +#include "eel-gconf-extensions.h" +#include "ephy-gobject-misc.h" +#include "ephy-marshal.h" +#include "ephy-bonobo-extensions.h" + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +/** + * Private data + */ +struct _EphyTbiZoomPrivate +{ + GtkWidget *widget; + GtkWidget *label; + GtkWidget *hbox; + GtkWidget *vbox; + guint notification; +}; + +enum +{ + TOOLBAR_ITEM_STYLE_PROP, + TOOLBAR_ITEM_ORIENTATION_PROP, + TOOLBAR_ITEM_WANT_LABEL_PROP +}; + +/** + * Private functions, only availble from this file + */ +static void ephy_tbi_zoom_class_init (EphyTbiZoomClass *klass); +static void ephy_tbi_zoom_init (EphyTbiZoom *tb); +static void ephy_tbi_zoom_finalize_impl (GObject *o); +static GtkWidget * ephy_tbi_zoom_get_widget_impl (EphyTbItem *i); +static GdkPixbuf * ephy_tbi_zoom_get_icon_impl (EphyTbItem *i); +static gchar * ephy_tbi_zoom_get_name_human_impl (EphyTbItem *i); +static gchar * ephy_tbi_zoom_to_string_impl (EphyTbItem *i); +static gboolean ephy_tbi_zoom_is_unique_impl (EphyTbItem *i); +static EphyTbItem * ephy_tbi_zoom_clone_impl (EphyTbItem *i); +static void ephy_tbi_zoom_parse_properties_impl (EphyTbItem *i, const gchar *props); +static void ephy_tbi_zoom_add_to_bonobo_tb_impl (EphyTbItem *i, + BonoboUIComponent *ui, + const char *container_path, + guint index); +static void ephy_tbi_zoom_setup_label (EphyTbiZoom *it); +static void ephy_tbi_zoom_notification_cb (GConfClient* client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data); + + +static gpointer ephy_tb_item_class; + +/** + * TbiZoom object + */ + +MAKE_GET_TYPE (ephy_tbi_zoom, "EphyTbiZoom", EphyTbiZoom, ephy_tbi_zoom_class_init, + ephy_tbi_zoom_init, EPHY_TYPE_TB_ITEM); + +static void +ephy_tbi_zoom_class_init (EphyTbiZoomClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = ephy_tbi_zoom_finalize_impl; + + EPHY_TB_ITEM_CLASS (klass)->get_widget = ephy_tbi_zoom_get_widget_impl; + EPHY_TB_ITEM_CLASS (klass)->get_icon = ephy_tbi_zoom_get_icon_impl; + EPHY_TB_ITEM_CLASS (klass)->get_name_human = ephy_tbi_zoom_get_name_human_impl; + EPHY_TB_ITEM_CLASS (klass)->to_string = ephy_tbi_zoom_to_string_impl; + EPHY_TB_ITEM_CLASS (klass)->is_unique = ephy_tbi_zoom_is_unique_impl; + EPHY_TB_ITEM_CLASS (klass)->clone = ephy_tbi_zoom_clone_impl; + EPHY_TB_ITEM_CLASS (klass)->parse_properties = ephy_tbi_zoom_parse_properties_impl; + EPHY_TB_ITEM_CLASS (klass)->add_to_bonobo_tb = ephy_tbi_zoom_add_to_bonobo_tb_impl; + + ephy_tb_item_class = g_type_class_peek_parent (klass); +} + +static void +ephy_tbi_zoom_init (EphyTbiZoom *tbi) +{ + EphyTbiZoomPrivate *p = g_new0 (EphyTbiZoomPrivate, 1); + tbi->priv = p; + + p->notification = eel_gconf_notification_add (CONF_DESKTOP_TOOLBAR_STYLE, + ephy_tbi_zoom_notification_cb, + tbi); +} + +EphyTbiZoom * +ephy_tbi_zoom_new (void) +{ + EphyTbiZoom *ret = g_object_new (EPHY_TYPE_TBI_ZOOM, NULL); + return ret; +} + +static void +ephy_tbi_zoom_finalize_impl (GObject *o) +{ + EphyTbiZoom *it = EPHY_TBI_ZOOM (o); + EphyTbiZoomPrivate *p = it->priv; + + if (p->widget) + { + g_object_unref (p->widget); + } + + if (p->label) + { + g_object_unref (p->label); + } + + if (p->vbox) + { + g_object_unref (p->vbox); + } + + if (p->hbox) + { + g_object_unref (p->hbox); + } + + if (p->notification) + { + eel_gconf_notification_remove (p->notification); + } + + g_free (p); + + DEBUG_MSG (("EphyTbiZoom finalized\n")); + + G_OBJECT_CLASS (ephy_tb_item_class)->finalize (o); +} + +static GtkWidget * +ephy_tbi_zoom_get_widget_impl (EphyTbItem *i) +{ + EphyTbiZoom *iz = EPHY_TBI_ZOOM (i); + EphyTbiZoomPrivate *p = iz->priv; + + if (!p->widget) + { + p->widget = gtk_spin_button_new_with_range (1, 999, 10); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (p->widget), 100); + g_object_ref (p->widget); + gtk_object_sink (GTK_OBJECT (p->widget)); + p->label = gtk_label_new (_("Zoom")); + g_object_ref (p->label); + gtk_object_sink (GTK_OBJECT (p->label)); + p->vbox = gtk_vbox_new (FALSE, 0); + g_object_ref (p->vbox); + gtk_object_sink (GTK_OBJECT (p->vbox)); + p->hbox = gtk_hbox_new (FALSE, 0); + g_object_ref (p->hbox); + gtk_object_sink (GTK_OBJECT (p->hbox)); + + gtk_box_pack_start_defaults (GTK_BOX (p->hbox), p->vbox); + gtk_box_pack_start_defaults (GTK_BOX (p->vbox), p->widget); + gtk_widget_show (p->vbox); + gtk_widget_show (p->hbox); + } + + return p->widget; +} + +static GdkPixbuf * +ephy_tbi_zoom_get_icon_impl (EphyTbItem *i) +{ + static GdkPixbuf *pb = NULL; + if (!pb) + { + /* what's the easier way? */ + GtkWidget *b = gtk_spin_button_new_with_range (0, 1, 0.5); + pb = gtk_widget_render_icon (b, + GTK_STOCK_ZOOM_IN, + GTK_ICON_SIZE_SMALL_TOOLBAR, + NULL); + gtk_widget_destroy (b); + } + return g_object_ref (pb); +} + +static gchar * +ephy_tbi_zoom_get_name_human_impl (EphyTbItem *i) +{ + return g_strdup (_("Zoom")); +} + +static gchar * +ephy_tbi_zoom_to_string_impl (EphyTbItem *i) +{ + /* if it had any properties, the string should include them */ + return g_strdup_printf ("%s=zoom", i->id); +} + +static gboolean +ephy_tbi_zoom_is_unique_impl (EphyTbItem *i) +{ + return TRUE; +} + +static EphyTbItem * +ephy_tbi_zoom_clone_impl (EphyTbItem *i) +{ + EphyTbItem *ret = EPHY_TB_ITEM (ephy_tbi_zoom_new ()); + + ephy_tb_item_set_id (ret, i->id); + + /* should copy properties too, if any */ + /* the zoom value is not copied, not sure if it should... */ + + return ret; +} + +static void +ephy_tbi_zoom_add_to_bonobo_tb_impl (EphyTbItem *i, BonoboUIComponent *ui, + const char *container_path, guint index) +{ + GtkWidget *w = ephy_tb_item_get_widget (i); + EphyTbiZoomPrivate *p = EPHY_TBI_ZOOM (i)->priv; + gtk_widget_show (w); + ephy_bonobo_add_numbered_control (ui, p->hbox, index, container_path); + ephy_tbi_zoom_setup_label (EPHY_TBI_ZOOM (i)); +} + +static void +ephy_tbi_zoom_parse_properties_impl (EphyTbItem *it, const gchar *props) +{ + /* we have no properties */ +} + +static void +ephy_tbi_zoom_setup_label (EphyTbiZoom *it) +{ + EphyTbiZoomPrivate *p = it->priv; + gchar *style = eel_gconf_get_string (CONF_DESKTOP_TOOLBAR_STYLE); + ephy_tb_item_get_widget (EPHY_TB_ITEM (it)); + + g_object_ref (p->label); + if (p->label->parent) + { + gtk_container_remove (GTK_CONTAINER (p->label->parent), p->label); + } + + if (!strcmp (style, "both_horiz") || !strcmp (style, "text")) + { + gtk_widget_show (p->label); + gtk_box_pack_start_defaults (GTK_BOX (p->hbox), p->label); + } + else if (!strcmp (style, "both")) + { + gtk_widget_show (p->label); + gtk_box_pack_start_defaults (GTK_BOX (p->vbox), p->label); + } + else + { + gtk_widget_hide (p->label); + } + + g_free (style); + g_object_unref (p->label); +} + +static void +ephy_tbi_zoom_notification_cb (GConfClient* client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) +{ + ephy_tbi_zoom_setup_label (user_data); +} + diff --git a/lib/toolbar/ephy-tbi-zoom.h b/lib/toolbar/ephy-tbi-zoom.h new file mode 100644 index 000000000..03f0ed61e --- /dev/null +++ b/lib/toolbar/ephy-tbi-zoom.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_TBI_ZOOM_H +#define EPHY_TBI_ZOOM_H + +#include "ephy-toolbar-item.h" + +G_BEGIN_DECLS + +/* object forward declarations */ + +typedef struct _EphyTbiZoom EphyTbiZoom; +typedef struct _EphyTbiZoomClass EphyTbiZoomClass; +typedef struct _EphyTbiZoomPrivate EphyTbiZoomPrivate; + +/** + * TbiZoom object + */ + +#define EPHY_TYPE_TBI_ZOOM (ephy_tbi_zoom_get_type()) +#define EPHY_TBI_ZOOM(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_TBI_ZOOM,\ + EphyTbiZoom)) +#define EPHY_TBI_ZOOM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TBI_ZOOM,\ + EphyTbiZoomClass)) +#define EPHY_IS_TBI_ZOOM(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_TBI_ZOOM)) +#define EPHY_IS_TBI_ZOOM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TBI_ZOOM)) +#define EPHY_TBI_ZOOM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TBI_ZOOM,\ + EphyTbiZoomClass)) + +struct _EphyTbiZoomClass +{ + EphyTbItemClass parent_class; +}; + +/* Remember: fields are public read-only */ +struct _EphyTbiZoom +{ + EphyTbItem parent_object; + + EphyTbiZoomPrivate *priv; +}; + +/* this class is abstract */ + +GType ephy_tbi_zoom_get_type (void); +EphyTbiZoom * ephy_tbi_zoom_new (void); + +G_END_DECLS + +#endif diff --git a/lib/toolbar/ephy-toolbar-bonobo-view.c b/lib/toolbar/ephy-toolbar-bonobo-view.c new file mode 100644 index 000000000..a22356e1e --- /dev/null +++ b/lib/toolbar/ephy-toolbar-bonobo-view.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <libgnome/gnome-i18n.h> + +#include "ephy-gobject-misc.h" +#include "ephy-marshal.h" +#include "ephy-toolbar-bonobo-view.h" +#include "ephy-bonobo-extensions.h" + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +/** + * Private data + */ +struct _EphyTbBonoboViewPrivate +{ + EphyToolbar *tb; + BonoboUIComponent *ui; + gchar *path; +}; + +/** + * Private functions, only availble from this file + */ +static void ephy_tb_bonobo_view_class_init (EphyTbBonoboViewClass *klass); +static void ephy_tb_bonobo_view_init (EphyTbBonoboView *tb); +static void ephy_tb_bonobo_view_finalize_impl (GObject *o); +static void ephy_tb_bonobo_view_rebuild (EphyTbBonoboView *tbv); +static void ephy_tb_bonobo_view_tb_changed (EphyToolbar *tb, EphyTbBonoboView *tbv); + +static gpointer g_object_class; + +/** + * TbBonoboView object + */ + +MAKE_GET_TYPE (ephy_tb_bonobo_view, "EphyTbBonoboView", EphyTbBonoboView, ephy_tb_bonobo_view_class_init, + ephy_tb_bonobo_view_init, G_TYPE_OBJECT); + +static void +ephy_tb_bonobo_view_class_init (EphyTbBonoboViewClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = ephy_tb_bonobo_view_finalize_impl; + + g_object_class = g_type_class_peek_parent (klass); +} + +static void +ephy_tb_bonobo_view_init (EphyTbBonoboView *tb) +{ + EphyTbBonoboViewPrivate *p = g_new0 (EphyTbBonoboViewPrivate, 1); + tb->priv = p; +} + +static void +ephy_tb_bonobo_view_finalize_impl (GObject *o) +{ + EphyTbBonoboView *tbv = EPHY_TB_BONOBO_VIEW (o); + EphyTbBonoboViewPrivate *p = tbv->priv; + + if (p->tb) + { + g_signal_handlers_disconnect_matched (p->tb, G_SIGNAL_MATCH_DATA, 0, 0, + NULL, NULL, tbv); + g_object_unref (p->tb); + } + if (p->ui) + { + g_object_unref (p->ui); + } + if (p->path) + { + g_free (p->path); + } + + g_free (p); + + DEBUG_MSG (("EphyTbBonoboView finalized\n")); + + G_OBJECT_CLASS (g_object_class)->finalize (o); +} + +EphyTbBonoboView * +ephy_tb_bonobo_view_new (void) +{ + EphyTbBonoboView *ret = g_object_new (EPHY_TYPE_TB_BONOBO_VIEW, NULL); + return ret; +} + +void +ephy_tb_bonobo_view_set_toolbar (EphyTbBonoboView *tbv, EphyToolbar *tb) +{ + EphyTbBonoboViewPrivate *p = tbv->priv; + + if (p->tb) + { + g_signal_handlers_disconnect_matched (p->tb, G_SIGNAL_MATCH_DATA, 0, 0, + NULL, NULL, tbv); + g_object_unref (p->tb); + } + + p->tb = g_object_ref (tb); + g_signal_connect (p->tb, "changed", G_CALLBACK (ephy_tb_bonobo_view_tb_changed), tbv); + + if (p->ui) + { + ephy_tb_bonobo_view_rebuild (tbv); + } +} + +static void +ephy_tb_bonobo_view_tb_changed (EphyToolbar *tb, EphyTbBonoboView *tbv) +{ + EphyTbBonoboViewPrivate *p = tbv->priv; + if (p->ui) + { + ephy_tb_bonobo_view_rebuild (tbv); + } +} + +void +ephy_tb_bonobo_view_set_path (EphyTbBonoboView *tbv, + BonoboUIComponent *ui, + const gchar *path) +{ + EphyTbBonoboViewPrivate *p = tbv->priv; + + if (p->ui) + { + g_object_unref (p->ui); + } + + if (p->path) + { + g_free (p->path); + } + + p->ui = g_object_ref (ui); + p->path = g_strdup (path); + + if (p->tb) + { + ephy_tb_bonobo_view_rebuild (tbv); + } +} + +static void +ephy_tb_bonobo_view_rebuild (EphyTbBonoboView *tbv) +{ + EphyTbBonoboViewPrivate *p = tbv->priv; + GSList *items; + GSList *li; + uint index = 0; + + g_return_if_fail (EPHY_IS_TOOLBAR (p->tb)); + g_return_if_fail (BONOBO_IS_UI_COMPONENT (p->ui)); + g_return_if_fail (p->path); + + DEBUG_MSG (("Rebuilding EphyTbBonoboView\n")); + + ephy_bonobo_clear_path (p->ui, p->path); + + items = (GSList *) ephy_toolbar_get_item_list (p->tb); + for (li = items; li; li = li->next) + { + ephy_tb_item_add_to_bonobo_tb (li->data, p->ui, p->path, index++); + } + + DEBUG_MSG (("Rebuilt EphyTbBonoboView\n")); +} + diff --git a/lib/toolbar/ephy-toolbar-bonobo-view.h b/lib/toolbar/ephy-toolbar-bonobo-view.h new file mode 100644 index 000000000..a914fc201 --- /dev/null +++ b/lib/toolbar/ephy-toolbar-bonobo-view.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_TOOLBAR_BONOBO_VIEW_H +#define EPHY_TOOLBAR_BONOBO_VIEW_H + +#include <glib-object.h> + +#include <bonobo/bonobo-ui-component.h> + +#include "ephy-toolbar.h" + +G_BEGIN_DECLS + +/* object forward declarations */ + +typedef struct _EphyTbBonoboView EphyTbBonoboView; +typedef struct _EphyTbBonoboViewClass EphyTbBonoboViewClass; +typedef struct _EphyTbBonoboViewPrivate EphyTbBonoboViewPrivate; + +/** + * TbBonoboView object + */ + +#define EPHY_TYPE_TB_BONOBO_VIEW (ephy_tb_bonobo_view_get_type()) +#define EPHY_TB_BONOBO_VIEW(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \ + EPHY_TYPE_TB_BONOBO_VIEW,\ + EphyTbBonoboView)) +#define EPHY_TB_BONOBO_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TB_BONOBO_VIEW,\ + EphyTbBonoboViewClass)) +#define EPHY_IS_TB_BONOBO_VIEW(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \ + EPHY_TYPE_TB_BONOBO_VIEW)) +#define EPHY_IS_TB_BONOBO_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TB_BONOBO_VIEW)) +#define EPHY_TB_BONOBO_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TB_BONOBO_VIEW,\ + EphyTbBonoboViewClass)) + +struct _EphyTbBonoboViewClass +{ + GObjectClass parent_class; +}; + +/* Remember: fields are public read-only */ +struct _EphyTbBonoboView +{ + GObject parent_object; + + EphyTbBonoboViewPrivate *priv; +}; + +/* this class is abstract */ + +GType ephy_tb_bonobo_view_get_type (void); +EphyTbBonoboView * ephy_tb_bonobo_view_new (void); +void ephy_tb_bonobo_view_set_toolbar (EphyTbBonoboView *tbv, EphyToolbar *tb); +void ephy_tb_bonobo_view_set_path (EphyTbBonoboView *tbv, + BonoboUIComponent *ui, + const gchar *path); + +#endif + diff --git a/lib/toolbar/ephy-toolbar-editor.c b/lib/toolbar/ephy-toolbar-editor.c new file mode 100644 index 000000000..e44767bad --- /dev/null +++ b/lib/toolbar/ephy-toolbar-editor.c @@ -0,0 +1,634 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <libgnome/gnome-i18n.h> + +#include "ephy-gobject-misc.h" +#include "ephy-marshal.h" +#include "ephy-toolbar-editor.h" +#include "ephy-toolbar-tree-model.h" +#include "ephy-glade.h" + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +/** + * Private data + */ +struct _EphyTbEditorPrivate +{ + EphyToolbar *tb; + EphyToolbar *available; + + gchar *tb_undo_string; + gchar *available_undo_string; + + gboolean in_toolbar_changed; + + GtkWidget *window; + GtkWidget *available_view; + GtkWidget *current_view; + GtkWidget *close_button; + GtkWidget *undo_button; + GtkWidget *revert_button; + GtkWidget *up_button; + GtkWidget *down_button; + GtkWidget *left_button; + GtkWidget *right_button; +}; + +/** + * Private functions, only available from this file + */ +static void ephy_tb_editor_class_init (EphyTbEditorClass *klass); +static void ephy_tb_editor_init (EphyTbEditor *tbe); +static void ephy_tb_editor_finalize_impl (GObject *o); +static void ephy_tb_editor_init_widgets (EphyTbEditor *tbe); +static void ephy_tb_editor_set_treeview_toolbar (EphyTbEditor *tbe, + GtkTreeView *tv, EphyToolbar *tb); +static void ephy_tb_editor_setup_treeview (EphyTbEditor *tbe, GtkTreeView *tv); +static EphyTbItem * ephy_tb_editor_get_selected (EphyTbEditor *tbe, GtkTreeView *tv); +static gint ephy_tb_editor_get_selected_index (EphyTbEditor *tbe, GtkTreeView *tv); +static void ephy_tb_editor_select_index (EphyTbEditor *tbe, GtkTreeView *tv, + gint index); +static void ephy_tb_editor_remove_used_items (EphyTbEditor *tbe); + +static void ephy_tb_editor_undo_clicked_cb (GtkWidget *b, EphyTbEditor *tbe); +static void ephy_tb_editor_close_clicked_cb (GtkWidget *b, EphyTbEditor *tbe); +static void ephy_tb_editor_up_clicked_cb (GtkWidget *b, EphyTbEditor *tbe); +static void ephy_tb_editor_down_clicked_cb (GtkWidget *b, EphyTbEditor *tbe); +static void ephy_tb_editor_left_clicked_cb (GtkWidget *b, EphyTbEditor *tbe); +static void ephy_tb_editor_right_clicked_cb (GtkWidget *b, EphyTbEditor *tbe); +static void ephy_tb_editor_toolbar_changed_cb (EphyToolbar *tb, EphyTbEditor *tbe); +static gboolean ephy_tb_editor_treeview_button_press_event_cb (GtkWidget *widget, + GdkEventButton *event, + EphyTbEditor *tbe); + + +static gpointer g_object_class; + +/* treeview dnd */ +enum +{ + TARGET_GTK_TREE_MODEL_ROW +}; +static GtkTargetEntry tree_view_row_targets[] = { + { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, TARGET_GTK_TREE_MODEL_ROW } +}; + +/** + * TbEditor object + */ + +MAKE_GET_TYPE (ephy_tb_editor, "EphyTbEditor", EphyTbEditor, ephy_tb_editor_class_init, + ephy_tb_editor_init, G_TYPE_OBJECT); + +static void +ephy_tb_editor_class_init (EphyTbEditorClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = ephy_tb_editor_finalize_impl; + + g_object_class = g_type_class_peek_parent (klass); +} + +static void +ephy_tb_editor_init (EphyTbEditor *tb) +{ + EphyTbEditorPrivate *p = g_new0 (EphyTbEditorPrivate, 1); + tb->priv = p; + + ephy_tb_editor_init_widgets (tb); +} + +static void +update_arrows_sensitivity (EphyTbEditor *tbe) +{ + GtkTreeSelection *selection; + gboolean current_sel; + gboolean avail_sel; + gboolean first = FALSE; + gboolean last = FALSE; + GtkTreeModel *tm; + GtkTreeIter iter; + GtkTreePath *path; + + selection = gtk_tree_view_get_selection + (GTK_TREE_VIEW (tbe->priv->current_view)); + current_sel = gtk_tree_selection_get_selected (selection, &tm, &iter); + if (current_sel) + { + path = gtk_tree_model_get_path (tm, &iter); + first = !gtk_tree_path_prev (path); + last = !gtk_tree_model_iter_next (tm, &iter); + } + + selection = gtk_tree_view_get_selection + (GTK_TREE_VIEW (tbe->priv->available_view)); + avail_sel = gtk_tree_selection_get_selected (selection, &tm, &iter); + + gtk_widget_set_sensitive (tbe->priv->right_button, + avail_sel); + gtk_widget_set_sensitive (tbe->priv->left_button, + current_sel); + gtk_widget_set_sensitive (tbe->priv->up_button, + current_sel && !first); + gtk_widget_set_sensitive (tbe->priv->down_button, + current_sel && !last); +} + +static void +ephy_tb_editor_treeview_selection_changed_cb (GtkTreeSelection *selection, + EphyTbEditor *tbe) +{ + update_arrows_sensitivity (tbe); +} + +static void +ephy_tb_editor_init_widgets (EphyTbEditor *tbe) +{ + EphyTbEditorPrivate *p = tbe->priv; + + GladeXML *gxml = ephy_glade_widget_new ("toolbar-editor.glade", "toolbar-editor-dialog", + NULL, tbe); + p->window = glade_xml_get_widget (gxml, "toolbar-editor-dialog"); + p->available_view = glade_xml_get_widget (gxml, "toolbar-editor-available-view"); + p->current_view = glade_xml_get_widget (gxml, "toolbar-editor-current-view"); + p->close_button = glade_xml_get_widget (gxml, "toolbar-editor-close-button"); + p->undo_button = glade_xml_get_widget (gxml, "toolbar-editor-undo-button"); + p->revert_button = glade_xml_get_widget (gxml, "toolbar-editor-revert-button"); + p->up_button = glade_xml_get_widget (gxml, "toolbar-editor-up-button"); + p->down_button = glade_xml_get_widget (gxml, "toolbar-editor-down-button"); + p->left_button = glade_xml_get_widget (gxml, "toolbar-editor-left-button"); + p->right_button = glade_xml_get_widget (gxml, "toolbar-editor-right-button"); + g_object_unref (gxml); + + g_signal_connect_swapped (p->window, "delete_event", G_CALLBACK (g_object_unref), tbe); + g_signal_connect (p->undo_button, "clicked", G_CALLBACK (ephy_tb_editor_undo_clicked_cb), tbe); + g_signal_connect (p->close_button, "clicked", G_CALLBACK (ephy_tb_editor_close_clicked_cb), tbe); + g_signal_connect (p->up_button, "clicked", G_CALLBACK (ephy_tb_editor_up_clicked_cb), tbe); + g_signal_connect (p->down_button, "clicked", G_CALLBACK (ephy_tb_editor_down_clicked_cb), tbe); + g_signal_connect (p->left_button, "clicked", G_CALLBACK (ephy_tb_editor_left_clicked_cb), tbe); + g_signal_connect (p->right_button, "clicked", G_CALLBACK (ephy_tb_editor_right_clicked_cb), tbe); + + ephy_tb_editor_setup_treeview (tbe, GTK_TREE_VIEW (p->current_view)); + ephy_tb_editor_setup_treeview (tbe, GTK_TREE_VIEW (p->available_view)); +} + +static void +ephy_tb_editor_undo_clicked_cb (GtkWidget *b, EphyTbEditor *tbe) +{ + EphyTbEditorPrivate *p = tbe->priv; + if (p->available_undo_string && p->available) + { + ephy_toolbar_parse (p->available, p->available_undo_string); + } + + if (p->tb_undo_string && p->tb) + { + ephy_toolbar_parse (p->tb, p->tb_undo_string); + } +} + +static void +ephy_tb_editor_close_clicked_cb (GtkWidget *b, EphyTbEditor *tbe) +{ + gtk_widget_hide (tbe->priv->window); + g_object_unref (tbe); +} + +static void +ephy_tb_editor_up_clicked_cb (GtkWidget *b, EphyTbEditor *tbe) +{ + EphyTbEditorPrivate *p = tbe->priv; + EphyTbItem *item = ephy_tb_editor_get_selected (tbe, GTK_TREE_VIEW (p->current_view)); + gint index = ephy_tb_editor_get_selected_index (tbe, GTK_TREE_VIEW (p->current_view)); + if (item && index > 0) + { + g_object_ref (item); + ephy_toolbar_remove_item (p->tb, item); + ephy_toolbar_add_item (p->tb, item, index - 1); + ephy_tb_editor_select_index (tbe, GTK_TREE_VIEW (p->current_view), index - 1); + g_object_unref (item); + } +} + +static void +ephy_tb_editor_down_clicked_cb (GtkWidget *b, EphyTbEditor *tbe) +{ + EphyTbEditorPrivate *p = tbe->priv; + EphyTbItem *item = ephy_tb_editor_get_selected (tbe, GTK_TREE_VIEW (p->current_view)); + gint index = ephy_tb_editor_get_selected_index (tbe, GTK_TREE_VIEW (p->current_view)); + if (item) + { + g_object_ref (item); + ephy_toolbar_remove_item (p->tb, item); + ephy_toolbar_add_item (p->tb, item, index + 1); + ephy_tb_editor_select_index (tbe, GTK_TREE_VIEW (p->current_view), index + 1); + g_object_unref (item); + } +} + +static void +ephy_tb_editor_left_clicked_cb (GtkWidget *b, EphyTbEditor *tbe) +{ + EphyTbEditorPrivate *p = tbe->priv; + EphyTbItem *item = ephy_tb_editor_get_selected (tbe, GTK_TREE_VIEW (p->current_view)); + /* probably is better not allowing reordering the available_view */ + gint index = ephy_tb_editor_get_selected_index (tbe, GTK_TREE_VIEW (p->available_view)); + if (item) + { + g_object_ref (item); + ephy_toolbar_remove_item (p->tb, item); + if (ephy_tb_item_is_unique (item)) + { + ephy_toolbar_add_item (p->available, item, index); + } + g_object_unref (item); + } +} + +static void +ephy_tb_editor_right_clicked_cb (GtkWidget *b, EphyTbEditor *tbe) +{ + EphyTbEditorPrivate *p = tbe->priv; + EphyTbItem *item = ephy_tb_editor_get_selected (tbe, GTK_TREE_VIEW (p->available_view)); + gint index = ephy_tb_editor_get_selected_index (tbe, GTK_TREE_VIEW (p->current_view)); + if (item) + { + if (ephy_tb_item_is_unique (item)) + { + g_object_ref (item); + ephy_toolbar_remove_item (p->available, item); + } + else + { + item = ephy_tb_item_clone (item); + } + ephy_toolbar_add_item (p->tb, item, index); + ephy_tb_editor_select_index (tbe, GTK_TREE_VIEW (p->current_view), index); + g_object_unref (item); + } +} + +static EphyTbItem * +ephy_tb_editor_get_selected (EphyTbEditor *tbe, GtkTreeView *tv) +{ + GtkTreeSelection *sel = gtk_tree_view_get_selection (tv); + GtkTreeModel *tm; + GtkTreeIter iter; + if (gtk_tree_selection_get_selected (sel, &tm, &iter)) + { + EphyTbItem *ret; + g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tm), NULL); + ret = ephy_tb_tree_model_item_from_iter (EPHY_TB_TREE_MODEL (tm), &iter); + return ret; + } + else + { + return NULL; + } +} + +static gint +ephy_tb_editor_get_selected_index (EphyTbEditor *tbe, GtkTreeView *tv) +{ + GtkTreeSelection *sel = gtk_tree_view_get_selection (tv); + GtkTreeModel *tm; + GtkTreeIter iter; + if (gtk_tree_selection_get_selected (sel, &tm, &iter)) + { + GtkTreePath *p = gtk_tree_model_get_path (tm, &iter); + if (p) + { + gint ret = gtk_tree_path_get_depth (p) > 0 ? gtk_tree_path_get_indices (p)[0] : -1; + gtk_tree_path_free (p); + return ret; + } + else + { + return -1; + } + } + else + { + return -1; + } +} + +static void +ephy_tb_editor_select_index (EphyTbEditor *tbe, GtkTreeView *tv, gint index) +{ + GtkTreeSelection *sel = gtk_tree_view_get_selection (tv); + GtkTreePath *p = gtk_tree_path_new (); + GtkTreeModel *tm = gtk_tree_view_get_model (tv); + gint max = gtk_tree_model_iter_n_children (tm, NULL); + + if (index < 0 || index >= max) + { + index = max - 1; + } + + gtk_tree_path_append_index (p, index); + gtk_tree_selection_select_path (sel, p); + gtk_tree_path_free (p); +} + +static void +ephy_tb_editor_finalize_impl (GObject *o) +{ + EphyTbEditor *tbe = EPHY_TB_EDITOR (o); + EphyTbEditorPrivate *p = tbe->priv; + + if (p->tb) + { + g_signal_handlers_disconnect_matched (p->tb, G_SIGNAL_MATCH_DATA, 0, 0, + NULL, NULL, tbe); + + g_object_unref (p->tb); + } + if (p->available) + { + g_signal_handlers_disconnect_matched (p->available, G_SIGNAL_MATCH_DATA, 0, 0, + NULL, NULL, tbe); + g_object_unref (p->available); + } + + if (p->window) + { + gtk_widget_destroy (p->window); + } + + g_free (p->tb_undo_string); + g_free (p->available_undo_string); + + g_free (p); + + DEBUG_MSG (("EphyTbEditor finalized\n")); + + G_OBJECT_CLASS (g_object_class)->finalize (o); +} + +EphyTbEditor * +ephy_tb_editor_new (void) +{ + EphyTbEditor *ret = g_object_new (EPHY_TYPE_TB_EDITOR, NULL); + return ret; +} + +void +ephy_tb_editor_set_toolbar (EphyTbEditor *tbe, EphyToolbar *tb) +{ + EphyTbEditorPrivate *p = tbe->priv; + + if (p->tb) + { + g_signal_handlers_disconnect_matched (p->tb, G_SIGNAL_MATCH_DATA, 0, 0, + NULL, NULL, tbe); + g_object_unref (p->tb); + } + p->tb = g_object_ref (tb); + + g_free (p->tb_undo_string); + p->tb_undo_string = ephy_toolbar_to_string (p->tb); + + if (p->available) + { + ephy_tb_editor_remove_used_items (tbe); + } + + g_signal_connect (p->tb, "changed", G_CALLBACK (ephy_tb_editor_toolbar_changed_cb), tbe); + + ephy_tb_editor_set_treeview_toolbar (tbe, GTK_TREE_VIEW (p->current_view), p->tb); + + gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (p->current_view), + GDK_BUTTON1_MASK, + tree_view_row_targets, + G_N_ELEMENTS (tree_view_row_targets), + GDK_ACTION_MOVE); + gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (p->current_view), + tree_view_row_targets, + G_N_ELEMENTS (tree_view_row_targets), + GDK_ACTION_COPY); +} + +void +ephy_tb_editor_set_available (EphyTbEditor *tbe, EphyToolbar *tb) +{ + EphyTbEditorPrivate *p = tbe->priv; + + if (p->available) + { + g_signal_handlers_disconnect_matched (p->available, G_SIGNAL_MATCH_DATA, 0, 0, + NULL, NULL, tbe); + g_object_unref (p->available); + } + p->available = g_object_ref (tb); + + g_free (p->available_undo_string); + p->available_undo_string = ephy_toolbar_to_string (p->available); + + ephy_toolbar_set_fixed_order (p->available, TRUE); + + if (p->tb) + { + ephy_tb_editor_remove_used_items (tbe); + } + + ephy_tb_editor_set_treeview_toolbar (tbe, GTK_TREE_VIEW (p->available_view), p->available); + + gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (p->available_view), + GDK_BUTTON1_MASK, + tree_view_row_targets, + G_N_ELEMENTS (tree_view_row_targets), + GDK_ACTION_COPY); + gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (p->available_view), + tree_view_row_targets, + G_N_ELEMENTS (tree_view_row_targets), + GDK_ACTION_MOVE); +} + +void +ephy_tb_editor_set_parent (EphyTbEditor *tbe, GtkWidget *parent) +{ + gtk_window_set_transient_for (GTK_WINDOW (tbe->priv->window), + GTK_WINDOW (parent)); +} + +void +ephy_tb_editor_show (EphyTbEditor *tbe) +{ + gtk_window_present (GTK_WINDOW (tbe->priv->window)); +} + +static void +ephy_tb_editor_set_treeview_toolbar (EphyTbEditor *tbe, GtkTreeView *tv, EphyToolbar *tb) +{ + EphyTbTreeModel *tm = ephy_tb_tree_model_new (); + ephy_tb_tree_model_set_toolbar (tm, tb); + gtk_tree_view_set_model (tv, GTK_TREE_MODEL (tm)); + g_object_unref (tm); +} + +static void +ephy_tb_editor_setup_treeview (EphyTbEditor *tbe, GtkTreeView *tv) +{ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (tv); + column = gtk_tree_view_column_new (); + renderer = gtk_cell_renderer_pixbuf_new (); + + gtk_tree_view_column_pack_start (column, renderer, FALSE); + gtk_tree_view_column_set_attributes (column, renderer, + "pixbuf", EPHY_TB_TREE_MODEL_COL_ICON, + NULL); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_set_attributes (column, renderer, + "text", EPHY_TB_TREE_MODEL_COL_NAME, + NULL); + gtk_tree_view_column_set_title (column, "Name"); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (tv), column); + + g_signal_connect (tv, "button-press-event", + G_CALLBACK (ephy_tb_editor_treeview_button_press_event_cb), tbe); + g_signal_connect (selection, "changed", + G_CALLBACK (ephy_tb_editor_treeview_selection_changed_cb), tbe); +} + +EphyToolbar * +ephy_tb_editor_get_toolbar (EphyTbEditor *tbe) +{ + EphyTbEditorPrivate *p; + + g_return_val_if_fail (EPHY_IS_TB_EDITOR (tbe), NULL); + + p = tbe->priv; + + return p->tb; +} + +EphyToolbar * +ephy_tb_editor_get_available (EphyTbEditor *tbe) +{ + EphyTbEditorPrivate *p; + + g_return_val_if_fail (EPHY_IS_TB_EDITOR (tbe), NULL); + + p = tbe->priv; + + return p->available; +} + + +static void +ephy_tb_editor_remove_used_items (EphyTbEditor *tbe) +{ + EphyTbEditorPrivate *p = tbe->priv; + const GSList *current_items; + const GSList *li; + + g_return_if_fail (EPHY_IS_TOOLBAR (p->tb)); + g_return_if_fail (EPHY_IS_TOOLBAR (p->available)); + + current_items = ephy_toolbar_get_item_list (p->tb); + for (li = current_items; li; li = li->next) + { + EphyTbItem *i = li->data; + if (ephy_tb_item_is_unique (i)) + { + EphyTbItem *j = ephy_toolbar_get_item_by_id (p->available, i->id); + if (j) + { + ephy_toolbar_remove_item (p->available, j); + } + } + } +} + +static void +ephy_tb_editor_toolbar_changed_cb (EphyToolbar *tb, EphyTbEditor *tbe) +{ + EphyTbEditorPrivate *p = tbe->priv; + + if (p->in_toolbar_changed) + { + return; + } + + if (p->tb && p->available) + { + p->in_toolbar_changed = TRUE; + ephy_tb_editor_remove_used_items (tbe); + p->in_toolbar_changed = FALSE; + } +} + +static gboolean +ephy_tb_editor_treeview_button_press_event_cb (GtkWidget *widget, + GdkEventButton *event, + EphyTbEditor *tbe) +{ + EphyTbEditorPrivate *p = tbe->priv; + + if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (widget))) + { + return FALSE; + } + + if (event->type == GDK_2BUTTON_PRESS) + { + if (widget == p->current_view) + { + ephy_tb_editor_left_clicked_cb (NULL, tbe); + } + else if (widget == p->available_view) + { + ephy_tb_editor_right_clicked_cb (NULL, tbe); + } + else + { + g_assert_not_reached (); + } + return TRUE; + } + + return FALSE; +} + +GtkButton * +ephy_tb_editor_get_revert_button (EphyTbEditor *tbe) +{ + EphyTbEditorPrivate *p; + g_return_val_if_fail (EPHY_IS_TB_EDITOR (tbe), NULL); + p = tbe->priv; + g_return_val_if_fail (GTK_IS_BUTTON (p->revert_button), NULL); + + return GTK_BUTTON (p->revert_button); + +} + diff --git a/lib/toolbar/ephy-toolbar-editor.h b/lib/toolbar/ephy-toolbar-editor.h new file mode 100644 index 000000000..97ee10e7a --- /dev/null +++ b/lib/toolbar/ephy-toolbar-editor.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_TOOLBAR_EDITOR_H +#define EPHY_TOOLBAR_EDITOR_H + +#include <glib-object.h> +#include <gtk/gtkbutton.h> + +#include "ephy-toolbar.h" + +G_BEGIN_DECLS + +/* object forward declarations */ + +typedef struct _EphyTbEditor EphyTbEditor; +typedef struct _EphyTbEditorClass EphyTbEditorClass; +typedef struct _EphyTbEditorPrivate EphyTbEditorPrivate; + +/** + * TbEditor object + */ + +#define EPHY_TYPE_TB_EDITOR (ephy_tb_editor_get_type()) +#define EPHY_TB_EDITOR(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \ + EPHY_TYPE_TB_EDITOR,\ + EphyTbEditor)) +#define EPHY_TB_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TB_EDITOR,\ + EphyTbEditorClass)) +#define EPHY_IS_TB_EDITOR(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \ + EPHY_TYPE_TB_EDITOR)) +#define EPHY_IS_TB_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TB_EDITOR)) +#define EPHY_TB_EDITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TB_EDITOR,\ + EphyTbEditorClass)) + +struct _EphyTbEditorClass +{ + GObjectClass parent_class; +}; + +/* Remember: fields are public read-only */ +struct _EphyTbEditor +{ + GObject parent_object; + + EphyTbEditorPrivate *priv; +}; + +/* this class is abstract */ + +GType ephy_tb_editor_get_type (void); +EphyTbEditor * ephy_tb_editor_new (void); +void ephy_tb_editor_set_toolbar (EphyTbEditor *tbe, EphyToolbar *tb); +EphyToolbar * ephy_tb_editor_get_toolbar (EphyTbEditor *tbe); +void ephy_tb_editor_set_available (EphyTbEditor *tbe, EphyToolbar *tb); +EphyToolbar * ephy_tb_editor_get_available (EphyTbEditor *tbe); +void ephy_tb_editor_set_parent (EphyTbEditor *tbe, GtkWidget *parent); +void ephy_tb_editor_show (EphyTbEditor *tbe); +/* the revert button is hidden initially */ +GtkButton * ephy_tb_editor_get_revert_button (EphyTbEditor *tbe); + +G_END_DECLS + +#endif + diff --git a/lib/toolbar/ephy-toolbar-item-factory.c b/lib/toolbar/ephy-toolbar-item-factory.c new file mode 100644 index 000000000..1637100ae --- /dev/null +++ b/lib/toolbar/ephy-toolbar-item-factory.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ephy-toolbar-item-factory.h" +#include <string.h> + +#include "ephy-tbi-zoom.h" +#include "ephy-tbi-separator.h" +#include "ephy-tbi-favicon.h" +#include "ephy-tbi-spinner.h" +#include "ephy-tbi-location.h" +#include "ephy-tbi-navigation-history.h" +#include "ephy-tbi-std-toolitem.h" + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +typedef EphyTbItem *(EphyTbItemConstructor) (void); + +typedef struct +{ + const char *type_name; + EphyTbItemConstructor *constructor; +} EphyTbItemTypeInfo; + +static EphyTbItemTypeInfo ephy_tb_item_known_types[] = +{ + { "std_toolitem", (EphyTbItemConstructor *) ephy_tbi_std_toolitem_new }, + { "navigation_history", (EphyTbItemConstructor *) ephy_tbi_navigation_history_new }, + { "zoom", (EphyTbItemConstructor *) ephy_tbi_zoom_new }, + { "location", (EphyTbItemConstructor *) ephy_tbi_location_new }, + { "spinner", (EphyTbItemConstructor *) ephy_tbi_spinner_new }, + { "favicon", (EphyTbItemConstructor *) ephy_tbi_favicon_new }, + { "separator", (EphyTbItemConstructor *) ephy_tbi_separator_new }, + { NULL, NULL } +}; + +EphyTbItem * +ephy_toolbar_item_create_from_string (const gchar *str) +{ + EphyTbItem *ret = NULL; + gchar *type; + gchar *props; + gchar *id; + const gchar *rest; + const gchar *lpar; + const gchar *rpar; + const gchar *eq; + int i; + + rest = str; + + eq = strchr (rest, '='); + if (eq) + { + id = g_strndup (rest, eq - rest); + rest = eq + 1; + } + else + { + id = NULL; + } + + lpar = strchr (rest, '('); + if (lpar) + { + type = g_strndup (rest, lpar - rest); + rest = lpar + 1; + + rpar = strchr (rest, ')'); + if (rpar) + { + props = g_strndup (rest, rpar - rest); + rest = rpar + 1; + } + else + { + props = g_strdup (rest); + } + } + else + { + type = g_strdup (rest); + props = NULL; + } + + DEBUG_MSG (("ephytoolbar_item_create_from_string id=%s type=%s props=%s\n", id, type, props)); + + for (i = 0; ephy_tb_item_known_types[i].type_name; ++i) + { + if (!strcmp (type, ephy_tb_item_known_types[i].type_name)) + { + ret = ephy_tb_item_known_types[i].constructor (); + if (id) + { + ephy_tb_item_set_id (ret, id); + } + if (props) + { + ephy_tb_item_parse_properties (ret, props); + } + } + } + + if (!ret) + { + g_warning ("Error creating toolbar item of type %s", type); + } + + if (id) + { + g_free (id); + } + if (type) + { + g_free (type); + } + if (props) + { + g_free (props); + } + + return ret; +} + +GSList * +ephy_toolbar_list_item_types (void) +{ + int i; + GSList *ret = NULL; + for (i = 0; ephy_tb_item_known_types[i].type_name; ++i) + { + ret = g_slist_prepend (ret, + (gchar *) ephy_tb_item_known_types[i].type_name); + } + return ret; +} + diff --git a/lib/toolbar/ephy-toolbar-item-factory.h b/lib/toolbar/ephy-toolbar-item-factory.h new file mode 100644 index 000000000..e86179399 --- /dev/null +++ b/lib/toolbar/ephy-toolbar-item-factory.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_TOOLBAR_ITEM_FACTORY_H +#define EPHY_TOOLBAR_ITEM_FACTORY_H + +#include "ephy-toolbar-item.h" + +G_BEGIN_DECLS + +EphyTbItem * ephy_toolbar_item_create_from_string (const gchar *str); +GSList * ephy_toolbar_list_item_types (void); + +G_END_DECLS + +#endif diff --git a/lib/toolbar/ephy-toolbar-item.c b/lib/toolbar/ephy-toolbar-item.c new file mode 100644 index 000000000..f9c452f02 --- /dev/null +++ b/lib/toolbar/ephy-toolbar-item.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <libgnome/gnome-i18n.h> + +#include "ephy-gobject-misc.h" +#include "ephy-marshal.h" +#include "ephy-toolbar-item.h" + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +/** + * Private data + */ +struct _EphyTbItemPrivate +{ +}; + +/** + * Private functions, only availble from this file + */ +static void ephy_tb_item_class_init (EphyTbItemClass *klass); +static void ephy_tb_item_init (EphyTbItem *tb); +static void ephy_tb_item_finalize_impl (GObject *o); + +static gpointer g_object_class; + +/** + * TbItem object + */ + +MAKE_GET_TYPE (ephy_tb_item, "EphyTbItem", EphyTbItem, ephy_tb_item_class_init, + ephy_tb_item_init, G_TYPE_OBJECT); + +static void +ephy_tb_item_class_init (EphyTbItemClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = ephy_tb_item_finalize_impl; + + g_object_class = g_type_class_peek_parent (klass); +} + +static void +ephy_tb_item_init (EphyTbItem *it) +{ + EphyTbItemPrivate *p = g_new0 (EphyTbItemPrivate, 1); + it->priv = p; + it->id = g_strdup (""); +} + +static void +ephy_tb_item_finalize_impl (GObject *o) +{ + EphyTbItem *it = EPHY_TB_ITEM (o); + EphyTbItemPrivate *p = it->priv; + + g_free (it->id); + g_free (p); + + DEBUG_MSG (("EphyTbItem finalized\n")); + + G_OBJECT_CLASS (g_object_class)->finalize (o); +} + +GtkWidget * +ephy_tb_item_get_widget (EphyTbItem *i) +{ + return EPHY_TB_ITEM_GET_CLASS (i)->get_widget (i); +} + +GdkPixbuf * +ephy_tb_item_get_icon (EphyTbItem *i) +{ + return EPHY_TB_ITEM_GET_CLASS (i)->get_icon (i); +} + +gchar * +ephy_tb_item_get_name_human (EphyTbItem *i) +{ + return EPHY_TB_ITEM_GET_CLASS (i)->get_name_human (i); +} + +gchar * +ephy_tb_item_to_string (EphyTbItem *i) +{ + return EPHY_TB_ITEM_GET_CLASS (i)->to_string (i); +} + +gboolean +ephy_tb_item_is_unique (EphyTbItem *i) +{ + return EPHY_TB_ITEM_GET_CLASS (i)->is_unique (i); +} + +EphyTbItem * +ephy_tb_item_clone (EphyTbItem *i) +{ + return EPHY_TB_ITEM_GET_CLASS (i)->clone (i); +} + +void +ephy_tb_item_add_to_bonobo_tb (EphyTbItem *i, BonoboUIComponent *ui, + const char *container_path, guint index) +{ + EPHY_TB_ITEM_GET_CLASS (i)->add_to_bonobo_tb (i, ui, container_path, index); +} + +void +ephy_tb_item_set_id (EphyTbItem *i, const gchar *id) +{ + g_return_if_fail (EPHY_IS_TB_ITEM (i)); + + g_free (i->id); + i->id = g_strdup (id); +} + +void +ephy_tb_item_parse_properties (EphyTbItem *i, const gchar *props) +{ + EPHY_TB_ITEM_GET_CLASS (i)->parse_properties (i, props); +} diff --git a/lib/toolbar/ephy-toolbar-item.h b/lib/toolbar/ephy-toolbar-item.h new file mode 100644 index 000000000..29e46697f --- /dev/null +++ b/lib/toolbar/ephy-toolbar-item.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_TOOLBAR_ITEM_H +#define EPHY_TOOLBAR_ITEM_H + +#include <glib-object.h> + +#include <bonobo/bonobo-ui-component.h> +#include <gtk/gtkwidget.h> + +G_BEGIN_DECLS + +/* object forward declarations */ + +typedef struct _EphyTbItem EphyTbItem; +typedef struct _EphyTbItemClass EphyTbItemClass; +typedef struct _EphyTbItemPrivate EphyTbItemPrivate; + +/** + * TbItem object + */ + +#define EPHY_TYPE_TB_ITEM (ephy_tb_item_get_type()) +#define EPHY_TB_ITEM(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_TB_ITEM,\ + EphyTbItem)) +#define EPHY_TB_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TB_ITEM,\ + EphyTbItemClass)) +#define EPHY_IS_TB_ITEM(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_TB_ITEM)) +#define EPHY_IS_TB_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TB_ITEM)) +#define EPHY_TB_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TB_ITEM,\ + EphyTbItemClass)) + +struct _EphyTbItemClass +{ + GObjectClass parent_class; + + /* virtual */ + GtkWidget * (*get_widget) (EphyTbItem *it); + GdkPixbuf * (*get_icon) (EphyTbItem *it); + gchar * (*get_name_human) (EphyTbItem *it); + gchar * (*to_string) (EphyTbItem *it); + gboolean (*is_unique) (EphyTbItem *it); + void (*add_to_bonobo_tb) (EphyTbItem *it, BonoboUIComponent *ui, + const char *container_path, guint index); + EphyTbItem * (*clone) (EphyTbItem *it); + void (*parse_properties) (EphyTbItem *it, const gchar *props); +}; + +/* Remember: fields are public read-only */ +struct _EphyTbItem +{ + GObject parent_object; + + gchar *id; + + EphyTbItemPrivate *priv; +}; + +/* this class is abstract */ + +GType ephy_tb_item_get_type (void); +GtkWidget * ephy_tb_item_get_widget (EphyTbItem *i); +GdkPixbuf * ephy_tb_item_get_icon (EphyTbItem *i); +gchar * ephy_tb_item_get_name_human (EphyTbItem *i); +gchar * ephy_tb_item_to_string (EphyTbItem *i); +gboolean ephy_tb_item_is_unique (EphyTbItem *i); +void ephy_tb_item_add_to_bonobo_tb (EphyTbItem *i, BonoboUIComponent *ui, + const char *container_path, guint index); +EphyTbItem * ephy_tb_item_clone (EphyTbItem *i); +void ephy_tb_item_set_id (EphyTbItem *i, const gchar *id); +void ephy_tb_item_parse_properties (EphyTbItem *i, const gchar *props); + +G_END_DECLS + +#endif diff --git a/lib/toolbar/ephy-toolbar-tree-model.c b/lib/toolbar/ephy-toolbar-tree-model.c new file mode 100644 index 000000000..91acba952 --- /dev/null +++ b/lib/toolbar/ephy-toolbar-tree-model.c @@ -0,0 +1,784 @@ +/* + * Copyright (C) 2002 Ricardo Fernándezs Pascual <ric@users.sourceforge.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gtk/gtktreednd.h> +#include <glib-object.h> +#include <string.h> + +#include "ephy-toolbar-tree-model.h" + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +#define VALID_ITER(iter, tb_tree_model) (iter!= NULL && iter->user_data != NULL \ + && tb_tree_model->stamp == iter->stamp) + +/** + * Private data + */ +struct _EphyTbTreeModelPrivate +{ + EphyToolbar *tb; + GSList *curr_items; +}; + +/** + * Private functions + */ +static void ephy_tb_tree_model_init (EphyTbTreeModel *tb_tree_model); +static void ephy_tb_tree_model_class_init (EphyTbTreeModelClass *tb_tree_model_class); +static void ephy_tb_tree_model_tb_tree_model_init (GtkTreeModelIface *iface); +static void ephy_tb_tree_model_drag_source_init (GtkTreeDragSourceIface *iface); +static void ephy_tb_tree_model_drag_dest_init (GtkTreeDragDestIface *iface); +static void ephy_tb_tree_model_finalize_impl (GObject *object); +static guint ephy_tb_tree_model_get_flags_impl (GtkTreeModel *tb_tree_model); +static gint ephy_tb_tree_model_get_n_columns_impl (GtkTreeModel *tb_tree_model); +static GType ephy_tb_tree_model_get_column_type_impl (GtkTreeModel *tb_tree_model, + gint index); +static gboolean ephy_tb_tree_model_get_iter_impl (GtkTreeModel *tb_tree_model, + GtkTreeIter *iter, + GtkTreePath *path); +static GtkTreePath * ephy_tb_tree_model_get_path_impl (GtkTreeModel *tb_tree_model, + GtkTreeIter *iter); +static void ephy_tb_tree_model_get_value_impl (GtkTreeModel *tb_tree_model, + GtkTreeIter *iter, + gint column, + GValue *value); +static gboolean ephy_tb_tree_model_iter_next_impl (GtkTreeModel *tb_tree_model, + GtkTreeIter *iter); +static gboolean ephy_tb_tree_model_iter_children_impl (GtkTreeModel *tb_tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent); +static gboolean ephy_tb_tree_model_iter_has_child_impl (GtkTreeModel *tb_tree_model, + GtkTreeIter *iter); +static gint ephy_tb_tree_model_iter_n_children_impl (GtkTreeModel *tb_tree_model, + GtkTreeIter *iter); +static gboolean ephy_tb_tree_model_iter_nth_child_impl (GtkTreeModel *tb_tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent, + gint n); +static gboolean ephy_tb_tree_model_iter_parent_impl (GtkTreeModel *tb_tree_model, + GtkTreeIter *iter, + GtkTreeIter *child); + +/* DND interfaces */ +static gboolean ephy_tb_tree_model_drag_data_delete_impl(GtkTreeDragSource *drag_source, + GtkTreePath *path); +static gboolean ephy_tb_tree_model_drag_data_get_impl (GtkTreeDragSource *drag_source, + GtkTreePath *path, + GtkSelectionData *selection_data); +static gboolean ephy_tb_tree_model_drag_data_received_impl (GtkTreeDragDest *drag_dest, + GtkTreePath *dest, + GtkSelectionData *selection_data); +static gboolean ephy_tb_tree_model_row_drop_possible_impl (GtkTreeDragDest *drag_dest, + GtkTreePath *dest_path, + GtkSelectionData *selection_data); + +/* helper functions */ +static void ephy_tb_tree_model_toolbar_changed_cb (EphyToolbar *tb, EphyTbTreeModel *tm); +static void ephy_tb_tree_model_update (EphyTbTreeModel *tm); + + +static GObjectClass *parent_class = NULL; + +GtkType +ephy_tb_tree_model_get_type (void) +{ + static GType tb_tree_model_type = 0; + + if (!tb_tree_model_type) + { + static const GTypeInfo tb_tree_model_info = + { + sizeof (EphyTbTreeModelClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_tb_tree_model_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EphyTbTreeModel), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_tb_tree_model_init + }; + + static const GInterfaceInfo tb_gtk_tree_model_info = + { + (GInterfaceInitFunc) ephy_tb_tree_model_tb_tree_model_init, + NULL, + NULL + }; + + static const GInterfaceInfo drag_source_info = + { + (GInterfaceInitFunc) ephy_tb_tree_model_drag_source_init, + NULL, + NULL + }; + + static const GInterfaceInfo drag_dest_info = + { + (GInterfaceInitFunc) ephy_tb_tree_model_drag_dest_init, + NULL, + NULL + }; + + tb_tree_model_type = g_type_register_static (G_TYPE_OBJECT, "EphyTbTreeModel", + &tb_tree_model_info, 0); + + g_type_add_interface_static (tb_tree_model_type, + GTK_TYPE_TREE_MODEL, + &tb_gtk_tree_model_info); + g_type_add_interface_static (tb_tree_model_type, + GTK_TYPE_TREE_DRAG_SOURCE, + &drag_source_info); + g_type_add_interface_static (tb_tree_model_type, + GTK_TYPE_TREE_DRAG_DEST, + &drag_dest_info); + } + + return tb_tree_model_type; +} + +static void +ephy_tb_tree_model_class_init (EphyTbTreeModelClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + object_class = (GObjectClass *) class; + + object_class->finalize = ephy_tb_tree_model_finalize_impl; +} + +static void +ephy_tb_tree_model_tb_tree_model_init (GtkTreeModelIface *iface) +{ + iface->get_flags = ephy_tb_tree_model_get_flags_impl; + iface->get_n_columns = ephy_tb_tree_model_get_n_columns_impl; + iface->get_column_type = ephy_tb_tree_model_get_column_type_impl; + iface->get_iter = ephy_tb_tree_model_get_iter_impl; + iface->get_path = ephy_tb_tree_model_get_path_impl; + iface->get_value = ephy_tb_tree_model_get_value_impl; + iface->iter_next = ephy_tb_tree_model_iter_next_impl; + iface->iter_children = ephy_tb_tree_model_iter_children_impl; + iface->iter_has_child = ephy_tb_tree_model_iter_has_child_impl; + iface->iter_n_children = ephy_tb_tree_model_iter_n_children_impl; + iface->iter_nth_child = ephy_tb_tree_model_iter_nth_child_impl; + iface->iter_parent = ephy_tb_tree_model_iter_parent_impl; +} + +static void +ephy_tb_tree_model_drag_source_init (GtkTreeDragSourceIface *iface) +{ + iface->drag_data_delete = ephy_tb_tree_model_drag_data_delete_impl; + iface->drag_data_get = ephy_tb_tree_model_drag_data_get_impl; +} + +static void +ephy_tb_tree_model_drag_dest_init (GtkTreeDragDestIface *iface) +{ + iface->drag_data_received = ephy_tb_tree_model_drag_data_received_impl; + iface->row_drop_possible = ephy_tb_tree_model_row_drop_possible_impl; +} + +static void +ephy_tb_tree_model_init (EphyTbTreeModel *tb_tree_model) +{ + EphyTbTreeModelPrivate *p = g_new0 (EphyTbTreeModelPrivate, 1); + tb_tree_model->priv = p; + + do + { + tb_tree_model->stamp = g_random_int (); + } + while (tb_tree_model->stamp == 0); +} + +EphyTbTreeModel * +ephy_tb_tree_model_new (void) +{ + EphyTbTreeModel *ret = EPHY_TB_TREE_MODEL (g_object_new (EPHY_TYPE_TB_TREE_MODEL, NULL)); + return ret; +} + + +void +ephy_tb_tree_model_set_toolbar (EphyTbTreeModel *tm, EphyToolbar *tb) +{ + EphyTbTreeModelPrivate *p; + + g_return_if_fail (EPHY_IS_TB_TREE_MODEL (tm)); + g_return_if_fail (EPHY_IS_TOOLBAR (tb)); + + p = tm->priv; + + if (p->tb) + { + g_signal_handlers_disconnect_matched (p->tb, G_SIGNAL_MATCH_DATA, 0, 0, + NULL, NULL, tm); + g_object_unref (p->tb); + } + + p->tb = g_object_ref (tb); + g_signal_connect (p->tb, "changed", G_CALLBACK (ephy_tb_tree_model_toolbar_changed_cb), tm); + + ephy_tb_tree_model_update (tm); +} + +static void +ephy_tb_tree_model_finalize_impl (GObject *object) +{ + EphyTbTreeModel *tm = EPHY_TB_TREE_MODEL (object); + EphyTbTreeModelPrivate *p = tm->priv; + + DEBUG_MSG (("Finalizing a EphyTbTreeModel\n")); + + if (p->tb) + { + g_signal_handlers_disconnect_matched (p->tb, G_SIGNAL_MATCH_DATA, 0, 0, + NULL, NULL, tm); + g_object_unref (p->tb); + } + + g_slist_foreach (p->curr_items, (GFunc) g_object_unref, NULL); + g_slist_free (p->curr_items); + g_free (p); + + (* parent_class->finalize) (object); +} + +/* fulfill the GtkTreeModel requirements */ + +static guint +ephy_tb_tree_model_get_flags_impl (GtkTreeModel *tb_tree_model) +{ + return 0; +} + +static gint +ephy_tb_tree_model_get_n_columns_impl (GtkTreeModel *tb_tree_model) +{ + return EPHY_TB_TREE_MODEL_NUM_COLUMS; +} + +static GType +ephy_tb_tree_model_get_column_type_impl (GtkTreeModel *tb_tree_model, + gint index) +{ + g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tb_tree_model), G_TYPE_INVALID); + g_return_val_if_fail ((index < EPHY_TB_TREE_MODEL_NUM_COLUMS) && (index >= 0), G_TYPE_INVALID); + + switch (index) + { + case EPHY_TB_TREE_MODEL_COL_ICON: + return GDK_TYPE_PIXBUF; + break; + case EPHY_TB_TREE_MODEL_COL_NAME: + return G_TYPE_STRING; + break; + default: + g_assert_not_reached (); + return G_TYPE_INVALID; + break; + } +} + +static gboolean +ephy_tb_tree_model_get_iter_impl (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreePath *path) +{ + EphyTbTreeModel *tb_tree_model = (EphyTbTreeModel *) tree_model; + EphyTbTreeModelPrivate *p; + GSList *li; + gint i; + + g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tb_tree_model), FALSE); + g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE); + + p = tb_tree_model->priv; + i = gtk_tree_path_get_indices (path)[0]; + li = g_slist_nth (p->curr_items, i); + + if (!li) + { + return FALSE; + } + + iter->stamp = tb_tree_model->stamp; + iter->user_data = li; + + return TRUE; +} + +static GtkTreePath * +ephy_tb_tree_model_get_path_impl (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + EphyTbTreeModel *tb_tree_model = (EphyTbTreeModel *) tree_model; + EphyTbTreeModelPrivate *p; + gint i; + + g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tb_tree_model), NULL); + g_return_val_if_fail (iter != NULL, NULL); + g_return_val_if_fail (iter->user_data != NULL, NULL); + g_return_val_if_fail (iter->stamp == tb_tree_model->stamp, NULL); + + p = tb_tree_model->priv; + + i = g_slist_position (p->curr_items, iter->user_data); + if (i < 0) + { + return NULL; + } + else + { + GtkTreePath *retval; + retval = gtk_tree_path_new (); + gtk_tree_path_append_index (retval, i); + return retval; + } +} + + +static void +ephy_tb_tree_model_get_value_impl (GtkTreeModel *tb_tree_model, + GtkTreeIter *iter, + gint column, + GValue *value) +{ + EphyTbItem *it; + GdkPixbuf *pb; + gchar *s; + + g_return_if_fail (EPHY_IS_TB_TREE_MODEL (tb_tree_model)); + g_return_if_fail (iter != NULL); + g_return_if_fail (iter->stamp == EPHY_TB_TREE_MODEL (tb_tree_model)->stamp); + g_return_if_fail (EPHY_IS_TB_ITEM (((GSList *) iter->user_data)->data)); + g_return_if_fail (column < EPHY_TB_TREE_MODEL_NUM_COLUMS); + + it = ((GSList *) iter->user_data)->data; + + switch (column) { + case EPHY_TB_TREE_MODEL_COL_ICON: + g_value_init (value, GDK_TYPE_PIXBUF); + pb = ephy_tb_item_get_icon (it); + g_value_set_object (value, pb); + break; + case EPHY_TB_TREE_MODEL_COL_NAME: + g_value_init (value, G_TYPE_STRING); + s = ephy_tb_item_get_name_human (it); + g_value_set_string_take_ownership (value, s); + break; + default: + g_assert_not_reached (); + break; + } +} + +static gboolean +ephy_tb_tree_model_iter_next_impl (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tree_model), FALSE); + g_return_val_if_fail (EPHY_TB_TREE_MODEL (tree_model)->stamp == iter->stamp, FALSE); + + iter->user_data = ((GSList *) (iter->user_data))->next; + return (iter->user_data != NULL); +} + +static gboolean +ephy_tb_tree_model_iter_children_impl (GtkTreeModel *tb_tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent) +{ + if (parent) + { + /* this is a list, nodes have no children */ + return FALSE; + } + else + { + /* but if parent == NULL we return the list itself as children of the + * "root" + */ + EphyTbTreeModel *tm = EPHY_TB_TREE_MODEL (tb_tree_model); + EphyTbTreeModelPrivate *p = tm->priv; + + iter->stamp = tm->stamp; + iter->user_data = p->curr_items; + return (p->curr_items != NULL); + } +} + +static gboolean +ephy_tb_tree_model_iter_has_child_impl (GtkTreeModel *tb_tree_model, + GtkTreeIter *iter) +{ + return FALSE; +} + +static gint +ephy_tb_tree_model_iter_n_children_impl (GtkTreeModel *tb_tree_model, + GtkTreeIter *iter) +{ + EphyTbTreeModel *tm = (EphyTbTreeModel *) tb_tree_model; + EphyTbTreeModelPrivate *p; + g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tm), -1); + + p = tm->priv; + + if (iter == NULL) + { + return g_slist_length (p->curr_items); + } + + g_return_val_if_fail (tm->stamp == iter->stamp, -1); + return 0; +} + +static gboolean +ephy_tb_tree_model_iter_nth_child_impl (GtkTreeModel *tb_tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent, + gint n) +{ + EphyTbTreeModel *tm = (EphyTbTreeModel *) tb_tree_model; + EphyTbTreeModelPrivate *p; + g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tm), FALSE); + + p = tm->priv; + + if (parent) + { + return FALSE; + } + else + { + GSList *li = g_slist_nth (p->curr_items, n); + + if (li) + { + iter->stamp = tm->stamp; + iter->user_data = li; + return TRUE; + } + else + { + return FALSE; + } + } +} + +static gboolean +ephy_tb_tree_model_iter_parent_impl (GtkTreeModel *tb_tree_model, + GtkTreeIter *iter, + GtkTreeIter *child) +{ + return FALSE; +} + + + +/* DND */ + + +static gboolean +ephy_tb_tree_model_drag_data_delete_impl (GtkTreeDragSource *drag_source, + GtkTreePath *path) +{ + GtkTreeIter iter; + EphyTbTreeModel *tm; + + g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (drag_source), FALSE); + + tm = EPHY_TB_TREE_MODEL (drag_source); + + DEBUG_MSG (("in ephy_tb_tree_model_drag_data_delete_impl\n")); + + if (ephy_tb_tree_model_get_iter_impl (GTK_TREE_MODEL (tm), &iter, path)) + { + EphyTbTreeModelPrivate *p = tm->priv; + EphyTbItem *it = ephy_tb_tree_model_item_from_iter (tm, &iter); + EphyTbItem *delete_hack; + if ((delete_hack = g_object_get_data (G_OBJECT (tm), + "gul-toolbar-tree-model-dnd-delete-hack")) != NULL) + { + g_return_val_if_fail (EPHY_IS_TB_ITEM (delete_hack), FALSE); + g_object_ref (delete_hack); + + g_object_set_data (G_OBJECT (tm), + "gul-toolbar-tree-model-dnd-delete-hack", NULL); + + if (!strcmp (delete_hack->id, it->id)) + { + g_object_unref (delete_hack); + return FALSE; + } + g_object_unref (delete_hack); + } + + ephy_toolbar_remove_item (p->tb, it); + return TRUE; + } + else + { + return FALSE; + } +} + +static gboolean +ephy_tb_tree_model_drag_data_get_impl (GtkTreeDragSource *drag_source, + GtkTreePath *path, + GtkSelectionData *selection_data) +{ + g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (drag_source), FALSE); + + /* Note that we don't need to handle the GTK_TB_TREE_MODEL_ROW + * target, because the default handler does it for us, but + * we do anyway for the convenience of someone maybe overriding the + * default handler. + */ + + if (gtk_tree_set_row_drag_data (selection_data, + GTK_TREE_MODEL (drag_source), + path)) + { + return TRUE; + } + else + { + /* to string ? */ + } + + return FALSE; +} + + +static gboolean +ephy_tb_tree_model_drag_data_received_impl (GtkTreeDragDest *drag_dest, + GtkTreePath *dest, + GtkSelectionData *selection_data) +{ + EphyTbTreeModel *tbm; + GtkTreeModel *src_model = NULL; + GtkTreePath *src_path = NULL; + + g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (drag_dest), FALSE); + g_return_val_if_fail (gtk_tree_path_get_depth (dest) == 1, FALSE); + + tbm = EPHY_TB_TREE_MODEL (drag_dest); + + DEBUG_MSG (("in ephy_tb_tree_model_drag_data_received_impl\n")); + + if (gtk_tree_get_row_drag_data (selection_data, + &src_model, + &src_path) + && EPHY_IS_TB_TREE_MODEL (src_model)) + { + /* copy the item */ + + GtkTreeIter src_iter; + EphyTbItem *it; + int idx = gtk_tree_path_get_indices (dest)[0]; + + if (!gtk_tree_model_get_iter (src_model, + &src_iter, + src_path)) + { + gtk_tree_path_free (src_path); + return FALSE; + } + gtk_tree_path_free (src_path); + + if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (drag_dest), + "gtk-tree-model-drop-append"))) + { + ++idx; + } + + it = ephy_tb_item_clone (EPHY_TB_ITEM (((GSList *)src_iter.user_data)->data)); + ephy_toolbar_add_item (tbm->priv->tb, it, idx); + + /* hack */ + if (src_model == GTK_TREE_MODEL (drag_dest) + && ephy_toolbar_get_check_unique (EPHY_TB_TREE_MODEL (src_model)->priv->tb) + && ephy_tb_item_is_unique (it)) + { + g_object_set_data_full (G_OBJECT (src_model), + "gul-toolbar-tree-model-dnd-delete-hack", it, + g_object_unref); + } + else + { + g_object_unref (it); + } + + g_object_set_data (G_OBJECT (drag_dest), "gtk-tree-model-drop-append", NULL); + return TRUE; + } + + return FALSE; +} + +static gboolean +ephy_tb_tree_model_row_drop_possible_impl (GtkTreeDragDest *drag_dest, + GtkTreePath *dest_path, + GtkSelectionData *selection_data) +{ + GtkTreeModel *src_model = NULL; + GtkTreePath *src_path = NULL; + gboolean retval = FALSE; + EphyTbTreeModel *tm; + EphyTbTreeModelPrivate *p; + + g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (drag_dest), FALSE); + tm = EPHY_TB_TREE_MODEL (drag_dest); + p = tm->priv; + + if (gtk_tree_path_get_depth (dest_path) != 1) + { + return FALSE; + } + if (!gtk_tree_get_row_drag_data (selection_data, + &src_model, + &src_path)) + { + return FALSE; + } + + /* can drop before any existing node, or before one past any existing. */ + + retval = (gtk_tree_path_get_indices (dest_path)[0] <= (gint) g_slist_length (p->curr_items)); + + gtk_tree_path_free (src_path); + + return retval; +} + + +EphyTbItem * +ephy_tb_tree_model_item_from_iter (EphyTbTreeModel *tm, GtkTreeIter *iter) +{ + return iter ? EPHY_TB_ITEM (((GSList *) iter->user_data)->data) : NULL; +} + +static void +ephy_tb_tree_model_toolbar_changed_cb (EphyToolbar *tb, EphyTbTreeModel *tm) +{ + ephy_tb_tree_model_update (tm); +} + +static void +ephy_tb_tree_model_update (EphyTbTreeModel *tm) +{ + EphyTbTreeModelPrivate *p; + GSList *new_items; + GSList *old_items; + GSList *li; + GSList *lj; + int i; + + g_return_if_fail (EPHY_IS_TB_TREE_MODEL (tm)); + p = tm->priv; + g_return_if_fail (EPHY_IS_TOOLBAR (p->tb)); + + old_items = p->curr_items; + new_items = g_slist_copy ((GSList *) ephy_toolbar_get_item_list (p->tb)); + g_slist_foreach (new_items, (GFunc) g_object_ref, NULL); + p->curr_items = new_items; + + li = new_items; + lj = old_items; + i = 0; + + while (li && lj) + { + if (li->data == lj->data) + { + li = li->next; + lj = lj->next; + ++i; + } + else if (lj->next && lj->next->data == li->data) + { + GtkTreePath *p = gtk_tree_path_new (); + gtk_tree_path_append_index (p, i); + gtk_tree_model_row_deleted (GTK_TREE_MODEL (tm), p); + gtk_tree_path_free (p); + lj = lj->next; + } + else if (li->next && li->next->data == lj->data) + { + GtkTreePath *p = gtk_tree_path_new (); + GtkTreeIter iter; + iter.stamp = tm->stamp; + iter.user_data = li; + gtk_tree_path_append_index (p, i); + gtk_tree_model_row_inserted (GTK_TREE_MODEL (tm), p, &iter); + gtk_tree_path_free (p); + li = li->next; + ++i; + } + else + { + GtkTreePath *p = gtk_tree_path_new (); + GtkTreeIter iter; + iter.stamp = tm->stamp; + iter.user_data = li; + gtk_tree_path_append_index (p, i); + gtk_tree_model_row_deleted (GTK_TREE_MODEL (tm), p); + gtk_tree_model_row_inserted (GTK_TREE_MODEL (tm), p, &iter); + gtk_tree_path_free (p); + lj = lj->next; + li = li->next; + ++i; + } + } + + while (li) + { + GtkTreePath *p = gtk_tree_path_new (); + GtkTreeIter iter; + iter.stamp = tm->stamp; + iter.user_data = li; + gtk_tree_path_append_index (p, i); + gtk_tree_model_row_inserted (GTK_TREE_MODEL (tm), p, &iter); + gtk_tree_path_free (p); + li = li->next; + ++i; + } + + while (lj) + { + GtkTreePath *p = gtk_tree_path_new (); + gtk_tree_path_append_index (p, i); + gtk_tree_model_row_deleted (GTK_TREE_MODEL (tm), p); + gtk_tree_path_free (p); + lj = lj->next; + } + + g_slist_foreach (old_items, (GFunc) g_object_unref, NULL); + g_slist_free (old_items); +} + diff --git a/lib/toolbar/ephy-toolbar-tree-model.h b/lib/toolbar/ephy-toolbar-tree-model.h new file mode 100644 index 000000000..893e6ba9a --- /dev/null +++ b/lib/toolbar/ephy-toolbar-tree-model.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2002 Ricardo Fernándezs Pascual <ric@users.sourceforge.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_TOOLBAR_TREE_MODEL_H +#define EPHY_TOOLBAR_TREE_MODEL_H + +#include <gtk/gtktreemodel.h> +#include "ephy-toolbar.h" + +G_BEGIN_DECLS + +/* object forward declarations */ + +typedef struct _EphyTbTreeModel EphyTbTreeModel; +typedef struct _EphyTbTreeModelClass EphyTbTreeModelClass; +typedef struct _EphyTbTreeModelPrivate EphyTbTreeModelPrivate; + +typedef enum { + EPHY_TB_TREE_MODEL_COL_ICON, + EPHY_TB_TREE_MODEL_COL_NAME, + EPHY_TB_TREE_MODEL_NUM_COLUMS +} EphyTbTreeModelColumn; + +/** + * Tb tree model object + */ + +#define EPHY_TYPE_TB_TREE_MODEL (ephy_tb_tree_model_get_type()) +#define EPHY_TB_TREE_MODEL(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_TB_TREE_MODEL,\ + EphyTbTreeModel)) +#define EPHY_TB_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TB_TREE_MODEL,\ + EphyTbTreeModelClass)) +#define EPHY_IS_TB_TREE_MODEL(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_TB_TREE_MODEL)) +#define EPHY_IS_TB_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TB_TREE_MODEL)) +#define EPHY_TB_TREE_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TB_TREE_MODEL,\ + EphyTbTreeModelClass)) + +struct _EphyTbTreeModel +{ + GObject parent; + + EphyTbTreeModelPrivate *priv; + gint stamp; +}; + +struct _EphyTbTreeModelClass +{ + GObjectClass parent_class; +}; + + +GtkType ephy_tb_tree_model_get_type (void); +EphyTbTreeModel * ephy_tb_tree_model_new (void); +void ephy_tb_tree_model_set_toolbar (EphyTbTreeModel *tm, EphyToolbar *tb); +EphyTbItem * ephy_tb_tree_model_item_from_iter (EphyTbTreeModel *tm, GtkTreeIter *iter); + +G_END_DECLS + +#endif diff --git a/lib/toolbar/ephy-toolbar.c b/lib/toolbar/ephy-toolbar.c new file mode 100644 index 000000000..53598cc6c --- /dev/null +++ b/lib/toolbar/ephy-toolbar.c @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <libgnome/gnome-i18n.h> +#include <string.h> +#include "ephy-gobject-misc.h" +#include "ephy-marshal.h" +#include "ephy-toolbar.h" +#include "ephy-toolbar-item-factory.h" +#include "eel-gconf-extensions.h" + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +/** + * Private data + */ +struct _EphyToolbarPrivate +{ + GSList *items; + guint gconf_notification_id; + + gboolean check_unique; + gboolean fixed_order; + GSList *order; /* list of ids */ +}; + +/** + * Private functions, only availble from this file + */ +static void ephy_toolbar_class_init (EphyToolbarClass *klass); +static void ephy_toolbar_init (EphyToolbar *tb); +static void ephy_toolbar_finalize_impl (GObject *o); +static void ephy_toolbar_listen_to_gconf_cb (GConfClient* client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data); +static void ephy_toolbar_update_order (EphyToolbar *tb); + + +static gpointer g_object_class; + +/* signals enums and ids */ +enum EphyToolbarSignalsEnum { + EPHY_TOOLBAR_CHANGED, + EPHY_TOOLBAR_LAST_SIGNAL +}; +static gint EphyToolbarSignals[EPHY_TOOLBAR_LAST_SIGNAL]; + +/** + * Toolbar object + */ + +MAKE_GET_TYPE (ephy_toolbar, "EphyToolbar", EphyToolbar, ephy_toolbar_class_init, + ephy_toolbar_init, G_TYPE_OBJECT); + +static void +ephy_toolbar_class_init (EphyToolbarClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = ephy_toolbar_finalize_impl; + + EphyToolbarSignals[EPHY_TOOLBAR_CHANGED] = g_signal_new ( + "changed", G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP, + G_STRUCT_OFFSET (EphyToolbarClass, changed), + NULL, NULL, + ephy_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + g_object_class = g_type_class_peek_parent (klass); +} + +static void +ephy_toolbar_init (EphyToolbar *tb) +{ + EphyToolbarPrivate *p = g_new0 (EphyToolbarPrivate, 1); + tb->priv = p; + + p->check_unique = TRUE; +} + +static void +ephy_toolbar_finalize_impl (GObject *o) +{ + EphyToolbar *tb = EPHY_TOOLBAR (o); + EphyToolbarPrivate *p = tb->priv; + + g_slist_foreach (p->items, (GFunc) g_object_unref, NULL); + g_slist_free (p->items); + + if (p->gconf_notification_id) + { + eel_gconf_notification_remove (p->gconf_notification_id); + } + + g_slist_foreach (p->order, (GFunc) g_free, NULL); + g_slist_free (p->order); + + g_free (p); + + DEBUG_MSG (("EphyToolbar finalized\n")); + + G_OBJECT_CLASS (g_object_class)->finalize (o); +} + + +EphyToolbar * +ephy_toolbar_new (void) +{ + EphyToolbar *ret = g_object_new (EPHY_TYPE_TOOLBAR, NULL); + return ret; +} + +gboolean +ephy_toolbar_parse (EphyToolbar *tb, const gchar *cfg) +{ + EphyToolbarPrivate *p = tb->priv; + GSList *list = NULL; + gchar **items; + int i; + + g_return_val_if_fail (EPHY_IS_TOOLBAR (tb), FALSE); + g_return_val_if_fail (cfg != NULL, FALSE); + + items = g_strsplit (cfg, ";", 9999); + if (!items) return FALSE; + + for (i = 0; items[i]; ++i) + { + if (items[i][0]) + { + EphyTbItem *it = ephy_toolbar_item_create_from_string (items[i]); + + if (!it) + { + /* FIXME: this leaks everything... */ + return FALSE; + } + + list = g_slist_prepend (list, it); + } + } + + g_strfreev (items); + + g_slist_foreach (p->items, (GFunc) g_object_unref, NULL); + g_slist_free (p->items); + p->items = g_slist_reverse (list); + + if (p->fixed_order) + { + ephy_toolbar_update_order (tb); + } + + g_signal_emit (tb, EphyToolbarSignals[EPHY_TOOLBAR_CHANGED], 0); + + return TRUE; +} + +gchar * +ephy_toolbar_to_string (EphyToolbar *tb) +{ + EphyToolbarPrivate *p = tb->priv; + gchar *ret; + GString *str = g_string_new (""); + GSList *li; + + for (li = p->items; li; li = li->next) + { + EphyTbItem *it = li->data; + gchar *s = ephy_tb_item_to_string (it); + g_string_append (str, s); + if (li->next) + { + g_string_append (str, ";"); + } + g_free (s); + } + + ret = str->str; + g_string_free (str, FALSE); + return ret; +} + +static void +ephy_toolbar_listen_to_gconf_cb (GConfClient* client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) +{ + EphyToolbar *tb = user_data; + GConfValue *value; + const char *str; + + g_return_if_fail (EPHY_IS_TOOLBAR (tb)); + + value = gconf_entry_get_value (entry); + str = gconf_value_get_string (value); + + DEBUG_MSG (("in ephy_toolbar_listen_to_gconf_cb\n")); + + ephy_toolbar_parse (tb, str); +} + +/** + * Listen to changes in the toolbar configuration. Returns TRUE if the + * current configuration is valid. + */ +gboolean +ephy_toolbar_listen_to_gconf (EphyToolbar *tb, const gchar *gconf_key) +{ + EphyToolbarPrivate *p = tb->priv; + gchar *s; + gboolean ret = FALSE; + + if (p->gconf_notification_id) + { + eel_gconf_notification_remove (p->gconf_notification_id); + } + + s = eel_gconf_get_string (gconf_key); + if (s) + { + ret = ephy_toolbar_parse (tb, s); + g_free (s); + } + + p->gconf_notification_id = eel_gconf_notification_add (gconf_key, + ephy_toolbar_listen_to_gconf_cb, + tb); + + DEBUG_MSG (("listening to %s, %d (FIXME: does not seem to work)\n", + gconf_key, p->gconf_notification_id)); + + return ret; +} + +EphyTbItem * +ephy_toolbar_get_item_by_id (EphyToolbar *tb, const gchar *id) +{ + EphyToolbarPrivate *p = tb->priv; + GSList *li; + + for (li = p->items; li; li = li->next) + { + EphyTbItem *i = li->data; + if (i->id && !strcmp (i->id, id)) + { + return i; + } + } + return NULL; +} + +const GSList * +ephy_toolbar_get_item_list (EphyToolbar *tb) +{ + EphyToolbarPrivate *p = tb->priv; + return p->items; +} + +void +ephy_toolbar_add_item (EphyToolbar *tb, EphyTbItem *it, gint index) +{ + EphyToolbarPrivate *p = tb->priv; + EphyTbItem *old_it; + + g_return_if_fail (g_slist_find (p->items, it) == NULL); + + if (p->check_unique && ephy_tb_item_is_unique (it) + && (old_it = ephy_toolbar_get_item_by_id (tb, it->id)) != NULL) + { + GSList *old_it_link; + if (p->fixed_order) + { + return; + } + old_it_link = g_slist_find (p->items, old_it); + p->items = g_slist_insert (p->items, old_it, index); + p->items = g_slist_delete_link (p->items, old_it_link); + + } + else + { + if (p->fixed_order) + { + GSList *li; + if (ephy_toolbar_get_item_by_id (tb, it->id) != NULL) + { + return; + } + index = 0; + for (li = p->order; li && strcmp (li->data, it->id); li = li->next) + { + if (ephy_toolbar_get_item_by_id (tb, li->data) != NULL) + { + ++index; + } + } + } + + p->items = g_slist_insert (p->items, it, index); + g_object_ref (it); + } + g_signal_emit (tb, EphyToolbarSignals[EPHY_TOOLBAR_CHANGED], 0); +} + +void +ephy_toolbar_remove_item (EphyToolbar *tb, EphyTbItem *it) +{ + EphyToolbarPrivate *p = tb->priv; + + g_return_if_fail (g_slist_find (p->items, it) != NULL); + + p->items = g_slist_remove (p->items, it); + + g_signal_emit (tb, EphyToolbarSignals[EPHY_TOOLBAR_CHANGED], 0); + + g_object_unref (it); +} + +void +ephy_toolbar_set_fixed_order (EphyToolbar *tb, gboolean value) +{ + EphyToolbarPrivate *p = tb->priv; + p->fixed_order = value; + + if (value) + { + ephy_toolbar_update_order (tb); + } +} + +void +ephy_toolbar_set_check_unique (EphyToolbar *tb, gboolean value) +{ + EphyToolbarPrivate *p = tb->priv; + p->check_unique = value; + + /* maybe it should remove duplicated items now, if any */ +} + +gboolean +ephy_toolbar_get_check_unique (EphyToolbar *tb) +{ + EphyToolbarPrivate *p = tb->priv; + return p->check_unique; +} + +static void +ephy_toolbar_update_order (EphyToolbar *tb) +{ + EphyToolbarPrivate *p = tb->priv; + GSList *li; + GSList *lj; + GSList *new_order = NULL; + + lj = p->order; + for (li = p->items; li; li = li->next) + { + EphyTbItem *i = li->data; + const gchar *id = i->id; + + if (g_slist_find_custom (lj, id, (GCompareFunc) strcmp)) + { + for ( ; lj && strcmp (lj->data, id); lj = lj->next) + { + if (ephy_toolbar_get_item_by_id (tb, lj->data) == NULL) + { + new_order = g_slist_prepend (new_order, g_strdup (lj->data)); + } + } + } + + new_order = g_slist_prepend (new_order, g_strdup (id)); + + } + + for ( ; lj; lj = lj->next) + { + if (ephy_toolbar_get_item_by_id (tb, lj->data) == NULL) + { + new_order = g_slist_prepend (new_order, g_strdup (lj->data)); + } + } + + g_slist_foreach (p->order, (GFunc) g_free, NULL); + g_slist_free (p->order); + + p->order = g_slist_reverse (new_order); + +#ifdef DEBUG_ORDER + DEBUG_MSG (("New order:\n")); + for (lj = p->order; lj; lj = lj->next) + { + DEBUG_MSG (("%s\n", (char *) lj->data)); + } +#endif +} + diff --git a/lib/toolbar/ephy-toolbar.h b/lib/toolbar/ephy-toolbar.h new file mode 100644 index 000000000..3c70a4783 --- /dev/null +++ b/lib/toolbar/ephy-toolbar.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_TOOLBAR_H +#define EPHY_TOOLBAR_H + +#include <glib-object.h> + +#include "ephy-toolbar-item.h" + +G_BEGIN_DECLS + +/* object forward declarations */ + +typedef struct _EphyToolbar EphyToolbar; +typedef struct _EphyToolbarClass EphyToolbarClass; +typedef struct _EphyToolbarPrivate EphyToolbarPrivate; + +/** + * Toolbar object + */ + +#define EPHY_TYPE_TOOLBAR (ephy_toolbar_get_type()) +#define EPHY_TOOLBAR(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_TOOLBAR,\ + EphyToolbar)) +#define EPHY_TOOLBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TOOLBAR,\ + EphyToolbarClass)) +#define EPHY_IS_TOOLBAR(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_TOOLBAR)) +#define EPHY_IS_TOOLBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TOOLBAR)) +#define EPHY_TOOLBAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TOOLBAR,\ + EphyToolbarClass)) + +struct _EphyToolbarClass +{ + GObjectClass parent_class; + + /* signals */ + void (*changed) (EphyToolbar *tb); + +}; + +/* Remember: fields are public read-only */ +struct _EphyToolbar +{ + GObject parent_object; + + EphyToolbarPrivate *priv; +}; + +GType ephy_toolbar_get_type (void); +EphyToolbar * ephy_toolbar_new (void); +gboolean ephy_toolbar_parse (EphyToolbar *tb, const gchar *cfg); +gchar * ephy_toolbar_to_string (EphyToolbar *tb); +gboolean ephy_toolbar_listen_to_gconf (EphyToolbar *tb, const gchar *gconf_key); +EphyTbItem * ephy_toolbar_get_item_by_id (EphyToolbar *tb, const gchar *id); +const GSList * ephy_toolbar_get_item_list (EphyToolbar *tb); +void ephy_toolbar_add_item (EphyToolbar *tb, EphyTbItem *it, gint index); +void ephy_toolbar_remove_item (EphyToolbar *tb, EphyTbItem *it); +void ephy_toolbar_set_fixed_order (EphyToolbar *tb, gboolean value); +void ephy_toolbar_set_check_unique (EphyToolbar *tb, gboolean value); +gboolean ephy_toolbar_get_check_unique (EphyToolbar *tb); + +G_END_DECLS + +#endif diff --git a/lib/widgets/.cvsignore b/lib/widgets/.cvsignore new file mode 100644 index 000000000..20e4cb0c8 --- /dev/null +++ b/lib/widgets/.cvsignore @@ -0,0 +1,6 @@ +Makefile +Makefile.in +*.lo +.deps +.libs +*.la diff --git a/lib/widgets/Makefile.am b/lib/widgets/Makefile.am new file mode 100644 index 000000000..a8b7a69b8 --- /dev/null +++ b/lib/widgets/Makefile.am @@ -0,0 +1,30 @@ +INCLUDES = \ + -I$(top_srcdir)/lib \ + $(WARN_CFLAGS) \ + $(EPIPHANY_DEPENDENCY_CFLAGS) \ + -DSHARE_DIR=\"$(pkgdatadir)\" \ + -DG_DISABLE_DEPRECATED \ + -DGDK_DISABLE_DEPRECATED \ + -DGTK_DISABLE_DEPRECATED \ + -DGDK_PIXBUF_DISABLE_DEPRECATED \ + -DGNOME_DISABLE_DEPRECATED + +noinst_LTLIBRARIES = libephywidgets.la + +libephywidgets_la_SOURCES = \ + ephy-ellipsizing-label.c \ + ephy-ellipsizing-label.h \ + ephy-notebook.c \ + ephy-notebook.h \ + ephy-location-entry.c \ + ephy-location-entry.h \ + ephy-autocompletion-window.c \ + ephy-autocompletion-window.h \ + ephy-spinner.c \ + ephy-spinner.h \ + eggtreemultidnd.c \ + eggtreemultidnd.h \ + ephy-tree-model-sort.c \ + ephy-tree-model-sort.h \ + eggtreemodelfilter.c \ + eggtreemodelfilter.h diff --git a/lib/widgets/eggtreemodelfilter.c b/lib/widgets/eggtreemodelfilter.c new file mode 100644 index 000000000..b3b31a46d --- /dev/null +++ b/lib/widgets/eggtreemodelfilter.c @@ -0,0 +1,2560 @@ +/* eggtreemodelfilter.c + * Copyright (C) 2000,2001 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com> + * Copyright (C) 2001,2002 Kristian Rietveld <kris@gtk.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "eggtreemodelfilter.h" +#include <gtk/gtksignal.h> +#include <string.h> + +/****** NOTE NOTE NOTE WARNING WARNING ****** + * + * This is *unstable* code. Don't use it in any project. This warning + * will be removed when this treemodel works. + */ + +/*#define VERBOSE 1*/ + +/* removed this when you add support for i18n */ +#define _ + +/* ITER FORMAT: + * + * iter->stamp = filter->stamp + * iter->user_data = FilterLevel + * iter->user_data2 = FilterElt + */ + +/* all paths, iters, etc prefixed with c_ are paths, iters, etc relative to the + * child model. + */ + +typedef struct _FilterElt FilterElt; +typedef struct _FilterLevel FilterLevel; + +struct _FilterElt +{ + GtkTreeIter iter; + FilterLevel *children; + gint offset; + gint ref_count; + gint zero_ref_count; + gboolean visible; +}; + +struct _FilterLevel +{ + GArray *array; + gint ref_count; + + FilterElt *parent_elt; + FilterLevel *parent_level; +}; + +/* properties */ +enum +{ + PROP_0, + PROP_CHILD_MODEL, + PROP_VIRTUAL_ROOT +}; + +#define EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS(filter) \ + (((EggTreeModelFilter *)filter)->child_flags & GTK_TREE_MODEL_ITERS_PERSIST) + +#define FILTER_ELT(filter_elt) ((FilterElt *)filter_elt) +#define FILTER_LEVEL(filter_level) ((FilterLevel *)filter_level) + +/* general code (object/interface init, properties, etc) */ +static void egg_tree_model_filter_init (EggTreeModelFilter *filter); +static void egg_tree_model_filter_class_init (EggTreeModelFilterClass *filter_class); +static void egg_tree_model_filter_tree_model_init (GtkTreeModelIface *iface); +static void egg_tree_model_filter_finalize (GObject *object); +static void egg_tree_model_filter_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void egg_tree_model_filter_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +/* signal handlers */ +static void egg_tree_model_filter_row_changed (GtkTreeModel *c_model, + GtkTreePath *c_path, + GtkTreeIter *c_iter, + gpointer data); +static void egg_tree_model_filter_row_inserted (GtkTreeModel *c_model, + GtkTreePath *c_path, + GtkTreeIter *c_iter, + gpointer data); +static void egg_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model, + GtkTreePath *c_path, + GtkTreeIter *c_iter, + gpointer data); +static void egg_tree_model_filter_row_deleted (GtkTreeModel *c_model, + GtkTreePath *c_path, + gpointer data); +static void egg_tree_model_filter_rows_reordered (GtkTreeModel *c_model, + GtkTreePath *c_path, + GtkTreeIter *c_iter, + gint *new_order, + gpointer data); + +/* GtkTreeModel interface */ +static guint egg_tree_model_filter_get_flags (GtkTreeModel *model); +static gint egg_tree_model_filter_get_n_columns (GtkTreeModel *model); +static GType egg_tree_model_filter_get_column_type (GtkTreeModel *model, + gint index); +static gboolean egg_tree_model_filter_get_iter (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreePath *path); +static GtkTreePath *egg_tree_model_filter_get_path (GtkTreeModel *model, + GtkTreeIter *iter); +static void egg_tree_model_filter_get_value (GtkTreeModel *model, + GtkTreeIter *iter, + gint column, + GValue *value); +static gboolean egg_tree_model_filter_iter_next (GtkTreeModel *model, + GtkTreeIter *iter); +static gboolean egg_tree_model_filter_iter_children (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *parent); +static gboolean egg_tree_model_filter_iter_has_child (GtkTreeModel *model, + GtkTreeIter *iter); +static gint egg_tree_model_filter_iter_n_children (GtkTreeModel *model, + GtkTreeIter *iter); +static gboolean egg_tree_model_filter_iter_nth_child (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *parent, + gint n); +static gboolean egg_tree_model_filter_iter_parent (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *child); +static void egg_tree_model_filter_ref_node (GtkTreeModel *model, + GtkTreeIter *iter); +static void egg_tree_model_filter_unref_node (GtkTreeModel *model, + GtkTreeIter *iter); + + + +/* private functions */ +static void egg_tree_model_filter_build_level (EggTreeModelFilter *filter, + FilterLevel *parent_level, + FilterElt *parent_elt); +static void egg_tree_model_filter_free_level (EggTreeModelFilter *filter, + FilterLevel *filter_level); + +static GtkTreePath *egg_tree_model_filter_elt_get_path (FilterLevel *level, + FilterElt *elt, + GtkTreePath *root); + +static GtkTreePath *egg_tree_model_filter_add_root (GtkTreePath *src, + GtkTreePath *root); +static GtkTreePath *egg_tree_model_filter_remove_root (GtkTreePath *src, + GtkTreePath *root); + +static void egg_tree_model_filter_increment_stamp (EggTreeModelFilter *filter); + +static gboolean egg_tree_model_filter_visible (EggTreeModelFilter *filter, + GtkTreeIter *child_iter); +static void egg_tree_model_filter_clear_cache_helper (EggTreeModelFilter *filter, + FilterLevel *level); + +static void egg_tree_model_filter_real_unref_node (GtkTreeModel *model, + GtkTreeIter *iter, + gboolean propagate_unref); + +static void egg_tree_model_filter_set_model (EggTreeModelFilter *filter, + GtkTreeModel *child_model); +static void egg_tree_model_filter_set_root (EggTreeModelFilter *filter, + GtkTreePath *root); + +static GtkTreePath *egg_real_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter *filter, + GtkTreePath *child_path, + gboolean build_levels, + gboolean fetch_childs); + +static gboolean egg_tree_model_filter_fetch_child (EggTreeModelFilter *filter, + FilterLevel *level, + gint offset); +static void egg_tree_model_filter_remove_node (EggTreeModelFilter *filter, + GtkTreeIter *iter, + gboolean emit_signal); +static void egg_tree_model_filter_update_childs (EggTreeModelFilter *filter, + FilterLevel *level, + FilterElt *elt); + + +static GObjectClass *parent_class = NULL; + +GType +egg_tree_model_filter_get_type (void) +{ + static GType tree_model_filter_type = 0; + + if (!tree_model_filter_type) + { + static const GTypeInfo tree_model_filter_info = + { + sizeof (EggTreeModelFilterClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) egg_tree_model_filter_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EggTreeModelFilter), + 0, /* n_preallocs */ + (GInstanceInitFunc) egg_tree_model_filter_init + }; + + static const GInterfaceInfo tree_model_info = + { + (GInterfaceInitFunc) egg_tree_model_filter_tree_model_init, + NULL, + NULL + }; + + tree_model_filter_type = g_type_register_static (G_TYPE_OBJECT, + "EggTreeModelFilter", + &tree_model_filter_info, 0); + + g_type_add_interface_static (tree_model_filter_type, + GTK_TYPE_TREE_MODEL, + &tree_model_info); + } + + return tree_model_filter_type; +} + +static void +egg_tree_model_filter_init (EggTreeModelFilter *filter) +{ + filter->visible_column = -1; + filter->zero_ref_count = 0; + filter->visible_method_set = FALSE; + filter->modify_func_set = FALSE; +} + +static void +egg_tree_model_filter_class_init (EggTreeModelFilterClass *filter_class) +{ + GObjectClass *object_class; + + object_class = (GObjectClass *) filter_class; + parent_class = g_type_class_peek_parent (filter_class); + + object_class->set_property = egg_tree_model_filter_set_property; + object_class->get_property = egg_tree_model_filter_get_property; + + object_class->finalize = egg_tree_model_filter_finalize; + + /* Properties -- FIXME: write a better description ... */ + g_object_class_install_property (object_class, + PROP_CHILD_MODEL, + g_param_spec_object ("child_model", + "The child model", + "The model for the TreeModelFilter to filter", + GTK_TYPE_TREE_MODEL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (object_class, + PROP_VIRTUAL_ROOT, + g_param_spec_boxed ("virtual_root", + "The virtual root", + "The virtual root (relative to the child model) for this filtermodel", + GTK_TYPE_TREE_PATH, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +} + +static void +egg_tree_model_filter_tree_model_init (GtkTreeModelIface *iface) +{ + iface->get_flags = egg_tree_model_filter_get_flags; + iface->get_n_columns = egg_tree_model_filter_get_n_columns; + iface->get_column_type = egg_tree_model_filter_get_column_type; + iface->get_iter = egg_tree_model_filter_get_iter; + iface->get_path = egg_tree_model_filter_get_path; + iface->get_value = egg_tree_model_filter_get_value; + iface->iter_next = egg_tree_model_filter_iter_next; + iface->iter_children = egg_tree_model_filter_iter_children; + iface->iter_has_child = egg_tree_model_filter_iter_has_child; + iface->iter_n_children = egg_tree_model_filter_iter_n_children; + iface->iter_nth_child = egg_tree_model_filter_iter_nth_child; + iface->iter_parent = egg_tree_model_filter_iter_parent; + iface->ref_node = egg_tree_model_filter_ref_node; + iface->unref_node = egg_tree_model_filter_unref_node; +} + + +static void +egg_tree_model_filter_finalize (GObject *object) +{ + EggTreeModelFilter *filter = (EggTreeModelFilter *) object; + + egg_tree_model_filter_set_model (filter, NULL); + + if (filter->virtual_root) + gtk_tree_path_free (filter->virtual_root); + + if (filter->root) + egg_tree_model_filter_free_level (filter, filter->root); + + if (filter->modify_types) + g_free (filter->modify_types); + + /* must chain up */ + parent_class->finalize (object); +} + +static void +egg_tree_model_filter_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (object); + + switch (prop_id) + { + case PROP_CHILD_MODEL: + egg_tree_model_filter_set_model (filter, g_value_get_object (value)); + break; + case PROP_VIRTUAL_ROOT: + egg_tree_model_filter_set_root (filter, g_value_get_boxed (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +egg_tree_model_filter_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (object); + + switch (prop_id) + { + case PROP_CHILD_MODEL: + g_value_set_object (value, filter->child_model); + break; + case PROP_VIRTUAL_ROOT: + g_value_set_boxed (value, filter->virtual_root); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/* helpers */ + +static void +egg_tree_model_filter_build_level (EggTreeModelFilter *filter, + FilterLevel *parent_level, + FilterElt *parent_elt) +{ + GtkTreeIter iter; + GtkTreeIter root; + FilterLevel *new_level; + gint length = 0; + gint i; + + g_assert (filter->child_model != NULL); + + if (!parent_level) + { + if (filter->virtual_root) + { + if (gtk_tree_model_get_iter (filter->child_model, &root, filter->virtual_root) == FALSE) + return; + length = gtk_tree_model_iter_n_children (filter->child_model, &root); + +#ifdef VERBOSE + g_print ("-- vroot %d children\n", length); +#endif + + if (gtk_tree_model_iter_children (filter->child_model, &iter, &root) == FALSE) + return; + } + else + { + if (!gtk_tree_model_get_iter_first (filter->child_model, &iter)) + return; + length = gtk_tree_model_iter_n_children (filter->child_model, NULL); + } + } + else + { + GtkTreeIter parent_iter; + GtkTreeIter child_parent_iter; + + parent_iter.stamp = filter->stamp; + parent_iter.user_data = parent_level; + parent_iter.user_data2 = parent_elt; + + egg_tree_model_filter_convert_iter_to_child_iter (filter, + &child_parent_iter, + &parent_iter); + if (gtk_tree_model_iter_children (filter->child_model, &iter, &child_parent_iter) == FALSE) + return; + + /* stamp may have changed */ + egg_tree_model_filter_convert_iter_to_child_iter (filter, + &child_parent_iter, + &parent_iter); + length = gtk_tree_model_iter_n_children (filter->child_model, &child_parent_iter); + } + + g_return_if_fail (length > 0); + +#ifdef VERBOSE + g_print ("-- building new level with %d childs\n", length); +#endif + + new_level = g_new (FilterLevel, 1); + new_level->array = g_array_sized_new (FALSE, FALSE, + sizeof (FilterElt), + length); + new_level->ref_count = 0; + new_level->parent_elt = parent_elt; + new_level->parent_level = parent_level; + + if (parent_elt) + parent_elt->children = new_level; + else + filter->root = new_level; + + /* increase the count of zero ref_counts */ + while (parent_level) + { + parent_elt->zero_ref_count++; + + parent_elt = parent_level->parent_elt; + parent_level = parent_level->parent_level; + } + filter->zero_ref_count++; + +#ifdef VERBOSE + g_print ("_build_level: zero ref count on filter is now %d\n", + filter->zero_ref_count); +#endif + + i = 0; + do + { + if (egg_tree_model_filter_visible (filter, &iter)) + { + FilterElt filter_elt; + + filter_elt.offset = i; + filter_elt.zero_ref_count = 0; + filter_elt.ref_count = 0; + filter_elt.children = NULL; + filter_elt.visible = TRUE; + + if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter)) + filter_elt.iter = iter; + + g_array_append_val (new_level->array, filter_elt); + } + i++; + } + while (gtk_tree_model_iter_next (filter->child_model, &iter)); +} + +static void +egg_tree_model_filter_free_level (EggTreeModelFilter *filter, + FilterLevel *filter_level) +{ + gint i; + + g_assert (filter_level); + + if (filter_level->ref_count == 0) + { + FilterLevel *parent_level = filter_level->parent_level; + FilterElt *parent_elt = filter_level->parent_elt; + + do + { + if (parent_elt) + parent_elt->zero_ref_count--; + + if (parent_level) + { + parent_elt = parent_level->parent_elt; + parent_level = parent_level->parent_level; + } + } + while (parent_level); + filter->zero_ref_count--; + } + +#ifdef VERBOSE + g_print ("freeing level\n"); + g_print ("zero ref count is %d\n", filter->zero_ref_count); +#endif + + for (i = 0; i < filter_level->array->len; i++) + { + if (g_array_index (filter_level->array, FilterElt, i).children) + egg_tree_model_filter_free_level (filter, + FILTER_LEVEL (g_array_index (filter_level->array, FilterElt, i).children)); + } + + if (filter_level->parent_elt) + filter_level->parent_elt->children = NULL; + else + filter->root = NULL; + + g_array_free (filter_level->array, TRUE); + filter_level->array = NULL; + + g_free (filter_level); + filter_level = NULL; +} + +static GtkTreePath * +egg_tree_model_filter_elt_get_path (FilterLevel *level, + FilterElt *elt, + GtkTreePath *root) +{ + FilterLevel *walker = level; + FilterElt *walker2 = elt; + GtkTreePath *path; + GtkTreePath *real_path; + + g_return_val_if_fail (level != NULL, NULL); + g_return_val_if_fail (elt != NULL, NULL); + + path = gtk_tree_path_new (); + + while (walker) + { + gtk_tree_path_prepend_index (path, walker2->offset); + + walker2 = walker->parent_elt; + walker = walker->parent_level; + } + + if (root) + { + real_path = gtk_tree_path_copy (root); + + egg_tree_model_filter_add_root (real_path, path); + gtk_tree_path_free (path); + return real_path; + } + + return path; +} + +static GtkTreePath * +egg_tree_model_filter_add_root (GtkTreePath *src, + GtkTreePath *root) +{ + GtkTreePath *retval; + gint i; + + retval = gtk_tree_path_copy (root); + + for (i = 0; i < gtk_tree_path_get_depth (src); i++) + gtk_tree_path_append_index (retval, gtk_tree_path_get_indices (src)[i]); + + return retval; +} + +static GtkTreePath * +egg_tree_model_filter_remove_root (GtkTreePath *src, + GtkTreePath *root) +{ + GtkTreePath *retval; + gint i; + gint depth; + gint *indices; + + if (gtk_tree_path_get_depth (src) <= gtk_tree_path_get_depth (root)) + return NULL; + + depth = gtk_tree_path_get_depth (src); + indices = gtk_tree_path_get_indices (src); + + for (i = 0; i < gtk_tree_path_get_depth (root); i++) + if (indices[i] != gtk_tree_path_get_indices (root)[i]) + return NULL; + + retval = gtk_tree_path_new (); + + for (; i < depth; i++) + gtk_tree_path_append_index (retval, indices[i]); + + return retval; +} + +static void +egg_tree_model_filter_increment_stamp (EggTreeModelFilter *filter) +{ + do + { + filter->stamp++; + } + while (filter->stamp == 0); + + egg_tree_model_filter_clear_cache (filter); +} + +static gboolean +egg_tree_model_filter_visible (EggTreeModelFilter *filter, + GtkTreeIter *child_iter) +{ + if (filter->visible_func) + { + return (filter->visible_func (filter->child_model, + child_iter, + filter->visible_data)); + } + else if (filter->visible_column >= 0) + { + GValue val = {0, }; + + gtk_tree_model_get_value (filter->child_model, child_iter, + filter->visible_column, &val); + + if (g_value_get_boolean (&val)) + { + g_value_unset (&val); + return TRUE; + } + + g_value_unset (&val); + return FALSE; + } + + /* no filter thing set, so always visible */ + return TRUE; +} + +static void +egg_tree_model_filter_clear_cache_helper (EggTreeModelFilter *filter, + FilterLevel *level) +{ + gint i; + + g_assert (level); + + for (i = 0; i < level->array->len; i++) + { + if (g_array_index (level->array, FilterElt, i).zero_ref_count > 0) + egg_tree_model_filter_clear_cache_helper (filter, g_array_index (level->array, FilterElt, i).children); + } + + if (level->ref_count == 0 && level != filter->root) + { + egg_tree_model_filter_free_level (filter, level); + return; + } +} + +static gboolean +egg_tree_model_filter_fetch_child (EggTreeModelFilter *filter, + FilterLevel *level, + gint offset) +{ + gint i = 0; + gint len; + GtkTreePath *c_path = NULL; + GtkTreeIter c_iter; + GtkTreePath *c_parent_path = NULL; + GtkTreeIter c_parent_iter; + FilterElt elt; + +#ifdef VERBOSE + g_print ("_fetch_child: for offset %d\n", offset); +#endif + + /* check if child exists and is visible */ + if (level->parent_elt) + { + c_parent_path = + egg_tree_model_filter_elt_get_path (level->parent_level, + level->parent_elt, + filter->virtual_root); + if (!c_parent_path) + return FALSE; + } + else + { + if (filter->virtual_root) + c_parent_path = gtk_tree_path_copy (filter->virtual_root); + else + c_parent_path = NULL; + } + + if (c_parent_path) + { + gtk_tree_model_get_iter (filter->child_model, + &c_parent_iter, + c_parent_path); + len = gtk_tree_model_iter_n_children (filter->child_model, + &c_parent_iter); + + c_path = gtk_tree_path_copy (c_parent_path); + gtk_tree_path_free (c_parent_path); + } + else + { + len = gtk_tree_model_iter_n_children (filter->child_model, NULL); + c_path = gtk_tree_path_new (); + } + + gtk_tree_path_append_index (c_path, offset); + gtk_tree_model_get_iter (filter->child_model, &c_iter, c_path); + gtk_tree_path_free (c_path); + + if (offset >= len || !egg_tree_model_filter_visible (filter, &c_iter)) + return FALSE; + + /* add child */ + elt.offset = offset; + elt.zero_ref_count = 0; + elt.ref_count = 0; + elt.children = NULL; + /* visibility should be FALSE as we don't emit row_inserted */ + elt.visible = FALSE; + + if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter)) + elt.iter = c_iter; + + /* find index */ + for (i = 0; i < level->array->len; i++) + if (g_array_index (level->array, FilterElt, i).offset > offset) + break; + + g_array_insert_val (level->array, i, elt); + + for (i = 0; i < level->array->len; i++) + { + FilterElt *e = &(g_array_index (level->array, FilterElt, i)); + if (e->children) + e->children->parent_elt = e; + } + + return TRUE; +} + +static void +egg_tree_model_filter_remove_node (EggTreeModelFilter *filter, + GtkTreeIter *iter, + gboolean emit_signal) +{ + FilterElt *elt, *parent; + FilterLevel *level, *parent_level; + gint offset, i, length, level_refcount; + + /* FIXME: this function is very ugly. I need to rethink and + * rewrite it someday. + */ + + level = FILTER_LEVEL (iter->user_data); + elt = FILTER_ELT (iter->user_data2); + + parent = level->parent_elt; + parent_level = level->parent_level; + length = level->array->len; + offset = elt->offset; + +#ifdef VERBOSE + g_print ("|___ removing node\n"); +#endif + + /* ref counting */ + while (elt->ref_count > 0) + egg_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter), + iter, FALSE); + + level_refcount = level->ref_count; + + /* do the ref counting first! this touches the stamp */ + if (emit_signal) + { + GtkTreePath *path; + + path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter); + egg_tree_model_filter_increment_stamp (filter); + gtk_tree_model_row_deleted (GTK_TREE_MODEL (filter), path); + gtk_tree_path_free (path); + } + + if ((length == 1 || level_refcount == 0) && + emit_signal && iter->user_data != filter->root) + { + /* above code destroyed the level */ + goto emit_has_child_toggled; + } + + if (length == 1) + { + /* kill the level */ +#ifdef VERBOSE + g_print ("killing level ...\n"); +#endif + egg_tree_model_filter_free_level (filter, level); + + if (!filter->root) + /* we killed the root */ + return; + } + else + { +#ifdef VERBOSE + g_print ("removing the node...\n"); +#endif + + /* remove the node */ + for (i = 0; i < level->array->len; i++) + if (elt->offset == g_array_index (level->array, FilterElt, i).offset) + break; + + g_array_remove_index (level->array, i); + + for (i = 0; i < level->array->len; i++) + { + /* NOTE: here we do *not* decrease offsets, because the node was + * not removed from the child model + */ + elt = &g_array_index (level->array, FilterElt, i); + if (elt->children) + elt->children->parent_elt = elt; + } + } + +emit_has_child_toggled: + /* children are being handled first, so we can check it this way + * + * yes this if-statement is ugly + */ + if ((parent && parent->children && parent->children->array->len <= 1) || + (length == 1 && emit_signal && iter->user_data != filter->root)) + { + /* latest child has been removed, level has been destroyed */ + GtkTreeIter piter; + GtkTreePath *ppath; + + piter.stamp = filter->stamp; + piter.user_data = parent_level; + piter.user_data2 = parent; + + ppath = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &piter); + +#ifdef VERBOSE + g_print ("emitting has_child_toggled (by _filter_remove)\n"); +#endif + + gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter), + ppath, &piter); + gtk_tree_path_free (ppath); + } +} + +static void +egg_tree_model_filter_update_childs (EggTreeModelFilter *filter, + FilterLevel *level, + FilterElt *elt) +{ + GtkTreeIter c_iter; + GtkTreeIter iter; + +#ifdef VERBOSE + g_print ("~~ a node came back, search childs\n"); +#endif + + if (!elt->visible) + { +#ifdef VERBOSE + g_print (" + given elt not visible -- bailing out\n"); +#endif + return; + } + + iter.stamp = filter->stamp; + iter.user_data = level; + iter.user_data2 = elt; + + egg_tree_model_filter_convert_iter_to_child_iter (filter, &c_iter, &iter); + + if (gtk_tree_model_iter_has_child (filter->child_model, &c_iter)) + { + GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), + &iter); + gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter), + path, + &iter); + if (path) + gtk_tree_path_free (path); + } +} + +/* TreeModel signals */ +static void +egg_tree_model_filter_row_changed (GtkTreeModel *c_model, + GtkTreePath *c_path, + GtkTreeIter *c_iter, + gpointer data) +{ + EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data); + GtkTreeIter iter; + GtkTreeIter real_c_iter; + GtkTreePath *path; + + FilterElt *elt; + FilterLevel *level; + gint offset; + + gboolean new; + gboolean free_c_path = FALSE; + + g_return_if_fail (c_path != NULL || c_iter != NULL); + + if (!c_path) + { + c_path = gtk_tree_model_get_path (c_model, c_iter); + free_c_path = TRUE; + } + + if (c_iter) + real_c_iter = *c_iter; + else + gtk_tree_model_get_iter (c_model, &real_c_iter, c_path); + + if (!filter->root) + { + gint i; + FilterLevel *root; + + /* build root level */ + egg_tree_model_filter_build_level (filter, NULL, NULL); + + root = FILTER_LEVEL (filter->root); + + /* FIXME: + * we set the visibilities to FALSE here, so we ever emit + * a row_inserted. maybe it's even better to emit row_inserted + * here, not sure. + */ + if (root) + for (i = 0; i < root->array->len; i++) + g_array_index (root->array, FilterElt, i).visible = FALSE; + } + + path = egg_real_tree_model_filter_convert_child_path_to_path (filter, + c_path, + FALSE, + TRUE); + if (!path) + goto done; + + gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), &iter, path); + + level = FILTER_LEVEL (iter.user_data); + elt = FILTER_ELT (iter.user_data2); + offset = elt->offset; + new = egg_tree_model_filter_visible (filter, c_iter); + + if (elt->visible == TRUE && new == FALSE) + { +#ifdef VERBOSE + g_print ("visible to false -> delete row\n"); +#endif + egg_tree_model_filter_remove_node (filter, &iter, TRUE); + } + else if (elt->visible == FALSE && new == TRUE) + { + GtkTreeIter childs; + +#ifdef VERBOSE + g_print ("visible to true -> insert row\n"); +#endif + + elt->visible = TRUE; + + egg_tree_model_filter_increment_stamp (filter); + /* update stamp */ + gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), &iter, path); + gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter), path, &iter); + + if (gtk_tree_model_iter_children (c_model, &childs, c_iter)) + egg_tree_model_filter_update_childs (filter, level, elt); + } + else if (elt->visible == FALSE && new == FALSE) + { +#ifdef VERBOSE + g_print ("remove node in silence\n"); +#endif + egg_tree_model_filter_remove_node (filter, &iter, FALSE); + } + else + { + GtkTreeIter childs; + +#ifdef VERBOSE + g_print ("no change in visibility -- pass row_changed\n"); +#endif + + gtk_tree_model_row_changed (GTK_TREE_MODEL (filter), path, &iter); + + if (gtk_tree_model_iter_children (c_model, &childs, c_iter) && + elt->visible) + egg_tree_model_filter_update_childs (filter, level, elt); + } + + gtk_tree_path_free (path); + +done: + if (free_c_path) + gtk_tree_path_free (c_path); +} + +static void +egg_tree_model_filter_row_inserted (GtkTreeModel *c_model, + GtkTreePath *c_path, + GtkTreeIter *c_iter, + gpointer data) +{ + EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data); + GtkTreePath *path; + GtkTreePath *real_path; + GtkTreeIter iter; + + GtkTreeIter real_c_iter; + + FilterElt *elt; + FilterLevel *level; + FilterLevel *parent_level; + + gint i = 0, offset, index = -1; + + gboolean free_c_path = FALSE; + + g_return_if_fail (c_path != NULL || c_iter != NULL); + + if (!c_path) + { + c_path = gtk_tree_model_get_path (c_model, c_iter); + free_c_path = TRUE; + } + + if (c_iter) + real_c_iter = *c_iter; + else + gtk_tree_model_get_iter (c_model, &real_c_iter, c_path); + + /* the row has already been inserted. so we need to fixup the + * virtual root here first + */ + if (filter->virtual_root) + { + if (gtk_tree_path_get_depth (filter->virtual_root) >= + gtk_tree_path_get_depth (c_path)) + { + gint level; + gint *v_indices, *c_indices; + + level = gtk_tree_path_get_depth (c_path) - 1; + v_indices = gtk_tree_path_get_indices (filter->virtual_root); + c_indices = gtk_tree_path_get_indices (c_path); + + if (v_indices[level] >= c_indices[level]) + (v_indices[level])++; + } + } + + if (!filter->root) + { + egg_tree_model_filter_build_level (filter, NULL, NULL); + /* that already put the inserted iter in the level */ + + goto done_and_emit; + } + + parent_level = level = FILTER_LEVEL (filter->root); + + /* subtract virtual root if necessary */ + if (filter->virtual_root) + { + real_path = egg_tree_model_filter_remove_root (c_path, + filter->virtual_root); + /* not our kiddo */ + if (!real_path) + goto done; + } + else + real_path = gtk_tree_path_copy (c_path); + + if (gtk_tree_path_get_depth (real_path) - 1 >= 1) + { + /* find the parent level */ + while (i < gtk_tree_path_get_depth (real_path) - 1) + { + gint j; + + if (!level) + /* we don't cover this signal */ + goto done; + + elt = NULL; + for (j = 0; j < level->array->len; j++) + if (g_array_index (level->array, FilterElt, j).offset == + gtk_tree_path_get_indices (real_path)[i]) + { + elt = &g_array_index (level->array, FilterElt, j); + break; + } + + if (!elt) + /* parent is probably being filtered out */ + goto done; + + if (!elt->children) + { + GtkTreePath *tmppath; + GtkTreeIter tmpiter; + + tmpiter.stamp = filter->stamp; + tmpiter.user_data = level; + tmpiter.user_data2 = elt; + + tmppath = gtk_tree_model_get_path (GTK_TREE_MODEL (data), + &tmpiter); + + if (tmppath) + { + gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (data), + tmppath, &tmpiter); + gtk_tree_path_free (tmppath); + } + + /* not covering this signal */ + goto done; + } + + level = elt->children; + parent_level = level; + i++; + } + } + + if (!parent_level) + goto done; + + /* let's try to insert the value */ + offset = gtk_tree_path_get_indices (real_path)[gtk_tree_path_get_depth (real_path) - 1]; + + /* only insert when visible */ + if (egg_tree_model_filter_visible (filter, &real_c_iter)) + { + FilterElt felt; + + if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter)) + felt.iter = real_c_iter; + felt.offset = offset; + felt.zero_ref_count = 0; + felt.ref_count = 0; + felt.visible = TRUE; + felt.children = NULL; + + for (i = 0; i < level->array->len; i++) + if (g_array_index (level->array, FilterElt, i).offset > offset) + break; + + g_array_insert_val (level->array, i, felt); + index = i; + } + + /* update the offsets, yes if we didn't insert the node above, there will + * be a gap here. This will be filled with the node (via fetch_child) when + * it becomes visible + */ + for (i = 0; i < level->array->len; i++) + { + FilterElt *e = &g_array_index (level->array, FilterElt, i); + if ((e->offset >= offset) && i != index) + e->offset++; + if (e->children) + e->children->parent_elt = e; + } + + /* don't emit the signal if we aren't visible */ + if (!egg_tree_model_filter_visible (filter, &real_c_iter)) + goto done; + +done_and_emit: + /* NOTE: pass c_path here and NOT real_path. This function does + * root subtraction itself + */ + path = egg_real_tree_model_filter_convert_child_path_to_path (filter, + c_path, + FALSE, TRUE); + + if (!path) + return; + + egg_tree_model_filter_increment_stamp (filter); + + gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path); + gtk_tree_model_row_inserted (GTK_TREE_MODEL (data), path, &iter); + +#ifdef VERBOSE + g_print ("inserted row with offset %d\n", index); +#endif + +done: + if (free_c_path) + gtk_tree_path_free (c_path); +} + +static void +egg_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model, + GtkTreePath *c_path, + GtkTreeIter *c_iter, + gpointer data) +{ + EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data); + GtkTreePath *path; + GtkTreeIter iter; + + g_return_if_fail (c_path != NULL && c_iter != NULL); + + /* FIXME: does this code work? */ + + if (!egg_tree_model_filter_visible (filter, c_iter)) + return; + + path = egg_real_tree_model_filter_convert_child_path_to_path (filter, + c_path, + FALSE, + TRUE); + if (!path) + return; + + gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path); + gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (data), path, &iter); + + gtk_tree_path_free (path); +} + +static void +egg_tree_model_filter_row_deleted (GtkTreeModel *c_model, + GtkTreePath *c_path, + gpointer data) +{ + EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data); + GtkTreePath *path; + GtkTreeIter iter; + FilterElt *elt; + FilterLevel *level; + gint offset; + gboolean emit_signal = TRUE; + gint i; + + g_return_if_fail (c_path != NULL); + + /* special case the deletion of an ancestor of the virtual root */ + if (filter->virtual_root && + (gtk_tree_path_is_ancestor (c_path, filter->virtual_root) || + !gtk_tree_path_compare (c_path, filter->virtual_root))) + { + gint i; + GtkTreePath *path; + FilterLevel *level = FILTER_LEVEL (filter->root); + + if (!level) + return; + + /* remove everything in the filter model + * + * For now, we just iterate over the root level and emit a + * row_deleted for each FilterElt. Not sure if this is correct. + */ + + egg_tree_model_filter_increment_stamp (filter); + path = gtk_tree_path_new (); + gtk_tree_path_append_index (path, 0); + + for (i = 0; i < level->array->len; i++) + gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path); + + gtk_tree_path_free (path); + egg_tree_model_filter_free_level (filter, filter->root); + + return; + } + + /* fixup virtual root */ + if (filter->virtual_root) + { + if (gtk_tree_path_get_depth (filter->virtual_root) >= + gtk_tree_path_get_depth (c_path)) + { + gint level; + gint *v_indices, *c_indices; + + level = gtk_tree_path_get_depth (c_path) - 1; + v_indices = gtk_tree_path_get_indices (filter->virtual_root); + c_indices = gtk_tree_path_get_indices (c_path); + + if (v_indices[level] > c_indices[level]) + (v_indices[level])--; + } + } + + path = egg_real_tree_model_filter_convert_child_path_to_path (filter, + c_path, + FALSE, + FALSE); + if (!path) + { + path = egg_real_tree_model_filter_convert_child_path_to_path (filter, + c_path, + FALSE, + TRUE); + + if (!path) + { + /* fixup the offsets */ + GtkTreePath *real_path; + + if (!filter->root) + return; + + level = FILTER_LEVEL (filter->root); + + /* subtract vroot if necessary */ + if (filter->virtual_root) + { + real_path = egg_tree_model_filter_remove_root (c_path, + filter->virtual_root); + /* we don't handle this */ + if (!real_path) + return; + } + else + real_path = gtk_tree_path_copy (c_path); + + i = 0; + if (gtk_tree_path_get_depth (real_path) - 1 >= 1) + { + while (i < gtk_tree_path_get_depth (real_path) - 1) + { + gint j; + + if (!level) + { + /* we don't cover this */ + gtk_tree_path_free (real_path); + return; + } + + elt = NULL; + for (j = 0; j < level->array->len; j++) + if (g_array_index (level->array, FilterElt, j).offset == + gtk_tree_path_get_indices (real_path)[i]) + { + elt = &g_array_index (level->array, FilterElt, j); + break; + } + + if (!elt || !elt->children) + { + /* parent is filtered out, so no level */ + gtk_tree_path_free (real_path); + return; + } + + level = elt->children; + i++; + } + } + + offset = gtk_tree_path_get_indices (real_path)[gtk_tree_path_get_depth (real_path) - 1]; + gtk_tree_path_free (real_path); + + if (!level) + return; + + /* we need: + * - the offset of the removed item + * - the level + */ + for (i = 0; i < level->array->len; i++) + { + elt = &g_array_index (level->array, FilterElt, i); + if (elt->offset > offset) + elt->offset--; + if (elt->children) + elt->children->parent_elt = elt; + } + + return; + } + + emit_signal = FALSE; + } + + gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path); + + level = FILTER_LEVEL (iter.user_data); + elt = FILTER_ELT (iter.user_data2); + offset = elt->offset; + + if (emit_signal) + { + if (level->ref_count == 0 && level != filter->root) + { + egg_tree_model_filter_increment_stamp (filter); + gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path); + + gtk_tree_path_free (path); + return; + } + + egg_tree_model_filter_increment_stamp (filter); + gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path); + iter.stamp = filter->stamp; + + while (elt->ref_count > 0) + egg_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), &iter, + FALSE); + } + + if (level->array->len == 1) + { + /* kill level */ + egg_tree_model_filter_free_level (filter, level); + } + else + { + /* remove the row */ + for (i = 0; i < level->array->len; i++) + if (elt->offset == g_array_index (level->array, FilterElt, i).offset) + break; + + offset = g_array_index (level->array, FilterElt, i).offset; + g_array_remove_index (level->array, i); + + for (i = 0; i < level->array->len; i++) + { + elt = &g_array_index (level->array, FilterElt, i); + if (elt->offset > offset) + elt->offset--; + if (elt->children) + elt->children->parent_elt = elt; + } + } + + gtk_tree_path_free (path); +} + +static void +egg_tree_model_filter_rows_reordered (GtkTreeModel *c_model, + GtkTreePath *c_path, + GtkTreeIter *c_iter, + gint *new_order, + gpointer data) +{ + FilterElt *elt; + FilterLevel *level; + EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data); + + GtkTreePath *path; + GtkTreeIter iter; + + gint *tmp_array; + gint i, j, elt_count; + gint length; + + GArray *new_array; + + g_return_if_fail (new_order != NULL); + +#ifdef VERBOSE + g_print ("filter: reordering\n"); +#endif + + if (c_path == NULL || gtk_tree_path_get_indices (c_path) == NULL) + { + if (!filter->root) + return; + + length = gtk_tree_model_iter_n_children (c_model, NULL); + + if (filter->virtual_root) + { + gint new_pos = -1; + + /* reorder root level of path */ + for (i = 0; i < length; i++) + if (new_order[i] == gtk_tree_path_get_indices (filter->virtual_root)[0]) + new_pos = i; + + if (new_pos < 0) + return; + + gtk_tree_path_get_indices (filter->virtual_root)[0] = new_pos; + return; + } + + path = gtk_tree_path_new (); + level = FILTER_LEVEL (filter->root); + } + else + { + GtkTreeIter child_iter; + + /* virtual root anchor reordering */ + if (filter->virtual_root && + gtk_tree_path_get_depth (c_path) < + gtk_tree_path_get_depth (filter->virtual_root)) + { + gint new_pos = -1; + gint length; + gint level; + GtkTreeIter real_c_iter; + + level = gtk_tree_path_get_depth (c_path); + + if (c_iter) + real_c_iter = *c_iter; + else + gtk_tree_model_get_iter (c_model, &real_c_iter, c_path); + + length = gtk_tree_model_iter_n_children (c_model, &real_c_iter); + + for (i = 0; i < length; i++) + if (new_order[i] == gtk_tree_path_get_indices (filter->virtual_root)[level]) + new_pos = i; + + if (new_pos < 0) + return; + + gtk_tree_path_get_indices (filter->virtual_root)[level] = new_pos; + return; + } + + path = egg_real_tree_model_filter_convert_child_path_to_path (filter, + c_path, + FALSE, + FALSE); + if (!path && filter->virtual_root && + gtk_tree_path_compare (c_path, filter->virtual_root)) + return; + + if (!path && !filter->virtual_root) + return; + + if (!path) + { + /* root level mode */ + if (!c_iter) + gtk_tree_model_get_iter (c_model, c_iter, c_path); + length = gtk_tree_model_iter_n_children (c_model, c_iter); + path = gtk_tree_path_new (); + level = FILTER_LEVEL (filter->root); + } + else + { + gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path); + + level = FILTER_LEVEL (iter.user_data); + elt = FILTER_ELT (iter.user_data2); + + if (!elt->children) + { + gtk_tree_path_free (path); + return; + } + + level = elt->children; + + egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (filter), &child_iter, &iter); + length = gtk_tree_model_iter_n_children (c_model, &child_iter); + } + } + + if (level->array->len < 1) + return; + + /* NOTE: we do not bail out here if level->array->len < 2 like + * GtkTreeModelSort does. This because we do some special tricky + * reordering. + */ + + /* construct a new array */ + new_array = g_array_sized_new (FALSE, FALSE, sizeof (FilterElt), + level->array->len); + tmp_array = g_new (gint, level->array->len); + + for (i = 0, elt_count = 0; i < length; i++) + { + FilterElt *e = NULL; + gint old_offset = -1; + + for (j = 0; j < level->array->len; j++) + if (g_array_index (level->array, FilterElt, j).offset == new_order[i]) + { + e = &g_array_index (level->array, FilterElt, j); + old_offset = j; + break; + } + + if (!e) + continue; + + tmp_array[elt_count] = old_offset; + g_array_append_val (new_array, *e); + g_array_index (new_array, FilterElt, elt_count).offset = i; + elt_count++; + } + + g_array_free (level->array, TRUE); + level->array = new_array; + + /* fix up stuff */ + for (i = 0; i < level->array->len; i++) + { + FilterElt *e = &g_array_index (level->array, FilterElt, i); + if (e->children) + e->children->parent_elt = e; + } + + /* emit rows_reordered */ + if (!gtk_tree_path_get_indices (path)) + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data), path, NULL, + tmp_array); + else + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data), path, &iter, + tmp_array); + + /* done */ + g_free (tmp_array); + gtk_tree_path_free (path); +} + +/* TreeModelIface implementation */ +static guint +egg_tree_model_filter_get_flags (GtkTreeModel *model) +{ + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), 0); + + return 0; +} + +static gint +egg_tree_model_filter_get_n_columns (GtkTreeModel *model) +{ + EggTreeModelFilter *filter = (EggTreeModelFilter *)model; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), 0); + g_return_val_if_fail (filter->child_model != NULL, 0); + + if (filter->child_model == NULL) + return 0; + + /* so we can't modify the modify func after this ... */ + filter->modify_func_set = TRUE; + + if (filter->modify_n_columns > 0) + return filter->modify_n_columns; + + return gtk_tree_model_get_n_columns (filter->child_model); +} + +static GType +egg_tree_model_filter_get_column_type (GtkTreeModel *model, + gint index) +{ + EggTreeModelFilter *filter = (EggTreeModelFilter *)model; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), G_TYPE_INVALID); + g_return_val_if_fail (filter->child_model != NULL, G_TYPE_INVALID); + + /* so we can't modify the modify func after this ... */ + filter->modify_func_set = TRUE; + + if (filter->modify_types) + { + g_return_val_if_fail (index < filter->modify_n_columns, G_TYPE_INVALID); + + return filter->modify_types[index]; + } + + return gtk_tree_model_get_column_type (filter->child_model, index); +} + +static gboolean +egg_tree_model_filter_get_iter (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreePath *path) +{ + EggTreeModelFilter *filter = (EggTreeModelFilter *)model; + gint *indices; + FilterLevel *level; + gint depth, i; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); + g_return_val_if_fail (filter->child_model != NULL, FALSE); + + indices = gtk_tree_path_get_indices (path); + + if (filter->root == NULL) + egg_tree_model_filter_build_level (filter, NULL, NULL); + level = FILTER_LEVEL (filter->root); + + depth = gtk_tree_path_get_depth (path); + if (!depth) + { + iter->stamp = 0; + return FALSE; + } + + for (i = 0; i < depth - 1; i++) + { + if (!level || indices[i] >= level->array->len) + { + return FALSE; + } + + if (!g_array_index (level->array, FilterElt, indices[i]).children) + egg_tree_model_filter_build_level (filter, level, + &g_array_index (level->array, + FilterElt, + indices[i])); + level = g_array_index (level->array, FilterElt, indices[i]).children; + } + + if (!level || indices[i] >= level->array->len) + { + iter->stamp = 0; + return FALSE; + } + + iter->stamp = filter->stamp; + iter->user_data = level; + iter->user_data2 = &g_array_index (level->array, FilterElt, + indices[depth - 1]); + + return TRUE; +} + +static GtkTreePath * +egg_tree_model_filter_get_path (GtkTreeModel *model, + GtkTreeIter *iter) +{ + GtkTreePath *retval; + FilterLevel *level; + FilterElt *elt; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), NULL); + g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL, NULL); + g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == iter->stamp, NULL); + + retval = gtk_tree_path_new (); + level = iter->user_data; + elt = iter->user_data2; + + while (level) + { + gtk_tree_path_prepend_index (retval, + elt - FILTER_ELT (level->array->data)); + elt = level->parent_elt; + level = level->parent_level; + } + + return retval; +} + +static void +egg_tree_model_filter_get_value (GtkTreeModel *model, + GtkTreeIter *iter, + gint column, + GValue *value) +{ + GtkTreeIter child_iter; + EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (model); + + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model)); + g_return_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL); + g_return_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == iter->stamp); + + if (filter->modify_func) + { + g_return_if_fail (column < filter->modify_n_columns); + + g_value_init (value, filter->modify_types[column]); + filter->modify_func (model, + iter, + value, + column, + filter->modify_data); + + return; + } + + egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter); + gtk_tree_model_get_value (EGG_TREE_MODEL_FILTER (model)->child_model, + &child_iter, column, value); +} + +static gboolean +egg_tree_model_filter_iter_next (GtkTreeModel *model, + GtkTreeIter *iter) +{ + FilterLevel *level; + FilterElt *elt; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); + g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL, FALSE); + g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == iter->stamp, FALSE); + + level = iter->user_data; + elt = iter->user_data2; + + if (elt - FILTER_ELT (level->array->data) >= level->array->len - 1) + { + iter->stamp = 0; + return FALSE; + } + + iter->user_data2 = elt + 1; + + return TRUE; +} + +static gboolean +egg_tree_model_filter_iter_children (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *parent) +{ + EggTreeModelFilter *filter = (EggTreeModelFilter *)model; + FilterLevel *level; + + iter->stamp = 0; + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); + g_return_val_if_fail (filter->child_model != NULL, FALSE); + if (parent) + g_return_val_if_fail (filter->stamp == parent->stamp, FALSE); + + if (!parent) + { + if (!filter->root) + egg_tree_model_filter_build_level (filter, NULL, NULL); + if (!filter->root) + return FALSE; + + level = filter->root; + iter->stamp = filter->stamp; + iter->user_data = level; + iter->user_data2 = level->array->data; + } + else + { + if (FILTER_ELT (parent->user_data2)->children == NULL) + egg_tree_model_filter_build_level (filter, + FILTER_LEVEL (parent->user_data), + FILTER_ELT (parent->user_data2)); + if (FILTER_ELT (parent->user_data2)->children == NULL) + return FALSE; + + iter->stamp = filter->stamp; + iter->user_data = FILTER_ELT (parent->user_data2)->children; + iter->user_data2 = FILTER_LEVEL (iter->user_data)->array->data; + } + + return TRUE; +} + +static gboolean +egg_tree_model_filter_iter_has_child (GtkTreeModel *model, + GtkTreeIter *iter) +{ + GtkTreeIter child_iter; + EggTreeModelFilter *filter = (EggTreeModelFilter *)model; + FilterElt *elt; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); + g_return_val_if_fail (filter->child_model != NULL, FALSE); + g_return_val_if_fail (filter->stamp == iter->stamp, FALSE); + + filter = EGG_TREE_MODEL_FILTER (model); + + egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter); + elt = FILTER_ELT (iter->user_data2); + + /* we need to build the level to check if not all children are filtered + * out + */ + if (!elt->children + && gtk_tree_model_iter_has_child (filter->child_model, &child_iter)) + egg_tree_model_filter_build_level (filter, FILTER_LEVEL (iter->user_data), + elt); + + if (elt->children && elt->children->array->len > 0) + return TRUE; + + return FALSE; +} + +static gint +egg_tree_model_filter_iter_n_children (GtkTreeModel *model, + GtkTreeIter *iter) +{ + GtkTreeIter child_iter; + EggTreeModelFilter *filter = (EggTreeModelFilter *)model; + FilterElt *elt; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), 0); + g_return_val_if_fail (filter->child_model != NULL, 0); + if (iter) + g_return_val_if_fail (filter->stamp == iter->stamp, 0); + + if (!iter) + { + int i = 0; + int count = 0; + GArray *a; + + if (!filter->root) + egg_tree_model_filter_build_level (filter, NULL, NULL); + + a = FILTER_LEVEL (filter->root)->array; + + /* count visible nodes */ + + for (i = 0; i < a->len; i++) + if (g_array_index (a, FilterElt, i).visible) + count++; + + return count; + } + + elt = FILTER_ELT (iter->user_data2); + egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter); + + if (!elt->children && + gtk_tree_model_iter_has_child (filter->child_model, &child_iter)) + egg_tree_model_filter_build_level (filter, + FILTER_LEVEL (iter->user_data), + elt); + + if (elt->children && elt->children->array->len) + { + int i = 0; + int count = 0; + GArray *a = elt->children->array; + + /* count visible nodes */ + + for (i = 0; i < a->len; i++) + if (g_array_index (a, FilterElt, i).visible) + count++; + + return count; + } + + return 0; +} + +static gboolean +egg_tree_model_filter_iter_nth_child (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *parent, + gint n) +{ + FilterLevel *level; + GtkTreeIter children; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); + if (parent) + g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == parent->stamp, FALSE); + + /* use this instead of has_Child to force us to build the level, if needed */ + if (egg_tree_model_filter_iter_children (model, &children, parent) == FALSE) + { + iter->stamp = 0; + return FALSE; + } + + level = children.user_data; + if (n >= level->array->len) + { + iter->stamp = 0; + return FALSE; + } + + iter->stamp = EGG_TREE_MODEL_FILTER (model)->stamp; + iter->user_data = level; + iter->user_data2 = &g_array_index (level->array, FilterElt, n); + + return TRUE; +} + +static gboolean +egg_tree_model_filter_iter_parent (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *child) +{ + FilterLevel *level; + + iter->stamp = 0; + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); + g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL, FALSE); + g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == child->stamp, FALSE); + + level = child->user_data; + + if (level->parent_level) + { + iter->stamp = EGG_TREE_MODEL_FILTER (model)->stamp; + iter->user_data = level->parent_level; + iter->user_data2 = level->parent_elt; + + return TRUE; + } + + return FALSE; +} + +static void +egg_tree_model_filter_ref_node (GtkTreeModel *model, + GtkTreeIter *iter) +{ + EggTreeModelFilter *filter = (EggTreeModelFilter *)model; + GtkTreeIter child_iter; + FilterLevel *level; + FilterElt *elt; + + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model)); + g_return_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL); + g_return_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == iter->stamp); + + egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter); + + gtk_tree_model_ref_node (filter->child_model, &child_iter); + + level = iter->user_data; + elt = iter->user_data2; + + elt->ref_count++; + level->ref_count++; + if (level->ref_count == 1) + { + FilterLevel *parent_level = level->parent_level; + FilterElt *parent_elt = level->parent_elt; + + /* we were at zero -- time to decrease the zero_ref_count val */ + do + { + if (parent_elt) + parent_elt->zero_ref_count--; + + if (parent_level) + { + parent_elt = parent_level->parent_elt; + parent_level = parent_level->parent_level; + } + } + while (parent_level); + filter->zero_ref_count--; + } + +#ifdef VERBOSE + g_print ("reffed %p\n", iter->user_data2); + g_print ("zero ref count is now %d\n", filter->zero_ref_count); + if (filter->zero_ref_count < 0) + g_warning ("zero_ref_count < 0."); +#endif +} + +static void +egg_tree_model_filter_unref_node (GtkTreeModel *model, + GtkTreeIter *iter) +{ + egg_tree_model_filter_real_unref_node (model, iter, TRUE); +} + +static void +egg_tree_model_filter_real_unref_node (GtkTreeModel *model, + GtkTreeIter *iter, + gboolean propagate_unref) +{ + EggTreeModelFilter *filter = (EggTreeModelFilter *)model; + FilterLevel *level; + FilterElt *elt; + + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model)); + g_return_if_fail (filter->child_model != NULL); + g_return_if_fail (filter->stamp == iter->stamp); + + if (propagate_unref) + { + GtkTreeIter child_iter; + egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter); + gtk_tree_model_unref_node (filter->child_model, &child_iter); + } + + level = iter->user_data; + elt = iter->user_data2; + + g_return_if_fail (elt->ref_count > 0); + + elt->ref_count--; + level->ref_count--; + if (level->ref_count == 0) + { + FilterLevel *parent_level = level->parent_level; + FilterElt *parent_elt = level->parent_elt; + + /* we are at zero -- time to increase the zero_ref_count val */ + while (parent_level) + { + parent_elt->zero_ref_count++; + + parent_elt = parent_level->parent_elt; + parent_level = parent_level->parent_level; + } + filter->zero_ref_count++; + } + +#ifdef VERBOSE + g_print ("unreffed %p\n", iter->user_data2); + g_print ("zero ref count is now %d\n", filter->zero_ref_count); +#endif +} + +/* bits and pieces */ +static void +egg_tree_model_filter_set_model (EggTreeModelFilter *filter, + GtkTreeModel *child_model) +{ + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); + + if (filter->child_model) + { + g_signal_handler_disconnect (G_OBJECT (filter->child_model), + filter->changed_id); + g_signal_handler_disconnect (G_OBJECT (filter->child_model), + filter->inserted_id); + g_signal_handler_disconnect (G_OBJECT (filter->child_model), + filter->has_child_toggled_id); + g_signal_handler_disconnect (G_OBJECT (filter->child_model), + filter->deleted_id); + g_signal_handler_disconnect (G_OBJECT (filter->child_model), + filter->reordered_id); + + /* reset our state */ + if (filter->root) + egg_tree_model_filter_free_level (filter, filter->root); + + filter->root = NULL; + g_object_unref (G_OBJECT (filter->child_model)); + filter->visible_column = -1; + /* FIXME: destroy more crack here? the funcs? */ + } + + filter->child_model = child_model; + + if (child_model) + { + g_object_ref (G_OBJECT (filter->child_model)); + filter->changed_id = + g_signal_connect (child_model, "row_changed", + G_CALLBACK (egg_tree_model_filter_row_changed), + filter); + filter->inserted_id = + g_signal_connect (child_model, "row_inserted", + G_CALLBACK (egg_tree_model_filter_row_inserted), + filter); + filter->has_child_toggled_id = + g_signal_connect (child_model, "row_has_child_toggled", + G_CALLBACK (egg_tree_model_filter_row_has_child_toggled), + filter); + filter->deleted_id = + g_signal_connect (child_model, "row_deleted", + G_CALLBACK (egg_tree_model_filter_row_deleted), + filter); + filter->reordered_id = + g_signal_connect (child_model, "rows_reordered", + G_CALLBACK (egg_tree_model_filter_rows_reordered), + filter); + + filter->child_flags = gtk_tree_model_get_flags (child_model); + filter->stamp = g_random_int (); + } +} + +static void +egg_tree_model_filter_set_root (EggTreeModelFilter *filter, + GtkTreePath *root) +{ + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); + + if (!root) + filter->virtual_root = NULL; + else + filter->virtual_root = gtk_tree_path_copy (root); +} + +/* public API */ + +GtkTreeModel * +egg_tree_model_filter_new (GtkTreeModel *child_model, + GtkTreePath *root) +{ + GtkTreeModel *retval; + + g_return_val_if_fail (GTK_IS_TREE_MODEL (child_model), NULL); + + retval = GTK_TREE_MODEL (g_object_new (egg_tree_model_filter_get_type (), NULL)); + + egg_tree_model_filter_set_model (EGG_TREE_MODEL_FILTER (retval), + child_model); + egg_tree_model_filter_set_root (EGG_TREE_MODEL_FILTER (retval), root); + + return retval; +} + +GtkTreeModel * +egg_tree_model_filter_get_model (EggTreeModelFilter *filter) +{ + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter), NULL); + + return filter->child_model; +} + +void +egg_tree_model_filter_set_visible_func (EggTreeModelFilter *filter, + EggTreeModelFilterVisibleFunc func, + gpointer data, + GtkDestroyNotify destroy) +{ + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); + g_return_if_fail (func != NULL); + g_return_if_fail (filter->visible_method_set == FALSE); + + if (filter->visible_func) + { + GtkDestroyNotify d = filter->visible_destroy; + + filter->visible_destroy = NULL; + d (filter->visible_data); + } + + filter->visible_func = func; + filter->visible_data = data; + filter->visible_destroy = destroy; + + filter->visible_method_set = TRUE; +} + +void +egg_tree_model_filter_set_modify_func (EggTreeModelFilter *filter, + gint n_columns, + GType *types, + EggTreeModelFilterModifyFunc func, + gpointer data, + GtkDestroyNotify destroy) +{ + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); + g_return_if_fail (func != NULL); + g_return_if_fail (filter->modify_func_set == FALSE); + + if (filter->modify_destroy) + { + GtkDestroyNotify d = filter->modify_destroy; + + filter->modify_destroy = NULL; + d (filter->modify_data); + } + + filter->modify_n_columns = n_columns; + filter->modify_types = g_new0 (GType, n_columns); + memcpy (filter->modify_types, types, sizeof (GType) * n_columns); + filter->modify_func = func; + filter->modify_data = data; + filter->modify_destroy = destroy; + + filter->modify_func_set = TRUE; +} + +void +egg_tree_model_filter_set_visible_column (EggTreeModelFilter *filter, + gint column) +{ + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); + g_return_if_fail (column >= 0); + g_return_if_fail (filter->visible_method_set == FALSE); + + filter->visible_column = column; + + filter->visible_method_set = TRUE; +} + +/* conversion */ +void +egg_tree_model_filter_convert_child_iter_to_iter (EggTreeModelFilter *filter, + GtkTreeIter *filter_iter, + GtkTreeIter *child_iter) +{ + GtkTreePath *child_path, *path; + + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); + g_return_if_fail (filter->child_model != NULL); + g_return_if_fail (filter_iter != NULL); + g_return_if_fail (child_iter != NULL); + + filter_iter->stamp = 0; + + child_path = gtk_tree_model_get_path (filter->child_model, child_iter); + g_return_if_fail (child_path != NULL); + + path = egg_tree_model_filter_convert_child_path_to_path (filter, + child_path); + gtk_tree_path_free (child_path); + g_return_if_fail (path != NULL); + + gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), filter_iter, path); + gtk_tree_path_free (path); +} + +void +egg_tree_model_filter_convert_iter_to_child_iter (EggTreeModelFilter *filter, + GtkTreeIter *child_iter, + GtkTreeIter *filter_iter) +{ + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); + g_return_if_fail (filter->child_model != NULL); + g_return_if_fail (child_iter != NULL); + g_return_if_fail (filter_iter != NULL); + g_return_if_fail (filter_iter->stamp == filter->stamp); + + if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter)) + { + *child_iter = FILTER_ELT (filter_iter->user_data2)->iter; + } + else + { + GtkTreePath *path; + + path = egg_tree_model_filter_elt_get_path (filter_iter->user_data, + filter_iter->user_data2, + NULL); + gtk_tree_model_get_iter (filter->child_model, child_iter, path); + gtk_tree_path_free (path); + } +} + +static GtkTreePath * +egg_real_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter *filter, + GtkTreePath *child_path, + gboolean build_levels, + gboolean fetch_childs) +{ + gint *child_indices; + GtkTreePath *retval; + GtkTreePath *real_path; + FilterLevel *level; + gint i; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter), NULL); + g_return_val_if_fail (filter->child_model != NULL, NULL); + g_return_val_if_fail (child_path != NULL, NULL); + + if (!filter->virtual_root) + real_path = gtk_tree_path_copy (child_path); + else + real_path = egg_tree_model_filter_remove_root (child_path, + filter->virtual_root); + + if (!real_path) + return NULL; + + retval = gtk_tree_path_new (); + child_indices = gtk_tree_path_get_indices (real_path); + + if (filter->root == NULL && build_levels) + egg_tree_model_filter_build_level (filter, NULL, NULL); + level = FILTER_LEVEL (filter->root); + + for (i = 0; i < gtk_tree_path_get_depth (real_path); i++) + { + gint j; + gboolean found_child = FALSE; + + if (!level) + { + gtk_tree_path_free (real_path); + gtk_tree_path_free (retval); + return NULL; + } + + for (j = 0; j < level->array->len; j++) + { + if ((g_array_index (level->array, FilterElt, j)).offset == child_indices[i]) + { + gtk_tree_path_append_index (retval, j); + if (g_array_index (level->array, FilterElt, j).children == NULL && build_levels) + egg_tree_model_filter_build_level (filter, + level, + &g_array_index (level->array, FilterElt, j)); + level = g_array_index (level->array, FilterElt, j).children; + found_child = TRUE; + break; + } + } + + if (!found_child && fetch_childs) + { + /* didn't find the child, let's try to bring it back */ + if (!egg_tree_model_filter_fetch_child (filter, level, child_indices[i])) + { + /* not there */ + gtk_tree_path_free (real_path); + gtk_tree_path_free (retval); + return NULL; + } + + /* yay, let's search for the child again */ + for (j = 0; j < level->array->len; j++) + { + if ((g_array_index (level->array, FilterElt, j)).offset == child_indices[i]) + { + gtk_tree_path_append_index (retval, j); + if (g_array_index (level->array, FilterElt, j).children == NULL && build_levels) + egg_tree_model_filter_build_level (filter, + level, + &g_array_index (level->array, FilterElt, j)); + level = g_array_index (level->array, FilterElt, j).children; + found_child = TRUE; + break; + } + } + + if (!found_child) + { + /* our happy fun fetch attempt failed ?!?!?! no child! */ + gtk_tree_path_free (real_path); + gtk_tree_path_free (retval); + return NULL; + } + } + else if (!found_child && !fetch_childs) + { + /* no path */ + gtk_tree_path_free (real_path); + gtk_tree_path_free (retval); + return NULL; + } + } + + gtk_tree_path_free (real_path); + return retval; +} + +GtkTreePath * +egg_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter *filter, + GtkTreePath *child_path) +{ + /* this function does the sanity checks */ + return egg_real_tree_model_filter_convert_child_path_to_path (filter, + child_path, + TRUE, + TRUE); +} + +GtkTreePath * +egg_tree_model_filter_convert_path_to_child_path (EggTreeModelFilter *filter, + GtkTreePath *filter_path) +{ + gint *filter_indices; + GtkTreePath *retval; + FilterLevel *level; + gint i; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter), NULL); + g_return_val_if_fail (filter->child_model != NULL, NULL); + g_return_val_if_fail (filter_path != NULL, NULL); + + /* convert path */ + retval = gtk_tree_path_new (); + filter_indices = gtk_tree_path_get_indices (filter_path); + if (!filter->root) + egg_tree_model_filter_build_level (filter, NULL, NULL); + level = FILTER_LEVEL (filter->root); + + for (i = 0; i < gtk_tree_path_get_depth (filter_path); i++) + { + gint count = filter_indices[i]; + + if (!level || level->array->len <= filter_indices[i]) + { + gtk_tree_path_free (retval); + return NULL; + } + + if (g_array_index (level->array, FilterElt, count).children == NULL) + egg_tree_model_filter_build_level (filter, level, &g_array_index (level->array, FilterElt, count)); + + if (!level || level->array->len <= filter_indices[i]) + { + gtk_tree_path_free (retval); + return NULL; + } + + gtk_tree_path_append_index (retval, g_array_index (level->array, FilterElt, count).offset); + level = g_array_index (level->array, FilterElt, count).children; + } + + /* apply vroot */ + + if (filter->virtual_root) + { + GtkTreePath *real_retval; + + real_retval = egg_tree_model_filter_add_root (retval, + filter->virtual_root); + gtk_tree_path_free (retval); + + return real_retval; + } + + return retval; +} + +void +egg_tree_model_filter_clear_cache (EggTreeModelFilter *filter) +{ + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); + + if (filter->zero_ref_count) + egg_tree_model_filter_clear_cache_helper (filter, + FILTER_LEVEL (filter->root)); +} diff --git a/lib/widgets/eggtreemodelfilter.h b/lib/widgets/eggtreemodelfilter.h new file mode 100644 index 000000000..ada78c1be --- /dev/null +++ b/lib/widgets/eggtreemodelfilter.h @@ -0,0 +1,123 @@ +/* eggtreemodelfilter.h + * Copyright (C) 2000,2001 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com> + * Copyright (C) 2001,2002 Kristian Rietveld <kris@gtk.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EGG_TREE_MODEL_FILTER_H__ +#define __EGG_TREE_MODEL_FILTER_H__ + +#include <gtk/gtktreemodel.h> + +G_BEGIN_DECLS + +#define EGG_TYPE_TREE_MODEL_FILTER (egg_tree_model_filter_get_type ()) +#define EGG_TREE_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TREE_MODEL_FILTER, EggTreeModelFilter)) +#define EGG_TREE_MODEL_FILTER_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), EGG_TYPE_TREE_MODEL_FILTER, EggTreeModelFilterClass)) +#define EGG_IS_TREE_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TREE_MODEL_FILTER)) +#define EGG_IS_TREE_MODEL_FILTER_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), EGG_TYPE_TREE_MODEL_FILTER)) +#define EGG_TREE_MODEL_FILTER_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TREE_MODEL_FILTER, EggTreeModelFilterClass)) + +typedef gboolean (* EggTreeModelFilterVisibleFunc) (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data); +typedef void (* EggTreeModelFilterModifyFunc) (GtkTreeModel *model, + GtkTreeIter *iter, + GValue *value, + gint column, + gpointer data); + +typedef struct _EggTreeModelFilter EggTreeModelFilter; +typedef struct _EggTreeModelFilterClass EggTreeModelFilterClass; + +struct _EggTreeModelFilter +{ + GObject parent; + + /*< private >*/ + gpointer root; + gint stamp; + guint child_flags; + GtkTreeModel *child_model; + gint zero_ref_count; + + GtkTreePath *virtual_root; + + EggTreeModelFilterVisibleFunc visible_func; + gpointer visible_data; + GtkDestroyNotify visible_destroy; + + gint modify_n_columns; + GType *modify_types; + EggTreeModelFilterModifyFunc modify_func; + gpointer modify_data; + gpointer modify_destroy; + + gint visible_column; + + gboolean visible_method_set; + gboolean modify_func_set; + + /* signal ids */ + guint changed_id; + guint inserted_id; + guint has_child_toggled_id; + guint deleted_id; + guint reordered_id; +}; + +struct _EggTreeModelFilterClass +{ + GObjectClass parent_class; +}; + +GType egg_tree_model_filter_get_type (void); +GtkTreeModel * egg_tree_model_filter_new (GtkTreeModel *child_model, + GtkTreePath *root); +void egg_tree_model_filter_set_visible_func (EggTreeModelFilter *filter, + EggTreeModelFilterVisibleFunc func, + gpointer data, + GtkDestroyNotify destroy); +void egg_tree_model_filter_set_modify_func (EggTreeModelFilter *filter, + gint n_columns, + GType *types, + EggTreeModelFilterModifyFunc func, + gpointer data, + GtkDestroyNotify destroy); +void egg_tree_model_filter_set_visible_column (EggTreeModelFilter *filter, + gint column); + +GtkTreeModel *egg_tree_model_filter_get_model (EggTreeModelFilter *filter); + +/* conversion */ +void egg_tree_model_filter_convert_child_iter_to_iter (EggTreeModelFilter *filter, + GtkTreeIter *filter_iter, + GtkTreeIter *child_iter); +void egg_tree_model_filter_convert_iter_to_child_iter (EggTreeModelFilter *filter, + GtkTreeIter *child_iter, + GtkTreeIter *filter_iter); +GtkTreePath *egg_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter *filter, + GtkTreePath *child_path); +GtkTreePath *egg_tree_model_filter_convert_path_to_child_path (EggTreeModelFilter *path, + GtkTreePath *filter_path); + + +void egg_tree_model_filter_clear_cache (EggTreeModelFilter *filter); + +G_END_DECLS + +#endif /* __EGG_TREE_MODEL_FILTER_H__ */ diff --git a/lib/widgets/eggtreemultidnd.c b/lib/widgets/eggtreemultidnd.c new file mode 100644 index 000000000..8be54f442 --- /dev/null +++ b/lib/widgets/eggtreemultidnd.c @@ -0,0 +1,415 @@ +/* eggtreemultidnd.c + * Copyright (C) 2001 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <string.h> +#include <gtk/gtktreeselection.h> +#include <gtk/gtksignal.h> +#include <gtk/gtkwidget.h> +#include <gtk/gtkmain.h> +#include "eggtreemultidnd.h" + +#define EGG_TREE_MULTI_DND_STRING "EggTreeMultiDndString" + +typedef struct +{ + guint pressed_button; + gint x; + gint y; + guint motion_notify_handler; + guint button_release_handler; + guint drag_data_get_handler; + GSList *event_list; +} EggTreeMultiDndData; + +/* CUT-N-PASTE from gtktreeview.c */ +typedef struct _TreeViewDragInfo TreeViewDragInfo; +struct _TreeViewDragInfo +{ + GdkModifierType start_button_mask; + GtkTargetList *source_target_list; + GdkDragAction source_actions; + + GtkTargetList *dest_target_list; + + guint source_set : 1; + guint dest_set : 1; +}; + + +GType +egg_tree_multi_drag_source_get_type (void) +{ + static GType our_type = 0; + + if (!our_type) + { + static const GTypeInfo our_info = + { + sizeof (EggTreeMultiDragSourceIface), /* class_size */ + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL + }; + + our_type = g_type_register_static (G_TYPE_INTERFACE, "EggTreeMultiDragSource", &our_info, 0); + } + + return our_type; +} + + +/** + * egg_tree_multi_drag_source_row_draggable: + * @drag_source: a #EggTreeMultiDragSource + * @path: row on which user is initiating a drag + * + * Asks the #EggTreeMultiDragSource whether a particular row can be used as + * the source of a DND operation. If the source doesn't implement + * this interface, the row is assumed draggable. + * + * Return value: %TRUE if the row can be dragged + **/ +gboolean +egg_tree_multi_drag_source_row_draggable (EggTreeMultiDragSource *drag_source, + GList *path_list) +{ + EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source); + + g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE); + g_return_val_if_fail (iface->row_draggable != NULL, FALSE); + g_return_val_if_fail (path_list != NULL, FALSE); + + if (iface->row_draggable) + return (* iface->row_draggable) (drag_source, path_list); + else + return TRUE; +} + + +/** + * egg_tree_multi_drag_source_drag_data_delete: + * @drag_source: a #EggTreeMultiDragSource + * @path: row that was being dragged + * + * Asks the #EggTreeMultiDragSource to delete the row at @path, because + * it was moved somewhere else via drag-and-drop. Returns %FALSE + * if the deletion fails because @path no longer exists, or for + * some model-specific reason. Should robustly handle a @path no + * longer found in the model! + * + * Return value: %TRUE if the row was successfully deleted + **/ +gboolean +egg_tree_multi_drag_source_drag_data_delete (EggTreeMultiDragSource *drag_source, + GList *path_list) +{ + EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source); + + g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE); + g_return_val_if_fail (iface->drag_data_delete != NULL, FALSE); + g_return_val_if_fail (path_list != NULL, FALSE); + + return (* iface->drag_data_delete) (drag_source, path_list); +} + +/** + * egg_tree_multi_drag_source_drag_data_get: + * @drag_source: a #EggTreeMultiDragSource + * @path: row that was dragged + * @selection_data: a #EggSelectionData to fill with data from the dragged row + * + * Asks the #EggTreeMultiDragSource to fill in @selection_data with a + * representation of the row at @path. @selection_data->target gives + * the required type of the data. Should robustly handle a @path no + * longer found in the model! + * + * Return value: %TRUE if data of the required type was provided + **/ +gboolean +egg_tree_multi_drag_source_drag_data_get (EggTreeMultiDragSource *drag_source, + GList *path_list, + guint info, + GtkSelectionData *selection_data) +{ + EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source); + + g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE); + g_return_val_if_fail (iface->drag_data_get != NULL, FALSE); + g_return_val_if_fail (path_list != NULL, FALSE); + g_return_val_if_fail (selection_data != NULL, FALSE); + + return (* iface->drag_data_get) (drag_source, path_list, info, selection_data); +} + +static void +stop_drag_check (GtkWidget *widget) +{ + EggTreeMultiDndData *priv_data; + GSList *l; + + priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING); + + for (l = priv_data->event_list; l != NULL; l = l->next) + gdk_event_free (l->data); + + g_slist_free (priv_data->event_list); + priv_data->event_list = NULL; + g_signal_handler_disconnect (widget, priv_data->motion_notify_handler); + g_signal_handler_disconnect (widget, priv_data->button_release_handler); +} + +static gboolean +egg_tree_multi_drag_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + EggTreeMultiDndData *priv_data; + GSList *l; + + priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING); + + for (l = priv_data->event_list; l != NULL; l = l->next) + gtk_propagate_event (widget, l->data); + + stop_drag_check (widget); + + return FALSE; +} + +static void +selection_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + GList **list_ptr; + + list_ptr = (GList **) data; + + *list_ptr = g_list_prepend (*list_ptr, gtk_tree_row_reference_new (model, path)); +} + +static void +path_list_free (GList *path_list) +{ + g_list_foreach (path_list, (GFunc) gtk_tree_row_reference_free, NULL); + g_list_free (path_list); +} + +static void +set_context_data (GdkDragContext *context, + GList *path_list) +{ + g_object_set_data_full (G_OBJECT (context), + "egg-tree-view-multi-source-row", + path_list, + (GDestroyNotify) path_list_free); +} + +static GList * +get_context_data (GdkDragContext *context) +{ + return g_object_get_data (G_OBJECT (context), + "egg-tree-view-multi-source-row"); +} + +/* CUT-N-PASTE from gtktreeview.c */ +static TreeViewDragInfo* +get_info (GtkTreeView *tree_view) +{ + return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info"); +} + + +static void +egg_tree_multi_drag_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + GtkTreeView *tree_view; + GtkTreeModel *model; + TreeViewDragInfo *di; + GList *path_list; + + tree_view = GTK_TREE_VIEW (widget); + + model = gtk_tree_view_get_model (tree_view); + + if (model == NULL) + return; + + di = get_info (GTK_TREE_VIEW (widget)); + + if (di == NULL) + return; + + path_list = get_context_data (context); + + if (path_list == NULL) + return; + + /* We can implement the GTK_TREE_MODEL_ROW target generically for + * any model; for DragSource models there are some other targets + * we also support. + */ + + if (EGG_IS_TREE_MULTI_DRAG_SOURCE (model)) + { + egg_tree_multi_drag_source_drag_data_get (EGG_TREE_MULTI_DRAG_SOURCE (model), + path_list, + info, + selection_data); + } +} + +static gboolean +egg_tree_multi_drag_motion_event (GtkWidget *widget, + GdkEventMotion *event, + gpointer data) +{ + EggTreeMultiDndData *priv_data; + + priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING); + + if (gtk_drag_check_threshold (widget, + priv_data->x, + priv_data->y, + event->x, + event->y)) + { + GList *path_list = NULL; + GtkTreeSelection *selection; + GtkTreeModel *model; + GdkDragContext *context; + TreeViewDragInfo *di; + + di = get_info (GTK_TREE_VIEW (widget)); + + if (di == NULL) + return FALSE; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + stop_drag_check (widget); + gtk_tree_selection_selected_foreach (selection, selection_foreach, &path_list); + path_list = g_list_reverse (path_list); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); + + if (egg_tree_multi_drag_source_row_draggable (EGG_TREE_MULTI_DRAG_SOURCE (model), path_list)) + { + context = gtk_drag_begin (widget, + di->source_target_list, + di->source_actions, + priv_data->pressed_button, + (GdkEvent*)event); + set_context_data (context, path_list); + } + else + { + path_list_free (path_list); + } + } + + return TRUE; +} + +static gboolean +egg_tree_multi_drag_button_press_event (GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + GtkTreeView *tree_view; + GtkTreePath *path = NULL; + GtkTreeViewColumn *column = NULL; + gint cell_x, cell_y; + GtkTreeSelection *selection; + EggTreeMultiDndData *priv_data; + + if (event->button == 3) + return FALSE; + + tree_view = GTK_TREE_VIEW (widget); + priv_data = g_object_get_data (G_OBJECT (tree_view), EGG_TREE_MULTI_DND_STRING); + if (priv_data == NULL) + { + priv_data = g_new0 (EggTreeMultiDndData, 1); + g_object_set_data (G_OBJECT (tree_view), EGG_TREE_MULTI_DND_STRING, priv_data); + } + + if (g_slist_find (priv_data->event_list, event)) + return FALSE; + + if (priv_data->event_list) + { + /* save the event to be propagated in order */ + priv_data->event_list = g_slist_append (priv_data->event_list, gdk_event_copy ((GdkEvent*)event)); + return TRUE; + } + + if (event->type == GDK_2BUTTON_PRESS) + return FALSE; + + gtk_tree_view_get_path_at_pos (tree_view, + event->x, event->y, + &path, &column, + &cell_x, &cell_y); + + selection = gtk_tree_view_get_selection (tree_view); + + if (path && gtk_tree_selection_path_is_selected (selection, path)) + { + priv_data->pressed_button = event->button; + priv_data->x = event->x; + priv_data->y = event->y; + priv_data->event_list = g_slist_append (priv_data->event_list, gdk_event_copy ((GdkEvent*)event)); + priv_data->motion_notify_handler = + g_signal_connect (G_OBJECT (tree_view), "motion_notify_event", G_CALLBACK (egg_tree_multi_drag_motion_event), NULL); + priv_data->button_release_handler = + g_signal_connect (G_OBJECT (tree_view), "button_release_event", G_CALLBACK (egg_tree_multi_drag_button_release_event), NULL); + + if (priv_data->drag_data_get_handler == 0) + { + priv_data->drag_data_get_handler = + g_signal_connect (G_OBJECT (tree_view), "drag_data_get", G_CALLBACK (egg_tree_multi_drag_drag_data_get), NULL); + } + + return TRUE; + } + + if (path) + { + gtk_tree_path_free (path); + } + + return FALSE; +} + +void +egg_tree_multi_drag_add_drag_support (GtkTreeView *tree_view) +{ + g_return_if_fail (GTK_IS_TREE_VIEW (tree_view)); + g_signal_connect (G_OBJECT (tree_view), "button_press_event", G_CALLBACK (egg_tree_multi_drag_button_press_event), NULL); +} + diff --git a/lib/widgets/eggtreemultidnd.h b/lib/widgets/eggtreemultidnd.h new file mode 100644 index 000000000..460e60239 --- /dev/null +++ b/lib/widgets/eggtreemultidnd.h @@ -0,0 +1,78 @@ +/* eggtreednd.h + * Copyright (C) 2001 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EGG_TREE_MULTI_DND_H__ +#define __EGG_TREE_MULTI_DND_H__ + +#include <gtk/gtktreemodel.h> +#include <gtk/gtktreeview.h> +#include <gtk/gtkdnd.h> + +G_BEGIN_DECLS + +#define EGG_TYPE_TREE_MULTI_DRAG_SOURCE (egg_tree_multi_drag_source_get_type ()) +#define EGG_TREE_MULTI_DRAG_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE, EggTreeMultiDragSource)) +#define EGG_IS_TREE_MULTI_DRAG_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE)) +#define EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE, EggTreeMultiDragSourceIface)) + +typedef struct _EggTreeMultiDragSource EggTreeMultiDragSource; /* Dummy typedef */ +typedef struct _EggTreeMultiDragSourceIface EggTreeMultiDragSourceIface; + +struct _EggTreeMultiDragSourceIface +{ + GTypeInterface g_iface; + + /* VTable - not signals */ + gboolean (* row_draggable) (EggTreeMultiDragSource *drag_source, + GList *path_list); + + gboolean (* drag_data_get) (EggTreeMultiDragSource *drag_source, + GList *path_list, + guint info, + GtkSelectionData *selection_data); + + gboolean (* drag_data_delete) (EggTreeMultiDragSource *drag_source, + GList *path_list); +}; + +GType egg_tree_multi_drag_source_get_type (void) G_GNUC_CONST; + +/* Returns whether the given row can be dragged */ +gboolean egg_tree_multi_drag_source_row_draggable (EggTreeMultiDragSource *drag_source, + GList *path_list); + +/* Deletes the given row, or returns FALSE if it can't */ +gboolean egg_tree_multi_drag_source_drag_data_delete (EggTreeMultiDragSource *drag_source, + GList *path_list); + + +/* Fills in selection_data with type selection_data->target based on the row + * denoted by path, returns TRUE if it does anything + */ +gboolean egg_tree_multi_drag_source_drag_data_get (EggTreeMultiDragSource *drag_source, + GList *path_list, + guint info, + GtkSelectionData *selection_data); +void egg_tree_multi_drag_add_drag_support (GtkTreeView *tree_view); + + + +G_END_DECLS + +#endif /* __EGG_TREE_MULTI_DND_H__ */ diff --git a/lib/widgets/ephy-autocompletion-window.c b/lib/widgets/ephy-autocompletion-window.c new file mode 100644 index 000000000..9c639a52a --- /dev/null +++ b/lib/widgets/ephy-autocompletion-window.c @@ -0,0 +1,854 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <libgnome/gnome-i18n.h> +#include <gtk/gtkcellrenderertext.h> +#include <gtk/gtktreeview.h> +#include <gtk/gtkscrolledwindow.h> +#include <gtk/gtktreeselection.h> +#include <gtk/gtkliststore.h> +#include <gtk/gtkwindow.h> +#include <gtk/gtkmain.h> +#include <gtk/gtkvbox.h> +#include <gdk/gdkkeysyms.h> +#include <gtk/gtkframe.h> + +#include "ephy-autocompletion-window.h" +#include "ephy-gobject-misc.h" +#include "ephy-string.h" +#include "ephy-marshal.h" +#include "ephy-gui.h" + +/* This is copied from gtkscrollbarwindow.c */ +#define DEFAULT_SCROLLBAR_SPACING 3 + +#define SCROLLBAR_SPACING(w) \ + (GTK_SCROLLED_WINDOW_GET_CLASS (w)->scrollbar_spacing >= 0 ? \ + GTK_SCROLLED_WINDOW_GET_CLASS (w)->scrollbar_spacing : DEFAULT_SCROLLBAR_SPACING) + +#define MAX_VISIBLE_ROWS 9 +#define MAX_COMPLETION_ALTERNATIVES 7 + +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +//#define DEBUG_TIME + +#ifdef DEBUG_TIME +#include <glib/gtimer.h> +#endif + +/** + * Private data + */ +struct _EphyAutocompletionWindowPrivate { + EphyAutocompletion *autocompletion; + GtkWidget *parent; + + GtkWidget *window; + GtkScrolledWindow *scrolled_window; + GtkTreeView *tree_view; + GtkTreeViewColumn *col1; + GtkTreeView *action_tree_view; + GtkTreeViewColumn *action_col1; + GtkTreeView *active_tree_view; + gboolean only_actions; + + char *selected; + + GtkListStore *list_store; + GtkListStore *action_list_store; + guint last_added_match; + int view_nitems; + + gboolean shown; +}; + +/** + * Private functions, only availble from this file + */ +static void ephy_autocompletion_window_class_init (EphyAutocompletionWindowClass *klass); +static void ephy_autocompletion_window_init (EphyAutocompletionWindow *aw); +static void ephy_autocompletion_window_finalize_impl (GObject *o); +static void ephy_autocompletion_window_init_widgets (EphyAutocompletionWindow *aw); +static void ephy_autocompletion_window_selection_changed_cb (GtkTreeSelection *treeselection, + EphyAutocompletionWindow *aw); +static gboolean ephy_autocompletion_window_button_press_event_cb (GtkWidget *widget, + GdkEventButton *event, + EphyAutocompletionWindow *aw); +static gboolean ephy_autocompletion_window_key_press_cb (GtkWidget *widget, + GdkEventKey *event, + EphyAutocompletionWindow *aw); +static void ephy_autocompletion_window_event_after_cb (GtkWidget *wid, GdkEvent *event, + EphyAutocompletionWindow *aw); +static void ephy_autocompletion_window_fill_store_chunk (EphyAutocompletionWindow *aw); + + +static gpointer g_object_class; + +enum EphyAutocompletionWindowSignalsEnum { + ACTIVATED, + EPHY_AUTOCOMPLETION_WINDOW_HIDDEN, + EPHY_AUTOCOMPLETION_WINDOW_LAST_SIGNAL +}; +static gint EphyAutocompletionWindowSignals[EPHY_AUTOCOMPLETION_WINDOW_LAST_SIGNAL]; + +/** + * AutocompletionWindow object + */ + +MAKE_GET_TYPE (ephy_autocompletion_window, "EphyAutocompletionWindow", EphyAutocompletionWindow, + ephy_autocompletion_window_class_init, + ephy_autocompletion_window_init, G_TYPE_OBJECT); + +static void +ephy_autocompletion_window_class_init (EphyAutocompletionWindowClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = ephy_autocompletion_window_finalize_impl; + g_object_class = g_type_class_peek_parent (klass); + + EphyAutocompletionWindowSignals[ACTIVATED] = g_signal_new ( + "activated", G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP, + G_STRUCT_OFFSET (EphyAutocompletionWindowClass, activated), + NULL, NULL, + ephy_marshal_VOID__STRING_INT, + G_TYPE_NONE, + 2, + G_TYPE_STRING, + G_TYPE_INT); + + EphyAutocompletionWindowSignals[EPHY_AUTOCOMPLETION_WINDOW_HIDDEN] = g_signal_new ( + "hidden", G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP, + G_STRUCT_OFFSET (EphyAutocompletionWindowClass, hidden), + NULL, NULL, + ephy_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +ephy_autocompletion_window_init (EphyAutocompletionWindow *aw) +{ + EphyAutocompletionWindowPrivate *p = g_new0 (EphyAutocompletionWindowPrivate, 1); + GtkTreeSelection *s; + + aw->priv = p; + p->selected = NULL; + + ephy_autocompletion_window_init_widgets (aw); + + s = gtk_tree_view_get_selection (p->tree_view); + /* I would like to use GTK_SELECTION_SINGLE, but it seems to require that one + item is selected always */ + gtk_tree_selection_set_mode (s, GTK_SELECTION_MULTIPLE); + + g_signal_connect (s, "changed", G_CALLBACK (ephy_autocompletion_window_selection_changed_cb), aw); + + s = gtk_tree_view_get_selection (p->action_tree_view); + gtk_tree_selection_set_mode (s, GTK_SELECTION_MULTIPLE); + + g_signal_connect (s, "changed", G_CALLBACK (ephy_autocompletion_window_selection_changed_cb), aw); +} + +static void +ephy_autocompletion_window_finalize_impl (GObject *o) +{ + EphyAutocompletionWindow *aw = EPHY_AUTOCOMPLETION_WINDOW (o); + EphyAutocompletionWindowPrivate *p = aw->priv; + + if (p->list_store) g_object_unref (p->list_store); + if (p->action_list_store) g_object_unref (p->action_list_store); + if (p->parent) g_object_unref (p->parent); + if (p->window) gtk_widget_destroy (p->window); + + if (p->autocompletion) + { + g_signal_handlers_disconnect_matched (p->autocompletion, G_SIGNAL_MATCH_DATA, 0, 0, + NULL, NULL, aw); + g_object_unref (p->autocompletion); + } + + g_free (p->selected); + g_free (p); + + gdk_pointer_ungrab (GDK_CURRENT_TIME); + gdk_keyboard_ungrab (GDK_CURRENT_TIME); + + G_OBJECT_CLASS (g_object_class)->finalize (o); +} + +static void +ephy_autocompletion_window_init_widgets (EphyAutocompletionWindow *aw) +{ + EphyAutocompletionWindowPrivate *p = aw->priv; + GtkWidget *sw; + GtkCellRenderer *renderer; + GtkWidget *frame; + GtkWidget *vbox; + GdkColor *bg_color; + guint32 base, dark; + GValue v = { 0 }; + + p->window = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_resizable (GTK_WINDOW (p->window), FALSE); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), + GTK_SHADOW_OUT); + gtk_container_add (GTK_CONTAINER (p->window), frame); + gtk_widget_show (frame); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (frame), vbox); + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_box_pack_start (GTK_BOX (vbox), + sw, TRUE, TRUE, 0); + gtk_scrolled_window_set_shadow_type + (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + p->scrolled_window = GTK_SCROLLED_WINDOW (sw); + gtk_widget_show (sw); + + p->tree_view = GTK_TREE_VIEW (gtk_tree_view_new ()); + gtk_container_add (GTK_CONTAINER (sw), GTK_WIDGET (p->tree_view)); + + renderer = gtk_cell_renderer_text_new (); + p->col1 = gtk_tree_view_column_new (); + gtk_tree_view_column_pack_start (p->col1, renderer, TRUE); + gtk_tree_view_column_set_attributes (p->col1, renderer, + "text", 0, + NULL); + gtk_tree_view_append_column (p->tree_view, p->col1); + + gtk_tree_view_set_headers_visible (p->tree_view, FALSE); + gtk_widget_show (GTK_WIDGET(p->tree_view)); + + p->action_tree_view = GTK_TREE_VIEW (gtk_tree_view_new ()); + gtk_box_pack_start (GTK_BOX (vbox), + GTK_WIDGET (p->action_tree_view), + FALSE, TRUE, 0); + + renderer = gtk_cell_renderer_text_new (); + + g_value_init (&v, GDK_TYPE_COLOR); + g_object_get_property (G_OBJECT (renderer), "cell_background_gdk", &v); + bg_color = g_value_peek_pointer (&v); + base = ephy_gui_gdk_color_to_rgb (bg_color); + dark = ephy_gui_rgb_shift_color (base, 0.15); + *bg_color = ephy_gui_gdk_rgb_to_color (dark); + g_object_set_property (G_OBJECT (renderer), "cell_background_gdk", &v); + + p->action_col1 = gtk_tree_view_column_new (); + gtk_tree_view_column_pack_start (p->action_col1, renderer, TRUE); + gtk_tree_view_column_set_attributes (p->action_col1, renderer, + "text", 0, + NULL); + gtk_tree_view_append_column (p->action_tree_view, p->action_col1); + + gtk_tree_view_set_headers_visible (p->action_tree_view, FALSE); + gtk_widget_show (GTK_WIDGET(p->action_tree_view)); +} + +EphyAutocompletionWindow * +ephy_autocompletion_window_new (EphyAutocompletion *ac, GtkWidget *w) +{ + EphyAutocompletionWindow *ret = g_object_new (EPHY_TYPE_AUTOCOMPLETION_WINDOW, NULL); + ephy_autocompletion_window_set_parent_widget (ret, w); + ephy_autocompletion_window_set_autocompletion (ret, ac); + return ret; +} + +void +ephy_autocompletion_window_set_parent_widget (EphyAutocompletionWindow *aw, GtkWidget *w) +{ + if (aw->priv->parent) g_object_unref (aw->priv->parent); + aw->priv->parent = g_object_ref (w); +} + +void +ephy_autocompletion_window_set_autocompletion (EphyAutocompletionWindow *aw, + EphyAutocompletion *ac) +{ + EphyAutocompletionWindowPrivate *p = aw->priv; + + if (p->autocompletion) + { + g_signal_handlers_disconnect_matched (p->autocompletion, G_SIGNAL_MATCH_DATA, 0, 0, + NULL, NULL, aw); + + g_object_unref (p->autocompletion); + + } + p->autocompletion = g_object_ref (ac); +} + +static void +ephy_autocompletion_window_selection_changed_cb (GtkTreeSelection *treeselection, + EphyAutocompletionWindow *aw) +{ + GList *l; + GtkTreeModel *model; + + if (aw->priv->selected) g_free (aw->priv->selected); + + l = gtk_tree_selection_get_selected_rows (treeselection, &model); + if (l) + { + GtkTreePath *path; + GtkTreeIter iter; + path = (GtkTreePath *)l->data; + + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, 1, + &aw->priv->selected, -1); + + g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL); + g_list_free (l); + } + else + { + aw->priv->selected = NULL; + } +} + +static void +ephy_autocompletion_window_get_dimensions (EphyAutocompletionWindow *aw, + int *x, int *y, int *width, int *height) +{ + GtkBin *popwin; + GtkWidget *widget; + GtkScrolledWindow *popup; + gint real_height; + GtkRequisition list_requisition; + gboolean show_vscroll = FALSE; + gint avail_height; + gint min_height; + gint alloc_width; + gint work_height; + gint old_height; + gint old_width; + int row_height; + + widget = GTK_WIDGET (aw->priv->parent); + popup = GTK_SCROLLED_WINDOW (aw->priv->scrolled_window); + popwin = GTK_BIN (aw->priv->window); + + gdk_window_get_origin (widget->window, x, y); + real_height = MIN (widget->requisition.height, + widget->allocation.height); + *y += real_height; + avail_height = gdk_screen_height () - *y; + + gtk_widget_size_request (GTK_WIDGET(aw->priv->tree_view), + &list_requisition); + + alloc_width = (widget->allocation.width - + 2 * popwin->child->style->xthickness - + 2 * GTK_CONTAINER (popwin->child)->border_width - + 2 * GTK_CONTAINER (popup)->border_width - + 2 * GTK_CONTAINER (GTK_BIN (popup)->child)->border_width - + 2 * GTK_BIN (popup)->child->style->xthickness); + + work_height = (2 * popwin->child->style->ythickness + + 2 * GTK_CONTAINER (popwin->child)->border_width + + 2 * GTK_CONTAINER (popup)->border_width + + 2 * GTK_CONTAINER (GTK_BIN (popup)->child)->border_width + + 2 * GTK_BIN (popup)->child->style->ythickness); + + min_height = MIN (list_requisition.height, + popup->vscrollbar->requisition.height); + + row_height = list_requisition.height / MAX (aw->priv->view_nitems, 1); + DEBUG_MSG (("Real list requisition %d, Items %d\n", list_requisition.height, aw->priv->view_nitems)); + list_requisition.height = MIN (row_height * MAX_VISIBLE_ROWS, list_requisition.height); + DEBUG_MSG (("Row Height %d, Fake list requisition %d\n", + row_height, list_requisition.height)); + + do + { + old_width = alloc_width; + old_height = work_height; + + if (!show_vscroll && + work_height + list_requisition.height > avail_height) + { + if (work_height + min_height > avail_height && + *y - real_height > avail_height) + { + *y -= (work_height + list_requisition.height + + real_height); + break; + } + alloc_width -= (popup->vscrollbar->requisition.width + + SCROLLBAR_SPACING (popup)); + show_vscroll = TRUE; + } + } while (old_width != alloc_width || old_height != work_height); + + *width = widget->allocation.width; + + if (*x < 0) *x = 0; + + *height = MIN (work_height + list_requisition.height, + avail_height); + + /* Action view */ + work_height = (2 * GTK_CONTAINER (popup)->border_width + + 2 * GTK_WIDGET (popup)->style->ythickness); + + if (!GTK_WIDGET_VISIBLE (aw->priv->scrolled_window)) + { + *height = work_height; + } + + gtk_widget_size_request (GTK_WIDGET(aw->priv->action_tree_view), + &list_requisition); + + if (GTK_WIDGET_VISIBLE (aw->priv->action_tree_view)) + { + *height += list_requisition.height; + } +} + +static void +ephy_autocompletion_window_fill_store_chunk (EphyAutocompletionWindow *aw) +{ + EphyAutocompletionWindowPrivate *p = aw->priv; + const EphyAutocompletionMatch *matches; + guint i; + gboolean changed; + guint nmatches; + guint last; + guint completion_nitems = 0, action_nitems = 0, substring_nitems = 0; +#ifdef DEBUG_TIME + GTimer *timer; +#endif + DEBUG_MSG (("ACW: Filling the list from %d\n", last)); + +#ifdef DEBUG_TIME + timer = g_timer_new (); + g_timer_start (timer); +#endif + + nmatches = ephy_autocompletion_get_num_matches (p->autocompletion); + matches = ephy_autocompletion_get_matches_sorted_by_score (p->autocompletion, + &changed); + if (!changed) return; + + if (p->list_store) g_object_unref (p->list_store); + p->list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); + + if (p->action_list_store) g_object_unref (p->action_list_store); + p->action_list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); + + last = p->last_added_match = 0; + + for (i = 0; last < nmatches; i++, last++) + { + const EphyAutocompletionMatch *m = &matches[last]; + GtkTreeIter iter; + GtkListStore *store; + + if (m->is_action || m->substring || + completion_nitems <= MAX_COMPLETION_ALTERNATIVES) + { + if (m->is_action) + { + store = p->action_list_store; + action_nitems ++; + } + else if (m->substring) + { + store = p->list_store; + substring_nitems ++; + } + else + { + store = p->list_store; + completion_nitems ++; + } + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + 0, m->title, + 1, m->target, + -1); + } + } + + p->view_nitems = substring_nitems + completion_nitems; + + gtk_widget_show (GTK_WIDGET (p->scrolled_window)); + gtk_widget_show (GTK_WIDGET (p->action_tree_view)); + if (p->view_nitems == 0) + { + gtk_widget_hide (GTK_WIDGET (p->scrolled_window)); + } + if (action_nitems == 0) + { + gtk_widget_hide (GTK_WIDGET (p->action_tree_view)); + } + + p->last_added_match = last; + +#ifdef DEBUG_TIME + DEBUG_MSG (("ACW: %f elapsed filling the gtkliststore\n", g_timer_elapsed (timer, NULL))); + g_timer_destroy (timer); +#endif +} + +void +ephy_autocompletion_window_show (EphyAutocompletionWindow *aw) +{ + EphyAutocompletionWindowPrivate *p = aw->priv; + gint x, y, height, width; + guint nmatches; +#ifdef DEBUG_TIME + GTimer *timer1; + GTimer *timer2; +#endif + + g_return_if_fail (p->window); + g_return_if_fail (p->autocompletion); + + nmatches = ephy_autocompletion_get_num_matches (p->autocompletion); + if (nmatches <= 0) + { + ephy_autocompletion_window_hide (aw); + return; + } + +#ifdef DEBUG_TIME + DEBUG_MSG (("ACW: showing window.\n")); + timer1 = g_timer_new (); + g_timer_start (timer1); +#endif + +#ifdef DEBUG_TIME + timer2 = g_timer_new (); + g_timer_start (timer2); +#endif + + ephy_autocompletion_window_fill_store_chunk (aw); + + p->only_actions = (!GTK_WIDGET_VISIBLE (p->scrolled_window) || + GTK_WIDGET_HAS_FOCUS (p->action_tree_view)); + if (p->only_actions) + { + p->active_tree_view = p->action_tree_view; + } + else + { + p->active_tree_view = p->tree_view; + } + +#ifdef DEBUG_TIME + DEBUG_MSG (("ACW: %f elapsed creating liststore\n", g_timer_elapsed (timer2, NULL))); +#endif + + gtk_tree_view_set_model (p->tree_view, GTK_TREE_MODEL (p->list_store)); + gtk_tree_view_set_model (p->action_tree_view, GTK_TREE_MODEL (p->action_list_store)); + +#ifdef DEBUG_TIME + g_timer_start (timer2); +#endif + + ephy_autocompletion_window_get_dimensions (aw, &x, &y, &width, &height); + +#ifdef DEBUG_TIME + DEBUG_MSG (("ACW: %f elapsed calculating dimensions\n", g_timer_elapsed (timer2, NULL))); + g_timer_destroy (timer2); +#endif + + gtk_widget_set_size_request (GTK_WIDGET (p->window), width, + height); + gtk_window_move (GTK_WINDOW (p->window), x, y); + + if (!p->shown) + { + gtk_widget_show (p->window); + + gdk_pointer_grab (p->parent->window, TRUE, + GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK, + NULL, NULL, GDK_CURRENT_TIME); + gdk_keyboard_grab (p->parent->window, TRUE, GDK_CURRENT_TIME);\ + gtk_grab_add (p->window); + + g_signal_connect (p->window, "button-press-event", + G_CALLBACK (ephy_autocompletion_window_button_press_event_cb), + aw); + g_signal_connect (p->window, "key-press-event", + G_CALLBACK (ephy_autocompletion_window_key_press_cb), + aw); + g_signal_connect (p->tree_view, "event-after", + G_CALLBACK (ephy_autocompletion_window_event_after_cb), + aw); + g_signal_connect (p->action_tree_view, "event-after", + G_CALLBACK (ephy_autocompletion_window_event_after_cb), + aw); + + p->shown = TRUE; + } + + gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (p->tree_view), 0, 0); + + gtk_widget_grab_focus (GTK_WIDGET (p->tree_view)); +#ifdef DEBUG_TIME + DEBUG_MSG (("ACW: %f elapsed showing window\n", g_timer_elapsed (timer1, NULL))); + g_timer_destroy (timer1); +#endif +} + +static gboolean +ephy_autocompletion_window_button_press_event_cb (GtkWidget *widget, + GdkEventButton *event, + EphyAutocompletionWindow *aw) +{ + GtkWidget *event_widget; + + event_widget = gtk_get_event_widget ((GdkEvent *) event); + + /* Check to see if button press happened inside the alternatives + window. If not, destroy the window. */ + if (event_widget != aw->priv->window) + { + while (event_widget) + { + if (event_widget == aw->priv->window) + return FALSE; + event_widget = event_widget->parent; + } + } + ephy_autocompletion_window_hide (aw); + + return TRUE; +} + +static GtkTreeView * +hack_tree_view_move_selection (GtkTreeView *tv, GtkTreeView *alternate, int dir) +{ + GtkTreeSelection *ts = gtk_tree_view_get_selection (tv); + GtkTreeModel *model; + GList *selected = NULL; + selected = gtk_tree_selection_get_selected_rows (ts, &model); + gboolean prev_result = TRUE; + + gtk_tree_selection_unselect_all (ts); + + if (!selected) + { + GtkTreePath *p = gtk_tree_path_new_first (); + gtk_tree_selection_select_path (ts, p); + gtk_tree_view_scroll_to_cell (tv, p, NULL, FALSE, 0, 0); + gtk_tree_path_free (p); + } + else + { + GtkTreePath *p = selected->data; + int i; + if (dir > 0) + { + for (i = 0; i < dir; ++i) + { + gtk_tree_path_next (p); + } + } + else + { + for (i = 0; i > dir; --i) + { + prev_result = gtk_tree_path_prev (p); + } + } + + if (prev_result) + { + gtk_tree_selection_select_path (ts, p); + gtk_tree_view_scroll_to_cell (tv, p, NULL, FALSE, 0, 0); + } + } + + g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL); + g_list_free (selected); + + if (!prev_result) + { + GtkTreeModel *model; + int c; + GtkTreeIter iter; + GtkTreePath *p; + GtkTreeSelection *selection; + + model = gtk_tree_view_get_model (alternate); + c = gtk_tree_model_iter_n_children (model, NULL); + gtk_tree_model_iter_nth_child (model, &iter, NULL, c - 1); + p = gtk_tree_model_get_path (model, &iter); + selection = gtk_tree_view_get_selection (alternate); + gtk_tree_selection_select_path (selection, p); + gtk_tree_view_scroll_to_cell (alternate, p, NULL, FALSE, 0, 0); + gtk_tree_path_free (p); + return alternate; + } + else if (gtk_tree_selection_count_selected_rows (ts) == 0) + { + hack_tree_view_move_selection (alternate, tv, dir); + return alternate; + } + + return tv; +} + +static gboolean +ephy_autocompletion_window_key_press_hack (EphyAutocompletionWindow *aw, + guint keyval) +{ + GtkTreeView *tree_view, *alt; + EphyAutocompletionWindowPrivate *p = aw->priv; + gboolean action; + + action = (p->active_tree_view == p->action_tree_view); + tree_view = action ? p->action_tree_view : p->tree_view; + alt = action ? p->tree_view : p->action_tree_view; + alt = p->only_actions ? p->action_tree_view : alt; + + switch (keyval) + { + case GDK_Up: + p->active_tree_view = hack_tree_view_move_selection + (tree_view, alt, -1); + break; + case GDK_Down: + p->active_tree_view = hack_tree_view_move_selection + (tree_view, alt, +1); + break; + case GDK_Page_Down: + p->active_tree_view = hack_tree_view_move_selection + (tree_view, alt, +5); + break; + case GDK_Page_Up: + p->active_tree_view = hack_tree_view_move_selection + (tree_view, alt, -5); + break; + case GDK_Return: + case GDK_space: + if (aw->priv->selected) + { + g_signal_emit (aw, EphyAutocompletionWindowSignals + [ACTIVATED], 0, aw->priv->selected, action); + } + break; + default: + g_warning ("Unexpected keyval"); + break; + } + return TRUE; +} + +static gboolean +ephy_autocompletion_window_key_press_cb (GtkWidget *widget, + GdkEventKey *event, + EphyAutocompletionWindow *aw) +{ + GdkEventKey tmp_event; + EphyAutocompletionWindowPrivate *p = aw->priv; + GtkWidget *dest_widget; + + /* allow keyboard navigation in the alternatives clist */ + if (event->keyval == GDK_Up || event->keyval == GDK_Down + || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down + || ((event->keyval == GDK_space || event->keyval == GDK_Return) + && p->selected)) + { + return ephy_autocompletion_window_key_press_hack + (aw, event->keyval); + } + else + { + dest_widget = p->parent; + } + + if (dest_widget != widget) + { + //DEBUG_MSG (("Resending event\n")); + + tmp_event = *event; + gtk_widget_event (dest_widget, (GdkEvent *)&tmp_event); + + return TRUE; + } + else + { + if (widget == GTK_WIDGET (p->tree_view)) + { + //DEBUG_MSG (("on the tree view ")); + } + //DEBUG_MSG (("Ignoring event\n")); + return FALSE; + } + +} + +void +ephy_autocompletion_window_hide (EphyAutocompletionWindow *aw) +{ + if (aw->priv->window) + { + gtk_widget_hide (aw->priv->window); + gtk_grab_remove (aw->priv->window); + gdk_pointer_ungrab (GDK_CURRENT_TIME); + gdk_keyboard_ungrab (GDK_CURRENT_TIME); + ephy_autocompletion_window_unselect (aw); + g_signal_emit (aw, EphyAutocompletionWindowSignals[EPHY_AUTOCOMPLETION_WINDOW_HIDDEN], 0); + } + g_free (aw->priv->selected); + aw->priv->selected = NULL; + aw->priv->shown = FALSE; +} + +void +ephy_autocompletion_window_unselect (EphyAutocompletionWindow *aw) +{ + EphyAutocompletionWindowPrivate *p = aw->priv; + GtkTreeSelection *ts = gtk_tree_view_get_selection (p->tree_view); + gtk_tree_selection_unselect_all (ts); +} + +static void +ephy_autocompletion_window_event_after_cb (GtkWidget *wid, GdkEvent *event, + EphyAutocompletionWindow *aw) +{ + gboolean action; + EphyAutocompletionWindowPrivate *p = aw->priv; + + action = (wid == GTK_WIDGET (p->action_tree_view)); + + if (event->type == GDK_BUTTON_PRESS + && ((GdkEventButton *) event)->button == 1) + { + if (p->selected) + { + g_signal_emit (aw, EphyAutocompletionWindowSignals + [ACTIVATED], 0, p->selected, action); + } + } +} diff --git a/lib/widgets/ephy-autocompletion-window.h b/lib/widgets/ephy-autocompletion-window.h new file mode 100644 index 000000000..b390fc35c --- /dev/null +++ b/lib/widgets/ephy-autocompletion-window.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_AUTOCOMPLETION_WINDOW_H +#define EPHY_AUTOCOMPLETION_WINDOW_H + +#include <glib-object.h> +#include <gtk/gtkwidget.h> + +#include "ephy-autocompletion.h" + +G_BEGIN_DECLS + +/* object forward declarations */ + +typedef struct _EphyAutocompletionWindow EphyAutocompletionWindow; +typedef struct _EphyAutocompletionWindowClass EphyAutocompletionWindowClass; +typedef struct _EphyAutocompletionWindowPrivate EphyAutocompletionWindowPrivate; + +/** + * Editor object + */ + +#define EPHY_TYPE_AUTOCOMPLETION_WINDOW (ephy_autocompletion_window_get_type()) +#define EPHY_AUTOCOMPLETION_WINDOW(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \ + EPHY_TYPE_AUTOCOMPLETION_WINDOW,\ + EphyAutocompletionWindow)) +#define EPHY_AUTOCOMPLETION_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \ + EPHY_TYPE_AUTOCOMPLETION_WINDOW,\ + EphyAutocompletionWindowClass)) +#define EPHY_IS_AUTOCOMPLETION_WINDOW(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \ + EPHY_TYPE_AUTOCOMPLETION_WINDOW)) +#define EPHY_IS_AUTOCOMPLETION_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \ + EPHY_TYPE_AUTOCOMPLETION_WINDOW)) +#define EPHY_AUTOCOMPLETION_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ + EPHY_TYPE_AUTOCOMPLETION_WINDOW,\ + EphyAutocompletionWindowClass)) + +struct _EphyAutocompletionWindowClass +{ + GObjectClass parent_class; + + /* signals */ + void (*hidden) (EphyAutocompletionWindow *aw); + void (*activated) (EphyAutocompletionWindow *aw, + const char *target, + int action); + +}; + +/* Remember: fields are public read-only */ +struct _EphyAutocompletionWindow +{ + GObject parent_object; + + EphyAutocompletionWindowPrivate *priv; +}; + +GType ephy_autocompletion_window_get_type (void); +EphyAutocompletionWindow *ephy_autocompletion_window_new (EphyAutocompletion *ac, + GtkWidget *parent); +void ephy_autocompletion_window_set_parent_widget (EphyAutocompletionWindow *aw, + GtkWidget *w); +void ephy_autocompletion_window_set_autocompletion (EphyAutocompletionWindow *aw, + EphyAutocompletion *ac); +void ephy_autocompletion_window_show (EphyAutocompletionWindow *aw); +void ephy_autocompletion_window_hide (EphyAutocompletionWindow *aw); +void ephy_autocompletion_window_unselect (EphyAutocompletionWindow *aw); + +G_END_DECLS + +#endif diff --git a/lib/widgets/ephy-ellipsizing-label.c b/lib/widgets/ephy-ellipsizing-label.c new file mode 100644 index 000000000..13f911078 --- /dev/null +++ b/lib/widgets/ephy-ellipsizing-label.c @@ -0,0 +1,774 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-ellipsizing-label.c: Subclass of GtkLabel that ellipsizes the text. + + Copyright (C) 2001 Eazel, Inc. + + The Gnome Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more priv. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: John Sullivan <sullivan@eazel.com>, + Marco Pesenti Gritti <marco@it.gnome.org> Markup support + */ + +#include "ephy-ellipsizing-label.h" + +#include <string.h> + +struct EphyEllipsizingLabelPrivate +{ + char *full_text; + + EphyEllipsizeMode mode; +}; + +static void ephy_ellipsizing_label_class_init (EphyEllipsizingLabelClass *class); +static void ephy_ellipsizing_label_init (EphyEllipsizingLabel *label); + +static GObjectClass *parent_class = NULL; + +static int +ephy_strcmp (const char *string_a, const char *string_b) +{ + return strcmp (string_a == NULL ? "" : string_a, + string_b == NULL ? "" : string_b); +} + +static gboolean +ephy_str_is_equal (const char *string_a, const char *string_b) +{ + return ephy_strcmp (string_a, string_b) == 0; +} + +#define ELLIPSIS "..." + +/* Caution: this is an _expensive_ function */ +static int +measure_string_width (const char *string, + PangoLayout *layout, + gboolean markup) +{ + int width; + + if (markup) + { + pango_layout_set_markup (layout, string, -1); + } + else + { + pango_layout_set_text (layout, string, -1); + } + + pango_layout_get_pixel_size (layout, &width, NULL); + + return width; +} + +/* this is also plenty slow */ +static void +compute_character_widths (const char *string, + PangoLayout *layout, + int *char_len_return, + int **widths_return, + int **cuts_return, + gboolean markup) +{ + int *widths; + int *offsets; + int *cuts; + int char_len; + int byte_len; + const char *p; + const char *nm_string; + int i; + PangoLayoutIter *iter; + PangoLogAttr *attrs; + +#define BEGINS_UTF8_CHAR(x) (((x) & 0xc0) != 0x80) + + if (markup) + { + pango_layout_set_markup (layout, string, -1); + } + else + { + pango_layout_set_text (layout, string, -1); + } + + nm_string = pango_layout_get_text (layout); + + char_len = g_utf8_strlen (nm_string, -1); + byte_len = strlen (nm_string); + + widths = g_new (int, char_len); + offsets = g_new (int, byte_len); + + /* Create a translation table from byte index to char offset */ + p = nm_string; + i = 0; + while (*p) { + int byte_index = p - nm_string; + + if (BEGINS_UTF8_CHAR (*p)) { + offsets[byte_index] = i; + ++i; + } else { + offsets[byte_index] = G_MAXINT; /* segv if we try to use this */ + } + + ++p; + } + + /* Now fill in the widths array */ + iter = pango_layout_get_iter (layout); + + do { + PangoRectangle extents; + int byte_index; + + byte_index = pango_layout_iter_get_index (iter); + + if (byte_index < byte_len) { + pango_layout_iter_get_char_extents (iter, &extents); + + g_assert (BEGINS_UTF8_CHAR (nm_string[byte_index])); + g_assert (offsets[byte_index] < char_len); + + widths[offsets[byte_index]] = PANGO_PIXELS (extents.width); + } + + } while (pango_layout_iter_next_char (iter)); + + pango_layout_iter_free (iter); + + g_free (offsets); + + *widths_return = widths; + + /* Now compute character offsets that are legitimate places to + * chop the string + */ + attrs = g_new (PangoLogAttr, char_len + 1); + + pango_get_log_attrs (nm_string, byte_len, -1, + pango_context_get_language ( + pango_layout_get_context (layout)), + attrs, + char_len + 1); + + cuts = g_new (int, char_len); + i = 0; + while (i < char_len) { + cuts[i] = attrs[i].is_cursor_position; + + ++i; + } + + g_free (attrs); + + *cuts_return = cuts; + + *char_len_return = char_len; +} + +typedef struct +{ + GString *string; + int start_offset; + int end_offset; + int position; +} EllipsizeStringData; + +static void +start_element_handler (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) +{ + EllipsizeStringData *data = (EllipsizeStringData *)user_data; + int i; + + g_string_append_c (data->string, '<'); + g_string_append (data->string, element_name); + + for (i = 0; attribute_names[i] != NULL; i++) + { + g_string_append_c (data->string, ' '); + g_string_append (data->string, attribute_names[i]); + g_string_append (data->string, "=\""); + g_string_append (data->string, attribute_values[i]); + g_string_append_c (data->string, '"'); + } + + g_string_append_c (data->string, '>'); +} + +static void +end_element_handler (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error) +{ + EllipsizeStringData *data = (EllipsizeStringData *)user_data; + + g_string_append (data->string, "</"); + g_string_append (data->string, element_name); + g_string_append_c (data->string, '>'); +} + +static void +append_ellipsized_text (const char *text, + EllipsizeStringData *data, + int text_len) +{ + int position; + int new_position; + + position = data->position; + new_position = data->position + text_len; + + if (position > data->start_offset && + new_position < data->end_offset) + { + return; + } + else if ((position < data->start_offset && + new_position < data->start_offset) || + (position > data->end_offset && + new_position > data->end_offset)) + { + g_string_append (data->string, + text); + } + else if (position <= data->start_offset && + new_position >= data->end_offset) + { + if (position < data->start_offset) + { + g_string_append_len (data->string, + text, + data->start_offset - + position); + } + + g_string_append (data->string, + ELLIPSIS); + + if (new_position > data->end_offset) + { + g_string_append_len (data->string, + text + data->end_offset - + position, + position + text_len - + data->end_offset); + } + } + + data->position = new_position; +} + +static void +text_handler (GMarkupParseContext *context, + const gchar *text, + gsize text_len, + gpointer user_data, + GError **error) +{ + EllipsizeStringData *data = (EllipsizeStringData *)user_data; + + append_ellipsized_text (text, data, text_len); +} + +static GMarkupParser pango_markup_parser = { + start_element_handler, + end_element_handler, + text_handler, + NULL, + NULL +}; + +static char * +ellipsize_string (const char *string, + int start_offset, + int end_offset, + gboolean markup) +{ + GString *str; + EllipsizeStringData data; + char *result; + GMarkupParseContext *c; + + str = g_string_new (NULL); + data.string = str; + data.start_offset = start_offset; + data.end_offset = end_offset; + data.position = 0; + + if (markup) + { + c = g_markup_parse_context_new (&pango_markup_parser, + 0, &data, NULL); + g_markup_parse_context_parse (c, string, -1, NULL); + g_markup_parse_context_free (c); + } + else + { + append_ellipsized_text (string, &data, + g_utf8_strlen (string, -1)); + } + + result = str->str; + g_string_free (str, FALSE); + return result; +} + +static char * +ephy_string_ellipsize_start (const char *string, PangoLayout *layout, int width, gboolean markup) +{ + int resulting_width; + int *cuts; + int *widths; + int char_len; + int truncate_offset; + int bytes_end; + + /* Zero-length string can't get shorter - catch this here to + * avoid expensive calculations + */ + if (*string == '\0') + return g_strdup (""); + + /* I'm not sure if this short-circuit is a net win; it might be better + * to just dump this, and always do the compute_character_widths() etc. + * down below. + */ + resulting_width = measure_string_width (string, layout, markup); + + if (resulting_width <= width) { + /* String is already short enough. */ + return g_strdup (string); + } + + /* Remove width of an ellipsis */ + width -= measure_string_width (ELLIPSIS, layout, markup); + + if (width < 0) { + /* No room even for an ellipsis. */ + return g_strdup (""); + } + + /* Our algorithm involves removing enough chars from the string to bring + * the width to the required small size. However, due to ligatures, + * combining characters, etc., it's not guaranteed that the algorithm + * always works 100%. It's sort of a heuristic thing. It should work + * nearly all the time... but I wouldn't put in + * g_assert (width of resulting string < width). + * + * Hmm, another thing that this breaks with is explicit line breaks + * in "string" + */ + + compute_character_widths (string, layout, &char_len, &widths, &cuts, markup); + + for (truncate_offset = 1; truncate_offset < char_len; truncate_offset++) { + + resulting_width -= widths[truncate_offset]; + + if (resulting_width <= width && + cuts[truncate_offset]) { + break; + } + } + + g_free (cuts); + g_free (widths); + + bytes_end = g_utf8_offset_to_pointer (string, truncate_offset) - string; + + return ellipsize_string (string, 0, bytes_end, markup); +} + +static char * +ephy_string_ellipsize_end (const char *string, PangoLayout *layout, int width, gboolean markup) +{ + int resulting_width; + int *cuts; + int *widths; + int char_len; + int truncate_offset; + int bytes_end; + + /* See explanatory comments in ellipsize_start */ + + if (*string == '\0') + return g_strdup (""); + + resulting_width = measure_string_width (string, layout, markup); + + if (resulting_width <= width) { + return g_strdup (string); + } + + width -= measure_string_width (ELLIPSIS, layout, markup); + + if (width < 0) { + return g_strdup (""); + } + + compute_character_widths (string, layout, &char_len, &widths, &cuts, markup); + + for (truncate_offset = char_len - 1; truncate_offset > 0; truncate_offset--) { + resulting_width -= widths[truncate_offset]; + if (resulting_width <= width && + cuts[truncate_offset]) { + break; + } + } + + g_free (cuts); + g_free (widths); + + bytes_end = g_utf8_offset_to_pointer (string, truncate_offset) - string; + + return ellipsize_string (string, bytes_end, + char_len, markup); +} + +static char * +ephy_string_ellipsize_middle (const char *string, PangoLayout *layout, int width, gboolean markup) +{ + int resulting_width; + int *cuts; + int *widths; + int char_len; + int starting_fragment_length; + int ending_fragment_offset; + int bytes_start; + int bytes_end; + + /* See explanatory comments in ellipsize_start */ + + if (*string == '\0') + return g_strdup (""); + + resulting_width = measure_string_width (string, layout, markup); + + if (resulting_width <= width) { + return g_strdup (string); + } + + width -= measure_string_width (ELLIPSIS, layout, markup); + + if (width < 0) { + return g_strdup (""); + } + + compute_character_widths (string, layout, &char_len, &widths, &cuts, markup); + + starting_fragment_length = char_len / 2; + ending_fragment_offset = starting_fragment_length + 1; + + /* depending on whether the original string length is odd or even, start by + * shaving off the characters from the starting or ending fragment + */ + if (char_len % 2) { + goto shave_end; + } + + while (starting_fragment_length > 0 || ending_fragment_offset < char_len) { + if (resulting_width <= width && + cuts[ending_fragment_offset] && + cuts[starting_fragment_length]) { + break; + } + + if (starting_fragment_length > 0) { + resulting_width -= widths[starting_fragment_length]; + starting_fragment_length--; + } + + shave_end: + if (resulting_width <= width && + cuts[ending_fragment_offset] && + cuts[starting_fragment_length]) { + break; + } + + if (ending_fragment_offset < char_len) { + resulting_width -= widths[ending_fragment_offset]; + ending_fragment_offset++; + } + } + + g_free (cuts); + g_free (widths); + + bytes_start = g_utf8_offset_to_pointer (string, starting_fragment_length) - string; + bytes_end = g_utf8_offset_to_pointer (string, ending_fragment_offset) - string; + + return ellipsize_string (string, bytes_start, bytes_end, markup); +} + + +/** + * ephy_pango_layout_set_text_ellipsized + * + * @layout: a pango layout + * @string: A a string to be ellipsized. + * @width: Desired maximum width in points. + * @mode: The desired ellipsizing mode. + * + * Truncates a string if required to fit in @width and sets it on the + * layout. Truncation involves removing characters from the start, middle or end + * respectively and replacing them with "...". Algorithm is a bit + * fuzzy, won't work 100%. + * + */ +static void +gul_pango_layout_set_text_ellipsized (PangoLayout *layout, + const char *string, + int width, + EphyEllipsizeMode mode, + gboolean markup) +{ + char *s; + + g_return_if_fail (PANGO_IS_LAYOUT (layout)); + g_return_if_fail (string != NULL); + g_return_if_fail (width >= 0); + + switch (mode) { + case EPHY_ELLIPSIZE_START: + s = ephy_string_ellipsize_start (string, layout, width, markup); + break; + case EPHY_ELLIPSIZE_MIDDLE: + s = ephy_string_ellipsize_middle (string, layout, width, markup); + break; + case EPHY_ELLIPSIZE_END: + s = ephy_string_ellipsize_end (string, layout, width, markup); + break; + default: + g_return_if_reached (); + s = NULL; + } + + if (markup) + { + pango_layout_set_markup (layout, s, -1); + } + else + { + pango_layout_set_text (layout, s, -1); + } + + g_free (s); +} + +GType +ephy_ellipsizing_label_get_type (void) +{ + static GType ephy_ellipsizing_label_type = 0; + + if (ephy_ellipsizing_label_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyEllipsizingLabelClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_ellipsizing_label_class_init, + NULL, + NULL, /* class_data */ + sizeof (EphyEllipsizingLabel), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_ellipsizing_label_init + }; + + ephy_ellipsizing_label_type = g_type_register_static (GTK_TYPE_LABEL, + "EphyEllipsizingLabel", + &our_info, 0); + } + + return ephy_ellipsizing_label_type; +} + +static void +ephy_ellipsizing_label_init (EphyEllipsizingLabel *label) +{ + label->priv = g_new0 (EphyEllipsizingLabelPrivate, 1); + + label->priv->mode = EPHY_ELLIPSIZE_NONE; +} + +static void +real_finalize (GObject *object) +{ + EphyEllipsizingLabel *label; + + label = EPHY_ELLIPSIZING_LABEL (object); + + g_free (label->priv->full_text); + g_free (label->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +GtkWidget* +ephy_ellipsizing_label_new (const char *string) +{ + EphyEllipsizingLabel *label; + + label = g_object_new (EPHY_TYPE_ELLIPSIZING_LABEL, NULL); + ephy_ellipsizing_label_set_text (label, string); + + return GTK_WIDGET (label); +} + +void +ephy_ellipsizing_label_set_text (EphyEllipsizingLabel *label, + const char *string) +{ + g_return_if_fail (EPHY_IS_ELLIPSIZING_LABEL (label)); + + if (ephy_str_is_equal (string, label->priv->full_text)) { + return; + } + + g_free (label->priv->full_text); + label->priv->full_text = g_strdup (string); + + /* Queues a resize as side effect */ + gtk_label_set_text (GTK_LABEL (label), label->priv->full_text); +} + +void +ephy_ellipsizing_label_set_markup (EphyEllipsizingLabel *label, + const char *string) +{ + g_return_if_fail (EPHY_IS_ELLIPSIZING_LABEL (label)); + + if (ephy_str_is_equal (string, label->priv->full_text)) { + return; + } + + g_free (label->priv->full_text); + label->priv->full_text = g_strdup (string); + + /* Queues a resize as side effect */ + gtk_label_set_markup (GTK_LABEL (label), label->priv->full_text); +} + +void +ephy_ellipsizing_label_set_mode (EphyEllipsizingLabel *label, + EphyEllipsizeMode mode) +{ + g_return_if_fail (EPHY_IS_ELLIPSIZING_LABEL (label)); + + label->priv->mode = mode; +} + +static void +real_size_request (GtkWidget *widget, GtkRequisition *requisition) +{ + GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition); + + /* Don't demand any particular width; will draw ellipsized into whatever size we're given */ + requisition->width = 0; +} + +static void +real_size_allocate (GtkWidget *widget, GtkAllocation *allocation) +{ + EphyEllipsizingLabel *label; + gboolean markup; + + markup = gtk_label_get_use_markup (GTK_LABEL (widget)); + + label = EPHY_ELLIPSIZING_LABEL (widget); + + /* This is the bad hack of the century, using private + * GtkLabel layout object. If the layout is NULL + * then it got blown away since size request, + * we just punt in that case, I don't know what to do really. + */ + + if (GTK_LABEL (label)->layout != NULL) { + if (label->priv->full_text == NULL) { + pango_layout_set_text (GTK_LABEL (label)->layout, "", -1); + } else { + EphyEllipsizeMode mode; + + if (label->priv->mode != EPHY_ELLIPSIZE_NONE) + mode = label->priv->mode; + + if (ABS (GTK_MISC (label)->xalign - 0.5) < 1e-12) + mode = EPHY_ELLIPSIZE_MIDDLE; + else if (GTK_MISC (label)->xalign < 0.5) + mode = EPHY_ELLIPSIZE_END; + else + mode = EPHY_ELLIPSIZE_START; + + gul_pango_layout_set_text_ellipsized (GTK_LABEL (label)->layout, + label->priv->full_text, + allocation->width, + mode, + markup); + + gtk_widget_queue_draw (GTK_WIDGET (label)); + } + } + + GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation); +} + +static gboolean +real_expose_event (GtkWidget *widget, GdkEventExpose *event) +{ + EphyEllipsizingLabel *label; + GtkRequisition req; + + label = EPHY_ELLIPSIZING_LABEL (widget); + + /* push/pop the actual size so expose draws in the right + * place, yes this is bad hack central. Here we assume the + * ellipsized text has been set on the layout in size_allocate + */ + GTK_WIDGET_CLASS (parent_class)->size_request (widget, &req); + widget->requisition.width = req.width; + GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event); + widget->requisition.width = 0; + + return FALSE; +} + + +static void +ephy_ellipsizing_label_class_init (EphyEllipsizingLabelClass *klass) +{ + GtkWidgetClass *widget_class; + + parent_class = g_type_class_peek_parent (klass); + + widget_class = GTK_WIDGET_CLASS (klass); + + G_OBJECT_CLASS (klass)->finalize = real_finalize; + + widget_class->size_request = real_size_request; + widget_class->size_allocate = real_size_allocate; + widget_class->expose_event = real_expose_event; +} + diff --git a/lib/widgets/ephy-ellipsizing-label.h b/lib/widgets/ephy-ellipsizing-label.h new file mode 100644 index 000000000..6f596edfa --- /dev/null +++ b/lib/widgets/ephy-ellipsizing-label.h @@ -0,0 +1,71 @@ +/* eel-ellipsizing-label.h: Subclass of GtkLabel that ellipsizes the text. + + Copyright (C) 2001 Eazel, Inc. + + The Gnome Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: John Sullivan <sullivan@eazel.com>, + */ + +#ifndef EPHY_ELLIPSIZING_LABEL_H +#define EPHY_ELLIPSIZING_LABEL_H + +#include <gtk/gtklabel.h> + +#define EPHY_TYPE_ELLIPSIZING_LABEL (ephy_ellipsizing_label_get_type ()) +#define EPHY_ELLIPSIZING_LABEL(obj) (GTK_CHECK_CAST ((obj), EPHY_TYPE_ELLIPSIZING_LABEL, EphyEllipsizingLabel)) +#define EPHY_ELLIPSIZING_LABEL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_TYPE_ELLIPSIZING_LABEL, EphyEllipsizingLabelClass)) +#define EPHY_IS_ELLIPSIZING_LABEL(obj) (GTK_CHECK_TYPE ((obj), EPHY_TYPE_ELLIPSIZING_LABEL)) +#define EPHY_IS_ELLIPSIZING_LABEL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_TYPE_ELLIPSIZING_LABEL)) + +typedef struct EphyEllipsizingLabelPrivate EphyEllipsizingLabelPrivate; + +typedef enum +{ + EPHY_ELLIPSIZE_NONE, + EPHY_ELLIPSIZE_START, + EPHY_ELLIPSIZE_MIDDLE, + EPHY_ELLIPSIZE_END +} EphyEllipsizeMode; + +typedef struct +{ + GtkLabel parent; + + EphyEllipsizingLabelPrivate *priv; +} EphyEllipsizingLabel; + +typedef struct +{ + GtkLabelClass parent_class; +} EphyEllipsizingLabelClass; + +GtkType ephy_ellipsizing_label_get_type (void); + +GtkWidget *ephy_ellipsizing_label_new (const char *string); + +void ephy_ellipsizing_label_set_mode (EphyEllipsizingLabel *label, + EphyEllipsizeMode mode); + +void ephy_ellipsizing_label_set_text (EphyEllipsizingLabel *label, + const char *string); + +void ephy_ellipsizing_label_set_markup (EphyEllipsizingLabel *label, + const char *string); + +G_END_DECLS + +#endif /* EPHY_ELLIPSIZING_LABEL_H */ diff --git a/lib/widgets/ephy-location-entry.c b/lib/widgets/ephy-location-entry.c new file mode 100644 index 000000000..b0669f89f --- /dev/null +++ b/lib/widgets/ephy-location-entry.c @@ -0,0 +1,700 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-location-entry.h" +#include "ephy-autocompletion-window.h" +#include "ephy-marshal.h" +#include "ephy-gobject-misc.h" +#include "eel-gconf-extensions.h" +#include "ephy-prefs.h" + +#include <gtk/gtkentry.h> +#include <gtk/gtkwindow.h> +#include <gdk/gdkkeysyms.h> +#include <gtk/gtkmain.h> +#include <libgnomeui/gnome-entry.h> +#include <string.h> + +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); + +/** + * Private data + */ +struct _EphyLocationEntryPrivate { + GtkWidget *combo; + GtkWidget *entry; + gchar *before_completion; + EphyAutocompletion *autocompletion; + EphyAutocompletionWindow *autocompletion_window; + gboolean autocompletion_window_visible; + gint autocompletion_timeout; + gint show_alternatives_timeout; + gboolean block_set_autocompletion_key; + + gchar *autocompletion_key; + gchar *last_completion; + char *last_action_target; +}; + +#define AUTOCOMPLETION_DELAY 10 +#define SHOW_ALTERNATIVES_DELAY 100 + +/** + * Private functions, only availble from this file + */ +static void ephy_location_entry_class_init (EphyLocationEntryClass *klass); +static void ephy_location_entry_init (EphyLocationEntry *w); +static void ephy_location_entry_finalize_impl (GObject *o); +static void ephy_location_entry_build (EphyLocationEntry *w); +static gboolean ephy_location_entry_key_press_event_cb (GtkWidget *entry, GdkEventKey *event, + EphyLocationEntry *w); +static void ephy_location_entry_activate_cb (GtkEntry *entry, + EphyLocationEntry *w); +static void ephy_location_entry_autocompletion_sources_changed_cb (EphyAutocompletion *aw, + EphyLocationEntry *w); +static gint ephy_location_entry_autocompletion_to (EphyLocationEntry *w); +static gint ephy_location_entry_autocompletion_show_alternatives_to (EphyLocationEntry *w); +static void ephy_location_entry_autocompletion_window_url_activated_cb +/***/ (EphyAutocompletionWindow *aw, + const gchar *target, + int action, + EphyLocationEntry *w); +static void ephy_location_entry_list_event_after_cb (GtkWidget *list, + GdkEvent *event, + EphyLocationEntry *e); +static void ephy_location_entry_editable_changed_cb (GtkEditable *editable, + EphyLocationEntry *e); +static void ephy_location_entry_set_autocompletion_key (EphyLocationEntry *e); +static void ephy_location_entry_autocompletion_show_alternatives (EphyLocationEntry *w); +static void ephy_location_entry_autocompletion_hide_alternatives (EphyLocationEntry *w); +static void ephy_location_entry_autocompletion_window_hidden_cb (EphyAutocompletionWindow *aw, + EphyLocationEntry *w); + + + + +static gpointer gtk_hbox_class; + +/** + * Signals enums and ids + */ +enum EphyLocationEntrySignalsEnum { + ACTIVATED, + LAST_SIGNAL +}; +static gint EphyLocationEntrySignals[LAST_SIGNAL]; + +/** + * EphyLocationEntry object + */ + +MAKE_GET_TYPE (ephy_location_entry, "EphyLocationEntry", EphyLocationEntry, + ephy_location_entry_class_init, + ephy_location_entry_init, GTK_TYPE_HBOX); + +static void +ephy_location_entry_class_init (EphyLocationEntryClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = ephy_location_entry_finalize_impl; + gtk_hbox_class = g_type_class_peek_parent (klass); + + EphyLocationEntrySignals[ACTIVATED] = g_signal_new ( + "activated", G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP, + G_STRUCT_OFFSET (EphyLocationEntryClass, activated), + NULL, NULL, + ephy_marshal_VOID__STRING_STRING, + G_TYPE_NONE, + 2, + G_TYPE_STRING, + G_TYPE_STRING); +} + +static void +ephy_location_entry_init (EphyLocationEntry *w) +{ + EphyLocationEntryPrivate *p = g_new0 (EphyLocationEntryPrivate, 1); + w->priv = p; + p->last_action_target = NULL; + + ephy_location_entry_build (w); +} + +static void +ephy_location_entry_finalize_impl (GObject *o) +{ + EphyLocationEntry *w = EPHY_LOCATION_ENTRY (o); + EphyLocationEntryPrivate *p = w->priv; + + if (p->autocompletion) + { + g_signal_handlers_disconnect_matched (p->autocompletion, G_SIGNAL_MATCH_DATA, 0, 0, + NULL, NULL, w); + + g_signal_handlers_disconnect_matched (p->autocompletion_window, G_SIGNAL_MATCH_DATA, 0, 0, + NULL, NULL, w); + + g_object_unref (G_OBJECT (p->autocompletion)); + g_object_unref (G_OBJECT (p->autocompletion_window)); + } + + DEBUG_MSG (("EphyLocationEntry finalized\n")); + + g_free (p); + G_OBJECT_CLASS (gtk_hbox_class)->finalize (o); +} + +EphyLocationEntry * +ephy_location_entry_new (void) +{ + return EPHY_LOCATION_ENTRY (g_object_new (EPHY_TYPE_LOCATION_ENTRY, NULL)); +} + +static void +ephy_location_entry_build (EphyLocationEntry *w) +{ + EphyLocationEntryPrivate *p = w->priv; + GtkWidget *list; + + p->combo = gnome_entry_new ("ephy-url-history"); + p->entry = GTK_COMBO (p->combo)->entry; + gtk_widget_show (p->combo); + gtk_box_pack_start (GTK_BOX (w), p->combo, TRUE, TRUE, 0); + + g_signal_connect (p->entry, "key-press-event", + G_CALLBACK (ephy_location_entry_key_press_event_cb), w); + + g_signal_connect (p->entry, "activate", + G_CALLBACK (ephy_location_entry_activate_cb), w); + + g_signal_connect (p->entry, "changed", + G_CALLBACK (ephy_location_entry_editable_changed_cb), w); + + list = GTK_COMBO (p->combo)->list; + + g_signal_connect_after (list, "event-after", + G_CALLBACK (ephy_location_entry_list_event_after_cb), w); + +} + +static gboolean +ephy_location_ignore_prefix (EphyLocationEntry *w) +{ + char *text; + int text_len; + int i, k; + gboolean result = FALSE; + static const gchar *prefixes[] = { + EPHY_AUTOCOMPLETION_USUAL_WEB_PREFIXES, + NULL + }; + + text = ephy_location_entry_get_location (w); + text_len = g_utf8_strlen (text, -1); + + for (i = 0; prefixes[i] != NULL; i++) + { + const char *prefix = prefixes[i]; + + for (k = 0; k < g_utf8_strlen (prefix, -1); k++) + { + if (text_len == (k + 1) && + (strncmp (text, prefix, k + 1) == 0)) + { + result = TRUE; + } + } + } + + g_free (text); + + return result; +} + +static gint +ephy_location_entry_autocompletion_show_alternatives_to (EphyLocationEntry *w) +{ + EphyLocationEntryPrivate *p = w->priv; + + if (ephy_location_ignore_prefix (w)) return FALSE; + + if (p->autocompletion) + { + DEBUG_MSG (("+ephy_location_entry_autocompletion_show_alternatives_to\n")); + ephy_location_entry_set_autocompletion_key (w); + ephy_location_entry_autocompletion_show_alternatives (w); + } + p->show_alternatives_timeout = 0; + return FALSE; +} + +static void +ephy_location_entry_autocompletion_hide_alternatives (EphyLocationEntry *w) +{ + EphyLocationEntryPrivate *p = w->priv; + if (p->autocompletion_window) + { + ephy_autocompletion_window_hide (p->autocompletion_window); + p->autocompletion_window_visible = FALSE; + } +} + +static void +ephy_location_entry_autocompletion_show_alternatives (EphyLocationEntry *w) +{ + EphyLocationEntryPrivate *p = w->priv; + if (p->autocompletion_window) + { + ephy_autocompletion_window_show (p->autocompletion_window); + p->autocompletion_window_visible = TRUE; + } +} + +static void +ephy_location_entry_autocompletion_unselect_alternatives (EphyLocationEntry *w) +{ + EphyLocationEntryPrivate *p = w->priv; + if (p->autocompletion_window) + { + ephy_autocompletion_window_unselect (p->autocompletion_window); + } +} + +static gint +ephy_location_entry_autocompletion_to (EphyLocationEntry *w) +{ + EphyLocationEntryPrivate *p = w->priv; + gchar *text; + gchar *common_prefix; + + DEBUG_MSG (("in ephy_location_entry_autocompletion_to\n")); + + ephy_location_entry_set_autocompletion_key (w); + + { + GtkEditable *editable = GTK_EDITABLE (p->entry); + gint sstart, send; + gint pos = gtk_editable_get_position (editable); + const gchar *text = gtk_entry_get_text (GTK_ENTRY (p->entry)); + gint text_len = strlen (text); + gtk_editable_get_selection_bounds (editable, &sstart, &send); + + if (pos != text_len + || send != text_len) + { + /* the user is editing the entry, don't mess it */ + DEBUG_MSG (("The user seems editing the text: pos = %d, strlen (text) = %d, sstart = %d, send = %d\n", + pos, strlen (text), sstart, send)); + p->autocompletion_timeout = 0; + return FALSE; + } + } + + common_prefix = ephy_autocompletion_get_common_prefix (p->autocompletion); + + DEBUG_MSG (("common_prefix: %s\n", common_prefix)); + + if (common_prefix && (!p->before_completion || p->before_completion[0] == '\0')) + { + text = ephy_location_entry_get_location (w); + g_free (p->before_completion); + p->before_completion = text; + } + + if (common_prefix) + { + /* check original length */ + guint text_len = strlen (p->autocompletion_key); + + p->block_set_autocompletion_key = TRUE; + + /* set entry to completed text */ + gtk_entry_set_text (GTK_ENTRY (p->entry), common_prefix); + + /* move selection appropriately */ + gtk_editable_select_region (GTK_EDITABLE (p->entry), text_len, -1); + + p->block_set_autocompletion_key = FALSE; + + g_free (p->last_completion); + p->last_completion = common_prefix; + } + + p->autocompletion_timeout = 0; + return FALSE; +} + +/* this is from the old location entry, need to do the autocompletion before implementing this */ +static gboolean +ephy_location_entry_key_press_event_cb (GtkWidget *entry, GdkEventKey *event, EphyLocationEntry *w) +{ + EphyLocationEntryPrivate *p = w->priv; + static gboolean suggest = FALSE; + guint keyval = event->keyval; + + if (p->autocompletion_timeout != 0) + { + gtk_timeout_remove (p->autocompletion_timeout); + p->autocompletion_timeout = 0; + } + + if (p->show_alternatives_timeout != 0) + { + gtk_timeout_remove (p->show_alternatives_timeout); + p->show_alternatives_timeout = 0; + } + + /* only suggest heuristic completions if TAB is hit twice */ + if (event->keyval != GDK_Tab) + { + suggest = FALSE; + } + + if (((event->state & GDK_Control_L || event->state & GDK_Control_R) && + (keyval == GDK_a || keyval == GDK_b || keyval == GDK_c || + keyval == GDK_d || keyval == GDK_e || keyval == GDK_f || + keyval == GDK_h || keyval == GDK_k || keyval == GDK_u || + keyval == GDK_v || keyval == GDK_w || keyval == GDK_x)) || + (event->state == 0 && event->keyval == GDK_BackSpace)) + { + ephy_location_entry_autocompletion_hide_alternatives (w); + return FALSE; + } + + /* don't grab alt combos, thus you can still access the menus. */ + if (event->state & GDK_MOD1_MASK) + { + ephy_location_entry_autocompletion_hide_alternatives (w); + return FALSE; + } + + /* make sure the end key works at all times */ + if ((!((event->state & GDK_SHIFT_MASK) || + (event->state & GDK_CONTROL_MASK) || + (event->state & GDK_MOD1_MASK)) + && (event->keyval == GDK_End))) + { + ephy_location_entry_autocompletion_hide_alternatives (w); + gtk_editable_select_region (GTK_EDITABLE (p->entry), 0, 0); + gtk_editable_set_position (GTK_EDITABLE (p->entry), -1); + ephy_location_entry_autocompletion_unselect_alternatives (w); + return TRUE; + } + + switch (event->keyval) + { + case GDK_Left: + case GDK_Right: + ephy_location_entry_autocompletion_hide_alternatives (w); + return FALSE; + case GDK_Up: + case GDK_Down: + case GDK_Page_Up: + case GDK_Page_Down: + ephy_location_entry_autocompletion_hide_alternatives (w); + //ephy_embed_grab_focus (window->active_embed); + return FALSE; + case GDK_Tab: + { + gchar *common_prefix = NULL; + gchar *text; + + ephy_location_entry_set_autocompletion_key (w); + + gtk_editable_delete_selection (GTK_EDITABLE (p->entry)); + text = ephy_location_entry_get_location (w); + ephy_location_entry_autocompletion_unselect_alternatives (w); + + if (p->autocompletion) + { + common_prefix = ephy_autocompletion_get_common_prefix (p->autocompletion); + } + suggest = FALSE; + if (common_prefix) + { + if (!p->before_completion) + { + p->before_completion = g_strdup (text); + } + + p->block_set_autocompletion_key = TRUE; + + gtk_entry_set_text (GTK_ENTRY (p->entry), common_prefix); + gtk_editable_set_position (GTK_EDITABLE (p->entry), -1); + + p->block_set_autocompletion_key = FALSE; + + ephy_location_entry_autocompletion_show_alternatives (w); + if (!strcmp (common_prefix, text)) + { + /* really suggest something the next time */ + suggest = TRUE; + } + g_free (common_prefix); + } + else + { + ephy_location_entry_autocompletion_hide_alternatives (w); + } + g_free (text); + return TRUE; + } + case GDK_Escape: + ephy_location_entry_autocompletion_hide_alternatives (w); + if (p->before_completion) + { + ephy_location_entry_set_location (w, p->before_completion); + g_free (p->before_completion); + p->before_completion = NULL; + gtk_editable_set_position (GTK_EDITABLE (p->entry), -1); + return TRUE; + } + break; + default: + ephy_location_entry_autocompletion_unselect_alternatives (w); + if ((event->string[0] > 32) && (event->string[0] < 126)) + { + p->show_alternatives_timeout = g_timeout_add + (SHOW_ALTERNATIVES_DELAY, + (GSourceFunc) ephy_location_entry_autocompletion_show_alternatives_to, w); + } + break; + } + + return FALSE; +} + +static gboolean +ephy_location_entry_content_is_text (const char *content) +{ + return ((g_strrstr (content, ".") == NULL) && + (g_strrstr (content, "/") == NULL)); +} + +static void +ephy_location_entry_activate_cb (GtkEntry *entry, EphyLocationEntry *w) +{ + char *content; + char *target = NULL; + + content = gtk_editable_get_chars (GTK_EDITABLE(entry), 0, -1); + if (ephy_location_entry_content_is_text (content)) + { + target = w->priv->last_action_target; + } + + ephy_location_entry_autocompletion_hide_alternatives (w); + + DEBUG_MSG (("In ephy_location_entry_activate_cb, activating %s\n", content)); + + g_signal_emit (w, EphyLocationEntrySignals[ACTIVATED], 0, target, content); + g_free (content); +} + +static void +ephy_location_entry_autocompletion_sources_changed_cb (EphyAutocompletion *aw, + EphyLocationEntry *w) +{ + EphyLocationEntryPrivate *p = w->priv; + + DEBUG_MSG (("in ephy_location_entry_autocompletion_sources_changed_cb\n")); + + if (p->autocompletion_timeout == 0 + && p->last_completion + && !strcmp (p->last_completion, gtk_entry_get_text (GTK_ENTRY (p->entry)))) + { + p->autocompletion_timeout = gtk_timeout_add + (AUTOCOMPLETION_DELAY, + (GSourceFunc) ephy_location_entry_autocompletion_to, w); + } + + if (p->show_alternatives_timeout == 0 + && p->autocompletion_window_visible) + { + p->show_alternatives_timeout = gtk_timeout_add + (SHOW_ALTERNATIVES_DELAY, + (GSourceFunc) ephy_location_entry_autocompletion_show_alternatives_to, w); + } +} + +void +ephy_location_entry_set_location (EphyLocationEntry *w, + const gchar *new_location) +{ + EphyLocationEntryPrivate *p = w->priv; + int pos; + gtk_editable_delete_text (GTK_EDITABLE (p->entry), 0, -1); + gtk_editable_insert_text (GTK_EDITABLE (p->entry), new_location, g_utf8_strlen (new_location, -1), + &pos); +} + +gchar * +ephy_location_entry_get_location (EphyLocationEntry *w) +{ + char *location = gtk_editable_get_chars (GTK_EDITABLE (w->priv->entry), 0, -1); + return location; +} + +void +ephy_location_entry_set_autocompletion (EphyLocationEntry *w, + EphyAutocompletion *ac) +{ + EphyLocationEntryPrivate *p = w->priv; + if (p->autocompletion) + { + g_signal_handlers_disconnect_matched (p->autocompletion, G_SIGNAL_MATCH_DATA, 0, 0, + NULL, NULL, w); + + g_signal_handlers_disconnect_matched (p->autocompletion_window, G_SIGNAL_MATCH_DATA, 0, 0, + NULL, NULL, w); + + g_object_unref (G_OBJECT (p->autocompletion)); + g_object_unref (p->autocompletion_window); + } + p->autocompletion = ac; + if (p->autocompletion) + { + g_object_ref (G_OBJECT (p->autocompletion)); + p->autocompletion_window = ephy_autocompletion_window_new (p->autocompletion, + p->entry); + g_signal_connect (p->autocompletion_window, "activated", + G_CALLBACK (ephy_location_entry_autocompletion_window_url_activated_cb), + w); + + g_signal_connect (p->autocompletion_window, "hidden", + G_CALLBACK (ephy_location_entry_autocompletion_window_hidden_cb), + w); + + g_signal_connect (p->autocompletion, "sources-changed", + G_CALLBACK (ephy_location_entry_autocompletion_sources_changed_cb), + w); + + ephy_location_entry_set_autocompletion_key (w); + } + +} + +static void +ephy_location_entry_autocompletion_window_url_activated_cb (EphyAutocompletionWindow *aw, + const char *target, + int action, + EphyLocationEntry *w) +{ + char *content; + + if (action) + { + if (w->priv->last_action_target) + g_free (w->priv->last_action_target); + w->priv->last_action_target = g_strdup (target); + } + else + { + ephy_location_entry_set_location (w, target); + } + + content = gtk_editable_get_chars (GTK_EDITABLE(w->priv->entry), 0, -1); + + DEBUG_MSG (("In location_entry_autocompletion_window_url_activated_cb, going to %s\n", content)); + + ephy_location_entry_autocompletion_hide_alternatives (w); + + g_signal_emit (w, EphyLocationEntrySignals[ACTIVATED], 0, + action ? content : NULL, target); + + g_free (content); +} + +static void +ephy_location_entry_autocompletion_window_hidden_cb (EphyAutocompletionWindow *aw, + EphyLocationEntry *w) +{ + EphyLocationEntryPrivate *p = w->priv; + + DEBUG_MSG (("In location_entry_autocompletion_window_hidden_cb\n")); + + p->autocompletion_window_visible = FALSE; + + if (p->show_alternatives_timeout) + { + g_source_remove (p->show_alternatives_timeout); + p->show_alternatives_timeout = 0; + } + + if (p->autocompletion_timeout) + { + g_source_remove (p->autocompletion_timeout); + p->autocompletion_timeout = 0; + } +} + +void +ephy_location_entry_activate (EphyLocationEntry *w) +{ + GtkWidget *toplevel; + + toplevel = gtk_widget_get_toplevel (w->priv->entry); + + gtk_editable_select_region (GTK_EDITABLE(w->priv->entry), + 0, -1); + gtk_window_set_focus (GTK_WINDOW(toplevel), + w->priv->entry); +} + + +static void +ephy_location_entry_list_event_after_cb (GtkWidget *list, + GdkEvent *event, + EphyLocationEntry *e) +{ + if (event->type == GDK_BUTTON_PRESS + && ((GdkEventButton *) event)->button == 1) + { + gchar *url = ephy_location_entry_get_location (e); + g_signal_emit + (e, EphyLocationEntrySignals[ACTIVATED], 0, url); + g_free (url); + } +} + +static void +ephy_location_entry_editable_changed_cb (GtkEditable *editable, EphyLocationEntry *e) +{ + ephy_location_entry_set_autocompletion_key (e); +} + +static void +ephy_location_entry_set_autocompletion_key (EphyLocationEntry *e) +{ + EphyLocationEntryPrivate *p = e->priv; + if (p->autocompletion && !p->block_set_autocompletion_key) + { + GtkEditable *editable = GTK_EDITABLE (p->entry); + gint sstart, send; + gchar *text; + gtk_editable_get_selection_bounds (editable, &sstart, &send); + text = gtk_editable_get_chars (editable, 0, sstart); + ephy_autocompletion_set_key (p->autocompletion, text); + g_free (p->autocompletion_key); + p->autocompletion_key = text; + } +} + diff --git a/lib/widgets/ephy-location-entry.h b/lib/widgets/ephy-location-entry.h new file mode 100644 index 000000000..eebacc770 --- /dev/null +++ b/lib/widgets/ephy-location-entry.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_LOCATION_ENTRY_H +#define EPHY_LOCATION_ENTRY_H + +#include <glib-object.h> +#include <gtk/gtkhbox.h> + +#include "ephy-autocompletion.h" + +/* object forward declarations */ + +typedef struct _EphyLocationEntry EphyLocationEntry; +typedef struct _EphyLocationEntryClass EphyLocationEntryClass; +typedef struct _EphyLocationEntryPrivate EphyLocationEntryPrivate; + +/** + * EphyFolderTbWidget object + */ + +#define EPHY_TYPE_LOCATION_ENTRY (ephy_location_entry_get_type()) +#define EPHY_LOCATION_ENTRY(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_LOCATION_ENTRY,\ + EphyLocationEntry)) +#define EPHY_LOCATION_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_LOCATION_ENTRY,\ + EphyLocationEntryClass)) +#define EPHY_IS_LOCATION_ENTRY(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_LOCATION_ENTRY)) +#define EPHY_IS_LOCATION_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_LOCATION_ENTRY)) +#define EPHY_LOCATION_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_LOCATION_ENTRY,\ + EphyLocationEntryClass)) + +struct _EphyLocationEntryClass +{ + GtkHBoxClass parent_class; + + /* signals */ + void (*activated) (EphyLocationEntry *w, + const char *content, + const char *target); +}; + +/* Remember: fields are public read-only */ +struct _EphyLocationEntry +{ + GtkHBox parent_object; + + EphyLocationEntryPrivate *priv; +}; + +GType ephy_location_entry_get_type (void); +EphyLocationEntry * ephy_location_entry_new (void); +void ephy_location_entry_set_location (EphyLocationEntry *w, + const gchar *new_location); +gchar * ephy_location_entry_get_location (EphyLocationEntry *w); +void ephy_location_entry_set_autocompletion (EphyLocationEntry *w, + EphyAutocompletion *ac); +void ephy_location_entry_activate (EphyLocationEntry *w); + +#endif diff --git a/lib/widgets/ephy-notebook.c b/lib/widgets/ephy-notebook.c new file mode 100644 index 000000000..c03dc878a --- /dev/null +++ b/lib/widgets/ephy-notebook.c @@ -0,0 +1,843 @@ +/* + * Copyright (C) 2002 Christophe Fergeau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-notebook.h" +#include "eel-gconf-extensions.h" +#include "ephy-prefs.h" +#include "ephy-marshal.h" + +#include <gtk/gtk.h> +#include <glib-object.h> +#include <libgnome/gnome-i18n.h> + +#define AFTER_ALL_TABS -1 +#define NOT_IN_APP_WINDOWS -2 +#define TAB_MIN_SIZE 60 +#define TAB_NB_MAX 8 + +struct EphyNotebookPrivate +{ + GList *focused_pages; + GList *opened_tabs; + + /* Used during tab drag'n'drop */ + gulong motion_notify_handler_id; + gint x_start, y_start; + gboolean drag_in_progress; + EphyNotebook *src_notebook; + gint src_page; +}; + +/* GObject boilerplate code */ +static void ephy_notebook_init (EphyNotebook *notebook); +static void ephy_notebook_class_init (EphyNotebookClass *klass); +static void ephy_notebook_finalize (GObject *object); + +/* Local variables */ +static GdkCursor *cursor = NULL; +static GList *notebooks = NULL; + + +/* Local functions */ +static void drag_start (EphyNotebook *notebook, + EphyNotebook *src_notebook, + gint src_page); +static void drag_stop (EphyNotebook *notebook); + +static gboolean motion_notify_cb (EphyNotebook *notebook, + GdkEventMotion *event, + gpointer data); + +/* Signals */ +enum +{ + TAB_DROPPED, + TAB_DETACHED, + LAST_SIGNAL +}; + +static guint ephy_notebook_signals[LAST_SIGNAL] = { 0 }; + +GType +ephy_notebook_get_type (void) +{ + static GType ephy_notebook_type = 0; + + if (ephy_notebook_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyNotebookClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_notebook_class_init, + NULL, + NULL, /* class_data */ + sizeof (EphyNotebook), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_notebook_init + }; + + ephy_notebook_type = g_type_register_static (GTK_TYPE_NOTEBOOK, + "EphyNotebook", + &our_info, 0); + } + + return ephy_notebook_type; +} + +static void +ephy_notebook_class_init (EphyNotebookClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = ephy_notebook_finalize; + + /* init signals */ + ephy_notebook_signals[TAB_DROPPED] = + g_signal_new ("tab_dropped", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyNotebookClass, + tab_dropped), + NULL, NULL, + ephy_marshal_VOID__OBJECT_OBJECT_INT, + G_TYPE_NONE, + 3, + GTK_TYPE_WIDGET, + EPHY_NOTEBOOK_TYPE, + G_TYPE_INT); + ephy_notebook_signals[TAB_DETACHED] = + g_signal_new ("tab_detached", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyNotebookClass, + tab_detached), + NULL, NULL, + ephy_marshal_VOID__INT_INT_INT, + G_TYPE_NONE, + 3, + G_TYPE_INT, + G_TYPE_INT, + G_TYPE_INT); + +} + +static gboolean +is_in_notebook_window (EphyNotebook *notebook, + gint abs_x, gint abs_y) +{ + gint x, y; + gint rel_x, rel_y; + gint width, height; + GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET(notebook)); + GdkWindow *window = GTK_WIDGET(toplevel)->window; + + gdk_window_get_origin (window, &x, &y); + rel_x = abs_x - x; + rel_y = abs_y - y; + + x = GTK_WIDGET(notebook)->allocation.x; + y = GTK_WIDGET(notebook)->allocation.y; + height = GTK_WIDGET(notebook)->allocation.height; + width = GTK_WIDGET(notebook)->allocation.width; + return ((rel_x>=x) && (rel_y>=y) && (rel_x<=x+width) && (rel_y<=y+height)); +} + +static EphyNotebook * +find_notebook_at_pointer (gint abs_x, gint abs_y) +{ + GList *l; + gint x, y; + GdkWindow *win_at_pointer = gdk_window_at_pointer (&x, &y); + GdkWindow *parent_at_pointer = NULL; + + if (win_at_pointer == NULL) + { + /* We are outside all windows containing a notebook */ + return NULL; + } + + gdk_window_get_toplevel (win_at_pointer); + /* When we are in the notebook event window, win_at_pointer will be + this event window, and the toplevel window we are interested in + will be its parent + */ + parent_at_pointer = gdk_window_get_parent (win_at_pointer); + + for (l = notebooks; l != NULL; l = l->next) + { + EphyNotebook *nb = EPHY_NOTEBOOK (l->data); + GdkWindow *win = GTK_WIDGET (nb)->window; + + win = gdk_window_get_toplevel (win); + if (((win == win_at_pointer) || (win == parent_at_pointer)) + && is_in_notebook_window (nb, abs_x, abs_y)) + { + return nb; + } + } + return NULL; +} + + +static gint +find_tab_num_at_pos (EphyNotebook *notebook, gint abs_x, gint abs_y) +{ + GtkPositionType tab_pos; + int page_num = 0; + GtkNotebook *nb = GTK_NOTEBOOK (notebook); + GtkWidget *page; + + tab_pos = gtk_notebook_get_tab_pos (GTK_NOTEBOOK (notebook)); + + if (GTK_NOTEBOOK (notebook)->first_tab == NULL) + { + return AFTER_ALL_TABS; + } + + g_assert (is_in_notebook_window(notebook, abs_x, abs_y)); + + while ((page = gtk_notebook_get_nth_page (nb, page_num))) + { + GtkWidget *tab; + gint max_x, max_y; + gint x_root, y_root; + + tab = gtk_notebook_get_tab_label (nb, page); + g_return_val_if_fail (tab != NULL, -1); + + if (!GTK_WIDGET_MAPPED (GTK_WIDGET (tab))) + { + page_num++; + continue; + } + + gdk_window_get_origin (GDK_WINDOW (tab->window), + &x_root, &y_root); + + max_x = x_root + tab->allocation.x + tab->allocation.width; + max_y = y_root + tab->allocation.y + tab->allocation.height; + + if (((tab_pos == GTK_POS_TOP) + || (tab_pos == GTK_POS_BOTTOM)) + &&(abs_x<=max_x)) + { + return page_num; + } + else if (((tab_pos == GTK_POS_LEFT) + || (tab_pos == GTK_POS_RIGHT)) + && (abs_y<=max_y)) + { + return page_num; + } + + page_num++; + } + return AFTER_ALL_TABS; +} + + +static gint find_notebook_and_tab_at_pos (gint abs_x, gint abs_y, + EphyNotebook **notebook, + gint *page_num) +{ + *notebook = find_notebook_at_pointer (abs_x, abs_y); + if (*notebook == NULL) + { + return NOT_IN_APP_WINDOWS; + } + *page_num = find_tab_num_at_pos (*notebook, abs_x, abs_y); + + if (*page_num < 0) + { + return *page_num; + } + else + { + return 0; + } +} + +static void +tab_label_set_size (GtkWidget *window, GtkWidget *label) +{ + int label_width; + + label_width = window->allocation.width/TAB_NB_MAX; + + if (label_width < TAB_MIN_SIZE) label_width = TAB_MIN_SIZE; + + gtk_widget_set_size_request (label, label_width, -1); +} + +static GtkWidget * +tab_get_label (EphyNotebook *nb, GtkWidget *child) +{ + GtkWidget *hbox, *label; + + hbox = gtk_notebook_get_tab_label (GTK_NOTEBOOK (nb), + child); + label = g_object_get_data (G_OBJECT (hbox), "label"); + + return label; +} + +static void +tab_label_size_request_cb (GtkWidget *window, + GtkRequisition *requisition, + GtkWidget *child) +{ + GtkWidget *hbox; + GtkWidget *nb; + + nb = child->parent; + + hbox = gtk_notebook_get_tab_label (GTK_NOTEBOOK (nb), + child); + tab_label_set_size (window, hbox); +} + + +void +ephy_notebook_move_page (EphyNotebook *src, EphyNotebook *dest, + GtkWidget *src_page, gint dest_page) +{ + GtkWidget *tab_label; + + tab_label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (src), src_page); + + /* We don't want gtk to destroy tab and src_page behind our back */ + g_object_ref (G_OBJECT (src_page)); + g_object_ref (G_OBJECT (tab_label)); + ephy_notebook_remove_page (EPHY_NOTEBOOK (src), src_page); + ephy_notebook_insert_page (EPHY_NOTEBOOK (dest), src_page, + dest_page, TRUE); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (dest), src_page, tab_label); + g_object_unref (G_OBJECT (src_page)); + g_object_unref (G_OBJECT (tab_label)); +} + + + +static void +move_tab_to_another_notebook(EphyNotebook *src, + EphyNotebook *dest, gint dest_page) +{ + GtkWidget *child; + gint cur_page; + + /* This is getting tricky, the tab was dragged in a notebook + * in another window of the same app, we move the tab + * to that new notebook, and let this notebook handle the + * drag + */ + g_assert (dest != NULL); + g_assert (dest != src); + + /* Move the widgets (tab label and tab content) to the new + * notebook + */ + cur_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (src)); + child = gtk_notebook_get_nth_page (GTK_NOTEBOOK (src), cur_page); + ephy_notebook_move_page (src, dest, child, dest_page); + + /* "Give" drag handling to the new notebook */ + drag_start (dest, src->priv->src_notebook, src->priv->src_page); + drag_stop (src); + gtk_grab_remove (GTK_WIDGET (src)); + + dest->priv->motion_notify_handler_id = + g_signal_connect (G_OBJECT (dest), + "motion-notify-event", + G_CALLBACK (motion_notify_cb), + NULL); +} + + +static void +move_tab (EphyNotebook *notebook, gint dest_page_num) +{ + gint cur_page_num; + + cur_page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook)); + + if (dest_page_num != cur_page_num) + { + GtkWidget *cur_page; + cur_page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), + cur_page_num); + gtk_notebook_reorder_child (GTK_NOTEBOOK (notebook), cur_page, + dest_page_num); + + /* Reset the list of newly opened tabs when moving tabs. */ + g_list_free (notebook->priv->opened_tabs); + notebook->priv->opened_tabs = NULL; + } +} + +static void +drag_start (EphyNotebook *notebook, + EphyNotebook *src_notebook, + gint src_page) +{ + notebook->priv->drag_in_progress = TRUE; + notebook->priv->src_notebook = src_notebook; + notebook->priv->src_page = src_page; + + /* get a new cursor, if necessary */ + if (!cursor) cursor = gdk_cursor_new (GDK_FLEUR); + + /* grab the pointer */ + gtk_grab_add (GTK_WIDGET (notebook)); + if (!gdk_pointer_is_grabbed ()) { + gdk_pointer_grab (GDK_WINDOW(GTK_WIDGET (notebook)->window), + FALSE, + GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, + NULL, cursor, GDK_CURRENT_TIME); + } +} + +static void +drag_stop (EphyNotebook *notebook) +{ + notebook->priv->drag_in_progress = FALSE; + notebook->priv->src_notebook = NULL; + notebook->priv->src_page = -1; + if (notebook->priv->motion_notify_handler_id != 0) + { + g_signal_handler_disconnect (G_OBJECT (notebook), + notebook->priv->motion_notify_handler_id); + notebook->priv->motion_notify_handler_id = 0; + } +} + +/* Callbacks */ +static gboolean +button_release_cb (EphyNotebook *notebook, GdkEventButton *event, + gpointer data) +{ + if (notebook->priv->drag_in_progress) + { + gint cur_page_num; + GtkWidget *cur_page; + + cur_page_num = + gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook)); + cur_page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), + cur_page_num); + + if (!is_in_notebook_window (notebook, event->x_root, event->y_root)) + { + /* Tab was detached */ + g_signal_emit (G_OBJECT(notebook), + ephy_notebook_signals[TAB_DETACHED], 0, + cur_page_num, (gint)event->x_root, + (gint)event->y_root); + } + else + { + /* Tab was dragged and dropped (but it may have stayed + in the same place) */ + g_signal_emit (G_OBJECT(notebook), + ephy_notebook_signals[TAB_DROPPED], 0, + cur_page, + notebook->priv->src_notebook, + notebook->priv->src_page); + } + + /* ungrab the pointer if it's grabbed */ + if (gdk_pointer_is_grabbed ()) + { + gdk_pointer_ungrab (GDK_CURRENT_TIME); + gtk_grab_remove (GTK_WIDGET (notebook)); + } + } + /* This must be called even if a drag isn't happening */ + drag_stop (notebook); + return FALSE; +} + + +static gboolean +motion_notify_cb (EphyNotebook *notebook, GdkEventMotion *event, + gpointer data) +{ + EphyNotebook *dest; + gint page_num; + gint result; + + /* If the notebook only has one tab, we don't want to do + * anything since ephy can't handle empty notebooks + */ + if (g_list_length (GTK_NOTEBOOK (notebook)->children) <= 1) { + return FALSE; + } + + if ((notebook->priv->drag_in_progress == FALSE) + && (gtk_drag_check_threshold (GTK_WIDGET (notebook), + notebook->priv->x_start, + notebook->priv->y_start, + event->x_root, event->y_root))) + { + gint cur_page; + + cur_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook)); + drag_start (notebook, notebook, cur_page); + } + + result = find_notebook_and_tab_at_pos ((gint)event->x_root, + (gint)event->y_root, + &dest, &page_num); + + if (result != NOT_IN_APP_WINDOWS) + { + if (dest != notebook) + { + move_tab_to_another_notebook (notebook, dest, + page_num); + } + else + { + g_assert (page_num >= -1); + move_tab (notebook, page_num); + } + } + + return FALSE; +} + +static gboolean +button_press_cb (EphyNotebook *notebook, + GdkEventButton *event, + gpointer data) +{ + gint tab_clicked = find_tab_num_at_pos (notebook, + event->x_root, + event->y_root); + + if (notebook->priv->drag_in_progress) + { + return TRUE; + } + + if ((event->button == 1) && (event->type == GDK_BUTTON_PRESS) + && (tab_clicked != -1)) + { + notebook->priv->x_start = event->x_root; + notebook->priv->y_start = event->y_root; + notebook->priv->motion_notify_handler_id = + g_signal_connect (G_OBJECT (notebook), + "motion-notify-event", + G_CALLBACK (motion_notify_cb), NULL); + } + + return FALSE; +} + +GtkWidget * +ephy_notebook_new (void) +{ + return GTK_WIDGET (g_object_new (EPHY_NOTEBOOK_TYPE, NULL)); +} + +static void +ephy_notebook_switch_page_cb (GtkNotebook *notebook, + GtkNotebookPage *page, + guint page_num, + gpointer data) +{ + EphyNotebook *nb = EPHY_NOTEBOOK (notebook); + GtkWidget *child; + + child = gtk_notebook_get_nth_page (notebook, page_num); + + /* Remove the old page, we dont want to grow unnecessarily + * the list */ + if (nb->priv->focused_pages) + { + nb->priv->focused_pages = + g_list_remove (nb->priv->focused_pages, child); + } + + nb->priv->focused_pages = g_list_append (nb->priv->focused_pages, + child); + + /* Reset the list of newly opened tabs when switching tabs. */ + g_list_free (nb->priv->opened_tabs); + nb->priv->opened_tabs = NULL; +} + +static void +ephy_notebook_init (EphyNotebook *notebook) +{ + notebook->priv = g_new (EphyNotebookPrivate, 1); + + notebook->priv->drag_in_progress = FALSE; + notebook->priv->motion_notify_handler_id = 0; + notebook->priv->src_notebook = NULL; + notebook->priv->src_page = -1; + notebook->priv->focused_pages = NULL; + notebook->priv->opened_tabs = NULL; + + notebooks = g_list_append (notebooks, notebook); + + g_signal_connect (notebook, "button-press-event", + (GCallback)button_press_cb, NULL); + g_signal_connect (notebook, "button-release-event", + (GCallback)button_release_cb, NULL); + gtk_widget_add_events (GTK_WIDGET (notebook), GDK_BUTTON1_MOTION_MASK); + + g_signal_connect_after (G_OBJECT (notebook), "switch_page", + G_CALLBACK (ephy_notebook_switch_page_cb), + NULL); +} + +static void +ephy_notebook_finalize (GObject *object) +{ + EphyNotebook *notebook = EPHY_NOTEBOOK (object); + + notebooks = g_list_remove (notebooks, notebook); + + if (notebook->priv->focused_pages) + { + g_list_free (notebook->priv->focused_pages); + } + g_list_free (notebook->priv->opened_tabs); + + g_free (notebook->priv); +} + + +void +ephy_notebook_set_page_status (EphyNotebook *nb, + GtkWidget *child, + EphyNotebookPageLoadStatus status) +{ +} + +static void +ephy_tab_close_button_clicked_cb (GtkWidget *widget, + GtkWidget *child) +{ + EphyNotebook *notebook; + + notebook = EPHY_NOTEBOOK (gtk_widget_get_parent (child)); + ephy_notebook_remove_page (notebook, child); +} + +static GtkWidget * +tab_build_label (EphyNotebook *nb, GtkWidget *child) +{ + GtkWidget *label, *hbox, *close_button, *image; + int h, w; + GClosure *closure; + GtkWidget *window; + + window = gtk_widget_get_toplevel (GTK_WIDGET (nb)); + + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h); + + hbox = gtk_hbox_new (FALSE, 0); + + /* setup close button */ + close_button = gtk_button_new (); + gtk_button_set_relief (GTK_BUTTON (close_button), + GTK_RELIEF_NONE); + image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, + GTK_ICON_SIZE_MENU); + gtk_widget_set_size_request (close_button, w, h); + gtk_container_add (GTK_CONTAINER (close_button), + image); + + /* setup label */ + label = gtk_label_new (_("Untitled")); + gtk_misc_set_alignment (GTK_MISC (label), 0.00, 0.5); + gtk_misc_set_padding (GTK_MISC (label), 4, 0); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); + + tab_label_set_size (GTK_WIDGET (window), hbox); + + closure = g_cclosure_new (G_CALLBACK (tab_label_size_request_cb), + child, NULL); + g_object_watch_closure (G_OBJECT (label), closure); + g_signal_connect_closure_by_id (G_OBJECT (window), + g_signal_lookup ("size_request", + G_OBJECT_TYPE (G_OBJECT (window))), 0, + closure, + FALSE); + + /* setup button */ + gtk_box_pack_start (GTK_BOX (hbox), close_button, + FALSE, FALSE, 0); + + g_signal_connect (G_OBJECT (close_button), "clicked", + G_CALLBACK (ephy_tab_close_button_clicked_cb), + child); + + gtk_widget_show (hbox); + gtk_widget_show (label); + gtk_widget_show (image); + gtk_widget_show (close_button); + + g_object_set_data (G_OBJECT (hbox), "label", label); + + return hbox; +} + +/* + * update_tabs_visibility: Hide tabs if there is only one tab + * and the pref is not set. + * HACK We need to show tabs before inserting the second. Otherwise + * gtknotebook go crazy. + */ +static void +update_tabs_visibility (EphyNotebook *nb, gboolean before_inserting) +{ + gboolean show_tabs; + guint tabs_num = 1; + + if (before_inserting) tabs_num--; + + show_tabs = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), tabs_num) > 0; + + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (nb), show_tabs); +} + +void +ephy_notebook_insert_page (EphyNotebook *nb, + GtkWidget *child, + int position, + gboolean jump_to) +{ + GtkWidget *tab_hbox; + + tab_hbox = tab_build_label (nb, child); + + update_tabs_visibility (nb, TRUE); + + if (position == EPHY_NOTEBOOK_INSERT_GROUPED) + { + /* Keep a list of newly opened tabs, if the list is empty open the new + * tab after the current one. If it's not, add it after the newly + * opened tabs. + */ + if (nb->priv->opened_tabs != NULL) + { + GList *last = g_list_last (nb->priv->opened_tabs); + GtkWidget *last_tab = last->data; + position = gtk_notebook_page_num + (GTK_NOTEBOOK (nb), last_tab) + 1; + } + else + { + position = gtk_notebook_get_current_page + (GTK_NOTEBOOK (nb)) + 1; + } + nb->priv->opened_tabs = + g_list_append (nb->priv->opened_tabs, child); + } + + gtk_notebook_insert_page (GTK_NOTEBOOK (nb), + child, + tab_hbox, position); + + if (jump_to) + { + gtk_notebook_set_current_page (GTK_NOTEBOOK (nb), + position); + g_object_set_data (G_OBJECT (child), "jump_to", + GINT_TO_POINTER (jump_to)); + } +} + +static void +smart_tab_switching_on_closure (EphyNotebook *nb, + GtkWidget *child) +{ + gboolean jump_to; + + jump_to = GPOINTER_TO_INT (g_object_get_data + (G_OBJECT (child), "jump_to")); + + if (!jump_to || !nb->priv->focused_pages) + { + gtk_notebook_next_page (GTK_NOTEBOOK (nb)); + } + else + { + GList *l; + GtkWidget *child; + int page_num; + + /* activate the last focused tab */ + l = g_list_last (nb->priv->focused_pages); + child = GTK_WIDGET (l->data); + page_num = gtk_notebook_page_num (GTK_NOTEBOOK (nb), + child); + gtk_notebook_set_current_page + (GTK_NOTEBOOK (nb), page_num); + } +} + +void +ephy_notebook_remove_page (EphyNotebook *nb, + GtkWidget *child) +{ + int position, cur; + gboolean last_tab; + + last_tab = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), 1) == NULL; + if (last_tab) + { + GtkWidget *window; + window = gtk_widget_get_toplevel (GTK_WIDGET (nb)); + gtk_widget_destroy (window); + return; + } + + /* Remove the page from the focused pages list */ + nb->priv->focused_pages = g_list_remove (nb->priv->focused_pages, + child); + nb->priv->opened_tabs = g_list_remove (nb->priv->opened_tabs, child); + + + position = gtk_notebook_page_num (GTK_NOTEBOOK (nb), + child); + + cur = gtk_notebook_get_current_page (GTK_NOTEBOOK (nb)); + if (position == cur) + { + smart_tab_switching_on_closure (nb, child); + } + + gtk_notebook_remove_page (GTK_NOTEBOOK (nb), position); + + update_tabs_visibility (nb, FALSE); +} + +void +ephy_notebook_set_page_title (EphyNotebook *nb, + GtkWidget *child, + const char *title) +{ + GtkWidget *label; + + label = tab_get_label (nb, child); + gtk_label_set_label (GTK_LABEL (label), title); +} diff --git a/lib/widgets/ephy-notebook.h b/lib/widgets/ephy-notebook.h new file mode 100644 index 000000000..755eea84d --- /dev/null +++ b/lib/widgets/ephy-notebook.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2002 Christophe Fergeau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_NOTEBOOK_H +#define EPHY_NOTEBOOK_H + +#include <glib.h> +#include <gtk/gtknotebook.h> + +G_BEGIN_DECLS + +typedef struct EphyNotebookClass EphyNotebookClass; + +#define EPHY_NOTEBOOK_TYPE (ephy_notebook_get_type ()) +#define EPHY_NOTEBOOK(obj) (GTK_CHECK_CAST ((obj), EPHY_NOTEBOOK_TYPE, EphyNotebook)) +#define EPHY_NOTEBOOK_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_NOTEBOOK_TYPE, EphyNotebookClass)) +#define IS_EPHY_NOTEBOOK(obj) (GTK_CHECK_TYPE ((obj), EPHY_NOTEBOOK_TYPE)) +#define IS_EPHY_NOTEBOOK_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_NOTEBOOK)) + +typedef struct EphyNotebook EphyNotebook; +typedef struct EphyNotebookPrivate EphyNotebookPrivate; + +typedef enum +{ + EPHY_NOTEBOOK_TAB_LOAD_NORMAL, + EPHY_NOTEBOOK_TAB_LOAD_LOADING, + EPHY_NOTEBOOK_TAB_LOAD_COMPLETED +} EphyNotebookPageLoadStatus; + +enum +{ + EPHY_NOTEBOOK_INSERT_LAST = -1, + EPHY_NOTEBOOK_INSERT_GROUPED = -2 +}; + +struct EphyNotebook +{ + GtkNotebook parent; + EphyNotebookPrivate *priv; +}; + +struct EphyNotebookClass +{ + GtkNotebookClass parent_class; + + /* Signals */ + void (* tab_dropped) (EphyNotebook *dest, + GtkWidget *widget, + EphyNotebook *src, + gint src_page); + void (* tab_detached) (EphyNotebook *dest, + gint cur_page, + gint root_x, gint root_y); + +}; + +GType ephy_notebook_get_type (void); + +GtkWidget *ephy_notebook_new (void); + +void ephy_notebook_insert_page (EphyNotebook *nb, + GtkWidget *child, + int position, + gboolean jump_to); + +void ephy_notebook_remove_page (EphyNotebook *nb, + GtkWidget *child); + +void ephy_notebook_move_page (EphyNotebook *src, + EphyNotebook *dest, + GtkWidget *src_page, + gint dest_page); + +void ephy_notebook_set_page_status (EphyNotebook *nb, + GtkWidget *child, + EphyNotebookPageLoadStatus status); + +void ephy_notebook_set_page_title (EphyNotebook *nb, + GtkWidget *child, + const char *title); + +G_END_DECLS; + +#endif /* EPHY_NOTEBOOK_H */ diff --git a/lib/widgets/ephy-spinner.c b/lib/widgets/ephy-spinner.c new file mode 100644 index 000000000..e4462f889 --- /dev/null +++ b/lib/widgets/ephy-spinner.c @@ -0,0 +1,897 @@ +/* + * Nautilus + * + * Copyright (C) 2000 Eazel, Inc. + * Copyright (C) 2002 Marco Pesenti Gritti + * + * Nautilus is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Nautilus is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andy Hertzfeld <andy@eazel.com> + * + * Ephy port by Marco Pesenti Gritti <marco@it.gnome.org> + * + * This is the spinner (for busy feedback) for the location bar + * + */ + +#include "config.h" +#include "ephy-spinner.h" +#include "eel-gconf-extensions.h" +#include "ephy-prefs.h" +#include "ephy-string.h" +#include "ephy-file-helpers.h" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gtk/gtkmenu.h> +#include <gtk/gtkmenuitem.h> +#include <gtk/gtksignal.h> +#include <libgnome/gnome-macros.h> +#include <libgnome/gnome-util.h> +#include <math.h> +#include <libgnomevfs/gnome-vfs.h> + +#define spinner_DEFAULT_TIMEOUT 100 /* Milliseconds Per Frame */ + +struct EphySpinnerDetails { + GList *image_list; + + GdkPixbuf *quiescent_pixbuf; + + int max_frame; + int delay; + int current_frame; + guint timer_task; + + gboolean ready; + gboolean small_mode; + + gboolean button_in; + gboolean button_down; + + gint theme_notif; +}; + +static void ephy_spinner_class_init (EphySpinnerClass *class); +static void ephy_spinner_init (EphySpinner *spinner); +static void ephy_spinner_load_images (EphySpinner *spinner); +static void ephy_spinner_unload_images (EphySpinner *spinner); +static void ephy_spinner_remove_update_callback (EphySpinner *spinner); + + +static GList *spinner_directories = NULL; + +static void +ephy_spinner_init_directory_list (void); +static void +ephy_spinner_search_directory (const gchar *base, GList **spinner_list); +static EphySpinnerInfo * +ephy_spinner_get_theme_info (const gchar *base, const gchar *theme_name); +static gchar * +ephy_spinner_get_theme_path (const gchar *theme_name); + + +static GObjectClass *parent_class = NULL; + +GType +ephy_spinner_get_type (void) +{ + static GType ephy_spinner_type = 0; + + if (ephy_spinner_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphySpinnerClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_spinner_class_init, + NULL, + NULL, /* class_data */ + sizeof (EphySpinner), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_spinner_init + }; + + ephy_spinner_type = g_type_register_static (GTK_TYPE_EVENT_BOX, + "EphySpinner", + &our_info, 0); + + ephy_spinner_init_directory_list (); + } + + return ephy_spinner_type; + +} + +/* + * ephy_spinner_new: + * + * Create a new #EphySpinner. The spinner is a widget + * that gives the user feedback about network status with + * an animated image. + * + * Return Value: the spinner #GtkWidget + **/ +GtkWidget * +ephy_spinner_new (void) +{ + GtkWidget *s; + + s = GTK_WIDGET (g_object_new (EPHY_SPINNER_TYPE, NULL)); + + return s; +} + +static gboolean +is_throbbing (EphySpinner *spinner) +{ + return spinner->details->timer_task != 0; +} + +/* loop through all the images taking their union to compute the width and height of the spinner */ +static void +get_spinner_dimensions (EphySpinner *spinner, int *spinner_width, int* spinner_height) +{ + int current_width, current_height; + int pixbuf_width, pixbuf_height; + GList *current_entry; + GdkPixbuf *pixbuf; + + /* start with the quiescent image */ + current_width = gdk_pixbuf_get_width (spinner->details->quiescent_pixbuf); + current_height = gdk_pixbuf_get_height (spinner->details->quiescent_pixbuf); + + /* loop through all the installed images, taking the union */ + current_entry = spinner->details->image_list; + while (current_entry != NULL) { + pixbuf = GDK_PIXBUF (current_entry->data); + pixbuf_width = gdk_pixbuf_get_width (pixbuf); + pixbuf_height = gdk_pixbuf_get_height (pixbuf); + + if (pixbuf_width > current_width) { + current_width = pixbuf_width; + } + + if (pixbuf_height > current_height) { + current_height = pixbuf_height; + } + + current_entry = current_entry->next; + } + + /* return the result */ + *spinner_width = current_width; + *spinner_height = current_height; +} + +/* handler for handling theme changes */ +static void +ephy_spinner_theme_changed (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) +{ + EphySpinner *spinner; + + spinner = EPHY_SPINNER (user_data); + gtk_widget_hide (GTK_WIDGET (spinner)); + ephy_spinner_load_images (spinner); + gtk_widget_show (GTK_WIDGET (spinner)); + gtk_widget_queue_resize ( GTK_WIDGET (spinner)); +} + +static void +ephy_spinner_init (EphySpinner *spinner) +{ + GtkWidget *widget = GTK_WIDGET (spinner); + + GTK_WIDGET_UNSET_FLAGS (spinner, GTK_NO_WINDOW); + + gtk_widget_set_events (widget, + gtk_widget_get_events (widget) + | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); + + spinner->details = g_new0 (EphySpinnerDetails, 1); + + spinner->details->delay = spinner_DEFAULT_TIMEOUT; + + ephy_spinner_load_images (spinner); + gtk_widget_show (widget); + + spinner->details->theme_notif = + eel_gconf_notification_add (CONF_TOOLBAR_SPINNER_THEME, + (GConfClientNotifyFunc) + ephy_spinner_theme_changed, + spinner); +} + +/* here's the routine that selects the image to draw, based on the spinner's state */ + +static GdkPixbuf * +select_spinner_image (EphySpinner *spinner) +{ + GList *element; + + if (spinner->details->timer_task == 0) { + return g_object_ref (spinner->details->quiescent_pixbuf); + } + + if (spinner->details->image_list == NULL) { + return NULL; + } + + element = g_list_nth (spinner->details->image_list, spinner->details->current_frame); + + return g_object_ref (element->data); +} + +static guchar +lighten_component (guchar cur_value) +{ + int new_value = cur_value; + new_value += 24 + (new_value >> 3); + if (new_value > 255) { + new_value = 255; + } + return (guchar) new_value; +} + +static GdkPixbuf * +create_new_pixbuf (GdkPixbuf *src) +{ + g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL); + g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 3) + || (gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 4), NULL); + + return gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src), + gdk_pixbuf_get_has_alpha (src), + gdk_pixbuf_get_bits_per_sample (src), + gdk_pixbuf_get_width (src), + gdk_pixbuf_get_height (src)); +} + +static GdkPixbuf * +eel_create_darkened_pixbuf (GdkPixbuf *src, int saturation, int darken) +{ + gint i, j; + gint width, height, src_row_stride, dest_row_stride; + gboolean has_alpha; + guchar *target_pixels, *original_pixels; + guchar *pixsrc, *pixdest; + guchar intensity; + guchar alpha; + guchar negalpha; + guchar r, g, b; + GdkPixbuf *dest; + + g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL); + g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 3) + || (gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 4), NULL); + g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (src) == 8, NULL); + + dest = create_new_pixbuf (src); + + has_alpha = gdk_pixbuf_get_has_alpha (src); + width = gdk_pixbuf_get_width (src); + height = gdk_pixbuf_get_height (src); + dest_row_stride = gdk_pixbuf_get_rowstride (dest); + src_row_stride = gdk_pixbuf_get_rowstride (src); + target_pixels = gdk_pixbuf_get_pixels (dest); + original_pixels = gdk_pixbuf_get_pixels (src); + + for (i = 0; i < height; i++) { + pixdest = target_pixels + i * dest_row_stride; + pixsrc = original_pixels + i * src_row_stride; + for (j = 0; j < width; j++) { + r = *pixsrc++; + g = *pixsrc++; + b = *pixsrc++; + intensity = (r * 77 + g * 150 + b * 28) >> 8; + negalpha = ((255 - saturation) * darken) >> 8; + alpha = (saturation * darken) >> 8; + *pixdest++ = (negalpha * intensity + alpha * r) >> 8; + *pixdest++ = (negalpha * intensity + alpha * g) >> 8; + *pixdest++ = (negalpha * intensity + alpha * b) >> 8; + if (has_alpha) { + *pixdest++ = *pixsrc++; + } + } + } + return dest; +} + +static GdkPixbuf * +eel_create_spotlight_pixbuf (GdkPixbuf* src) +{ + GdkPixbuf *dest; + int i, j; + int width, height, has_alpha, src_row_stride, dst_row_stride; + guchar *target_pixels, *original_pixels; + guchar *pixsrc, *pixdest; + + g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL); + g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 3) + || (gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 4), NULL); + g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (src) == 8, NULL); + + dest = create_new_pixbuf (src); + + has_alpha = gdk_pixbuf_get_has_alpha (src); + width = gdk_pixbuf_get_width (src); + height = gdk_pixbuf_get_height (src); + dst_row_stride = gdk_pixbuf_get_rowstride (dest); + src_row_stride = gdk_pixbuf_get_rowstride (src); + target_pixels = gdk_pixbuf_get_pixels (dest); + original_pixels = gdk_pixbuf_get_pixels (src); + + for (i = 0; i < height; i++) { + pixdest = target_pixels + i * dst_row_stride; + pixsrc = original_pixels + i * src_row_stride; + for (j = 0; j < width; j++) { + *pixdest++ = lighten_component (*pixsrc++); + *pixdest++ = lighten_component (*pixsrc++); + *pixdest++ = lighten_component (*pixsrc++); + if (has_alpha) { + *pixdest++ = *pixsrc++; + } + } + } + return dest; +} + +/* handle expose events */ + +static int +ephy_spinner_expose (GtkWidget *widget, GdkEventExpose *event) +{ + EphySpinner *spinner; + GdkPixbuf *pixbuf, *massaged_pixbuf; + int x_offset, y_offset, width, height; + GdkRectangle pix_area, dest; + + g_return_val_if_fail (IS_EPHY_SPINNER (widget), FALSE); + + spinner = EPHY_SPINNER (widget); + if (!spinner->details->ready) { + return FALSE; + } + + pixbuf = select_spinner_image (spinner); + if (pixbuf == NULL) { + return FALSE; + } + + /* Get the right tint on the image */ + + if (spinner->details->button_in) { + if (spinner->details->button_down) { + massaged_pixbuf = eel_create_darkened_pixbuf (pixbuf, 0.8 * 255, 0.8 * 255); + } else { + massaged_pixbuf = eel_create_spotlight_pixbuf (pixbuf); + } + g_object_unref (pixbuf); + pixbuf = massaged_pixbuf; + } + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + + /* Compute the offsets for the image centered on our allocation */ + x_offset = widget->allocation.x + (widget->allocation.width - width) / 2; + y_offset = widget->allocation.y + (widget->allocation.height - height) / 2; + + pix_area.x = x_offset; + pix_area.y = y_offset; + pix_area.width = width; + pix_area.height = height; + + if (!gdk_rectangle_intersect (&event->area, &pix_area, &dest)) { + g_object_unref (pixbuf); + return FALSE; + } + + gdk_pixbuf_render_to_drawable_alpha ( + pixbuf, widget->window, + dest.x - x_offset, dest.y - y_offset, + dest.x, dest.y, + dest.width, dest.height, + GDK_PIXBUF_ALPHA_BILEVEL, 128, + GDK_RGB_DITHER_MAX, + 0, 0); + + g_object_unref (pixbuf); + + return FALSE; +} + +static void +ephy_spinner_map (GtkWidget *widget) +{ + EphySpinner *spinner; + + spinner = EPHY_SPINNER (widget); + + GTK_WIDGET_CLASS (parent_class)->map (widget); + + spinner->details->ready = TRUE; +} + +/* here's the actual timeout task to bump the frame and schedule a redraw */ + +static gboolean +bump_spinner_frame (gpointer callback_data) +{ + EphySpinner *spinner; + + spinner = EPHY_SPINNER (callback_data); + if (!spinner->details->ready) { + return TRUE; + } + + spinner->details->current_frame += 1; + if (spinner->details->current_frame > spinner->details->max_frame - 1) { + spinner->details->current_frame = 0; + } + + gtk_widget_queue_draw (GTK_WIDGET (spinner)); + return TRUE; +} + +/** + * ephy_spinner_start: + * @spinner: a #EphySpinner + * + * Start the spinner animation. + **/ +void +ephy_spinner_start (EphySpinner *spinner) +{ + if (is_throbbing (spinner)) { + return; + } + + if (spinner->details->timer_task != 0) { + gtk_timeout_remove (spinner->details->timer_task); + } + + /* reset the frame count */ + spinner->details->current_frame = 0; + spinner->details->timer_task = gtk_timeout_add (spinner->details->delay, + bump_spinner_frame, + spinner); +} + +static void +ephy_spinner_remove_update_callback (EphySpinner *spinner) +{ + if (spinner->details->timer_task != 0) { + gtk_timeout_remove (spinner->details->timer_task); + } + + spinner->details->timer_task = 0; +} + +/** + * ephy_spinner_stop: + * @spinner: a #EphySpinner + * + * Stop the spinner animation. + **/ +void +ephy_spinner_stop (EphySpinner *spinner) +{ + if (!is_throbbing (spinner)) { + return; + } + + ephy_spinner_remove_update_callback (spinner); + gtk_widget_queue_draw (GTK_WIDGET (spinner)); + +} + +/* routines to load the images used to draw the spinner */ + +/* unload all the images, and the list itself */ + +static void +ephy_spinner_unload_images (EphySpinner *spinner) +{ + GList *current_entry; + + if (spinner->details->quiescent_pixbuf != NULL) { + g_object_unref (spinner->details->quiescent_pixbuf); + spinner->details->quiescent_pixbuf = NULL; + } + + /* unref all the images in the list, and then let go of the list itself */ + current_entry = spinner->details->image_list; + while (current_entry != NULL) { + g_object_unref (current_entry->data); + current_entry = current_entry->next; + } + + g_list_free (spinner->details->image_list); + spinner->details->image_list = NULL; +} + +static GdkPixbuf* +load_themed_image (const char *path, const char *file_name, + gboolean small_mode) +{ + GdkPixbuf *pixbuf, *temp_pixbuf; + char *image_path; + + image_path = g_build_filename (path, file_name, NULL); + + if (!g_file_test(image_path, G_FILE_TEST_EXISTS)) + { + g_free (image_path); + return NULL; + } + + if (image_path) { + pixbuf = gdk_pixbuf_new_from_file (image_path, NULL); + + if (small_mode && pixbuf) { + temp_pixbuf = gdk_pixbuf_scale_simple (pixbuf, + gdk_pixbuf_get_width (pixbuf) * 2 / 3, + gdk_pixbuf_get_height (pixbuf) * 2 / 3, + GDK_INTERP_BILINEAR); + g_object_unref (pixbuf); + pixbuf = temp_pixbuf; + } + + g_free (image_path); + + return pixbuf; + } + return NULL; +} + +/* utility to make the spinner frame name from the index */ + +static char * +make_spinner_frame_name (int index) +{ + return g_strdup_printf ("%03d.png", index); +} + +/* load all of the images of the spinner sequentially */ +static void +ephy_spinner_load_images (EphySpinner *spinner) +{ + int index; + char *spinner_frame_name; + GdkPixbuf *pixbuf, *qpixbuf; + GList *image_list; + char *image_theme; + char *path; + + ephy_spinner_unload_images (spinner); + + image_theme = eel_gconf_get_string (CONF_TOOLBAR_SPINNER_THEME); + + path = ephy_spinner_get_theme_path (image_theme); + g_return_if_fail (path != NULL); + + qpixbuf = load_themed_image (path, "rest.png", + spinner->details->small_mode); + + g_return_if_fail (qpixbuf != NULL); + spinner->details->quiescent_pixbuf = qpixbuf; + + spinner->details->max_frame = 50; + + image_list = NULL; + for (index = 1; index <= spinner->details->max_frame; index++) { + spinner_frame_name = make_spinner_frame_name (index); + pixbuf = load_themed_image (path, spinner_frame_name, + spinner->details->small_mode); + g_free (spinner_frame_name); + if (pixbuf == NULL) { + spinner->details->max_frame = index - 1; + break; + } + image_list = g_list_prepend (image_list, pixbuf); + } + spinner->details->image_list = g_list_reverse (image_list); + + g_free (image_theme); +} + +static gboolean +ephy_spinner_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event) +{ + EphySpinner *spinner; + + spinner = EPHY_SPINNER (widget); + + if (!spinner->details->button_in) { + spinner->details->button_in = TRUE; + gtk_widget_queue_draw (widget); + } + + return FALSE; +} + +static gboolean +ephy_spinner_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event) +{ + EphySpinner *spinner; + + spinner = EPHY_SPINNER (widget); + + if (spinner->details->button_in) { + spinner->details->button_in = FALSE; + gtk_widget_queue_draw (widget); + } + + return FALSE; +} + +/* handle button presses by posting a change on the "location" property */ + +static gboolean +ephy_spinner_button_press_event (GtkWidget *widget, GdkEventButton *event) +{ + EphySpinner *spinner; + + spinner = EPHY_SPINNER (widget); + + if (event->button == 1) { + spinner->details->button_down = TRUE; + spinner->details->button_in = TRUE; + gtk_widget_queue_draw (widget); + return TRUE; + } + + return FALSE; +} + +static void +ephy_spinner_set_location (EphySpinner *spinner) +{ +} + +static gboolean +ephy_spinner_button_release_event (GtkWidget *widget, GdkEventButton *event) +{ + EphySpinner *spinner; + + spinner = EPHY_SPINNER (widget); + + if (event->button == 1) { + if (spinner->details->button_in) { + ephy_spinner_set_location (spinner); + } + spinner->details->button_down = FALSE; + gtk_widget_queue_draw (widget); + return TRUE; + } + + return FALSE; +} + +/* + * ephy_spinner_set_small_mode: + * @spinner: a #EphySpinner + * @new_mode: pass true to enable the small mode, false to disable + * + * Set the size mode of the spinner. We need a small mode to deal + * with only icons toolbars. + **/ +void +ephy_spinner_set_small_mode (EphySpinner *spinner, gboolean new_mode) +{ + if (new_mode != spinner->details->small_mode) { + spinner->details->small_mode = new_mode; + ephy_spinner_load_images (spinner); + + gtk_widget_queue_resize (GTK_WIDGET (spinner)); + } +} + +/* handle setting the size */ + +static void +ephy_spinner_size_request (GtkWidget *widget, GtkRequisition *requisition) +{ + int spinner_width, spinner_height; + EphySpinner *spinner = EPHY_SPINNER (widget); + + get_spinner_dimensions (spinner, &spinner_width, &spinner_height); + + /* allocate some extra margin so we don't butt up against toolbar edges */ + requisition->width = spinner_width + 8; + requisition->height = spinner_height; +} + +static void +ephy_spinner_finalize (GObject *object) +{ + EphySpinner *spinner; + + spinner = EPHY_SPINNER (object); + + ephy_spinner_remove_update_callback (spinner); + ephy_spinner_unload_images (spinner); + + eel_gconf_notification_remove (spinner->details->theme_notif); + + g_free (spinner->details); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +ephy_spinner_class_init (EphySpinnerClass *class) +{ + GtkWidgetClass *widget_class; + + parent_class = g_type_class_peek_parent (class); + widget_class = GTK_WIDGET_CLASS (class); + + G_OBJECT_CLASS (class)->finalize = ephy_spinner_finalize; + + widget_class->expose_event = ephy_spinner_expose; + widget_class->button_press_event = ephy_spinner_button_press_event; + widget_class->button_release_event = ephy_spinner_button_release_event; + widget_class->enter_notify_event = ephy_spinner_enter_notify_event; + widget_class->leave_notify_event = ephy_spinner_leave_notify_event; + widget_class->size_request = ephy_spinner_size_request; + widget_class->map = ephy_spinner_map; +} + +static void +ephy_spinner_search_directory (const gchar *base, GList **spinner_list) +{ + GnomeVFSResult rc; + GList *list, *node; + + rc = gnome_vfs_directory_list_load + (&list, base, (GNOME_VFS_FILE_INFO_GET_MIME_TYPE | + GNOME_VFS_FILE_INFO_FORCE_FAST_MIME_TYPE | + GNOME_VFS_FILE_INFO_FOLLOW_LINKS)); + if (rc != GNOME_VFS_OK) return; + + for (node = list; node != NULL; node = g_list_next (node)) + { + GnomeVFSFileInfo *file_info = node->data; + EphySpinnerInfo *info; + + if (file_info->name[0] == '.') + continue; + if (file_info->type != GNOME_VFS_FILE_TYPE_DIRECTORY) + continue; + + info = ephy_spinner_get_theme_info (base, file_info->name); + if (info != NULL) + { + *spinner_list = g_list_append (*spinner_list, info); + } + } + + gnome_vfs_file_info_list_free (list); +} + +static EphySpinnerInfo * +ephy_spinner_get_theme_info (const gchar *base, const gchar *theme_name) +{ + EphySpinnerInfo *info; + gchar *path; + gchar *icon; + + path = g_build_filename (base, theme_name, NULL); + icon = g_build_filename (path, "rest.png", NULL); + + if (!g_file_test (icon, G_FILE_TEST_EXISTS)) + { + g_free (path); + g_free (icon); + + /* handle nautilus throbbers as well */ + + path = g_build_filename (base, theme_name, "throbber", NULL); + icon = g_build_filename (path, "rest.png", NULL); + } + + if (!g_file_test (icon, G_FILE_TEST_EXISTS)) + { + g_free (path); + g_free (icon); + + return NULL; + } + + info = g_new(EphySpinnerInfo, 1); + info->name = g_strdup (theme_name); + info->directory = path; + info->filename = icon; + + return info; +} + +static void +ephy_spinner_init_directory_list (void) +{ + gchar *path; + + path = g_build_filename (g_get_home_dir (), ephy_dot_dir (), "spinners", NULL); + spinner_directories = g_list_append (spinner_directories, path); + + path = g_build_filename (SHARE_DIR, "spinners", NULL); + spinner_directories = g_list_append (spinner_directories, path); + + path = g_build_filename (SHARE_DIR, "..", "pixmaps", "nautilus", NULL); + spinner_directories = g_list_append (spinner_directories, path); + +#ifdef NAUTILUS_PREFIX + path = g_build_filename (NAUTILUS_PREFIX, "share", "pixmaps", "nautilus", NULL); + spinner_directories = g_list_append (spinner_directories, path); +#endif +} + +GList * +ephy_spinner_list_spinners (void) +{ + GList *spinner_list = NULL; + GList *tmp; + + for (tmp = spinner_directories; tmp != NULL; tmp = g_list_next (tmp)) + { + gchar *path = tmp->data; + ephy_spinner_search_directory (path, &spinner_list); + } + + return spinner_list; +} + +static gchar * +ephy_spinner_get_theme_path (const gchar *theme_name) +{ + EphySpinnerInfo *info; + GList *tmp; + + for (tmp = spinner_directories; tmp != NULL; tmp = g_list_next (tmp)) + { + gchar *path = tmp->data; + + info = ephy_spinner_get_theme_info (path, theme_name); + if (info != NULL) + { + path = g_strdup (info->directory); + ephy_spinner_info_free (info); + return path; + } + } + + return NULL; +} + +void +ephy_spinner_info_free (EphySpinnerInfo *info) +{ + g_free (info->name); + g_free (info->directory); + g_free (info->filename); + g_free (info); +} diff --git a/lib/widgets/ephy-spinner.h b/lib/widgets/ephy-spinner.h new file mode 100644 index 000000000..c72bee8c1 --- /dev/null +++ b/lib/widgets/ephy-spinner.h @@ -0,0 +1,78 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* + * Nautilus + * + * Copyright (C) 2000 Eazel, Inc. + * + * Nautilus is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Nautilus is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andy Hertzfeld <andy@eazel.com> + * + * This is the header file for the throbber on the location bar + * + */ + +#ifndef EPHY_SPINNER_H +#define EPHY_SPINNER_H + +#include <gtk/gtkeventbox.h> +#include <bonobo.h> + +G_BEGIN_DECLS + +#define EPHY_SPINNER_TYPE (ephy_spinner_get_type ()) +#define EPHY_SPINNER(obj) (GTK_CHECK_CAST ((obj), EPHY_SPINNER_TYPE, EphySpinner)) +#define EPHY_SPINNER_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_SPINNER_TYPE, EphySpinnerClass)) +#define IS_EPHY_SPINNER(obj) (GTK_CHECK_TYPE ((obj), EPHY_SPINNER_TYPE)) +#define IS_EPHY_SPINNER_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_SPINNER_TYPE)) + +typedef struct EphySpinnerInfo EphySpinnerInfo; + +struct EphySpinnerInfo +{ + gchar *name; + gchar *filename; + gchar *directory; +}; + +typedef struct EphySpinner EphySpinner; +typedef struct EphySpinnerClass EphySpinnerClass; +typedef struct EphySpinnerDetails EphySpinnerDetails; + +struct EphySpinner { + GtkEventBox parent; + EphySpinnerDetails *details; +}; + +struct EphySpinnerClass { + GtkEventBoxClass parent_class; +}; + +GtkType ephy_spinner_get_type (void); +GtkWidget *ephy_spinner_new (void); +void ephy_spinner_start (EphySpinner *throbber); +void ephy_spinner_stop (EphySpinner *throbber); +void ephy_spinner_set_small_mode (EphySpinner *throbber, + gboolean new_mode); + +GList *ephy_spinner_list_spinners (void); +void ephy_spinner_info_free (EphySpinnerInfo *info); + +G_END_DECLS + +#endif /* EPHY_SPINNER_H */ + + diff --git a/lib/widgets/ephy-tree-model-sort.c b/lib/widgets/ephy-tree-model-sort.c new file mode 100644 index 000000000..3c2377cf0 --- /dev/null +++ b/lib/widgets/ephy-tree-model-sort.c @@ -0,0 +1,240 @@ +/* Rhythmbox. + * Copyright (C) 2002 Olivier Martin <omartin@ifrance.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include <gtk/gtkmarshal.h> +#include <string.h> + +#include "ephy-node.h" +#include "ephy-tree-model-sort.h" +#include "eggtreemultidnd.h" +#include "ephy-dnd.h" +#include "ephy-marshal.h" + +static void ephy_tree_model_sort_class_init (EphyTreeModelSortClass *klass); +static void ephy_tree_model_sort_init (EphyTreeModelSort *ma); +static void ephy_tree_model_sort_finalize (GObject *object); +static void ephy_tree_model_sort_multi_drag_source_init (EggTreeMultiDragSourceIface *iface); +static gboolean ephy_tree_model_sort_multi_row_draggable (EggTreeMultiDragSource *drag_source, + GList *path_list); +static gboolean ephy_tree_model_sort_multi_drag_data_get (EggTreeMultiDragSource *drag_source, + GList *path_list, + guint info, + GtkSelectionData *selection_data); +static gboolean ephy_tree_model_sort_multi_drag_data_delete (EggTreeMultiDragSource *drag_source, + GList *path_list); + +struct EphyTreeModelSortPrivate +{ + char *str_list; +}; + +enum +{ + NODE_FROM_ITER, + LAST_SIGNAL +}; + +static GObjectClass *parent_class = NULL; + +static guint ephy_tree_model_sort_signals[LAST_SIGNAL] = { 0 }; + +GType +ephy_tree_model_sort_get_type (void) +{ + static GType ephy_tree_model_sort_type = 0; + + if (ephy_tree_model_sort_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyTreeModelSortClass), + NULL, /* base init */ + NULL, /* base finalize */ + (GClassInitFunc) ephy_tree_model_sort_class_init, + NULL, /* class finalize */ + NULL, /* class data */ + sizeof (EphyTreeModelSort), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_tree_model_sort_init + }; + static const GInterfaceInfo multi_drag_source_info = + { + (GInterfaceInitFunc) ephy_tree_model_sort_multi_drag_source_init, + NULL, + NULL + }; + + ephy_tree_model_sort_type = g_type_register_static (GTK_TYPE_TREE_MODEL_SORT, + "EphyTreeModelSort", + &our_info, 0); + + g_type_add_interface_static (ephy_tree_model_sort_type, + EGG_TYPE_TREE_MULTI_DRAG_SOURCE, + &multi_drag_source_info); + } + + return ephy_tree_model_sort_type; +} + +static void +ephy_tree_model_sort_class_init (EphyTreeModelSortClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_tree_model_sort_finalize; + + ephy_tree_model_sort_signals[NODE_FROM_ITER] = + g_signal_new ("node_from_iter", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyTreeModelSortClass, node_from_iter), + NULL, NULL, + ephy_marshal_VOID__POINTER_POINTER, + G_TYPE_NONE, + 2, + G_TYPE_POINTER, + G_TYPE_POINTER); +} + +static void +ephy_tree_model_sort_init (EphyTreeModelSort *ma) +{ + ma->priv = g_new0 (EphyTreeModelSortPrivate, 1); +} + +static void +ephy_tree_model_sort_finalize (GObject *object) +{ + EphyTreeModelSort *model; + + g_return_if_fail (object != NULL); + g_return_if_fail (EPHY_IS_TREE_MODEL_SORT (object)); + + model = EPHY_TREE_MODEL_SORT (object); + + g_free (model->priv->str_list); + g_free (model->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +GtkTreeModel* +ephy_tree_model_sort_new (GtkTreeModel *child_model) +{ + GtkTreeModel *model; + + g_return_val_if_fail (child_model != NULL, NULL); + + model = GTK_TREE_MODEL (g_object_new (EPHY_TYPE_TREE_MODEL_SORT, + "model", child_model, + NULL)); + + return model; +} + +static void +ephy_tree_model_sort_multi_drag_source_init (EggTreeMultiDragSourceIface *iface) +{ + iface->row_draggable = ephy_tree_model_sort_multi_row_draggable; + iface->drag_data_get = ephy_tree_model_sort_multi_drag_data_get; + iface->drag_data_delete = ephy_tree_model_sort_multi_drag_data_delete; +} + +static gboolean +ephy_tree_model_sort_multi_row_draggable (EggTreeMultiDragSource *drag_source, GList *path_list) +{ + GList *l; + + for (l = path_list; l != NULL; l = g_list_next (l)) + { + GtkTreeIter iter; + GtkTreePath *path; + EphyNode *node = NULL; + + path = gtk_tree_row_reference_get_path (l->data); + gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source), &iter, path); + g_signal_emit (G_OBJECT (drag_source), + ephy_tree_model_sort_signals[NODE_FROM_ITER], + 0, &iter, &node); + + if (node == NULL) + { + return FALSE; + } + } + + return TRUE; +} + +static gboolean +ephy_tree_model_sort_multi_drag_data_delete (EggTreeMultiDragSource *drag_source, + GList *path_list) +{ + return TRUE; +} + +static void +each_url_get_data_binder (EphyDragEachSelectedItemDataGet iteratee, + gpointer iterator_context, gpointer data) +{ + gpointer *context = (gpointer *) iterator_context; + GList *path_list = (GList *) (context[0]); + GList *i; + GtkTreeModel *model = GTK_TREE_MODEL (context[1]); + + for (i = path_list; i != NULL; i = i->next) + { + GtkTreeIter iter; + GtkTreePath *path = gtk_tree_row_reference_get_path (i->data); + EphyNode *node = NULL; + const char *value; + + gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path); + g_signal_emit (G_OBJECT (model), + ephy_tree_model_sort_signals[NODE_FROM_ITER], + 0, &iter, &node); + + if (node == NULL) + return; + + value = ephy_node_get_property_string (node, + EPHY_DND_NODE_PROPERTY); + + iteratee (value, -1, -1, -1, -1, data); + } +} + +static gboolean +ephy_tree_model_sort_multi_drag_data_get (EggTreeMultiDragSource *drag_source, + GList *path_list, + guint info, + GtkSelectionData *selection_data) +{ gpointer icontext[2]; + + icontext[0] = path_list; + icontext[1] = drag_source; + + ephy_dnd_drag_data_get (NULL, NULL, selection_data, + info, 0, &icontext, each_url_get_data_binder); + + return TRUE; +} diff --git a/lib/widgets/ephy-tree-model-sort.h b/lib/widgets/ephy-tree-model-sort.h new file mode 100644 index 000000000..f8cb9fb68 --- /dev/null +++ b/lib/widgets/ephy-tree-model-sort.h @@ -0,0 +1,59 @@ +/* Copyright (C) 2002 Olivier Martin <omartin@ifrance.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef EPHY_TREE_MODEL_SORT_H +#define EPHY_TREE_MODEL_SORT_H + +#include <glib-object.h> + +#include <gtk/gtktreemodelsort.h> + +G_BEGIN_DECLS + +#define EPHY_TYPE_TREE_MODEL_SORT (ephy_tree_model_sort_get_type ()) +#define EPHY_TREE_MODEL_SORT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_TREE_MODEL_SORT, EphyTreeModelSort)) +#define EPHY_TREE_MODEL_SORT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_TREE_MODEL_SORT, EphyTreeModelSortClass)) +#define EPHY_IS_TREE_MODEL_SORT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_TREE_MODEL_SORT)) +#define EPHY_IS_TREE_MODEL_SORT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_TREE_MODEL_SORT)) +#define EPHY_TREE_MODEL_SORT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_TREE_MODEL_SORT, EphyTreeModelSortClass)) + +typedef struct EphyTreeModelSortPrivate EphyTreeModelSortPrivate; + +typedef struct +{ + GtkTreeModelSort parent; + + EphyTreeModelSortPrivate *priv; +} EphyTreeModelSort; + +typedef struct +{ + GtkTreeModelSortClass parent_class; + + void (*node_from_iter) (EphyTreeModelSort *model, GtkTreeIter *iter, void **node); +} EphyTreeModelSortClass; + +GType ephy_tree_model_sort_get_type (void); + +GtkTreeModel *ephy_tree_model_sort_new (GtkTreeModel *child_model); + + +G_END_DECLS + +#endif /* EPHY_TREE_MODEL_SORT_H */ diff --git a/po/.cvsignore b/po/.cvsignore new file mode 100644 index 000000000..69ef08425 --- /dev/null +++ b/po/.cvsignore @@ -0,0 +1,6 @@ +Makefile +Makefile.in +Makefile.in.in +POTFILES +.intltool-merge-cache +epiphany-2.0.pot diff --git a/po/ChangeLog b/po/ChangeLog new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/po/ChangeLog diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 000000000..769ba1a42 --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1,45 @@ +data/GNOME_Epiphany_Automation.server.in +data/GNOME_Epiphany_NautilusView.server.in +data/epiphany.schemas.in +data/glade/epiphany.glade +data/glade/prefs-dialog.glade +data/glade/print.glade +data/glade/prompts.glade +data/glade/toolbar-editor.glade +data/ui/epiphany-ui.xml +data/ui/epiphany-ui.xml.in +data/ui/nautilus-epiphany-view.xml +data/ui/nautilus-epiphany-view.xml.in +embed/downloader-view.c +embed/ephy-embed-utils.c +embed/ephy-history.c +embed/mozilla/ContentHandler.cpp +embed/mozilla/ExternalProtocolService.cpp +embed/mozilla/FilePicker.cpp +embed/mozilla/PromptService.cpp +embed/mozilla/mozilla-embed-shell.cpp +embed/mozilla/mozilla-i18n.c +embed/mozilla/mozilla-notifiers.cpp +lib/eel-gconf-extensions.c +lib/ephy-file-helpers.c +lib/ephy-gui.c +lib/ephy-string.c +lib/toolbar/ephy-tbi-favicon.c +lib/toolbar/ephy-tbi-location.c +lib/toolbar/ephy-tbi-navigation-history.c +lib/toolbar/ephy-tbi-separator.c +lib/toolbar/ephy-tbi-spinner.c +lib/toolbar/ephy-tbi-std-toolitem.c +lib/toolbar/ephy-tbi-zoom.c +lib/widgets/ephy-notebook.c +src/bookmarks/ephy-bookmarks-editor.c +src/ephy-main.c +src/ephy-nautilus-view.c +src/ephy-tab.c +src/ephy-window.c +src/general-prefs.c +src/history-dialog.c +src/pdm-dialog.c +src/prefs-dialog.c +src/toolbar.c +src/window-commands.c diff --git a/src/.cvsignore b/src/.cvsignore new file mode 100644 index 000000000..27d9d0cd0 --- /dev/null +++ b/src/.cvsignore @@ -0,0 +1,6 @@ +*.o +Makefile +Makefile.in +.deps +.libs +epiphany diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 000000000..5ec49453d --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,101 @@ +SUBDIRS = bookmarks + +INCLUDES = \ + -I$(top_srcdir)/embed \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/lib/widgets \ + -I$(top_srcdir)/lib/toolbar \ + -I$(top_srcdir)/src/bookmarks \ + $(WARN_CFLAGS) \ + $(EPIPHANY_DEPENDENCY_CFLAGS) \ + -DSHARE_DIR=\"$(pkgdatadir)\" \ + -DDATADIR=\""$(datadir)"\" \ + -DPIXMAP_DIR=\""$(datadir)/pixmaps"\" \ + -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ + -DG_DISABLE_DEPRECATED \ + -DGDK_DISABLE_DEPRECATED \ + -DGTK_DISABLE_DEPRECATED \ + -DGDK_PIXBUF_DISABLE_DEPRECATED \ + -DGNOME_DISABLE_DEPRECATED + +bin_PROGRAMS = epiphany + +CXXLD = $(CXX) +LINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ + + +ephy_automation_interface_idl_sources = \ + EphyAutomation-common.c \ + EphyAutomation-stubs.c \ + EphyAutomation-skels.c \ + EphyAutomation.h + +if ENABLE_NAUTILUS_VIEW +nautilus_view_sources = \ + ephy-nautilus-view.c \ + ephy-nautilus-view.h +else +nautilus_view_sources = +endif + +epiphany_SOURCES = \ + $(ephy_automation_interface_idl_sources) \ + $(nautilus_view_sources) \ + ui-prefs.c \ + ui-prefs.h \ + prefs-dialog.c \ + prefs-dialog.h \ + toolbar.c \ + toolbar.h \ + statusbar.c \ + statusbar.h \ + ephy-main.c \ + ephy-automation.c \ + ephy-automation.h \ + ephy-shell.c \ + ephy-shell.h \ + ephy-tab.c \ + ephy-tab.h \ + ephy-window.c \ + ephy-window.h \ + window-commands.c \ + window-commands.h \ + popup-commands.c \ + popup-commands.h \ + history-dialog.c \ + history-dialog.h \ + ppview-toolbar.c \ + ppview-toolbar.h \ + session.c \ + session.h \ + general-prefs.c \ + general-prefs.h \ + language-editor.c \ + language-editor.h \ + appearance-prefs.c \ + appearance-prefs.h \ + pdm-dialog.c \ + pdm-dialog.h \ + ephy-favorites-menu.c \ + ephy-favorites-menu.h \ + ephy-history-model.c \ + ephy-history-model.h + +epiphany_LDADD = \ + $(top_builddir)/embed/libephyembed.la \ + $(top_builddir)/lib/libephy.la \ + $(top_builddir)/src/bookmarks/libephybookmarks.la \ + $(MOZILLA_COMPONENT_LIBS) \ + $(EPIPHANY_DEPENDENCY_LIBS) \ + $(INTLLIBS) + + +BUILT_SOURCES= \ + EphyAutomation.h EphyAutomation-common.c EphyAutomation-stubs.c EphyAutomation-skels.c + +CLEAN_FILES = $(BUILT_SOURCES) + +EphyAutomation-common.c EphyAutomation-stubs.c EphyAutomation-skels.c EphyAutomation.h: $(top_srcdir)/idl/EphyAutomation.idl + $(ORBIT_IDL) -I $(LIBBONOBO_IDL) -I $(BONOBO_ACTIVATION_IDL) $(top_srcdir)/idl/EphyAutomation.idl + +EXTRA_DIST = $(top_srcdir)/idl/EphyAutomation.idl diff --git a/src/appearance-prefs.c b/src/appearance-prefs.c new file mode 100755 index 000000000..da1056f3f --- /dev/null +++ b/src/appearance-prefs.c @@ -0,0 +1,458 @@ +/* + * Copyright (C) 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "appearance-prefs.h" +#include "ephy-shell.h" +#include "ephy-prefs.h" +#include "ephy-embed-prefs.h" +#include "eel-gconf-extensions.h" + +#include <string.h> +#include <gtk/gtkcombo.h> +#include <gtk/gtkspinbutton.h> +#include <gtk/gtkeditable.h> +#include <gtk/gtkoptionmenu.h> + +static void appearance_prefs_class_init (AppearancePrefsClass *klass); +static void appearance_prefs_init (AppearancePrefs *dialog); +static void appearance_prefs_finalize (GObject *object); + +/* Glade callbacks */ +void +fonts_language_optionmenu_changed_cb (GtkWidget *optionmenu, EphyDialog *dialog); + +static GObjectClass *parent_class = NULL; + +struct AppearancePrefsPrivate +{ + int language; + gboolean switching; +}; + +enum +{ + SERIF_PROP, + SANSSERIF_PROP, + MONOSPACE_PROP, + FIXED_SIZE_PROP, + VARIABLE_SIZE_PROP, + MIN_SIZE_PROP, + PROPORTIONAL_PROP, + BACKGROUND_PROP, + TEXT_PROP, + UNVISITED_PROP, + VISITED_PROP, + USE_SYSCOLORS_PROP, + USE_COLORS_PROP, + USE_FONTS_PROP, +}; + +static const +EphyDialogProperty properties [] = +{ + { SERIF_PROP, "serif_combo", NULL, PT_NORMAL, NULL }, + { SANSSERIF_PROP, "sansserif_combo", NULL, PT_NORMAL, NULL }, + { MONOSPACE_PROP, "monospace_combo", NULL, PT_NORMAL, NULL }, + { FIXED_SIZE_PROP, "fixed_size_spinbutton", NULL, PT_NORMAL, NULL }, + { VARIABLE_SIZE_PROP, "variable_size_spinbutton", NULL, PT_NORMAL, NULL }, + { MIN_SIZE_PROP, "min_size_spinbutton", NULL, PT_NORMAL, NULL }, + { PROPORTIONAL_PROP, "proportional_optionmenu", CONF_RENDERING_DEFAULT_FONT, PT_AUTOAPPLY, NULL }, + { BACKGROUND_PROP, "background_cpick", CONF_RENDERING_BG_COLOR, PT_AUTOAPPLY, NULL }, + { TEXT_PROP, "text_cpick", CONF_RENDERING_TEXT_COLOR, PT_AUTOAPPLY, NULL }, + { UNVISITED_PROP, "unvisited_cpick", CONF_RENDERING_UNVISITED_LINKS, PT_AUTOAPPLY, NULL }, + { VISITED_PROP, "visited_cpick", CONF_RENDERING_VISITED_LINKS, PT_AUTOAPPLY, NULL }, + { USE_SYSCOLORS_PROP, "use_syscolors_checkbutton", CONF_RENDERING_USE_SYSTEM_COLORS, PT_AUTOAPPLY, NULL }, + { USE_COLORS_PROP, "use_colors_checkbutton", CONF_RENDERING_USE_OWN_COLORS, PT_AUTOAPPLY, NULL }, + { USE_FONTS_PROP, "use_fonts_checkbutton", CONF_RENDERING_USE_OWN_FONTS, PT_AUTOAPPLY, NULL }, + + { -1, NULL, NULL } +}; + +/* FIXME duped in mozilla/ */ +const +char *lang_encode[] = +{ + "x-western", + "x-central-euro", + "ja", + "zh-TW", + "zh-CN", + "ko", + "x-cyrillic", + "x-baltic", + "el", + "tr", + "x-unicode", + "th", + "he", + "ar" +}; + +enum +{ + FONT_TYPE_SERIF, + FONT_TYPE_SANSSERIF, + FONT_TYPE_MONOSPACE +}; + +const +char *fonts_types[] = +{ + "serif", + "sans-serif", + "monospace" +}; + +enum +{ + FONT_SIZE_FIXED, + FONT_SIZE_VAR, + FONT_SIZE_MIN +}; + +const +char *size_prefs[] = +{ + CONF_RENDERING_FONT_FIXED_SIZE, + CONF_RENDERING_FONT_VAR_SIZE, + CONF_RENDERING_FONT_MIN_SIZE +}; + +GType +appearance_prefs_get_type (void) +{ + static GType appearance_prefs_type = 0; + + if (appearance_prefs_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (AppearancePrefsClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) appearance_prefs_class_init, + NULL, + NULL, /* class_data */ + sizeof (AppearancePrefs), + 0, /* n_preallocs */ + (GInstanceInitFunc) appearance_prefs_init + }; + + appearance_prefs_type = g_type_register_static (EPHY_DIALOG_TYPE, + "AppearancePrefs", + &our_info, 0); + } + + return appearance_prefs_type; + +} + +static void +appearance_prefs_class_init (AppearancePrefsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = appearance_prefs_finalize; +} + +static void +setup_font_menu (AppearancePrefs *dialog, + const char *type, + GtkWidget *combo) +{ + char *default_font; + GList *fonts; + EphyEmbedShell *shell; + const char *name; + char key[255]; + int pos; + GtkWidget *entry = GTK_COMBO(combo)->entry; + + shell = ephy_shell_get_embed_shell (ephy_shell); + + ephy_embed_shell_get_font_list (shell, + lang_encode[dialog->priv->language], + type, &fonts, &default_font); + + /* Get the default font */ + sprintf (key, "%s_%s_%s", CONF_RENDERING_FONT, type, + lang_encode[dialog->priv->language]); + name = eel_gconf_get_string (key); + if (name == NULL) + { + name = default_font; + } + + /* put the default font at the top in the list */ + if (name != NULL) + { + fonts = g_list_prepend (fonts, + (gpointer)g_strdup(name)); + } + + /* set popdown doesnt like NULL */ + if (fonts == NULL) + { + fonts = g_list_alloc (); + } + + gtk_combo_set_popdown_strings (GTK_COMBO(combo), fonts); + + /* set the default value */ + if (name != NULL) + { + gtk_editable_delete_text (GTK_EDITABLE(entry), 0, -1); + gtk_editable_insert_text (GTK_EDITABLE(entry), + name, g_utf8_strlen (name, -1), + &pos); + } + + g_free (default_font); + + /* FIXME free the list */ +} + +static void +save_font_menu (AppearancePrefs *dialog, + int type, + GtkWidget *entry) +{ + char *name; + char key[255]; + + name = gtk_editable_get_chars + (GTK_EDITABLE(entry), 0, -1); + + /* do not save empty fonts */ + if (!name || *name == '\0') + { + g_free (name); + return; + } + + sprintf (key, "%s_%s_%s", CONF_RENDERING_FONT, + fonts_types[type], + lang_encode[dialog->priv->language]); + eel_gconf_set_string (key, name); + g_free (name); +} + +static void +font_entry_changed_cb (GtkWidget *entry, AppearancePrefs *dialog) +{ + int type; + + if (dialog->priv->switching) return; + + type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(entry), + "type")); + save_font_menu (dialog, type, entry); +} + +static void +attach_font_signal (AppearancePrefs *dialog, int prop, + gpointer type) +{ + GtkWidget *combo; + GtkWidget *entry; + + combo = ephy_dialog_get_control (EPHY_DIALOG(dialog), + prop); + entry = GTK_COMBO(combo)->entry; + g_object_set_data (G_OBJECT(entry), "type", type); + g_signal_connect (entry, "changed", + G_CALLBACK(font_entry_changed_cb), + dialog); +} + +static void +attach_fonts_signals (AppearancePrefs *dialog) +{ + attach_font_signal (dialog, SERIF_PROP, + GINT_TO_POINTER(FONT_TYPE_SERIF)); + attach_font_signal (dialog, SANSSERIF_PROP, + GINT_TO_POINTER(FONT_TYPE_SANSSERIF)); + attach_font_signal (dialog, MONOSPACE_PROP, + GINT_TO_POINTER(FONT_TYPE_MONOSPACE)); +} + +static void +size_spinbutton_changed_cb (GtkWidget *spin, AppearancePrefs *dialog) +{ + int type; + char key[255]; + + if (dialog->priv->switching) return; + + type = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(spin), "type")); + + sprintf (key, "%s_%s", + size_prefs[type], + lang_encode[dialog->priv->language]); + eel_gconf_set_integer (key, gtk_spin_button_get_value (GTK_SPIN_BUTTON (spin))); +} + +static void +attach_size_controls_signals (AppearancePrefs *dialog) +{ + GtkWidget *spin; + + spin = ephy_dialog_get_control (EPHY_DIALOG(dialog), + FIXED_SIZE_PROP); + g_object_set_data (G_OBJECT(spin), "type", + GINT_TO_POINTER(FONT_SIZE_FIXED)); + g_signal_connect (spin, "value_changed", + G_CALLBACK(size_spinbutton_changed_cb), + dialog); + + spin = ephy_dialog_get_control (EPHY_DIALOG(dialog), + VARIABLE_SIZE_PROP); + g_object_set_data (G_OBJECT(spin), "type", + GINT_TO_POINTER(FONT_SIZE_VAR)); + g_signal_connect (spin, "value_changed", + G_CALLBACK(size_spinbutton_changed_cb), + dialog); + + spin = ephy_dialog_get_control (EPHY_DIALOG(dialog), + MIN_SIZE_PROP); + g_object_set_data (G_OBJECT(spin), "type", + GINT_TO_POINTER(FONT_SIZE_MIN)); + g_signal_connect (spin, "value_changed", + G_CALLBACK(size_spinbutton_changed_cb), + dialog); +} + +static void +setup_size_control (AppearancePrefs *dialog, + const char *pref, + int default_size, + GtkWidget *spin) +{ + char key[255]; + int size; + + sprintf (key, "%s_%s", pref, + lang_encode[dialog->priv->language]); + size = eel_gconf_get_integer (key); + + if (size == 0) size = default_size; + + gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin), size); +} + +static void +setup_size_controls (AppearancePrefs *dialog) +{ + GtkWidget *spin; + + spin = ephy_dialog_get_control (EPHY_DIALOG(dialog), + FIXED_SIZE_PROP); + setup_size_control (dialog, CONF_RENDERING_FONT_FIXED_SIZE, 12, spin); + + spin = ephy_dialog_get_control (EPHY_DIALOG(dialog), + VARIABLE_SIZE_PROP); + setup_size_control (dialog, CONF_RENDERING_FONT_VAR_SIZE, 16, spin); + + spin = ephy_dialog_get_control (EPHY_DIALOG(dialog), + MIN_SIZE_PROP); + setup_size_control (dialog, CONF_RENDERING_FONT_MIN_SIZE, 0, spin); +} + +static void +setup_fonts (AppearancePrefs *dialog) +{ + GtkWidget *combo; + + dialog->priv->switching = TRUE; + + combo = ephy_dialog_get_control (EPHY_DIALOG(dialog), + SERIF_PROP); + setup_font_menu (dialog, "serif", combo); + + combo = ephy_dialog_get_control (EPHY_DIALOG(dialog), + SANSSERIF_PROP); + setup_font_menu (dialog, "sans-serif", combo); + + combo = ephy_dialog_get_control (EPHY_DIALOG(dialog), + MONOSPACE_PROP); + setup_font_menu (dialog, "monospace", combo); + + dialog->priv->switching = FALSE; +} + +static void +appearance_prefs_init (AppearancePrefs *dialog) +{ + dialog->priv = g_new0 (AppearancePrefsPrivate, 1); + dialog->priv->switching = FALSE; + + ephy_dialog_construct (EPHY_DIALOG(dialog), + properties, + "prefs-dialog.glade", + "appearance_page_box"); + + setup_fonts (dialog); + setup_size_controls (dialog); + attach_fonts_signals (dialog); + attach_size_controls_signals (dialog); +} + +static void +appearance_prefs_finalize (GObject *object) +{ + AppearancePrefs *dialog; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_appearance_PREFS (object)); + + dialog = appearance_PREFS (object); + + g_return_if_fail (dialog->priv != NULL); + + g_free (dialog->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +EphyDialog * +appearance_prefs_new (void) +{ + AppearancePrefs *dialog; + + dialog = appearance_PREFS (g_object_new (appearance_PREFS_TYPE, + NULL)); + + return EPHY_DIALOG(dialog); +} + +void +fonts_language_optionmenu_changed_cb (GtkWidget *optionmenu, + EphyDialog *dialog) +{ + int i; + + i = gtk_option_menu_get_history + (GTK_OPTION_MENU (optionmenu)); + + appearance_PREFS(dialog)->priv->language = i; + + setup_fonts (appearance_PREFS(dialog)); + setup_size_controls (appearance_PREFS(dialog)); +} diff --git a/src/appearance-prefs.h b/src/appearance-prefs.h new file mode 100644 index 000000000..17067b7e9 --- /dev/null +++ b/src/appearance-prefs.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef APPEARANCE_PREFS_H +#define APPEARANCE_PREFS_H + +#include "ephy-dialog.h" + +#include <glib-object.h> +#include <glib.h> + +G_BEGIN_DECLS + +typedef struct AppearancePrefs AppearancePrefs; +typedef struct AppearancePrefsClass AppearancePrefsClass; + +#define appearance_PREFS_TYPE (appearance_prefs_get_type ()) +#define appearance_PREFS(obj) (GTK_CHECK_CAST ((obj), appearance_PREFS_TYPE, AppearancePrefs)) +#define appearance_PREFS_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), appearance_PREFS, AppearancePrefsClass)) +#define IS_appearance_PREFS(obj) (GTK_CHECK_TYPE ((obj), appearance_PREFS_TYPE)) +#define IS_appearance_PREFS_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), appearance_PREFS)) + +typedef struct AppearancePrefsPrivate AppearancePrefsPrivate; + +struct AppearancePrefs +{ + EphyDialog parent; + AppearancePrefsPrivate *priv; +}; + +struct AppearancePrefsClass +{ + EphyDialogClass parent_class; +}; + +GType appearance_prefs_get_type (void); + +EphyDialog *appearance_prefs_new (void); + +G_END_DECLS + +#endif + diff --git a/src/bookmarks/.cvsignore b/src/bookmarks/.cvsignore new file mode 100644 index 000000000..6e5ca7ed4 --- /dev/null +++ b/src/bookmarks/.cvsignore @@ -0,0 +1,6 @@ +Makefile +Makefile.in +.deps +.libs +*.lo +*.la diff --git a/src/bookmarks/Makefile.am b/src/bookmarks/Makefile.am new file mode 100644 index 000000000..4dd24c1bd --- /dev/null +++ b/src/bookmarks/Makefile.am @@ -0,0 +1,31 @@ +INCLUDES = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/embed \ + -I$(top_srcdir)/lib/widgets \ + $(WARN_CFLAGS) \ + $(EPIPHANY_DEPENDENCY_CFLAGS) \ + -DSHARE_DIR=\"$(pkgdatadir)\" \ + -DDATADIR=\""$(datadir)"\" \ + -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ + -DG_DISABLE_DEPRECATED \ + -DGDK_DISABLE_DEPRECATED \ + -DGTK_DISABLE_DEPRECATED \ + -DGDK_PIXBUF_DISABLE_DEPRECATED \ + -DGNOME_DISABLE_DEPRECATED + +noinst_LTLIBRARIES = libephybookmarks.la + +libephybookmarks_la_SOURCES = \ + ephy-bookmarks.c \ + ephy-bookmarks.h \ + ephy-tree-model-node.c \ + ephy-tree-model-node.h \ + ephy-node-view.c \ + ephy-node-view.h \ + ephy-bookmarks-editor.c \ + ephy-bookmarks-editor.h \ + ephy-keywords-entry.c \ + ephy-keywords-entry.h \ + ephy-new-bookmark.c \ + ephy-new-bookmark.h diff --git a/src/bookmarks/ephy-bookmarks-editor.c b/src/bookmarks/ephy-bookmarks-editor.c new file mode 100644 index 000000000..2888950df --- /dev/null +++ b/src/bookmarks/ephy-bookmarks-editor.c @@ -0,0 +1,534 @@ +/* + * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include <gtk/gtktable.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkentry.h> +#include <gtk/gtkstock.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtkvbox.h> +#include <libgnome/gnome-i18n.h> +#include <string.h> + +#include "ephy-bookmarks-editor.h" +#include "ephy-node-view.h" +#include "ephy-window.h" +#include "ephy-keywords-entry.h" +#include "ephy-dnd.h" + +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +static void ephy_bookmarks_editor_class_init (EphyBookmarksEditorClass *klass); +static void ephy_bookmarks_editor_init (EphyBookmarksEditor *editor); +static void ephy_bookmarks_editor_finalize (GObject *object); +static void ephy_bookmarks_editor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ephy_bookmarks_editor_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +struct EphyBookmarksEditorPrivate +{ + EphyBookmarks *bookmarks; + EphyNodeView *bm_view; + EphyNodeView *key_view; + EphyNodeFilter *bookmarks_filter; + GtkWidget *title_entry; + GtkWidget *keywords_entry; + GtkWidget *search_entry; +}; + +enum +{ + PROP_0, + PROP_BOOKMARKS +}; + +enum +{ + RESPONSE_REMOVE +}; + +static GObjectClass *parent_class = NULL; + +GType +ephy_bookmarks_editor_get_type (void) +{ + static GType ephy_bookmarks_editor_type = 0; + + if (ephy_bookmarks_editor_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyBookmarksEditorClass), + NULL, + NULL, + (GClassInitFunc) ephy_bookmarks_editor_class_init, + NULL, + NULL, + sizeof (EphyBookmarksEditor), + 0, + (GInstanceInitFunc) ephy_bookmarks_editor_init + }; + + ephy_bookmarks_editor_type = g_type_register_static (GTK_TYPE_DIALOG, + "EphyBookmarksEditor", + &our_info, 0); + } + + return ephy_bookmarks_editor_type; +} + +static void +ephy_bookmarks_editor_class_init (EphyBookmarksEditorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_bookmarks_editor_finalize; + + object_class->set_property = ephy_bookmarks_editor_set_property; + object_class->get_property = ephy_bookmarks_editor_get_property; + + g_object_class_install_property (object_class, + PROP_BOOKMARKS, + g_param_spec_object ("bookmarks", + "Bookmarks set", + "Bookmarks set", + EPHY_BOOKMARKS_TYPE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +} + +static void +ephy_bookmarks_editor_finalize (GObject *object) +{ + EphyBookmarksEditor *editor; + + g_return_if_fail (object != NULL); + g_return_if_fail (EPHY_IS_BOOKMARKS_EDITOR (object)); + + editor = EPHY_BOOKMARKS_EDITOR (object); + + g_return_if_fail (editor->priv != NULL); + + g_object_unref (G_OBJECT (editor->priv->bookmarks_filter)); + + g_free (editor->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +ephy_bookmarks_editor_node_selected_cb (GtkWidget *view, + EphyNode *node, + EphyBookmarksEditor *editor) +{ + const char *title; + const char *keywords; + + if (node != NULL) + { + g_assert (EPHY_IS_NODE (node)); + + title = ephy_node_get_property_string + (node, EPHY_NODE_BMK_PROP_TITLE); + keywords = ephy_node_get_property_string + (node, EPHY_NODE_BMK_PROP_KEYWORDS); + gtk_entry_set_text (GTK_ENTRY (editor->priv->title_entry), + title ? g_strdup (title) : ""); + gtk_entry_set_text (GTK_ENTRY (editor->priv->keywords_entry), + keywords ? g_strdup (keywords) : ""); + gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->title_entry), TRUE); + gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->keywords_entry), TRUE); + } + else + { + gtk_entry_set_text (GTK_ENTRY (editor->priv->title_entry), ""); + gtk_entry_set_text (GTK_ENTRY (editor->priv->keywords_entry), ""); + gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->title_entry), FALSE); + gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->keywords_entry), FALSE); + } +} + +static void +ephy_bookmarks_editor_node_activated_cb (GtkWidget *view, + EphyNode *node, + EphyBookmarksEditor *editor) +{ + const char *location; + GtkWindow *window; + + g_return_if_fail (EPHY_IS_NODE (node)); + location = ephy_node_get_property_string + (node, EPHY_NODE_BMK_PROP_LOCATION); + g_return_if_fail (location != NULL); + + window = gtk_window_get_transient_for (GTK_WINDOW (editor)); + g_return_if_fail (IS_EPHY_WINDOW (window)); + ephy_window_load_url (EPHY_WINDOW (window), location); +} + +static void +ephy_bookmarks_editor_response_cb (GtkDialog *dialog, + int response_id, + EphyBookmarksEditor *editor) +{ + switch (response_id) + { + case GTK_RESPONSE_CLOSE: + gtk_widget_destroy (GTK_WIDGET (dialog)); + break; + case RESPONSE_REMOVE: + ephy_node_view_remove (editor->priv->bm_view); + break; + } +} + +static void +update_prop_from_entry (EphyBookmarksEditor *editor, + GtkWidget *entry, + guint id) +{ + GList *selection; + GValue value = { 0, }; + + selection = ephy_node_view_get_selection (editor->priv->bm_view); + if (selection) + { + EphyNode *bm = EPHY_NODE (selection->data); + char *tmp; + + tmp = gtk_editable_get_chars + (GTK_EDITABLE (entry), 0, -1); + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, tmp); + ephy_node_set_property (bm, id, &value); + g_value_unset (&value); + g_free (tmp); + } + g_list_free (selection); +} + +static void +title_entry_changed_cb (GtkWidget *entry, EphyBookmarksEditor *editor) +{ + update_prop_from_entry (editor, editor->priv->title_entry, + EPHY_NODE_BMK_PROP_TITLE); +} + +static void +keywords_changed_cb (GtkWidget *entry, + EphyBookmarksEditor *editor) +{ + EphyNode *node; + GList *selection; + char *keywords; + + selection = ephy_node_view_get_selection (editor->priv->bm_view); + if (selection == NULL) return; + node = EPHY_NODE (selection->data); + g_list_free (selection); + + keywords = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); + ephy_bookmarks_update_keywords (editor->priv->bookmarks, + keywords, node); + g_free (keywords); + + update_prop_from_entry (editor, editor->priv->keywords_entry, + EPHY_NODE_BMK_PROP_KEYWORDS); +} + +static GtkWidget * +build_editing_table (EphyBookmarksEditor *editor) +{ + GtkWidget *table, *label, *entry; + + table = gtk_table_new (2, 2, FALSE); + gtk_table_set_row_spacings (GTK_TABLE (table), 6); + gtk_table_set_col_spacings (GTK_TABLE (table), 6); + gtk_widget_show (table); + + label = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_label_set_markup (GTK_LABEL (label), _("<b>Title:</b>")); + gtk_widget_show (label); + entry = gtk_entry_new (); + editor->priv->title_entry = entry; + gtk_widget_set_sensitive (GTK_WIDGET (entry), FALSE); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0); + gtk_table_attach_defaults (GTK_TABLE (table), entry, 1, 2, 0, 1); + g_signal_connect (G_OBJECT (entry), "changed", + G_CALLBACK (title_entry_changed_cb), + editor); + + label = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_label_set_markup (GTK_LABEL (label), _("<b>Keywords:</b>")); + gtk_widget_show (label); + entry = ephy_keywords_entry_new (); + ephy_keywords_entry_set_bookmarks (EPHY_KEYWORDS_ENTRY (entry), + editor->priv->bookmarks); + editor->priv->keywords_entry = entry; + gtk_widget_set_sensitive (GTK_WIDGET (entry), FALSE); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0); + gtk_table_attach_defaults (GTK_TABLE (table), entry, 1, 2, 1, 2); + g_signal_connect (G_OBJECT (entry), "keywords_changed", + G_CALLBACK (keywords_changed_cb), + editor); + + return table; +} + +static void +bookmarks_filter (EphyBookmarksEditor *editor, + EphyNode *keyword) +{ + ephy_node_filter_empty (editor->priv->bookmarks_filter); + ephy_node_filter_add_expression (editor->priv->bookmarks_filter, + ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_HAS_PARENT, + keyword), + 0); + ephy_node_filter_done_changing (editor->priv->bookmarks_filter); +} + +static void +keyword_node_selected_cb (EphyNodeView *view, + EphyNode *node, + EphyBookmarksEditor *editor) +{ + if (node == NULL) + { + ephy_node_view_select_node + (editor->priv->key_view, + ephy_bookmarks_get_bookmarks + (editor->priv->bookmarks)); + } + else + { + bookmarks_filter (editor, node); + } +} + +static void +search_entry_changed_cb (GtkWidget *entry, EphyBookmarksEditor *editor) +{ + char *search_text; + + search_text = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); + + GDK_THREADS_ENTER (); + + ephy_node_filter_empty (editor->priv->bookmarks_filter); + ephy_node_filter_add_expression (editor->priv->bookmarks_filter, + ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS, + EPHY_NODE_BMK_PROP_TITLE, + search_text), + 0); + ephy_node_filter_add_expression (editor->priv->bookmarks_filter, + ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS, + EPHY_NODE_BMK_PROP_KEYWORDS, + search_text), + 0); + ephy_node_filter_done_changing (editor->priv->bookmarks_filter); + + GDK_THREADS_LEAVE (); + + g_free (search_text); +} + +static GtkWidget * +build_search_box (EphyBookmarksEditor *editor) +{ + GtkWidget *box; + GtkWidget *label; + GtkWidget *entry; + + box = gtk_hbox_new (FALSE, 6); + gtk_widget_show (box); + + label = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_label_set_markup (GTK_LABEL (label), _("<b>Search:</b>")); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (box), + label, FALSE, TRUE, 0); + + entry = gtk_entry_new (); + editor->priv->search_entry = entry; + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (box), + entry, TRUE, TRUE, 0); + g_signal_connect (G_OBJECT (entry), "changed", + G_CALLBACK (search_entry_changed_cb), + editor); + return box; +} + +static void +ephy_bookmarks_editor_construct (EphyBookmarksEditor *editor) +{ + GtkWidget *hbox, *vbox; + EphyNodeView *bm_view, *key_view; + EphyNode *node; + + gtk_dialog_set_has_separator (GTK_DIALOG (editor), FALSE); + gtk_container_set_border_width (GTK_CONTAINER (editor), 6); + gtk_widget_set_size_request (GTK_WIDGET (editor), 500, 400); + g_signal_connect (G_OBJECT (editor), + "response", + G_CALLBACK (ephy_bookmarks_editor_response_cb), + editor); + + hbox = gtk_hbox_new (FALSE, 6); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 6); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (editor)->vbox), + hbox, TRUE, TRUE, 0); + gtk_widget_show (hbox); + + g_assert (editor->priv->bookmarks); + + node = ephy_bookmarks_get_keywords (editor->priv->bookmarks); + key_view = ephy_node_view_new (node, NULL); + ephy_node_view_set_browse_mode (key_view); + ephy_node_view_add_column (key_view, _("Keywords"), + EPHY_TREE_MODEL_NODE_COL_KEYWORD, FALSE); + gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (key_view), FALSE, TRUE, 0); + gtk_widget_set_size_request (GTK_WIDGET (key_view), 120, -1); + gtk_widget_show (GTK_WIDGET (key_view)); + editor->priv->key_view = key_view; + g_signal_connect (G_OBJECT (key_view), + "node_selected", + G_CALLBACK (keyword_node_selected_cb), + editor); + + vbox = gtk_vbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (hbox), + vbox, TRUE, TRUE, 0); + gtk_widget_show (vbox); + + gtk_box_pack_start (GTK_BOX (vbox), + build_search_box (editor), + FALSE, FALSE, 0); + + node = ephy_bookmarks_get_bookmarks (editor->priv->bookmarks); + editor->priv->bookmarks_filter = ephy_node_filter_new (); + bm_view = ephy_node_view_new (node, editor->priv->bookmarks_filter); + ephy_node_view_enable_drag_source (bm_view); + ephy_node_view_add_column (bm_view, _("Title"), + EPHY_TREE_MODEL_NODE_COL_BOOKMARK, TRUE); + ephy_node_view_add_column (bm_view, _("Location"), + EPHY_TREE_MODEL_NODE_COL_LOCATION, TRUE); + gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (bm_view), TRUE, TRUE, 0); + gtk_widget_show (GTK_WIDGET (bm_view)); + editor->priv->bm_view = bm_view; + g_signal_connect (G_OBJECT (bm_view), + "node_activated", + G_CALLBACK (ephy_bookmarks_editor_node_activated_cb), + editor); + g_signal_connect (G_OBJECT (bm_view), + "node_selected", + G_CALLBACK (ephy_bookmarks_editor_node_selected_cb), + editor); + + gtk_box_pack_start (GTK_BOX (vbox), + build_editing_table (editor), + FALSE, FALSE, 0); + + gtk_dialog_add_button (GTK_DIALOG (editor), + GTK_STOCK_REMOVE, + RESPONSE_REMOVE); + gtk_dialog_add_button (GTK_DIALOG (editor), + GTK_STOCK_CLOSE, + GTK_RESPONSE_CLOSE); + gtk_dialog_set_default_response (GTK_DIALOG (editor), GTK_RESPONSE_CLOSE); +} + +GtkWidget * +ephy_bookmarks_editor_new (EphyBookmarks *bookmarks, + GtkWindow *parent) +{ + EphyBookmarksEditor *editor; + + g_assert (bookmarks != NULL); + + editor = EPHY_BOOKMARKS_EDITOR (g_object_new + (EPHY_TYPE_BOOKMARKS_EDITOR, + "bookmarks", bookmarks, + NULL)); + + if (parent) + { + gtk_window_set_transient_for (GTK_WINDOW (editor), parent); + } + + ephy_bookmarks_editor_construct (editor); + + return GTK_WIDGET (editor); +} + +static void +ephy_bookmarks_editor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyBookmarksEditor *editor = EPHY_BOOKMARKS_EDITOR (object); + + switch (prop_id) + { + case PROP_BOOKMARKS: + editor->priv->bookmarks = g_value_get_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ephy_bookmarks_editor_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyBookmarksEditor *editor = EPHY_BOOKMARKS_EDITOR (object); + + switch (prop_id) + { + case PROP_BOOKMARKS: + g_value_set_object (value, editor->priv->bookmarks); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ephy_bookmarks_editor_init (EphyBookmarksEditor *editor) +{ + editor->priv = g_new0 (EphyBookmarksEditorPrivate, 1); +} diff --git a/src/bookmarks/ephy-bookmarks-editor.h b/src/bookmarks/ephy-bookmarks-editor.h new file mode 100644 index 000000000..f79dfa673 --- /dev/null +++ b/src/bookmarks/ephy-bookmarks-editor.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef EPHY_BOOKMARKS_EDITOR_H +#define EPHY_BOOKMARKS_EDITOR_H + +#include <gtk/gtkdialog.h> + +#include "ephy-node-view.h" +#include "ephy-bookmarks.h" + +G_BEGIN_DECLS + +#define EPHY_TYPE_BOOKMARKS_EDITOR (ephy_bookmarks_editor_get_type ()) +#define EPHY_BOOKMARKS_EDITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_BOOKMARKS_EDITOR, EphyBookmarksEditor)) +#define EPHY_BOOKMARKS_EDITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_BOOKMARKS_EDITOR, EphyBookmarksEditorClass)) +#define EPHY_IS_BOOKMARKS_EDITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_BOOKMARKS_EDITOR)) +#define EPHY_IS_BOOKMARKS_EDITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_BOOKMARKS_EDITOR)) +#define EPHY_BOOKMARKS_EDITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_BOOKMARKS_EDITOR, EphyBookmarksEditorClass)) + +typedef struct EphyBookmarksEditorPrivate EphyBookmarksEditorPrivate; + +typedef struct +{ + GtkDialog parent; + + EphyBookmarksEditorPrivate *priv; +} EphyBookmarksEditor; + +typedef struct +{ + GtkDialogClass parent; +} EphyBookmarksEditorClass; + +GType ephy_bookmarks_editor_get_type (void); + +GtkWidget *ephy_bookmarks_editor_new (EphyBookmarks *bookmarks, + GtkWindow *parent); + +G_END_DECLS + +#endif /* EPHY_BOOKMARKS_EDITOR_H */ diff --git a/src/bookmarks/ephy-bookmarks.c b/src/bookmarks/ephy-bookmarks.c new file mode 100644 index 000000000..e27a30496 --- /dev/null +++ b/src/bookmarks/ephy-bookmarks.c @@ -0,0 +1,988 @@ +/* + * Copyright (C) 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-bookmarks.h" +#include "ephy-file-helpers.h" +#include "ephy-shell.h" +#include "ephy-history.h" + +#include <string.h> +#include <libgnome/gnome-i18n.h> + +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +#define EPHY_BOOKMARKS_XML_VERSION "0.1" + +#define MAX_FAVORITES_NUM 10 + +struct EphyBookmarksPrivate +{ + char *xml_file; + EphyNode *bookmarks; + EphyNode *keywords; + EphyNode *favorites; + EphyNode *lower_fav; + double lower_score; + GHashTable *bookmarks_hash; + GStaticRWLock *bookmarks_hash_lock; + GHashTable *favorites_hash; + GStaticRWLock *favorites_hash_lock; + GHashTable *keywords_hash; + GStaticRWLock *keywords_hash_lock; +}; + +static void +ephy_bookmarks_class_init (EphyBookmarksClass *klass); +static void +ephy_bookmarks_init (EphyBookmarks *tab); +static void +ephy_bookmarks_finalize (GObject *object); +static void +ephy_bookmarks_autocompletion_source_init (EphyAutocompletionSourceIface *iface); + +static GObjectClass *parent_class = NULL; + +GType +ephy_bookmarks_get_type (void) +{ + static GType ephy_bookmarks_type = 0; + + if (ephy_bookmarks_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyBookmarksClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_bookmarks_class_init, + NULL, + NULL, /* class_data */ + sizeof (EphyBookmarks), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_bookmarks_init + }; + + static const GInterfaceInfo autocompletion_source_info = + { + (GInterfaceInitFunc) ephy_bookmarks_autocompletion_source_init, + NULL, + NULL + }; + + ephy_bookmarks_type = g_type_register_static (G_TYPE_OBJECT, + "EphyBookmarks", + &our_info, 0); + + g_type_add_interface_static (ephy_bookmarks_type, + EPHY_TYPE_AUTOCOMPLETION_SOURCE, + &autocompletion_source_info); + } + + return ephy_bookmarks_type; +} + +static void +ephy_bookmarks_autocompletion_source_set_basic_key (EphyAutocompletionSource *source, + const gchar *basic_key) +{ + /* nothing to do here */ +} + +static void +ephy_bookmarks_autocompletion_source_foreach (EphyAutocompletionSource *source, + const gchar *current_text, + EphyAutocompletionSourceForeachFunc func, + gpointer data) +{ + GPtrArray *children; + int i; + EphyBookmarks *eb = EPHY_BOOKMARKS (source); + + children = ephy_node_get_children (eb->priv->bookmarks); + for (i = 0; i < children->len; i++) + { + EphyNode *kid; + const char *url, *smart_url, *title, *keywords; + char *item; + + kid = g_ptr_array_index (children, i); + url = ephy_node_get_property_string + (kid, EPHY_NODE_BMK_PROP_LOCATION); + smart_url = ephy_node_get_property_string + (kid, EPHY_NODE_BMK_PROP_SMART_LOCATION); + title = ephy_node_get_property_string + (kid, EPHY_NODE_BMK_PROP_TITLE); + keywords = ephy_node_get_property_string + (kid, EPHY_NODE_BMK_PROP_KEYWORDS); + item = g_strconcat (title, keywords, NULL); + + if (smart_url == NULL || + g_utf8_strlen (smart_url, -1) == 0) + { + smart_url = NULL; + } + + func (source, + smart_url ? NULL : item, + title, + smart_url ? smart_url : url, + (smart_url != NULL), + TRUE, 0, data); + + g_free (item); + } + ephy_node_thaw (eb->priv->bookmarks); +} + +static void +ephy_bookmarks_emit_data_changed (EphyBookmarks *eb) +{ + g_signal_emit_by_name (eb, "data-changed"); +} + +static void +ephy_bookmarks_autocompletion_source_init (EphyAutocompletionSourceIface *iface) +{ + iface->foreach = ephy_bookmarks_autocompletion_source_foreach; + iface->set_basic_key = ephy_bookmarks_autocompletion_source_set_basic_key; +} + +static void +ephy_bookmarks_class_init (EphyBookmarksClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_bookmarks_finalize; +} + +static gboolean +ephy_bookmarks_clean_empty_keywords (EphyBookmarks *eb) +{ + GPtrArray *children; + int i; + + children = ephy_node_get_children (eb->priv->keywords); + ephy_node_thaw (eb->priv->keywords); + for (i = 0; i < children->len; i++) + { + EphyNode *kid; + + kid = g_ptr_array_index (children, i); + + if (ephy_node_get_n_children (kid) == 0) + { + DEBUG_MSG (("Remove empty keyword: %s\n", + ephy_node_get_property_string (kid, + EPHY_NODE_KEYWORD_PROP_NAME))); + ephy_node_unref (kid); + } + } + + return FALSE; +} + +static void +ephy_bookmarks_load (EphyBookmarks *eb) +{ + xmlDocPtr doc; + xmlNodePtr root, child; + char *tmp; + + if (g_file_test (eb->priv->xml_file, G_FILE_TEST_EXISTS) == FALSE) + return; + + doc = xmlParseFile (eb->priv->xml_file); + g_assert (doc != NULL); + + root = xmlDocGetRootElement (doc); + + tmp = xmlGetProp (root, "version"); + g_assert (tmp != NULL && strcmp (tmp, EPHY_BOOKMARKS_XML_VERSION) == 0); + g_free (tmp); + + for (child = root->children; child != NULL; child = child->next) + { + EphyNode *node; + + node = ephy_node_new_from_xml (child); + } + + xmlFreeDoc (doc); +} + +static void +ephy_bookmarks_save (EphyBookmarks *eb) +{ + xmlDocPtr doc; + xmlNodePtr root; + GPtrArray *children; + int i; + + DEBUG_MSG (("Saving bookmarks\n")); + + /* save nodes to xml */ + xmlIndentTreeOutput = TRUE; + doc = xmlNewDoc ("1.0"); + + root = xmlNewDocNode (doc, NULL, "ephy_bookmarks", NULL); + xmlSetProp (root, "version", EPHY_BOOKMARKS_XML_VERSION); + xmlDocSetRootElement (doc, root); + + children = ephy_node_get_children (eb->priv->keywords); + for (i = 0; i < children->len; i++) + { + EphyNode *kid; + + kid = g_ptr_array_index (children, i); + + if (kid != eb->priv->bookmarks) + { + ephy_node_save_to_xml (kid, root); + } + } + ephy_node_thaw (eb->priv->keywords); + + children = ephy_node_get_children (eb->priv->bookmarks); + for (i = 0; i < children->len; i++) + { + EphyNode *kid; + + kid = g_ptr_array_index (children, i); + + ephy_node_save_to_xml (kid, root); + } + ephy_node_thaw (eb->priv->bookmarks); + + xmlSaveFormatFile (eb->priv->xml_file, doc, 1); +} + +static double +get_history_item_score (EphyHistory *eh, const char *page) +{ + return ephy_history_get_page_visits (eh, page); +} + +static EphyNode * +compute_lower_fav (EphyNode *favorites, double *score) +{ + GPtrArray *children; + int i; + EphyEmbedShell *embed_shell; + EphyHistory *history; + EphyNode *result = NULL; + + embed_shell = ephy_shell_get_embed_shell (ephy_shell); + history = ephy_embed_shell_get_global_history (embed_shell); + + *score = DBL_MAX; + children = ephy_node_get_children (favorites); + for (i = 0; i < children->len; i++) + { + const char *url; + EphyNode *child; + double item_score; + + child = g_ptr_array_index (children, i); + url = ephy_node_get_property_string + (child, EPHY_NODE_BMK_PROP_LOCATION); + item_score = get_history_item_score (history, url); + if (*score > item_score) + { + *score = item_score; + result = child; + } + } + ephy_node_thaw (favorites); + + if (result == NULL) *score = 0; + + return result; +} + +static void +ephy_bookmarks_update_favorites (EphyBookmarks *eb) +{ + eb->priv->lower_fav = compute_lower_fav (eb->priv->favorites, + &eb->priv->lower_score); +} + +static gboolean +add_to_favorites (EphyBookmarks *eb, EphyNode *node, EphyHistory *eh) +{ + const char *url; + EphyNode *fav_node; + gboolean full_menu; + double score; + + url = ephy_node_get_property_string (node, EPHY_NODE_BMK_PROP_LOCATION); + g_static_rw_lock_reader_lock (eb->priv->favorites_hash_lock); + fav_node = g_hash_table_lookup (eb->priv->favorites_hash, url); + g_static_rw_lock_reader_unlock (eb->priv->favorites_hash_lock); + if (fav_node) return FALSE; + + score = get_history_item_score (eh, url); + full_menu = ephy_node_get_n_children (eb->priv->favorites) + > MAX_FAVORITES_NUM; + if (full_menu && score < eb->priv->lower_score) return FALSE; + + if (eb->priv->lower_fav && full_menu) + { + ephy_node_remove_child (eb->priv->favorites, + eb->priv->lower_fav); + } + + ephy_node_add_child (eb->priv->favorites, node); + ephy_bookmarks_update_favorites (eb); + + return TRUE; +} + +static void +update_favorites_menus () +{ + Session *session; + GList *l; + + session = ephy_shell_get_session (ephy_shell); + l = session_get_windows (session); + + for (; l != NULL; l = l->next) + { + EphyWindow *window = EPHY_WINDOW (l->data); + + ephy_window_update_control (window, FavoritesControl); + } +} + +static void +history_site_visited_cb (EphyHistory *gh, const char *url, EphyBookmarks *eb) +{ + EphyNode *node; + + g_static_rw_lock_reader_lock (eb->priv->bookmarks_hash_lock); + node = g_hash_table_lookup (eb->priv->bookmarks_hash, url); + g_static_rw_lock_reader_unlock (eb->priv->bookmarks_hash_lock); + if (!node) return; + + if (add_to_favorites (eb, node, gh)) + { + update_favorites_menus (); + } +} + +static void +ephy_setup_history_notifiers (EphyBookmarks *eb) +{ + EphyEmbedShell *embed_shell; + EphyHistory *history; + + embed_shell = ephy_shell_get_embed_shell (ephy_shell); + history = ephy_embed_shell_get_global_history (embed_shell); + + g_signal_connect (history, "visited", + G_CALLBACK (history_site_visited_cb), eb); +} + +static void +keywords_added_cb (EphyNode *node, + EphyNode *child, + EphyBookmarks *eb) +{ + g_static_rw_lock_writer_lock (eb->priv->keywords_hash_lock); + + g_hash_table_insert (eb->priv->keywords_hash, + (char *) ephy_node_get_property_string (child, EPHY_NODE_KEYWORD_PROP_NAME), + child); + + g_static_rw_lock_writer_unlock (eb->priv->keywords_hash_lock); +} + +static void +keywords_removed_cb (EphyNode *node, + EphyNode *child, + EphyBookmarks *eb) +{ + g_static_rw_lock_writer_lock (eb->priv->keywords_hash_lock); + + g_hash_table_remove (eb->priv->keywords_hash, + ephy_node_get_property_string (child, EPHY_NODE_KEYWORD_PROP_NAME)); + + g_static_rw_lock_writer_unlock (eb->priv->keywords_hash_lock); +} + +static void +favorites_added_cb (EphyNode *node, + EphyNode *child, + EphyBookmarks *eb) +{ + g_static_rw_lock_writer_lock (eb->priv->favorites_hash_lock); + + g_hash_table_insert (eb->priv->favorites_hash, + (char *) ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_LOCATION), + child); + + g_static_rw_lock_writer_unlock (eb->priv->favorites_hash_lock); +} + +static void +favorites_removed_cb (EphyNode *node, + EphyNode *child, + EphyBookmarks *eb) +{ + g_static_rw_lock_writer_lock (eb->priv->favorites_hash_lock); + + g_hash_table_remove (eb->priv->favorites_hash, + ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_LOCATION)); + + g_static_rw_lock_writer_unlock (eb->priv->favorites_hash_lock); +} + +static void +bookmarks_added_cb (EphyNode *node, + EphyNode *child, + EphyBookmarks *eb) +{ + g_static_rw_lock_writer_lock (eb->priv->bookmarks_hash_lock); + + g_hash_table_insert (eb->priv->bookmarks_hash, + (char *) ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_LOCATION), + child); + + g_static_rw_lock_writer_unlock (eb->priv->bookmarks_hash_lock); +} + +static void +bookmarks_removed_cb (EphyNode *node, + EphyNode *child, + EphyBookmarks *eb) +{ + ephy_bookmarks_emit_data_changed (eb); + g_idle_add ((GSourceFunc)ephy_bookmarks_clean_empty_keywords, eb); + + g_static_rw_lock_writer_lock (eb->priv->bookmarks_hash_lock); + + g_hash_table_remove (eb->priv->bookmarks_hash, + ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_LOCATION)); + + g_static_rw_lock_writer_unlock (eb->priv->bookmarks_hash_lock); +} + +static void +ephy_bookmarks_init (EphyBookmarks *eb) +{ + GValue value = { 0, }; + + eb->priv = g_new0 (EphyBookmarksPrivate, 1); + + eb->priv->xml_file = g_build_filename (ephy_dot_dir (), + "bookmarks.xml", + NULL); + + eb->priv->bookmarks_hash = g_hash_table_new (g_str_hash, + g_str_equal); + eb->priv->bookmarks_hash_lock = g_new0 (GStaticRWLock, 1); + g_static_rw_lock_init (eb->priv->bookmarks_hash_lock); + + eb->priv->keywords_hash = g_hash_table_new (g_str_hash, + g_str_equal); + eb->priv->keywords_hash_lock = g_new0 (GStaticRWLock, 1); + g_static_rw_lock_init (eb->priv->keywords_hash_lock); + + eb->priv->favorites_hash = g_hash_table_new (g_str_hash, + g_str_equal); + eb->priv->favorites_hash_lock = g_new0 (GStaticRWLock, 1); + g_static_rw_lock_init (eb->priv->favorites_hash_lock); + + /* Bookmarks */ + eb->priv->bookmarks = ephy_node_new (); + ephy_node_ref (eb->priv->bookmarks); + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, _("All")); + ephy_node_set_property (eb->priv->bookmarks, + EPHY_NODE_KEYWORD_PROP_NAME, + &value); + g_value_unset (&value); + g_signal_connect_object (G_OBJECT (eb->priv->bookmarks), + "child_added", + G_CALLBACK (bookmarks_added_cb), + G_OBJECT (eb), + 0); + g_signal_connect_object (G_OBJECT (eb->priv->bookmarks), + "child_removed", + G_CALLBACK (bookmarks_removed_cb), + G_OBJECT (eb), + 0); + + /* Keywords */ + eb->priv->keywords = ephy_node_new (); + ephy_node_ref (eb->priv->keywords); + + ephy_node_add_child (eb->priv->keywords, + eb->priv->bookmarks); + g_signal_connect_object (G_OBJECT (eb->priv->keywords), + "child_added", + G_CALLBACK (keywords_added_cb), + G_OBJECT (eb), + 0); + g_signal_connect_object (G_OBJECT (eb->priv->keywords), + "child_removed", + G_CALLBACK (keywords_removed_cb), + G_OBJECT (eb), + 0); + + eb->priv->favorites = ephy_node_new (); + ephy_node_ref (eb->priv->favorites); + g_signal_connect_object (G_OBJECT (eb->priv->favorites), + "child_added", + G_CALLBACK (favorites_added_cb), + G_OBJECT (eb), + 0); + g_signal_connect_object (G_OBJECT (eb->priv->favorites), + "child_removed", + G_CALLBACK (favorites_removed_cb), + G_OBJECT (eb), + 0); + + ephy_bookmarks_load (eb); + ephy_bookmarks_emit_data_changed (eb); + + ephy_setup_history_notifiers (eb); + ephy_bookmarks_update_favorites (eb); +} + +static void +ephy_bookmarks_finalize (GObject *object) +{ + EphyBookmarks *eb; + + g_return_if_fail (IS_EPHY_BOOKMARKS (object)); + + eb = EPHY_BOOKMARKS (object); + + g_return_if_fail (eb->priv != NULL); + + ephy_bookmarks_save (eb); + + ephy_node_unref (eb->priv->bookmarks); + ephy_node_unref (eb->priv->keywords); + ephy_node_unref (eb->priv->favorites); + + g_hash_table_destroy (eb->priv->bookmarks_hash); + g_static_rw_lock_free (eb->priv->bookmarks_hash_lock); + g_hash_table_destroy (eb->priv->favorites_hash); + g_static_rw_lock_free (eb->priv->favorites_hash_lock); + g_hash_table_destroy (eb->priv->keywords_hash); + g_static_rw_lock_free (eb->priv->keywords_hash_lock); + + g_free (eb->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +EphyBookmarks * +ephy_bookmarks_new () +{ + EphyBookmarks *tab; + + tab = EPHY_BOOKMARKS (g_object_new (EPHY_BOOKMARKS_TYPE, NULL)); + + return tab; +} + +EphyNode * +ephy_bookmarks_add (EphyBookmarks *eb, + const char *title, + const char *url, + const char *smart_url, + const char *keywords) +{ + EphyNode *bm; + GValue value = { 0, }; + + bm = ephy_node_new (); + + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, title); + ephy_node_set_property (bm, EPHY_NODE_BMK_PROP_TITLE, + &value); + g_value_unset (&value); + + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, url); + ephy_node_set_property (bm, EPHY_NODE_BMK_PROP_LOCATION, + &value); + g_value_unset (&value); + + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, smart_url); + ephy_node_set_property (bm, EPHY_NODE_BMK_PROP_SMART_LOCATION, + &value); + g_value_unset (&value); + + ephy_bookmarks_update_keywords (eb, keywords, bm); + + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, keywords); + ephy_node_set_property (bm, EPHY_NODE_BMK_PROP_KEYWORDS, + &value); + g_value_unset (&value); + + ephy_node_add_child (eb->priv->bookmarks, bm); + + ephy_bookmarks_emit_data_changed (eb); + + return bm; +} + +static gchar * +options_skip_spaces (const gchar *str) +{ + const gchar *ret = str; + while (*ret && g_ascii_isspace (*ret)) + { + ++ret; + } + return (gchar *) ret; +} + +static char * +options_find_value_end (const gchar *value_start) +{ + const gchar *value_end; + if (*value_start == '"') + { + for (value_end = value_start + 1; + *value_end && (*value_end != '"' || *(value_end - 1) == '\\'); + ++value_end) ; + } + else + { + for (value_end = value_start; + *value_end && ! (g_ascii_isspace (*value_end) + || *value_end == ',' + || *value_end == ';'); + ++value_end) ; + } + return (gchar *) value_end; +} + +static char * +options_find_next_option (const char *current) +{ + const gchar *value_start; + const gchar *value_end; + const gchar *ret; + value_start = strchr (current, '='); + if (!value_start) return NULL; + value_start = options_skip_spaces (value_start + 1); + value_end = options_find_value_end (value_start); + if (! (*value_end)) return NULL; + for (ret = value_end + 1; + *ret && (g_ascii_isspace (*ret) + || *ret == ',' + || *ret == ';'); + ++ret); + return (char *) ret; +} + +/** + * Very simple parser for option strings in the + * form a=b,c=d,e="f g",... + */ +static gchar * +smart_url_options_get (const gchar *options, const gchar *option) +{ + gchar *ret = NULL; + gsize optionlen = strlen (option); + const gchar *current = options_skip_spaces (options); + + while (current) + { + if (!strncmp (option, current, optionlen)) + { + if (g_ascii_isspace (*(current + optionlen)) || *(current + optionlen) == '=') + { + const gchar *value_start; + const gchar *value_end; + value_start = strchr (current + optionlen, '='); + if (!value_start) continue; + value_start = options_skip_spaces (value_start + 1); + value_end = options_find_value_end (value_start); + if (*value_start == '"') value_start++; + if (value_end >= value_start) + { + ret = g_strndup (value_start, value_end - value_start); + break; + } + } + } + current = options_find_next_option (current); + } + + return ret; +} + +static char * +get_smarturl_only (const char *smarturl) +{ + const gchar *openbrace; + const gchar *closebrace; + const gchar *c; + + openbrace = strchr (smarturl, '{'); + if (!openbrace) return g_strdup (smarturl); + for (c = smarturl; c < openbrace; ++c) + { + if (!strchr (" \t\n", *c)) return g_strdup (smarturl); + } + + closebrace = strchr (openbrace + 1, '}'); + if (!closebrace) return g_strdup (smarturl); + + return g_strdup (closebrace + 1); +} + +char * +ephy_bookmarks_solve_smart_url (EphyBookmarks *eb, + const char *smart_url, + const char *content) +{ + gchar *ret; + GString *s; + gchar *t1; + gchar *t2; + gchar *encoding; + gchar *smarturl_only; + gchar *arg; + + g_return_val_if_fail (content != NULL, NULL); + + smarturl_only = get_smarturl_only (smart_url); + + s = g_string_new (""); + + encoding = smart_url_options_get (smart_url, "encoding"); + if (!encoding) + { + encoding = g_strdup ("UTF-8"); + } + + arg = g_convert (content, strlen (content), + encoding, "UTF-8", NULL, NULL, NULL); + + t1 = smarturl_only; + t2 = strstr (t1, "%s"); + g_return_val_if_fail (t2 != NULL, NULL); + g_string_append_len (s, t1, t2 - t1); + g_string_append (s, arg); + t1 = t2 + 2; + g_string_append (s, t1); + ret = s->str; + g_string_free (s, FALSE); + + g_free (arg); + g_free (encoding); + g_free (smarturl_only); + + return ret; +} + +EphyNode * +ephy_bookmarks_add_keyword (EphyBookmarks *eb, + const char *name) +{ + EphyNode *key; + GValue value = { 0, }; + + key = ephy_node_new (); + + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, name); + ephy_node_set_property (key, EPHY_NODE_KEYWORD_PROP_NAME, + &value); + g_value_unset (&value); + + ephy_node_add_child (eb->priv->keywords, key); + + return key; +} + +EphyNode * +ephy_bookmarks_find_keyword (EphyBookmarks *eb, + const char *name, + gboolean partial_match) +{ + EphyNode *node; + + g_return_val_if_fail (name != NULL, NULL); + + if (!partial_match) + { + g_static_rw_lock_reader_lock (eb->priv->keywords_hash_lock); + node = g_hash_table_lookup (eb->priv->keywords_hash, name); + g_static_rw_lock_reader_unlock (eb->priv->keywords_hash_lock); + } + else + { + GPtrArray *children; + int i; + + if (g_utf8_strlen (name, -1) == 0) + { + DEBUG_MSG (("Empty name, no keyword matches.\n")); + return NULL; + } + + children = ephy_node_get_children (eb->priv->keywords); + node = NULL; + for (i = 0; i < children->len; i++) + { + EphyNode *kid; + const char *key; + + kid = g_ptr_array_index (children, i); + key = ephy_node_get_property_string (kid, EPHY_NODE_KEYWORD_PROP_NAME); + + if (g_str_has_prefix (key, name) > 0) + { + node = kid; + } + } + ephy_node_thaw (eb->priv->keywords); + } + + return node; +} + +void +ephy_bookmarks_set_keyword (EphyBookmarks *eb, + EphyNode *keyword, + EphyNode *bookmark) +{ + ephy_node_add_child (keyword, bookmark); +} + +void +ephy_bookmarks_unset_keyword (EphyBookmarks *eb, + EphyNode *keyword, + EphyNode *bookmark) +{ + ephy_node_remove_child (keyword, bookmark); + ephy_bookmarks_clean_empty_keywords (eb); +} + +static GList * +diff_keywords (char **ks1, char **ks2) +{ + GList *result = NULL; + int i, j; + + for (i = 0; ks1 != NULL && ks1[i] != NULL; i++) + { + gboolean found = FALSE; + + DEBUG_MSG (("Diff keywords, keyword:\"%s\"\n", ks1[i])); + + for (j = 0; ks2 != NULL && ks2[j] != NULL; j++) + { + if (strcmp (ks1[i], ks2[j]) == 0) + { + found = TRUE; + } + } + + if (!found && g_utf8_strlen (ks1[i], -1) > 0) + { + result = g_list_append (result, ks1[i]); + } + } + + return result; +} + +void +ephy_bookmarks_update_keywords (EphyBookmarks *eb, + const char *keywords, + EphyNode *node) +{ + const char *prop; + char **ks, **old_ks = NULL; + GList *diffs, *l; + EphyNode *keyword; + + prop = ephy_node_get_property_string (node, EPHY_NODE_BMK_PROP_KEYWORDS); + ks = g_strsplit (keywords, " ", 10); + if (prop != NULL) + { + old_ks = g_strsplit (prop, " ", 10); + } + + diffs = diff_keywords (ks, old_ks); + for (l = diffs; l != NULL; l = l->next) + { + char *word = (char *)l->data; + + keyword = ephy_bookmarks_find_keyword + (eb, word, FALSE); + + if (!keyword) + { + keyword = ephy_bookmarks_add_keyword + (eb, word); + } + + ephy_bookmarks_set_keyword (eb, keyword, node); + } + g_list_free (diffs); + + diffs = diff_keywords (old_ks, ks); + for (l = diffs; l != NULL; l = l->next) + { + keyword = ephy_bookmarks_find_keyword (eb, + (char *)l->data, FALSE); + g_return_if_fail (keyword != NULL); + + ephy_bookmarks_unset_keyword (eb, keyword, node); + } + g_list_free (diffs); + + g_strfreev (ks); + g_strfreev (old_ks); +} + +EphyNode * +ephy_bookmarks_get_keywords (EphyBookmarks *eb) +{ + return eb->priv->keywords; +} + +EphyNode * +ephy_bookmarks_get_bookmarks (EphyBookmarks *eb) +{ + return eb->priv->bookmarks; +} + +EphyNode * +ephy_bookmarks_get_favorites (EphyBookmarks *eb) +{ + return eb->priv->favorites; +} + diff --git a/src/bookmarks/ephy-bookmarks.h b/src/bookmarks/ephy-bookmarks.h new file mode 100644 index 000000000..e355950c4 --- /dev/null +++ b/src/bookmarks/ephy-bookmarks.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_BOOKMARKS_H +#define EPHY_BOOKMARKS_H + +#include <glib-object.h> + +#include "ephy-node.h" + +G_BEGIN_DECLS + +typedef struct EphyBookmarksClass EphyBookmarksClass; + +#define EPHY_BOOKMARKS_TYPE (ephy_bookmarks_get_type ()) +#define EPHY_BOOKMARKS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPHY_BOOKMARKS_TYPE, EphyBookmarks)) +#define EPHY_BOOKMARKS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EPHY_BOOKMARKS_TYPE, EphyBookmarksClass)) +#define IS_EPHY_BOOKMARKS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_BOOKMARKS_TYPE)) +#define IS_EPHY_BOOKMARKS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EPHY_BOOKMARKS_TYPE)) + +typedef struct EphyBookmarks EphyBookmarks; +typedef struct EphyBookmarksPrivate EphyBookmarksPrivate; + +enum +{ + EPHY_NODE_BMK_PROP_TITLE = 2, + EPHY_NODE_BMK_PROP_LOCATION = 3, + EPHY_NODE_BMK_PROP_KEYWORDS = 4, + EPHY_NODE_KEYWORD_PROP_NAME = 5, + EPHY_NODE_BMK_PROP_SMART_LOCATION = 6 +}; + +struct EphyBookmarks +{ + GObject parent; + EphyBookmarksPrivate *priv; +}; + +struct EphyBookmarksClass +{ + GObjectClass parent_class; +}; + +GType ephy_bookmarks_get_type (void); + +EphyBookmarks *ephy_bookmarks_new (void); + +/* Bookmarks */ + +EphyNode *ephy_bookmarks_add (EphyBookmarks *eb, + const char *title, + const char *url, + const char *smart_url, + const char *keywords); + +char *ephy_bookmarks_solve_smart_url (EphyBookmarks *eb, + const char *smart_url, + const char *content); + +/* Keywords */ + +EphyNode *ephy_bookmarks_add_keyword (EphyBookmarks *eb, + const char *name); + +EphyNode *ephy_bookmarks_find_keyword (EphyBookmarks *eb, + const char *name, + gboolean partial_match); + +void ephy_bookmarks_set_keyword (EphyBookmarks *eb, + EphyNode *keyword, + EphyNode *bookmark); + +void ephy_bookmarks_unset_keyword (EphyBookmarks *eb, + EphyNode *keyword, + EphyNode *bookmark); + +void ephy_bookmarks_update_keywords (EphyBookmarks *eb, + const char *keywords, + EphyNode *bookmark_node); + +/* Favorites */ + +EphyNode *ephy_bookmarks_get_favorites (EphyBookmarks *eb); + +/* Root */ + +EphyNode *ephy_bookmarks_get_keywords (EphyBookmarks *eb); + +EphyNode *ephy_bookmarks_get_bookmarks (EphyBookmarks *eb); + +G_END_DECLS + +#endif diff --git a/src/bookmarks/ephy-keywords-entry.c b/src/bookmarks/ephy-keywords-entry.c new file mode 100644 index 000000000..94d6c93a9 --- /dev/null +++ b/src/bookmarks/ephy-keywords-entry.c @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-keywords-entry.h" +#include "ephy-marshal.h" +#include "ephy-gobject-misc.h" + +#include <gdk/gdkkeysyms.h> + +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); + +/** + * Private data + */ +struct _EphyKeywordsEntryPrivate +{ + EphyBookmarks *bookmarks; +}; + +/** + * Private functions, only availble from this file + */ +static void ephy_keywords_entry_class_init (EphyKeywordsEntryClass *klass); +static void ephy_keywords_entry_init (EphyKeywordsEntry *w); +static void ephy_keywords_entry_finalize_impl (GObject *o); +static gint ephy_keywords_entry_key_press (GtkWidget *widget, + GdkEventKey *event); + +enum +{ + KEYWORDS_CHANGED, + LAST_SIGNAL +}; + +static GObjectClass *parent_class = NULL; + +static guint keywords_entry_signals[LAST_SIGNAL] = { 0 }; + +MAKE_GET_TYPE (ephy_keywords_entry, "EphyKeywordsEntry", EphyKeywordsEntry, + ephy_keywords_entry_class_init, + ephy_keywords_entry_init, GTK_TYPE_ENTRY); + +static void +ephy_keywords_entry_class_init (EphyKeywordsEntryClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + GtkWidgetClass *widget_class; + + parent_class = g_type_class_peek_parent (class); + widget_class = (GtkWidgetClass*) class; + + gobject_class->finalize = ephy_keywords_entry_finalize_impl; + + widget_class->key_press_event = ephy_keywords_entry_key_press; + + keywords_entry_signals[KEYWORDS_CHANGED] = + g_signal_new ("keywords_changed", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EphyKeywordsEntryClass, keywords_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +static void +try_to_expand_keyword (GtkEditable *editable) +{ + char *entry_text; + char *user_text; + const char *expand_text; + char *insert_text; + int user_text_length; + int expand_text_length; + int keyword_offset = 0; + int tmp; + EphyKeywordsEntry *entry = EPHY_KEYWORDS_ENTRY (editable); + EphyNode *node; + + entry_text = gtk_editable_get_chars (editable, 0, -1); + g_return_if_fail (entry_text != NULL); + + DEBUG_MSG (("Entry text \"%s\"\n", entry_text)); + + user_text = g_utf8_strrchr (entry_text, -1, ' '); + + if (user_text) + { + user_text = g_utf8_find_next_char (user_text, NULL); + keyword_offset = g_utf8_pointer_to_offset + (entry_text, user_text); + } + else + { + user_text = entry_text; + } + + DEBUG_MSG (("User text \"%s\"\n", user_text)); + + node = ephy_bookmarks_find_keyword (entry->priv->bookmarks, + user_text, TRUE); + if (node) + { + expand_text = ephy_node_get_property_string + (node, EPHY_NODE_KEYWORD_PROP_NAME); + + DEBUG_MSG (("Expand text %s\n", expand_text)); + + expand_text_length = g_utf8_strlen (expand_text, -1); + user_text_length = g_utf8_strlen (user_text, -1); + + insert_text = g_utf8_offset_to_pointer (expand_text, user_text_length); + gtk_editable_insert_text (editable, + insert_text, + g_utf8_strlen (insert_text, -1), + &tmp); + gtk_editable_select_region (editable, user_text_length + keyword_offset, -1); + } + else + { + DEBUG_MSG (("No expansion.\n")); + } + + g_free (entry_text); +} + +/* Until we have a more elegant solution, this is how we figure out if + * the GtkEntry inserted characters, assuming that the return value is + * TRUE indicating that the GtkEntry consumed the key event for some + * reason. This is a clone of code from GtkEntry. + */ +static gboolean +entry_would_have_inserted_characters (const GdkEventKey *event) +{ + switch (event->keyval) { + case GDK_BackSpace: + case GDK_Clear: + case GDK_Insert: + case GDK_Delete: + case GDK_Home: + case GDK_End: + case GDK_Left: + case GDK_Right: + case GDK_Return: + return FALSE; + default: + if (event->keyval >= 0x20 && event->keyval <= 0xFF) { + if ((event->state & GDK_CONTROL_MASK) != 0) { + return FALSE; + } + if ((event->state & GDK_MOD1_MASK) != 0) { + return FALSE; + } + } + return event->length > 0; + } +} + +static int +get_editable_number_of_chars (GtkEditable *editable) +{ + char *text; + int length; + + text = gtk_editable_get_chars (editable, 0, -1); + length = g_utf8_strlen (text, -1); + g_free (text); + return length; +} + +static void +set_position_and_selection_to_end (GtkEditable *editable) +{ + int end; + + end = get_editable_number_of_chars (editable); + gtk_editable_select_region (editable, end, end); + gtk_editable_set_position (editable, end); +} + +static gboolean +position_and_selection_are_at_end (GtkEditable *editable) +{ + int end; + int start_sel, end_sel; + + end = get_editable_number_of_chars (editable); + if (gtk_editable_get_selection_bounds (editable, &start_sel, &end_sel)) + { + if (start_sel != end || end_sel != end) + { + return FALSE; + } + } + return gtk_editable_get_position (editable) == end; +} + +static gint +ephy_keywords_entry_key_press (GtkWidget *widget, + GdkEventKey *event) +{ + GtkEditable *editable; + GdkEventKey *keyevent; + EphyKeywordsEntry *entry; + gboolean result; + + entry = EPHY_KEYWORDS_ENTRY (widget); + editable = GTK_EDITABLE (entry); + keyevent = (GdkEventKey *)event; + + /* After typing the right arrow key we move the selection to + * the end, if we have a valid selection - since this is most + * likely an auto-completion. We ignore shift / control since + * they can validly be used to extend the selection. + */ + if ((keyevent->keyval == GDK_Right || keyevent->keyval == GDK_End) && + !(keyevent->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) && + gtk_editable_get_selection_bounds (editable, NULL, NULL)) + { + set_position_and_selection_to_end (editable); + } + + result = GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event); + + /* Only do expanding when we are typing at the end of the + * text. + */ + if (entry_would_have_inserted_characters (event) + && position_and_selection_are_at_end (editable)) + { + try_to_expand_keyword (editable); + } + + g_signal_emit (G_OBJECT (entry), keywords_entry_signals[KEYWORDS_CHANGED], 0); + + return result; +} + +static void +ephy_keywords_entry_init (EphyKeywordsEntry *w) +{ + w->priv = g_new0 (EphyKeywordsEntryPrivate, 1); + w->priv->bookmarks = NULL; +} + +static void +ephy_keywords_entry_finalize_impl (GObject *o) +{ + EphyKeywordsEntry *w = EPHY_KEYWORDS_ENTRY (o); + EphyKeywordsEntryPrivate *p = w->priv; + + g_free (p); + G_OBJECT_CLASS (parent_class)->finalize (o); +} + +GtkWidget * +ephy_keywords_entry_new (void) +{ + return GTK_WIDGET (g_object_new (EPHY_TYPE_LOCATION_ENTRY, NULL)); +} + +void +ephy_keywords_entry_set_bookmarks (EphyKeywordsEntry *w, + EphyBookmarks *bookmarks) +{ + w->priv->bookmarks = bookmarks; +} diff --git a/src/bookmarks/ephy-keywords-entry.h b/src/bookmarks/ephy-keywords-entry.h new file mode 100644 index 000000000..5ab5df257 --- /dev/null +++ b/src/bookmarks/ephy-keywords-entry.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_KEYWORDS_ENTRY_H +#define EPHY_KEYWORDS_ENTRY_H + +#include "ephy-bookmarks.h" + +#include <glib-object.h> +#include <gtk/gtkentry.h> + +/* object forward declarations */ + +typedef struct _EphyKeywordsEntry EphyKeywordsEntry; +typedef struct _EphyKeywordsEntryClass EphyKeywordsEntryClass; +typedef struct _EphyKeywordsEntryPrivate EphyKeywordsEntryPrivate; + +/** + * EphyFolderTbWidget object + */ + +#define EPHY_TYPE_LOCATION_ENTRY (ephy_keywords_entry_get_type()) +#define EPHY_KEYWORDS_ENTRY(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_LOCATION_ENTRY,\ + EphyKeywordsEntry)) +#define EPHY_KEYWORDS_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_LOCATION_ENTRY,\ + EphyKeywordsEntryClass)) +#define EPHY_IS_LOCATION_ENTRY(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_LOCATION_ENTRY)) +#define EPHY_IS_LOCATION_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_LOCATION_ENTRY)) +#define EPHY_KEYWORDS_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_LOCATION_ENTRY,\ + EphyKeywordsEntryClass)) + +struct _EphyKeywordsEntryClass +{ + GtkEntryClass parent_class; + + void (* keywords_changed) (EphyKeywordsEntry *entry); +}; + +struct _EphyKeywordsEntry +{ + GtkEntry parent_object; + + EphyKeywordsEntryPrivate *priv; +}; + +GType ephy_keywords_entry_get_type (void); + +GtkWidget *ephy_keywords_entry_new (void); + +void ephy_keywords_entry_set_bookmarks (EphyKeywordsEntry *w, + EphyBookmarks *bookmarks); + +#endif diff --git a/src/bookmarks/ephy-new-bookmark.c b/src/bookmarks/ephy-new-bookmark.c new file mode 100644 index 000000000..ee0d4b983 --- /dev/null +++ b/src/bookmarks/ephy-new-bookmark.c @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include <gtk/gtktable.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkentry.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtkvbox.h> +#include <gtk/gtkstock.h> +#include <gtk/gtkeditable.h> +#include <libgnome/gnome-i18n.h> + +#include "ephy-new-bookmark.h" +#include "ephy-keywords-entry.h" + +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +static void ephy_new_bookmark_class_init (EphyNewBookmarkClass *klass); +static void ephy_new_bookmark_init (EphyNewBookmark *editor); +static void ephy_new_bookmark_finalize (GObject *object); +static void ephy_new_bookmark_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ephy_new_bookmark_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +struct EphyNewBookmarkPrivate +{ + EphyBookmarks *bookmarks; + char *location; + char *smarturl; + + GtkWidget *title_entry; + GtkWidget *keywords_entry; +}; + +enum +{ + PROP_0, + PROP_BOOKMARKS, + PROP_LOCATION +}; + +static GObjectClass *parent_class = NULL; + +GType +ephy_new_bookmark_get_type (void) +{ + static GType ephy_new_bookmark_type = 0; + + if (ephy_new_bookmark_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyNewBookmarkClass), + NULL, + NULL, + (GClassInitFunc) ephy_new_bookmark_class_init, + NULL, + NULL, + sizeof (EphyNewBookmark), + 0, + (GInstanceInitFunc) ephy_new_bookmark_init + }; + + ephy_new_bookmark_type = g_type_register_static (GTK_TYPE_DIALOG, + "EphyNewBookmark", + &our_info, 0); + } + + return ephy_new_bookmark_type; +} + +static void +ephy_new_bookmark_class_init (EphyNewBookmarkClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_new_bookmark_finalize; + + object_class->set_property = ephy_new_bookmark_set_property; + object_class->get_property = ephy_new_bookmark_get_property; + + g_object_class_install_property (object_class, + PROP_BOOKMARKS, + g_param_spec_object ("bookmarks", + "Bookmarks set", + "Bookmarks set", + EPHY_BOOKMARKS_TYPE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, + PROP_LOCATION, + g_param_spec_string ("location", + "Bookmark location", + "Bookmark location", + "", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +} + +static void +ephy_new_bookmark_finalize (GObject *object) +{ + EphyNewBookmark *editor; + + g_return_if_fail (object != NULL); + g_return_if_fail (EPHY_IS_NEW_BOOKMARK (object)); + + editor = EPHY_NEW_BOOKMARK (object); + + g_return_if_fail (editor->priv != NULL); + + g_free (editor->priv->location); + g_free (editor->priv->smarturl); + + g_free (editor->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +ephy_new_bookmark_add (EphyNewBookmark *new_bookmark) +{ + char *title; + char *keywords; + + title = gtk_editable_get_chars + (GTK_EDITABLE (new_bookmark->priv->title_entry), 0, -1); + keywords = gtk_editable_get_chars + (GTK_EDITABLE (new_bookmark->priv->keywords_entry), 0, -1); + ephy_bookmarks_add (new_bookmark->priv->bookmarks, title, + new_bookmark->priv->location, + new_bookmark->priv->smarturl, keywords); +} + +static void +ephy_new_bookmark_response_cb (GtkDialog *dialog, + int response_id, + EphyNewBookmark *new_bookmark) +{ + switch (response_id) + { + case GTK_RESPONSE_CANCEL: + break; + case GTK_RESPONSE_OK: + ephy_new_bookmark_add (new_bookmark); + break; + } + + gtk_widget_destroy (GTK_WIDGET (dialog)); +} + +static GtkWidget * +build_editing_table (EphyNewBookmark *editor) +{ + GtkWidget *table, *label, *entry; + + table = gtk_table_new (2, 2, FALSE); + gtk_table_set_row_spacings (GTK_TABLE (table), 6); + gtk_table_set_col_spacings (GTK_TABLE (table), 6); + gtk_widget_show (table); + + label = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_label_set_markup (GTK_LABEL (label), _("<b>Title:</b>")); + gtk_widget_show (label); + entry = gtk_entry_new (); + editor->priv->title_entry = entry; + gtk_widget_set_size_request (entry, 200, -1); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0); + gtk_table_attach_defaults (GTK_TABLE (table), entry, 1, 2, 0, 1); + + label = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_label_set_markup (GTK_LABEL (label), _("<b>Keywords:</b>")); + gtk_widget_show (label); + entry = ephy_keywords_entry_new (); + ephy_keywords_entry_set_bookmarks (EPHY_KEYWORDS_ENTRY (entry), + editor->priv->bookmarks); + editor->priv->keywords_entry = entry; + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0); + gtk_table_attach_defaults (GTK_TABLE (table), entry, 1, 2, 1, 2); + + return table; +} + +static void +ephy_new_bookmark_construct (EphyNewBookmark *editor) +{ + GtkWidget *hbox, *vbox; + + gtk_window_set_title (GTK_WINDOW (editor), + _("Add bookmark")); + + gtk_dialog_set_has_separator (GTK_DIALOG (editor), FALSE); + gtk_container_set_border_width (GTK_CONTAINER (editor), 6); + g_signal_connect (G_OBJECT (editor), + "response", + G_CALLBACK (ephy_new_bookmark_response_cb), + editor); + + hbox = gtk_hbox_new (FALSE, 6); + gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (editor)->vbox), 12); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (editor)->vbox), + hbox, TRUE, TRUE, 0); + gtk_widget_show (hbox); + + vbox = gtk_vbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (hbox), + vbox, TRUE, TRUE, 0); + gtk_widget_show (vbox); + + gtk_box_pack_start (GTK_BOX (vbox), + build_editing_table (editor), + FALSE, FALSE, 0); + + gtk_dialog_add_button (GTK_DIALOG (editor), + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL); + gtk_dialog_add_button (GTK_DIALOG (editor), + GTK_STOCK_OK, + GTK_RESPONSE_OK); + gtk_dialog_set_default_response (GTK_DIALOG (editor), GTK_RESPONSE_OK); +} + +GtkWidget * +ephy_new_bookmark_new (EphyBookmarks *bookmarks, + GtkWindow *parent, + const char *location) +{ + EphyNewBookmark *editor; + + g_assert (bookmarks != NULL); + + editor = EPHY_NEW_BOOKMARK (g_object_new + (EPHY_TYPE_NEW_BOOKMARK, + "bookmarks", bookmarks, + "location", location, + NULL)); + + if (parent) + { + gtk_window_set_transient_for (GTK_WINDOW (editor), parent); + } + + ephy_new_bookmark_construct (editor); + + return GTK_WIDGET (editor); +} + +static void +ephy_new_bookmark_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyNewBookmark *editor = EPHY_NEW_BOOKMARK (object); + + switch (prop_id) + { + case PROP_BOOKMARKS: + editor->priv->bookmarks = g_value_get_object (value); + break; + case PROP_LOCATION: + g_free (editor->priv->location); + editor->priv->location = g_strdup (g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ephy_new_bookmark_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyNewBookmark *editor = EPHY_NEW_BOOKMARK (object); + + switch (prop_id) + { + case PROP_LOCATION: + g_value_set_string (value, editor->priv->location); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ephy_new_bookmark_init (EphyNewBookmark *editor) +{ + editor->priv = g_new0 (EphyNewBookmarkPrivate, 1); + editor->priv->location = NULL; + editor->priv->smarturl = NULL; +} + +void +ephy_new_bookmark_set_title (EphyNewBookmark *bookmark, + const char *title) +{ + DEBUG_MSG (("Setting new bookmark title to: \"%s\"", title)); + gtk_entry_set_text (GTK_ENTRY (bookmark->priv->title_entry), + g_strdup (title)); +} + +void +ephy_new_bookmark_set_smarturl (EphyNewBookmark *bookmark, + const char *url) +{ + g_free (bookmark->priv->smarturl); + bookmark->priv->smarturl = g_strdup (url); +} + diff --git a/src/bookmarks/ephy-new-bookmark.h b/src/bookmarks/ephy-new-bookmark.h new file mode 100644 index 000000000..7e1091f50 --- /dev/null +++ b/src/bookmarks/ephy-new-bookmark.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef EPHY_NEW_BOOKMARK_H +#define EPHY_NEW_BOOKMARK_H + +#include <gtk/gtkdialog.h> + +#include "ephy-bookmarks.h" + +G_BEGIN_DECLS + +#define EPHY_TYPE_NEW_BOOKMARK (ephy_new_bookmark_get_type ()) +#define EPHY_NEW_BOOKMARK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_NEW_BOOKMARK, EphyNewBookmark)) +#define EPHY_NEW_BOOKMARK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_NEW_BOOKMARK, EphyNewBookmarkClass)) +#define EPHY_IS_NEW_BOOKMARK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_NEW_BOOKMARK)) +#define EPHY_IS_NEW_BOOKMARK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_NEW_BOOKMARK)) +#define EPHY_NEW_BOOKMARK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_NEW_BOOKMARK, EphyNewBookmarkClass)) + +typedef struct EphyNewBookmarkPrivate EphyNewBookmarkPrivate; + +typedef struct +{ + GtkDialog parent; + + EphyNewBookmarkPrivate *priv; +} EphyNewBookmark; + +typedef struct +{ + GtkDialogClass parent; +} EphyNewBookmarkClass; + +GType ephy_new_bookmark_get_type (void); + +GtkWidget *ephy_new_bookmark_new (EphyBookmarks *bookmarks, + GtkWindow *parent, + const char *location); + +void ephy_new_bookmark_set_title (EphyNewBookmark *bookmark, + const char *title); + +void ephy_new_bookmark_set_smarturl (EphyNewBookmark *bookmark, + const char *url); + +G_END_DECLS + +#endif /* EPHY_NEW_BOOKMARK_H */ diff --git a/src/bookmarks/ephy-node-view.c b/src/bookmarks/ephy-node-view.c new file mode 100644 index 000000000..f537855d8 --- /dev/null +++ b/src/bookmarks/ephy-node-view.c @@ -0,0 +1,531 @@ +/* + * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include <gtk/gtktreeview.h> +#include <gtk/gtktreeselection.h> +#include <gtk/gtktreeviewcolumn.h> +#include <gtk/gtkcellrenderertext.h> +#include <libgnome/gnome-i18n.h> + +#include "eggtreemodelfilter.h" +#include "ephy-tree-model-node.h" +#include "ephy-node-view.h" +#include "ephy-tree-model-sort.h" +#include "eggtreemultidnd.h" +#include "ephy-dnd.h" + +static void ephy_node_view_class_init (EphyNodeViewClass *klass); +static void ephy_node_view_init (EphyNodeView *view); +static void ephy_node_view_finalize (GObject *object); +static void ephy_node_view_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ephy_node_view_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +struct EphyNodeViewPrivate +{ + EphyNode *root; + + EphyTreeModelNode *nodemodel; + GtkTreeModel *filtermodel; + GtkTreeModel *sortmodel; + + EphyNodeFilter *filter; + + GtkWidget *treeview; +}; + +enum +{ + NODE_ACTIVATED, + NODE_SELECTED, + SHOW_POPUP, + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_ROOT, + PROP_FILTER +}; + +static GObjectClass *parent_class = NULL; + +static guint ephy_node_view_signals[LAST_SIGNAL] = { 0 }; + +GType +ephy_node_view_get_type (void) +{ + static GType ephy_node_view_type = 0; + + if (ephy_node_view_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyNodeViewClass), + NULL, + NULL, + (GClassInitFunc) ephy_node_view_class_init, + NULL, + NULL, + sizeof (EphyNodeView), + 0, + (GInstanceInitFunc) ephy_node_view_init + }; + + ephy_node_view_type = g_type_register_static (GTK_TYPE_SCROLLED_WINDOW, + "EphyNodeView", + &our_info, 0); + } + + return ephy_node_view_type; +} + +static void +ephy_node_view_class_init (EphyNodeViewClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_node_view_finalize; + + object_class->set_property = ephy_node_view_set_property; + object_class->get_property = ephy_node_view_get_property; + + g_object_class_install_property (object_class, + PROP_ROOT, + g_param_spec_object ("root", + "Root node", + "Root node", + EPHY_TYPE_NODE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, + PROP_FILTER, + g_param_spec_object ("filter", + "Filter object", + "Filter object", + EPHY_TYPE_NODE_FILTER, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + ephy_node_view_signals[NODE_ACTIVATED] = + g_signal_new ("node_activated", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyNodeViewClass, node_activated), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + EPHY_TYPE_NODE); + ephy_node_view_signals[NODE_SELECTED] = + g_signal_new ("node_selected", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyNodeViewClass, node_selected), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + EPHY_TYPE_NODE); + ephy_node_view_signals[SHOW_POPUP] = + g_signal_new ("show_popup", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyNodeViewClass, show_popup), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +static void +ephy_node_view_finalize (GObject *object) +{ + EphyNodeView *view; + + g_return_if_fail (object != NULL); + g_return_if_fail (EPHY_IS_NODE_VIEW (object)); + + view = EPHY_NODE_VIEW (object); + + g_return_if_fail (view->priv != NULL); + + g_object_unref (G_OBJECT (view->priv->sortmodel)); + g_object_unref (G_OBJECT (view->priv->filtermodel)); + g_object_unref (G_OBJECT (view->priv->nodemodel)); + + g_free (view->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +filter_changed_cb (EphyNodeFilter *filter, + EphyNodeView *view) +{ + GtkWidget *window; + + g_return_if_fail (EPHY_IS_NODE_VIEW (view)); + + window = gtk_widget_get_toplevel (GTK_WIDGET (view)); + + if (window != NULL && window->window != NULL) + { + /* nice busy cursor */ + GdkCursor *cursor; + + cursor = gdk_cursor_new (GDK_WATCH); + gdk_window_set_cursor (window->window, cursor); + gdk_cursor_unref (cursor); + + gdk_flush (); + + gdk_window_set_cursor (window->window, NULL); + + /* no flush: this will cause the cursor to be reset + * only when the UI is free again */ + } +} + +static void +ephy_node_view_selection_changed_cb (GtkTreeSelection *selection, + EphyNodeView *view) +{ + GList *list; + EphyNode *node = NULL; + + list = ephy_node_view_get_selection (view); + if (list) + { + node = EPHY_NODE (list->data); + } + g_list_free (list); + + g_signal_emit (G_OBJECT (view), ephy_node_view_signals[NODE_SELECTED], 0, node); +} + +static void +ephy_node_view_row_activated_cb (GtkTreeView *treeview, + GtkTreePath *path, + GtkTreeViewColumn *column, + EphyNodeView *view) +{ + GtkTreeIter iter, iter2; + EphyNode *node; + + gtk_tree_model_get_iter (view->priv->sortmodel, &iter, path); + gtk_tree_model_sort_convert_iter_to_child_iter + (GTK_TREE_MODEL_SORT (view->priv->sortmodel), &iter2, &iter); + egg_tree_model_filter_convert_iter_to_child_iter + (EGG_TREE_MODEL_FILTER (view->priv->filtermodel), &iter, &iter2); + + node = ephy_tree_model_node_node_from_iter (view->priv->nodemodel, &iter); + + g_signal_emit (G_OBJECT (view), ephy_node_view_signals[NODE_ACTIVATED], 0, node); +} + +static gboolean +ephy_node_view_button_press_cb (GtkTreeView *treeview, + GdkEventButton *event, + EphyNodeView *view) +{ + if (event->button == 3) + { + g_signal_emit (G_OBJECT (view), ephy_node_view_signals[SHOW_POPUP], 0); + } + + return FALSE; +} + +static void +ephy_node_view_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyNodeView *view = EPHY_NODE_VIEW (object); + + switch (prop_id) + { + case PROP_ROOT: + view->priv->root = g_value_get_object (value); + break; + case PROP_FILTER: + view->priv->filter = g_value_get_object (value); + + if (view->priv->filter != NULL) + { + g_signal_connect_object (G_OBJECT (view->priv->filter), + "changed", + G_CALLBACK (filter_changed_cb), + G_OBJECT (view), + 0); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ephy_node_view_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyNodeView *view = EPHY_NODE_VIEW (object); + + switch (prop_id) + { + case PROP_ROOT: + g_value_set_object (value, view->priv->root); + break; + case PROP_FILTER: + g_value_set_object (value, view->priv->filter); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +node_from_sort_iter_cb (EphyTreeModelSort *model, + GtkTreeIter *iter, + void **node, + EphyNodeView *view) +{ + GtkTreeIter filter_iter, node_iter; + + gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (model), + &filter_iter, iter); + egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (view->priv->filtermodel), + &node_iter, &filter_iter); + *node = ephy_tree_model_node_node_from_iter + (EPHY_TREE_MODEL_NODE (view->priv->nodemodel), &node_iter); +} + +static void +ephy_node_view_construct (EphyNodeView *view) +{ + GtkTreeSelection *selection; + + + view->priv->nodemodel = ephy_tree_model_node_new (view->priv->root, + view->priv->filter); + view->priv->filtermodel = egg_tree_model_filter_new (GTK_TREE_MODEL (view->priv->nodemodel), + NULL); + egg_tree_model_filter_set_visible_column (EGG_TREE_MODEL_FILTER (view->priv->filtermodel), + EPHY_TREE_MODEL_NODE_COL_VISIBLE); + view->priv->sortmodel = ephy_tree_model_sort_new (view->priv->filtermodel); + g_signal_connect_object (G_OBJECT (view->priv->sortmodel), + "node_from_iter", + G_CALLBACK (node_from_sort_iter_cb), + view, + 0); + view->priv->treeview = gtk_tree_view_new_with_model + (GTK_TREE_MODEL (view->priv->sortmodel)); + gtk_widget_show (view->priv->treeview); + g_signal_connect_object (G_OBJECT (view->priv->treeview), + "button_press_event", + G_CALLBACK (ephy_node_view_button_press_cb), + view, + 0); + g_signal_connect_object (G_OBJECT (view->priv->treeview), + "row_activated", + G_CALLBACK (ephy_node_view_row_activated_cb), + view, + 0); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); + g_signal_connect_object (G_OBJECT (selection), + "changed", + G_CALLBACK (ephy_node_view_selection_changed_cb), + view, + 0); + + gtk_container_add (GTK_CONTAINER (view), view->priv->treeview); +} + +EphyNodeView * +ephy_node_view_new (EphyNode *root, + EphyNodeFilter *filter) +{ + EphyNodeView *view; + + view = EPHY_NODE_VIEW (g_object_new (EPHY_TYPE_NODE_VIEW, + "filter", filter, + "hadjustment", NULL, + "vadjustment", NULL, + "hscrollbar_policy", GTK_POLICY_AUTOMATIC, + "vscrollbar_policy", GTK_POLICY_AUTOMATIC, + "shadow_type", GTK_SHADOW_IN, + "root", root, + NULL)); + + ephy_node_view_construct (view); + + g_return_val_if_fail (view->priv != NULL, NULL); + + return view; +} + +void +ephy_node_view_add_column (EphyNodeView *view, + const char *title, + EphyTreeModelNodeColumn column, + gboolean sortable) +{ + GtkTreeViewColumn *gcolumn; + GtkCellRenderer *renderer; + + gcolumn = (GtkTreeViewColumn *) gtk_tree_view_column_new (); + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (gcolumn, renderer, TRUE); + gtk_tree_view_column_set_attributes (gcolumn, renderer, + "text", column, + NULL); + gtk_tree_view_column_set_sizing (gcolumn, + GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_column_set_title (gcolumn, title); + gtk_tree_view_append_column (GTK_TREE_VIEW (view->priv->treeview), + gcolumn); + if (sortable) + { + gtk_tree_view_column_set_sort_column_id (gcolumn, column); + } +} + +static void +ephy_node_view_init (EphyNodeView *view) +{ + view->priv = g_new0 (EphyNodeViewPrivate, 1); +} + +static void +get_selection (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + void **data) +{ + GtkTreeModelSort *sortmodel = GTK_TREE_MODEL_SORT (model); + EggTreeModelFilter *filtermodel = EGG_TREE_MODEL_FILTER (sortmodel->child_model); + EphyTreeModelNode *nodemodel = EPHY_TREE_MODEL_NODE (filtermodel->child_model); + GList **list = (GList **) data; + GtkTreeIter *iter2 = gtk_tree_iter_copy (iter); + GtkTreeIter iter3; + GtkTreeIter iter4; + EphyNode *node; + + gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (model), + &iter3, iter2); + egg_tree_model_filter_convert_iter_to_child_iter (filtermodel, &iter4, &iter3); + + node = ephy_tree_model_node_node_from_iter (nodemodel, &iter4); + + gtk_tree_iter_free (iter2); + + *list = g_list_prepend (*list, node); +} + +GList * +ephy_node_view_get_selection (EphyNodeView *view) +{ + GList *list = NULL; + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection + (GTK_TREE_VIEW (view->priv->treeview)); + + gtk_tree_selection_selected_foreach (selection, + (GtkTreeSelectionForeachFunc) get_selection, + (void **) &list); + + return list; +} + +void +ephy_node_view_remove (EphyNodeView *view) +{ + GList *list; + + list = ephy_node_view_get_selection (view); + + for (; list != NULL; list = list->next) + { + ephy_node_unref (EPHY_NODE (list->data)); + } + + g_list_free (list); +} + +void +ephy_node_view_set_browse_mode (EphyNodeView *view) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); +} + +void +ephy_node_view_select_node (EphyNodeView *view, + EphyNode *node) +{ + GtkTreeIter iter, iter2; + GValue val = { 0, }; + gboolean visible; + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview)); + + g_return_if_fail (node != NULL); + + ephy_tree_model_node_iter_from_node (EPHY_TREE_MODEL_NODE (view->priv->nodemodel), + node, &iter); + gtk_tree_model_get_value (GTK_TREE_MODEL (view->priv->nodemodel), &iter, + EPHY_TREE_MODEL_NODE_COL_VISIBLE, &val); + visible = g_value_get_boolean (&val); + g_value_unset (&val); + if (visible == FALSE) return; + + egg_tree_model_filter_convert_child_iter_to_iter (EGG_TREE_MODEL_FILTER (view->priv->filtermodel), + &iter2, &iter); + gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (view->priv->sortmodel), + &iter, &iter2); + + gtk_tree_selection_select_iter (selection, &iter); +} + +void +ephy_node_view_enable_drag_source (EphyNodeView *view) +{ + g_return_if_fail (view != NULL); + + egg_tree_multi_drag_add_drag_support (GTK_TREE_VIEW (view->priv->treeview)); + ephy_dnd_enable_model_drag_source (GTK_WIDGET (view->priv->treeview)); +} diff --git a/src/bookmarks/ephy-node-view.h b/src/bookmarks/ephy-node-view.h new file mode 100644 index 000000000..71f19d7c7 --- /dev/null +++ b/src/bookmarks/ephy-node-view.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef __EPHY_NODE_VIEW_H +#define __EPHY_NODE_VIEW_H + +#include <gtk/gtkscrolledwindow.h> +#include <gtk/gtkdnd.h> + +#include "ephy-tree-model-node.h" +#include "ephy-node-filter.h" + +G_BEGIN_DECLS + +#define EPHY_TYPE_NODE_VIEW (ephy_node_view_get_type ()) +#define EPHY_NODE_VIEW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_NODE_VIEW, EphyNodeView)) +#define EPHY_NODE_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_NODE_VIEW, EphyNodeViewClass)) +#define EPHY_IS_NODE_VIEW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_NODE_VIEW)) +#define EPHY_IS_NODE_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_NODE_VIEW)) +#define EPHY_NODE_VIEW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_NODE_VIEW, EphyNodeViewClass)) + +typedef struct EphyNodeViewPrivate EphyNodeViewPrivate; + +typedef struct +{ + GtkScrolledWindow parent; + + EphyNodeViewPrivate *priv; +} EphyNodeView; + +typedef struct +{ + GtkScrolledWindowClass parent; + + void (*node_activated) (EphyNodeView *view, EphyNode *node); + void (*node_selected) (EphyNodeView *view, EphyNode *node); + void (*show_popup) (EphyNodeView *view); +} EphyNodeViewClass; + +GType ephy_node_view_get_type (void); + +EphyNodeView *ephy_node_view_new (EphyNode *root, + EphyNodeFilter *filter); + +void ephy_node_view_enable_dnd (EphyNodeView *view); + +void ephy_node_view_add_column (EphyNodeView *view, + const char *title, + EphyTreeModelNodeColumn column, + gboolean sortable); + +void ephy_node_view_remove (EphyNodeView *view); + +GList *ephy_node_view_get_selection (EphyNodeView *view); + +void ephy_node_view_set_browse_mode (EphyNodeView *view); + +void ephy_node_view_select_node (EphyNodeView *view, + EphyNode *node); + +void ephy_node_view_enable_drag_source (EphyNodeView *view); + +G_END_DECLS + +#endif /* EPHY_NODE_VIEW_H */ diff --git a/src/bookmarks/ephy-tree-model-node.c b/src/bookmarks/ephy-tree-model-node.c new file mode 100644 index 000000000..d1030d5da --- /dev/null +++ b/src/bookmarks/ephy-tree-model-node.c @@ -0,0 +1,702 @@ +/* + * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include <config.h> +#include <gtk/gtktreeview.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <libgnome/gnome-i18n.h> +#include <time.h> +#include <string.h> + +#include "ephy-node-filter.h" +#include "ephy-bookmarks.h" +#include "ephy-tree-model-node.h" +#include "ephy-stock-icons.h" +#include "ephy-node.h" + +static void ephy_tree_model_node_class_init (EphyTreeModelNodeClass *klass); +static void ephy_tree_model_node_init (EphyTreeModelNode *model); +static void ephy_tree_model_node_finalize (GObject *object); +static void ephy_tree_model_node_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ephy_tree_model_node_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static guint ephy_tree_model_node_get_flags (GtkTreeModel *tree_model); +static int ephy_tree_model_node_get_n_columns (GtkTreeModel *tree_model); +static GType ephy_tree_model_node_get_column_type (GtkTreeModel *tree_model, + int index); +static gboolean ephy_tree_model_node_get_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreePath *path); +static GtkTreePath *ephy_tree_model_node_get_path (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static void ephy_tree_model_node_get_value (GtkTreeModel *tree_model, + GtkTreeIter *iter, + int column, + GValue *value); +static gboolean ephy_tree_model_node_iter_next (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static gboolean ephy_tree_model_node_iter_children (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent); +static gboolean ephy_tree_model_node_iter_has_child (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static int ephy_tree_model_node_iter_n_children (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static gboolean ephy_tree_model_node_iter_nth_child (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent, + int n); +static gboolean ephy_tree_model_node_iter_parent (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *child); +static void ephy_tree_model_node_tree_model_init (GtkTreeModelIface *iface); +static void root_child_removed_cb (EphyNode *node, + EphyNode *child, + EphyTreeModelNode *model); +static void root_child_added_cb (EphyNode *node, + EphyNode *child, + EphyTreeModelNode *model); +static void root_child_changed_cb (EphyNode *node, + EphyNode *child, + EphyTreeModelNode *model); +static inline void ephy_tree_model_node_update_node (EphyTreeModelNode *model, + EphyNode *node, + int idx); +static void root_destroyed_cb (EphyNode *node, + EphyTreeModelNode *model); +static inline GtkTreePath *get_path_real (EphyTreeModelNode *model, + EphyNode *node); + +struct EphyTreeModelNodePrivate +{ + EphyNode *root; + + EphyNodeFilter *filter; +}; + +enum +{ + PROP_0, + PROP_ROOT, + PROP_FILTER +}; + +static GObjectClass *parent_class = NULL; + +GType +ephy_tree_model_node_get_type (void) +{ + static GType ephy_tree_model_node_type = 0; + + if (ephy_tree_model_node_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyTreeModelNodeClass), + NULL, + NULL, + (GClassInitFunc) ephy_tree_model_node_class_init, + NULL, + NULL, + sizeof (EphyTreeModelNode), + 0, + (GInstanceInitFunc) ephy_tree_model_node_init + }; + + static const GInterfaceInfo tree_model_info = + { + (GInterfaceInitFunc) ephy_tree_model_node_tree_model_init, + NULL, + NULL + }; + + ephy_tree_model_node_type = g_type_register_static (G_TYPE_OBJECT, + "EphyTreeModelNode", + &our_info, 0); + + g_type_add_interface_static (ephy_tree_model_node_type, + GTK_TYPE_TREE_MODEL, + &tree_model_info); + } + + return ephy_tree_model_node_type; +} + +static void +ephy_tree_model_node_class_init (EphyTreeModelNodeClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_tree_model_node_finalize; + + object_class->set_property = ephy_tree_model_node_set_property; + object_class->get_property = ephy_tree_model_node_get_property; + + g_object_class_install_property (object_class, + PROP_ROOT, + g_param_spec_object ("root", + "Root node", + "Root node", + EPHY_TYPE_NODE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, + PROP_FILTER, + g_param_spec_object ("filter", + "Filter object", + "Filter object", + EPHY_TYPE_NODE_FILTER, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +} + +static void +ephy_tree_model_node_init (EphyTreeModelNode *model) +{ + GtkWidget *dummy; + + do + { + model->stamp = g_random_int (); + } + while (model->stamp == 0); + + model->priv = g_new0 (EphyTreeModelNodePrivate, 1); + + dummy = gtk_tree_view_new (); + + gtk_widget_destroy (dummy); +} + +static void +ephy_tree_model_node_finalize (GObject *object) +{ + EphyTreeModelNode *model; + + g_return_if_fail (object != NULL); + g_return_if_fail (EPHY_IS_TREE_MODEL_NODE (object)); + + model = EPHY_TREE_MODEL_NODE (object); + + g_return_if_fail (model->priv != NULL); + + g_free (model->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +filter_changed_cb (EphyNodeFilter *filter, + EphyTreeModelNode *model) +{ + GPtrArray *kids; + int i; + + kids = ephy_node_get_children (model->priv->root); + + for (i = 0; i < kids->len; i++) + { + ephy_tree_model_node_update_node (model, + g_ptr_array_index (kids, i), + i); + } + + ephy_node_thaw (model->priv->root); +} + +static void +ephy_tree_model_node_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (object); + + switch (prop_id) + { + case PROP_ROOT: + model->priv->root = g_value_get_object (value); + + g_signal_connect_object (G_OBJECT (model->priv->root), + "child_added", + G_CALLBACK (root_child_added_cb), + G_OBJECT (model), + 0); + g_signal_connect_object (G_OBJECT (model->priv->root), + "child_removed", + G_CALLBACK (root_child_removed_cb), + G_OBJECT (model), + 0); + g_signal_connect_object (G_OBJECT (model->priv->root), + "child_changed", + G_CALLBACK (root_child_changed_cb), + G_OBJECT (model), + 0); + g_signal_connect_object (G_OBJECT (model->priv->root), + "destroyed", + G_CALLBACK (root_destroyed_cb), + G_OBJECT (model), + 0); + + break; + case PROP_FILTER: + model->priv->filter = g_value_get_object (value); + + if (model->priv->filter != NULL) + { + g_signal_connect_object (G_OBJECT (model->priv->filter), + "changed", + G_CALLBACK (filter_changed_cb), + G_OBJECT (model), + 0); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ephy_tree_model_node_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (object); + + switch (prop_id) + { + case PROP_ROOT: + g_value_set_object (value, model->priv->root); + break; + case PROP_FILTER: + g_value_set_object (value, model->priv->filter); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +EphyTreeModelNode * +ephy_tree_model_node_new (EphyNode *root, + EphyNodeFilter *filter) +{ + EphyTreeModelNode *model; + + model = EPHY_TREE_MODEL_NODE (g_object_new (EPHY_TYPE_TREE_MODEL_NODE, + "filter", filter, + "root", root, + NULL)); + + g_return_val_if_fail (model->priv != NULL, NULL); + + return model; +} + +static void +ephy_tree_model_node_tree_model_init (GtkTreeModelIface *iface) +{ + iface->get_flags = ephy_tree_model_node_get_flags; + iface->get_n_columns = ephy_tree_model_node_get_n_columns; + iface->get_column_type = ephy_tree_model_node_get_column_type; + iface->get_iter = ephy_tree_model_node_get_iter; + iface->get_path = ephy_tree_model_node_get_path; + iface->get_value = ephy_tree_model_node_get_value; + iface->iter_next = ephy_tree_model_node_iter_next; + iface->iter_children = ephy_tree_model_node_iter_children; + iface->iter_has_child = ephy_tree_model_node_iter_has_child; + iface->iter_n_children = ephy_tree_model_node_iter_n_children; + iface->iter_nth_child = ephy_tree_model_node_iter_nth_child; + iface->iter_parent = ephy_tree_model_node_iter_parent; +} + +static guint +ephy_tree_model_node_get_flags (GtkTreeModel *tree_model) +{ + return 0; +} + +static int +ephy_tree_model_node_get_n_columns (GtkTreeModel *tree_model) +{ + return EPHY_TREE_MODEL_NODE_NUM_COLUMNS; +} + +static GType +ephy_tree_model_node_get_column_type (GtkTreeModel *tree_model, + int index) +{ + g_return_val_if_fail (EPHY_IS_TREE_MODEL_NODE (tree_model), G_TYPE_INVALID); + g_return_val_if_fail ((index < EPHY_TREE_MODEL_NODE_NUM_COLUMNS) && (index >= 0), G_TYPE_INVALID); + + switch (index) + { + case EPHY_TREE_MODEL_NODE_COL_BOOKMARK: + case EPHY_TREE_MODEL_NODE_COL_LOCATION: + case EPHY_TREE_MODEL_NODE_COL_KEYWORD: + return G_TYPE_STRING; + case EPHY_TREE_MODEL_NODE_COL_VISIBLE: + return G_TYPE_BOOLEAN; + default: + g_assert_not_reached (); + return G_TYPE_INVALID; + } +} + +static gboolean +ephy_tree_model_node_get_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreePath *path) +{ + EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model); + int i; + + g_return_val_if_fail (EPHY_IS_TREE_MODEL_NODE (model), FALSE); + g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE); + + if (model->priv->root == NULL) + return FALSE; + + i = gtk_tree_path_get_indices (path)[0]; + + iter->stamp = model->stamp; + iter->user_data = ephy_node_get_nth_child (model->priv->root, i); + + if (iter->user_data == NULL) + { + iter->stamp = 0; + return FALSE; + } + + return TRUE; +} + +static inline GtkTreePath * +get_path_real (EphyTreeModelNode *model, + EphyNode *node) +{ + GtkTreePath *retval; + + retval = gtk_tree_path_new (); + gtk_tree_path_append_index (retval, ephy_node_get_child_index (model->priv->root, node)); + + return retval; +} + +static GtkTreePath * +ephy_tree_model_node_get_path (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model); + EphyNode *node; + + g_return_val_if_fail (EPHY_IS_TREE_MODEL_NODE (tree_model), NULL); + g_return_val_if_fail (iter != NULL, NULL); + g_return_val_if_fail (iter->user_data != NULL, NULL); + g_return_val_if_fail (iter->stamp == model->stamp, NULL); + + if (model->priv->root == NULL) + return NULL; + + node = EPHY_NODE (iter->user_data); + + if (node == model->priv->root) + return gtk_tree_path_new (); + + return get_path_real (model, node); +} + +static void +ephy_tree_model_node_get_value (GtkTreeModel *tree_model, + GtkTreeIter *iter, + int column, + GValue *value) +{ + EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model); + EphyNode *node; + + g_return_if_fail (EPHY_IS_TREE_MODEL_NODE (tree_model)); + g_return_if_fail (iter != NULL); + g_return_if_fail (iter->stamp == model->stamp); + g_return_if_fail (EPHY_IS_NODE (iter->user_data)); + g_return_if_fail (column < EPHY_TREE_MODEL_NODE_NUM_COLUMNS); + + if (model->priv->root == NULL) + return; + + node = EPHY_NODE (iter->user_data); + + switch (column) + { + case EPHY_TREE_MODEL_NODE_COL_BOOKMARK: + ephy_node_get_property (node, + EPHY_NODE_BMK_PROP_TITLE, + value); + break; + case EPHY_TREE_MODEL_NODE_COL_LOCATION: + ephy_node_get_property (node, + EPHY_NODE_BMK_PROP_LOCATION, + value); + break; + case EPHY_TREE_MODEL_NODE_COL_KEYWORD: + ephy_node_get_property (node, + EPHY_NODE_KEYWORD_PROP_NAME, + value); + break; + case EPHY_TREE_MODEL_NODE_COL_VISIBLE: + g_value_init (value, G_TYPE_BOOLEAN); + + if (model->priv->filter != NULL) + { + g_value_set_boolean (value, + ephy_node_filter_evaluate (model->priv->filter, node)); + } + else + { + g_value_set_boolean (value, TRUE); + } + break; + default: + g_assert_not_reached (); + break; + } +} + +static gboolean +ephy_tree_model_node_iter_next (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model); + EphyNode *node; + + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (iter->user_data != NULL, FALSE); + g_return_val_if_fail (iter->stamp == EPHY_TREE_MODEL_NODE (tree_model)->stamp, FALSE); + + if (model->priv->root == NULL) + return FALSE; + + node = EPHY_NODE (iter->user_data); + + if (node == model->priv->root) + return FALSE; + + iter->user_data = ephy_node_get_next_child (model->priv->root, node); + + return (iter->user_data != NULL); +} + +static gboolean +ephy_tree_model_node_iter_children (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent) +{ + EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model); + + if (model->priv->root == NULL) + return FALSE; + + if (parent != NULL) + return FALSE; + + iter->stamp = model->stamp; + iter->user_data = model->priv->root; + + return TRUE; +} + +static gboolean +ephy_tree_model_node_iter_has_child (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + return FALSE; +} + +static int +ephy_tree_model_node_iter_n_children (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model); + + g_return_val_if_fail (EPHY_IS_TREE_MODEL_NODE (tree_model), -1); + + if (model->priv->root == NULL) + return 0; + + if (iter == NULL) + return ephy_node_get_n_children (model->priv->root); + + g_return_val_if_fail (model->stamp == iter->stamp, -1); + + return 0; +} + +static gboolean +ephy_tree_model_node_iter_nth_child (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent, + int n) +{ + EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model); + EphyNode *node; + + g_return_val_if_fail (EPHY_IS_TREE_MODEL_NODE (tree_model), FALSE); + + if (model->priv->root == NULL) + return FALSE; + + if (parent != NULL) + return FALSE; + + node = ephy_node_get_nth_child (model->priv->root, n); + + if (node != NULL) + { + iter->stamp = model->stamp; + iter->user_data = node; + return TRUE; + } + else + return FALSE; +} + +static gboolean +ephy_tree_model_node_iter_parent (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *child) +{ + return FALSE; +} + +EphyNode * +ephy_tree_model_node_node_from_iter (EphyTreeModelNode *model, + GtkTreeIter *iter) +{ + return EPHY_NODE (iter->user_data); +} + +void +ephy_tree_model_node_iter_from_node (EphyTreeModelNode *model, + EphyNode *node, + GtkTreeIter *iter) +{ + iter->stamp = model->stamp; + iter->user_data = node; +} + +static void +root_child_removed_cb (EphyNode *node, + EphyNode *child, + EphyTreeModelNode *model) +{ + GtkTreePath *path; + + path = get_path_real (model, child); + gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path); + gtk_tree_path_free (path); +} + +static void +root_child_added_cb (EphyNode *node, + EphyNode *child, + EphyTreeModelNode *model) +{ + GtkTreePath *path; + GtkTreeIter iter; + + ephy_tree_model_node_iter_from_node (model, child, &iter); + + path = get_path_real (model, child); + gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter); + gtk_tree_path_free (path); +} + +static inline void +ephy_tree_model_node_update_node (EphyTreeModelNode *model, + EphyNode *node, + int idx) +{ + GtkTreePath *path; + GtkTreeIter iter; + + ephy_tree_model_node_iter_from_node (model, node, &iter); + + if (idx >= 0) + { + path = gtk_tree_path_new (); + gtk_tree_path_append_index (path, idx); + } + else + { + path = get_path_real (model, node); + } + + gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter); + gtk_tree_path_free (path); +} + +static void +root_child_changed_cb (EphyNode *node, + EphyNode *child, + EphyTreeModelNode *model) +{ + ephy_tree_model_node_update_node (model, child, -1); +} + +static void +root_destroyed_cb (EphyNode *node, + EphyTreeModelNode *model) +{ + model->priv->root = NULL; + + /* no need to do other stuff since we should have had a bunch of child_removed + * signals already */ +} + +GType +ephy_tree_model_node_column_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) + { + static const GEnumValue values[] = + { + { EPHY_TREE_MODEL_NODE_COL_BOOKMARK, "EPHY_TREE_MODEL_NODE_COL_BOOKMARK", "bookmark" }, + { EPHY_TREE_MODEL_NODE_COL_LOCATION, "EPHY_TREE_MODEL_NODE_COL_LOCATION", "location" }, + { EPHY_TREE_MODEL_NODE_COL_KEYWORD, "EPHY_TREE_MODEL_NODE_COL_KEYWORD", "keyword" }, + { EPHY_TREE_MODEL_NODE_COL_VISIBLE, "EPHY_TREE_MODEL_NODE_COL_VISIBLE", "visible" }, + + { 0, 0, 0 } + }; + + etype = g_enum_register_static ("EphyTreeModelNodeColumn", values); + } + + return etype; +} + diff --git a/src/bookmarks/ephy-tree-model-node.h b/src/bookmarks/ephy-tree-model-node.h new file mode 100644 index 000000000..a48bc6ad5 --- /dev/null +++ b/src/bookmarks/ephy-tree-model-node.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef __EPHY_TREE_MODEL_NODE_H +#define __EPHY_TREE_MODEL_NODE_H + +#include <gtk/gtktreemodel.h> + +#include "ephy-node.h" +#include "ephy-node-filter.h" + +G_BEGIN_DECLS + +#define EPHY_TYPE_TREE_MODEL_NODE (ephy_tree_model_node_get_type ()) +#define EPHY_TREE_MODEL_NODE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_TREE_MODEL_NODE, EphyTreeModelNode)) +#define EPHY_TREE_MODEL_NODE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_TREE_MODEL_NODE, EphyTreeModelNodeClass)) +#define EPHY_IS_TREE_MODEL_NODE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_TREE_MODEL_NODE)) +#define EPHY_IS_TREE_MODEL_NODE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_TREE_MODEL_NODE)) +#define EPHY_TREE_MODEL_NODE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_TREE_MODEL_NODE, EphyTreeModelNodeClass)) + +typedef enum +{ + EPHY_TREE_MODEL_NODE_COL_BOOKMARK, + EPHY_TREE_MODEL_NODE_COL_LOCATION, + EPHY_TREE_MODEL_NODE_COL_KEYWORD, + EPHY_TREE_MODEL_NODE_COL_VISIBLE, + EPHY_TREE_MODEL_NODE_NUM_COLUMNS +} EphyTreeModelNodeColumn; + +GType ephy_tree_model_node_column_get_type (void); + +#define EPHY_TYPE_TREE_MODEL_NODE_COLUMN (ephy_tree_model_node_column_get_type ()) + +typedef struct EphyTreeModelNodePrivate EphyTreeModelNodePrivate; + +typedef struct +{ + GObject parent; + + EphyTreeModelNodePrivate *priv; + + int stamp; +} EphyTreeModelNode; + +typedef struct +{ + GObjectClass parent; +} EphyTreeModelNodeClass; + +GType ephy_tree_model_node_get_type (void); + +EphyTreeModelNode *ephy_tree_model_node_new (EphyNode *root, + EphyNodeFilter *filter); + +EphyNode *ephy_tree_model_node_node_from_iter (EphyTreeModelNode *model, + GtkTreeIter *iter); + +void ephy_tree_model_node_iter_from_node (EphyTreeModelNode *model, + EphyNode *node, + GtkTreeIter *iter); + +G_END_DECLS + +#endif /* EPHY_TREE_MODEL_NODE_H */ diff --git a/src/ephy-automation.c b/src/ephy-automation.c new file mode 100644 index 000000000..d7757fe75 --- /dev/null +++ b/src/ephy-automation.c @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-automation.h" +#include "ephy-shell.h" +#include "EphyAutomation.h" +#include "ephy-embed.h" +#include "ephy-window.h" + +#include <string.h> +#include <bonobo/bonobo-generic-factory.h> +#include <bonobo/bonobo-main.h> +#include <bonobo/bonobo-context.h> + +static CORBA_boolean +impl_ephy_automation_add_bookmark (PortableServer_Servant _servant, + const CORBA_char * url, + CORBA_Environment * ev); +static CORBA_boolean +impl_ephy_automation_quit (PortableServer_Servant _servant, + const CORBA_boolean disableServer, + CORBA_Environment * ev); +static CORBA_boolean +impl_ephy_automation_load_session (PortableServer_Servant _servant, + const CORBA_char * filename, + CORBA_Environment * ev); +static void +ephy_automation_class_init (EphyAutomationClass *klass); +static void +ephy_automation_init (EphyAutomation *a); +static void +ephy_automation_object_finalize (GObject *object); +static BonoboObject * +ephy_automation_factory (BonoboGenericFactory *this_factory, + const char *iid, + gpointer user_data); + +static GObjectClass *ephy_automation_parent_class; + +#define EPHY_FACTORY_OAFIID "OAFIID:GNOME_Epiphany_Automation_Factory" + +static BonoboObject * +ephy_automation_factory (BonoboGenericFactory *this_factory, + const char *iid, + gpointer user_data) +{ + EphyAutomation *a; + + a = g_object_new (EPHY_AUTOMATION_TYPE, NULL); + + return BONOBO_OBJECT(a); +} + +BonoboObject * +ephy_automation_new (void) +{ + BonoboGenericFactory *factory; + + factory = bonobo_generic_factory_new (EPHY_FACTORY_OAFIID, + ephy_automation_factory, + NULL); + + g_return_val_if_fail (factory != NULL, NULL); + + return BONOBO_OBJECT (factory); +} + +static CORBA_boolean +impl_ephy_automation_loadurl (PortableServer_Servant _servant, + const CORBA_char * url, + const CORBA_char * geometry, + const CORBA_boolean fullscreen, + const CORBA_boolean open_in_existing_tab, + const CORBA_boolean open_in_new_window, + const CORBA_boolean open_in_new_tab, + const CORBA_boolean raise, + CORBA_Environment * ev) +{ + EphyNewTabFlags flags = 0; + const char *load_page = NULL; + EphyWindow *window; + Session *session; + + session = ephy_shell_get_session (ephy_shell); + + /* no window open, let's try to autoresume */ + if (session_get_windows (session) == NULL) + { + gboolean res; + res = session_autoresume (session); + /* no need to open the homepage, + * we did already open session windows */ + if (res && *url == '\0') return TRUE; + } + + window = ephy_shell_get_active_window (ephy_shell); + + if (open_in_existing_tab && window != NULL) + { + ephy_window_load_url (window, url); + return TRUE; + } + + if (*url == '\0') + { + flags = EPHY_NEW_TAB_HOMEPAGE; + } + else + { + load_page = url; + } + + if (open_in_new_window) + { + flags |= EPHY_NEW_TAB_IN_NEW_WINDOW; + } + + if (open_in_new_tab) + { + flags |= EPHY_NEW_TAB_IN_EXISTING_WINDOW; + } + + ephy_shell_new_tab (ephy_shell, window, NULL, load_page, + flags); + + return TRUE; +} + +static CORBA_boolean +impl_ephy_automation_add_bookmark (PortableServer_Servant _servant, + const CORBA_char * url, + CORBA_Environment * ev) +{ + CORBA_boolean retval = TRUE; + return retval; +} + +static CORBA_boolean +impl_ephy_automation_quit (PortableServer_Servant _servant, + const CORBA_boolean disableServer, + CORBA_Environment * ev) +{ + CORBA_boolean retval = TRUE; + + Session *session; + + session = ephy_shell_get_session (ephy_shell); + + session_close (session); + + return retval; +} + +static CORBA_boolean +impl_ephy_automation_load_session (PortableServer_Servant _servant, + const CORBA_char * filename, + CORBA_Environment * ev) +{ + CORBA_boolean retval = TRUE; + Session *session; + + session = ephy_shell_get_session (ephy_shell); + session_load (session, filename); + + return retval; +} + +static void +ephy_automation_class_init (EphyAutomationClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + POA_GNOME_EphyAutomation__epv *epv = &klass->epv; + + ephy_automation_parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_automation_object_finalize; + + /* connect implementation callbacks */ + epv->loadurl = impl_ephy_automation_loadurl; + epv->addBookmark = impl_ephy_automation_add_bookmark; + epv->quit = impl_ephy_automation_quit; + epv->loadSession = impl_ephy_automation_load_session; +} + +static void +ephy_automation_init (EphyAutomation *c) +{ +} + +static void +ephy_automation_object_finalize (GObject *object) +{ + EphyAutomation *a = EPHY_AUTOMATION (object); + + ephy_automation_parent_class->finalize (G_OBJECT (a)); +} + +BONOBO_TYPE_FUNC_FULL ( + EphyAutomation, + GNOME_EphyAutomation, + BONOBO_TYPE_OBJECT, + ephy_automation); diff --git a/src/ephy-automation.h b/src/ephy-automation.h new file mode 100644 index 000000000..4b3701605 --- /dev/null +++ b/src/ephy-automation.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _EPHY_AUTOMATION_H_ +#define _EPHY_AUTOMATION_H_ + +#include "EphyAutomation.h" + +#include <bonobo/bonobo-control.h> +#include <bonobo/bonobo-object.h> + +G_BEGIN_DECLS + +#define EPHY_AUTOMATION_TYPE (ephy_automation_get_type ()) +#define EPHY_AUTOMATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_AUTOMATION_TYPE, EphyAutomation)) +#define EPHY_AUTOMATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_AUTOMATION_TYPE, EphyAutomationClass)) +#define EPHY_AUTOMATION_IS_OBJECT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_AUTOMATION_TYPE)) +#define EPHY_AUTOMATION_IS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_AUTOMATION_TYPE)) +#define EPHY_AUTOMATION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_AUTOMATION_TYPE, EphyAutomationClass)) + +typedef struct { + BonoboObject parent; +} EphyAutomation; + +typedef struct { + BonoboObjectClass parent_class; + + POA_GNOME_EphyAutomation__epv epv; +} EphyAutomationClass; + +GType ephy_automation_get_type (void); + +BonoboObject *ephy_automation_new (void); + +G_END_DECLS + +#endif /* _EPHY_AUTOMATION_H_ */ diff --git a/src/ephy-favorites-menu.c b/src/ephy-favorites-menu.c new file mode 100644 index 000000000..d8f44f852 --- /dev/null +++ b/src/ephy-favorites-menu.c @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ephy-favorites-menu.h" +#include "ephy-gobject-misc.h" +#include "ephy-string.h" +#include "ephy-bonobo-extensions.h" +#include "ephy-marshal.h" +#include "ephy-shell.h" + +#include <string.h> +#include <stdlib.h> +#include <libxml/entities.h> + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +#define MAX_LABEL_LENGTH 30 + +/** + * Private data + */ +struct _EphyFavoritesMenuPrivate +{ + gchar *path; + EphyWindow *window; + EphyBookmarks *bookmarks; +}; + +typedef struct +{ + EphyWindow *window; + const char *url; +} FavoriteData; + +/** + * Private functions, only availble from this file + */ +static void ephy_favorites_menu_class_init (EphyFavoritesMenuClass *klass); +static void ephy_favorites_menu_init (EphyFavoritesMenu *wrhm); +static void ephy_favorites_menu_finalize_impl (GObject *o); +static void ephy_favorites_menu_rebuild (EphyFavoritesMenu *wrhm); +static void ephy_favorites_menu_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ephy_favorites_menu_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +enum +{ + PROP_0, + PROP_EPHY_WINDOW +}; + +static gpointer g_object_class; + +/** + * EphyFavoritesMenu object + */ +MAKE_GET_TYPE (ephy_favorites_menu, + "EphyFavoritesMenu", EphyFavoritesMenu, + ephy_favorites_menu_class_init, ephy_favorites_menu_init, + G_TYPE_OBJECT); + +static void +ephy_favorites_menu_class_init (EphyFavoritesMenuClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + G_OBJECT_CLASS (klass)->finalize = ephy_favorites_menu_finalize_impl; + g_object_class = g_type_class_peek_parent (klass); + + object_class->set_property = ephy_favorites_menu_set_property; + object_class->get_property = ephy_favorites_menu_get_property; + + g_object_class_install_property (object_class, + PROP_EPHY_WINDOW, + g_param_spec_object ("EphyWindow", + "EphyWindow", + "Parent window", + EPHY_WINDOW_TYPE, + G_PARAM_READWRITE)); +} + +static void +ephy_favorites_menu_init (EphyFavoritesMenu *wrhm) +{ + EphyFavoritesMenuPrivate *p = g_new0 (EphyFavoritesMenuPrivate, 1); + wrhm->priv = p; + + wrhm->priv->bookmarks = ephy_shell_get_bookmarks (ephy_shell); +} + +static void +ephy_favorites_menu_finalize_impl (GObject *o) +{ + EphyFavoritesMenu *wrhm = EPHY_FAVORITES_MENU (o); + EphyFavoritesMenuPrivate *p = wrhm->priv; + + if (p->path) + { + g_free (p->path); + } + + g_free (p); + + G_OBJECT_CLASS (g_object_class)->finalize (o); +} + +static void +ephy_favorites_menu_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyFavoritesMenu *m = EPHY_FAVORITES_MENU (object); + + switch (prop_id) + { + case PROP_EPHY_WINDOW: + m->priv->window = g_value_get_object (value); + break; + } +} + +static void +ephy_favorites_menu_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyFavoritesMenu *m = EPHY_FAVORITES_MENU (object); + + switch (prop_id) + { + case PROP_EPHY_WINDOW: + g_value_set_object (value, m->priv->window); + break; + } +} + +EphyFavoritesMenu * +ephy_favorites_menu_new (EphyWindow *window) +{ + EphyFavoritesMenu *ret = g_object_new (EPHY_TYPE_FAVORITES_MENU, + "EphyWindow", window, + NULL); + return ret; +} + +void +ephy_favorites_menu_set_path (EphyFavoritesMenu *wrhm, + const gchar *path) +{ + EphyFavoritesMenuPrivate *p; + + g_return_if_fail (EPHY_IS_FAVORITES_MENU (wrhm)); + g_return_if_fail (path != NULL); + + p = wrhm->priv; + + if (p->path) + { + g_free (p->path); + } + p->path = g_strdup (path); + + ephy_favorites_menu_update (wrhm); +} + +static void +ephy_favorites_menu_verb_cb (BonoboUIComponent *uic, + FavoriteData *data, + const char *cname) +{ + ephy_window_load_url (data->window, data->url); +} + +static void +ephy_favorites_menu_rebuild (EphyFavoritesMenu *wrhm) +{ + EphyFavoritesMenuPrivate *p = wrhm->priv; + GString *xml; + gint i; + EphyNode *fav; + GPtrArray *children; + BonoboUIComponent *uic = BONOBO_UI_COMPONENT (p->window->ui_component); + + if (!p->path) return; + + ephy_bonobo_clear_path (uic, p->path); + + DEBUG_MSG (("Rebuilding recent history menu\n")); + + fav = ephy_bookmarks_get_favorites (p->bookmarks); + children = ephy_node_get_children (fav); + + xml = g_string_new (NULL); + g_string_append_printf (xml, "<placeholder name=\"wrhm%x\">\n", (guint) wrhm); + + for (i = 0; i < children->len; i++) + { + char *verb = g_strdup_printf ("Wrhm%xn%d", (guint) wrhm, i); + char *title_s; + const char *title; + const char *url; + xmlChar *label_x; + EphyNode *child; + FavoriteData *data; + + child = g_ptr_array_index (children, i); + title = ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_TITLE); + url = ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_LOCATION); + title_s = ephy_string_shorten (title, MAX_LABEL_LENGTH); + label_x = xmlEncodeSpecialChars (NULL, title_s); + + g_string_append (xml, "<menuitem name=\""); + g_string_append (xml, verb); + g_string_append (xml, "\" label=\""); + g_string_append (xml, label_x); + g_string_append (xml, "\" verb=\""); + g_string_append (xml, verb); + g_string_append (xml, "\"/>\n"); + + data = g_new0 (FavoriteData, 1); + data->window = wrhm->priv->window; + data->url = url; + bonobo_ui_component_add_verb_full (uic, verb, g_cclosure_new + (G_CALLBACK (ephy_favorites_menu_verb_cb), data, + (GClosureNotify)g_free)); + + xmlFree (label_x); + g_free (title_s); + g_free (verb); + } + + ephy_node_thaw (fav); + + g_string_append (xml, "</placeholder>\n"); + DEBUG_MSG (("\n%s\n", xml->str)); + if (children->len > 0) + { + bonobo_ui_component_set (uic, p->path, + xml->str, NULL); + } + g_string_free (xml, TRUE); +} + +void ephy_favorites_menu_update (EphyFavoritesMenu *wrhm) +{ + ephy_favorites_menu_rebuild (wrhm); +} diff --git a/src/ephy-favorites-menu.h b/src/ephy-favorites-menu.h new file mode 100644 index 000000000..b76e8d2d8 --- /dev/null +++ b/src/ephy-favorites-menu.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_FAVORITES_MENU_H +#define EPHY_FAVORITES_MENU_H + +#include "ephy-window.h" + +#include <bonobo/bonobo-ui-component.h> + +/* object forward declarations */ + +typedef struct _EphyFavoritesMenu EphyFavoritesMenu; +typedef struct _EphyFavoritesMenuClass EphyFavoritesMenuClass; +typedef struct _EphyFavoritesMenuPrivate EphyFavoritesMenuPrivate; + +/** + * Editor object + */ + +#define EPHY_TYPE_FAVORITES_MENU (ephy_favorites_menu_get_type()) +#define EPHY_FAVORITES_MENU(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_FAVORITES_MENU, EphyFavoritesMenu)) +#define EPHY_FAVORITES_MENU_CLASS(klass)(G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_FAVORITES_MENU, EphyFavoritesMenuClass)) +#define EPHY_IS_FAVORITES_MENU(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_FAVORITES_MENU)) +#define EPHY_IS_FAVORITES_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_FAVORITES_MENU)) +#define EPHY_FAVORITES_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_FAVORITES_MENU, EphyFavoritesMenuClass)) + +struct _EphyFavoritesMenuClass +{ + GObjectClass parent_class; +}; + +/* Remember: fields are public read-only */ +struct _EphyFavoritesMenu +{ + GObject parent_object; + + EphyFavoritesMenuPrivate *priv; +}; + +GType ephy_favorites_menu_get_type (void); + +EphyFavoritesMenu *ephy_favorites_menu_new (EphyWindow *window); + +void ephy_favorites_menu_update (EphyFavoritesMenu *wrhm); + +void ephy_favorites_menu_set_path (EphyFavoritesMenu *wrhm, + const gchar *path); + +#endif + diff --git a/src/ephy-history-model.c b/src/ephy-history-model.c new file mode 100644 index 000000000..c4e694bcd --- /dev/null +++ b/src/ephy-history-model.c @@ -0,0 +1,838 @@ +/* + * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include <config.h> +#include <gtk/gtktreeview.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <libgnome/gnome-i18n.h> +#include <time.h> +#include <string.h> + +#include "ephy-node-filter.h" +#include "ephy-history-model.h" +#include "ephy-history.h" +#include "ephy-tree-model-node.h" +#include "ephy-stock-icons.h" +#include "ephy-node.h" + +static void ephy_history_model_class_init (EphyHistoryModelClass *klass); +static void ephy_history_model_init (EphyHistoryModel *model); +static void ephy_history_model_finalize (GObject *object); +static void ephy_history_model_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ephy_history_model_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static guint ephy_history_model_get_flags (GtkTreeModel *tree_model); +static int ephy_history_model_get_n_columns (GtkTreeModel *tree_model); +static GType ephy_history_model_get_column_type (GtkTreeModel *tree_model, + int index); +static gboolean ephy_history_model_get_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreePath *path); +static GtkTreePath *ephy_history_model_get_path (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static void ephy_history_model_get_value (GtkTreeModel *tree_model, + GtkTreeIter *iter, + int column, + GValue *value); +static gboolean ephy_history_model_iter_next (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static gboolean ephy_history_model_iter_children (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent); +static gboolean ephy_history_model_iter_has_child (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static int ephy_history_model_iter_n_children (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static gboolean ephy_history_model_iter_nth_child (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent, + int n); +static gboolean ephy_history_model_iter_parent (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *child); +static void ephy_history_model_tree_model_init (GtkTreeModelIface *iface); +static void root_child_removed_cb (EphyNode *node, + EphyNode *child, + EphyHistoryModel *model); +static void root_child_added_cb (EphyNode *node, + EphyNode *child, + EphyHistoryModel *model); +static void root_child_changed_cb (EphyNode *node, + EphyNode *child, + EphyHistoryModel *model); +static inline void ephy_history_model_update_node (EphyHistoryModel *model, + EphyNode *node, + int idx); + +struct EphyHistoryModelPrivate +{ + EphyNode *root; + EphyNode *pages; + + EphyNodeFilter *filter; +}; + +enum +{ + PROP_0, + PROP_ROOT, + PROP_PAGES, + PROP_FILTER +}; + +static GObjectClass *parent_class = NULL; + +GType +ephy_history_model_get_type (void) +{ + static GType ephy_history_model_type = 0; + + if (ephy_history_model_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyHistoryModelClass), + NULL, + NULL, + (GClassInitFunc) ephy_history_model_class_init, + NULL, + NULL, + sizeof (EphyHistoryModel), + 0, + (GInstanceInitFunc) ephy_history_model_init + }; + + static const GInterfaceInfo tree_model_info = + { + (GInterfaceInitFunc) ephy_history_model_tree_model_init, + NULL, + NULL + }; + + ephy_history_model_type = g_type_register_static (G_TYPE_OBJECT, + "EphyHistoryModel", + &our_info, 0); + + g_type_add_interface_static (ephy_history_model_type, + GTK_TYPE_TREE_MODEL, + &tree_model_info); + } + + return ephy_history_model_type; +} + +static void +ephy_history_model_class_init (EphyHistoryModelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_history_model_finalize; + + object_class->set_property = ephy_history_model_set_property; + object_class->get_property = ephy_history_model_get_property; + + g_object_class_install_property (object_class, + PROP_ROOT, + g_param_spec_object ("root", + "Root node", + "Root node", + EPHY_TYPE_NODE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, + PROP_PAGES, + g_param_spec_object ("pages", + "Pages node", + "Pages node", + EPHY_TYPE_NODE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (object_class, + PROP_FILTER, + g_param_spec_object ("filter", + "Filter object", + "Filter object", + EPHY_TYPE_NODE_FILTER, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +} + +static void +ephy_history_model_init (EphyHistoryModel *model) +{ + GtkWidget *dummy; + + do + { + model->stamp = g_random_int (); + } + while (model->stamp == 0); + + model->priv = g_new0 (EphyHistoryModelPrivate, 1); + + dummy = gtk_tree_view_new (); + + gtk_widget_destroy (dummy); +} + +static void +ephy_history_model_finalize (GObject *object) +{ + EphyHistoryModel *model; + + g_return_if_fail (object != NULL); + g_return_if_fail (EPHY_IS_HISTORY_MODEL (object)); + + model = EPHY_HISTORY_MODEL (object); + + g_return_if_fail (model->priv != NULL); + + g_free (model->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +filter_changed_cb (EphyNodeFilter *filter, + EphyHistoryModel *model) +{ + GPtrArray *kids; + int i; + + kids = ephy_node_get_children (model->priv->root); + + for (i = 0; i < kids->len; i++) + { + ephy_history_model_update_node (model, + g_ptr_array_index (kids, i), + i); + } + + ephy_node_thaw (model->priv->root); +} + +static void +ephy_history_model_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyHistoryModel *model = EPHY_HISTORY_MODEL (object); + + switch (prop_id) + { + case PROP_ROOT: + model->priv->root = g_value_get_object (value); + g_signal_connect_object (G_OBJECT (model->priv->root), + "child_added", + G_CALLBACK (root_child_added_cb), + G_OBJECT (model), + 0); + g_signal_connect_object (G_OBJECT (model->priv->root), + "child_removed", + G_CALLBACK (root_child_removed_cb), + G_OBJECT (model), + 0); + g_signal_connect_object (G_OBJECT (model->priv->root), + "child_changed", + G_CALLBACK (root_child_changed_cb), + G_OBJECT (model), + 0); + break; + case PROP_PAGES: + model->priv->pages = g_value_get_object (value); + g_signal_connect_object (G_OBJECT (model->priv->pages), + "child_added", + G_CALLBACK (root_child_added_cb), + G_OBJECT (model), + 0); + g_signal_connect_object (G_OBJECT (model->priv->pages), + "child_removed", + G_CALLBACK (root_child_removed_cb), + G_OBJECT (model), + 0); + g_signal_connect_object (G_OBJECT (model->priv->pages), + "child_changed", + G_CALLBACK (root_child_changed_cb), + G_OBJECT (model), + 0); + break; + case PROP_FILTER: + model->priv->filter = g_value_get_object (value); + + if (model->priv->filter != NULL) + { + g_signal_connect_object (G_OBJECT (model->priv->filter), + "changed", + G_CALLBACK (filter_changed_cb), + G_OBJECT (model), + 0); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ephy_history_model_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyHistoryModel *model = EPHY_HISTORY_MODEL (object); + + switch (prop_id) + { + case PROP_ROOT: + g_value_set_object (value, model->priv->root); + break; + case PROP_PAGES: + g_value_set_object (value, model->priv->root); + break; + case PROP_FILTER: + g_value_set_object (value, model->priv->filter); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +EphyHistoryModel * +ephy_history_model_new (EphyNode *root, + EphyNode *pages, + EphyNodeFilter *filter) +{ + EphyHistoryModel *model; + + model = EPHY_HISTORY_MODEL (g_object_new (EPHY_TYPE_HISTORY_MODEL, + "filter", filter, + "root", root, + "pages", pages, + NULL)); + + g_return_val_if_fail (model->priv != NULL, NULL); + + return model; +} + +static void +ephy_history_model_tree_model_init (GtkTreeModelIface *iface) +{ + iface->get_flags = ephy_history_model_get_flags; + iface->get_n_columns = ephy_history_model_get_n_columns; + iface->get_column_type = ephy_history_model_get_column_type; + iface->get_iter = ephy_history_model_get_iter; + iface->get_path = ephy_history_model_get_path; + iface->get_value = ephy_history_model_get_value; + iface->iter_next = ephy_history_model_iter_next; + iface->iter_children = ephy_history_model_iter_children; + iface->iter_has_child = ephy_history_model_iter_has_child; + iface->iter_n_children = ephy_history_model_iter_n_children; + iface->iter_nth_child = ephy_history_model_iter_nth_child; + iface->iter_parent = ephy_history_model_iter_parent; +} + +static guint +ephy_history_model_get_flags (GtkTreeModel *tree_model) +{ + return 0; +} + +static int +ephy_history_model_get_n_columns (GtkTreeModel *tree_model) +{ + return EPHY_HISTORY_MODEL_NUM_COLUMNS; +} + +static GType +ephy_history_model_get_column_type (GtkTreeModel *tree_model, + int index) +{ + g_return_val_if_fail (EPHY_IS_HISTORY_MODEL (tree_model), G_TYPE_INVALID); + g_return_val_if_fail ((index < EPHY_HISTORY_MODEL_NUM_COLUMNS) && (index >= 0), G_TYPE_INVALID); + + switch (index) + { + case EPHY_HISTORY_MODEL_COL_TITLE: + case EPHY_HISTORY_MODEL_COL_LOCATION: + case EPHY_HISTORY_MODEL_COL_VISITS: + case EPHY_HISTORY_MODEL_COL_LAST_VISIT: + case EPHY_HISTORY_MODEL_COL_FIRST_VISIT: + return G_TYPE_STRING; + case EPHY_HISTORY_MODEL_COL_VISIBLE: + return G_TYPE_BOOLEAN; + default: + g_assert_not_reached (); + return G_TYPE_INVALID; + } +} + +static gboolean +ephy_history_model_get_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreePath *path) +{ + EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model); + gint *indices; + gint depth; + EphyNode *host; + + g_return_val_if_fail (EPHY_IS_HISTORY_MODEL (model), FALSE); + + indices = gtk_tree_path_get_indices (path); + depth = gtk_tree_path_get_depth (path); + + g_return_val_if_fail (depth > 0, FALSE); + + iter->stamp = model->stamp; + host = ephy_node_get_nth_child (model->priv->root, indices [0]); + + if (depth == 2 && host != NULL) + { + iter->user_data = ephy_node_get_nth_child (host, indices [1]); + } + else + { + iter->user_data = host; + } + + if (iter->user_data == NULL) + { + iter->stamp = 0; + return FALSE; + } + + return TRUE; +} + +static EphyNode * +ensure_iter (EphyHistoryModel *model, GtkTreeIter *parent) +{ + EphyNode *node; + + if (parent) + { + node = EPHY_NODE (parent->user_data); + } + else + { + node = model->priv->root; + } + + return node; +} + +static EphyNode * +get_parent_node (EphyHistoryModel *model, EphyNode *node) +{ + int host_id; + + host_id = ephy_node_get_property_int (node, EPHY_NODE_PAGE_PROP_HOST_ID); + + if (host_id < 0) + { + return model->priv->root; + } + else + { + EphyNode *host; + host = ephy_node_get_from_id (host_id); + return host; + } +} + +static inline GtkTreePath * +get_one_level_path_real (EphyHistoryModel *model, + EphyNode *node) +{ + GtkTreePath *retval; + EphyNode *my_parent; + + retval = gtk_tree_path_new (); + + my_parent = get_parent_node (model, node); + + gtk_tree_path_append_index (retval, ephy_node_get_child_index (my_parent, node)); + + return retval; +} + +static inline GtkTreePath * +get_path_real (EphyHistoryModel *model, + EphyNode *page) +{ + GtkTreePath *retval; + EphyNode *host; + + retval = gtk_tree_path_new (); + host = get_parent_node (model, page); + + gtk_tree_path_append_index (retval, ephy_node_get_child_index (model->priv->root, host)); + gtk_tree_path_append_index (retval, ephy_node_get_child_index (host, page)); + + return retval; +} + +static GtkTreePath * +ephy_history_model_get_path (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model); + EphyNode *node; + + g_return_val_if_fail (EPHY_IS_HISTORY_MODEL (tree_model), NULL); + g_return_val_if_fail (iter != NULL, NULL); + g_return_val_if_fail (iter->user_data != NULL, NULL); + g_return_val_if_fail (iter->stamp == model->stamp, NULL); + + node = EPHY_NODE (iter->user_data); + + if (node == model->priv->root) + return gtk_tree_path_new (); + + return get_one_level_path_real (model, node); +} + +static void +get_property_as_date (EphyNode *node, + int id, + GValue *value) +{ + GTime time; + char s[50]; + GDate *date; + + time = ephy_node_get_property_int (node, id); + date = g_date_new (); + g_date_set_time (date, time); + g_date_strftime (s, 50, "%c", date); + + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, s); + + g_date_free (date); +} + +static void +ephy_history_model_get_value (GtkTreeModel *tree_model, + GtkTreeIter *iter, + int column, + GValue *value) +{ + EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model); + EphyNode *node; + + g_return_if_fail (EPHY_IS_HISTORY_MODEL (tree_model)); + g_return_if_fail (iter != NULL); + g_return_if_fail (iter->stamp == model->stamp); + g_return_if_fail (EPHY_IS_NODE (iter->user_data)); + g_return_if_fail (column < EPHY_HISTORY_MODEL_NUM_COLUMNS); + + node = EPHY_NODE (iter->user_data); + + if (ephy_node_get_property_int (node, EPHY_NODE_PAGE_PROP_HOST_ID) < 0 && + (column == EPHY_HISTORY_MODEL_COL_LOCATION || + column == EPHY_HISTORY_MODEL_COL_FIRST_VISIT || + column == EPHY_HISTORY_MODEL_COL_LAST_VISIT || + column == EPHY_HISTORY_MODEL_COL_VISITS)) + { + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, ""); + return; + } + + switch (column) + { + case EPHY_HISTORY_MODEL_COL_TITLE: + ephy_node_get_property (node, + EPHY_NODE_PAGE_PROP_TITLE, + value); + break; + case EPHY_HISTORY_MODEL_COL_LOCATION: + ephy_node_get_property (node, + EPHY_NODE_PAGE_PROP_LOCATION, + value); + break; + case EPHY_HISTORY_MODEL_COL_VISITS: + ephy_node_get_property (node, + EPHY_NODE_PAGE_PROP_VISITS, + value); + break; + case EPHY_HISTORY_MODEL_COL_FIRST_VISIT: + get_property_as_date (node, + EPHY_NODE_PAGE_PROP_FIRST_VISIT, + value); + break; + case EPHY_HISTORY_MODEL_COL_LAST_VISIT: + get_property_as_date (node, + EPHY_NODE_PAGE_PROP_LAST_VISIT, + value); + break; + case EPHY_HISTORY_MODEL_COL_VISIBLE: + g_value_init (value, G_TYPE_BOOLEAN); + + if (model->priv->filter != NULL) + { + g_value_set_boolean (value, + ephy_node_filter_evaluate (model->priv->filter, node)); + } + else + { + g_value_set_boolean (value, TRUE); + } + break; + default: + g_assert_not_reached (); + break; + } +} + +static gboolean +ephy_history_model_iter_next (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model); + EphyNode *node; + + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (iter->user_data != NULL, FALSE); + g_return_val_if_fail (iter->stamp == EPHY_HISTORY_MODEL (tree_model)->stamp, FALSE); + + node = EPHY_NODE (iter->user_data); + + iter->user_data = ephy_node_get_next_child + (get_parent_node (model, node), node); + + return (iter->user_data != NULL); +} + +static gboolean +ephy_history_model_iter_children (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent) +{ + EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model); + EphyNode *node; + + node = ensure_iter (model, parent); + + iter->user_data = ephy_node_get_nth_child (node, 0); + iter->stamp = model->stamp; + + return (iter->user_data != NULL); +} + +static gboolean +ephy_history_model_iter_has_child (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model); + EphyNode *node; + int host_id; + + node = EPHY_NODE (iter->user_data); + host_id = ephy_node_get_property_int (node, EPHY_NODE_PAGE_PROP_HOST_ID); + if (host_id < 0) + { + return ephy_node_has_child (model->priv->root, node); + } + else + { + return FALSE; + } +} + +static int +ephy_history_model_iter_n_children (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model); + EphyNode *node; + + g_return_val_if_fail (iter == NULL || iter->user_data != NULL, FALSE); + + node = ensure_iter (model, iter); + + return ephy_node_get_n_children (node); +} + +static gboolean +ephy_history_model_iter_nth_child (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent, + int n) +{ + EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model); + EphyNode *node; + + node = ensure_iter (model, parent); + + iter->user_data = ephy_node_get_nth_child (node, n); + iter->stamp = model->stamp; + + return (iter->user_data != NULL); +} + +static gboolean +ephy_history_model_iter_parent (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *child) +{ + EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model); + EphyNode *parent, *node; + + node = EPHY_NODE (iter->user_data); + parent = get_parent_node (model, node); + + if (parent != model->priv->root) + { + iter->user_data = parent; + iter->stamp = model->stamp; + return TRUE; + } + else + { + return FALSE; + } +} + +EphyNode * +ephy_history_model_node_from_iter (EphyHistoryModel *model, + GtkTreeIter *iter) +{ + return EPHY_NODE (iter->user_data); +} + +void +ephy_history_model_iter_from_node (EphyHistoryModel *model, + EphyNode *node, + GtkTreeIter *iter) +{ + iter->stamp = model->stamp; + iter->user_data = node; +} + +static inline void +ephy_history_model_update_node (EphyHistoryModel *model, + EphyNode *node, + int idx) +{ + GtkTreePath *path; + GtkTreeIter iter; + + ephy_history_model_iter_from_node (model, node, &iter); + + if (idx >= 0) + { + path = gtk_tree_path_new (); + gtk_tree_path_append_index (path, idx); + } + else + { + path = get_one_level_path_real (model, node); + } + + gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter); + gtk_tree_path_free (path); +} + +static void +root_child_removed_cb (EphyNode *node, + EphyNode *child, + EphyHistoryModel *model) +{ + GtkTreePath *path; + + if (node == model->priv->root) + { + path = get_one_level_path_real (model, child); + } + else + { + path = get_path_real (model, child); + } + gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path); + gtk_tree_path_free (path); +} + +static void +root_child_added_cb (EphyNode *node, + EphyNode *child, + EphyHistoryModel *model) +{ + GtkTreePath *path; + GtkTreeIter iter; + + ephy_history_model_iter_from_node (model, child, &iter); + + if (node == model->priv->root) + { + path = get_one_level_path_real (model, child); + } + else + { + path = get_path_real (model, child); + } + + gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter); + gtk_tree_path_free (path); +} + +static void +root_child_changed_cb (EphyNode *node, + EphyNode *child, + EphyHistoryModel *model) +{ + ephy_history_model_update_node (model, child, -1); +} + +GType +ephy_history_model_column_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) + { + static const GEnumValue values[] = + { + { EPHY_HISTORY_MODEL_COL_TITLE, "EPHY_HISTORY_MODEL_COL_TITLE", "title" }, + { EPHY_HISTORY_MODEL_COL_LOCATION, "EPHY_HISTORY_MODEL_COL_LOCATION", "location" }, + { EPHY_HISTORY_MODEL_COL_VISITS, "EPHY_HISTORY_MODEL_COL_VISITS", "visits" }, + { EPHY_HISTORY_MODEL_COL_FIRST_VISIT, "EPHY_HISTORY_MODEL_COL_FIRST_VISIT", "last_visit" }, + { EPHY_HISTORY_MODEL_COL_LAST_VISIT, "EPHY_HISTORY_MODEL_COL_LAST_VISIT", "last_visit" }, + { EPHY_HISTORY_MODEL_COL_VISIBLE, "EPHY_HISTORY_MODEL_COL_FIRST_VISIT", "first_visit" }, + + { 0, 0, 0 } + }; + + etype = g_enum_register_static ("EphyHistoryModelColumn", values); + } + + return etype; +} + diff --git a/src/ephy-history-model.h b/src/ephy-history-model.h new file mode 100644 index 000000000..6ff0058de --- /dev/null +++ b/src/ephy-history-model.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef __EPHY_HISTORY_MODEL_H +#define __EPHY_HISTORY_MODEL_H + +#include <gtk/gtktreemodel.h> + +#include "ephy-node.h" +#include "ephy-node-filter.h" + +G_BEGIN_DECLS + +#define EPHY_TYPE_HISTORY_MODEL (ephy_history_model_get_type ()) +#define EPHY_HISTORY_MODEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_HISTORY_MODEL, EphyHistoryModel)) +#define EPHY_HISTORY_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_HISTORY_MODEL, EphyHistoryModelClass)) +#define EPHY_IS_HISTORY_MODEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_HISTORY_MODEL)) +#define EPHY_IS_HISTORY_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_HISTORY_MODEL)) +#define EPHY_HISTORY_MODEL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_HISTORY_MODEL, EphyHistoryModelClass)) + +typedef enum +{ + EPHY_HISTORY_MODEL_COL_TITLE, + EPHY_HISTORY_MODEL_COL_LOCATION, + EPHY_HISTORY_MODEL_COL_VISITS, + EPHY_HISTORY_MODEL_COL_FIRST_VISIT, + EPHY_HISTORY_MODEL_COL_LAST_VISIT, + EPHY_HISTORY_MODEL_COL_VISIBLE, + EPHY_HISTORY_MODEL_NUM_COLUMNS +} EphyHistoryModelColumn; + +GType ephy_history_model_column_get_type (void); + +#define EPHY_TYPE_HISTORY_MODEL_COLUMN (ephy_history_model_column_get_type ()) + +typedef struct EphyHistoryModelPrivate EphyHistoryModelPrivate; + +typedef struct +{ + GObject parent; + + EphyHistoryModelPrivate *priv; + + int stamp; +} EphyHistoryModel; + +typedef struct +{ + GObjectClass parent; +} EphyHistoryModelClass; + +GType ephy_history_model_get_type (void); + +EphyHistoryModel *ephy_history_model_new (EphyNode *root, + EphyNode *pages, + EphyNodeFilter *filter); + +EphyNode *ephy_history_model_node_from_iter (EphyHistoryModel *model, + GtkTreeIter *iter); + +void ephy_history_model_iter_from_node (EphyHistoryModel *model, + EphyNode *node, + GtkTreeIter *iter); + +G_END_DECLS + +#endif /* EPHY_HISTORY_MODEL_H */ diff --git a/src/ephy-main.c b/src/ephy-main.c new file mode 100644 index 000000000..0a0093974 --- /dev/null +++ b/src/ephy-main.c @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2000-2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "ephy-shell.h" +#include "ephy-automation.h" +#include "ephy-window.h" +#include "EphyAutomation.h" + +#include <libbonoboui.h> +#include <libgnome/gnome-program.h> +#include <libgnomeui/gnome-ui-init.h> +#include <libgnomeui/gnome-window-icon.h> +#include <libgnomevfs/gnome-vfs-init.h> +#include <glade/glade-init.h> + +#define EPHY_FACTORY_OAFIID "OAFIID:GNOME_Epiphany_Automation_Factory" + +static gboolean +ephy_main_automation_init (void); +static gint +ephy_main_translate_url_arguments (poptContext context, gchar ***urls); +static gboolean +ephy_main_start (gpointer data); + +GnomeProgram *program; +CORBA_Environment corba_env; /* Global for downloader */ +static gboolean open_in_existing = FALSE; /* load in existing window? */ +static gboolean open_in_new_tab = FALSE; /* force open in a new tab? */ +static gboolean noraise = FALSE; /* no raise */ +static gboolean open_in_new_window = FALSE; /* force open in a new window? */ +static gboolean open_fullscreen = FALSE; /* open ephy in full screen ? */ +static gchar *session_filename = NULL; /* the session filename */ +static gchar *geometry_string = NULL; /* the geometry string */ +static gchar *bookmark_url = NULL; /* the temp bookmark to add */ +static gboolean close_option = FALSE; /* --close */ +static gboolean quit_option = FALSE; /* --quit */ +static gboolean ephy_server_mode = FALSE; +static gboolean open_as_nautilus_view = FALSE; + +static BonoboObject *automation_object; +static gint n_urls; +static gchar **url; +static gboolean first_instance; + +/* command line argument parsing structure */ +static struct poptOption popt_options[] = +{ + { NULL, '\0', POPT_ARG_INCLUDE_TABLE, &bonobo_activation_popt_options, 0, NULL, + NULL }, + { "new-tab", 'n', POPT_ARG_NONE, &open_in_new_tab, 0, + N_("Open a new tab in an existing Ephy window"), + NULL }, + { "new-window", 'w', POPT_ARG_NONE, &open_in_new_window, 0, + N_("Open a new window in an existing Ephy process"), + NULL }, + { "noraise", '\0', POPT_ARG_NONE, &noraise, 0, + N_("Do not raise the window when opening a page in an existing Ephy process"), + NULL }, + { "fullscreen", 'f', POPT_ARG_NONE, &open_fullscreen, 0, + N_("Run Ephy in full screen mode"), + NULL }, + { "existing", 'x', POPT_ARG_NONE, &open_in_existing, 0, + N_("Attempt to load URL in existing Ephy window"), + NULL }, + { "load-session", 'l', POPT_ARG_STRING, &session_filename, 0, + N_("Load the given session file"), + N_("FILE") }, + { "server", 's', POPT_ARG_NONE, &ephy_server_mode, 0, + N_("Don't open any windows; instead act as a server " + "for quick startup of new Ephy instances"), + NULL }, + { "add-bookmark", 't', POPT_ARG_STRING, &bookmark_url, + 0, N_("Add a bookmark (don't open any window)"), + N_("URL")}, + { "geometry", 'g', POPT_ARG_STRING, &geometry_string, + 0, N_("Create the initial window with the given geometry.\n" + "see X(1) for the GEOMETRY format"), + N_("GEOMETRY")}, + { "close", 'c', POPT_ARG_NONE, &close_option, 0, + N_("Close all Ephy windows"), + NULL }, + { "quit", 'q', POPT_ARG_NONE, &quit_option, 0, + N_("Same as --close, but exits server mode too"), + NULL }, + { "nautilus-view", 'v', POPT_ARG_NONE, &open_as_nautilus_view, 0, + N_("Used internally by the nautilus view"), + NULL }, + + /* terminator, must be last */ + { NULL, 0, 0, NULL, 0, NULL, NULL } +}; + +int +main (int argc, char *argv[]) +{ + poptContext context; + GValue context_as_value = { 0 }; + GnomeProgram *program; + +#ifdef ENABLE_NLS + /* Initialize the i18n stuff */ + bindtextdomain(GETTEXT_PACKAGE, GNOMELOCALEDIR); + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); + textdomain(GETTEXT_PACKAGE); +#endif + + program = gnome_program_init (PACKAGE, VERSION, + LIBGNOMEUI_MODULE, argc, argv, + GNOME_PARAM_POPT_TABLE, popt_options, + GNOME_PARAM_HUMAN_READABLE_NAME, _("Ephy"), + GNOME_PARAM_APP_DATADIR, DATADIR, + NULL); + + g_object_get_property (G_OBJECT (program), + GNOME_PARAM_POPT_CONTEXT, + g_value_init (&context_as_value, G_TYPE_POINTER)); + + context = g_value_get_pointer (&context_as_value); + + /* load arguments that aren't regular options (urls to load) */ + n_urls = ephy_main_translate_url_arguments (context, &url); + + first_instance = ephy_main_automation_init (); + + if (first_instance) + { + gnome_vfs_init (); + + glade_gnome_init (); + + gnome_window_icon_set_default_from_file (PIXMAP_DIR "/ephy.png"); + + ephy_shell_new (); + + g_idle_add ((GSourceFunc) ephy_main_start, NULL); + + bonobo_main (); + + gnome_vfs_shutdown (); + } + + return 0; +} + +static gboolean +ephy_main_start (gpointer data) +{ + GNOME_EphyAutomation gaserver; + int i; + + CORBA_exception_init (&corba_env); + + gaserver = bonobo_activation_activate_from_id ("OAFIID:GNOME_Epiphany_Automation", + 0, NULL, &corba_env); + + if (gaserver == NULL) + { + GtkWidget *dialog; + dialog = gtk_message_dialog_new + (NULL, + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "Ephy can't be used now. " + "Running the command \"bonobo-slay\" " + "from the console may fix the problem. If not, " + "you can try rebooting the computer or " + "installing Ephy again.\n\n" + "Bonobo couldn't locate the GNOME_Epiphany_Automation.server. "); + gtk_dialog_run (GTK_DIALOG (dialog)); + + } + /* FIXME ephy --server doesnt work when not first istance */ + /* Server mode */ + else if (ephy_server_mode) + { + g_object_ref (G_OBJECT(ephy_shell)); + } + /* load the session if requested */ + else if (session_filename) + { + GNOME_EphyAutomation_loadSession + (gaserver, session_filename, &corba_env); + } + /* if found and we're given a bookmark to add... */ + else if (bookmark_url != NULL) + { + GNOME_EphyAutomation_addBookmark + (gaserver, bookmark_url, &corba_env); + } + else if (close_option || quit_option) + { + GNOME_EphyAutomation_quit + (gaserver, quit_option, &corba_env); + } + /* provided with urls? */ + else if (n_urls == 0 && + !open_as_nautilus_view) + { + /* no, open a default window */ + GNOME_EphyAutomation_loadurl + (gaserver, "", + geometry_string ? + geometry_string : "", + open_fullscreen, + open_in_existing, + open_in_new_window, + open_in_new_tab, + !noraise, + &corba_env); + } + else + { + /* open all of the urls */ + for (i = 0; i < n_urls; i++) + { + GNOME_EphyAutomation_loadurl + (gaserver, url[i], + geometry_string ? + geometry_string : "", + open_fullscreen, + open_in_existing, + open_in_new_window, + open_in_new_tab, + !noraise, + &corba_env); + } + } + + /* Unref so it will exit if no more used */ + if (first_instance) + { + g_object_unref (G_OBJECT(ephy_shell)); + } + + if (gaserver) + { + bonobo_object_release_unref (gaserver, &corba_env); + } + + CORBA_exception_free (&corba_env); + + return FALSE; +} + +static gboolean +ephy_main_automation_init (void) +{ + CORBA_Object factory; + + factory = bonobo_activation_activate_from_id + (EPHY_FACTORY_OAFIID, + Bonobo_ACTIVATION_FLAG_EXISTING_ONLY, + NULL, NULL); + + if (!factory) + { + automation_object = ephy_automation_new (); + return TRUE; + } + else + { + ephy_main_start (NULL); + g_message (_("Ephy already running, using existing process")); + return FALSE; + } +} + +/** + * translate_url_arguments: gather URL arguments and expand them fully + * with realpath if they're filenames + */ +static gint +ephy_main_translate_url_arguments (poptContext context, gchar ***urls) +{ + gchar buffer[PATH_MAX]; + gchar **args; + gint i, n; + + /* any context remaining? */ + if (context == NULL) + { + *urls = NULL; + return 0; + } + + /* get the args and check */ + args = (gchar **) poptGetArgs (context); + if (args == NULL) + { + poptFreeContext (context); + *urls = NULL; + return 0; + } + + /* count args */ + for (n = 0; args[n] != NULL; n++) + /* nothing */; + + /* allocate pointer array */ + *urls = g_new0 (gchar *, n + 1); + + /* translate each one */ + for (i = 0; i < n; i++) + { + /* try to expand as files */ + if (realpath (args[i], buffer) != NULL) + { + (*urls)[i] = g_strconcat ("file://", buffer, NULL); + } + else + { + (*urls)[i] = g_strdup (args[i]); + } + } + poptFreeContext (context); + (*urls)[i] = NULL; + + /* return the number of urls */ + return n; +} diff --git a/src/ephy-nautilus-view.c b/src/ephy-nautilus-view.c new file mode 100644 index 000000000..f7a0ff867 --- /dev/null +++ b/src/ephy-nautilus-view.c @@ -0,0 +1,954 @@ +/* + * Copyright (C) 2001, 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#include <config.h> +#include <libgnome/gnome-macros.h> +#include <bonobo/bonobo-zoomable.h> +#include <bonobo/bonobo-ui-util.h> +#include <string.h> +#include "ephy-embed-popup-control.h" +#include "ephy-nautilus-view.h" +#include "ephy-embed.h" +#include "ephy-embed-utils.h" +#include "find-dialog.h" +#include "print-dialog.h" +#include "ephy-prefs.h" +#include "eel-gconf-extensions.h" + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); +#define DEBUG_MSG(x) g_print x +//#define DEBUG_MSG(x) + +static void gnv_embed_location_cb (EphyEmbed *embed, + EphyNautilusView *view); +static void gnv_embed_title_cb (EphyEmbed *embed, + EphyNautilusView *view); +static void gnv_embed_new_window_cb (EphyEmbed *embed, + EphyEmbed **new_embed, + EmbedChromeMask chromemask, + EphyNautilusView *view); +static void gnv_embed_link_message_cb (EphyEmbed *embed, + const char *message, + EphyNautilusView *view); +static gint gnv_embed_dom_mouse_down_cb (EphyEmbed *embed, + EphyEmbedEvent *event, + EphyNautilusView *view); +static void gnv_embed_zoom_change_cb (EphyNautilusView *embed, + guint new_zoom, + EphyNautilusView *view); + + +static void gnv_load_location_cb (EphyNautilusView *view, + const char *location, + gpointer user_data); +static void gnv_stop_loading_cb (EphyNautilusView *view, + gpointer user_data); +static void gnv_bonobo_control_activate_cb (BonoboControl *control, + gboolean state, + EphyNautilusView *view); + +/* zoomable */ +static void gnv_zoomable_set_zoom_level_cb (BonoboZoomable *zoomable, + float level, + EphyNautilusView *view); +static void gnv_zoomable_zoom_in_cb (BonoboZoomable *zoomable, + EphyNautilusView *view); +static void gnv_zoomable_zoom_out_cb (BonoboZoomable *zoomable, + EphyNautilusView *view); +static void gnv_zoomable_zoom_to_fit_cb (BonoboZoomable *zoomable, + EphyNautilusView *view); +static void gnv_zoomable_zoom_to_default_cb (BonoboZoomable *zoomable, + EphyNautilusView *view); +/* commands */ +static void gnv_cmd_set_charset (BonoboUIComponent *uic, + EncodingMenuData *data, + const char* verbname); +static void gnv_cmd_file_print (BonoboUIComponent *uic, + EphyNautilusView *view, + const char* verbname); +static void gnv_cmd_edit_find (BonoboUIComponent *uic, + EphyNautilusView *view, + const char* verbname); + + +/* popups */ +static EphyNautilusView *gnv_view_from_popup (EphyEmbedPopup *popup); + +static void gnv_popup_cmd_new_window (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); +static void gnv_popup_cmd_image_in_new_window (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); +static void gnv_popup_cmd_frame_in_new_window (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); + + +static float preferred_zoom_levels[] = { + 0.2, 0.4, 0.6, 0.8, + 1.0, 1.2, 1.4, 1.6, 1.8, + 2.0, 2.2, 2.4, 2.6, 2.8, + 3.0, 3.2, 3.4, 3.6, 3.8, + 4.0, 4.2, 4.4, 4.6, 4.8, + 5.0, 5.2, 5.4, 5.6, 5.8, + 6.0, 6.2, 6.4, 6.6, 6.8, + 7.0, 7.2, 7.4, 7.6, 7.8, + 8.0, 8.2, 8.4, 8.6, 8.8, + 9.0, 9.2, 9.4, 9.6, 9.8, +}; + +static const gchar *preferred_zoom_level_names[] = { + "20%", "40%", "60%", "80%", + "100%", "120%", "140%", "160%", "180%", + "200%", "220%", "240%", "260%", "280%", + "300%", "320%", "340%", "360%", "380%", + "400%", "420%", "440%", "460%", "480%", + "500%", "520%", "540%", "560%", "580%", + "600%", "620%", "640%", "660%", "680%", + "700%", "720%", "740%", "760%", "780%", + "800%", "820%", "840%", "860%", "880%", + "900%", "920%", "940%", "960%", "980%", +}; +#define NUM_ZOOM_LEVELS (sizeof (preferred_zoom_levels) / sizeof (float)) + +struct EphyNautilusViewPrivate { + EphyEmbed *embed; + char *title; + char *location; + int load_percent; + + /* + BonoboPropertyBag *property_bag; + */ + + EphyEmbedPopupControl *popup; + BonoboUIComponent *popup_ui; + BonoboControl *control; + BonoboUIComponent *ui; + BonoboZoomable *zoomable; + + EphyDialog *find_dialog; +}; + +static BonoboUIVerb ephy_popup_verbs [] = { + BONOBO_UI_VERB ("EPOpenInNewWindow", (BonoboUIVerbFn) gnv_popup_cmd_new_window), + BONOBO_UI_VERB ("EPOpenImageInNewWindow", (BonoboUIVerbFn) gnv_popup_cmd_image_in_new_window), + BONOBO_UI_VERB ("DPOpenFrameInNewWindow", (BonoboUIVerbFn) gnv_popup_cmd_frame_in_new_window), + + BONOBO_UI_VERB_END +}; + +BonoboUIVerb ephy_verbs [] = { + BONOBO_UI_VERB ("FilePrint", (BonoboUIVerbFn) gnv_cmd_file_print), + BONOBO_UI_VERB ("EditFind", (BonoboUIVerbFn) gnv_cmd_edit_find), + BONOBO_UI_VERB_END +}; + +#define CHARSET_MENU_PATH "/menu/View/Encoding" + + +BONOBO_CLASS_BOILERPLATE (EphyNautilusView, ephy_nautilus_view, + NautilusView, NAUTILUS_TYPE_VIEW) + +static void +ephy_nautilus_view_instance_init (EphyNautilusView *view) +{ + GtkWidget *w; + EphyNautilusViewPrivate *p = g_new0 (EphyNautilusViewPrivate, 1); + + view->priv = p; + view->priv->embed = ephy_embed_new (G_OBJECT (ephy_shell_get_embed_shell (ephy_shell))); + + g_object_ref (G_OBJECT (ephy_shell)); + + g_signal_connect (view->priv->embed, "ge_link_message", + GTK_SIGNAL_FUNC (gnv_embed_link_message_cb), + view); + g_signal_connect (view->priv->embed, "ge_location", + GTK_SIGNAL_FUNC (gnv_embed_location_cb), + view); + g_signal_connect (view->priv->embed, "ge_title", + GTK_SIGNAL_FUNC (gnv_embed_title_cb), + view); +/* + g_signal_connect (view->priv->embed, "ge_js_status", + GTK_SIGNAL_FUNC (gnv_embed_js_status_cb), + view); + g_signal_connect (view->priv->embed, "ge_progress", + GTK_SIGNAL_FUNC (gnv_embed_progress_cb), + view); + g_signal_connect (view->priv->embed, "ge_net_state", + GTK_SIGNAL_FUNC (gnv_embed_net_state_cb), + view); +*/ + g_signal_connect (view->priv->embed, "ge_new_window", + GTK_SIGNAL_FUNC (gnv_embed_new_window_cb), + view); +/* + g_signal_connect (view->priv->embed, "ge_visibility", + GTK_SIGNAL_FUNC (gnv_embed_visibility_cb), + view); + g_signal_connect (view->priv->embed, "ge_destroy_brsr", + GTK_SIGNAL_FUNC (gnv_embed_destroy_brsr_cb), + view); + g_signal_connect (view->priv->embed, "ge_open_uri", + GTK_SIGNAL_FUNC (gnv_embed_open_uri_cb), + view); + g_signal_connect (view->priv->embed, "ge_size_to", + GTK_SIGNAL_FUNC (gnv_embed_size_to_cb), + view); + g_signal_connect (view->priv->embed, "ge_dom_mouse_click", + GTK_SIGNAL_FUNC (gnv_embed_dom_mouse_click_cb), + view); +*/ + g_signal_connect (view->priv->embed, "ge_dom_mouse_down", + GTK_SIGNAL_FUNC (gnv_embed_dom_mouse_down_cb), + view); +/* + g_signal_connect (view->priv->embed, "ge_security_change", + GTK_SIGNAL_FUNC (gnv_embed_security_change_cb), + view); +*/ + g_signal_connect (view->priv->embed, "ge_zoom_change", + GTK_SIGNAL_FUNC (gnv_embed_zoom_change_cb), + view); + + w = GTK_WIDGET (view->priv->embed); + gtk_widget_show (w); + + nautilus_view_construct (NAUTILUS_VIEW (view), w); + + g_signal_connect (G_OBJECT (view), "load_location", + G_CALLBACK (gnv_load_location_cb), NULL); + + g_signal_connect (G_OBJECT (view), "stop_loading", + G_CALLBACK (gnv_stop_loading_cb), NULL); + + g_signal_connect (G_OBJECT (nautilus_view_get_bonobo_control (NAUTILUS_VIEW (view))), + "activate", + G_CALLBACK (gnv_bonobo_control_activate_cb), view); + + view->priv->zoomable = bonobo_zoomable_new (); + bonobo_object_add_interface (BONOBO_OBJECT (view), + BONOBO_OBJECT (view->priv->zoomable)); + + bonobo_zoomable_set_parameters_full (view->priv->zoomable, + 1.0, + preferred_zoom_levels [0], + preferred_zoom_levels [NUM_ZOOM_LEVELS - 1], + FALSE, FALSE, TRUE, + preferred_zoom_levels, + preferred_zoom_level_names, + NUM_ZOOM_LEVELS); + + bonobo_object_add_interface (BONOBO_OBJECT (view), + BONOBO_OBJECT (view->priv->zoomable)); + + g_signal_connect (view->priv->zoomable, "set_zoom_level", + G_CALLBACK (gnv_zoomable_set_zoom_level_cb), view); + g_signal_connect (view->priv->zoomable, "zoom_in", + G_CALLBACK (gnv_zoomable_zoom_in_cb), view); + g_signal_connect (view->priv->zoomable, "zoom_out", + G_CALLBACK (gnv_zoomable_zoom_out_cb), view); + g_signal_connect (view->priv->zoomable, "zoom_to_fit", + G_CALLBACK (gnv_zoomable_zoom_to_fit_cb), view); + g_signal_connect (view->priv->zoomable, "zoom_to_default", + G_CALLBACK (gnv_zoomable_zoom_to_default_cb), view); + + p->control = nautilus_view_get_bonobo_control (NAUTILUS_VIEW (view)); + + p->popup_ui = bonobo_control_get_popup_ui_component (p->control); + g_assert (BONOBO_IS_UI_COMPONENT (p->popup_ui)); + bonobo_ui_util_set_ui (p->popup_ui, DATADIR, + "nautilus-ephy-view-ui.xml", + "EphyNutilusView", NULL); + p->popup = ephy_embed_popup_control_new (p->control); + ephy_embed_popup_connect_verbs (EPHY_EMBED_POPUP (p->popup), p->popup_ui); + g_object_set_data (G_OBJECT (p->popup), "NautilisView", view); + + bonobo_ui_component_add_verb_list_with_data (p->popup_ui, ephy_popup_verbs, p->popup); +} + +/** + * Returns a new EphyNautilusView as a BonoboObject + **/ +BonoboObject * +ephy_nautilus_view_new_component (EphyShell *gs) +{ + EphyNautilusView *view; + view = EPHY_NAUTILUS_VIEW (g_object_new (EPHY_TYPE_NAUTILUS_VIEW, NULL)); + return BONOBO_OBJECT (view); +} + +static void +ephy_nautilus_view_finalize (GObject *object) +{ + EphyNautilusView *view = EPHY_NAUTILUS_VIEW (object); + EphyNautilusViewPrivate *p = view->priv; + + if (p->find_dialog) + { + g_object_unref (p->find_dialog); + } + + g_object_unref (p->popup); + + g_free (p->title); + g_free (p->location); + g_free (p); + + GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); + + g_object_unref (G_OBJECT (ephy_shell)); +} + +static void +ephy_nautilus_view_class_init (EphyNautilusViewClass *class) +{ + G_OBJECT_CLASS (class)->finalize = ephy_nautilus_view_finalize; +} + + + +static gint +gnv_embed_dom_mouse_down_cb (EphyEmbed *embed, + EphyEmbedEvent *event, + EphyNautilusView *view) +{ + EphyNautilusViewPrivate *p = view->priv; + int button; + EmbedEventContext context; + + ephy_embed_event_get_mouse_button (event, &button); + ephy_embed_event_get_context (event, &context); + + if (button == 2) + { + ephy_embed_popup_set_event (EPHY_EMBED_POPUP (p->popup), event); + ephy_embed_popup_show (EPHY_EMBED_POPUP (p->popup), embed); + return TRUE; + + } + else if (button == 1 + && (context & EMBED_CONTEXT_LINK)) + { + GValue *value; + const gchar *url; + ephy_embed_event_get_property (event, "link", &value); + url = g_value_get_string (value); + + g_return_val_if_fail (url, FALSE); + + nautilus_view_open_location_force_new_window (NAUTILUS_VIEW (view), + url, NULL); + } + + return FALSE; +} + +static void +gnv_embed_link_message_cb (EphyEmbed *embed, const char *message, EphyNautilusView *view) +{ + g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view)); + g_return_if_fail (message != NULL); + + nautilus_view_report_status (NAUTILUS_VIEW (view), message); +} + +static void +gnv_embed_location_cb (EphyEmbed *embed, EphyNautilusView *view) +{ + EphyNautilusViewPrivate *p; + const gchar *prefixes_to_ignore[] = + { + "about:", + "javascript:", + NULL + }; + int i = 0; + gchar *new_uri; + + g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view)); + p = view->priv; + g_return_if_fail (view->priv->embed == embed); + + ephy_embed_get_location (embed, TRUE, FALSE, + &new_uri); + + g_return_if_fail (new_uri != NULL); + + + /* don't inform nautilus about uris that it can't understand */ + while (prefixes_to_ignore[i] != NULL) + { + if (!strncmp (prefixes_to_ignore[i], new_uri, strlen (prefixes_to_ignore[i]))) + { + g_free (new_uri); + return; + } + ++i; + } + + nautilus_view_report_location_change (NAUTILUS_VIEW (view), new_uri, NULL, new_uri); + + /* TODO, FIXME + nautilus_view_report_redirect (view, p->location, new_uri, NULL, new_uri); + */ + + + g_free (p->location); + p->location = new_uri; + + +} + +static void +gnv_embed_title_cb (EphyEmbed *embed, EphyNautilusView *view) +{ + EphyNautilusViewPrivate *p; + + g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view)); + p = view->priv; + g_return_if_fail (view->priv->embed == embed); + + g_free (p->title); + ephy_embed_get_title (embed, &p->title); + + nautilus_view_set_title (NAUTILUS_VIEW (view), p->title); +} + +static void +gnv_load_location_cb (EphyNautilusView *view, const char *location, gpointer user_data) +{ + g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view)); + g_return_if_fail (location != NULL); + + nautilus_view_report_load_underway (NAUTILUS_VIEW (view)); + ephy_embed_load_url (view->priv->embed, location); + +} + +static void +gnv_stop_loading_cb (EphyNautilusView *view, gpointer user_data) +{ +} + +static void +gnv_embed_new_window_cb (EphyEmbed *embed, EphyEmbed **new_embed, + EmbedChromeMask chromemask, EphyNautilusView *view) +{ + EphyTab *new_tab; + EphyWindow *window; + + window = ephy_window_new (); + if (!(chromemask & EMBED_CHROME_OPENASCHROME)) + { + ephy_window_set_chrome (window, + chromemask | + EMBED_CHROME_OPENASPOPUP); + } + new_tab = ephy_tab_new (); + ephy_window_add_tab (window, new_tab, FALSE); + + *new_embed = ephy_tab_get_embed (new_tab); +} + + +static void +gnv_bonobo_control_activate_cb (BonoboControl *control, gboolean state, EphyNautilusView *view) +{ + if (state) + { + EphyNautilusViewPrivate *p = view->priv; + + p->ui = nautilus_view_set_up_ui (NAUTILUS_VIEW (view), DATADIR, + "nautilus-ephy-view-ui.xml", "EphyNutilusView"); + g_return_if_fail (BONOBO_IS_UI_COMPONENT (p->ui)); + + ephy_embed_utils_build_charsets_submenu (p->ui, + CHARSET_MENU_PATH, + (BonoboUIVerbFn) gnv_cmd_set_charset, + view); + + bonobo_ui_component_add_verb_list_with_data (p->ui, ephy_verbs, view); + } +} + +static EphyNautilusView * +gnv_view_from_popup (EphyEmbedPopup *popup) +{ + return g_object_get_data (G_OBJECT (popup), "NautilisView"); +} + + +static void +gnv_popup_cmd_new_window (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + EphyEmbedEvent *info; + EphyNautilusView *view; + GValue *value; + + view = gnv_view_from_popup (popup); + + info = ephy_embed_popup_get_event (popup); + + ephy_embed_event_get_property (info, "link", &value); + + nautilus_view_open_location_force_new_window (NAUTILUS_VIEW (view), + g_value_get_string (value), NULL); +} + +static void +gnv_popup_cmd_image_in_new_window (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + EphyEmbedEvent *info; + EphyNautilusView *view; + GValue *value; + + view = gnv_view_from_popup (popup); + + info = ephy_embed_popup_get_event (popup); + + ephy_embed_event_get_property (info, "image", &value); + + nautilus_view_open_location_force_new_window (NAUTILUS_VIEW (view), + g_value_get_string (value), NULL); +} + +static void +gnv_popup_cmd_frame_in_new_window (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + EphyEmbedEvent *info; + EphyNautilusView *view; + gchar *location; + + view = gnv_view_from_popup (popup); + + info = ephy_embed_popup_get_event (popup); + + ephy_embed_get_location (view->priv->embed, FALSE, FALSE, &location); + + nautilus_view_open_location_force_new_window (NAUTILUS_VIEW (view), + location, NULL); +} + +void +gnv_cmd_set_charset (BonoboUIComponent *uic, + EncodingMenuData *data, + const char* verbname) +{ + EphyNautilusView *view = data->data; + EphyNautilusViewPrivate *p; + + g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view)); + + p = view->priv; + + DEBUG_MSG ((data->encoding)); + ephy_embed_set_charset (p->embed, data->encoding); +} + +static void +gnv_cmd_file_print (BonoboUIComponent *uic, + EphyNautilusView *view, + const char* verbname) +{ + EphyDialog *dialog; + EphyNautilusViewPrivate *p = view->priv; + + dialog = print_dialog_new (p->embed, NULL); + + //g_signal_connect (G_OBJECT(dialog), + // "preview", + // G_CALLBACK (print_dialog_preview_cb), + // window); + + ephy_dialog_set_modal (dialog, TRUE); + ephy_dialog_show (dialog); + +} + +static void +gnv_cmd_edit_find (BonoboUIComponent *uic, + EphyNautilusView *view, + const char* verbname) +{ + EphyNautilusViewPrivate *p = view->priv; + + if (!p->find_dialog) + { + p->find_dialog = find_dialog_new (p->embed); + } + + ephy_dialog_show (p->find_dialog); +} + + +/* zoomable */ +static void +gnv_zoomable_set_zoom_level_cb (BonoboZoomable *zoomable, + float level, + EphyNautilusView *view) +{ + gint zoom = level * 100; + g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view)); + if (zoom < 10) return; + if (zoom > 1000) return; + ephy_embed_zoom_set (view->priv->embed, zoom, TRUE); +} + +static void +gnv_zoomable_zoom_in_cb (BonoboZoomable *zoomable, + EphyNautilusView *view) +{ + gint zoom; + g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view)); + ephy_embed_zoom_get (view->priv->embed, &zoom); + if (zoom > 990) return; + ephy_embed_zoom_set (view->priv->embed, zoom + 10, TRUE); +} + +static void +gnv_zoomable_zoom_out_cb (BonoboZoomable *zoomable, + EphyNautilusView *view) +{ + gint zoom; + g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view)); + ephy_embed_zoom_get (view->priv->embed, &zoom); + if (zoom < 20) return; + ephy_embed_zoom_set (view->priv->embed, zoom - 10, TRUE); +} + +static void +gnv_zoomable_zoom_to_fit_cb (BonoboZoomable *zoomable, + EphyNautilusView *view) +{ + gnv_zoomable_zoom_to_default_cb (zoomable, view); +} + +static void +gnv_zoomable_zoom_to_default_cb (BonoboZoomable *zoomable, + EphyNautilusView *view) +{ + g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view)); + ephy_embed_zoom_set (view->priv->embed, 100, TRUE); +} + +static void +gnv_embed_zoom_change_cb (EphyNautilusView *embed, + guint new_zoom, + EphyNautilusView *view) +{ + float flevel; + g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view)); + + flevel = ((float) new_zoom) / 100.0; + + bonobo_zoomable_report_zoom_level_changed (view->priv->zoomable, + flevel, NULL); + +} + + +#ifdef IM_TOO_LAZY_TO_MOVE_THIS_TO_ANOTHER_FILE + + +/* property bag properties */ +enum { + ICON_NAME, + COMPONENT_INFO +}; + + +static void +get_bonobo_properties (BonoboPropertyBag *bag, + BonoboArg *arg, + guint arg_id, + CORBA_Environment *ev, + gpointer callback_data) +{ + EphyNautilusView *content_view; + + content_view = (EphyNautilusView*) callback_data; + + switch (arg_id) { + case ICON_NAME: + if (!strncmp (content_view->priv->uri, "man:", 4)) { + BONOBO_ARG_SET_STRING (arg, "manual"); + } else if (!strncmp (content_view->priv->uri, "http:", 5)) { + BONOBO_ARG_SET_STRING (arg, "i-web"); + } else if (!strncmp (content_view->priv->uri, "https:", 6)) { + /* FIXME: put a nice icon for secure sites */ + BONOBO_ARG_SET_STRING (arg, "i-web"); + } else { + BONOBO_ARG_SET_STRING (arg, ""); + } + break; + + case COMPONENT_INFO: + BONOBO_ARG_SET_STRING (arg, ""); + break; + + default: + g_warning ("Unhandled arg %d", arg_id); + break; + } +} + +/* there are no settable properties, so complain if someone tries to set one */ +static void +set_bonobo_properties (BonoboPropertyBag *bag, + const BonoboArg *arg, + guint arg_id, + CORBA_Environment *ev, + gpointer callback_data) +{ + g_warning ("Bad Property set on view: property ID %d", + arg_id); +} + +static void +ephy_nautilus_view_initialize (EphyNautilusView *view) +{ + + +#ifdef NOT_PORTED + bonobo_control_set_properties (nautilus_view_get_bonobo_control (view->priv->nautilus_view), + view->priv->property_bag); +#endif + bonobo_property_bag_add (view->priv->property_bag, "icon_name", ICON_NAME, + BONOBO_ARG_STRING, NULL, + _("name of icon for the mozilla view"), 0); + bonobo_property_bag_add (view->priv->property_bag, "summary_info", COMPONENT_INFO, + BONOBO_ARG_STRING, NULL, + _("mozilla summary info"), 0); +} + + + /* free the property bag */ + if (view->priv->property_bag != NULL) { + bonobo_object_unref (BONOBO_OBJECT (view->priv->property_bag)); + view->priv->property_bag = NULL; + } + +} + + + +void +ephy_nautilus_view_report_load_progress (EphyNautilusView *view, + double value) +{ + g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view)); + + if (value < 0.0) value = 0.0; + if (value > 1.0) value = 1.0; + + nautilus_view_report_load_progress (view->priv->nautilus_view, value); +} + +/***********************************************************************************/ + +/** + * vfs_open_cb + * + * Callback for gnome_vfs_async_open. Attempt to read data from handle + * and pass to mozilla streaming callback. + * + **/ +static void +vfs_open_cb (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer data) +{ + EphyNautilusView *view = data; + + DEBUG_MSG (("+%s GnomeVFSResult: %u\n", G_GNUC_FUNCTION, (unsigned)result)); + + if (result != GNOME_VFS_OK) + { + gtk_moz_embed_close_stream (GTK_MOZ_EMBED (view->priv->embed->mozembed)); + /* NOTE: the view may go away after a call to report_load_failed */ + DEBUG_MSG ((">nautilus_view_report_load_failed\n")); + nautilus_view_report_load_failed (view->priv->nautilus_view); + } else { + if (view->priv->vfs_read_buffer == NULL) { + view->priv->vfs_read_buffer = g_malloc (VFS_READ_BUFFER_SIZE); + } + gtk_moz_embed_open_stream (GTK_MOZ_EMBED (view->priv->embed->mozembed), "file:///", "text/html"); + gnome_vfs_async_read (handle, view->priv->vfs_read_buffer, VFS_READ_BUFFER_SIZE, vfs_read_cb, view); + } + DEBUG_MSG (("-%s\n", G_GNUC_FUNCTION)); +} + +/** + * vfs_read_cb: + * + * Read data from buffer and copy into mozilla stream. + **/ + +static void +vfs_read_cb (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer buffer, + GnomeVFSFileSize bytes_requested, + GnomeVFSFileSize bytes_read, + gpointer data) +{ + EphyNautilusView *view = data; + + DEBUG_MSG (("+%s %ld/%ld bytes\n", G_GNUC_FUNCTION, (long)bytes_requested, (long) bytes_read)); + + if (bytes_read != 0) { + gtk_moz_embed_append_data (GTK_MOZ_EMBED (view->priv->embed->mozembed), buffer, bytes_read); + } + + if (bytes_read == 0 || result != GNOME_VFS_OK) { + gtk_moz_embed_close_stream (GTK_MOZ_EMBED (view->priv->embed->mozembed)); + view->priv->vfs_handle = NULL; + g_free (view->priv->vfs_read_buffer); + view->priv->vfs_read_buffer = NULL; + + gnome_vfs_async_close (handle, (GnomeVFSAsyncCloseCallback) gtk_true, NULL); + + DEBUG_MSG ((">nautilus_view_report_load_complete\n")); + nautilus_view_report_load_complete (view->priv->nautilus_view); + + DEBUG_MSG (("=%s load complete\n", G_GNUC_FUNCTION)); + } else { + gnome_vfs_async_read (handle, view->priv->vfs_read_buffer, VFS_READ_BUFFER_SIZE, vfs_read_cb, view); + } + + DEBUG_MSG (("-%s\n", G_GNUC_FUNCTION)); +} + +/***********************************************************************************/ + +static void +cancel_pending_vfs_operation (EphyNautilusView *view) +{ + if (view->priv->vfs_handle != NULL) { + gnome_vfs_async_cancel (view->priv->vfs_handle); + gtk_moz_embed_close_stream (GTK_MOZ_EMBED (view->priv->embed->mozembed)); + } + + view->priv->vfs_handle = NULL; + g_free (view->priv->vfs_read_buffer); + view->priv->vfs_read_buffer = NULL; +} + + +/* this takes a "nautilus" uri, not a "mozilla" uri and uses (sometimes) GnomeVFS */ +static void +navigate_mozilla_to_nautilus_uri (EphyNautilusView *view, + const char *uri) +{ + char *old_uri; + + cancel_pending_vfs_operation (view); + + if (!GTK_WIDGET_REALIZED (view->priv->embed->mozembed)) { + + /* Doing certain things to gtkmozembed before + * the widget has realized (specifically, opening + * content streams) can cause crashes. To avoid + * this, we postpone all navigations + * until the widget has realized (we believe + * premature realization may cause other issues) + */ + + DEBUG_MSG (("=%s: Postponing navigation request to widget realization\n", G_GNUC_FUNCTION)); + /* Note that view->priv->uri is still set below */ + } else { + if (should_mozilla_load_uri_directly (uri)) { + + /* See if the current URI is the same as what mozilla already + * has. If so, issue a reload rather than a load. + * We ask mozilla for it's uri rather than using view->priv->uri because, + * from time to time, our understanding of mozilla's URI can become inaccurate + * (in particular, certain errors may cause embedded mozilla to not change + * locations) + */ + + old_uri = view->priv->embed->location; + + if (old_uri != NULL && uris_identical (uri, old_uri)) { + DEBUG_MSG (("=%s uri's identical, telling ephy to reload\n", G_GNUC_FUNCTION)); + embed_reload (view->priv->embed, + GTK_MOZ_EMBED_FLAG_RELOADBYPASSCACHE); + } else { + embed_load_url (view->priv->embed, uri); + } + + } else { + DEBUG_MSG (("=%s loading URI via gnome-vfs\n", G_GNUC_FUNCTION)); + gnome_vfs_async_open (&(view->priv->vfs_handle), uri, + GNOME_VFS_OPEN_READ, GNOME_VFS_PRIORITY_DEFAULT, + vfs_open_cb, view); + } + } + + g_free (view->priv->uri); + view->priv->uri = g_strdup (uri); + + DEBUG_MSG (("=%s current URI is now '%s'\n", G_GNUC_FUNCTION, view->priv->uri)); +} + +/* + * This a list of URI schemes that mozilla should load directly, rather than load through gnome-vfs + */ +static gboolean +should_mozilla_load_uri_directly (const char *uri) +{ + static const char *handled_by_mozilla[] = + { + "http", + "file", + "toc", + "man", + "info", + "ghelp", + "gnome-help", + "https", + NULL + }; + gint i; + gint uri_length; + + if (uri == NULL) return FALSE; + + uri_length = strlen (uri); + + for (i = 0; handled_by_mozilla[i] != NULL; i++) + { + const gchar *current = handled_by_mozilla[i]; + gint current_length = strlen (current); + if ((uri_length >= current_length) + && (!strncasecmp (uri, current, current_length))) + return TRUE; + } + return FALSE; +} + + + +#endif diff --git a/src/ephy-nautilus-view.h b/src/ephy-nautilus-view.h new file mode 100644 index 000000000..3dd13560b --- /dev/null +++ b/src/ephy-nautilus-view.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2001, 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#ifndef EPHY_NAUTILUS_VIEW_H +#define EPHY_NAUTILUS_VIEW_H + +#include <libnautilus/nautilus-view.h> +#include "ephy-shell.h" + +G_BEGIN_DECLS + +#define EPHY_TYPE_NAUTILUS_VIEW (ephy_nautilus_view_get_type ()) +#define EPHY_NAUTILUS_VIEW(obj) (GTK_CHECK_CAST ((obj), EPHY_TYPE_NAUTILUS_VIEW, \ + EphyNautilusView)) +#define EPHY_NAUTILUS_VIEW_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_TYPE_NAUTILUS_VIEW, \ + EphyNautilusViewClass)) +#define EPHY_IS_NAUTILUS_VIEW(obj) (GTK_CHECK_TYPE ((obj), EPHY_TYPE_NAUTILUS_VIEW)) +#define EPHY_IS_NAUTILUS_VIEW_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_IS_NAUTILUS_VIEW_CLASS)) + +typedef struct EphyNautilusView EphyNautilusView; +typedef struct EphyNautilusViewClass EphyNautilusViewClass; +typedef struct EphyNautilusViewPrivate EphyNautilusViewPrivate; + +struct EphyNautilusView +{ + NautilusView parent; + EphyNautilusViewPrivate *priv; +}; + +struct EphyNautilusViewClass +{ + NautilusViewClass parent_class; +}; + + +GType ephy_nautilus_view_get_type (void); +BonoboObject * ephy_nautilus_view_new_component (EphyShell *gs); + +/* old public methods, probably all of them are going to be killed */ + +void +ephy_nautilus_view_set_title (EphyNautilusView *view, + const gchar *title); +void +ephy_nautilus_view_set_location (EphyNautilusView *view, + const gchar *uri); +void +ephy_nautilus_view_set_statusbar (EphyNautilusView *view, + const gchar *message); +void +ephy_nautilus_view_report_load_underway (EphyNautilusView *view); + +void +ephy_nautilus_view_report_load_complete (EphyNautilusView *view); + +void +ephy_nautilus_view_report_load_progress (EphyNautilusView *view, + double value); +void +ephy_nautilus_view_report_zoom (EphyNautilusView *view, + gint level); + +void ephy_nautilus_view_open_in_new_window (EphyNautilusView *view, + const gchar *url); + +G_END_DECLS + +#endif diff --git a/src/ephy-shell.c b/src/ephy-shell.c new file mode 100644 index 000000000..eeacdf819 --- /dev/null +++ b/src/ephy-shell.c @@ -0,0 +1,525 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-shell.h" +#include "ephy-embed-shell.h" +#include "eel-gconf-extensions.h" +#include "ephy-prefs.h" +#include "ephy-favicon-cache.h" +#include "ephy-stock-icons.h" +#include "ephy-filesystem-autocompletion.h" +#include "ephy-window.h" +#include "ephy-file-helpers.h" +#include "ephy-thread-helpers.h" + +#include <libgnomeui/gnome-client.h> +#include <bonobo/bonobo-main.h> +#include <bonobo/bonobo-i18n.h> +#include <gtk/gtksignal.h> +#include <gtk/gtkmain.h> +#include <gtk/gtkmessagedialog.h> + +#ifdef ENABLE_NAUTILUS_VIEW + +#include <bonobo/bonobo-generic-factory.h> +#include "ephy-nautilus-view.h" + +#define EPHY_NAUTILUS_VIEW_OAFIID "OAFIID:GNOME_Ephy_NautilusViewFactory" + +#endif + +struct EphyShellPrivate +{ + EphyEmbedShell *embed_shell; + Session *session; + EphyAutocompletion *autocompletion; + EphyBookmarks *bookmarks; +}; + +enum +{ + STARTPAGE_HOME, + STARTPAGE_LAST, + STARTPAGE_BLANK, +}; + +static void +ephy_shell_class_init (EphyShellClass *klass); +static void +ephy_shell_init (EphyShell *gs); +static void +ephy_shell_finalize (GObject *object); +static void +ephy_init_services (EphyShell *gs); + +#ifdef ENABLE_NAUTILUS_VIEW + +static void +ephy_nautilus_view_init_factory (EphyShell *gs); +static BonoboObject * +ephy_nautilus_view_new (BonoboGenericFactory *factory, + const char *id, + EphyShell *gs); + +#endif + +static GObjectClass *parent_class = NULL; + +EphyShell *ephy_shell; + +GType +ephy_shell_get_type (void) +{ + static GType ephy_shell_type = 0; + + if (ephy_shell_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyShellClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_shell_class_init, + NULL, + NULL, /* class_data */ + sizeof (EphyShell), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_shell_init + }; + + ephy_shell_type = g_type_register_static (G_TYPE_OBJECT, + "EphyShell", + &our_info, 0); + } + + return ephy_shell_type; + +} + +static void +ephy_shell_class_init (EphyShellClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_shell_finalize; +} + +static void +ephy_shell_new_window_cb (EphyEmbedShell *shell, + EphyEmbed **new_embed, + EmbedChromeMask chromemask, + gpointer data) +{ + EphyTab *new_tab; + EphyWindow *window; + gboolean open_in_tab; + + g_assert (new_embed != NULL); + + open_in_tab = (chromemask & EMBED_CHROME_OPENASCHROME) ? + FALSE : + eel_gconf_get_boolean (CONF_TABS_TABBED_POPUPS); + + if (open_in_tab) + { + window = ephy_shell_get_active_window (ephy_shell); + } + else + { + window = ephy_window_new (); + ephy_window_set_chrome (window, chromemask); + } + + new_tab = ephy_tab_new (); + ephy_window_add_tab (window, new_tab, FALSE); + *new_embed = ephy_tab_get_embed (new_tab); +} + +static void +ephy_shell_init (EphyShell *gs) +{ + ephy_shell = gs; + g_object_add_weak_pointer (G_OBJECT(ephy_shell), + (gpointer *)&ephy_shell); + + ephy_thread_helpers_init (); + ephy_node_system_init (); + ephy_file_helpers_init (); + ephy_stock_icons_init (); + ephy_ensure_dir_exists (ephy_dot_dir ()); + + gs->priv = g_new0 (EphyShellPrivate, 1); + gs->priv->session = NULL; + gs->priv->bookmarks = NULL; + + gs->priv->embed_shell = ephy_embed_shell_new ("mozilla"); + + g_assert (gs->priv->embed_shell != NULL); + + g_signal_connect (G_OBJECT(embed_shell), + "new_window_orphan", + G_CALLBACK(ephy_shell_new_window_cb), + NULL); + + ephy_init_services (gs); +} + +static void +ephy_shell_finalize (GObject *object) +{ + EphyShell *gs; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_EPHY_SHELL (object)); + + gs = EPHY_SHELL (object); + + g_return_if_fail (gs->priv != NULL); + + g_assert (ephy_shell == NULL); + + g_return_if_fail (IS_EPHY_EMBED_SHELL (gs->priv->embed_shell)); + g_object_unref (G_OBJECT (gs->priv->embed_shell)); + + if (gs->priv->session) + { + g_return_if_fail (IS_SESSION(gs->priv->session)); + g_object_remove_weak_pointer + (G_OBJECT(gs->priv->session), + (gpointer *)&gs->priv->session); + g_object_unref (G_OBJECT (gs->priv->session)); + } + + if (gs->priv->autocompletion) + { + g_object_unref (gs->priv->autocompletion); + } + + if (gs->priv->bookmarks) + { + g_object_unref (gs->priv->bookmarks); + } + + ephy_file_helpers_shutdown (); + ephy_node_system_shutdown (); + + g_free (gs->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); + +#ifdef DEBUG_MARCO + g_print ("Ephy shell finalized\n"); +#endif + + bonobo_main_quit (); + +#ifdef DEBUG_MARCO + g_print ("Bonobo quit done\n"); +#endif +} + +EphyShell * +ephy_shell_new (void) +{ + return EPHY_SHELL (g_object_new (EPHY_SHELL_TYPE, NULL)); +} + +/** + * ephy_shell_get_embed_shell: + * @gs: a #EphyShell + * + * Returns the embed shell created by the #EphyShell + * + * Return value: the embed shell + **/ +EphyEmbedShell * +ephy_shell_get_embed_shell (EphyShell *gs) +{ + g_return_val_if_fail (IS_EPHY_SHELL (gs), NULL); + + return gs->priv->embed_shell; +} + +static void +ephy_init_services (EphyShell *gs) +{ + /* preload the prefs */ + /* it also enables notifiers support */ + eel_gconf_monitor_add ("/apps/epiphany"); + eel_gconf_monitor_add ("/apps/nautilus/preferences"); + +#ifdef ENABLE_NAUTILUS_VIEW + + ephy_nautilus_view_init_factory (gs); + +#endif + +} + +static char * +build_homepage_url (EphyShell *gs, + EphyEmbed *previous_embed) +{ + const gchar *last_page_url; + gchar *home_page_url; + gint page_type; + EphyHistory *gh; + char *result = NULL; + + if (previous_embed == NULL) + { + page_type = STARTPAGE_HOME; + } + else + { + page_type = eel_gconf_get_integer (CONF_GENERAL_NEWPAGE_TYPE); + } + + /* return the appropriate page */ + if (page_type == STARTPAGE_HOME) + { + /* get location of home page */ + home_page_url = eel_gconf_get_string(CONF_GENERAL_HOMEPAGE); + result = home_page_url; + } + else if (page_type == STARTPAGE_LAST) + { + if (previous_embed != NULL) + { + ephy_embed_get_location (previous_embed, + TRUE, TRUE, + &result); + } + + if (result == NULL) + { + /* get location of last page */ + gh = ephy_embed_shell_get_global_history + (gs->priv->embed_shell); + last_page_url = ephy_history_get_last_page (gh); + result = g_strdup (last_page_url); + } + } + + if (result == NULL) + { + /* even in case of error, it's a good default */ + result = g_strdup ("about:blank"); + } + + return result; +} + +/** + * ephy_shell_get_active_window: + * @gs: a #EphyShell + * + * Get the current active window. Use it when you + * need to take an action (like opening an url) on + * a window but you dont have a target window. + * Ex. open a new tab from command line. + * + * Return value: the current active window + **/ +EphyWindow * +ephy_shell_get_active_window (EphyShell *gs) +{ + Session *session; + GList *windows; + + session = ephy_shell_get_session (gs); + windows = session_get_windows (session); + + if (windows == NULL) return NULL; + + return EPHY_WINDOW(windows->data); +} + +/** + * ephy_shell_new_tab: + * @shell: a #EphyShell + * @parent_window: the target #EphyWindow or %NULL + * @previous_tab: the referrer tab or %NULL + * @url: an url to load or %NULL + * + * Create a new tab and the parent window when necessary. + * Ever use this function to open urls in new window/tabs. + * + * ReturnValue: the created #EphyTab + **/ +EphyTab * +ephy_shell_new_tab (EphyShell *shell, + EphyWindow *parent_window, + EphyTab *previous_tab, + const char *url, + EphyNewTabFlags flags) +{ + EphyWindow *window; + EphyTab *tab; + EphyEmbed *embed; + gboolean in_new_window; + gboolean jump_to; + EphyEmbed *previous_embed = NULL; + + in_new_window = !eel_gconf_get_boolean (CONF_TABS_TABBED); + + if (flags & EPHY_NEW_TAB_IN_NEW_WINDOW) in_new_window = TRUE; + if (flags & EPHY_NEW_TAB_IN_EXISTING_WINDOW) in_new_window = FALSE; + + jump_to = eel_gconf_get_boolean (CONF_TABS_TABBED_AUTOJUMP); + + if (flags & EPHY_NEW_TAB_JUMP) jump_to = TRUE; + if (flags & EPHY_NEW_TAB_DONT_JUMP_TO) jump_to = FALSE; + + if (!in_new_window && parent_window != NULL) + { + window = parent_window; + } + else + { + window = ephy_window_new (); + } + + if (previous_tab) + { + previous_embed = ephy_tab_get_embed (previous_tab); + } + + tab = ephy_tab_new (); + embed = ephy_tab_get_embed (tab); + gtk_widget_show (GTK_WIDGET(embed)); + ephy_window_add_tab (window, tab, + jump_to); + gtk_widget_show (GTK_WIDGET(window)); + + if (flags & EPHY_NEW_TAB_HOMEPAGE) + { + char *homepage; + + homepage = build_homepage_url (shell, previous_embed); + g_assert (homepage != NULL); + + ephy_embed_load_url (embed, homepage); + + g_free (homepage); + } + else if ((flags & EPHY_NEW_TAB_IS_A_COPY) || + (flags & EPHY_NEW_TAB_VIEW_SOURCE)) + { + EmbedDisplayType display_type = + (flags & EPHY_NEW_TAB_VIEW_SOURCE) ? + DISPLAY_AS_SOURCE : DISPLAY_NORMAL; + EphyEmbed *source = ephy_tab_get_embed(previous_tab); + ephy_embed_load_url (embed, "about:blank"); + ephy_embed_copy_page (embed, source, display_type); + } + else if (url) + { + ephy_embed_load_url (embed, url); + } + + return tab; +} + +#ifdef ENABLE_NAUTILUS_VIEW + +static void +ephy_nautilus_view_init_factory (EphyShell *gs) +{ + BonoboGenericFactory *ephy_nautilusview_factory; + ephy_nautilusview_factory = bonobo_generic_factory_new + (EPHY_NAUTILUS_VIEW_OAFIID, + (BonoboFactoryCallback) ephy_nautilus_view_new, gs); + if (!BONOBO_IS_GENERIC_FACTORY (ephy_nautilusview_factory)) + g_warning ("Couldn't create the factory!"); + +} + +static BonoboObject * +ephy_nautilus_view_new (BonoboGenericFactory *factory, const char *id, + EphyShell *gs) +{ + return ephy_nautilus_view_new_component (gs); +} + +#endif + +/** + * ephy_shell_get_session: + * @gs: a #EphyShell + * + * Returns current session. + * + * Return value: the current session. + **/ +Session * +ephy_shell_get_session (EphyShell *gs) +{ + if (!gs->priv->session) + { + gs->priv->session = session_new (); + g_object_add_weak_pointer + (G_OBJECT(gs->priv->session), + (gpointer *)&gs->priv->session); + } + + return gs->priv->session; +} + +EphyAutocompletion * +ephy_shell_get_autocompletion (EphyShell *gs) +{ + EphyShellPrivate *p = gs->priv; + + if (!p->autocompletion) + { + static const gchar *prefixes[] = { + EPHY_AUTOCOMPLETION_USUAL_WEB_PREFIXES, + NULL + }; + + EphyHistory *gh = ephy_embed_shell_get_global_history (gs->priv->embed_shell); + EphyFilesystemAutocompletion *fa = ephy_filesystem_autocompletion_new (); + p->autocompletion = ephy_autocompletion_new (); + ephy_autocompletion_set_prefixes (p->autocompletion, prefixes); + + ephy_autocompletion_add_source (p->autocompletion, + EPHY_AUTOCOMPLETION_SOURCE (gh)); + ephy_autocompletion_add_source (p->autocompletion, + EPHY_AUTOCOMPLETION_SOURCE (fa)); + ephy_autocompletion_add_source (p->autocompletion, + EPHY_AUTOCOMPLETION_SOURCE (gs->priv->bookmarks)); + + g_object_unref (fa); + g_object_unref (gs->priv->bookmarks); + } + return p->autocompletion; +} + +EphyBookmarks * +ephy_shell_get_bookmarks (EphyShell *gs) +{ + if (gs->priv->bookmarks == NULL) + { + gs->priv->bookmarks = ephy_bookmarks_new (); + } + + return gs->priv->bookmarks; +} diff --git a/src/ephy-shell.h b/src/ephy-shell.h new file mode 100644 index 000000000..3590931f9 --- /dev/null +++ b/src/ephy-shell.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_SHELL_H +#define EPHY_SHELL_H + +#include "ephy-autocompletion.h" +#include "prefs-dialog.h" +#include "downloader-view.h" +#include "ephy-embed-shell.h" +#include "session.h" +#include "ephy-bookmarks.h" + +#include <glib-object.h> +#include <glib.h> + +G_BEGIN_DECLS + +#ifndef EPHY_SHELL_TYPE_DEF +typedef struct EphyShell EphyShell; +#define EPHY_SHELL_TYPE_DEF +#endif + +typedef struct EphyShellClass EphyShellClass; + +#define EPHY_SHELL_TYPE (ephy_shell_get_type ()) +#define EPHY_SHELL(obj) (GTK_CHECK_CAST ((obj), EPHY_SHELL_TYPE, EphyShell)) +#define EPHY_SHELL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_SHELL, EphyShellClass)) +#define IS_EPHY_SHELL(obj) (GTK_CHECK_TYPE ((obj), EPHY_SHELL_TYPE)) +#define IS_EPHY_SHELL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_SHELL)) + +typedef struct EphyShellPrivate EphyShellPrivate; + +extern EphyShell *ephy_shell; + +typedef enum +{ + EPHY_NEW_TAB_HOMEPAGE = 1 << 0, + EPHY_NEW_TAB_FULLSCREEN = 1 << 1, + EPHY_NEW_TAB_APPEND = 1 << 2, + EPHY_NEW_TAB_PREPEND = 1 << 3, + EPHY_NEW_TAB_APPEND_AFTER_CURRENT = 1 << 4, + EPHY_NEW_TAB_JUMP = 1 << 5, + EPHY_NEW_TAB_DONT_JUMP_TO = 1 << 6, + EPHY_NEW_TAB_RAISE_WINDOW = 1 << 7, + EPHY_NEW_TAB_DONT_RAISE_WINDOW = 1 << 8, + EPHY_NEW_TAB_IN_NEW_WINDOW = 1 << 9, + EPHY_NEW_TAB_IN_EXISTING_WINDOW = 1 << 10, + EPHY_NEW_TAB_IS_A_COPY = 1 << 11, + EPHY_NEW_TAB_VIEW_SOURCE = 1 << 12 +} EphyNewTabFlags; + +struct EphyShell +{ + GObject parent; + EphyShellPrivate *priv; +}; + +struct EphyShellClass +{ + GObjectClass parent_class; +}; + +GType ephy_shell_get_type (void); + +EphyShell *ephy_shell_new (void); + +EphyEmbedShell *ephy_shell_get_embed_shell (EphyShell *gs); + +EphyWindow *ephy_shell_get_active_window (EphyShell *gs); + +EphyTab *ephy_shell_new_tab (EphyShell *shell, + EphyWindow *parent_window, + EphyTab *previous_tab, + const char *url, + EphyNewTabFlags flags); + +Session *ephy_shell_get_session (EphyShell *gs); + +EphyAutocompletion *ephy_shell_get_autocompletion (EphyShell *gs); + +EphyBookmarks *ephy_shell_get_bookmarks (EphyShell *gs); + +G_END_DECLS + +#endif diff --git a/src/ephy-tab.c b/src/ephy-tab.c new file mode 100644 index 000000000..b1fe71fb6 --- /dev/null +++ b/src/ephy-tab.c @@ -0,0 +1,945 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define DEBUG_MSG(x) g_print x +//#define DEBUG_MSG(x) + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); + +#include "ephy-tab.h" +#include "ephy-shell.h" +#include "ephy-embed-popup-bw.h" +#include "eel-gconf-extensions.h" +#include "ephy-prefs.h" +#include "ephy-embed-prefs.h" + +#include <bonobo/bonobo-i18n.h> +#include <libgnomevfs/gnome-vfs-uri.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkbutton.h> +#include <gtk/gtkstock.h> +#include <gtk/gtkmisc.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtkimage.h> +#include <gtk/gtkiconfactory.h> +#include <gtk/gtkstyle.h> +#include <gtk/gtkselection.h> +#include <string.h> + +struct EphyTabPrivate +{ + EphyEmbed *embed; + EphyWindow *window; + gboolean is_active; + TabLoadStatus load_status; + char status_message[255]; + char *title; + char *location; + int load_percent; + gboolean visibility; + int cur_requests; + int total_requests; + int width; + int height; +}; + +static void +ephy_tab_class_init (EphyTabClass *klass); +static void +ephy_tab_init (EphyTab *tab); +static void +ephy_tab_finalize (GObject *object); + +enum +{ + PROP_0, + PROP_EPHY_SHELL +}; + +static void +ephy_tab_link_message_cb (EphyEmbed *embed, + const char *message, + EphyTab *tab); +static void +ephy_tab_js_status_cb (EphyEmbed *embed, + const char *status, + EphyTab *tab); +static void +ephy_tab_location_cb (EphyEmbed *embed, EphyTab *tab); +static void +ephy_tab_title_cb (EphyEmbed *embed, EphyTab *tab); +static void +ephy_tab_net_state_cb (EphyEmbed *embed, const char *uri, + EmbedState state, EphyTab *tab); +static void +ephy_tab_new_window_cb (EphyEmbed *embed, EphyEmbed **new_embed, + EmbedChromeMask chromemask, EphyTab *tab); +static void +ephy_tab_visibility_cb (EphyEmbed *embed, gboolean visibility, + EphyTab *tab); +static void +ephy_tab_destroy_brsr_cb (EphyEmbed *embed, EphyTab *tab); +static gint +ephy_tab_open_uri_cb (EphyEmbed *embed, const char *uri, + EphyTab *tab); +static void +ephy_tab_size_to_cb (EphyEmbed *embed, gint width, gint height, + EphyTab *tab); +static gint +ephy_tab_dom_mouse_click_cb (EphyEmbed *embed, + EphyEmbedEvent *event, + EphyTab *tab); +static gint +ephy_tab_dom_mouse_down_cb (EphyEmbed *embed, + EphyEmbedEvent *event, + EphyTab *tab); +static void +ephy_tab_security_change_cb (EphyEmbed *embed, EmbedSecurityLevel level, + EphyTab *tab); +static void +ephy_tab_zoom_changed_cb (EphyEmbed *embed, gint zoom, + EphyTab *tab); + +static GObjectClass *parent_class = NULL; + +/* Class functions */ + +GType +ephy_tab_get_type (void) +{ + static GType ephy_tab_type = 0; + + if (ephy_tab_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyTabClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_tab_class_init, + NULL, + NULL, /* class_data */ + sizeof (EphyTab), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_tab_init + }; + + ephy_tab_type = g_type_register_static (G_TYPE_OBJECT, + "EphyTab", + &our_info, 0); + } + + return ephy_tab_type; +} + +static void +ephy_tab_class_init (EphyTabClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_tab_finalize; +} + +static void +ephy_tab_parent_set_cb (GtkWidget *widget, GtkWidget *previous_parent, + EphyTab *tab) +{ + GtkWidget *toplevel; + + /* FIXME maybe we dont need to set the tab parent explicitly + * anymore with this callback taking care of it */ + + if (widget->parent == NULL) return; + + toplevel = gtk_widget_get_toplevel (widget); + + tab->priv->window = EPHY_WINDOW (toplevel); +} + +static void +ephy_tab_embed_destroy_cb (GtkWidget *widget, EphyTab *tab) +{ +#ifdef DEBUG_MARCO + g_print ("GtkMozEmbed destroy signal on EphyTab\n"); +#endif + g_object_unref (tab); +} + +static void +ephy_tab_init (EphyTab *tab) +{ + GObject *embed, *embed_widget; + EphyEmbedShell *shell; + + tab->priv = g_new0 (EphyTabPrivate, 1); + + shell = ephy_shell_get_embed_shell (ephy_shell); + + tab->priv->embed = ephy_embed_new (G_OBJECT(shell)); + + tab->priv->window = NULL; + tab->priv->is_active = FALSE; + *tab->priv->status_message = '\0'; + tab->priv->load_status = TAB_LOAD_NONE; + tab->priv->load_percent = 0; + tab->priv->title = NULL; + tab->priv->location = NULL; + tab->priv->total_requests = 0; + tab->priv->cur_requests = 0; + tab->priv->width = -1; + tab->priv->height = -1; + + + embed = G_OBJECT (tab->priv->embed); + embed_widget = G_OBJECT (tab->priv->embed); + + /* set a pointer in the embed's widget back to the tab */ + g_object_set_data (embed_widget, "EphyTab", tab); + + g_signal_connect (embed_widget, "parent_set", + G_CALLBACK (ephy_tab_parent_set_cb), + tab); + g_signal_connect (embed_widget, "destroy", + GTK_SIGNAL_FUNC (ephy_tab_embed_destroy_cb), + tab); + g_signal_connect (embed, "ge_link_message", + GTK_SIGNAL_FUNC (ephy_tab_link_message_cb), + tab); + g_signal_connect (embed, "ge_js_status", + GTK_SIGNAL_FUNC (ephy_tab_js_status_cb), + tab); + g_signal_connect (embed, "ge_location", + GTK_SIGNAL_FUNC (ephy_tab_location_cb), + tab); + g_signal_connect (embed, "ge_title", + GTK_SIGNAL_FUNC (ephy_tab_title_cb), + tab); + g_signal_connect (embed, "ge_zoom_change", + GTK_SIGNAL_FUNC (ephy_tab_zoom_changed_cb), + tab); + g_signal_connect (embed, "ge_net_state", + GTK_SIGNAL_FUNC (ephy_tab_net_state_cb), + tab); + g_signal_connect (embed, "ge_new_window", + GTK_SIGNAL_FUNC (ephy_tab_new_window_cb), + tab); + g_signal_connect (embed, "ge_visibility", + GTK_SIGNAL_FUNC (ephy_tab_visibility_cb), + tab); + g_signal_connect (embed, "ge_destroy_brsr", + GTK_SIGNAL_FUNC (ephy_tab_destroy_brsr_cb), + tab); + g_signal_connect (embed, "ge_open_uri", + GTK_SIGNAL_FUNC (ephy_tab_open_uri_cb), + tab); + g_signal_connect (embed, "ge_size_to", + GTK_SIGNAL_FUNC (ephy_tab_size_to_cb), + tab); + g_signal_connect (embed, "ge_dom_mouse_click", + GTK_SIGNAL_FUNC (ephy_tab_dom_mouse_click_cb), + tab); + g_signal_connect (embed, "ge_dom_mouse_down", + GTK_SIGNAL_FUNC (ephy_tab_dom_mouse_down_cb), + tab); + g_signal_connect (embed, "ge_security_change", + GTK_SIGNAL_FUNC (ephy_tab_security_change_cb), + tab); +} + +/* Destructor */ + +static void +ephy_tab_finalize (GObject *object) +{ + EphyTab *tab; + + g_return_if_fail (IS_EPHY_TAB (object)); + + tab = EPHY_TAB (object); + + g_return_if_fail (tab->priv != NULL); + + g_idle_remove_by_data (tab->priv->embed); + + g_free (tab->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); + +#ifdef DEBUG_MARCO + g_print ("EphyTab finalized %p\n", tab); +#endif +} + +/* Public functions */ + +EphyTab * +ephy_tab_new () +{ + EphyTab *tab; + + tab = EPHY_TAB (g_object_new (EPHY_TAB_TYPE, NULL)); + g_return_val_if_fail (tab->priv != NULL, NULL); + return tab; +} + +static void +ephy_tab_set_load_status (EphyTab *tab, + TabLoadStatus status) +{ + if (status == TAB_LOAD_COMPLETED) + { + Session *s; + s = ephy_shell_get_session (ephy_shell); + session_save (s, SESSION_CRASHED); + } + + if (ephy_tab_get_is_active (tab) && + status == TAB_LOAD_COMPLETED) + { + tab->priv->load_status = TAB_LOAD_NONE; + } + else + { + tab->priv->load_status = status; + } +} + +EphyEmbed * +ephy_tab_get_embed (EphyTab *tab) +{ + g_return_val_if_fail (IS_EPHY_TAB (G_OBJECT (tab)), NULL); + + return tab->priv->embed; +} + +void +ephy_tab_set_window (EphyTab *tab, EphyWindow *window) +{ + g_return_if_fail (IS_EPHY_TAB (G_OBJECT (tab))); + if (window) g_return_if_fail (IS_EPHY_WINDOW (G_OBJECT (window))); + + tab->priv->window = window; +} + +EphyWindow * +ephy_tab_get_window (EphyTab *tab) +{ + g_return_val_if_fail (IS_EPHY_TAB (G_OBJECT (tab)), NULL); + + return tab->priv->window; +} + +static void +ephy_tab_update_color (EphyTab *tab) +{ + TabLoadStatus status = ephy_tab_get_load_status (tab); + EphyNotebookPageLoadStatus page_status = 0; + GtkWidget *nb; + + nb = ephy_window_get_notebook (tab->priv->window); + + switch (status) + { + case TAB_LOAD_NONE: + page_status = EPHY_NOTEBOOK_TAB_LOAD_NORMAL; + break; + case TAB_LOAD_STARTED: + page_status = EPHY_NOTEBOOK_TAB_LOAD_LOADING; + break; + case TAB_LOAD_COMPLETED: + page_status = EPHY_NOTEBOOK_TAB_LOAD_COMPLETED; + break; + } + + ephy_notebook_set_page_status (EPHY_NOTEBOOK (nb), + GTK_WIDGET (tab->priv->embed), + page_status); +} + +void +ephy_tab_set_is_active (EphyTab *tab, gboolean is_active) +{ + TabLoadStatus status; + + g_return_if_fail (IS_EPHY_TAB (G_OBJECT (tab))); + + tab->priv->is_active = is_active; + + status = ephy_tab_get_load_status (tab); + if (status == TAB_LOAD_COMPLETED) + { + ephy_tab_set_load_status (tab, TAB_LOAD_NONE); + } + ephy_tab_update_color (tab); +} + +gboolean +ephy_tab_get_is_active (EphyTab *tab) +{ + g_return_val_if_fail (IS_EPHY_TAB (G_OBJECT (tab)), FALSE); + + return tab->priv->is_active; +} + +gboolean +ephy_tab_get_visibility (EphyTab *tab) +{ + return tab->priv->visibility; +} + +void +ephy_tab_get_size (EphyTab *tab, int *width, int *height) +{ + *width = tab->priv->width; + *height = tab->priv->height; +} + +static void +ephy_tab_set_visibility (EphyTab *tab, + gboolean visible) +{ + g_return_if_fail (tab->priv->window != NULL); + + /* FIXME show/hide the tab widget */ + + tab->priv->visibility = visible; +} + +/* Private callbacks for embed signals */ + +static void +ephy_tab_link_message_cb (EphyEmbed *embed, + const char *message, + EphyTab *tab) +{ + if (!tab->priv->is_active) return; + + g_strlcpy (tab->priv->status_message, + message, 255); + + ephy_window_update_control (tab->priv->window, + StatusbarMessageControl); +} + +static void +ephy_tab_js_status_cb (EphyEmbed *embed, + const char *status, + EphyTab *tab) +{ + if (!tab->priv->is_active) + return; + + g_strlcpy (tab->priv->status_message, + status, 255); + + ephy_window_update_control (tab->priv->window, + StatusbarMessageControl); +} + +static void +ephy_tab_location_cb (EphyEmbed *embed, EphyTab *tab) +{ + if (tab->priv->location) g_free (tab->priv->location); + ephy_embed_get_location (embed, TRUE, FALSE, + &tab->priv->location); + + if (tab->priv->is_active) + { + ephy_window_update_control (tab->priv->window, LocationControl); + ephy_window_update_control (tab->priv->window, NavControl); + } +} + +static void +ephy_tab_zoom_changed_cb (EphyEmbed *embed, gint zoom, EphyTab *tab) +{ + if (tab->priv->is_active) + { + ephy_window_update_control (tab->priv->window, ZoomControl); + } +} + +static void +ephy_tab_set_title (EphyTab *tab, const char *title) +{ + GtkWidget *nb; + + nb = ephy_window_get_notebook (tab->priv->window); + ephy_notebook_set_page_title (EPHY_NOTEBOOK (nb), + GTK_WIDGET (tab->priv->embed), + title); +} + +static void +ephy_tab_title_cb (EphyEmbed *embed, EphyTab *tab) +{ + if (tab->priv->title) g_free (tab->priv->title); + ephy_embed_get_title (embed, &tab->priv->title); + + if (*(tab->priv->title) == '\0') + { + g_free (tab->priv->title); + tab->priv->title = g_strdup (_("Untitled")); + } + + ephy_tab_set_title (tab, tab->priv->title); + + if (tab->priv->is_active) + { + ephy_window_update_control (tab->priv->window, + TitleControl); + } +} + +static int +build_load_percent (int bytes_loaded, int max_bytes_loaded) +{ + if (max_bytes_loaded > 0) + { + return (bytes_loaded * 100) / max_bytes_loaded; + } + else + { + return -1; + } +} + +static char * +get_host_name_from_uri (const char *uri) +{ + GnomeVFSURI *vfs_uri = NULL; + const char *host = NULL; + char *result; + + if (uri) + { + vfs_uri = gnome_vfs_uri_new (uri); + } + + if (vfs_uri) + { + host = gnome_vfs_uri_get_host_name (vfs_uri); + } + + if (!host) + { + host = _("site"); + } + + result = g_strdup (host); + + if (vfs_uri) gnome_vfs_uri_unref (vfs_uri); + + return result; +} + +static void +build_net_state_message (char *message, + const char *uri, + EmbedState flags) +{ + const char *msg = NULL; + char *host; + + host = get_host_name_from_uri (uri); + + /* IS_REQUEST and IS_NETWORK can be both set */ + + if (flags & EMBED_STATE_IS_REQUEST) + { + if (flags & EMBED_STATE_REDIRECTING) + { + msg = _("Redirecting to %s..."); + } + else if (flags & EMBED_STATE_TRANSFERRING) + { + msg = _("Transferring data from %s..."); + } + else if (flags & EMBED_STATE_NEGOTIATING) + { + msg = _("Waiting for authorization from %s..."); + } + } + + if (flags & EMBED_STATE_IS_NETWORK) + { + if (flags & EMBED_STATE_START) + { + msg = _("Loading %s..."); + } + else if (flags & EMBED_STATE_STOP) + { + msg = _("Done."); + } + } + + if (msg) + { + g_snprintf (message, 255, msg, host); + } + + g_free (host); +} + +static void +build_progress_from_requests (EphyTab *tab, EmbedState state) +{ + int load_percent; + + if (state & EMBED_STATE_IS_REQUEST) + { + if (state & EMBED_STATE_START) + { + tab->priv->total_requests ++; + } + else if (state & EMBED_STATE_STOP) + { + tab->priv->cur_requests ++; + } + + load_percent = build_load_percent (tab->priv->cur_requests, + tab->priv->total_requests); + if (load_percent > tab->priv->load_percent) + { + tab->priv->load_percent = load_percent; + } + } +} + +static void +ensure_location (EphyTab *tab, const char *uri) +{ + if (tab->priv->location == NULL) + { + tab->priv->location = g_strdup (uri); + ephy_window_update_control (tab->priv->window, + LocationControl); + } +} + +static void +ephy_tab_net_state_cb (EphyEmbed *embed, const char *uri, + EmbedState state, EphyTab *tab) +{ + build_net_state_message (tab->priv->status_message, uri, state); + + ephy_window_update_control (tab->priv->window, + StatusbarMessageControl); + + if (state & EMBED_STATE_IS_NETWORK) + { + if (state & EMBED_STATE_START) + { + tab->priv->total_requests = 0; + tab->priv->cur_requests = 0; + tab->priv->load_percent = 0; + + ensure_location (tab, uri); + + ephy_tab_set_load_status (tab, TAB_LOAD_STARTED); + + ephy_window_update_control (tab->priv->window, + NavControl); + ephy_window_update_control (tab->priv->window, + SpinnerControl); + ephy_tab_update_color (tab); + } + else if (state & EMBED_STATE_STOP) + { + tab->priv->load_percent = 0; + + ephy_tab_set_load_status (tab, TAB_LOAD_COMPLETED); + + ephy_window_update_control (tab->priv->window, + NavControl); + ephy_window_update_control (tab->priv->window, + SpinnerControl); + ephy_tab_update_color (tab); + } + } + + build_progress_from_requests (tab, state); + + ephy_window_update_control (tab->priv->window, + StatusbarProgressControl); +} + +static void +ephy_tab_new_window_cb (EphyEmbed *embed, EphyEmbed **new_embed, + EmbedChromeMask chromemask, EphyTab *tab) +{ + EphyTab *new_tab; + EphyWindow *window; + gboolean open_in_tab; + + open_in_tab = (chromemask & EMBED_CHROME_OPENASCHROME) ? + FALSE : + eel_gconf_get_boolean (CONF_TABS_TABBED_POPUPS); + + if (open_in_tab) + { + window = ephy_tab_get_window (tab); + } + else + { + window = ephy_window_new (); + ephy_window_set_chrome (window, chromemask); + } + + new_tab = ephy_tab_new (); + ephy_window_add_tab (window, new_tab, FALSE); + + *new_embed = ephy_tab_get_embed (new_tab); +} + +static gboolean +let_me_resize_hack (gpointer data) +{ + gtk_widget_set_size_request (GTK_WIDGET(data), + -1, -1); + return FALSE; +} + +static void +ephy_tab_visibility_cb (EphyEmbed *embed, gboolean visibility, + EphyTab *tab) +{ + EphyWindow *window; + + if (visibility) + { + gtk_widget_show (GTK_WIDGET(embed)); + } + else + { + gtk_widget_hide (GTK_WIDGET(embed)); + } + + ephy_tab_set_visibility (tab, visibility); + + window = ephy_tab_get_window (tab); + g_return_if_fail (window != NULL); + + ephy_window_update_control (window, WindowVisibilityControl); +} + +static void +ephy_tab_destroy_brsr_cb (EphyEmbed *embed, EphyTab *tab) +{ + EphyWindow *window; + + window = ephy_tab_get_window (tab); + + ephy_window_remove_tab (window, tab); +} + +static gint +ephy_tab_open_uri_cb (EphyEmbed *embed, const char *uri, + EphyTab *tab) +{ + return FALSE; +} + +static void +ephy_tab_size_to_cb (EphyEmbed *embed, gint width, gint height, + EphyTab *tab) +{ + GList *tabs; + EphyWindow *window; + GtkWidget *widget; + EmbedChromeMask chromemask; + + tab->priv->width = width; + tab->priv->height = height; + + window = ephy_tab_get_window (tab); + tabs = (GList *) ephy_window_get_tabs (window); + widget = GTK_WIDGET (embed); + chromemask = ephy_window_get_chrome (window); + + /* Do not resize window with multiple tabs. + * Do not resize window already showed because + * it's not possible to calculate a sensible window + * size based on the embed size */ + if (g_list_length (tabs) == 1 && !tab->priv->visibility) + { + gtk_widget_set_size_request + (widget, width, height); + + /* HACK reset widget requisition after the container + * has been resized. It appears to be the only way + * to have the window sized according to embed + * size correctly. + * We dont do it for XUL dialogs because in that case + * a "forced" requisition appear correct. + */ + if (!(chromemask & EMBED_CHROME_OPENASCHROME)) + { + g_idle_add (let_me_resize_hack, embed); + } + } +} + +static gint +ephy_tab_dom_mouse_click_cb (EphyEmbed *embed, + EphyEmbedEvent *event, + EphyTab *tab) +{ + return FALSE; +} + +static void +ephy_tab_show_embed_popup (EphyTab *tab, EphyEmbedEvent *event) +{ + EphyEmbedPopup *popup; + EphyWindow *window; + EphyEmbed *embed; + + window = ephy_tab_get_window (tab); + embed = ephy_tab_get_embed (tab); + + popup = EPHY_EMBED_POPUP (ephy_window_get_popup_factory (window)); + ephy_embed_popup_set_event (popup, event); + ephy_embed_popup_show (popup, embed); +} + +static gint +ephy_tab_dom_mouse_down_cb (EphyEmbed *embed, + EphyEmbedEvent *event, + EphyTab *tab) +{ + EphyWindow *window; + int button; + EmbedEventContext context; + + g_assert (IS_EPHY_EMBED_EVENT(event)); + + window = ephy_tab_get_window (tab); + g_return_val_if_fail (window != NULL, FALSE); + + ephy_embed_event_get_mouse_button (event, &button); + ephy_embed_event_get_context (event, &context); + + if (button == 2) + { + ephy_tab_show_embed_popup (tab, event); + } + else if (button == 1 + && (context & EMBED_CONTEXT_LINK)) + { + GValue *value; + + ephy_embed_event_get_property (event, "link", &value); + ephy_shell_new_tab (ephy_shell, window, tab, + g_value_get_string (value), 0); + } + else if (button == 1 + && !(context & EMBED_CONTEXT_LINK + || context & EMBED_CONTEXT_EMAIL_LINK + || context & EMBED_CONTEXT_INPUT)) + { + /* paste url */ + gtk_selection_convert (GTK_WIDGET (window), + GDK_SELECTION_PRIMARY, + GDK_SELECTION_TYPE_STRING, + GDK_CURRENT_TIME); + } + + return FALSE; +} + +static void +ephy_tab_security_change_cb (EphyEmbed *embed, EmbedSecurityLevel level, + EphyTab *tab) +{ + if (!tab->priv->is_active) return; + + ephy_window_update_control (tab->priv->window, + StatusbarSecurityControl); +} + +TabLoadStatus +ephy_tab_get_load_status (EphyTab *tab) +{ + return tab->priv->load_status; +} + +int +ephy_tab_get_load_percent (EphyTab *tab) +{ + return tab->priv->load_percent; +} + +const char * +ephy_tab_get_status_message (EphyTab *tab) +{ + if (tab->priv->status_message) + { + return tab->priv->status_message; + } + else + { + return " "; + } +} + +const char * +ephy_tab_get_title (EphyTab *tab) +{ + if (tab->priv->title && + g_utf8_strlen(tab->priv->title, -1)) + { + return tab->priv->title; + } + else + { + return _("Untitled"); + } +} + +const char * +ephy_tab_get_location (EphyTab *tab) +{ + return tab->priv->location; +} + +void +ephy_tab_set_location (EphyTab *tab, + char *location) +{ + if (tab->priv->location) g_free (tab->priv->location); + tab->priv->location = location; +} + +void +ephy_tab_update_control (EphyTab *tab, + TabControlID id) +{ + switch (id) + { + case TAB_CONTROL_TITLE: + ephy_tab_set_title (tab, tab->priv->title); + break; + } +} diff --git a/src/ephy-tab.h b/src/ephy-tab.h new file mode 100644 index 000000000..02e06746f --- /dev/null +++ b/src/ephy-tab.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_TAB_H +#define EPHY_TAB_H + +#include "ephy-embed.h" + +#include <glib-object.h> + +G_BEGIN_DECLS + +typedef struct EphyTabClass EphyTabClass; + +#define EPHY_TAB_TYPE (ephy_tab_get_type ()) +#define EPHY_TAB(obj) (GTK_CHECK_CAST ((obj), EPHY_TAB_TYPE, EphyTab)) +#define EPHY_TAB_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_TAB, EphyTabClass)) +#define IS_EPHY_TAB(obj) (GTK_CHECK_TYPE ((obj), EPHY_TAB_TYPE)) +#define IS_EPHY_TAB_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_TAB)) + +typedef struct EphyTab EphyTab; +typedef struct EphyTabPrivate EphyTabPrivate; + +typedef enum +{ + TAB_CONTROL_TITLE +} TabControlID; + +typedef enum +{ + TAB_LOAD_NONE, + TAB_LOAD_STARTED, + TAB_LOAD_COMPLETED +} TabLoadStatus; + +struct EphyTab +{ + GObject parent; + EphyTabPrivate *priv; +}; + +struct EphyTabClass +{ + GObjectClass parent_class; +}; + +/* Include the header down here to resolve circular dependency */ +#include "ephy-window.h" + +GType ephy_tab_get_type (void); + +EphyTab *ephy_tab_new (void); + +EphyEmbed *ephy_tab_get_embed (EphyTab *tab); + +void ephy_tab_set_window (EphyTab *tab, + EphyWindow *window); + +EphyWindow *ephy_tab_get_window (EphyTab *tab); + +void ephy_tab_set_is_active (EphyTab *tab, + gboolean is_active); + +gboolean ephy_tab_get_is_active (EphyTab *tab); + +gboolean ephy_tab_get_visibility (EphyTab *tab); + +TabLoadStatus ephy_tab_get_load_status (EphyTab *tab); + +int ephy_tab_get_load_percent (EphyTab *tab); + +const char *ephy_tab_get_status_message (EphyTab *tab); + +const char *ephy_tab_get_title (EphyTab *tab); + +const char *ephy_tab_get_location (EphyTab *tab); + +void ephy_tab_set_location (EphyTab *tab, + char *location); + +void ephy_tab_get_size (EphyTab *tab, + int *width, + int *height); + +void ephy_tab_update_control (EphyTab *tab, + TabControlID id); + +G_END_DECLS + +#endif diff --git a/src/ephy-window.c b/src/ephy-window.c new file mode 100644 index 000000000..311d6202c --- /dev/null +++ b/src/ephy-window.c @@ -0,0 +1,1428 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "ephy-window.h" +#include "ephy-favorites-menu.h" +#include "ephy-state.h" +#include "ephy-gobject-misc.h" +#include "statusbar.h" +#include "toolbar.h" +#include "ppview-toolbar.h" +#include "window-commands.h" +#include "find-dialog.h" +#include "history-dialog.h" +#include "popup-commands.h" +#include "ephy-shell.h" +#include "ephy-bonobo-extensions.h" +#include "eel-gconf-extensions.h" +#include "ephy-prefs.h" +#include "ephy-embed-utils.h" + +#include <string.h> +#include <bonobo/bonobo-window.h> +#include <bonobo/bonobo-i18n.h> +#include <bonobo/bonobo-ui-util.h> +#include <bonobo/bonobo-ui-component.h> +#include <libgnomevfs/gnome-vfs-uri.h> +#include <gtk/gtk.h> +#include <X11/X.h> +#include <X11/Xlib.h> +#include <gdk/gdkx.h> +#include <gdk/gdkkeysyms.h> + +#define CHARSET_MENU_PATH "/menu/View/EncodingMenuPlaceholder" +#define GO_FAVORITES_PATH "/menu/Go/Favorites" + +#define GO_BACK_CMD_PATH "/commands/GoBack" +#define GO_FORWARD_CMD_PATH "/commands/GoForward" +#define GO_UP_CMD_PATH "/commands/GoUp" +#define EDIT_FIND_NEXT_CMD_PATH "/commands/EditFindNext" +#define EDIT_FIND_PREV_CMD_PATH "/commands/EditFindPrev" +#define VIEW_MENUBAR_PATH "/commands/View Menubar" +#define VIEW_STATUSBAR_PATH "/commands/View Statusbar" +#define VIEW_TOOLBAR_PATH "/commands/View Toolbar" +#define VIEW_BOOKMARKSBAR_PATH "/commands/View BookmarksBar" +#define VIEW_FULLSCREEN_PATH "/commands/View Fullscreen" + +#define ID_VIEW_MENUBAR "View Menubar" +#define ID_VIEW_STATUSBAR "View Statusbar" +#define ID_VIEW_TOOLBAR "View Toolbar" +#define ID_VIEW_BOOKMARKSBAR "View BookmarksBar" +#define ID_VIEW_FULLSCREEN "View Fullscreen" + +static BonoboUIVerb ephy_verbs [] = { + BONOBO_UI_VERB ("EditFind", (BonoboUIVerbFn)window_cmd_edit_find), + BONOBO_UI_VERB ("FilePrint", (BonoboUIVerbFn)window_cmd_file_print), + BONOBO_UI_VERB ("GoStop", (BonoboUIVerbFn)window_cmd_go_stop), + BONOBO_UI_VERB ("GoReload", (BonoboUIVerbFn)window_cmd_go_reload), + BONOBO_UI_VERB ("GoBack", (BonoboUIVerbFn)window_cmd_go_back), + BONOBO_UI_VERB ("GoForward", (BonoboUIVerbFn)window_cmd_go_forward), + BONOBO_UI_VERB ("GoGo", (BonoboUIVerbFn)window_cmd_go_go), + BONOBO_UI_VERB ("GoUp", (BonoboUIVerbFn)window_cmd_go_up), + BONOBO_UI_VERB ("GoHome", (BonoboUIVerbFn)window_cmd_go_home), + BONOBO_UI_VERB ("GoMyportal", (BonoboUIVerbFn)window_cmd_go_myportal), + BONOBO_UI_VERB ("GoLocation", (BonoboUIVerbFn)window_cmd_go_location), + BONOBO_UI_VERB ("FileNew", (BonoboUIVerbFn)window_cmd_new), + BONOBO_UI_VERB ("FileNewWindow", (BonoboUIVerbFn)window_cmd_new_window), + BONOBO_UI_VERB ("FileNewTab", (BonoboUIVerbFn)window_cmd_new_tab), + BONOBO_UI_VERB ("FileOpen", (BonoboUIVerbFn)window_cmd_file_open), + BONOBO_UI_VERB ("FileSaveAs", (BonoboUIVerbFn)window_cmd_file_save_as), + BONOBO_UI_VERB ("FileCloseTab", (BonoboUIVerbFn)window_cmd_file_close_tab), + BONOBO_UI_VERB ("FileCloseWindow", (BonoboUIVerbFn)window_cmd_file_close_window), + BONOBO_UI_VERB ("FileSendTo", (BonoboUIVerbFn)window_cmd_file_send_to), + BONOBO_UI_VERB ("EditCut", (BonoboUIVerbFn)window_cmd_edit_cut), + BONOBO_UI_VERB ("EditCopy", (BonoboUIVerbFn)window_cmd_edit_copy), + BONOBO_UI_VERB ("EditPaste", (BonoboUIVerbFn)window_cmd_edit_paste), + BONOBO_UI_VERB ("EditSelectAll", (BonoboUIVerbFn)window_cmd_edit_select_all), + BONOBO_UI_VERB ("EditPrefs", (BonoboUIVerbFn)window_cmd_edit_prefs), + BONOBO_UI_VERB ("SettingsToolbarEditor", (BonoboUIVerbFn)window_cmd_settings_toolbar_editor), + BONOBO_UI_VERB ("Zoom In", (BonoboUIVerbFn)window_cmd_view_zoom_in), + BONOBO_UI_VERB ("EditFindNext", (BonoboUIVerbFn)window_cmd_edit_find_next), + BONOBO_UI_VERB ("EditFindPrev", (BonoboUIVerbFn)window_cmd_edit_find_prev), + BONOBO_UI_VERB ("Zoom Out", (BonoboUIVerbFn)window_cmd_view_zoom_out), + BONOBO_UI_VERB ("Zoom Normal", (BonoboUIVerbFn)window_cmd_view_zoom_normal), + BONOBO_UI_VERB ("ViewPageSource", (BonoboUIVerbFn)window_cmd_view_page_source), + BONOBO_UI_VERB ("BookmarksAddDefault", (BonoboUIVerbFn)window_cmd_bookmarks_add_default), + BONOBO_UI_VERB ("BookmarksEdit", (BonoboUIVerbFn)window_cmd_bookmarks_edit), + BONOBO_UI_VERB ("ToolsHistory", (BonoboUIVerbFn)window_cmd_tools_history), + BONOBO_UI_VERB ("ToolsPDM", (BonoboUIVerbFn)window_cmd_tools_pdm), + BONOBO_UI_VERB ("TabsNext", (BonoboUIVerbFn)window_cmd_tabs_next), + BONOBO_UI_VERB ("TabsPrevious", (BonoboUIVerbFn)window_cmd_tabs_previous), + BONOBO_UI_VERB ("TabsMoveLeft", (BonoboUIVerbFn)window_cmd_tabs_move_left), + BONOBO_UI_VERB ("TabsMoveRight", (BonoboUIVerbFn)window_cmd_tabs_move_right), + BONOBO_UI_VERB ("TabsDetach", (BonoboUIVerbFn)window_cmd_tabs_detach), + BONOBO_UI_VERB ("HelpContents", (BonoboUIVerbFn)window_cmd_help_manual), + BONOBO_UI_VERB ("About", (BonoboUIVerbFn)window_cmd_help_about), + + BONOBO_UI_VERB_END +}; + +static BonoboUIVerb ephy_popup_verbs [] = { + BONOBO_UI_VERB ("EPOpenInNewWindow", (BonoboUIVerbFn)popup_cmd_new_window), + BONOBO_UI_VERB ("EPOpenInNewTab", (BonoboUIVerbFn)popup_cmd_new_tab), + BONOBO_UI_VERB ("EPAddBookmark", (BonoboUIVerbFn)popup_cmd_add_bookmark), + BONOBO_UI_VERB ("EPOpenImageInNewWindow", (BonoboUIVerbFn)popup_cmd_image_in_new_window), + BONOBO_UI_VERB ("EPOpenImageInNewTab", (BonoboUIVerbFn)popup_cmd_image_in_new_tab), + BONOBO_UI_VERB ("DPOpenFrameInNewWindow", (BonoboUIVerbFn)popup_cmd_frame_in_new_window), + BONOBO_UI_VERB ("DPOpenFrameInNewTab", (BonoboUIVerbFn)popup_cmd_frame_in_new_tab), + BONOBO_UI_VERB ("DPAddFrameBookmark", (BonoboUIVerbFn)popup_cmd_add_frame_bookmark), + BONOBO_UI_VERB ("DPViewSource", (BonoboUIVerbFn)popup_cmd_view_source), + + BONOBO_UI_VERB_END +}; + +struct EphyWindowPrivate +{ + EphyFavoritesMenu *fav_menu; + PPViewToolbar *ppview_toolbar; + Toolbar *toolbar; + Statusbar *statusbar; + GtkNotebook *notebook; + EphyTab *active_tab; + GtkWidget *sidebar; + EphyEmbedPopupBW *embed_popup; + EphyDialog *find_dialog; + EphyDialog *history_dialog; + EphyDialog *history_sidebar; + EmbedChromeMask chrome_mask; + gboolean ignore_layout_toggles; + gboolean has_default_size; + gboolean closing; +}; + +static void +ephy_window_class_init (EphyWindowClass *klass); +static void +ephy_window_init (EphyWindow *gs); +static void +ephy_window_finalize (GObject *object); +static void +ephy_window_show (GtkWidget *widget); +static void +ephy_window_notebook_switch_page_cb (GtkNotebook *notebook, + GtkNotebookPage *page, + guint page_num, + EphyWindow *window); + +static void +ephy_window_tab_detached_cb (EphyNotebook *notebook, gint page, + gint x, gint y, gpointer data); + + +static GObjectClass *parent_class = NULL; + +GType +ephy_window_get_type (void) +{ + static GType ephy_window_type = 0; + + if (ephy_window_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyWindowClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_window_class_init, + NULL, + NULL, /* class_data */ + sizeof (EphyWindow), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_window_init + }; + + ephy_window_type = g_type_register_static (BONOBO_TYPE_WINDOW, + "EphyWindow", + &our_info, 0); + } + + return ephy_window_type; +} + +static void +ephy_window_class_init (EphyWindowClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_window_finalize; + + widget_class->show = ephy_window_show; +} + +static +gboolean +ephy_window_key_press_event_cb (GtkWidget *widget, + GdkEventKey *event, + EphyWindow *window) +{ + int page; + + if ((event->state & GDK_Shift_L) || (event->state & GDK_Shift_R)) + return FALSE; + + if ((event->state & GDK_Alt_L) || (event->state & GDK_Alt_R)) + { + page = event->keyval - GDK_0 -1; + + if (page == -1) page = 9; + + if (page>=-1 && page<=9) + { + gtk_notebook_set_current_page + (GTK_NOTEBOOK (window->priv->notebook), + page == -1 ? -1 : page); + return TRUE; + } + } + + return FALSE; +} + +static void +ephy_window_selection_received_cb (GtkWidget *widget, + GtkSelectionData *selection_data, + guint time, EphyWindow *window) +{ + EphyTab *tab; + + if (selection_data->length <= 0 || selection_data->data == NULL) + return; + + tab = ephy_window_get_active_tab (window); + ephy_shell_new_tab (ephy_shell, window, tab, + selection_data->data, 0); +} + +static void +save_window_state (GtkWidget *win) +{ + EphyWindow *window = EPHY_WINDOW (win); + + if (!(window->priv->chrome_mask & EMBED_CHROME_OPENASPOPUP) && + !(window->priv->chrome_mask & EMBED_CHROME_OPENASFULLSCREEN)) + { + ephy_state_save_window (win, "main_window"); + } +} + +static gboolean +ephy_window_configure_event_cb (GtkWidget *widget, + GdkEventConfigure *event, + gpointer data) +{ + save_window_state (widget); + return FALSE; +} + +static gboolean +ephy_window_state_event_cb (GtkWidget *widget, + GdkEventWindowState *event, + gpointer data) +{ + save_window_state (widget); + return FALSE; +} + +static void +setup_bonobo_window (EphyWindow *window, + BonoboUIComponent **ui_component) +{ + BonoboWindow *win = BONOBO_WINDOW(window); + BonoboUIContainer *container; + Bonobo_UIContainer corba_container; + + container = bonobo_window_get_ui_container (win); + + bonobo_ui_engine_config_set_path (bonobo_window_get_ui_engine (win), + "/apps/ephy/UIConfig/kvps"); + + corba_container = BONOBO_OBJREF (container); + + *ui_component = bonobo_ui_component_new_default (); + + bonobo_ui_component_set_container (*ui_component, + corba_container, + NULL); + + bonobo_ui_util_set_ui (*ui_component, + DATADIR, + "epiphany-ui.xml", + "ephy", NULL); + + /* Key handling */ + g_signal_connect(G_OBJECT(win), + "key-press-event", + G_CALLBACK(ephy_window_key_press_event_cb), + window); + + g_signal_connect (G_OBJECT(win), "configure_event", + G_CALLBACK (ephy_window_configure_event_cb), NULL); + g_signal_connect (G_OBJECT(win), "window_state_event", + G_CALLBACK (ephy_window_state_event_cb), NULL); + + g_signal_connect (G_OBJECT(win), + "selection-received", + G_CALLBACK (ephy_window_selection_received_cb), + window); +} + +static EphyEmbedPopupBW * +setup_popup_factory (EphyWindow *window, + BonoboUIComponent *ui_component) +{ + EphyEmbedPopupBW *popup; + + popup = ephy_window_get_popup_factory (window); + g_object_set_data (G_OBJECT(popup), "EphyWindow", window); + bonobo_ui_component_add_verb_list_with_data (ui_component, + ephy_popup_verbs, + popup); + + return popup; +} + +static GtkNotebook * +setup_notebook (EphyWindow *window) +{ + GtkNotebook *notebook; + + notebook = GTK_NOTEBOOK (ephy_notebook_new ()); + gtk_notebook_set_scrollable (notebook, TRUE); + gtk_notebook_set_show_border (notebook, FALSE); + gtk_notebook_set_show_tabs (notebook, FALSE); + + g_signal_connect_after (G_OBJECT (notebook), "switch_page", + G_CALLBACK ( + ephy_window_notebook_switch_page_cb), + window); + + g_signal_connect (G_OBJECT (notebook), "tab_detached", + G_CALLBACK (ephy_window_tab_detached_cb), + NULL); + + gtk_widget_show (GTK_WIDGET (notebook)); + + return notebook; +} + +static void +view_toolbar_changed_cb (BonoboUIComponent *component, + const char *path, + Bonobo_UIComponent_EventType type, + const char *state, + EphyWindow *window) +{ + EmbedChromeMask mask; + + if (window->priv->ignore_layout_toggles) return; + + mask = ephy_window_get_chrome (window); + mask ^= EMBED_CHROME_TOOLBARON; + ephy_window_set_chrome (window, mask); +} + +static void +view_statusbar_changed_cb (BonoboUIComponent *component, + const char *path, + Bonobo_UIComponent_EventType type, + const char *state, + EphyWindow *window) +{ + EmbedChromeMask mask; + + if (window->priv->ignore_layout_toggles) return; + + mask = ephy_window_get_chrome (window); + mask ^= EMBED_CHROME_STATUSBARON; + ephy_window_set_chrome (window, mask); +} + +static void +view_fullscreen_changed_cb (BonoboUIComponent *component, + const char *path, + Bonobo_UIComponent_EventType type, + const char *state, + EphyWindow *window) +{ + EmbedChromeMask mask; + + if (window->priv->ignore_layout_toggles) return; + + mask = ephy_window_get_chrome (window); + mask ^= EMBED_CHROME_OPENASFULLSCREEN; + mask |= EMBED_CHROME_DEFAULT; + ephy_window_set_chrome (window, mask); +} + +static void +update_layout_toggles (EphyWindow *window) +{ + BonoboUIComponent *ui_component = BONOBO_UI_COMPONENT (window->ui_component); + EmbedChromeMask mask = window->priv->chrome_mask; + + window->priv->ignore_layout_toggles = TRUE; + + ephy_bonobo_set_toggle_state (ui_component, VIEW_TOOLBAR_PATH, + mask & EMBED_CHROME_TOOLBARON); + ephy_bonobo_set_toggle_state (ui_component, VIEW_STATUSBAR_PATH, + mask & EMBED_CHROME_STATUSBARON); + ephy_bonobo_set_toggle_state (ui_component, VIEW_FULLSCREEN_PATH, + mask & EMBED_CHROME_OPENASFULLSCREEN); + + window->priv->ignore_layout_toggles = FALSE; +} + +static void +setup_layout_menus (EphyWindow *window) +{ + BonoboUIComponent *ui_component = BONOBO_UI_COMPONENT (window->ui_component); + + bonobo_ui_component_add_listener (ui_component, ID_VIEW_TOOLBAR, + (BonoboUIListenerFn)view_toolbar_changed_cb, + window); + bonobo_ui_component_add_listener (ui_component, ID_VIEW_STATUSBAR, + (BonoboUIListenerFn)view_statusbar_changed_cb, + window); + bonobo_ui_component_add_listener (ui_component, ID_VIEW_FULLSCREEN, + (BonoboUIListenerFn)view_fullscreen_changed_cb, + window); +} + +static void +ephy_window_init (EphyWindow *window) +{ + BonoboUIComponent *ui_component; + Session *session; + + session = ephy_shell_get_session (ephy_shell); + + window->priv = g_new0 (EphyWindowPrivate, 1); + window->priv->embed_popup = NULL; + window->priv->active_tab = NULL; + window->priv->chrome_mask = 0; + window->priv->ignore_layout_toggles = FALSE; + window->priv->closing = FALSE; + window->priv->has_default_size = FALSE; + + /* Setup the window and connect verbs */ + setup_bonobo_window (window, &ui_component); + window->ui_component = G_OBJECT (ui_component); + bonobo_ui_component_add_verb_list_with_data (ui_component, + ephy_verbs, + window); + setup_layout_menus (window); + + /* Setup the embed popups factory */ + window->priv->embed_popup = setup_popup_factory (window, + ui_component); + + bonobo_ui_component_freeze (ui_component, NULL); + + /* Setup menubar */ + ephy_embed_utils_build_charsets_submenu (ui_component, + CHARSET_MENU_PATH, + (BonoboUIVerbFn)window_cmd_set_charset, + window); + window->priv->fav_menu = ephy_favorites_menu_new (window); + ephy_favorites_menu_set_path (window->priv->fav_menu, GO_FAVORITES_PATH); + + /* Setup toolbar and statusbar */ + window->priv->toolbar = toolbar_new (window); + window->priv->statusbar = statusbar_new (window); + window->priv->ppview_toolbar = ppview_toolbar_new (window); + + /* Setup window contents */ + window->priv->notebook = setup_notebook (window); + bonobo_window_set_contents (BONOBO_WINDOW (window), + GTK_WIDGET (window->priv->notebook)); + + bonobo_ui_component_thaw (ui_component, NULL); + + g_object_ref (ephy_shell); + + /*Once window is fully created, add it to the session list*/ + session_add_window (session, window); +} + +static void +save_window_chrome (EphyWindow *window) +{ + EmbedChromeMask flags = window->priv->chrome_mask; + + if (flags & EMBED_CHROME_OPENASPOPUP) + { + } + else if (flags & EMBED_CHROME_PPVIEWTOOLBARON) + { + } + else if (flags & EMBED_CHROME_OPENASFULLSCREEN) + { + eel_gconf_set_boolean (CONF_WINDOWS_FS_SHOW_TOOLBARS, + flags & EMBED_CHROME_TOOLBARON); + eel_gconf_set_boolean (CONF_WINDOWS_FS_SHOW_STATUSBAR, + flags & EMBED_CHROME_STATUSBARON); + } + else + { + eel_gconf_set_boolean (CONF_WINDOWS_SHOW_TOOLBARS, + flags & EMBED_CHROME_TOOLBARON); + eel_gconf_set_boolean (CONF_WINDOWS_SHOW_STATUSBAR, + flags & EMBED_CHROME_STATUSBARON); + } +} + +static void +remove_from_session (EphyWindow *window) +{ + Session *session; + + session = ephy_shell_get_session (ephy_shell); + g_return_if_fail (session != NULL); + + session_remove_window (session, window); +} + +static void +ephy_window_finalize (GObject *object) +{ + EphyWindow *window; + + g_return_if_fail (IS_EPHY_WINDOW (object)); + + window = EPHY_WINDOW (object); + + g_return_if_fail (window->priv != NULL); + + remove_from_session (window); + + if (window->priv->embed_popup) + { + g_object_unref (G_OBJECT (window->priv->embed_popup)); + } + + g_object_unref (G_OBJECT (window->priv->toolbar)); + g_object_unref (G_OBJECT (window->priv->statusbar)); + + if (window->priv->find_dialog) + { + g_object_unref (G_OBJECT (window->priv->find_dialog)); + } + + if (window->priv->history_dialog) + { + g_object_remove_weak_pointer + (G_OBJECT(window->priv->history_dialog), + (gpointer *)&window->priv->history_dialog); + } + + g_free (window->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); + +#ifdef DEBUG_MARCO + g_print ("Ephy Window finalized %p\n", window); +#endif + + g_object_unref (ephy_shell); +} + +EphyWindow * +ephy_window_new (void) +{ + return EPHY_WINDOW (g_object_new (EPHY_WINDOW_TYPE, NULL)); +} + +static void +dock_item_set_visibility (EphyWindow *window, + const char *path, + gboolean visibility) +{ + ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(window->ui_component), + path, + !visibility); +} + +EmbedChromeMask +ephy_window_get_chrome (EphyWindow *window) +{ + return window->priv->chrome_mask; +} + +static void +wmspec_change_state (gboolean add, + GdkWindow *window, + GdkAtom state1, + GdkAtom state2) +{ + XEvent xev; + + #define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ + #define _NET_WM_STATE_ADD 1 /* add/set property */ + #define _NET_WM_STATE_TOGGLE 2 /* toggle property */ + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.display = gdk_display; + xev.xclient.window = GDK_WINDOW_XID (window); + xev.xclient.message_type = gdk_x11_get_xatom_by_name ("_NET_WM_STATE"); + xev.xclient.format = 32; + xev.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; + xev.xclient.data.l[1] = gdk_x11_atom_to_xatom (state1); + xev.xclient.data.l[2] = gdk_x11_atom_to_xatom (state2); + + XSendEvent (gdk_display, GDK_WINDOW_XID (gdk_get_default_root_window ()), + False, + SubstructureRedirectMask | SubstructureNotifyMask, + &xev); +} + +static void +window_set_fullscreen_mode (EphyWindow *window, gboolean active) +{ + GdkWindow *gdk_window; + + gdk_window = GTK_WIDGET(window)->window; + + if (gdk_net_wm_supports (gdk_atom_intern ("_NET_WM_STATE_FULLSCREEN", + FALSE))) + { + wmspec_change_state (active, + gdk_window, + gdk_atom_intern ("_NET_WM_STATE_FULLSCREEN", + FALSE), + GDK_NONE); + } + else + { + g_warning ("NET_WM_STATE_FULLSCREEN not supported"); + } +} + +static void +translate_default_chrome (EmbedChromeMask *chrome_mask) +{ + /* keep only not layout flags */ + *chrome_mask &= (EMBED_CHROME_WINDOWRAISED | + EMBED_CHROME_WINDOWLOWERED | + EMBED_CHROME_CENTERSCREEN | + EMBED_CHROME_OPENASDIALOG | + EMBED_CHROME_OPENASCHROME | + EMBED_CHROME_OPENASPOPUP | + EMBED_CHROME_OPENASFULLSCREEN); + + /* Load defaults */ + if (*chrome_mask & EMBED_CHROME_OPENASFULLSCREEN) + { + if (eel_gconf_get_boolean (CONF_WINDOWS_FS_SHOW_STATUSBAR)) + { + *chrome_mask |= EMBED_CHROME_STATUSBARON; + } + if (eel_gconf_get_boolean (CONF_WINDOWS_FS_SHOW_TOOLBARS)) + { + *chrome_mask |= EMBED_CHROME_TOOLBARON; + } + } + else + { + if (eel_gconf_get_boolean (CONF_WINDOWS_SHOW_STATUSBAR)) + { + *chrome_mask |= EMBED_CHROME_STATUSBARON; + } + if (eel_gconf_get_boolean (CONF_WINDOWS_SHOW_TOOLBARS)) + { + *chrome_mask |= EMBED_CHROME_TOOLBARON; + } + + *chrome_mask |= EMBED_CHROME_PERSONALTOOLBARON; + *chrome_mask |= EMBED_CHROME_MENUBARON; + } +} + +void +ephy_window_set_chrome (EphyWindow *window, + EmbedChromeMask flags) +{ + gboolean toolbar, ppvtoolbar, statusbar; + + if (flags & EMBED_CHROME_DEFAULT) + { + translate_default_chrome (&flags); + } + + dock_item_set_visibility (window, "/menu", + flags & EMBED_CHROME_MENUBARON); + + toolbar = (flags & EMBED_CHROME_TOOLBARON) != FALSE; + toolbar_set_visibility (window->priv->toolbar, + toolbar); + + statusbar = (flags & EMBED_CHROME_STATUSBARON) != FALSE; + statusbar_set_visibility (window->priv->statusbar, + statusbar); + + ppvtoolbar = (flags & EMBED_CHROME_PPVIEWTOOLBARON) != FALSE; + ppview_toolbar_set_old_chrome (window->priv->ppview_toolbar, + window->priv->chrome_mask); + ppview_toolbar_set_visibility (window->priv->ppview_toolbar, + ppvtoolbar); + + /* set fullscreen only when it's really changed */ + if ((window->priv->chrome_mask & EMBED_CHROME_OPENASFULLSCREEN) != + (flags & EMBED_CHROME_OPENASFULLSCREEN)) + { + save_window_chrome (window); + window_set_fullscreen_mode (window, + flags & EMBED_CHROME_OPENASFULLSCREEN); + } + + window->priv->chrome_mask = flags; + + update_layout_toggles (window); + + save_window_chrome (window); +} + +GtkWidget * +ephy_window_get_notebook (EphyWindow *window) +{ + return GTK_WIDGET (window->priv->notebook); +} + +void +ephy_window_add_tab (EphyWindow *window, + EphyTab *tab, + gboolean jump_to) +{ + GtkWidget *widget; + + g_return_if_fail (IS_EPHY_WINDOW (window)); + g_return_if_fail (IS_EPHY_TAB (tab)); + + ephy_tab_set_window (tab, window); + + widget = GTK_WIDGET(ephy_tab_get_embed (tab)); + + ephy_notebook_insert_page (EPHY_NOTEBOOK (window->priv->notebook), + widget, + EPHY_NOTEBOOK_INSERT_GROUPED, + jump_to); +} + +void +ephy_window_jump_to_tab (EphyWindow *window, + EphyTab *tab) +{ + GtkWidget *widget; + int page; + + widget = GTK_WIDGET(ephy_tab_get_embed (tab)); + + page = gtk_notebook_page_num + (window->priv->notebook, widget); + gtk_notebook_set_current_page + (window->priv->notebook, page); +} + +static EphyTab * +get_tab_from_page_num (GtkNotebook *notebook, gint page_num) +{ + EphyTab *tab; + GtkWidget *embed_widget; + + if (page_num < 0) return NULL; + + embed_widget = gtk_notebook_get_nth_page (notebook, page_num); + + g_return_val_if_fail (GTK_IS_WIDGET (embed_widget), NULL); + tab = g_object_get_data (G_OBJECT (embed_widget), "EphyTab"); + g_return_val_if_fail (IS_EPHY_TAB (G_OBJECT (tab)), NULL); + + return tab; +} + +static EphyTab * +real_get_active_tab (EphyWindow *window, int page_num) +{ + if (page_num == -1) + { + page_num = gtk_notebook_get_current_page (window->priv->notebook); + } + + return get_tab_from_page_num (window->priv->notebook, page_num); +} + +void +ephy_window_remove_tab (EphyWindow *window, + EphyTab *tab) +{ + GtkWidget *embed; + + g_return_if_fail (IS_EPHY_WINDOW (window)); + g_return_if_fail (IS_EPHY_TAB (tab)); + + window->priv->active_tab = NULL; + + embed = GTK_WIDGET (ephy_tab_get_embed (tab)); + + ephy_notebook_remove_page (EPHY_NOTEBOOK (window->priv->notebook), + embed); +} + +void +ephy_window_load_url (EphyWindow *window, + const char *url) +{ + EphyEmbed *embed; + + g_return_if_fail (IS_EPHY_WINDOW(window)); + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + g_return_if_fail (url != NULL); + + ephy_embed_load_url (embed, url); +} + +void ephy_window_activate_location (EphyWindow *window) +{ + toolbar_activate_location (window->priv->toolbar); +} + +void +ephy_window_show (GtkWidget *widget) +{ + EphyWindow *window = EPHY_WINDOW(widget); + EphyTab *tab; + int w = -1, h = -1; + + if (!window->priv->chrome_mask) + { + ephy_window_set_chrome (window, EMBED_CHROME_DEFAULT); + } + + tab = ephy_window_get_active_tab (window); + if (tab) ephy_tab_get_size (tab, &w, &h); + + if (!window->priv->has_default_size && w == -1 && h == -1) + { + ephy_state_load_window (GTK_WIDGET(window), + "main_window", + 600, 500, TRUE); + window->priv->has_default_size = TRUE; + } + + GTK_WIDGET_CLASS (parent_class)->show (widget); +} + +static void +update_status_message (EphyWindow *window) +{ + const char *message; + EphyTab *tab; + + tab = ephy_window_get_active_tab (window); + g_return_if_fail (tab != NULL); + + message = ephy_tab_get_status_message (tab); + g_return_if_fail (message != NULL); + + statusbar_set_message (STATUSBAR(window->priv->statusbar), + message); +} + +static void +update_progress (EphyWindow *window) +{ + EphyTab *tab; + int load_percent; + + tab = ephy_window_get_active_tab (window); + g_return_if_fail (tab != NULL); + + load_percent = ephy_tab_get_load_percent (tab); + + statusbar_set_progress (STATUSBAR(window->priv->statusbar), + load_percent); +} + +static void +update_security (EphyWindow *window) +{ + EphyEmbed *embed; + EmbedSecurityLevel level; + char *description; + char *state = NULL; + gboolean secure; + char *tooltip; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + if (ephy_embed_get_security_level (embed, &level, &description) != G_OK) + { + level = STATE_IS_UNKNOWN; + description = NULL; + } + + secure = FALSE; + switch (level) + { + case STATE_IS_UNKNOWN: + state = _("Unknown"); + break; + case STATE_IS_INSECURE: + state = _("Insecure"); + break; + case STATE_IS_BROKEN: + state = _("Broken"); + break; + case STATE_IS_SECURE_MED: + state = _("Medium"); + secure = TRUE; + break; + case STATE_IS_SECURE_LOW: + state = _("Low"); + secure = TRUE; + break; + case STATE_IS_SECURE_HIGH: + state = _("High"); + secure = TRUE; + break; + default: + g_assert_not_reached (); + break; + } + + if (description != NULL) + { + tooltip = g_strdup_printf (_("Security level: %s\n%s"), + state, description); + g_free (description); + } + else + { + tooltip = g_strdup_printf (_("Security level: %s"), state); + + } + + statusbar_set_security_state (STATUSBAR (window->priv->statusbar), + secure, tooltip); + g_free (tooltip); +} + +static void +update_nav_control (EphyWindow *window) +{ + /* the zoom control is updated at the same time than the navigation + controls. This keeps it synched most of the time, but not always, + because we don't get a notification when zoom changes */ + + gresult back, forward, up, stop; + EphyEmbed *embed; + EphyTab *tab; + gint zoom; + + g_return_if_fail (window != NULL); + + tab = ephy_window_get_active_tab (window); + g_return_if_fail (tab != NULL); + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + back = ephy_embed_can_go_back (embed); + forward = ephy_embed_can_go_forward (embed); + up = ephy_embed_can_go_up (embed); + stop = ephy_tab_get_load_status (tab) & TAB_LOAD_STARTED; + + toolbar_button_set_sensitive (window->priv->toolbar, + TOOLBAR_BACK_BUTTON, + back == G_OK ? TRUE : FALSE); + toolbar_button_set_sensitive (window->priv->toolbar, + TOOLBAR_FORWARD_BUTTON, + forward == G_OK ? TRUE : FALSE); + toolbar_button_set_sensitive (window->priv->toolbar, + TOOLBAR_UP_BUTTON, + up == G_OK ? TRUE : FALSE); + toolbar_button_set_sensitive (window->priv->toolbar, + TOOLBAR_STOP_BUTTON, + stop); + if (ephy_embed_zoom_get (embed, &zoom) == G_OK) + { + toolbar_set_zoom (window->priv->toolbar, zoom); + } + + ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component), + GO_BACK_CMD_PATH, !back); + ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component), + GO_FORWARD_CMD_PATH, !forward); + ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component), + GO_UP_CMD_PATH, !up); +} + +static void +update_title_control (EphyWindow *window) +{ + EphyTab *tab; + const char *title; + + tab = ephy_window_get_active_tab (window); + g_return_if_fail (tab != NULL); + + title = ephy_tab_get_title (tab); + + if (title) + { + gtk_window_set_title (GTK_WINDOW(window), + title); + } +} + +static void +update_location_control (EphyWindow *window) +{ + EphyTab *tab; + const char *location; + + tab = ephy_window_get_active_tab (window); + g_return_if_fail (tab != NULL); + + location = ephy_tab_get_location (tab); + + if (!location) location = ""; + + toolbar_set_location (window->priv->toolbar, + location); +} + +static void +update_favorites_control (EphyWindow *window) +{ + ephy_favorites_menu_update (window->priv->fav_menu); +} + +static void +update_favicon_control (EphyWindow *window) +{ + toolbar_update_favicon (window->priv->toolbar); +} + +static void +update_find_control (EphyWindow *window) +{ + gboolean can_go_next, can_go_prev; + + if (window->priv->find_dialog) + { + can_go_next = find_dialog_can_go_next + (FIND_DIALOG(window->priv->find_dialog)); + can_go_prev = find_dialog_can_go_prev + (FIND_DIALOG(window->priv->find_dialog)); + + ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component), + EDIT_FIND_NEXT_CMD_PATH, can_go_next); + ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component), + EDIT_FIND_PREV_CMD_PATH, can_go_prev); + } +} + +static void +update_window_visibility (EphyWindow *window) +{ + GList *l; + + l = ephy_window_get_tabs (window); + for (; l != NULL; l = l->next) + { + EphyTab *tab = EPHY_TAB(l->data); + g_return_if_fail (IS_EPHY_TAB(tab)); + + if (ephy_tab_get_visibility (tab)) + { + gtk_widget_show (GTK_WIDGET(window)); + return; + } + } + g_list_free (l); + + if (GTK_WIDGET_VISIBLE (GTK_WIDGET (window))) + { + gtk_widget_hide (GTK_WIDGET (window)); + } +} + +static void +update_spinner_control (EphyWindow *window) +{ + GList *l; + + l = ephy_window_get_tabs (window); + for (; l != NULL; l = l->next) + { + EphyTab *tab = EPHY_TAB(l->data); + g_return_if_fail (IS_EPHY_TAB(tab)); + + if (ephy_tab_get_load_status (tab) & TAB_LOAD_STARTED) + { + toolbar_spinner_start (window->priv->toolbar); + return; + } + } + g_list_free (l); + + toolbar_spinner_stop (window->priv->toolbar); +} + +void +ephy_window_update_control (EphyWindow *window, + ControlID control) +{ + g_return_if_fail (IS_EPHY_WINDOW (window)); + + switch (control) + { + case StatusbarMessageControl: + update_status_message (window); + break; + case StatusbarProgressControl: + update_progress (window); + break; + case StatusbarSecurityControl: + update_security (window); + break; + case FindControl: + update_find_control (window); + break; + case ZoomControl: + /* the zoom control is updated at the same time than the navigation + controls. This keeps it synched most of the time, but not always, + because we don't get a notification when zoom changes */ + case NavControl: + update_nav_control (window); + break; + case TitleControl: + update_title_control (window); + break; + case WindowVisibilityControl: + update_window_visibility (window); + break; + case SpinnerControl: + update_spinner_control (window); + break; + case LocationControl: + update_location_control (window); + break; + case FaviconControl: + update_favicon_control (window); + break; + case FavoritesControl: + update_favorites_control (window); + break; + default: + g_warning ("unknown control specified for updating"); + break; + } +} + +void +ephy_window_update_all_controls (EphyWindow *window) +{ + g_return_if_fail (IS_EPHY_WINDOW (window)); + + if (ephy_window_get_active_tab (window) != NULL) + { + update_nav_control (window); + update_title_control (window); + update_location_control (window); + update_favicon_control (window); + update_status_message (window); + update_progress (window); + update_security (window); + update_find_control (window); + update_spinner_control (window); + } +} + +EphyTab * +ephy_window_get_active_tab (EphyWindow *window) +{ + g_return_val_if_fail (IS_EPHY_WINDOW (window), NULL); + + return window->priv->active_tab; +} + +EphyEmbed * +ephy_window_get_active_embed (EphyWindow *window) +{ + EphyTab *tab; + + tab = ephy_window_get_active_tab (window); + + if (tab) + { + g_return_val_if_fail (IS_EPHY_WINDOW (G_OBJECT (window)), + NULL); + return ephy_tab_get_embed (tab); + } + else return NULL; +} + +EphyEmbedPopupBW * +ephy_window_get_popup_factory (EphyWindow *window) +{ + if (!window->priv->embed_popup) + { + window->priv->embed_popup = ephy_embed_popup_bw_new + (BONOBO_WINDOW(window)); + ephy_embed_popup_connect_verbs + (EPHY_EMBED_POPUP (window->priv->embed_popup), + BONOBO_UI_COMPONENT (window->ui_component)); + } + + return window->priv->embed_popup; +} + +GList * +ephy_window_get_tabs (EphyWindow *window) +{ + GList *tabs = NULL; + GtkWidget *w; + int i = 0; + + while ((w = gtk_notebook_get_nth_page (window->priv->notebook, i)) != NULL) + { + EphyTab *tab; + + tab = g_object_get_data (G_OBJECT (w), "EphyTab"); + g_return_val_if_fail (IS_EPHY_TAB (G_OBJECT (tab)), NULL); + + tabs = g_list_append (tabs, tab); + i++; + } + + return tabs; +} + +static void +save_old_embed_status (EphyTab *tab, EphyWindow *window) +{ + /* save old tab location status */ + ephy_tab_set_location (tab, toolbar_get_location (window->priv->toolbar)); +} + +static void +update_embed_dialogs (EphyWindow *window, + EphyTab *tab) +{ + EphyEmbed *embed; + EphyDialog *find_dialog = window->priv->find_dialog; + EphyDialog *history_dialog = window->priv->history_dialog; + EphyDialog *history_sidebar = window->priv->history_sidebar; + + embed = ephy_tab_get_embed (tab); + + if (find_dialog) + { + ephy_embed_dialog_set_embed + (EPHY_EMBED_DIALOG(find_dialog), + embed); + } + + if (history_dialog) + { + ephy_embed_dialog_set_embed + (EPHY_EMBED_DIALOG(history_dialog), + embed); + } + + if (history_sidebar) + { + ephy_embed_dialog_set_embed + (EPHY_EMBED_DIALOG(history_sidebar), + embed); + } +} + +static void +ephy_window_notebook_switch_page_cb (GtkNotebook *notebook, + GtkNotebookPage *page, + guint page_num, + EphyWindow *window) +{ + EphyTab *tab, *old_tab; + + if (window->priv->closing) return; + + g_return_if_fail (IS_EPHY_WINDOW (window)); + + /* get the new tab */ + tab = real_get_active_tab (window, page_num); + + /* update old tab */ + old_tab = window->priv->active_tab; + if (old_tab && tab != old_tab) + { + g_return_if_fail (IS_EPHY_TAB (G_OBJECT (old_tab))); + ephy_tab_set_is_active (old_tab, FALSE); + save_old_embed_status (old_tab, window); + } + + /* update new tab */ + window->priv->active_tab = tab; + ephy_tab_set_is_active (tab, TRUE); + + update_embed_dialogs (window, tab); + + /* update window controls */ + ephy_window_update_all_controls (window); +} + +static void +find_dialog_search_cb (FindDialog *dialog, EphyWindow *window) +{ + ephy_window_update_control (window, FindControl); +} + +EphyDialog * +ephy_window_get_find_dialog (EphyWindow *window) +{ + EphyDialog *dialog; + EphyEmbed *embed; + + if (window->priv->find_dialog) + { + return window->priv->find_dialog; + } + + embed = ephy_window_get_active_embed (window); + g_return_val_if_fail (GTK_IS_WINDOW(window), NULL); + dialog = find_dialog_new_with_parent (GTK_WIDGET(window), + embed); + + g_signal_connect (dialog, "search", + G_CALLBACK (find_dialog_search_cb), + window); + + window->priv->find_dialog = dialog; + + return dialog; +} + +void +ephy_window_show_history (EphyWindow *window) +{ + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + window->priv->history_dialog = history_dialog_new_with_parent + (GTK_WIDGET(window), + embed, + FALSE); + g_object_add_weak_pointer + (G_OBJECT(window->priv->history_dialog), + (gpointer *)&window->priv->history_dialog); + + ephy_dialog_show (window->priv->history_dialog); +} + +void +ephy_window_set_zoom (EphyWindow *window, + gint zoom) +{ + EphyEmbed *embed; + + g_return_if_fail (IS_EPHY_WINDOW (window)); + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_zoom_set (embed, zoom, TRUE); +} + +Toolbar * +ephy_window_get_toolbar (EphyWindow *window) +{ + return window->priv->toolbar; +} + +void +ephy_window_tab_detached_cb (EphyNotebook *notebook, gint page, + gint x, gint y, gpointer data) +{ + EphyTab *tab; + EphyWindow *window; + GtkWidget *src_page; + + src_page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), page); + tab = get_tab_from_page_num (GTK_NOTEBOOK (notebook), page); + window = ephy_window_new (); + ephy_notebook_move_page (notebook, + EPHY_NOTEBOOK (ephy_window_get_notebook (window)), + src_page, 0); + ephy_tab_set_window (tab, window); + gtk_widget_show (GTK_WIDGET (window)); +} diff --git a/src/ephy-window.h b/src/ephy-window.h new file mode 100644 index 000000000..315cd8cca --- /dev/null +++ b/src/ephy-window.h @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_WINDOW_H +#define EPHY_WINDOW_H + +#include "ephy-embed.h" +#include "ephy-embed-persist.h" +#include "ephy-embed-popup-bw.h" +#include "ephy-dialog.h" +#include "ephy-notebook.h" +#include <glib-object.h> +#include <glib.h> +#include <bonobo/bonobo-window.h> + +G_BEGIN_DECLS + +typedef struct EphyWindowClass EphyWindowClass; + +#define EPHY_WINDOW_TYPE (ephy_window_get_type ()) +#define EPHY_WINDOW(obj) (GTK_CHECK_CAST ((obj), EPHY_WINDOW_TYPE, EphyWindow)) +#define EPHY_WINDOW_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_WINDOW, EphyWindowClass)) +#define IS_EPHY_WINDOW(obj) (GTK_CHECK_TYPE ((obj), EPHY_WINDOW_TYPE)) +#define IS_EPHY_WINDOW_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_WINDOW)) + +typedef struct EphyWindow EphyWindow; +typedef struct EphyWindowPrivate EphyWindowPrivate; +typedef struct Toolbar Toolbar; + +struct EphyWindow +{ + BonoboWindow parent; + EphyWindowPrivate *priv; + + /* Public to toolbar and statusbar, dont use outside */ + GObject *ui_component; +}; + +struct EphyWindowClass +{ + BonoboWindowClass parent_class; +}; + +typedef enum +{ + NormalMode, + FullscreenMode +} EphyWindowMode; + +typedef enum +{ + TabsControl, + NavControl, + FindControl, + ZoomControl, + CharsetsControl, + TitleControl, + LocationControl, + FaviconControl, + StatusbarSecurityControl, + StatusbarMessageControl, + StatusbarProgressControl, + SpinnerControl, + WindowVisibilityControl, + BMAndHistoryControl, + TabsAppeareanceControl, + FavoritesControl +} ControlID; + +/* Include the header down here to resolve circular dependency */ +#include "ephy-tab.h" + +GType ephy_window_get_type (void); + +EphyWindow *ephy_window_new (void); + +void ephy_window_set_chrome (EphyWindow *window, + EmbedChromeMask chrome_flags); + +EmbedChromeMask ephy_window_get_chrome (EphyWindow *window); + +GtkWidget *ephy_window_get_notebook (EphyWindow *window); + +void ephy_window_add_tab (EphyWindow *window, + EphyTab *tab, + gboolean jump_to); + +void ephy_window_remove_tab (EphyWindow *window, + EphyTab *tab); + +void ephy_window_jump_to_tab (EphyWindow *window, + EphyTab *tab); + +void ephy_window_load_url (EphyWindow *window, + const char *url); + +void ephy_window_set_zoom (EphyWindow *window, + gint zoom); + +void ephy_window_activate_location (EphyWindow *window); + +void ephy_window_update_control (EphyWindow *window, + ControlID control); + +void ephy_window_update_all_controls (EphyWindow *window); + +EphyTab *ephy_window_get_active_tab (EphyWindow *window); + +EphyEmbed *ephy_window_get_active_embed (EphyWindow *window); + +EphyEmbedPopupBW *ephy_window_get_popup_factory (EphyWindow *window); + +GList *ephy_window_get_tabs (EphyWindow *window); + +Toolbar *ephy_window_get_toolbar (EphyWindow *window); + +/* Dialogs */ + +EphyDialog *ephy_window_get_find_dialog (EphyWindow *window); + +void ephy_window_show_history (EphyWindow *window); + +G_END_DECLS + +#endif diff --git a/src/general-prefs.c b/src/general-prefs.c new file mode 100755 index 000000000..f9eecf4e6 --- /dev/null +++ b/src/general-prefs.c @@ -0,0 +1,484 @@ +/* + * Copyright (C) 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "general-prefs.h" +#include "ephy-shell.h" +#include "ephy-prefs.h" +#include "ephy-embed-prefs.h" +#include "ephy-shell.h" +#include "eel-gconf-extensions.h" +#include "language-editor.h" + +#include <string.h> +#include <gtk/gtkeditable.h> +#include <gtk/gtkmenu.h> +#include <gtk/gtkoptionmenu.h> +#include <gtk/gtkmenuitem.h> +#include <bonobo/bonobo-i18n.h> + +static void general_prefs_class_init (GeneralPrefsClass *klass); +static void general_prefs_init (GeneralPrefs *dialog); +static void general_prefs_finalize (GObject *object); + +/* Glade callbacks */ +void +prefs_homepage_current_button_clicked_cb (GtkWidget *button, + EphyDialog *dialog); +void +prefs_homepage_blank_button_clicked_cb (GtkWidget *button, + EphyDialog *dialog); +void +prefs_language_more_button_clicked_cb (GtkWidget *button, + EphyDialog *dialog); + +static GObjectClass *parent_class = NULL; + +struct GeneralPrefsPrivate +{ + gpointer dummy; +}; + +enum +{ + HOMEPAGE_ENTRY_PROP, + NEW_PAGE_PROP, + AUTOCHARSET_PROP, + DEFAULT_CHARSET_PROP, + LANGUAGE_PROP +}; + +static const +EphyDialogProperty properties [] = +{ + { HOMEPAGE_ENTRY_PROP, "homepage_entry", CONF_GENERAL_HOMEPAGE, PT_AUTOAPPLY, NULL }, + { NEW_PAGE_PROP, "new_page_show_homepage", CONF_GENERAL_NEWPAGE_TYPE, PT_AUTOAPPLY, NULL }, + { AUTOCHARSET_PROP, "autocharset_optionmenu", CONF_LANGUAGE_AUTODETECT_CHARSET, PT_AUTOAPPLY, NULL }, + { DEFAULT_CHARSET_PROP, "default_charset_optionmenu", NULL, PT_NORMAL, NULL }, + { LANGUAGE_PROP, "language_optionmenu", NULL, PT_NORMAL, NULL }, + + { -1, NULL, NULL } +}; + +static const +struct +{ + char *name; + char *code; +} +languages [] = +{ + { _("Afrikaans"), "ak" }, + { _("Albanian"), "sq" }, + { _("Arabic"), "ar" }, + { _("Azerbaijani"), "az" }, + { _("Basque"), "eu" }, + { _("Breton"), "br" }, + { _("Bulgarian"), "bg" }, + { _("Byelorussian"), "be" }, + { _("Catalan"), "ca" }, + { _("Chinese"), "zh" }, + { _("Croatian"), "hr" }, + { _("Czech"), "cs" }, + { _("Danish"), "da" }, + { _("Dutch"), "nl" }, + { _("English"), "en" }, + { _("Esperanto"), "eo" }, + { _("Estonian"), "et" }, + { _("Faeroese"), "fo" }, + { _("Finnish"), "fi" }, + { _("French"), "fr" }, + { _("Galician"), "gl" }, + { _("German"), "de" }, + { _("Greek"), "el" }, + { _("Hebrew"), "he" }, + { _("Hungarian"), "hu" }, + { _("Icelandic"), "is" }, + { _("Indonesian"), "id" }, + { _("Irish"), "ga" }, + { _("Italian"), "it" }, + { _("Japanese"), "ja" }, + { _("Korean"), "ko" }, + { _("Latvian"), "lv" }, + { _("Lithuanian"), "lt" }, + { _("Macedonian"), "mk" }, + { _("Malay"), "ms" }, + { _("Norwegian/Nynorsk"), "nn" }, + { _("Norwegian/Bokmaal"), "nb" }, + { _("Norwegian"), "no" }, + { _("Polish"), "pl" }, + { _("Portuguese"), "pt" }, + { _("Portuguese of Brazil"), "pt-BR" }, + { _("Romanian"), "ro" }, + { _("Russian"), "ru" }, + { _("Scottish"), "gd" }, + { _("Serbian"), "sr" }, + { _("Slovak"), "sk" }, + { _("Slovenian"), "sl" }, + { _("Spanish"), "es" }, + { _("Swedish"), "sv" }, + { _("Tamil"), "ta" }, + { _("Turkish"), "tr" }, + { _("Ukrainian"), "uk" }, + { _("Vietnamian"), "vi" }, + { _("Walloon"), "wa" }, + { NULL, NULL } +}; + +GType +general_prefs_get_type (void) +{ + static GType general_prefs_type = 0; + + if (general_prefs_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (GeneralPrefsClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) general_prefs_class_init, + NULL, + NULL, /* class_data */ + sizeof (GeneralPrefs), + 0, /* n_preallocs */ + (GInstanceInitFunc) general_prefs_init + }; + + general_prefs_type = g_type_register_static (EPHY_DIALOG_TYPE, + "GeneralPrefs", + &our_info, 0); + } + + return general_prefs_type; + +} + +static void +general_prefs_class_init (GeneralPrefsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = general_prefs_finalize; +} + +static void +default_charset_menu_changed_cb (GtkOptionMenu *option_menu, + EphyEmbedShell *shell) +{ + GList *charsets; + int i; + CharsetInfo *info; + + ephy_embed_shell_get_charset_titles (shell, NULL, &charsets); + + i = gtk_option_menu_get_history (option_menu); + charsets = g_list_nth (charsets, i); + g_assert (charsets != NULL); + info = (CharsetInfo *) charsets->data; + eel_gconf_set_string (CONF_LANGUAGE_DEFAULT_CHARSET, + info->name); + + g_list_free (charsets); +} + +static gint +find_charset_in_list_cmp (gconstpointer a, + gconstpointer b) +{ + CharsetInfo *info = (CharsetInfo *)a; + const char *value = b; + + return (strcmp (info->name, value)); +} + +static void +create_default_charset_menu (GeneralPrefs *dialog) +{ + EphyEmbedShell *shell; + GList *l; + GList *charsets; + GtkWidget *menu; + GtkWidget *optionmenu; + char *value; + + shell = ephy_shell_get_embed_shell (ephy_shell); + ephy_embed_shell_get_charset_titles (shell, NULL, &l); + + menu = gtk_menu_new (); + + optionmenu = ephy_dialog_get_control (EPHY_DIALOG (dialog), + DEFAULT_CHARSET_PROP); + + for (charsets = l; charsets != NULL; charsets = charsets->next) + { + CharsetInfo *info = (CharsetInfo *) charsets->data; + GtkWidget *item; + + item = gtk_menu_item_new_with_label (info->title); + gtk_menu_shell_append (GTK_MENU_SHELL(menu), + item); + gtk_widget_show (item); + } + + gtk_option_menu_set_menu (GTK_OPTION_MENU(optionmenu), menu); + + /* init value */ + charsets = l; + value = eel_gconf_get_string (CONF_LANGUAGE_DEFAULT_CHARSET); + charsets = g_list_find_custom (charsets, (gconstpointer)value, + (GCompareFunc)find_charset_in_list_cmp); + gtk_option_menu_set_history (GTK_OPTION_MENU(optionmenu), + g_list_position (l, charsets)); + g_free (value); + + g_signal_connect (optionmenu, "changed", + G_CALLBACK (default_charset_menu_changed_cb), + shell); + + g_list_free (l); +} + +static GtkWidget * +general_prefs_new_language_menu (GeneralPrefs *dialog) +{ + int i; + GtkWidget *menu; + + menu = gtk_menu_new (); + + for (i = 0; languages[i].name != NULL; i++) + { + GtkWidget *item; + + item = gtk_menu_item_new_with_label (languages[i].name); + gtk_menu_shell_append (GTK_MENU_SHELL(menu), + item); + gtk_widget_show (item); + g_object_set_data (G_OBJECT(item), "desc", + languages[i].name); + } + + return menu; +} + +static void +language_menu_changed_cb (GtkOptionMenu *option_menu, + gpointer data) +{ + GSList *list; + GSList *l = NULL; + int history; + + list = eel_gconf_get_string_list (CONF_RENDERING_LANGUAGE); + l = g_slist_copy (list); + + /* Subst the first item according to the optionmenu */ + history = gtk_option_menu_get_history (option_menu); + l->data = languages [history].code; + + eel_gconf_set_string_list (CONF_RENDERING_LANGUAGE, l); + + g_slist_free (l); +} + +static void +create_language_menu (GeneralPrefs *dialog) +{ + GtkWidget *optionmenu; + GtkWidget *menu; + const char *value; + int i; + GSList *list; + + optionmenu = ephy_dialog_get_control (EPHY_DIALOG (dialog), + LANGUAGE_PROP); + + menu = general_prefs_new_language_menu (dialog); + + gtk_option_menu_set_menu (GTK_OPTION_MENU(optionmenu), menu); + + /* init value */ + list = eel_gconf_get_string_list (CONF_RENDERING_LANGUAGE); + g_return_if_fail (list != NULL); + value = (const char *)list->data; + + i = 0; + while (languages[i].code && strcmp (languages[i].code, value) != 0) + { + i++; + } + + gtk_option_menu_set_history (GTK_OPTION_MENU(optionmenu), i); + + g_signal_connect (optionmenu, "changed", + G_CALLBACK (language_menu_changed_cb), + NULL); +} + +static void +general_prefs_init (GeneralPrefs *dialog) +{ + dialog->priv = g_new0 (GeneralPrefsPrivate, 1); + + ephy_dialog_construct (EPHY_DIALOG(dialog), + properties, + "prefs-dialog.glade", + "general_page_box"); + + create_default_charset_menu (dialog); + create_language_menu (dialog); +} + +static void +general_prefs_finalize (GObject *object) +{ + GeneralPrefs *dialog; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_GENERAL_PREFS (object)); + + dialog = GENERAL_PREFS (object); + + g_return_if_fail (dialog->priv != NULL); + + g_free (dialog->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +EphyDialog * +general_prefs_new (void) +{ + GeneralPrefs *dialog; + + dialog = GENERAL_PREFS (g_object_new (GENERAL_PREFS_TYPE, + NULL)); + + return EPHY_DIALOG(dialog); +} + +static void +set_homepage_entry (EphyDialog *dialog, + const char *new_location) +{ + GtkWidget *entry; + int pos; + + entry = ephy_dialog_get_control (dialog, HOMEPAGE_ENTRY_PROP); + + gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1); + gtk_editable_insert_text (GTK_EDITABLE (entry), new_location, + g_utf8_strlen (new_location, -1), + &pos); +} + +void +prefs_homepage_current_button_clicked_cb (GtkWidget *button, + EphyDialog *dialog) +{ + EphyWindow *window; + EphyTab *tab; + + window = ephy_shell_get_active_window (ephy_shell); + g_return_if_fail (window != NULL); + + tab = ephy_window_get_active_tab (window); + g_return_if_fail (tab != NULL); + + set_homepage_entry (dialog, ephy_tab_get_location (tab)); +} + +void +prefs_homepage_blank_button_clicked_cb (GtkWidget *button, + EphyDialog *dialog) +{ + set_homepage_entry (dialog, "about:blank"); +} + +static void +fill_language_editor (LanguageEditor *le) +{ + GSList *strings; + GSList *tmp; + int i; + + /* Fill the list */ + strings = eel_gconf_get_string_list (CONF_RENDERING_LANGUAGE); + + for (tmp = strings; tmp != NULL; tmp = g_slist_next (tmp)) + { + char *value = (char *)tmp->data; + + i = 0; + while (languages[i].code && strcmp (languages[i].code, value) != 0) + { + i++; + } + + /* FIXME unsafe, bad prefs could cause it to access random memory */ + language_editor_add (le, languages[i].name, i); + } +} + +static void +language_dialog_changed_cb (LanguageEditor *le, + GSList *list, + GeneralPrefs *dialog) +{ + GtkWidget *optionmenu; + GSList *l = list; + GSList *langs = NULL; + + optionmenu = ephy_dialog_get_control (EPHY_DIALOG (dialog), + LANGUAGE_PROP); + gtk_option_menu_set_history (GTK_OPTION_MENU(optionmenu), + (int)(l->data)); + + for (; l != NULL; l = l->next) + { + int i = (int)l->data; + langs = g_slist_append (langs, languages[i].code); + } + + eel_gconf_set_string_list (CONF_RENDERING_LANGUAGE, langs); +} + +void +prefs_language_more_button_clicked_cb (GtkWidget *button, + EphyDialog *dialog) +{ + LanguageEditor *editor; + GtkWidget *menu; + GtkWidget *toplevel; + + menu = general_prefs_new_language_menu (GENERAL_PREFS(dialog)); + + toplevel = gtk_widget_get_toplevel (button); + editor = language_editor_new (toplevel); + language_editor_set_menu (editor, menu); + fill_language_editor (editor); + ephy_dialog_set_modal (EPHY_DIALOG(editor), TRUE); + + g_signal_connect (editor, "changed", + G_CALLBACK(language_dialog_changed_cb), + dialog); + + ephy_dialog_show (EPHY_DIALOG(editor)); +} diff --git a/src/general-prefs.h b/src/general-prefs.h new file mode 100644 index 000000000..74cfa26a7 --- /dev/null +++ b/src/general-prefs.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef GENERAL_PREFS_H +#define GENERAL_PREFS_H + +#include "ephy-embed-dialog.h" + +#include <glib-object.h> +#include <glib.h> + +G_BEGIN_DECLS + +typedef struct GeneralPrefs GeneralPrefs; +typedef struct GeneralPrefsClass GeneralPrefsClass; + +#define GENERAL_PREFS_TYPE (general_prefs_get_type ()) +#define GENERAL_PREFS(obj) (GTK_CHECK_CAST ((obj), GENERAL_PREFS_TYPE, GeneralPrefs)) +#define GENERAL_PREFS_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GENERAL_PREFS, GeneralPrefsClass)) +#define IS_GENERAL_PREFS(obj) (GTK_CHECK_TYPE ((obj), GENERAL_PREFS_TYPE)) +#define IS_GENERAL_PREFS_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GENERAL_PREFS)) + +typedef struct GeneralPrefsPrivate GeneralPrefsPrivate; + +struct GeneralPrefs +{ + EphyDialog parent; + GeneralPrefsPrivate *priv; +}; + +struct GeneralPrefsClass +{ + EphyDialogClass parent_class; +}; + +GType general_prefs_get_type (void); + +EphyDialog *general_prefs_new (void); + +G_END_DECLS + +#endif + diff --git a/src/history-dialog.c b/src/history-dialog.c new file mode 100755 index 000000000..4f5b5cc2b --- /dev/null +++ b/src/history-dialog.c @@ -0,0 +1,478 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "history-dialog.h" +#include "ephy-shell.h" +#include "ephy-embed-shell.h" +#include "ephy-string.h" +#include "ephy-gui.h" +#include "ephy-dnd.h" +#include "ephy-node-filter.h" +#include "ephy-history-model.h" +#include "eggtreemodelfilter.h" +#include "eggtreemultidnd.h" +#include "ephy-tree-model-sort.h" + +#include <gtk/gtktreeview.h> +#include <gtk/gtktreestore.h> +#include <gtk/gtkcellrenderertext.h> +#include <bonobo/bonobo-i18n.h> + +#define CONF_HISTORY_SEARCH_TEXT "/apps/epiphany/history/search_text" +#define CONF_HISTORY_SEARCH_TIME "/apps/epiphany/history/search_time" + +static void history_dialog_class_init (HistoryDialogClass *klass); +static void history_dialog_init (HistoryDialog *dialog); +static void history_dialog_finalize (GObject *object); +static void history_dialog_set_embedded (HistoryDialog *d, + gboolean embedded); + + +/* Glade callbacks */ +void +history_host_checkbutton_toggled_cb (GtkWidget *widget, + HistoryDialog *dialog); +void +history_time_optionmenu_changed_cb (GtkWidget *widget, + HistoryDialog *dialog); +void +history_entry_changed_cb (GtkWidget *widget, + HistoryDialog *dialog); +void +history_ok_button_clicked_cb (GtkWidget *button, + HistoryDialog *dialog); +void +history_clear_button_clicked_cb (GtkWidget *button, + HistoryDialog *dialog); + + +static GObjectClass *parent_class = NULL; + +struct HistoryDialogPrivate +{ + EphyHistory *gh; + EphyNode *root; + EphyNode *pages; + EphyNodeFilter *filter; + GtkTreeView *treeview; + GtkTreeModel *model; + EphyHistoryModel *nodemodel; + GtkTreeModel *filtermodel; + EphyTreeModelSort *sortmodel; + gboolean group; + gboolean embedded; +}; + +enum +{ + PROP_0, + PROP_EMBEDDED +}; + +enum +{ + PROP_TREEVIEW, + PROP_WORD, + PROP_TIME +}; + +static const +EphyDialogProperty properties [] = +{ + { PROP_TREEVIEW, "history_treeview", NULL, PT_NORMAL, NULL }, + { PROP_WORD, "history_entry", CONF_HISTORY_SEARCH_TEXT, PT_NORMAL, NULL }, + { PROP_TIME, "history_time_optionmenu", CONF_HISTORY_SEARCH_TIME, PT_NORMAL, NULL }, + { -1, NULL, NULL } +}; + +GType +history_dialog_get_type (void) +{ + static GType history_dialog_type = 0; + + if (history_dialog_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (HistoryDialogClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) history_dialog_class_init, + NULL, + NULL, /* class_data */ + sizeof (HistoryDialog), + 0, /* n_preallocs */ + (GInstanceInitFunc) history_dialog_init + }; + + history_dialog_type = g_type_register_static (EPHY_EMBED_DIALOG_TYPE, + "HistoryDialog", + &our_info, 0); + } + + return history_dialog_type; + +} + +static void +history_dialog_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + HistoryDialog *d = HISTORY_DIALOG (object); + + switch (prop_id) + { + case PROP_EMBEDDED: + history_dialog_set_embedded + (d, g_value_get_boolean (value)); + break; + } +} + +static void +history_dialog_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + HistoryDialog *d = HISTORY_DIALOG (object); + + switch (prop_id) + { + case PROP_EMBEDDED: + g_value_set_boolean (value, d->priv->embedded); + break; + } +} + + +static void +history_dialog_class_init (HistoryDialogClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = history_dialog_finalize; + object_class->set_property = history_dialog_set_property; + object_class->get_property = history_dialog_get_property; + + g_object_class_install_property (object_class, + PROP_EMBEDDED, + g_param_spec_boolean ("embedded", + "Show embedded in another widget", + "Show embedded in another widget", + TRUE, + G_PARAM_READWRITE)); +} + +static void +add_column (HistoryDialog *dialog, + const char *title, + EphyHistoryModelColumn column) +{ + GtkTreeViewColumn *gcolumn; + GtkCellRenderer *renderer; + + gcolumn = (GtkTreeViewColumn *) gtk_tree_view_column_new (); + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (gcolumn, renderer, TRUE); + gtk_tree_view_column_set_attributes (gcolumn, renderer, + "text", column, + NULL); + gtk_tree_view_column_set_sizing (gcolumn, + GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_column_set_sort_column_id (gcolumn, column); + gtk_tree_view_column_set_title (gcolumn, title); + gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->priv->treeview), + gcolumn); +} + +static void +history_view_row_activated_cb (GtkTreeView *treeview, + GtkTreePath *path, + GtkTreeViewColumn *column, + HistoryDialog *dialog) +{ + GtkTreeIter iter, iter2; + EphyNode *node; + EphyEmbed *embed; + const char *location; + + gtk_tree_model_get_iter (GTK_TREE_MODEL (dialog->priv->sortmodel), &iter, path); + gtk_tree_model_sort_convert_iter_to_child_iter + (GTK_TREE_MODEL_SORT (dialog->priv->sortmodel), &iter2, &iter); + egg_tree_model_filter_convert_iter_to_child_iter + (EGG_TREE_MODEL_FILTER (dialog->priv->filtermodel), &iter, &iter2); + + node = ephy_history_model_node_from_iter (dialog->priv->nodemodel, &iter); + location = ephy_node_get_property_string (node, EPHY_NODE_PAGE_PROP_LOCATION); + g_return_if_fail (location != NULL); + embed = ephy_embed_dialog_get_embed (EPHY_EMBED_DIALOG(dialog)); + ephy_embed_load_url (embed, location); +} + +static void +node_from_sort_iter_cb (EphyTreeModelSort *model, + GtkTreeIter *iter, + void **node, + HistoryDialog *dialog) +{ + GtkTreeIter filter_iter, node_iter; + + gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (model), + &filter_iter, iter); + egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (dialog->priv->filtermodel), + &node_iter, &filter_iter); + *node = ephy_history_model_node_from_iter (EPHY_HISTORY_MODEL (dialog->priv->nodemodel), &node_iter); + g_return_if_fail (*node != NULL); +} + +static void +history_dialog_setup_view (HistoryDialog *dialog) +{ + dialog->priv->nodemodel = ephy_history_model_new (dialog->priv->root, + dialog->priv->pages, + dialog->priv->filter); + dialog->priv->filtermodel = egg_tree_model_filter_new (GTK_TREE_MODEL (dialog->priv->nodemodel), + NULL); + egg_tree_model_filter_set_visible_column (EGG_TREE_MODEL_FILTER (dialog->priv->filtermodel), + EPHY_HISTORY_MODEL_COL_VISIBLE); + dialog->priv->sortmodel = EPHY_TREE_MODEL_SORT ( + ephy_tree_model_sort_new (GTK_TREE_MODEL (dialog->priv->filtermodel))); + g_signal_connect_object (G_OBJECT (dialog->priv->sortmodel), + "node_from_iter", + G_CALLBACK (node_from_sort_iter_cb), + dialog, + 0); + gtk_tree_view_set_model (dialog->priv->treeview, + GTK_TREE_MODEL (dialog->priv->sortmodel)); + + egg_tree_multi_drag_add_drag_support (GTK_TREE_VIEW (dialog->priv->treeview)); + ephy_dnd_enable_model_drag_source (GTK_WIDGET (dialog->priv->treeview)); + + add_column (dialog, _("Title"), EPHY_HISTORY_MODEL_COL_TITLE); + add_column (dialog, _("Location"), EPHY_HISTORY_MODEL_COL_LOCATION); + add_column (dialog, _("Last Visit"), EPHY_HISTORY_MODEL_COL_LAST_VISIT); + + g_signal_connect (dialog->priv->treeview, + "row_activated", + G_CALLBACK (history_view_row_activated_cb), + dialog); +} + +static GTime +get_date_filter (int filter_type, + GTime atime) +{ + GDate date, current_date; + struct tm tm; + + g_date_clear (¤t_date, 1); + g_date_set_time (¤t_date, time (NULL)); + + g_date_clear (&date, 1); + g_date_set_time (&date, atime); + + switch (filter_type) + { + /* Always */ + case 0: + return 0; + /* Today */ + case 1: + break; + /* Last two days */ + case 2: + g_date_subtract_days (¤t_date, 1); + break; + /* Last three days */ + case 3: + g_date_subtract_days (¤t_date, 2); + break; + /* Week */ + case 4: + g_date_subtract_days (¤t_date, 7); + break; + /* Month */ + case 5: + g_date_subtract_months (¤t_date, 1); + break; + default: + break; + } + + g_date_to_struct_tm (¤t_date, &tm); + return mktime (&tm); +} + +static void +history_dialog_setup_filter (HistoryDialog *dialog) +{ + GValue word = {0, }; + GValue atime = {0, }; + const char *search_text; + GTime date_filter; + + ephy_dialog_get_value (EPHY_DIALOG(dialog), PROP_WORD, &word); + search_text = g_value_get_string (&word); + ephy_dialog_get_value (EPHY_DIALOG(dialog), PROP_TIME, &atime); + date_filter = get_date_filter (g_value_get_int (&atime), time (NULL)); + + GDK_THREADS_ENTER (); + + ephy_node_filter_empty (dialog->priv->filter); + ephy_node_filter_add_expression (dialog->priv->filter, + ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS, + EPHY_NODE_PAGE_PROP_TITLE, + search_text), + 0); + ephy_node_filter_add_expression (dialog->priv->filter, + ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS, + EPHY_NODE_PAGE_PROP_LOCATION, + search_text), + 0); + ephy_node_filter_add_expression (dialog->priv->filter, + ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_INT_PROP_BIGGER_THAN, + EPHY_NODE_PAGE_PROP_LAST_VISIT, + date_filter), + 1); + + ephy_node_filter_done_changing (dialog->priv->filter); + + GDK_THREADS_LEAVE (); +} + +static void +history_dialog_init (HistoryDialog *dialog) +{ + EphyEmbedShell *ges; + + dialog->priv = g_new0 (HistoryDialogPrivate, 1); + + ges = ephy_shell_get_embed_shell (ephy_shell); + dialog->priv->gh = ephy_embed_shell_get_global_history (ges); + g_return_if_fail (dialog->priv->gh != NULL); + + dialog->priv->root = ephy_history_get_hosts (dialog->priv->gh); + dialog->priv->pages = ephy_history_get_pages (dialog->priv->gh); + dialog->priv->filter = ephy_node_filter_new (); +} + +static void +history_dialog_set_embedded (HistoryDialog *dialog, + gboolean embedded) +{ + dialog->priv->embedded = embedded; + + ephy_dialog_construct (EPHY_DIALOG(dialog), + properties, + "epiphany.glade", + embedded ? + "history_dock_box" : + "history_dialog"); + + dialog->priv->treeview = GTK_TREE_VIEW ( + ephy_dialog_get_control (EPHY_DIALOG(dialog), + PROP_TREEVIEW)); + history_dialog_setup_view (dialog); + history_dialog_setup_filter (dialog); +} + +static void +history_dialog_finalize (GObject *object) +{ + HistoryDialog *dialog; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_HISTORY_DIALOG (object)); + + dialog = HISTORY_DIALOG (object); + + g_return_if_fail (dialog->priv != NULL); + + g_object_unref (G_OBJECT (dialog->priv->sortmodel)); + g_object_unref (G_OBJECT (dialog->priv->filtermodel)); + g_object_unref (G_OBJECT (dialog->priv->nodemodel)); + + g_free (dialog->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +EphyDialog * +history_dialog_new (EphyEmbed *embed, + gboolean embedded) +{ + HistoryDialog *dialog; + + dialog = HISTORY_DIALOG (g_object_new (HISTORY_DIALOG_TYPE, + "embedded", embedded, + "EphyEmbed", embed, + NULL)); + + return EPHY_DIALOG(dialog); +} + +EphyDialog * +history_dialog_new_with_parent (GtkWidget *window, + EphyEmbed *embed, + gboolean embedded) +{ + HistoryDialog *dialog; + + dialog = HISTORY_DIALOG (g_object_new (HISTORY_DIALOG_TYPE, + "embedded", embedded, + "EphyEmbed", embed, + "ParentWindow", window, + NULL)); + + return EPHY_DIALOG(dialog); +} + +void +history_entry_changed_cb (GtkWidget *widget, + HistoryDialog *dialog) +{ + if (dialog->priv->treeview == NULL) return; + history_dialog_setup_filter (dialog); +} + +void +history_time_optionmenu_changed_cb (GtkWidget *widget, + HistoryDialog *dialog) +{ + if (dialog->priv->treeview == NULL) return; + history_dialog_setup_filter (dialog); +} + +void +history_ok_button_clicked_cb (GtkWidget *button, + HistoryDialog *dialog) +{ + g_object_unref (G_OBJECT(dialog)); +} + +void +history_clear_button_clicked_cb (GtkWidget *button, + HistoryDialog *dialog) +{ + ephy_history_clear (dialog->priv->gh); +} diff --git a/src/history-dialog.h b/src/history-dialog.h new file mode 100644 index 000000000..9a064de5c --- /dev/null +++ b/src/history-dialog.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef HISTORY_DIALOG_H +#define HISTORY_DIALOG_H + +#include "ephy-embed-dialog.h" + +#include <glib-object.h> +#include <glib.h> + +G_BEGIN_DECLS + +typedef struct HistoryDialog HistoryDialog; +typedef struct HistoryDialogClass HistoryDialogClass; + +#define HISTORY_DIALOG_TYPE (history_dialog_get_type ()) +#define HISTORY_DIALOG(obj) (GTK_CHECK_CAST ((obj), HISTORY_DIALOG_TYPE, HistoryDialog)) +#define HISTORY_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), HISTORY_DIALOG, HistoryDialogClass)) +#define IS_HISTORY_DIALOG(obj) (GTK_CHECK_TYPE ((obj), HISTORY_DIALOG_TYPE)) +#define IS_HISTORY_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), HISTORY_DIALOG)) + +typedef struct HistoryDialogPrivate HistoryDialogPrivate; + +struct HistoryDialog +{ + EphyEmbedDialog parent; + HistoryDialogPrivate *priv; +}; + +struct HistoryDialogClass +{ + EphyEmbedDialogClass parent_class; +}; + +GType history_dialog_get_type (void); + +EphyDialog *history_dialog_new (EphyEmbed *embed, + gboolean embedded); + +EphyDialog *history_dialog_new_with_parent (GtkWidget *window, + EphyEmbed *embed, + gboolean embedded); + +G_END_DECLS + +#endif + diff --git a/src/language-editor.c b/src/language-editor.c new file mode 100644 index 000000000..7c24f99fd --- /dev/null +++ b/src/language-editor.c @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "language-editor.h" +#include "ephy-gui.h" +#include "ephy-prefs.h" +#include "eel-gconf-extensions.h" + +#include <gtk/gtklabel.h> +#include <gtk/gtkoptionmenu.h> +#include <gtk/gtksignal.h> +#include <gtk/gtkbutton.h> +#include <gtk/gtkeditable.h> +#include <gtk/gtktreeview.h> +#include <gtk/gtktreeselection.h> +#include <gtk/gtkliststore.h> +#include <gtk/gtkcellrenderertext.h> + +enum +{ + COL_DESCRIPTION, + COL_DATA +}; + +enum +{ + TREEVIEW_PROP, + ADD_PROP, + REMOVE_PROP, + LANGUAGE_PROP +}; + +static const +EphyDialogProperty properties [] = +{ + { TREEVIEW_PROP, "languages_treeview", NULL, PT_NORMAL, NULL }, + { ADD_PROP, "add_button", NULL, PT_NORMAL, NULL }, + { REMOVE_PROP, "remove_button", NULL, PT_NORMAL, NULL }, + { LANGUAGE_PROP, "languages_optionmenu", NULL, PT_NORMAL, NULL }, + + { -1, NULL, NULL } +}; + + +struct LanguageEditorPrivate +{ + GtkWidget *treeview; + GtkTreeModel *model; + GtkWidget *optionmenu; +}; + +enum +{ + CHANGED, + LAST_SIGNAL +}; + +static void +language_editor_class_init (LanguageEditorClass *klass); +static void +language_editor_init (LanguageEditor *ge); +static void +language_editor_finalize (GObject *object); + +/* Glade callbacks */ + +void +language_editor_close_button_cb (GtkWidget *button, EphyDialog *dialog); + +static GObjectClass *parent_class = NULL; + +static gint signals[LAST_SIGNAL]; + +GType +language_editor_get_type (void) +{ + static GType language_editor_type = 0; + + if (language_editor_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (LanguageEditorClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) language_editor_class_init, + NULL, + NULL, /* class_data */ + sizeof (LanguageEditor), + 0, /* n_preallocs */ + (GInstanceInitFunc) language_editor_init + }; + + language_editor_type = g_type_register_static (EPHY_DIALOG_TYPE, + "LanguageEditor", + &our_info, 0); + } + + return language_editor_type; + +} + +static void +language_editor_class_init (LanguageEditorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = language_editor_finalize; + + signals[CHANGED] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (LanguageEditorClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); +} + +static void +language_editor_update_pref (LanguageEditor *editor) +{ + GtkTreeIter iter; + int index; + GSList *strings = NULL; + + if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (editor->priv->model), &iter)) + { + return; + } + + do + { + GValue val = {0, }; + gtk_tree_model_get_value (GTK_TREE_MODEL (editor->priv->model), + &iter, COL_DATA, &val); + index = g_value_get_int (&val); + + strings = g_slist_append(strings, GINT_TO_POINTER(index)); + } + while (gtk_tree_model_iter_next (GTK_TREE_MODEL (editor->priv->model), &iter)); + + g_signal_emit (editor, signals[CHANGED], 0, strings); + + g_slist_free (strings); +} + +static void +language_editor_add_button_clicked_cb (GtkButton *button, + LanguageEditor *editor) +{ + const char *description; + GtkTreeIter iter; + GtkWidget *menu; + GtkWidget *item; + int history; + + history = gtk_option_menu_get_history (GTK_OPTION_MENU(editor->priv->optionmenu)); + menu = gtk_option_menu_get_menu (GTK_OPTION_MENU(editor->priv->optionmenu)); + item = gtk_menu_get_active (GTK_MENU(menu)); + description = (const char *) g_object_get_data (G_OBJECT(item), "desc"); + + g_return_if_fail (description != NULL); + + gtk_list_store_append (GTK_LIST_STORE (editor->priv->model), + &iter); + + gtk_list_store_set (GTK_LIST_STORE (editor->priv->model), + &iter, + COL_DESCRIPTION, description, + COL_DATA, history, + -1); + + language_editor_update_pref (editor); +} + +static void +language_editor_remove_button_clicked_cb (GtkButton *button, + LanguageEditor *editor) +{ + GList *l, *r = NULL; + GtkTreeIter iter; + GtkTreeSelection *selection; + GtkTreeModel *model; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(editor->priv->treeview)); + l = gtk_tree_selection_get_selected_rows (selection, &model); + for (;l != NULL; l = l->next) + { + r = g_list_append (r, gtk_tree_row_reference_new + (model, (GtkTreePath *)l->data)); + } + + for (; r != NULL; r = r->next) + { + GtkTreePath *node; + + node = gtk_tree_row_reference_get_path + ((GtkTreeRowReference *)r->data); + + gtk_tree_model_get_iter (model, &iter, node); + + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); + + gtk_tree_row_reference_free ((GtkTreeRowReference *)r->data); + } + + l = g_list_first (l); + g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL); + g_list_free (l); + g_list_free (r); + + language_editor_update_pref (editor); +} + +static void +language_editor_treeview_drag_end_cb (GtkWidget *widget, + GdkDragContext *context, + LanguageEditor *editor) +{ + language_editor_update_pref (editor); +} + +static void +language_editor_set_view (LanguageEditor *ge, + GtkWidget *treeview, + GtkWidget *add_button, + GtkWidget *remove_button, + GtkWidget *optionmenu) +{ + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GtkListStore *liststore; + GtkTreeSelection *selection; + + ge->priv->treeview = treeview; + ge->priv->optionmenu = optionmenu; + + gtk_tree_view_set_reorderable (GTK_TREE_VIEW(ge->priv->treeview), TRUE); + + liststore = gtk_list_store_new (2, + G_TYPE_STRING, + G_TYPE_INT); + + ge->priv->model = GTK_TREE_MODEL (liststore); + + gtk_tree_view_set_model (GTK_TREE_VIEW(ge->priv->treeview), + ge->priv->model); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(ge->priv->treeview), + FALSE); + + renderer = gtk_cell_renderer_text_new (); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(ge->priv->treeview), + 0, "Language", + renderer, + "text", 0, + NULL); + column = gtk_tree_view_get_column (GTK_TREE_VIEW(ge->priv->treeview), 0); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_sort_column_id (column, COL_DESCRIPTION); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(ge->priv->treeview)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); + + /* Connect treeview signals */ + g_signal_connect + (G_OBJECT (ge->priv->treeview), + "drag_end", + G_CALLBACK(language_editor_treeview_drag_end_cb), + ge); + + /* Connect buttons signals */ + g_signal_connect + (G_OBJECT (add_button), + "clicked", + G_CALLBACK(language_editor_add_button_clicked_cb), + ge); + + g_signal_connect + (G_OBJECT (remove_button), + "clicked", + G_CALLBACK(language_editor_remove_button_clicked_cb), + ge); +} + +static void +language_editor_init (LanguageEditor *le) +{ + GtkWidget *treeview; + GtkWidget *optionmenu; + GtkWidget *add_button; + GtkWidget *remove_button; + + le->priv = g_new0 (LanguageEditorPrivate, 1); + + ephy_dialog_construct (EPHY_DIALOG(le), + properties, + "prefs-dialog.glade", + "languages_dialog"); + + treeview = ephy_dialog_get_control (EPHY_DIALOG(le), + TREEVIEW_PROP); + add_button = ephy_dialog_get_control (EPHY_DIALOG(le), + ADD_PROP); + remove_button = ephy_dialog_get_control (EPHY_DIALOG(le), + REMOVE_PROP); + optionmenu = ephy_dialog_get_control (EPHY_DIALOG(le), + LANGUAGE_PROP); + + language_editor_set_view (le, treeview, add_button, remove_button, + optionmenu); +} + +static void +language_editor_finalize (GObject *object) +{ + LanguageEditor *ge; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_LANGUAGE_EDITOR (object)); + + ge = LANGUAGE_EDITOR (object); + + g_return_if_fail (ge->priv != NULL); + + g_free (ge->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +LanguageEditor * +language_editor_new (GtkWidget *parent) +{ + return LANGUAGE_EDITOR (g_object_new (LANGUAGE_EDITOR_TYPE, + "ParentWindow", parent, + NULL)); +} + +void +language_editor_set_menu (LanguageEditor *editor, + GtkWidget *menu) +{ + gtk_option_menu_set_menu (GTK_OPTION_MENU(editor->priv->optionmenu), + menu); +} + +void +language_editor_add (LanguageEditor *ge, + const char *language, + int id) +{ + GtkTreeIter iter; + + gtk_list_store_append (GTK_LIST_STORE (ge->priv->model), + &iter); + + gtk_list_store_set (GTK_LIST_STORE (ge->priv->model), + &iter, + COL_DESCRIPTION, language, + COL_DATA, id, + -1); +} + +void +language_editor_close_button_cb (GtkWidget *button, EphyDialog *dialog) +{ + g_object_unref (dialog); +} diff --git a/src/language-editor.h b/src/language-editor.h new file mode 100644 index 000000000..153fa136a --- /dev/null +++ b/src/language-editor.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef LANGUAGE_EDITOR_H +#define LANGUAGE_EDITOR_H + +#include "general-prefs.h" + +#include <gtk/gtkwidget.h> +#include <glib-object.h> +#include <glib.h> + +G_BEGIN_DECLS + +typedef struct LanguageEditor LanguageEditor; +typedef struct LanguageEditorClass LanguageEditorClass; + +#define LANGUAGE_EDITOR_TYPE (language_editor_get_type ()) +#define LANGUAGE_EDITOR(obj) (GTK_CHECK_CAST ((obj), LANGUAGE_EDITOR_TYPE, LanguageEditor)) +#define LANGUAGE_EDITOR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), LANGUAGE_EDITOR, LanguageEditorClass)) +#define IS_LANGUAGE_EDITOR(obj) (GTK_CHECK_TYPE ((obj), LANGUAGE_EDITOR_TYPE)) +#define IS_LANGUAGE_EDITOR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), LANGUAGE_EDITOR)) + +typedef struct LanguageEditorPrivate LanguageEditorPrivate; + +struct LanguageEditor +{ + EphyDialog parent; + LanguageEditorPrivate *priv; +}; + +struct LanguageEditorClass +{ + EphyDialogClass parent_class; + + void (* changed) (GSList *languages); +}; + +GType language_editor_get_type (void); + +LanguageEditor *language_editor_new (GtkWidget *parent); + +void language_editor_set_menu (LanguageEditor *editor, + GtkWidget *menu); + +void language_editor_add (LanguageEditor *editor, + const char *language, + int id); + +G_END_DECLS + +#endif diff --git a/src/pdm-dialog.c b/src/pdm-dialog.c new file mode 100755 index 000000000..5e077972a --- /dev/null +++ b/src/pdm-dialog.c @@ -0,0 +1,669 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "pdm-dialog.h" +#include "ephy-shell.h" +#include "ephy-embed-shell.h" +#include "ephy-gui.h" +#include "ephy-ellipsizing-label.h" + +#include <gtk/gtktreeview.h> +#include <gtk/gtkliststore.h> +#include <gtk/gtkcellrenderertext.h> +#include <bonobo/bonobo-i18n.h> + +typedef struct PdmActionInfo PdmActionInfo; + +typedef void (* PDM_add) (PdmActionInfo *info, gpointer data); +typedef void (* PDM_remove) (PdmActionInfo *info, GList *data); +typedef void (* PDM_free) (PdmActionInfo *info, GList *data); + +static void pdm_dialog_class_init (PdmDialogClass *klass); +static void pdm_dialog_init (PdmDialog *dialog); +static void pdm_dialog_finalize (GObject *object); + +/* Glade callbacks */ +void +pdm_dialog_close_button_clicked_cb (GtkWidget *button, + PdmDialog *dialog); +void +pdm_dialog_cookies_properties_button_clicked_cb (GtkWidget *button, + PdmDialog *dialog); +void +pdm_dialog_cookies_treeview_selection_changed_cb (GtkTreeSelection *selection, + PdmDialog *dialog); +void +pdm_dialog_passwords_treeview_selection_changed_cb (GtkTreeSelection *selection, + PdmDialog *dialog); + +static GObjectClass *parent_class = NULL; + +struct PdmActionInfo +{ + PDM_add add; + PDM_remove remove; + PDM_free free; + GtkWidget *treeview; + GList *list; + int remove_id; + int data_col; + PdmDialog *dialog; +}; + +struct PdmDialogPrivate +{ + GtkTreeModel *model; + PdmActionInfo *cookies; + PdmActionInfo *passwords; +}; + +enum +{ + PROP_COOKIES_TREEVIEW, + PROP_COOKIES_REMOVE, + PROP_PASSWORDS_TREEVIEW, + PROP_PASSWORDS_REMOVE, + PROP_DIALOG, + PROP_COOKIES_PROPERTIES +}; + +enum +{ + COL_COOKIES_HOST, + COL_COOKIES_NAME, + COL_COOKIES_DATA +}; + +enum +{ + COL_PASSWORDS_HOST, + COL_PASSWORDS_USER, + COL_PASSWORDS_DATA +}; + +static const +EphyDialogProperty properties [] = +{ + { PROP_COOKIES_TREEVIEW, "cookies_treeview", NULL, PT_NORMAL, NULL }, + { PROP_COOKIES_REMOVE, "cookies_remove_button", NULL, PT_NORMAL, NULL }, + { PROP_PASSWORDS_TREEVIEW, "passwords_treeview", NULL, PT_NORMAL, NULL }, + { PROP_PASSWORDS_REMOVE, "passwords_remove_button", NULL, PT_NORMAL, NULL }, + { PROP_DIALOG, "pdm_dialog", NULL, PT_NORMAL, NULL }, + { PROP_COOKIES_PROPERTIES, "cookies_properties_button", NULL, PT_NORMAL, NULL }, + + { -1, NULL, NULL } +}; + +GType +pdm_dialog_get_type (void) +{ + static GType pdm_dialog_type = 0; + + if (pdm_dialog_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (PdmDialogClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) pdm_dialog_class_init, + NULL, + NULL, /* class_data */ + sizeof (PdmDialog), + 0, /* n_preallocs */ + (GInstanceInitFunc) pdm_dialog_init + }; + + pdm_dialog_type = g_type_register_static (EPHY_DIALOG_TYPE, + "PdmDialog", + &our_info, 0); + } + + return pdm_dialog_type; + +} + +static void +pdm_dialog_class_init (PdmDialogClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = pdm_dialog_finalize; +} + +static void +cookies_treeview_selection_changed_cb (GtkTreeSelection *selection, + PdmDialog *dialog) +{ + GtkWidget *widget; + GList *l; + EphyDialog *d = EPHY_DIALOG(dialog); + gboolean has_selection; + GtkTreeModel *model; + + l = gtk_tree_selection_get_selected_rows + (selection, &model); + + has_selection = l != NULL; + + widget = ephy_dialog_get_control (d, PROP_COOKIES_PROPERTIES); + gtk_widget_set_sensitive (widget, has_selection); + + g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL); + g_list_free (l); +} + +static void +action_treeview_selection_changed_cb (GtkTreeSelection *selection, + PdmActionInfo *action) +{ + GtkWidget *widget; + GList *l; + EphyDialog *d = EPHY_DIALOG(action->dialog); + gboolean has_selection; + GtkTreeModel *model; + + l = gtk_tree_selection_get_selected_rows + (selection, &model); + + has_selection = l != NULL; + + widget = ephy_dialog_get_control (d, action->remove_id); + gtk_widget_set_sensitive (widget, has_selection); + + g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL); + g_list_free (l); +} + +static GtkWidget * +setup_passwords_treeview (PdmDialog *dialog) +{ + + GtkTreeView *treeview; + GtkListStore *liststore; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *selection; + + treeview = GTK_TREE_VIEW(ephy_dialog_get_control + (EPHY_DIALOG(dialog), + PROP_PASSWORDS_TREEVIEW)); + + /* set tree model */ + liststore = gtk_list_store_new (3, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_POINTER); + gtk_tree_view_set_model (treeview, GTK_TREE_MODEL(liststore)); + gtk_tree_view_set_headers_visible (treeview, TRUE); + selection = gtk_tree_view_get_selection (treeview); + gtk_tree_selection_set_mode (selection, + GTK_SELECTION_MULTIPLE); + + renderer = gtk_cell_renderer_text_new (); + + gtk_tree_view_insert_column_with_attributes (treeview, + COL_PASSWORDS_HOST, + _("Host"), + renderer, + "text", COL_PASSWORDS_HOST, + NULL); + column = gtk_tree_view_get_column (treeview, COL_PASSWORDS_HOST); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_reorderable (column, TRUE); + gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_column_set_sort_column_id (column, COL_PASSWORDS_HOST); + + gtk_tree_view_insert_column_with_attributes (treeview, + COL_PASSWORDS_USER, + _("User Name"), + renderer, + "text", COL_PASSWORDS_USER, + NULL); + column = gtk_tree_view_get_column (treeview, COL_PASSWORDS_USER); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_reorderable (column, TRUE); + gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_column_set_sort_column_id (column, COL_PASSWORDS_USER); + + return GTK_WIDGET (treeview); +} + +static GtkWidget * +setup_cookies_treeview (PdmDialog *dialog) +{ + GtkTreeView *treeview; + GtkListStore *liststore; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *selection; + + treeview = GTK_TREE_VIEW (ephy_dialog_get_control + (EPHY_DIALOG(dialog), + PROP_COOKIES_TREEVIEW)); + + /* set tree model */ + liststore = gtk_list_store_new (3, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_POINTER); + gtk_tree_view_set_model (treeview, GTK_TREE_MODEL(liststore)); + gtk_tree_view_set_headers_visible (treeview, TRUE); + selection = gtk_tree_view_get_selection (treeview); + gtk_tree_selection_set_mode (selection, + GTK_SELECTION_MULTIPLE); + + g_signal_connect (selection, "changed", + G_CALLBACK(cookies_treeview_selection_changed_cb), + dialog); + + renderer = gtk_cell_renderer_text_new (); + + gtk_tree_view_insert_column_with_attributes (treeview, + COL_COOKIES_HOST, + _("Domain"), + renderer, + "text", COL_COOKIES_HOST, + NULL); + column = gtk_tree_view_get_column (treeview, COL_COOKIES_HOST); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_reorderable (column, TRUE); + gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_column_set_sort_column_id (column, COL_COOKIES_HOST); + + gtk_tree_view_insert_column_with_attributes (treeview, + COL_COOKIES_NAME, + _("Name"), + renderer, + "text", COL_COOKIES_NAME, + NULL); + column = gtk_tree_view_get_column (treeview, COL_COOKIES_NAME); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_reorderable (column, TRUE); + gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_column_set_sort_column_id (column, COL_COOKIES_NAME); + + return GTK_WIDGET(treeview); +} + +static void +pdm_dialog_remove_button_clicked_cb (GtkWidget *button, + PdmActionInfo *action) +{ + GList *l, *r = NULL; + GList *remove_list = NULL; + GtkTreeModel *model; + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection + (GTK_TREE_VIEW(action->treeview)); + l = gtk_tree_selection_get_selected_rows + (selection, &model); + for (;l != NULL; l = l->next) + { + r = g_list_append (r, gtk_tree_row_reference_new + (model, (GtkTreePath *)l->data)); + } + + for (; r != NULL; r = r->next) + { + GtkTreeIter iter; + gpointer data; + GtkTreePath *path; + GValue val = {0, }; + + path = gtk_tree_row_reference_get_path + ((GtkTreeRowReference *)r->data); + + gtk_tree_model_get_iter + (model, &iter, path); + gtk_tree_model_get_value + (model, &iter, action->data_col, &val); + data = g_value_get_pointer (&val); + + gtk_list_store_remove (GTK_LIST_STORE(model), + &iter); + + action->list = g_list_remove (action->list, data); + remove_list = g_list_append (remove_list, data); + + gtk_tree_row_reference_free ((GtkTreeRowReference *)r->data); + } + + if (remove_list) + { + action->remove (action, remove_list); + action->free (action, remove_list); + } + + l = g_list_first (l); + g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL); + g_list_free (l); + g_list_free (r); +} + +static void +setup_action (PdmActionInfo *action) +{ + GList *l; + GtkWidget *widget; + GtkTreeSelection *selection; + + for (l = action->list; l != NULL; l = l->next) + { + action->add (action, l->data); + } + + widget = ephy_dialog_get_control (EPHY_DIALOG(action->dialog), + action->remove_id); + g_signal_connect (widget, "clicked", + G_CALLBACK(pdm_dialog_remove_button_clicked_cb), + action); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(action->treeview)); + g_signal_connect (selection, "changed", + G_CALLBACK(action_treeview_selection_changed_cb), + action); +} + +static void +pdm_dialog_cookie_add (PdmActionInfo *info, + gpointer cookie) +{ + GtkListStore *store; + GtkTreeIter iter; + CookieInfo *cinfo = (CookieInfo *)cookie; + + store = GTK_LIST_STORE(gtk_tree_view_get_model + (GTK_TREE_VIEW(info->treeview))); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, + &iter, + COL_COOKIES_HOST, cinfo->base.domain, + COL_COOKIES_NAME, cinfo->name, + COL_COOKIES_DATA, cinfo, + -1); +} + +static void +pdm_dialog_password_add (PdmActionInfo *info, + gpointer password) +{ + GtkListStore *store; + GtkTreeIter iter; + PasswordInfo *pinfo = (PasswordInfo *)password; + + store = GTK_LIST_STORE(gtk_tree_view_get_model + (GTK_TREE_VIEW(info->treeview))); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, + &iter, + COL_PASSWORDS_HOST, pinfo->host, + COL_PASSWORDS_USER, pinfo->username, + COL_PASSWORDS_DATA, pinfo, + -1); +} + +static void +pdm_dialog_cookie_remove (PdmActionInfo *info, + GList *data) +{ + EphyEmbedShell *shell; + shell = ephy_shell_get_embed_shell (ephy_shell); + ephy_embed_shell_remove_cookies (shell, data); +} + +static void +pdm_dialog_password_remove (PdmActionInfo *info, + GList *data) +{ + EphyEmbedShell *shell; + shell = ephy_shell_get_embed_shell (ephy_shell); + ephy_embed_shell_remove_passwords (shell, data, PASSWORD_PASSWORD); +} + +static void +pdm_dialog_cookies_free (PdmActionInfo *info, + GList *data) +{ + EphyEmbedShell *shell; + GList *l; + + shell = ephy_shell_get_embed_shell (ephy_shell); + l = data ? data : info->list; + ephy_embed_shell_free_cookies (shell, l); +} + +static void +pdm_dialog_passwords_free (PdmActionInfo *info, + GList *data) +{ + EphyEmbedShell *shell; + GList *l; + + shell = ephy_shell_get_embed_shell (ephy_shell); + l = data ? data : info->list; + ephy_embed_shell_free_passwords (shell, l); +} + +static void +pdm_dialog_init (PdmDialog *dialog) +{ + EphyEmbedShell *shell; + PdmActionInfo *cookies; + PdmActionInfo *passwords; + GtkWidget *cookies_tv; + GtkWidget *passwords_tv; + + shell = ephy_shell_get_embed_shell (ephy_shell); + + dialog->priv = g_new0 (PdmDialogPrivate, 1); + dialog->priv->cookies = NULL; + dialog->priv->passwords = NULL; + + ephy_dialog_construct (EPHY_DIALOG(dialog), + properties, + "epiphany.glade", + "pdm_dialog"); + + cookies_tv = setup_cookies_treeview (dialog); + passwords_tv = setup_passwords_treeview (dialog); + + cookies = g_new0 (PdmActionInfo, 1); + ephy_embed_shell_list_cookies (shell, &cookies->list); + cookies->dialog = dialog; + cookies->remove_id = PROP_COOKIES_REMOVE; + cookies->add = pdm_dialog_cookie_add; + cookies->remove = pdm_dialog_cookie_remove; + cookies->free = pdm_dialog_cookies_free; + cookies->treeview = cookies_tv; + cookies->data_col = COL_COOKIES_DATA; + setup_action (cookies); + + passwords = g_new0 (PdmActionInfo, 1); + ephy_embed_shell_list_passwords (shell, PASSWORD_PASSWORD, + &passwords->list); + passwords->dialog = dialog; + passwords->remove_id = PROP_PASSWORDS_REMOVE; + passwords->add = pdm_dialog_password_add; + passwords->remove = pdm_dialog_password_remove; + passwords->free = pdm_dialog_passwords_free; + passwords->treeview = passwords_tv; + passwords->data_col = COL_PASSWORDS_DATA; + setup_action (passwords); + + dialog->priv->cookies = cookies; + dialog->priv->passwords = passwords; +} + +static void +pdm_dialog_finalize (GObject *object) +{ + PdmDialog *dialog; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_PDM_DIALOG (object)); + + dialog = PDM_DIALOG (object); + + g_return_if_fail (dialog->priv != NULL); + + pdm_dialog_passwords_free (dialog->priv->passwords, NULL); + pdm_dialog_cookies_free (dialog->priv->cookies, NULL); + + g_free (dialog->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +EphyDialog * +pdm_dialog_new (GtkWidget *window) +{ + PdmDialog *dialog; + + dialog = PDM_DIALOG (g_object_new (PDM_DIALOG_TYPE, + "ParentWindow", window, + NULL)); + + return EPHY_DIALOG(dialog); +} + +static void +show_cookies_properties (PdmDialog *dialog, + CookieInfo *info) +{ + GtkWidget *gdialog; + GtkWidget *table; + GtkWidget *label; + GtkWidget *parent; + GtkWidget *dialog_vbox; + + parent = ephy_dialog_get_control (EPHY_DIALOG(dialog), + PROP_DIALOG); + + gdialog = gtk_dialog_new_with_buttons + (_("Cookie properties"), + GTK_WINDOW(parent), + GTK_DIALOG_MODAL, + GTK_STOCK_CLOSE, 0, NULL); + gtk_dialog_set_has_separator (GTK_DIALOG(gdialog), FALSE); + gtk_container_set_border_width (GTK_CONTAINER(gdialog), 6); + + table = gtk_table_new (2, 4, FALSE); + gtk_container_set_border_width (GTK_CONTAINER(table), 6); + gtk_table_set_row_spacings (GTK_TABLE(table), 10); + gtk_table_set_col_spacings (GTK_TABLE(table), 10); + gtk_widget_show (table); + + label = gtk_label_new (_("<b>Value</b>")); + gtk_label_set_use_markup (GTK_LABEL(label), TRUE); + gtk_misc_set_alignment (GTK_MISC(label), 0, 0); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + GTK_FILL, GTK_FILL, 0, 0); + + label = ephy_ellipsizing_label_new (info->value); + gtk_misc_set_alignment (GTK_MISC(label), 0, 0); + gtk_widget_show (label); + gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, 0, 1); + + label = gtk_label_new (_("<b>Path</b>")); + gtk_label_set_use_markup (GTK_LABEL(label), TRUE); + gtk_misc_set_alignment (GTK_MISC(label), 0, 0); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + GTK_FILL, GTK_FILL, 0, 0); + + label = gtk_label_new (info->path); + gtk_misc_set_alignment (GTK_MISC(label), 0, 0); + gtk_widget_show (label); + gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, 1, 2); + + label = gtk_label_new (_("<b>Secure</b>")); + gtk_label_set_use_markup (GTK_LABEL(label), TRUE); + gtk_misc_set_alignment (GTK_MISC(label), 0, 0); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + GTK_FILL, GTK_FILL, 0, 0); + + label = gtk_label_new (info->secure); + gtk_misc_set_alignment (GTK_MISC(label), 0, 0); + gtk_widget_show (label); + gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, 2, 3); + + label = gtk_label_new (_("<b>Expire</b>")); + gtk_label_set_use_markup (GTK_LABEL(label), TRUE); + gtk_misc_set_alignment (GTK_MISC(label), 0, 0); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4, + GTK_FILL, GTK_FILL, 0, 0); + + label = gtk_label_new (info->expire); + gtk_misc_set_alignment (GTK_MISC(label), 0, 0.5); + gtk_widget_show (label); + gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, 3, 4); + + dialog_vbox = GTK_DIALOG(gdialog)->vbox; + gtk_box_pack_start (GTK_BOX(dialog_vbox), + table, + FALSE, FALSE, 0); + + gtk_dialog_run (GTK_DIALOG(gdialog)); + + gtk_widget_destroy (gdialog); +} + +void +pdm_dialog_cookies_properties_button_clicked_cb (GtkWidget *button, + PdmDialog *dialog) +{ + GtkTreeModel *model; + GValue val = {0, }; + GtkTreeIter iter; + GtkTreePath *path; + CookieInfo *info; + GList *l; + GtkWidget *treeview = dialog->priv->cookies->treeview; + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + l = gtk_tree_selection_get_selected_rows + (selection, &model); + + path = (GtkTreePath *)l->data; + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get_value + (model, &iter, COL_COOKIES_DATA, &val); + info = (CookieInfo *)g_value_get_pointer (&val); + + show_cookies_properties (dialog, info); + + g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL); + g_list_free (l); +} + +void +pdm_dialog_close_button_clicked_cb (GtkWidget *button, + PdmDialog *dialog) +{ + g_object_unref (dialog); +} diff --git a/src/pdm-dialog.h b/src/pdm-dialog.h new file mode 100644 index 000000000..7216d4ac0 --- /dev/null +++ b/src/pdm-dialog.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PDM_DIALOG_H +#define PDM_DIALOG_H + +#include "ephy-dialog.h" +#include <glib.h> + +G_BEGIN_DECLS + +typedef struct PdmDialog PdmDialog; +typedef struct PdmDialogClass PdmDialogClass; + +#define PDM_DIALOG_TYPE (pdm_dialog_get_type ()) +#define PDM_DIALOG(obj) (GTK_CHECK_CAST ((obj), PDM_DIALOG_TYPE, PdmDialog)) +#define PDM_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), PDM_DIALOG, PdmDialogClass)) +#define IS_PDM_DIALOG(obj) (GTK_CHECK_TYPE ((obj), PDM_DIALOG_TYPE)) +#define IS_PDM_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), PDM_DIALOG)) + +typedef struct PdmDialogPrivate PdmDialogPrivate; + +struct PdmDialog +{ + EphyDialog parent; + PdmDialogPrivate *priv; +}; + +struct PdmDialogClass +{ + EphyDialogClass parent_class; +}; + +GType pdm_dialog_get_type (void); + +EphyDialog *pdm_dialog_new (GtkWidget *window); + +G_END_DECLS + +#endif + diff --git a/src/popup-commands.c b/src/popup-commands.c new file mode 100644 index 000000000..bf187d981 --- /dev/null +++ b/src/popup-commands.c @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "popup-commands.h" +#include "ephy-shell.h" + +static EphyWindow * +get_window_from_popup (EphyEmbedPopup *popup) +{ + return EPHY_WINDOW (g_object_get_data(G_OBJECT(popup), "EphyWindow")); +} + +void popup_cmd_new_window (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + EphyEmbedEvent *info; + EphyTab *tab; + GValue *value; + + tab = ephy_window_get_active_tab (get_window_from_popup (popup)); + + info = ephy_embed_popup_get_event (popup); + + ephy_embed_event_get_property (info, "link", &value); + + ephy_shell_new_tab (ephy_shell, NULL, tab, + g_value_get_string (value), + EPHY_NEW_TAB_IN_NEW_WINDOW); +} + +void popup_cmd_new_tab (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + EphyEmbedEvent *info; + EphyTab *tab; + EphyWindow *window; + GValue *value; + + window = get_window_from_popup (popup); + g_return_if_fail (window != NULL); + + tab = ephy_window_get_active_tab (window); + + info = ephy_embed_popup_get_event (popup); + + ephy_embed_event_get_property (info, "link", &value); + + ephy_shell_new_tab (ephy_shell, window, tab, + g_value_get_string (value), + EPHY_NEW_TAB_IN_EXISTING_WINDOW); +} + +void popup_cmd_image_in_new_tab (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + EphyEmbedEvent *info; + EphyTab *tab; + EphyWindow *window; + GValue *value; + + window = get_window_from_popup (popup); + g_return_if_fail (window != NULL); + + tab = ephy_window_get_active_tab (window); + + info = ephy_embed_popup_get_event (popup); + + ephy_embed_event_get_property (info, "image", &value); + + ephy_shell_new_tab (ephy_shell, window, tab, + g_value_get_string (value), + EPHY_NEW_TAB_IN_EXISTING_WINDOW); +} + +void popup_cmd_image_in_new_window (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + EphyEmbedEvent *info; + EphyTab *tab; + GValue *value; + + tab = ephy_window_get_active_tab (get_window_from_popup (popup)); + + info = ephy_embed_popup_get_event (popup); + + ephy_embed_event_get_property (info, "image", &value); + + ephy_shell_new_tab (ephy_shell, NULL, tab, + g_value_get_string (value), + EPHY_NEW_TAB_IN_NEW_WINDOW); +} + +void popup_cmd_add_bookmark (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + GtkWidget *new_bookmark; + EphyBookmarks *bookmarks; + EphyEmbedEvent *info = ephy_embed_popup_get_event (popup); + EphyEmbed *embed; + GtkWidget *window; + GValue *link_title; + GValue *link_rel; + GValue *link; + GValue *link_is_smart; + const char *title; + const char *location; + const char *rel; + gboolean is_smart; + + embed = ephy_embed_popup_get_embed (popup); + window = gtk_widget_get_toplevel (GTK_WIDGET (embed)); + + ephy_embed_event_get_property (info, "link_is_smart", &link_is_smart); + ephy_embed_event_get_property (info, "link", &link); + ephy_embed_event_get_property (info, "link_title", &link_title); + ephy_embed_event_get_property (info, "link_rel", &link_rel); + + title = g_value_get_string (link_title); + location = g_value_get_string (link); + rel = g_value_get_string (link_rel); + is_smart = g_value_get_int (link_is_smart); + + g_return_if_fail (location); + + if (!title || !title[0]) + { + title = location; + } + + bookmarks = ephy_shell_get_bookmarks (ephy_shell); + new_bookmark = ephy_new_bookmark_new + (bookmarks, GTK_WINDOW (window), location); + ephy_new_bookmark_set_title + (EPHY_NEW_BOOKMARK (new_bookmark), title); + ephy_new_bookmark_set_smarturl + (EPHY_NEW_BOOKMARK (new_bookmark), rel); + gtk_widget_show (new_bookmark); +} + +void popup_cmd_frame_in_new_tab (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + EphyTab *tab; + EphyWindow *window; + EphyEmbed *embed; + char *location; + + window = get_window_from_popup (popup); + g_return_if_fail (window != NULL); + + tab = ephy_window_get_active_tab (window); + + embed = ephy_window_get_active_embed (window); + + ephy_embed_get_location (embed, FALSE, FALSE, &location); + + ephy_shell_new_tab (ephy_shell, window, tab, + location, + EPHY_NEW_TAB_IN_EXISTING_WINDOW); + + g_free (location); +} + +void popup_cmd_frame_in_new_window (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + EphyTab *tab; + EphyEmbed *embed; + EphyWindow *window; + char *location; + + window = get_window_from_popup (popup); + g_return_if_fail (window != NULL); + + tab = ephy_window_get_active_tab (window); + + embed = ephy_window_get_active_embed (window); + + ephy_embed_get_location (embed, FALSE, FALSE, &location); + + ephy_shell_new_tab (ephy_shell, NULL, tab, + location, + EPHY_NEW_TAB_IN_NEW_WINDOW); + + g_free (location); +} + +void popup_cmd_add_frame_bookmark (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + /* FIXME implement */ +} + +void popup_cmd_view_source (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname) +{ + /* FIXME implement */ +} diff --git a/src/popup-commands.h b/src/popup-commands.h new file mode 100644 index 000000000..e5b369c76 --- /dev/null +++ b/src/popup-commands.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-embed-popup.h" +#include "ephy-new-bookmark.h" + +#include <bonobo/bonobo-ui-component.h> + +void popup_cmd_new_window (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); + +void popup_cmd_new_tab (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); + +void popup_cmd_image_in_new_tab (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); + +void popup_cmd_image_in_new_window (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); + +void popup_cmd_add_bookmark (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); + +void popup_cmd_frame_in_new_tab (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); + +void popup_cmd_frame_in_new_window (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); + +void popup_cmd_add_frame_bookmark (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); + +void popup_cmd_view_source (BonoboUIComponent *uic, + EphyEmbedPopup *popup, + const char* verbname); diff --git a/src/ppview-toolbar.c b/src/ppview-toolbar.c new file mode 100755 index 000000000..06b2cbb6e --- /dev/null +++ b/src/ppview-toolbar.c @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#include "ppview-toolbar.h" +#include "ephy-window.h" +#include "ephy-bonobo-extensions.h" +#include "ephy-string.h" +#include "ephy-gui.h" + +#include <string.h> +#include <bonobo/bonobo-i18n.h> +#include <bonobo/bonobo-window.h> +#include <bonobo/bonobo-control.h> +#include <bonobo/bonobo-ui-toolbar-button-item.h> +#include <bonobo/bonobo-property-bag.h> +#include <gtk/gtkentry.h> +#include <gtk/gtkmenu.h> + +#define PPV_GOTO_FIRST_PATH "/commands/PPVGotoFirst" +#define PPV_GOTO_LAST_PATH "/commands/PPVGotoLast" +#define PPV_GO_BACK_PATH "/commands/PPVGoBack" +#define PPV_GO_FORWARD_PATH "/commands/PPVGoForward" + +static void ppview_toolbar_class_init (PPViewToolbarClass *klass); +static void ppview_toolbar_init (PPViewToolbar *t); +static void ppview_toolbar_finalize (GObject *object); +static void ppview_toolbar_set_window (PPViewToolbar *t, EphyWindow *window); +static void +ppview_toolbar_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void +ppview_toolbar_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +enum +{ + PROP_0, + PROP_EPHY_WINDOW +}; + +static GObjectClass *parent_class = NULL; + +struct PPViewToolbarPrivate +{ + EphyWindow *window; + BonoboUIComponent *ui_component; + gboolean visibility; + EmbedChromeMask old_chrome; + int current_page; +}; + +static void +toolbar_cmd_ppv_goto_first (BonoboUIComponent *uic, + PPViewToolbar *t, + const char* verbname); + +static void +toolbar_cmd_ppv_goto_last (BonoboUIComponent *uic, + PPViewToolbar *t, + const char* verbname); + +static void +toolbar_cmd_ppv_go_back (BonoboUIComponent *uic, + PPViewToolbar *t, + const char* verbname); + +static void +toolbar_cmd_ppv_go_forward (BonoboUIComponent *uic, + PPViewToolbar *t, + const char* verbname); + +static void +toolbar_cmd_ppv_close (BonoboUIComponent *uic, + PPViewToolbar *t, + const char* verbname); + +BonoboUIVerb ppview_toolbar_verbs [] = { + BONOBO_UI_VERB ("PPVGotoFirst", (BonoboUIVerbFn)toolbar_cmd_ppv_goto_first), + BONOBO_UI_VERB ("PPVGotoLast", (BonoboUIVerbFn)toolbar_cmd_ppv_goto_last), + BONOBO_UI_VERB ("PPVGoBack", (BonoboUIVerbFn)toolbar_cmd_ppv_go_back), + BONOBO_UI_VERB ("PPVGoForward", (BonoboUIVerbFn)toolbar_cmd_ppv_go_forward), + BONOBO_UI_VERB ("PPVClose", (BonoboUIVerbFn)toolbar_cmd_ppv_close), + + BONOBO_UI_VERB_END +}; + +GType +ppview_toolbar_get_type (void) +{ + static GType ppview_toolbar_type = 0; + + if (ppview_toolbar_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (PPViewToolbarClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ppview_toolbar_class_init, + NULL, + NULL, /* class_data */ + sizeof (PPViewToolbar), + 0, /* n_preallocs */ + (GInstanceInitFunc) ppview_toolbar_init + }; + + ppview_toolbar_type = g_type_register_static (G_TYPE_OBJECT, + "PPViewToolbar", + &our_info, 0); + } + + return ppview_toolbar_type; + +} + +static void +ppview_toolbar_class_init (PPViewToolbarClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ppview_toolbar_finalize; + + object_class->set_property = ppview_toolbar_set_property; + object_class->get_property = ppview_toolbar_get_property; + + g_object_class_install_property (object_class, + PROP_EPHY_WINDOW, + g_param_spec_object ("EphyWindow", + "EphyWindow", + "Parent window", + EPHY_WINDOW_TYPE, + G_PARAM_READWRITE)); +} + +static void +ppview_toolbar_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PPViewToolbar *t = PPVIEW_TOOLBAR (object); + + switch (prop_id) + { + case PROP_EPHY_WINDOW: + ppview_toolbar_set_window (t, g_value_get_object (value)); + break; + } +} + +static void +ppview_toolbar_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PPViewToolbar *t = PPVIEW_TOOLBAR (object); + + switch (prop_id) + { + case PROP_EPHY_WINDOW: + g_value_set_object (value, t->priv->window); + break; + } +} + +static void +ppview_toolbar_set_window (PPViewToolbar *t, EphyWindow *window) +{ + g_return_if_fail (t->priv->window == NULL); + + t->priv->window = window; + t->priv->ui_component = BONOBO_UI_COMPONENT + (t->priv->window->ui_component); + + bonobo_ui_component_add_verb_list_with_data (t->priv->ui_component, + ppview_toolbar_verbs, + t); +} + +static void +ppview_toolbar_init (PPViewToolbar *t) +{ + t->priv = g_new0 (PPViewToolbarPrivate, 1); + + t->priv->window = NULL; + t->priv->ui_component = NULL; + t->priv->visibility = TRUE; +} + +static void +ppview_toolbar_finalize (GObject *object) +{ + PPViewToolbar *t; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_PPVIEW_TOOLBAR (object)); + + t = PPVIEW_TOOLBAR (object); + + g_return_if_fail (t->priv != NULL); + + g_free (t->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +PPViewToolbar * +ppview_toolbar_new (EphyWindow *window) +{ + PPViewToolbar *t; + + t = PPVIEW_TOOLBAR (g_object_new (PPVIEW_TOOLBAR_TYPE, + "EphyWindow", window, + NULL)); + + g_return_val_if_fail (t->priv != NULL, NULL); + + return t; +} + +void +ppview_toolbar_set_old_chrome (PPViewToolbar *t, + EmbedChromeMask chrome) +{ + t->priv->old_chrome = chrome; +} + +static void +toolbar_update_sensitivity (PPViewToolbar *t) +{ + int pages, c_page; + EphyWindow *window = t->priv->window; + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_print_preview_num_pages (embed, &pages); + c_page = t->priv->current_page; + + ephy_bonobo_set_sensitive (t->priv->ui_component, + PPV_GO_BACK_PATH, c_page > 1); + ephy_bonobo_set_sensitive (t->priv->ui_component, + PPV_GOTO_FIRST_PATH, c_page > 1); + ephy_bonobo_set_sensitive (t->priv->ui_component, + PPV_GO_FORWARD_PATH, c_page < pages); + ephy_bonobo_set_sensitive (t->priv->ui_component, + PPV_GOTO_LAST_PATH, c_page < pages); +} + +void +ppview_toolbar_set_visibility (PPViewToolbar *t, gboolean visibility) +{ + if (visibility == t->priv->visibility) return; + + t->priv->visibility = visibility; + + if (visibility) + { + t->priv->current_page = 1; + toolbar_update_sensitivity (t); + } + + ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(t->priv->ui_component), + "/PrintPreview", + !visibility); +} + +static void +toolbar_cmd_ppv_goto_first (BonoboUIComponent *uic, + PPViewToolbar *t, + const char* verbname) +{ + EphyWindow *window = t->priv->window; + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_print_preview_navigate (embed, PRINTPREVIEW_HOME, 0); + + t->priv->current_page = 1; + + toolbar_update_sensitivity (t); +} + +static void +toolbar_cmd_ppv_goto_last (BonoboUIComponent *uic, + PPViewToolbar *t, + const char* verbname) +{ + EphyWindow *window = t->priv->window; + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_print_preview_navigate (embed, + PRINTPREVIEW_END, + 0); + + ephy_embed_print_preview_num_pages (embed, + &t->priv->current_page); + + toolbar_update_sensitivity (t); +} + +static void +toolbar_cmd_ppv_go_back (BonoboUIComponent *uic, + PPViewToolbar *t, + const char* verbname) +{ + EphyWindow *window = t->priv->window; + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_print_preview_navigate (embed, + PRINTPREVIEW_PREV_PAGE, + 0); + + t->priv->current_page --; + + toolbar_update_sensitivity (t); +} + +static void +toolbar_cmd_ppv_go_forward (BonoboUIComponent *uic, + PPViewToolbar *t, + const char* verbname) +{ + EphyWindow *window = t->priv->window; + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_print_preview_navigate (embed, + PRINTPREVIEW_NEXT_PAGE, + 0); + + t->priv->current_page ++; + + toolbar_update_sensitivity (t); +} + +static void +toolbar_cmd_ppv_close (BonoboUIComponent *uic, + PPViewToolbar *t, + const char* verbname) +{ + EphyWindow *window = t->priv->window; + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_window_set_chrome (window, t->priv->old_chrome); + + ephy_embed_print_preview_close (embed); + + toolbar_update_sensitivity (t); +} + diff --git a/src/ppview-toolbar.h b/src/ppview-toolbar.h new file mode 100644 index 000000000..3e6a4b504 --- /dev/null +++ b/src/ppview-toolbar.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PPVIEW_TOOLBAR_H +#define PPVIEW_TOOLBAR_H + +#include "ephy-window.h" +#include <glib-object.h> +#include <glib.h> +#include <gtk/gtkbutton.h> + +G_BEGIN_DECLS + +typedef struct PPViewToolbar PPViewToolbar; +typedef struct PPViewToolbarClass PPViewToolbarClass; + +#define PPVIEW_TOOLBAR_TYPE (ppview_toolbar_get_type ()) +#define PPVIEW_TOOLBAR(obj) (GTK_CHECK_CAST ((obj), PPVIEW_TOOLBAR_TYPE, PPViewToolbar)) +#define PPVIEW_TOOLBAR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), PPVIEW_TOOLBAR, PPViewToolbarClass)) +#define IS_PPVIEW_TOOLBAR(obj) (GTK_CHECK_TYPE ((obj), PPVIEW_TOOLBAR_TYPE)) +#define IS_PPVIEW_TOOLBAR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), PPVIEW_TOOLBAR)) + +typedef struct PPViewToolbarPrivate PPViewToolbarPrivate; + +struct PPViewToolbar +{ + GObject parent; + PPViewToolbarPrivate *priv; +}; + +struct PPViewToolbarClass +{ + GObjectClass parent_class; +}; + +GType ppview_toolbar_get_type (void); + +PPViewToolbar *ppview_toolbar_new (EphyWindow *window); + +void ppview_toolbar_set_visibility (PPViewToolbar *t, + gboolean visibility); + +void ppview_toolbar_set_old_chrome (PPViewToolbar *t, + EmbedChromeMask chrome); + +G_END_DECLS + +#endif diff --git a/src/prefs-dialog.c b/src/prefs-dialog.c new file mode 100644 index 000000000..8f010420c --- /dev/null +++ b/src/prefs-dialog.c @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "prefs-dialog.h" +#include "general-prefs.h" +#include "appearance-prefs.h" +#include "ui-prefs.h" +#include "ephy-dialog.h" +#include "ephy-prefs.h" +#include "ephy-embed-prefs.h" +#include "ephy-shell.h" +#include "ephy-state.h" + +#include <bonobo/bonobo-i18n.h> +#include <gtk/gtkframe.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtkvbox.h> +#include <gtk/gtkradiobutton.h> +#include <gtk/gtktogglebutton.h> +#include <gtk/gtkimage.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkstock.h> + +static void +prefs_dialog_class_init (PrefsDialogClass *klass); +static void +prefs_dialog_init (PrefsDialog *pd); +static void +prefs_dialog_finalize (GObject *object); + +/* Glade callbacks */ +void +prefs_proxy_auto_url_reload_cb (GtkWidget *button, + EphyDialog *dialog); +void +prefs_clear_memory_cache_button_clicked_cb (GtkWidget *button, + gpointer data); +void +prefs_clear_disk_cache_button_clicked_cb (GtkWidget *button, + gpointer data); + + +/* Proxy page */ + +enum +{ + CACHE_COMPARE_PROP, + DISK_CACHE_PROP, + MEMORY_CACHE_PROP +}; + +static const +EphyDialogProperty network_properties [] = +{ + { CACHE_COMPARE_PROP, "cache_compare_radiobutton", CONF_NETWORK_CACHE_COMPARE, PT_AUTOAPPLY, NULL }, + { DISK_CACHE_PROP, "disk_cache_spin", CONF_NETWORK_DISK_CACHE, PT_AUTOAPPLY, NULL }, + { MEMORY_CACHE_PROP, "memory_cache_spin", CONF_NETWORK_MEMORY_CACHE, PT_AUTOAPPLY, NULL }, + + { -1, NULL, NULL } +}; + +struct PrefsDialogPrivate +{ + GtkWidget *notebook; +}; + +static GObjectClass *parent_class = NULL; + +GType +prefs_dialog_get_type (void) +{ + static GType prefs_dialog_type = 0; + + if (prefs_dialog_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (PrefsDialogClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) prefs_dialog_class_init, + NULL, + NULL, /* class_data */ + sizeof (PrefsDialog), + 0, /* n_preallocs */ + (GInstanceInitFunc) prefs_dialog_init + }; + + prefs_dialog_type = g_type_register_static (GTK_TYPE_DIALOG, + "PrefsDialog", + &our_info, 0); + } + + return prefs_dialog_type; + +} + +GtkDialog * +prefs_dialog_new (void) +{ + GtkDialog *dialog; + + dialog = GTK_DIALOG (g_object_new (PREFS_DIALOG_TYPE, NULL)); + + return dialog; +} + +static void +prefs_dialog_class_init (PrefsDialogClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = prefs_dialog_finalize; +} + +static void +prefs_dialog_finalize (GObject *object) +{ + PrefsDialog *pd; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_PREFS_DIALOG (object)); + + pd = PREFS_DIALOG (object); + + g_return_if_fail (pd->priv != NULL); + + g_free (pd->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static EphyDialog * +create_page (PrefsPageID id, + const char *page_widget, + const EphyDialogProperty *prop) +{ + EphyDialog *page = NULL; + + switch (id) + { + case PREFS_PAGE_GENERAL: + page = general_prefs_new (); + break; + case PREFS_PAGE_APPEARANCE: + page = appearance_prefs_new (); + break; + case PREFS_PAGE_UI: + page = ui_prefs_new (); + break; + case PREFS_PAGE_ADVANCED: + page = ephy_dialog_new (); + ephy_dialog_construct (EPHY_DIALOG(page), + prop, + "prefs-dialog.glade", + page_widget); + break; + } + + return page; +} + +static EphyDialog * +prefs_dialog_get_page (PrefsDialog *pd, + PrefsPageID id) +{ + const char *page_widget = NULL; + EphyDialog *page; + const EphyDialogProperty *prop = NULL; + + switch (id) + { + case PREFS_PAGE_APPEARANCE: + page_widget = "appearance_page_box"; + break; + case PREFS_PAGE_GENERAL: + page_widget = "general_page_box"; + break; + case PREFS_PAGE_UI: + page_widget = "ui_page_box"; + break; + case PREFS_PAGE_ADVANCED: + page_widget = "network_page_box"; + prop = network_properties; + break; + } + + g_assert (page_widget != NULL); + + page = create_page (id, page_widget, prop); + g_assert (page != NULL); + + return page; +} + +void +prefs_dialog_show_page (PrefsDialog *pd, + PrefsPageID id) +{ + gtk_notebook_set_current_page (GTK_NOTEBOOK (pd->priv->notebook), id); +} + +static void +prefs_dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer data) +{ + if (response_id == GTK_RESPONSE_CLOSE) + { + gtk_widget_destroy (GTK_WIDGET(dialog)); + } +} + +static void +prefs_build_notebook (PrefsDialog *pd) +{ + int i; + GtkWidget *nb; + + struct + { + char *name; + int id; + } + pages[] = + { + { _("General"), PREFS_PAGE_GENERAL }, + { _("Appearance"), PREFS_PAGE_APPEARANCE }, + { _("User Interface"), PREFS_PAGE_UI }, + { _("Advanced"), PREFS_PAGE_ADVANCED }, + + { NULL, 0 } + }; + + gtk_dialog_add_button (GTK_DIALOG (pd), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE); + + g_signal_connect (pd, "response", + G_CALLBACK (prefs_dialog_response_cb), + NULL); + + gtk_container_set_border_width (GTK_CONTAINER (pd), 5); + + nb = gtk_notebook_new (); + gtk_container_set_border_width (GTK_CONTAINER (nb), 5); + gtk_widget_show (nb); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (pd)->vbox), nb); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (nb), TRUE); + pd->priv->notebook = nb; + + for (i = 0; pages[i].name != NULL; i++) + { + GtkWidget *label, *child; + EphyDialog *page; + + page = prefs_dialog_get_page (pd, pages[i].id); + + child = gtk_hbox_new (FALSE, 0); + gtk_widget_show (child); + label = gtk_label_new (pages[i].name); + gtk_notebook_append_page (GTK_NOTEBOOK (nb), + child, label); + + ephy_dialog_show_embedded (page, child); + } +} + +static gboolean +prefs_dialog_configure_event_cb (GtkWidget *widget, + GdkEventConfigure *event, + gpointer data) +{ + ephy_state_save_window (widget, "prefs_dialog"); + + return FALSE; +} + +static void +prefs_dialog_init (PrefsDialog *pd) +{ + pd->priv = g_new0 (PrefsDialogPrivate, 1); + + gtk_window_set_title (GTK_WINDOW(pd), _("Preferences")); + gtk_dialog_set_has_separator (GTK_DIALOG(pd), FALSE); + + ephy_state_load_window (GTK_WIDGET(pd), + "prefs_dialog", -1, -1, FALSE); + + g_signal_connect (pd, + "configure_event", + G_CALLBACK (prefs_dialog_configure_event_cb), + NULL); + + prefs_build_notebook (pd); +} + +/* Network page callbacks */ + +void +prefs_clear_memory_cache_button_clicked_cb (GtkWidget *button, + gpointer data) +{ + EphyEmbedShell *shell; + + shell = ephy_shell_get_embed_shell (ephy_shell); + ephy_embed_shell_clear_cache (shell, MEMORY_CACHE); +} + +void +prefs_clear_disk_cache_button_clicked_cb (GtkWidget *button, + gpointer data) +{ + EphyEmbedShell *shell; + + shell = ephy_shell_get_embed_shell (ephy_shell); + ephy_embed_shell_clear_cache (shell, DISK_CACHE); +} diff --git a/src/prefs-dialog.h b/src/prefs-dialog.h new file mode 100644 index 000000000..3c5528b2f --- /dev/null +++ b/src/prefs-dialog.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PREFS_DIALOG_H +#define PREFS_DIALOG_H + +#include <gtk/gtkdialog.h> +#include <glib-object.h> +#include <glib.h> + +typedef struct PrefsDialog PrefsDialog; +typedef struct PrefsDialogClass PrefsDialogClass; + +#define PREFS_DIALOG_TYPE (prefs_dialog_get_type ()) +#define PREFS_DIALOG(obj) (GTK_CHECK_CAST ((obj), PREFS_DIALOG_TYPE, PrefsDialog)) +#define PREFS_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), PREFS_DIALOG, PrefsDialogClass)) +#define IS_PREFS_DIALOG(obj) (GTK_CHECK_TYPE ((obj), PREFS_DIALOG_TYPE)) +#define IS_PREFS_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), PREFS_DIALOG)) + +typedef struct PrefsDialogPrivate PrefsDialogPrivate; + +typedef enum +{ + PREFS_PAGE_GENERAL, + PREFS_PAGE_APPEARANCE, + PREFS_PAGE_UI, + PREFS_PAGE_ADVANCED +} PrefsPageID; + +struct PrefsDialog +{ + GtkDialog parent; + PrefsDialogPrivate *priv; +}; + +struct PrefsDialogClass +{ + GtkDialogClass parent_class; +}; + +GType prefs_dialog_get_type (void); + +GtkDialog *prefs_dialog_new (void); + +void prefs_dialog_show_page (PrefsDialog *pd, + PrefsPageID id); + +#endif diff --git a/src/session.c b/src/session.c new file mode 100644 index 000000000..920b49df9 --- /dev/null +++ b/src/session.c @@ -0,0 +1,690 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "session.h" +#include "ephy-shell.h" +#include "ephy-tab.h" +#include "ephy-window.h" +#include "ephy-prefs.h" +#include "ephy-string.h" +#include "ephy-file-helpers.h" +#include "eel-gconf-extensions.h" + +#include <libgnome/gnome-i18n.h> +#include <string.h> +#include <gtk/gtkdialog.h> +#include <gtk/gtkimage.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkstock.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtkvbox.h> +#include <libxml/parser.h> +#include <libxml/tree.h> +#include <libxml/xmlmemory.h> +#include <libgnomevfs/gnome-vfs-ops.h> +#include <libgnomeui/gnome-client.h> + +enum +{ + RESTORE_TYPE_PROP +}; + +enum +{ + RESTORE_SESSION, + RESTORE_AS_BOOKMARKS, + DISCARD_SESSION +}; + +static void session_class_init (SessionClass *klass); +static void session_init (Session *t); +static void session_finalize (GObject *object); +static void session_dispose (GObject *object); + +static GObjectClass *parent_class = NULL; + +struct SessionPrivate +{ + GList *windows; + gboolean dont_remove_crashed; +}; + +enum +{ + NEW_WINDOW, + CLOSE_WINDOW, + LAST_SIGNAL +}; + +static guint session_signals[LAST_SIGNAL] = { 0 }; + +GType +session_get_type (void) +{ + static GType session_type = 0; + + if (session_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (SessionClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) session_class_init, + NULL, + NULL, /* class_data */ + sizeof (Session), + 0, /* n_preallocs */ + (GInstanceInitFunc) session_init + }; + + session_type = g_type_register_static (G_TYPE_OBJECT, + "Session", + &our_info, 0); + } + + return session_type; + +} + +static void +session_class_init (SessionClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = session_finalize; + object_class->dispose = session_dispose; + + session_signals[NEW_WINDOW] = + g_signal_new ("new_window", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (SessionClass, new_window), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + G_TYPE_OBJECT); + + session_signals[CLOSE_WINDOW] = + g_signal_new ("close_window", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (SessionClass, close_window), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +static char * +get_session_filename (const char *filename) +{ + char *save_to; + + g_return_val_if_fail (filename != NULL, NULL); + + if (strcmp (filename, SESSION_CRASHED) == 0) + { + save_to = g_build_filename (ephy_dot_dir (), + "session_crashed.xml", + NULL); + } + else if (strcmp (filename, SESSION_GNOME) == 0) + { + char *tmp; + + save_to = g_build_filename (ephy_dot_dir (), + "session_gnome-XXXXXX", + NULL); + tmp = ephy_file_tmp_filename (save_to, "xml"); + g_free (save_to); + save_to = tmp; + } + else + { + save_to = g_strdup (filename); + } + + return save_to; +} + +static void +do_session_resume (Session *session) +{ + const char *crashed_session; + + crashed_session = get_session_filename (SESSION_CRASHED); + session_load (session, crashed_session); +} + +static void +crashed_resume_dialog (Session *session) +{ + GtkWidget *dialog; + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *image; + + dialog = gtk_dialog_new_with_buttons + (_("Crash Recovery"), NULL, + GTK_DIALOG_NO_SEPARATOR, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + _("_Recover"), GTK_RESPONSE_OK, + NULL); + gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); + gtk_container_set_border_width (GTK_CONTAINER (dialog), 6); + gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 12); + + hbox = gtk_hbox_new (FALSE, 6); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, + TRUE, TRUE, 0); + + image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, + GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0); + gtk_widget_show (image); + gtk_box_pack_start (GTK_BOX (hbox), image, + TRUE, TRUE, 0); + + vbox = gtk_vbox_new (FALSE, 6); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, + TRUE, TRUE, 0); + + label = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_widget_show (label); + gtk_label_set_markup (GTK_LABEL (label), + _("<b>Epiphany appears to have crashed or been killed the last time it was run.</b>")); + gtk_box_pack_start (GTK_BOX (vbox), label, + TRUE, TRUE, 0); + + label = gtk_label_new (_("You can recover the opened tabs and windows.")); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, + TRUE, TRUE, 0); + + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) + { + do_session_resume (session); + } + + gtk_widget_destroy (dialog); +} + +/** + * session_autoresume: + * @session: a #Session + * + * Resume a crashed session when necessary (interactive) + * + * Return value: return false if no window has been opened + **/ +gboolean +session_autoresume (Session *session) +{ + char *saved_session; + gboolean loaded = FALSE; + + saved_session = get_session_filename (SESSION_CRASHED); + + if (g_file_test (saved_session, G_FILE_TEST_EXISTS)) + { + crashed_resume_dialog (session); + loaded = TRUE; + } + + g_free (saved_session); + + /* return false if no window has been opened */ + return (session->priv->windows != NULL); +} + +static void +create_session_directory (void) +{ + char *dir; + + dir = g_build_filename (ephy_dot_dir (), + "/sessions", + NULL); + + if (!g_file_test (dir, G_FILE_TEST_EXISTS)) + { + if (mkdir (dir, 488) != 0) + { + g_error ("couldn't make %s' directory", dir); + } + } + + g_free (dir); +} + +static gboolean +save_yourself_cb (GnomeClient *client, + gint phase, + GnomeSaveStyle save_style, + gboolean shutdown, + GnomeInteractStyle interact_style, + gboolean fast, + Session *session) +{ + char *argv[] = { "ephy", "--load-session", NULL }; + char *discard_argv[] = { "rm", "-r", NULL }; + + argv[2] = get_session_filename (SESSION_GNOME); + gnome_client_set_restart_command + (client, 3, argv); + + discard_argv[2] = argv[2]; + gnome_client_set_discard_command (client, 3, + discard_argv); + + session_save (session, argv[2]); + + g_free (argv[2]); + + return TRUE; +} + +static void +session_die_cb (GnomeClient* client, + Session *session) +{ + session_close (session); +} + +static void +gnome_session_init (Session *session) +{ + GnomeClient *client; + + client = gnome_master_client (); + + g_signal_connect (G_OBJECT (client), + "save_yourself", + G_CALLBACK (save_yourself_cb), + session); + + g_signal_connect (G_OBJECT (client), + "die", + G_CALLBACK (session_die_cb), + session); +} + +static void +session_init (Session *session) +{ + session->priv = g_new0 (SessionPrivate, 1); + session->priv->windows = NULL; + session->priv->dont_remove_crashed = FALSE; + + create_session_directory (); + + gnome_session_init (session); +} + +/* + * session_close: + * @session: a #Session + * + * Close the session and all the owned windows + **/ +void +session_close (Session *session) +{ + GList *l; + + /* close all windows */ + l = g_list_copy (session->priv->windows); + for (; l != NULL; l = l->next) + { + EphyWindow *window = EPHY_WINDOW(l->data); + gtk_widget_destroy (GTK_WIDGET(window)); + } +} + +static void +session_delete (Session *session, + const char *filename) +{ + char *save_to; + + save_to = get_session_filename (filename); + + gnome_vfs_unlink (save_to); + + g_free (save_to); +} + +static void +session_dispose (GObject *object) +{ + Session *session = SESSION(object); + + if (!session->priv->dont_remove_crashed) + { + session_delete (session, SESSION_CRASHED); + } +} + +static void +session_finalize (GObject *object) +{ + Session *t; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_SESSION (object)); + + t = SESSION (object); + + g_return_if_fail (t->priv != NULL); + + g_list_free (t->priv->windows); + + g_free (t->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +/** + * session_new: + * + * Create a #Session. A session hold the information + * about the windows currently opened and is able to persist + * and restore his status. + **/ +Session * +session_new (void) +{ + Session *t; + + t = SESSION (g_object_new (SESSION_TYPE, NULL)); + + g_return_val_if_fail (t->priv != NULL, NULL); + + return t; +} + +static void +save_tab (EphyWindow *window, + EphyTab *tab, + xmlDocPtr doc, + xmlNodePtr window_node) +{ + EmbedChromeMask chrome; + const char *location; + const char *title; + xmlNodePtr embed_node; + + chrome = ephy_window_get_chrome (window); + + /* skip if it's a XUL dialog */ + if (chrome & EMBED_CHROME_OPENASCHROME) return; + + /* make a new XML node */ + embed_node = xmlNewDocNode (doc, NULL, + "embed", NULL); + + /* store title in the node */ + title = ephy_tab_get_title (tab); + xmlSetProp (embed_node, "title", title); + + /* otherwise, use the actual location. */ + location = ephy_tab_get_location (tab); + xmlSetProp (embed_node, "url", location); + + /* insert node into the tree */ + xmlAddChild (window_node, embed_node); +} + +/* + * session_save: + * @session: a #Session + * @filename: path of the xml file where the session is saved. + * + * Save the session on disk. Keep information about window size, + * opened urls ... + **/ +void +session_save (Session *session, + const char *filename) +{ + GList *w; + xmlNodePtr root_node; + xmlNodePtr window_node; + xmlDocPtr doc; + gchar buffer[32]; + char *save_to; + + save_to = get_session_filename (filename); + + doc = xmlNewDoc ("1.0"); + + /* create and set the root node for the session */ + root_node = xmlNewDocNode (doc, NULL, "session", NULL); + xmlDocSetRootElement (doc, root_node); + + w = session_get_windows (session); + + /* iterate through all the windows */ + for (; w != NULL; w = w->next) + { + const GList *tabs; + int x = 0, y = 0, width = 0, height = 0; + EphyWindow *window = EPHY_WINDOW(w->data); + GtkWidget *wmain; + + tabs = ephy_window_get_tabs (window); + g_return_if_fail (tabs != NULL); + + /* make a new XML node */ + window_node = xmlNewDocNode (doc, NULL, "window", NULL); + + /* get window geometry */ + wmain = GTK_WIDGET (window); + gtk_window_get_size (GTK_WINDOW(wmain), &width, &height); + gtk_window_get_position (GTK_WINDOW(wmain), &x, &y); + + /* set window properties */ + snprintf(buffer, 32, "%d", x); + xmlSetProp (window_node, "x", buffer); + snprintf(buffer, 32, "%d", y); + + xmlSetProp (window_node, "y", buffer); + snprintf(buffer, 32, "%d", width); + xmlSetProp (window_node, "width", buffer); + snprintf(buffer, 32, "%d", height); + xmlSetProp (window_node, "height", buffer); + + for (; tabs != NULL; tabs = tabs->next) + { + EphyTab *tab = EPHY_TAB(tabs->data); + save_tab (window, tab, doc, window_node); + } + + xmlAddChild (root_node, window_node); + } + + /* save it all out to disk */ + xmlSaveFile (save_to, doc); + xmlFreeDoc (doc); + + g_free (save_to); +} + +static void +parse_embed (xmlNodePtr child, EphyWindow *window) +{ + EphyTab *tab; + EphyEmbed *embed; + + while (child != NULL) + { + if (strcmp (child->name, "embed") == 0) + { + char *url; + char *title; + + g_return_if_fail (window != NULL); + + url = xmlGetProp (child, "url"); + title = xmlGetProp (child, "title"); + + tab = ephy_tab_new (); + embed = ephy_tab_get_embed (tab); + + gtk_widget_show (GTK_WIDGET(embed)); + + ephy_window_add_tab (window, tab, FALSE); + + ephy_embed_load_url (embed, url); + + xmlFree (url); + xmlFree (title); + } + + child = child->next; + } +} + +/* + * session_load: + * @session: a #Session + * @filename: the path of the source file + * + * Load a session from disk, restoring the windows and their state + **/ +void +session_load (Session *session, + const char *filename) +{ + xmlDocPtr doc; + xmlNodePtr child; + GtkWidget *wmain; + EphyWindow *window; + char *save_to; + + save_to = get_session_filename (filename); + + doc = xmlParseFile (save_to); + + child = xmlDocGetRootElement (doc); + + /* skip the session node */ + child = child->children; + + while (child != NULL) + { + if (strcmp (child->name, "window") == 0) + { + gint x = 0, y = 0, width = 0, height = 0; + xmlChar *tmp; + + tmp = xmlGetProp (child, "x"); + ephy_str_to_int (tmp, &x); + xmlFree (tmp); + tmp = xmlGetProp (child, "y"); + ephy_str_to_int (tmp, &y); + xmlFree (tmp); + tmp = xmlGetProp (child, "width"); + ephy_str_to_int (tmp, &width); + xmlFree (tmp); + tmp = xmlGetProp (child, "height"); + ephy_str_to_int (tmp, &height); + xmlFree (tmp); + + window = ephy_window_new (); + wmain = GTK_WIDGET (window); + gtk_widget_show (GTK_WIDGET(window)); + + gtk_window_move (GTK_WINDOW(wmain), x, y); + gtk_window_set_default_size (GTK_WINDOW (wmain), + width, height); + + parse_embed (child->children, window); + } + + child = child->next; + } + + xmlFreeDoc (doc); + + g_free (save_to); +} + +GList * +session_get_windows (Session *session) +{ + g_return_val_if_fail (IS_SESSION (session), NULL); + + return session->priv->windows; +} + +/** + * session_add_window: + * @session: a #Session + * @window: a #EphyWindow + * + * Add a window to the session. #EphyWindow take care of adding + * itself to session. + **/ +void +session_add_window (Session *session, + EphyWindow *window) +{ + session->priv->windows = g_list_append (session->priv->windows, window); + + g_signal_emit (G_OBJECT (session), + session_signals[NEW_WINDOW], + 0, window); +} + +/** + * session_remove_window: + * @session: a #Session + * @window: a #EphyWindow + * + * Remove a window from the session. #EphyWindow take care of removing + * itself to session. + **/ +void +session_remove_window (Session *session, + EphyWindow *window) +{ + g_signal_emit (G_OBJECT (session), + session_signals[CLOSE_WINDOW], + 0); + + session->priv->windows = g_list_remove (session->priv->windows, window); + + /* autodestroy of the session, necessay to avoid + * conflicts with the nautilus view */ + if (session->priv->windows == NULL) + { + g_object_unref (session); + } +} + diff --git a/src/session.h b/src/session.h new file mode 100644 index 000000000..e2ac6b9b2 --- /dev/null +++ b/src/session.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef SESSION_H +#define SESSION_H + +#define SESSION_CRASHED "type:session_crashed" +#define SESSION_GNOME "type:session_gnome" + +#include "ephy-window.h" + +G_BEGIN_DECLS + +#include <glib-object.h> +#include <glib.h> + +typedef struct Session Session; +typedef struct SessionClass SessionClass; + +#define SESSION_TYPE (session_get_type ()) +#define SESSION(obj) (GTK_CHECK_CAST ((obj), SESSION_TYPE, Session)) +#define SESSION_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), SESSION, SessionClass)) +#define IS_SESSION(obj) (GTK_CHECK_TYPE ((obj), SESSION_TYPE)) +#define IS_SESSION_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), SESSION)) + +typedef struct SessionPrivate SessionPrivate; + +struct Session +{ + GObject parent; + SessionPrivate *priv; +}; + +struct SessionClass +{ + GObjectClass parent_class; + + void ( *new_window) (Session *session, + EphyWindow *window); + void ( *close_window) (Session *session); +}; + +GType session_get_type (void); + +Session *session_new (void); + +void session_close (Session *session); + +void session_load (Session *session, + const char *filename); + +void session_save (Session *session, + const char *filename); + +gboolean session_autoresume (Session *session); + +GList *session_get_windows (Session *session); + +void session_add_window (Session *session, + EphyWindow *window); + +void session_remove_window (Session *session, + EphyWindow *window); + +EphyWindow *session_get_active_window (Session *session); + +G_END_DECLS + +#endif diff --git a/src/statusbar.c b/src/statusbar.c new file mode 100755 index 000000000..8ac84cfb9 --- /dev/null +++ b/src/statusbar.c @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "statusbar.h" +#include "ephy-stock-icons.h" +#include "ephy-bonobo-extensions.h" + +#include <string.h> +#include <time.h> +#include <gtk/gtkprogressbar.h> +#include <gtk/gtkeventbox.h> +#include <gtk/gtkimage.h> +#include <gtk/gtkframe.h> +#include <gtk/gtktooltips.h> +#include <bonobo/bonobo-window.h> +#include <bonobo/bonobo-control.h> + +static void statusbar_class_init (StatusbarClass *klass); +static void statusbar_init (Statusbar *t); +static void statusbar_finalize (GObject *object); +static void +statusbar_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void +statusbar_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void +statusbar_set_window (Statusbar *t, EphyWindow *window); + +enum +{ + PROP_0, + PROP_EPHY_WINDOW +}; + +static GObjectClass *parent_class = NULL; + +struct StatusbarPrivate +{ + EphyWindow *window; + BonoboUIComponent *ui_component; + GtkWidget *security_icon; + GtkWidget *progress; + GtkTooltips *tooltips; + GtkWidget *security_evbox; + gboolean visibility; +}; + +GType +statusbar_get_type (void) +{ + static GType statusbar_type = 0; + + if (statusbar_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (StatusbarClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) statusbar_class_init, + NULL, + NULL, /* class_data */ + sizeof (Statusbar), + 0, /* n_preallocs */ + (GInstanceInitFunc) statusbar_init + }; + + statusbar_type = g_type_register_static (G_TYPE_OBJECT, + "Statusbar", + &our_info, 0); + } + + return statusbar_type; + +} + +static void +statusbar_class_init (StatusbarClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = statusbar_finalize; + object_class->set_property = statusbar_set_property; + object_class->get_property = statusbar_get_property; + + g_object_class_install_property (object_class, + PROP_EPHY_WINDOW, + g_param_spec_object ("EphyWindow", + "EphyWindow", + "Parent window", + EPHY_WINDOW_TYPE, + G_PARAM_READWRITE)); +} + +static void +statusbar_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + Statusbar *s = STATUSBAR (object); + + switch (prop_id) + { + case PROP_EPHY_WINDOW: + statusbar_set_window (s, g_value_get_object (value)); + break; + } +} + +static void +statusbar_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + Statusbar *s = STATUSBAR (object); + + switch (prop_id) + { + case PROP_EPHY_WINDOW: + g_value_set_object (value, s->priv->window); + break; + } +} + +static void +create_statusbar_security_icon (Statusbar *s) +{ + GtkWidget *security_frame; + BonoboControl *control; + + security_frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (security_frame), + GTK_SHADOW_IN); + + s->priv->security_icon = gtk_image_new (); + s->priv->security_evbox = gtk_event_box_new (); + gtk_container_add (GTK_CONTAINER (security_frame), + GTK_WIDGET (s->priv->security_evbox)); + gtk_container_add (GTK_CONTAINER (s->priv->security_evbox), + GTK_WIDGET (s->priv->security_icon)); + /* + g_signal_connect (G_OBJECT (security_eventbox), + "button_release_event", + GTK_SIGNAL_FUNC + (security_icon_button_release_cb), t); + */ + + control = bonobo_control_new (security_frame); + bonobo_ui_component_object_set (s->priv->ui_component, + "/status/SecurityIconWrapper", + BONOBO_OBJREF (control), + NULL); + bonobo_object_unref (control); + + statusbar_set_security_state (s, FALSE, NULL); + + gtk_widget_show_all (security_frame); +} + +static void +create_statusbar_progress (Statusbar *s) +{ + BonoboControl *control; + + s->priv->progress = gtk_progress_bar_new (); + + control = bonobo_control_new (s->priv->progress); + bonobo_ui_component_object_set (s->priv->ui_component, + "/status/ProgressWrapper", + BONOBO_OBJREF (control), + NULL); + + gtk_widget_show_all (s->priv->progress); +} + +static void +statusbar_set_window (Statusbar *s, EphyWindow *window) +{ + g_return_if_fail (s->priv->window == NULL); + + s->priv->window = window; + s->priv->ui_component = BONOBO_UI_COMPONENT + (s->priv->window->ui_component); + + create_statusbar_progress (s); + create_statusbar_security_icon (s); +} + +static void +statusbar_init (Statusbar *t) +{ + t->priv = g_new0 (StatusbarPrivate, 1); + t->priv->visibility = TRUE; + + t->priv->tooltips = gtk_tooltips_new (); +} + +static void +statusbar_finalize (GObject *object) +{ + Statusbar *t; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_STATUSBAR (object)); + + t = STATUSBAR (object); + + g_return_if_fail (t->priv != NULL); + + gtk_object_destroy (GTK_OBJECT (t->priv->tooltips)); + + g_free (t->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +Statusbar * +statusbar_new (EphyWindow *window) +{ + Statusbar *t; + + t = STATUSBAR (g_object_new (STATUSBAR_TYPE, + "EphyWindow", window, + NULL)); + + g_return_val_if_fail (t->priv != NULL, NULL); + + return t; +} + +void +statusbar_set_visibility (Statusbar *t, + gboolean visibility) +{ + if (visibility == t->priv->visibility) return; + + t->priv->visibility = visibility; + + ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(t->priv->ui_component), + "/status", + !visibility); +} + +void +statusbar_set_security_state (Statusbar *t, + gboolean state, + const char *tooltip) +{ + const char *stock; + + stock = state ? EPHY_STOCK_SECURE : EPHY_STOCK_UNSECURE; + + gtk_image_set_from_stock (GTK_IMAGE (t->priv->security_icon), stock, + GTK_ICON_SIZE_MENU); + + gtk_tooltips_set_tip (t->priv->tooltips, t->priv->security_evbox, + tooltip, NULL); +} + +void +statusbar_set_progress (Statusbar *t, + int progress) +{ + if (progress == -1) + { + gtk_progress_bar_pulse (GTK_PROGRESS_BAR(t->priv->progress)); + } + else + { + float tmp; + tmp = (float)(progress) / 100; + gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(t->priv->progress), + tmp); + } +} + +void +statusbar_set_message (Statusbar *s, + const char *message) +{ + g_return_if_fail (BONOBO_IS_UI_COMPONENT(s->priv->ui_component)); + g_return_if_fail (message != NULL); + + /* Bonobo doesnt like 0 length messages */ + if (g_utf8_strlen (message, -1) == 0) + { + message = " "; + } + + if (bonobo_ui_component_get_container (s->priv->ui_component)) /* should not do this here... */ + { + bonobo_ui_component_set_status (s->priv->ui_component, + message, + NULL); + } +} + diff --git a/src/statusbar.h b/src/statusbar.h new file mode 100644 index 000000000..590b89394 --- /dev/null +++ b/src/statusbar.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef STATUSBAR_H +#define STATUSBAR_H + +#include "ephy-window.h" + +G_BEGIN_DECLS + +#include <glib-object.h> +#include <glib.h> + +typedef struct Statusbar Statusbar; +typedef struct StatusbarClass StatusbarClass; + +#define STATUSBAR_TYPE (statusbar_get_type ()) +#define STATUSBAR(obj) (GTK_CHECK_CAST ((obj), STATUSBAR_TYPE, Statusbar)) +#define STATUSBAR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), STATUSBAR, StatusbarClass)) +#define IS_STATUSBAR(obj) (GTK_CHECK_TYPE ((obj), STATUSBAR_TYPE)) +#define IS_STATUSBAR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), STATUSBAR)) + +typedef struct StatusbarPrivate StatusbarPrivate; + +struct Statusbar +{ + GObject parent; + StatusbarPrivate *priv; +}; + +struct StatusbarClass +{ + GObjectClass parent_class; +}; + +GType statusbar_get_type (void); + +Statusbar *statusbar_new (EphyWindow *window); + +void statusbar_set_visibility (Statusbar *s, + gboolean visibility); + +void statusbar_set_security_state (Statusbar *s, + gboolean state, + const char *tooltip); + +void statusbar_set_progress (Statusbar *s, + int progress); + +void statusbar_set_message (Statusbar *s, + const gchar *message); + +G_END_DECLS + +#endif diff --git a/src/toolbar.c b/src/toolbar.c new file mode 100755 index 000000000..4bff4615e --- /dev/null +++ b/src/toolbar.c @@ -0,0 +1,982 @@ +/* + * Copyright (C) 2000 Marco Pesenti Gritti + * (C) 2001, 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); + +#include "toolbar.h" +#include "ephy-spinner.h" +#include "ephy-window.h" +#include "ephy-bonobo-extensions.h" +#include "ephy-string.h" +#include "ephy-gui.h" +#include "ephy-location-entry.h" +#include "ephy-shell.h" +#include "ephy-embed-favicon.h" +#include "ephy-dnd.h" +#include "ephy-toolbar-bonobo-view.h" +#include "ephy-prefs.h" +#include "eel-gconf-extensions.h" + +#include <string.h> +#include <bonobo/bonobo-i18n.h> +#include <bonobo/bonobo-window.h> +#include <bonobo/bonobo-control.h> +#include <bonobo/bonobo-ui-toolbar-button-item.h> +#include <bonobo/bonobo-property-bag.h> +#include <gtk/gtkentry.h> +#include <gtk/gtkmenu.h> + +#define DEFAULT_TOOLBAR_SETUP \ + "back=std_toolitem(item=back);" \ + "back_history=navigation_history(direction=back);" \ + "up=std_toolitem(item=up);" \ + "up_history=navigation_history(direction=up);" \ + "forward=std_toolitem(item=forward);" \ + "forward_history=navigation_history(direction=forward);" \ + "stop=std_toolitem(item=stop);" \ + "reload=std_toolitem(item=reload);" \ + "home=std_toolitem(item=home);" \ + "favicon=favicon;" \ + "location=location;" \ + "zoom=zoom;" \ + "spinner=spinner;" + +#define ZOOM_DELAY 50 + +static void toolbar_class_init (ToolbarClass *klass); +static void toolbar_init (Toolbar *t); +static void toolbar_finalize (GObject *object); +static void toolbar_set_window (Toolbar *t, EphyWindow *window); +static void toolbar_get_widgets (Toolbar *t); +static void toolbar_changed_cb (EphyToolbar *gt, Toolbar *t); +static void +toolbar_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void +toolbar_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + + +enum +{ + PROP_0, + PROP_EPHY_WINDOW +}; + +enum +{ + TOOLBAR_ITEM_STYLE_PROP, + TOOLBAR_ITEM_ORIENTATION_PROP, + TOOLBAR_ITEM_PRIORITY_PROP +}; + +static GObjectClass *parent_class = NULL; + +struct ToolbarPrivate +{ + EphyWindow *window; + BonoboUIComponent *ui_component; + EphyTbBonoboView *bview; + + GtkWidget *spinner; + gboolean visibility; + /* This field is unused... what is it? + GdkPixbufAnimation *animation; + */ + GtkWidget *back_button; + GtkWidget *forward_button; + GtkWidget *up_button; + GtkWidget *location_entry; + GtkTooltips *tooltips; + GtkWidget *favicon; + GtkWidget *favicon_ebox; + GtkWidget *zoom_spinbutton; + guint zoom_timeout_id; + gboolean zoom_lock; +}; + +GType +toolbar_get_type (void) +{ + static GType toolbar_type = 0; + + if (toolbar_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (ToolbarClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) toolbar_class_init, + NULL, + NULL, /* class_data */ + sizeof (Toolbar), + 0, /* n_preallocs */ + (GInstanceInitFunc) toolbar_init + }; + + toolbar_type = g_type_register_static (EPHY_TYPE_TOOLBAR, + "Toolbar", + &our_info, 0); + } + + return toolbar_type; + +} + +static void +toolbar_class_init (ToolbarClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = toolbar_finalize; + + object_class->set_property = toolbar_set_property; + object_class->get_property = toolbar_get_property; + + g_object_class_install_property (object_class, + PROP_EPHY_WINDOW, + g_param_spec_object ("EphyWindow", + "EphyWindow", + "Parent window", + EPHY_WINDOW_TYPE, + G_PARAM_READWRITE)); +} + +static void +toolbar_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + Toolbar *t = TOOLBAR (object); + + switch (prop_id) + { + case PROP_EPHY_WINDOW: + toolbar_set_window (t, g_value_get_object (value)); + break; + } +} + +static void +toolbar_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + Toolbar *t = TOOLBAR (object); + + switch (prop_id) + { + case PROP_EPHY_WINDOW: + g_value_set_object (value, t->priv->window); + break; + } +} + +static GtkWidget * +new_history_menu_item (gint num, gchar *origtext, gboolean lettersok, + GtkWidget *menu, const GdkPixbuf *ico) +{ + GtkWidget *item = gtk_image_menu_item_new (); + GtkWidget *hb = gtk_hbox_new (FALSE, 0); + GtkWidget *label = gtk_label_new (origtext); + + gtk_box_pack_start (GTK_BOX (hb), label, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (item), hb); + + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), + gtk_image_new_from_pixbuf ((GdkPixbuf *) ico)); + + gtk_widget_show_all (item); + + return item; +} + +static void +activate_back_or_forward_menu_item_cb (GtkWidget *menu, EphyWindow *window) +{ + EphyEmbed *embed; + int go_nth; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + go_nth = (int)g_object_get_data (G_OBJECT(menu), "go_nth"); + + ephy_embed_shistory_go_nth (embed, go_nth); +} + +static void +activate_up_menu_item_cb (GtkWidget *menu, EphyWindow *window) +{ + EphyEmbed *embed; + int go_nth; + GSList *l; + gchar *url; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + go_nth = (int)g_object_get_data (G_OBJECT(menu), "go_nth"); + + ephy_embed_get_go_up_list (embed, &l); + + url = g_slist_nth_data (l, go_nth); + if (url) + { + ephy_embed_load_url (embed, url); + } + + g_slist_foreach (l, (GFunc) g_free, NULL); + g_slist_free (l); +} + +static gboolean +back_or_forward_button_pressed_callback (GtkWidget *widget, + GdkEventButton *event, + gpointer *user_data) +{ + Toolbar *t; + GtkWidget *menu; + int pos, count; + EphyEmbed *embed; + int start, end, accell_count = 0; + + g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE); + + t = TOOLBAR (user_data); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE); + + embed = ephy_window_get_active_embed (t->priv->window); + g_return_val_if_fail (embed != NULL, FALSE); + + ephy_embed_shistory_get_pos (embed, &pos); + ephy_embed_shistory_count (embed, &count); + + if (count == 0) return FALSE; + + if (widget == t->priv->back_button) + { + start = pos - 1; + end = -1; + } + else + { + start = pos + 1; + end = count; + } + + menu = gtk_menu_new (); + + while (start != end) + { + char *title, *url; + GtkWidget *item; + ephy_embed_shistory_get_nth (embed, start, FALSE, + &url, &title); + item = new_history_menu_item (accell_count, url, TRUE, + menu, NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + g_object_set_data (G_OBJECT(item), "go_nth", GINT_TO_POINTER (start)); + g_signal_connect (item, "activate", + G_CALLBACK (activate_back_or_forward_menu_item_cb), + t->priv->window); + gtk_widget_show_all (item); + + g_free (url); + g_free (title); + + accell_count++; + if (start < end) start++; + else start--; + } + + + gnome_popup_menu_do_popup_modal (menu, + ephy_gui_menu_position_under_widget, widget, event, widget, widget); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE); + + return TRUE; +} + +static gboolean +up_button_pressed_callback (GtkWidget *widget, + GdkEventButton *event, + gpointer *user_data) +{ + Toolbar *t; + GtkWidget *menu; + EphyEmbed *embed; + int accell_count = 0; + GSList *l; + GSList *li; + + g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE); + + t = TOOLBAR (user_data); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE); + + embed = ephy_window_get_active_embed (t->priv->window); + g_return_val_if_fail (embed != NULL, FALSE); + + ephy_embed_get_go_up_list (embed, &l); + + if (l == NULL) return FALSE; + + menu = gtk_menu_new (); + + for (li = l; li; li = li->next) + { + char *url = li->data; + GtkWidget *item; + item = new_history_menu_item (accell_count, url, TRUE, + menu, NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + g_object_set_data (G_OBJECT(item), "go_nth", GINT_TO_POINTER (accell_count)); + g_signal_connect (item, "activate", + G_CALLBACK (activate_up_menu_item_cb), + t->priv->window); + gtk_widget_show_all (item); + + accell_count++; + } + + g_slist_foreach (l, (GFunc) g_free, NULL); + g_slist_free (l); + + gnome_popup_menu_do_popup_modal (menu, + ephy_gui_menu_position_under_widget, widget, event, widget, widget); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE); + + return TRUE; +} + +static gboolean +back_or_forward_key_pressed_callback (GtkWidget *widget, + GdkEventKey *event, + gpointer *user_data) +{ + if (event->keyval == GDK_space || + event->keyval == GDK_KP_Space || + event->keyval == GDK_Return || + event->keyval == GDK_KP_Enter) + { + back_or_forward_button_pressed_callback (widget, NULL, user_data); + } + + return FALSE; +} + +static gboolean +up_key_pressed_callback (GtkWidget *widget, + GdkEventKey *event, + gpointer *user_data) +{ + if (event->keyval == GDK_space || + event->keyval == GDK_KP_Space || + event->keyval == GDK_Return || + event->keyval == GDK_KP_Enter) + { + up_button_pressed_callback (widget, NULL, user_data); + } + + return FALSE; +} + +static void +toolbar_setup_navigation_button (Toolbar *t, GtkWidget *w, const char *tooltip) +{ + g_signal_connect_object (w, "key_press_event", + G_CALLBACK (back_or_forward_key_pressed_callback), + t, 0); + g_signal_connect_object (w, "button_press_event", + G_CALLBACK (back_or_forward_button_pressed_callback), + t, 0); + + gtk_tooltips_set_tip (t->priv->tooltips, w, tooltip, NULL); +} + +static void +toolbar_setup_up_button (Toolbar *t, GtkWidget *w, const char *tooltip) +{ + g_signal_connect_object (w, "key_press_event", + G_CALLBACK (up_key_pressed_callback), + t, 0); + g_signal_connect_object (w, "button_press_event", + G_CALLBACK (up_button_pressed_callback), + t, 0); + + gtk_tooltips_set_tip (t->priv->tooltips, w, tooltip, NULL); +} + + +static void +toolbar_location_url_activate_cb (EphyLocationEntry *entry, + const char *content, + const char *target, + EphyWindow *window) +{ + EphyBookmarks *bookmarks; + + bookmarks = ephy_shell_get_bookmarks (ephy_shell); + + if (!content) + { + ephy_window_load_url (window, target); + } + else + { + char *url; + + url = ephy_bookmarks_solve_smart_url + (bookmarks, target, content); + g_return_if_fail (url != NULL); + ephy_window_load_url (window, url); + g_free (url); + } +} + +static void +each_url_get_data_binder (EphyDragEachSelectedItemDataGet iteratee, + gpointer iterator_context, gpointer data) +{ + const char *location; + EphyTab *tab; + EphyWindow *window = EPHY_WINDOW(iterator_context); + + tab = ephy_window_get_active_tab (window); + location = ephy_tab_get_location (tab); + + iteratee (location, -1, -1, -1, -1, data); +} + +static void +favicon_drag_data_get_cb (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint32 time, + EphyWindow *window) +{ + g_assert (widget != NULL); + g_return_if_fail (context != NULL); + + ephy_dnd_drag_data_get (widget, context, selection_data, + info, time, window, each_url_get_data_binder); +} + +static void +toolbar_setup_favicon_ebox (Toolbar *t, GtkWidget *w) +{ + ToolbarPrivate *p = t->priv; + + g_return_if_fail (w == p->favicon_ebox); + + p->favicon = g_object_ref (ephy_embed_favicon_new + (ephy_window_get_active_embed (p->window))); + gtk_container_add (GTK_CONTAINER (p->favicon_ebox), p->favicon); + gtk_container_set_border_width (GTK_CONTAINER (p->favicon_ebox), 2); + + ephy_dnd_url_drag_source_set (p->favicon_ebox); + + g_signal_connect (G_OBJECT (p->favicon_ebox), + "drag_data_get", + G_CALLBACK (favicon_drag_data_get_cb), + p->window); + gtk_widget_show_all (p->favicon_ebox); +} + +static gboolean +toolbar_zoom_timeout_cb (gpointer data) +{ + Toolbar *t = data; + gint zoom = toolbar_get_zoom (t); + + g_return_val_if_fail (IS_EPHY_WINDOW (t->priv->window), FALSE); + + ephy_window_set_zoom (t->priv->window, zoom); + + return FALSE; +} + +static void +toolbar_zoom_spinbutton_value_changed_cb (GtkSpinButton *sb, Toolbar *t) +{ + ToolbarPrivate *p = t->priv; + if (p->zoom_timeout_id != 0) + { + g_source_remove (p->zoom_timeout_id); + } + if (!p->zoom_lock) + { + p->zoom_timeout_id = g_timeout_add (ZOOM_DELAY, toolbar_zoom_timeout_cb, t); + } +} + +static void +toolbar_setup_zoom_spinbutton (Toolbar *t, GtkWidget *w) +{ + g_signal_connect (w, "value_changed", + G_CALLBACK (toolbar_zoom_spinbutton_value_changed_cb), t); + gtk_tooltips_set_tip (t->priv->tooltips, w, _("Zoom"), NULL); +} + +static void +toolbar_setup_location_entry (Toolbar *t, GtkWidget *w) +{ + EphyAutocompletion *ac = ephy_shell_get_autocompletion (ephy_shell); + EphyLocationEntry *e; + + g_return_if_fail (w == t->priv->location_entry); + g_return_if_fail (EPHY_IS_LOCATION_ENTRY (w)); + + e = EPHY_LOCATION_ENTRY (w); + ephy_location_entry_set_autocompletion (e, ac); + + g_signal_connect (e, "activated", + GTK_SIGNAL_FUNC(toolbar_location_url_activate_cb), + t->priv->window); +} + +static void +toolbar_setup_spinner (Toolbar *t, GtkWidget *w) +{ + ToolbarPrivate *p = t->priv; + GtkWidget *spinner; + + g_return_if_fail (w == p->spinner); + + /* build the spinner and insert it into the box */ + spinner = ephy_spinner_new (); + ephy_spinner_set_small_mode (EPHY_SPINNER (spinner), TRUE); + gtk_container_add (GTK_CONTAINER (p->spinner), spinner); + gtk_widget_show (spinner); + + /* don't care about the box anymore */ + g_object_unref (p->spinner); + p->spinner = g_object_ref (spinner); +} + + +static void +toolbar_set_window (Toolbar *t, EphyWindow *window) +{ + g_return_if_fail (t->priv->window == NULL); + + t->priv->window = window; + t->priv->ui_component = g_object_ref (t->priv->window->ui_component); + + ephy_tb_bonobo_view_set_path (t->priv->bview, t->priv->ui_component, "/Toolbar"); + + toolbar_get_widgets (t); +} + +static void +toolbar_get_widgets (Toolbar *t) +{ + ToolbarPrivate *p; + EphyToolbar *gt; + EphyTbItem *it; + + DEBUG_MSG (("in toolbar_get_widgets\n")); + + g_return_if_fail (IS_TOOLBAR (t)); + p = t->priv; + g_return_if_fail (IS_EPHY_WINDOW (p->window)); + g_return_if_fail (BONOBO_IS_UI_COMPONENT (p->ui_component)); + + /* release all the widgets */ + + if (p->back_button) + { + g_object_unref (p->back_button); + p->back_button = NULL; + } + + if (p->forward_button) + { + g_object_unref (p->forward_button); + p->forward_button = NULL; + } + + if (p->up_button) + { + g_object_unref (p->up_button); + p->up_button = NULL; + } + + if (p->favicon_ebox) + { + g_object_unref (p->favicon_ebox); + p->favicon_ebox = NULL; + } + + if (p->favicon) + { + g_object_unref (p->favicon); + p->favicon = NULL; + } + + if (p->location_entry) + { + g_object_unref (p->location_entry); + p->location_entry = NULL; + } + + if (p->spinner) + { + g_object_unref (p->spinner); + p->spinner = NULL; + } + + if (p->zoom_spinbutton) + { + g_object_unref (p->zoom_spinbutton); + p->zoom_spinbutton = NULL; + } + + gt = EPHY_TOOLBAR (t); + + it = ephy_toolbar_get_item_by_id (gt, "back_history"); + if (it) + { + p->back_button = ephy_tb_item_get_widget (it); + g_object_ref (p->back_button); + toolbar_setup_navigation_button (t, p->back_button, _("Go back a number of pages")); + + DEBUG_MSG ((" got a back_history button\n")); + } + + it = ephy_toolbar_get_item_by_id (gt, "forward_history"); + if (it) + { + p->forward_button = ephy_tb_item_get_widget (it); + g_object_ref (p->forward_button); + toolbar_setup_navigation_button (t, p->forward_button, _("Go forward a number of pages")); + + DEBUG_MSG ((" got a forward_history button\n")); + } + + it = ephy_toolbar_get_item_by_id (gt, "up_history"); + if (it) + { + p->up_button = ephy_tb_item_get_widget (it); + g_object_ref (p->up_button); + toolbar_setup_up_button (t, p->up_button, _("Go up a number of levels")); + + DEBUG_MSG ((" got a up_history button\n")); + } + + it = ephy_toolbar_get_item_by_id (gt, "location"); + if (it) + { + p->location_entry = ephy_tb_item_get_widget (it); + g_object_ref (p->location_entry); + toolbar_setup_location_entry (t, p->location_entry); + + DEBUG_MSG ((" got a location entry\n")); + } + + it = ephy_toolbar_get_item_by_id (gt, "favicon"); + if (it) + { + p->favicon_ebox = ephy_tb_item_get_widget (it); + g_object_ref (p->favicon_ebox); + toolbar_setup_favicon_ebox (t, p->favicon_ebox); + + DEBUG_MSG ((" got a favicon ebox\n")); + } + + it = ephy_toolbar_get_item_by_id (gt, "spinner"); + if (it) + { + p->spinner = ephy_tb_item_get_widget (it); + g_object_ref (p->spinner); + toolbar_setup_spinner (t, p->spinner); + + DEBUG_MSG ((" got a spinner\n")); + } + + it = ephy_toolbar_get_item_by_id (gt, "zoom"); + if (it) + { + p->zoom_spinbutton = ephy_tb_item_get_widget (it); + g_object_ref (p->zoom_spinbutton); + toolbar_setup_zoom_spinbutton (t, p->zoom_spinbutton); + + DEBUG_MSG ((" got a zoom control\n")); + } + + /* update the controls */ + ephy_window_update_all_controls (p->window); +} + +static void +toolbar_init (Toolbar *t) +{ + t->priv = g_new0 (ToolbarPrivate, 1); + + t->priv->window = NULL; + t->priv->ui_component = NULL; + t->priv->visibility = TRUE; + t->priv->tooltips = gtk_tooltips_new (); + g_object_ref (t->priv->tooltips); + gtk_object_sink (GTK_OBJECT (t->priv->tooltips)); + + if (!ephy_toolbar_listen_to_gconf (EPHY_TOOLBAR (t), CONF_TOOLBAR_SETUP)) + { + /* FIXME: make this a dialog? */ + g_warning ("An incorrect toolbar configuration has been found, resetting to the default"); + + /* this is to make sure we get a toolbar, even if the + setup is wrong or there is no schema */ + eel_gconf_set_string (CONF_TOOLBAR_SETUP, DEFAULT_TOOLBAR_SETUP); + } + + g_signal_connect (t, "changed", G_CALLBACK (toolbar_changed_cb), t); + + t->priv->bview = ephy_tb_bonobo_view_new (); + ephy_tb_bonobo_view_set_toolbar (t->priv->bview, EPHY_TOOLBAR (t)); +} + +static void +toolbar_changed_cb (EphyToolbar *gt, Toolbar *t) +{ + g_return_if_fail (gt == EPHY_TOOLBAR (t)); + + if (t->priv->window) + { + toolbar_get_widgets (t); + } +} + +static void +toolbar_finalize (GObject *object) +{ + Toolbar *t; + ToolbarPrivate *p; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_TOOLBAR (object)); + + t = TOOLBAR (object); + p = t->priv; + + g_return_if_fail (p != NULL); + + if (p->location_entry) g_object_unref (p->location_entry); + if (p->back_button) g_object_unref (p->back_button); + if (p->forward_button) g_object_unref (p->forward_button); + if (p->up_button) g_object_unref (p->up_button); + if (p->favicon_ebox) g_object_unref (p->favicon_ebox); + if (p->favicon) g_object_unref (p->favicon); + if (p->spinner) g_object_unref (p->spinner); + if (p->tooltips) g_object_unref (p->tooltips); + if (p->zoom_spinbutton) g_object_unref (p->zoom_spinbutton); + if (p->zoom_timeout_id != 0) + { + g_source_remove (p->zoom_timeout_id); + } + + g_object_unref (t->priv->bview); + + g_free (t->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +Toolbar * +toolbar_new (EphyWindow *window) +{ + Toolbar *t; + + t = TOOLBAR (g_object_new (TOOLBAR_TYPE, + "EphyWindow", window, + NULL)); + + g_return_val_if_fail (t->priv != NULL, NULL); + + return t; +} + +void +toolbar_set_visibility (Toolbar *t, gboolean visibility) +{ + if (visibility == t->priv->visibility) return; + + t->priv->visibility = visibility; + + ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(t->priv->ui_component), + "/Toolbar", + !visibility); +} + +void +toolbar_activate_location (Toolbar *t) +{ + if (t->priv->location_entry) + { + ephy_location_entry_activate + (EPHY_LOCATION_ENTRY(t->priv->location_entry)); + } +} + +void +toolbar_spinner_start (Toolbar *t) +{ + if (t->priv->spinner) + { + ephy_spinner_start (EPHY_SPINNER(t->priv->spinner)); + } +} + +void +toolbar_spinner_stop (Toolbar *t) +{ + if (t->priv->spinner) + { + ephy_spinner_stop (EPHY_SPINNER(t->priv->spinner)); + } +} + +void +toolbar_button_set_sensitive (Toolbar *t, + ToolbarButtonID id, + gboolean sensitivity) +{ + switch (id) + { + case TOOLBAR_BACK_BUTTON: + ephy_bonobo_set_sensitive (t->priv->ui_component, + "/commands/GoBack", + sensitivity); + if (t->priv->back_button) + { + gtk_widget_set_sensitive (t->priv->back_button, + sensitivity); + } + break; + case TOOLBAR_FORWARD_BUTTON: + ephy_bonobo_set_sensitive (t->priv->ui_component, + "/commands/GoForward", + sensitivity); + if (t->priv->forward_button) + { + gtk_widget_set_sensitive (t->priv->forward_button, + sensitivity); + } + break; + case TOOLBAR_STOP_BUTTON: + ephy_bonobo_set_sensitive (t->priv->ui_component, + "/commands/GoStop", + sensitivity); + break; + case TOOLBAR_UP_BUTTON: + ephy_bonobo_set_sensitive (t->priv->ui_component, + "/commands/GoUp", + sensitivity); + if (t->priv->up_button) + { + gtk_widget_set_sensitive (t->priv->up_button, + sensitivity); + } + break; + } +} + +void +toolbar_set_location (Toolbar *t, + const char *location) +{ + g_return_if_fail (location != NULL); + + if (t->priv->location_entry) + { + ephy_location_entry_set_location + (EPHY_LOCATION_ENTRY (t->priv->location_entry), location); + } +} + +void +toolbar_update_favicon (Toolbar *t) +{ + if (t->priv->favicon) + { + ephy_embed_favicon_set_embed (EPHY_EMBED_FAVICON (t->priv->favicon), + ephy_window_get_active_embed (t->priv->window)); + } +} + +char * +toolbar_get_location (Toolbar *t) +{ + gchar *location; + if (t->priv->location_entry) + { + location = ephy_location_entry_get_location + (EPHY_LOCATION_ENTRY (t->priv->location_entry)); + } + else + { + location = g_strdup (""); + } + return location; +} + +gint +toolbar_get_zoom (Toolbar *t) +{ + gint zoom; + if (t->priv->zoom_spinbutton) + { + zoom = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (t->priv->zoom_spinbutton)); + } + else + { + zoom = 100; + } + return zoom; +} + +void +toolbar_set_zoom (Toolbar *t, gint zoom) +{ + ToolbarPrivate *p = t->priv; + if (p->zoom_spinbutton) + { + p->zoom_lock = TRUE; + gtk_spin_button_set_value (GTK_SPIN_BUTTON (p->zoom_spinbutton), zoom); + p->zoom_lock = FALSE; + } +} + diff --git a/src/toolbar.h b/src/toolbar.h new file mode 100644 index 000000000..5764c14e1 --- /dev/null +++ b/src/toolbar.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef TOOLBAR_H +#define TOOLBAR_H + +#include "ephy-window.h" +#include <glib-object.h> +#include <glib.h> +#include "ephy-toolbar.h" + +G_BEGIN_DECLS + +typedef struct ToolbarClass ToolbarClass; + +#define TOOLBAR_TYPE (toolbar_get_type ()) +#define TOOLBAR(obj) (GTK_CHECK_CAST ((obj), TOOLBAR_TYPE, Toolbar)) +#define TOOLBAR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), TOOLBAR, ToolbarClass)) +#define IS_TOOLBAR(obj) (GTK_CHECK_TYPE ((obj), TOOLBAR_TYPE)) +#define IS_TOOLBAR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), TOOLBAR)) + +typedef struct ToolbarPrivate ToolbarPrivate; + +typedef enum +{ + TOOLBAR_BACK_BUTTON, + TOOLBAR_FORWARD_BUTTON, + TOOLBAR_STOP_BUTTON, + TOOLBAR_UP_BUTTON +} ToolbarButtonID; + +struct Toolbar +{ + EphyToolbar parent_object; + ToolbarPrivate *priv; +}; + +struct ToolbarClass +{ + EphyToolbarClass parent_class; +}; + +GType toolbar_get_type (void); + +Toolbar *toolbar_new (EphyWindow *window); + +void toolbar_set_visibility (Toolbar *t, + gboolean visibility); + +void toolbar_button_set_sensitive (Toolbar *t, + ToolbarButtonID id, + gboolean sensitivity); + +void toolbar_spinner_start (Toolbar *t); + +void toolbar_spinner_stop (Toolbar *t); + +char *toolbar_get_location (Toolbar *t); + +void toolbar_set_location (Toolbar *t, + const char *location); + +gint toolbar_get_zoom (Toolbar *t); + +void toolbar_set_zoom (Toolbar *t, gint zoom); + +void toolbar_activate_location (Toolbar *t); + +void toolbar_update_favicon (Toolbar *t); + +G_END_DECLS + +#endif diff --git a/src/ui-prefs.c b/src/ui-prefs.c new file mode 100755 index 000000000..e461bf7e6 --- /dev/null +++ b/src/ui-prefs.c @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ui-prefs.h" +#include "ephy-shell.h" +#include "ephy-prefs.h" +#include "eel-gconf-extensions.h" +#include "ephy-spinner.h" + +#include <string.h> +#include <libgnome/gnome-util.h> +#include <libgnomeui/gnome-icon-list.h> + +static void ui_prefs_class_init (UIPrefsClass *klass); +static void ui_prefs_init (UIPrefs *dialog); +static void ui_prefs_finalize (GObject *object); + +/* Glade callbacks */ +void +spinners_iconlist_select_icon_cb (GtkWidget *iconlist, gint num, + GdkEvent *event, UIPrefs *dialog); + +static GObjectClass *parent_class = NULL; + +struct UIPrefsPrivate +{ + gpointer dummy; + GList *spinner_list; +}; + +enum +{ + SPINNERS_PROP, + OPEN_IN_TABS_PROP, + JUMP_TO_PROP, + POPUPS_PROP +}; + +static const +EphyDialogProperty properties [] = +{ + { SPINNERS_PROP, "spinners_iconlist", NULL, PT_NORMAL, NULL }, + { OPEN_IN_TABS_PROP, "open_in_tabs_checkbutton", CONF_TABS_TABBED, PT_AUTOAPPLY, NULL }, + { JUMP_TO_PROP, "jump_to_checkbutton", CONF_TABS_TABBED_AUTOJUMP, PT_AUTOAPPLY, NULL }, + { POPUPS_PROP, "popups_checkbutton", CONF_TABS_TABBED_POPUPS, PT_AUTOAPPLY, NULL }, + + { -1, NULL, NULL } +}; + +GType +ui_prefs_get_type (void) +{ + static GType ui_prefs_type = 0; + + if (ui_prefs_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (UIPrefsClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ui_prefs_class_init, + NULL, + NULL, /* class_data */ + sizeof (UIPrefs), + 0, /* n_preallocs */ + (GInstanceInitFunc) ui_prefs_init + }; + + ui_prefs_type = g_type_register_static (EPHY_DIALOG_TYPE, + "UIPrefs", + &our_info, 0); + } + + return ui_prefs_type; + +} + +static void +ui_prefs_class_init (UIPrefsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ui_prefs_finalize; +} + +/** + * Free any existing spinner list. + */ +static void +free_spinner_list (UIPrefs *dialog) +{ + GList *node; + + for (node = dialog->priv->spinner_list; node; node = node->next) + g_free(node->data); + + g_list_free(dialog->priv->spinner_list); + dialog->priv->spinner_list = NULL; +} + +/** + * spinner_get_path_from_index: used in prefs_callbacks.c to get the + * path of selected icon + */ +static const gchar * +spinner_get_path_from_index (UIPrefs *dialog, gint index) +{ + gchar *path; + + path = g_list_nth_data (dialog->priv->spinner_list, index); + + return path; +} + +/* + * spinner_fill_iconlist: fill a gnome icon list with icons of available spinners + */ +static void +spinner_fill_iconlist (UIPrefs *dialog, GnomeIconList *icon_list) +{ + GList *spinners, *tmp; + gchar *pref_spinner_path; + gint index; + + /* clear spinner list */ + free_spinner_list (dialog); + gnome_icon_list_clear (GNOME_ICON_LIST (icon_list)); + + pref_spinner_path = + eel_gconf_get_string (CONF_TOOLBAR_SPINNER_THEME); + index = gnome_icon_list_get_num_icons (icon_list); + + spinners = ephy_spinner_list_spinners (); + for (tmp = spinners; tmp != NULL; tmp = g_list_next (tmp)) + { + EphySpinnerInfo *info = tmp->data; + + dialog->priv->spinner_list = + g_list_append (dialog->priv->spinner_list, + g_strdup (info->name)); + + gnome_icon_list_append (icon_list, info->filename, info->name); + + /* Select the icon configured in prefs */ + if (pref_spinner_path && + strcmp (pref_spinner_path, info->name) == 0) + { + gnome_icon_list_select_icon (icon_list, index); + } + index++; + } + g_list_foreach (spinners, (GFunc)ephy_spinner_info_free, NULL); + g_list_free (spinners); + + g_free (pref_spinner_path); +} + +static void +ui_prefs_init (UIPrefs *dialog) +{ + GtkWidget *icon_list; + + dialog->priv = g_new0 (UIPrefsPrivate, 1); + dialog->priv->spinner_list = NULL; + + ephy_dialog_construct (EPHY_DIALOG(dialog), + properties, + "prefs-dialog.glade", + "ui_page_box"); + + icon_list = ephy_dialog_get_control (EPHY_DIALOG(dialog), + SPINNERS_PROP); + + spinner_fill_iconlist (dialog, GNOME_ICON_LIST (icon_list)); +} + +static void +ui_prefs_finalize (GObject *object) +{ + UIPrefs *dialog; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_UI_PREFS (object)); + + dialog = UI_PREFS (object); + + g_return_if_fail (dialog->priv != NULL); + + free_spinner_list (dialog); + + g_free (dialog->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +EphyDialog * +ui_prefs_new (void) +{ + UIPrefs *dialog; + + dialog = UI_PREFS (g_object_new (UI_PREFS_TYPE, + NULL)); + + return EPHY_DIALOG(dialog); +} + +void +spinners_iconlist_select_icon_cb (GtkWidget *iconlist, gint num, + GdkEvent *event, UIPrefs *dialog) +{ + const char *path; + path = spinner_get_path_from_index (dialog, num); + eel_gconf_set_string (CONF_TOOLBAR_SPINNER_THEME, path); +} diff --git a/src/ui-prefs.h b/src/ui-prefs.h new file mode 100644 index 000000000..bbd3dbe75 --- /dev/null +++ b/src/ui-prefs.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2002 Jorn Baayen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef UI_PREFS_H +#define UI_PREFS_H + +#include "ephy-dialog.h" + +#include <glib-object.h> +#include <glib.h> + +G_BEGIN_DECLS + +typedef struct UIPrefs UIPrefs; +typedef struct UIPrefsClass UIPrefsClass; + +#define UI_PREFS_TYPE (ui_prefs_get_type ()) +#define UI_PREFS(obj) (GTK_CHECK_CAST ((obj), UI_PREFS_TYPE, UIPrefs)) +#define UI_PREFS_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), UI_PREFS, UIPrefsClass)) +#define IS_UI_PREFS(obj) (GTK_CHECK_TYPE ((obj), UI_PREFS_TYPE)) +#define IS_UI_PREFS_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), UI_PREFS)) + +typedef struct UIPrefsPrivate UIPrefsPrivate; + +struct UIPrefs +{ + EphyDialog parent; + UIPrefsPrivate *priv; +}; + +struct UIPrefsClass +{ + EphyDialogClass parent_class; +}; + +GType ui_prefs_get_type (void); + +EphyDialog *ui_prefs_new (void); + +G_END_DECLS + +#endif + diff --git a/src/window-commands.c b/src/window-commands.c new file mode 100644 index 000000000..cef1d675c --- /dev/null +++ b/src/window-commands.c @@ -0,0 +1,917 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <config.h> + +#include "ephy-shell.h" +#include "window-commands.h" +#include "find-dialog.h" +#include "print-dialog.h" +#include "eel-gconf-extensions.h" +#include "ephy-prefs.h" +#include "ephy-embed-utils.h" +#include "pdm-dialog.h" +#include "toolbar.h" +#include "ephy-toolbar-editor.h" +#include "ephy-bookmarks-editor.h" +#include "ephy-new-bookmark.h" + +#include <string.h> +#include <libgnomevfs/gnome-vfs-uri.h> +#include <libgnomevfs/gnome-vfs-utils.h> +#include <bonobo/bonobo-i18n.h> +#include <libgnomeui/gnome-about.h> +#include <libgnome/gnome-help.h> +#include <gtk/gtkmessagedialog.h> +#include <gtk/gtkeditable.h> + +#define AVAILABLE_TOOLBAR_ITEMS \ + "new=std_toolitem(item=new);" \ + "back=std_toolitem(item=back);" \ + "back_history=navigation_history(direction=back);" \ + "up=std_toolitem(item=up);" \ + "up_history=navigation_history(direction=up);" \ + "forward=std_toolitem(item=forward);" \ + "forward_history=navigation_history(direction=forward);" \ + "stop=std_toolitem(item=stop);" \ + "reload=std_toolitem(item=reload);" \ + "home=std_toolitem(item=home);" \ + "favicon=favicon;" \ + "location=location;" \ + "go=std_toolitem(item=go);" \ + "zoom=zoom;" \ + "spinner=spinner;" \ + "separator;" + + + +void +window_cmd_edit_find (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyDialog *dialog; + dialog = ephy_window_get_find_dialog (window); + + g_object_ref (dialog); + + ephy_dialog_show (dialog); +} + +static void +print_dialog_preview_cb (PrintDialog *dialog, + EphyWindow *window) +{ + ephy_window_set_chrome (window, EMBED_CHROME_PPVIEWTOOLBARON); +} + +void +window_cmd_file_print (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyDialog *dialog; + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + dialog = print_dialog_new_with_parent (GTK_WIDGET(window), + embed, NULL); + g_signal_connect (G_OBJECT(dialog), + "preview", + G_CALLBACK (print_dialog_preview_cb), + window); + ephy_dialog_set_modal (dialog, TRUE); + ephy_dialog_show (dialog); +} + +void +window_cmd_go_back (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_go_back (embed); +} + +void +window_cmd_go_up (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_go_up (embed); +} + +void +window_cmd_file_send_to (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + char *url; + EphyTab *tab; + EphyEmbed *embed; + char *location; + char *title; + + tab = ephy_window_get_active_tab (window); + g_return_if_fail (tab); + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (tab); + + location = gnome_vfs_escape_string (ephy_tab_get_location (tab)); + if (ephy_embed_get_title (embed, &title) == G_OK) + { + char *tmp = gnome_vfs_escape_string (title); + g_free (title); + title = tmp; + } + else + { + title = gnome_vfs_escape_string (_("Check this out!")); + } + + url = g_strconcat ("mailto:", + "?Subject=", title, + "&Body=", location, NULL); + + ephy_embed_load_url (embed, url); + + g_free (title); + g_free (location); + g_free (url); +} + +void +window_cmd_go_forward (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_go_forward (embed); +} + +void +window_cmd_go_go (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + Toolbar *tb; + + g_return_if_fail (IS_EPHY_WINDOW (window)); + + tb = ephy_window_get_toolbar (window); + + if (tb) + { + char *location = toolbar_get_location (tb); + ephy_window_load_url (window, location); + g_free (location); + } +} + +void +window_cmd_go_home (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyEmbed *embed; + char *location; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + location = eel_gconf_get_string (CONF_GENERAL_HOMEPAGE); + g_return_if_fail (location != NULL); + + ephy_embed_load_url (embed, location); + + g_free (location); +} + +void +window_cmd_go_myportal (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_load_url (embed, "myportal:"); +} + +void +window_cmd_go_location (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + ephy_window_activate_location (window); +} + +void +window_cmd_go_stop (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_stop_load (embed); +} + +void +window_cmd_go_reload (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_reload (embed, EMBED_RELOAD_NORMAL); +} + +void +window_cmd_new (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyTab *tab; + + tab = ephy_window_get_active_tab (window); + + ephy_shell_new_tab (ephy_shell, window, tab, NULL, + EPHY_NEW_TAB_HOMEPAGE | + EPHY_NEW_TAB_JUMP); +} + +void +window_cmd_new_window (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyTab *tab; + + tab = ephy_window_get_active_tab (window); + + ephy_shell_new_tab (ephy_shell, NULL, tab, NULL, + EPHY_NEW_TAB_HOMEPAGE | + EPHY_NEW_TAB_IN_NEW_WINDOW | + EPHY_NEW_TAB_JUMP); +} + +void +window_cmd_new_tab (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyTab *tab; + + tab = ephy_window_get_active_tab (window); + + ephy_shell_new_tab (ephy_shell, window, tab, NULL, + EPHY_NEW_TAB_HOMEPAGE | + EPHY_NEW_TAB_IN_EXISTING_WINDOW | + EPHY_NEW_TAB_JUMP); +} + +void +window_cmd_bookmarks_edit (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + GtkWidget *dialog; + EphyBookmarks *bookmarks; + + bookmarks = ephy_shell_get_bookmarks (ephy_shell); + g_assert (bookmarks != NULL); + dialog = ephy_bookmarks_editor_new (bookmarks, GTK_WINDOW (window)); + gtk_widget_show (dialog); +} + +void +window_cmd_bookmarks_add_default (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyTab *tab; + EphyEmbed *embed; + EphyBookmarks *bookmarks; + GtkWidget *new_bookmark; + const char *location; + char *title; + + tab = ephy_window_get_active_tab (window); + g_return_if_fail (tab); + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (tab); + + location = ephy_tab_get_location (tab); + if (ephy_embed_get_title (embed, &title) != G_OK) + { + title = _("Untitled"); + } + + bookmarks = ephy_shell_get_bookmarks (ephy_shell); + new_bookmark = ephy_new_bookmark_new + (bookmarks, GTK_WINDOW (window), location); + ephy_new_bookmark_set_title + (EPHY_NEW_BOOKMARK (new_bookmark), title); + gtk_widget_show (new_bookmark); +} + +void +window_cmd_file_open (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + gchar *dir, *retDir; + gchar *file = NULL; + GnomeVFSURI *uri; + GtkWidget *wmain; + EphyEmbedShell *embed_shell; + gresult result; + + embed_shell = ephy_shell_get_embed_shell (ephy_shell); + g_return_if_fail (embed_shell != NULL); + + wmain = GTK_WIDGET (window); + g_return_if_fail (wmain != NULL); + + dir = eel_gconf_get_string (CONF_STATE_OPEN_DIR); + + result = ephy_embed_shell_show_file_picker + (embed_shell, wmain, + _("Select the file to open"), + dir, NULL, modeOpen, + &file, NULL, NULL, NULL); + + if (result == G_OK) + { + uri = gnome_vfs_uri_new (file); + if (uri) + { + + ephy_window_load_url(window, file); + + retDir = gnome_vfs_uri_extract_dirname (uri); + + /* set default open dir */ + eel_gconf_set_string (CONF_STATE_OPEN_DIR, + retDir); + + g_free (retDir); + gnome_vfs_uri_unref (uri); + } + } + + g_free (dir); + g_free (file); +} + +void +window_cmd_file_save_as (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyEmbed *embed; + EphyEmbedPersist *persist; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + persist = ephy_embed_persist_new (embed); + ephy_embed_persist_set_flags (persist, + EMBED_PERSIST_MAINDOC); + + ephy_embed_utils_save (GTK_WIDGET(window), + CONF_STATE_SAVE_DIR, + TRUE, + TRUE, + persist); + + g_object_unref (G_OBJECT(persist)); +} + +void +window_cmd_file_close_tab (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyTab *tab; + + tab = ephy_window_get_active_tab (window); + g_return_if_fail (tab != NULL); + + ephy_window_remove_tab (window, tab); +} + +void +window_cmd_file_close_window (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + gtk_widget_destroy (GTK_WIDGET(window)); +} + +void +window_cmd_edit_cut (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window)); + + if (GTK_IS_EDITABLE (widget)) + { + gtk_editable_cut_clipboard (GTK_EDITABLE (widget)); + } + else + { + EphyEmbed *embed; + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_selection_cut (embed); + } +} + +void +window_cmd_edit_copy (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window)); + + if (GTK_IS_EDITABLE (widget)) + { + gtk_editable_copy_clipboard (GTK_EDITABLE (widget)); + } + else + { + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_selection_copy (embed); + } +} + +void +window_cmd_edit_paste (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window)); + + if (GTK_IS_EDITABLE (widget)) + { + gtk_editable_paste_clipboard (GTK_EDITABLE (widget)); + } + else + { + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_paste (embed); + } +} + +void +window_cmd_edit_select_all (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window)); + + if (GTK_IS_EDITABLE (widget)) + { + gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1); + } + else + { + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_select_all (embed); + } +} + +void +window_cmd_edit_find_next (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyDialog *dialog; + + dialog = ephy_window_get_find_dialog (window); + + find_dialog_go_next (FIND_DIALOG(dialog), FALSE); + + ephy_window_update_control (window, FindControl); +} + +void +window_cmd_edit_find_prev (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyDialog *dialog; + + dialog = ephy_window_get_find_dialog (window); + + find_dialog_go_prev (FIND_DIALOG(dialog), FALSE); + + ephy_window_update_control (window, FindControl); +} + +void +window_cmd_view_zoom_in (BonoboUIComponent *uic, + EphyWindow *window, + const char *verbname) +{ + EphyEmbed *embed; + int zoom; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_zoom_get (embed, &zoom); + ephy_window_set_zoom (window, zoom + 10); +} + +void +window_cmd_view_zoom_out (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyEmbed *embed; + int zoom; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_zoom_get (embed, &zoom); + if (zoom >= 10) + { + ephy_window_set_zoom (window, zoom - 10); + } +} + +void +window_cmd_view_zoom_normal (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + ephy_window_set_zoom (window, 100); +} + +void +window_cmd_view_page_source (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyTab *tab; + + tab = ephy_window_get_active_tab (window); + g_return_if_fail (tab != NULL); + + ephy_shell_new_tab (ephy_shell, window, tab, NULL, + EPHY_NEW_TAB_VIEW_SOURCE); +} + +void +window_cmd_tools_history (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + ephy_window_show_history (window); +} + +void +window_cmd_tools_pdm (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyDialog *dialog; + + dialog = pdm_dialog_new (GTK_WIDGET(window)); + + ephy_dialog_show (dialog); +} + +void +window_cmd_edit_prefs (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + GtkDialog *dialog; + + dialog = prefs_dialog_new (); + prefs_dialog_show_page (PREFS_DIALOG(dialog), + PREFS_PAGE_GENERAL); + gtk_window_set_transient_for (GTK_WINDOW (dialog), + GTK_WINDOW (window)); + gtk_widget_show (GTK_WIDGET(dialog)); +} + +static void +window_cmd_settings_toolbar_editor_revert_clicked_cb (GtkButton *b, EphyTbEditor *tbe) +{ + gchar *def; + + g_return_if_fail (EPHY_IS_TB_EDITOR (tbe)); + + eel_gconf_unset (CONF_TOOLBAR_SETUP); + def = eel_gconf_get_string (CONF_TOOLBAR_SETUP); + if (def) + { + EphyToolbar *current; + EphyToolbar *avail; + current = ephy_tb_editor_get_toolbar (tbe); + ephy_toolbar_parse (current, def); + g_free (def); + + avail = ephy_tb_editor_get_available (tbe); + g_object_ref (avail); + ephy_toolbar_parse (avail, AVAILABLE_TOOLBAR_ITEMS); + ephy_tb_editor_set_available (tbe, avail); + g_object_unref (avail); + } + +} + +static void +window_cmd_settings_toolbar_editor_current_changed_cb (EphyToolbar *tb, gpointer data) +{ + gchar *current_str; + + g_return_if_fail (EPHY_IS_TOOLBAR (tb)); + + current_str = ephy_toolbar_to_string (tb); + eel_gconf_set_string (CONF_TOOLBAR_SETUP, current_str); + g_free (current_str); +} + +void +window_cmd_settings_toolbar_editor (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + static EphyTbEditor *tbe = NULL; + EphyToolbar *avail; + EphyToolbar *current; + gchar *current_str; + GtkButton *revert_button; + + avail = ephy_toolbar_new (); + ephy_toolbar_parse (avail, AVAILABLE_TOOLBAR_ITEMS); + + current_str = eel_gconf_get_string (CONF_TOOLBAR_SETUP); + current = ephy_toolbar_new (); + if (current_str) + { + ephy_toolbar_parse (current, current_str); + g_free (current_str); + } + + if (!tbe) + { + tbe = ephy_tb_editor_new (); + g_object_add_weak_pointer (G_OBJECT (tbe), + (void **)&tbe); + ephy_tb_editor_set_parent (tbe, + GTK_WIDGET(window)); + } + else + { + ephy_tb_editor_show (tbe); + return; + } + + ephy_tb_editor_set_toolbar (tbe, current); + ephy_tb_editor_set_available (tbe, avail); + g_object_unref (avail); + g_object_unref (current); + + g_signal_connect (current, "changed", + G_CALLBACK (window_cmd_settings_toolbar_editor_current_changed_cb), NULL); + + revert_button = ephy_tb_editor_get_revert_button (tbe); + gtk_widget_show (GTK_WIDGET (revert_button)); + + g_signal_connect (revert_button, "clicked", + G_CALLBACK (window_cmd_settings_toolbar_editor_revert_clicked_cb), tbe); + + ephy_tb_editor_show (tbe); +} + +void +window_cmd_help_about (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + static GtkWidget *about = NULL; + + static gchar *authors[] = { + "Marco Pesenti Gritti <mpeseng@tin.it>", + NULL + }; + + gchar *documenters[] = { + NULL + }; + + /* Translator credits */ + gchar *translator_credits = _("translator_credits"); + + if (about != NULL) + { + gdk_window_show(about->window); + gdk_window_raise(about->window); + return; + } + + about = gnome_about_new( + _("Epiphany"), VERSION, + /* Translators: Please change the (C) to a real + * copyright character if your character set allows it + * (Hint: iso-8859-1 is one of the character sets that + * has this symbol). */ + _("Copyright (C) 2002 Marco Pesenti Gritti"), + _("A GNOME browser based on Mozilla"), + (const char **)authors, + (const char **)documenters, + strcmp (translator_credits, "translator_credits") != 0 ? translator_credits : NULL, + NULL); + + gtk_window_set_transient_for (GTK_WINDOW (about), + GTK_WINDOW (window)); + g_object_add_weak_pointer (G_OBJECT (about), (gpointer *)&about); + gtk_widget_show (about); +} + +void +window_cmd_set_charset (BonoboUIComponent *uic, + EncodingMenuData *data, + const char* verbname) +{ + EphyWindow *window = data->data; + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + g_print (data->encoding); + ephy_embed_set_charset (embed, data->encoding); +} + +void +window_cmd_tabs_next (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + GList *tabs; + EphyTab *tab; + + tab = ephy_window_get_active_tab (window); + tabs = ephy_window_get_tabs (window); + g_return_if_fail (tab != NULL); + + tabs = g_list_find (tabs, (gpointer)tab); + tabs = tabs->next; + + if (tabs) + { + tab = EPHY_TAB (tabs->data); + ephy_window_jump_to_tab (window, tab); + g_list_free (tabs); + } +} + +void +window_cmd_tabs_previous (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + GList *tabs; + EphyTab *tab; + + tab = ephy_window_get_active_tab (window); + tabs = ephy_window_get_tabs (window); + g_return_if_fail (tab != NULL); + + tabs = g_list_find (tabs, (gpointer)tab); + tabs = tabs->prev; + + if (tabs) + { + tab = EPHY_TAB (tabs->data); + ephy_window_jump_to_tab (window, tab); + g_list_free (tabs); + } +} + +void +window_cmd_tabs_move_left (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ +} + +void window_cmd_tabs_move_right (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ +} + +void +window_cmd_tabs_detach (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname) +{ + EphyTab *tab; + GtkWidget *src_page; + EphyWindow *new_win; + + if (g_list_length (ephy_window_get_tabs (window)) <= 1) { + return; + } + + tab = ephy_window_get_active_tab (window); + src_page = GTK_WIDGET (ephy_tab_get_embed (tab)); + new_win = ephy_window_new (); + ephy_notebook_move_page (EPHY_NOTEBOOK (ephy_window_get_notebook (window)), + EPHY_NOTEBOOK (ephy_window_get_notebook (new_win)), + src_page, 0); + ephy_tab_set_window (tab, new_win); + gtk_widget_show (GTK_WIDGET (new_win)); +} + +void +window_cmd_help_manual (BonoboUIComponent *uic, + char *filename, + const char* verbname) +{ + GError *error; + GtkWidget *dialog; + + error = NULL; + gnome_help_display ("Ephy.xml", NULL, &error); + + if (error) + { + dialog = gtk_message_dialog_new (NULL, + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("There was an error displaying help: \n%s"), + error->message); + g_signal_connect (G_OBJECT (dialog), "response", + G_CALLBACK (gtk_widget_destroy), + NULL); + + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + gtk_widget_show (dialog); + g_error_free (error); + } +} diff --git a/src/window-commands.h b/src/window-commands.h new file mode 100644 index 000000000..df05a4d50 --- /dev/null +++ b/src/window-commands.h @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-window.h" +#include "ephy-embed-utils.h" + +#include <bonobo/bonobo-ui-component.h> + +void window_cmd_edit_find (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_file_print (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_go_stop (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_go_back (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_go_forward (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_go_go (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_go_up (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_go_home (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_go_myportal (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_go_location (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_go_reload (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_new (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_new_window (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_new_tab (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_bookmarks_add_default (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_bookmarks_edit (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_file_open (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_file_save_as (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_file_send_to (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_file_close_tab (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_file_close_window (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_edit_cut (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_edit_copy (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_edit_paste (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_edit_select_all (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_edit_find_next (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_edit_find_prev (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_view_zoom_in (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_view_zoom_out (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_view_zoom_normal(BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_view_page_source(BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_tools_history (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_tools_pdm (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_edit_prefs (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void +window_cmd_settings_toolbar_editor (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_help_about (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_set_charset (BonoboUIComponent *uic, + EncodingMenuData *data, + const char* verbname); + +void window_cmd_tabs_next (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_tabs_previous (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_tabs_move_left (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_tabs_move_right (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_tabs_detach (BonoboUIComponent *uic, + EphyWindow *window, + const char* verbname); + +void window_cmd_help_manual (BonoboUIComponent *uic, + char *filename, + const char* verbname); + |