diff options
60 files changed, 8408 insertions, 0 deletions
@@ -0,0 +1 @@ +Craig Drummond <[email protected]> diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..0593586 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,82 @@ +project(KGtk) +cmake_minimum_required(VERSION 2.4.0) + +set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README") +set(CPACK_GENERATOR "TBZ2") +set(CPACK_SOURCE_GENERATOR "TBZ2") +set(CPACK_PACKAGE_VERSION_MAJOR "0") +set(CPACK_PACKAGE_VERSION_MINOR "10") +set(CPACK_PACKAGE_VERSION_PATCH "1") +set(KGTK_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}") +set(KGTK_VERSION_FULL "${KGTK_VERSION}.${CPACK_PACKAGE_VERSION_PATCH}") +set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${KGTK_VERSION_FULL}") +include(CPack) + +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) +include(CheckFunctionExists) +check_function_exists(getpeereid HAVE_GETPEEREID) + +# Cant compile Qt3/KDE3 at the same time as Qt4/KDE4... +if ("${KGTK_KDE4}" MATCHES "true" OR "${KGTK_QT4}" MATCHES "true") + if (NOT "${KGTK_KDE3}" MATCHES "false" OR NOT "${KGTK_QT3}" MATCHES "false") + set(KGTK_KDE3 "false") + set(KGTK_QT3 "false") + message("** INFORMATION: Compiling Qt4/KDE4, Qt3/KDE3 disabled") + endif (NOT "${KGTK_KDE3}" MATCHES "false" OR NOT "${KGTK_QT3}" MATCHES "false") +endif ("${KGTK_KDE4}" MATCHES "true" OR "${KGTK_QT4}" MATCHES "true") + +if (NOT "${KGTK_KDE3}" MATCHES "false") + add_subdirectory(kdialogd3) +endif (NOT "${KGTK_KDE3}" MATCHES "false") + +if ("${KGTK_KDE4}" MATCHES "true") + add_subdirectory(kdialogd4) + # For some reason kdialogd4 does not install unless you cd into the kdialogd4 folder? + # ...hacky fix for this... + install(PROGRAMS ${CMAKE_BINARY_DIR}/kdialogd4/kdialogd4 DESTINATION bin) +endif ("${KGTK_KDE4}" MATCHES "true") + +if (NOT "${KGTK_GTK2}" MATCHES "false") + # Check if we have dlvsym... + find_library(LIBDLVSYM_LIBRARY + NAMES dl + PATHS /lib /usr/lib /usr/X11R6/lib /usr/local/lib) + + if(LIBDLVSYM_LIBRARY) + set(HAVE_DLVSYM 1) + # Determine version of dlsym... + find_library(LIBDL_LIBRARY + NAMES dl + PATHS /lib /usr/lib /usr/X11R6/lib /usr/local/lib) + + if(LIBDL_LIBRARY) + execute_process(COMMAND objdump --dynamic-syms ${LIBDL_LIBRARY} + COMMAND grep dlsym + OUTPUT_VARIABLE DLSYM_DATA) + separate_arguments(DLSYM_DATA) + if (${CMAKE_MAJOR_VERSION} GREATER 2 OR ${CMAKE_MINOR_VERSION} GREATER 4) + cmake_policy(SET CMP0007 OLD) + endif (${CMAKE_MAJOR_VERSION} GREATER 2 OR ${CMAKE_MINOR_VERSION} GREATER 4) + list(GET DLSYM_DATA 4 KGTK_DLSYM_VERSION) + endif(LIBDL_LIBRARY) + else(LIBDLVSYM_LIBRARY) + message("** INFORMATION: You're libdl does not contain dlvsym - SWT apps will not be supported") + endif(LIBDLVSYM_LIBRARY) + + add_subdirectory(gtk2) +endif (NOT "${KGTK_GTK2}" MATCHES "false") + +if (NOT "${KGTK_QT3}" MATCHES "false") + add_subdirectory(qt3) +endif (NOT "${KGTK_QT3}" MATCHES "false") + +if ("${KGTK_QT4}" MATCHES "true") + add_subdirectory(qt4) +endif ("${KGTK_QT4}" MATCHES "true") + + +install(PROGRAMS ${CMAKE_SOURCE_DIR}/kdialogd-wrapper DESTINATION bin) +install(PROGRAMS ${CMAKE_SOURCE_DIR}/kgtk-wrapper DESTINATION bin) + +message("** INFORMATION: Using installation prefix: ${CMAKE_INSTALL_PREFIX}") +configure_file (config.h.cmake ${CMAKE_BINARY_DIR}/config.h) @@ -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 0000000..46ae342 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,198 @@ +0.10.1 +------ +1. Fix 'kgtk-wrapper ./app' case. +2. Set filename for KdialogD4's save as filedialog. +3. Hacky fix for Firefox crashing when trying to save to a file that + already exists -> delete it first! +4. When launching KDialogD, try todetermin which version is installed. +5. Add some compile fixes from kde-apps + +0.10 +---- +1. Fix CMake bug at double definition of destantion dir for gmo. + - thanks to Yar Odin. +2. When KDialogD is started, write its PID to a file. When each app + attempts to connect to KDialogD, it checks if the PID in the file + is still active - if not it starts KDialogD. +3. KIO::NetAccess::mostLocalUrl fails if a file does not exist. If so, + then check if parent folder exists - and if so, append filename to + that. + +0.9.6 +----- +1. Fix russion translation files - thanks to Yar Odin +2. Fix some CMake 2.6 issues. + +0.9.5 +----- +1. Fix detection of firefox. Treat xulrunner as Firefox. +2. Quick hack for kino - always save as .kino +3. Prevent dummy gtk window from appearing in KDE4's 'present windows' + window selector. +4. Translations: + Brazillian Portuguese (pt_BR) Márcio Moraes + Russion (ru) Yar Odin +5. Fix kdialogd4's file widget. +6. Fix kgtk-wrapper script for relative paths - thanks to Ingo Müller. +7. set G_BROKEN_FILENAMES=1 for non UTF8 locales. + +0.9.4 +----- +1. Translations: + Spanish (es) Marco Antonio Blanco <[email protected]> +2. When saving with opera, show the suggested filename. + +0.9.3 +----- +1. Translations: + German (de) [email protected] + Czech (cs) Marián Kyral <[email protected]> +2. Fix firefox crash when overwriting an existing file. + +0.9.2 +----- +1. Remove 'which gimp' from kgtk-wrapper - oops! +2. In kgtk-wrapper, set opera to use qt3 +3. Fix opera crash. +4. Use GLib's convert function to convert to/from utf8, and + to/from URIs +5. Walk through Qt3's QFileDialog's children to locate combobox + containing filetypes, as opposed to using a copy of QFileDialogPrivate +6. Translations: + Simplified Chinese (zh_CN) Liang Qi <[email protected]> + French (fr) Paul Thomas <[email protected]> + British English (en_GB) Me! +7. Implement over-riding of non statically called Qt4 QFileDialogs + +0.9.1 +----- +1. Use cmake as build system. +2. Fix recognition of gimp 2.4 +3. Fix translation of standard kde strings. +4. Fix case where kgtk-wrapper is called via a symlink. + +0.9 +--- +1. Fix dialog parenting issues with Gtk folder picker combo/menu. +2. Fix compilation issue for KDE < 3.4 +3. Treat Iceweasel and Swiftfox the same as firefox. +4. Improve operation under beryl. +5. Add KDE4 and Qt4 support. +6. Reduce heavy CPU usage of kqt +7. Fix some i18n issues. +8. Place wrapper scripts into prefix/bin, and libraries into prefix/lib/kgtk +9. kgtk-wrapper can now be called for Gtk2, Qt3, nd Qt4 apps. The app is checked + to determin which toolkit it is using. If this check fails, you may edit + ~/.kde/share/config/kgtkrc and add lines such as + + [Apps] + eclipse=gtk2 + scribus=qt3 + abiword=x + + Setting "abiword=x" disables kgtk for abiword (as it doesnt work!) + +0.8 +--- +1. Install scripts into $prefix/bin as opposed to hard-coding + /usr/local/bin +2. Debug messages are disabled by default, to enable reconfigure + with --enable-debug-messages +3. Work correctly for autopackage'd apps - e.g. Inkscape 0.44 +4. Fix inkscape 0.44's export bitmap file dialog appearing underneath + export dialog. +5. Convert kdialogd to a KDE app. This app is started by Gtk/Qt apps, + and will self terminate 30 seconds after the last connected app + has disconnected. This timeout can be changed by editing kdialogdrc + and changing + + [General] + Timeout=10 + +6. Libraries installed to $KDEPREFIX/share/apps/kgtk +7. Remove .sh extension from scripts +8. When starting kdialogd, create the socket folder if it does not + already exist. + +**NOTE** You *MUST* remove any previous version of KGtk before using this +version. i.e. you must delete the kded_kdialgd.la, kded_kdialgd.so, and the +kdialogd.desktop files. KDE also must be restarted - to remove the KDED +module. + +0.7 +--- +1. Bug fix in wrapper scripts, use "$@" and not $* - thanks to + Victor Fernandez Martinez +2. Fix sending of UTF-8 characters from KDED module to app. + +0.6 +----- +1. Check for existance $KDETMP, or $TMPDIR when creating socket. +2. Use UTF-8 when talking to KDED module. + +0.5.1 +----- +1. Compile fixes - 64bit, Gtk<2.6 + +0.5 +--- +1. Make the KDED module a load-on-demand module, as opposed to always being + loaded. Module can be unloaded with: + + dcop kded kded unloadModule kdialogd + +2. Filters should now work for inkscape save - at least in inkscape 0.43 +3. Add ./configure check to ensure Gtk >= 2.4 +4. Added a ./configure check for dlvsym within libdl, if not found then + dlsym is not overriden - and SWT aps wont work :-( +5. In ./configure try to determine version of dlsym. +6. Try to load gtk_file_chooser_set/get_do_overwrite_confirmation's + from libgtk - if found then use, otherwise assume Gtk app will + do overwrite detection. +7. Correctly handle empty selection in single-file open mode. +8. Fix initial dir of non-statically called QFileDialogs +9. Modify Scribus's save file filters to have a "Compressed Documents" entry + -- will break localisation of scribus :-( + +0.4 +--- +1. Support non-statically called QFileDialogs +2. Fix compilation under KDE <3.5 +3. Save/restore PATH in wrapper scripts. +4. Now works with eclipse 3.1 (and all SWT apps? Seems to also work with + Azureus) +5. At start up Gtk app passes its name to KDialogD so that dialog settings + can be saved per-app. +6. Remove patterns from filter combo strings - more KDE like. + +** NOTE: After installing v0.4, KDE (or at least kded) *must* be restarted - + due to changes in the communication off apps -> kdialogd. + +0.3 +--- +1. Don't show Gtk file-overwrite dialogs, handle the file exists case within + KDE portion. +2. Fix retrieval/display of file filters. +3. Check for accessing of non-local URLs before dialog is closed. + +0.2.2 +----- +1. Remove kgtk-wrapper.sh and kqt-wrapper.sh shell scripts from archive - + these should've been generated at make time. Hopefully they will now. + +0.2.1 +----- +1. Fix qt compile issues. + +0.2 +--- +1. Convert kdialogd into a kded module. +2. Make gtk library a LD_PRELOAD library +3. Add a Qt library +4. Try to convert KURL's into local files +5. When performing a save as, etc, correctly set the current filename and path. +6. Remove font and colour dialog support + +0.1 +--- +1. Initial version. @@ -0,0 +1,124 @@ +Introduction +------------ + +KGtk is a quick-n-dirty hack to allow some Gtk2, Qt3, and Qt4 +applications to use KDE3 or KDE4 file dialogs. + +KGtk is composed of the following pieces: + +1. An application called kdialogd. In this archive there are + two varieties of this - a KDE3 version, and a KDE4 version. +2. LD_PRELOAD libraries that are used to override the Gtk2, Qt3, + and Qt4 file dialogs. + +If you start an application using the following command: + kgtk-wrapper gimp + +...the the following occurs: + +1. kgtk-wrapper determines whether the application is a Gtk2, Qt3, + or Qt4 application. It then sets the LD_PRELOAD environment + variable to point to the approriate KGtk library. +2. When the application now starts, it checks for the + KDE_SESSION_VERSION environment variable. If this is not set, + or is less than 4, then the KDE3 version of kdialogd is started, + else the KDE4 version is started. +3. When 'gimp' now tries to open a file dialog, the KGtk library + intercepts this, and asks kdialogd to open a file dialog instead. + +There will only ever be one instance of kdialogd, and all apps communicate with the same +instance - and it termiantes itself 30 seconds after the last Gtk/Qt app has +disconnected. This timeout can be changed by editing kdialogdrc and setting/changing + + [General] + Timeout=10 + + +Installation +------------ +As of v0.9.1, kgtk uses CMake in place of autotools. + +Because KGtk includes code for Qt3/KDE3 and Qt4/KDE4, you need +to specify when building which variants you would like to build. +This is accomplished as follows: + +1. mkdir build +2. cd build +3. cmake .. -DCMAKE_INSTALL_PREFIX=/usr +4. make +5. sudo make install + +* -DKGTK_KDE3=true instructs CMake to create makefiles for the KDE3 + version of KDialogD. Defaults to "true", use -DKGTK_KDE3=false + to turn off. Turning this on, sets -DKGTK_KDE4=false and + -DKGTK_QT4=false + +* -DKGTK_KDE4=true would instruct CMake to create makefiles for + the KDE4 version of KDialogD. Defaults to "false". + +* -DKGTK_GTK2=true instructs CMake to create makefiles for the Gtk2 + version of the LD_PRELOAD library. Defaults to "true", use + -DKGTK_GTK2=false to turn off. + +* -DKGTK_QT3=true instructs CMake to create makefiles for the Qt3 + version of the LD_PRELOAD library. Defaults to "true", use + -DKGTK_QT3=false to turn off. Turning this on, sets + -DKGTK_KDE4=false and -DKGTK_QT4=false + +* -DKGTK_QT4=true instructs CMake to create makefiles for the Qt4 + version of the LD_PRELOAD library. Defaults to "false". + +* For 64 bit systems, also append -DLIB_SUFFIX=64 + +Mixing '-DKGTK_KDE3=true' and '-DKGTK_KDE4=true' wont work, so compile the Qt3/KDE3, +and Qt4/KDE4 variants separately. Also, the 'build' folder *must* be cleaned before +switching to/from Qt3/KDE3 from/to Qt4/KDE4 + + +So, to compile everything I suggest the following: + + 1. mkdir build3 + 2. cd build3 + 3. cmake .. -DCMAKE_INSTALL_PREFIX=/usr + [ This will build KDialogD for KDE3, and create the LD_PRELOAD libraries for + Qt3 and Gtk2 ] + 4. make + 5. sudo make install + + 6. set up Qt4/KDE4 env variables + 7. clean build folder + + 8. mkdir build4 + 9. cd build4 +10. cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DKGTK_KDE4=true -DKGTK_QT4=true -DKGTK_GTK2=false +11. make +12. sudo make install + +NOTE: If you have both KDE3 and KDE4 installed, when calling cmake for KDE3, set KDEDIR to be empty. + e.g. + KDEDIR= cmake -DCMAKE_INSTALL_PREFIX=/usr -DKGTK_KDE4=false -DKGTK_QT4=false + +Notes +----- + +The library has been tested with the following applications: + +Reported to work: + + 1. Firefox (1.5.x only, not 1.0.x) + 2. Inkscape + 3. GIMP + 4. Kino + 5. Eclipse + 6. Azureus + 7. Galde-2 + 8. Streamtuner + 9. Avidemux2 + 10. Scribus + 11. QComcBook + 12. Planner 0.14: works, but asks twice for open file + +Reported *not* working: + + 1. AbiWord + @@ -0,0 +1 @@ +KDE4: File dialog history diff --git a/cmake/FindMsgfmt.cmake b/cmake/FindMsgfmt.cmake new file mode 100644 index 0000000..60e33ee --- /dev/null +++ b/cmake/FindMsgfmt.cmake @@ -0,0 +1,86 @@ +# +# - Try to find the msgfmt executeable +# +# It will set the following variables: +# +# MSGFMT_FOUND +# MSGFMT_EXECUTABLE +# +################################################################### +# +# Copyright (c) 2006, Andreas Schneider <[email protected]> +# +# 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., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +################################################################### +# +# Copyright (c) 2006 Andreas Schneider <[email protected]> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# * Neither the name of the cmake-modules nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +IF (MSGFMT_EXECUTABLE) + # in cache alread? + SET(MSGFMT_FOUND TRUE) +ELSE (MSGFMT_EXECUTABLE) + IF (UNIX) + FIND_PROGRAM(MSGFMT_EXECUTABLE + NAMES + msgfmt + PATHS + /usr/bin + /usr/local/bin + ) + + IF(MSGFMT_EXECUTABLE) + SET(MSGFMT_FOUND TRUE) + ELSE(MSGFMT_EXECUTABLE) + MESSAGE(FATAL_ERROR "msgfmt not found - po files can't be processed") + ENDIF(MSGFMT_EXECUTABLE) + + MARK_AS_ADVANCED(MSGFMT_EXECUTABLE) + ENDIF(UNIX) +ENDIF (MSGFMT_EXECUTABLE) + +# vim:et ts=2 sw=2 comments=\:\# diff --git a/common/common.h b/common/common.h new file mode 100644 index 0000000..ca246b9 --- /dev/null +++ b/common/common.h @@ -0,0 +1,237 @@ +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#define KDIALOGD_APP + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <time.h> +#include "config.h" + +#ifdef __KDIALOGD_H__ +#include <kstandarddirs.h> +#endif + +typedef enum +{ + OP_NULL = 0, + OP_FILE_OPEN = 1, + OP_FILE_OPEN_MULTIPLE = 2, + OP_FILE_SAVE = 3, + OP_FOLDER = 4 +} Operation; + +#define PID_DIR "kde-" +#define PID_NAME "kdialogd.pid" + +static const char * getPidFileName() +{ + static char *pidfile=NULL; + + if(!pidfile) + { + char *user=getenv("USER"); + + if(!user) + user=getenv("LOGNAME"); + + if(user) + { + char *tmp=getenv("KDETMP"); + + if(!tmp || !tmp[0]) + tmp=getenv("TMPDIR"); + + if(!tmp || !tmp[0]) + tmp=(char *)"/tmp"; + + pidfile=(char *)malloc(strlen(tmp)+strlen(PID_DIR)+strlen(user)+strlen(PID_NAME)+1); + pidfile=(char *)malloc(strlen(tmp)+strlen("/")+strlen(PID_DIR)+strlen(user)+strlen("/")+strlen(PID_NAME)+1); + +#ifdef __KDIALOGD_H__ + // We are kdialogd - so create socket folder if it does not exist... + sprintf(pidfile, "%s/%s%s", tmp, PID_DIR, user); + KStandardDirs::makeDir(QString::fromAscii(pidfile)); +#endif + + /* CPD: TODO get dispaly number! */ + sprintf(pidfile, "%s/%s%s/%s", tmp, PID_DIR, user, PID_NAME); + } + } + + return pidfile; +} + +#define SOCK_DIR "ksocket-" +#define SOCK_NAME "kdialogd" + +static const char * getSockName() +{ + static char *sock=NULL; + + if(!sock) + { + char *user=getenv("USER"); + + if(!user) + user=getenv("LOGNAME"); + + if(user) + { + char *tmp=getenv("KDETMP"); + + if(!tmp || !tmp[0]) + tmp=getenv("TMPDIR"); + + if(!tmp || !tmp[0]) + tmp=(char *)"/tmp"; + + sock=(char *)malloc(strlen(tmp)+strlen("/")+strlen(SOCK_DIR)+strlen(user)+strlen("/")+strlen(SOCK_NAME)+strlen("18446744073709551616")+1); + +#ifdef __KDIALOGD_H__ + // We are kdialogd - so create socket folder if it does not exist... + sprintf(sock, "%s/%s%s", tmp, SOCK_DIR, user); + KStandardDirs::makeDir(QString::fromAscii(sock)); +#endif + + /* CPD: TODO get dispaly number! */ + sprintf(sock, "%s/%s%s/%s-%d", tmp, SOCK_DIR, user, SOCK_NAME, 1); + } + } + + return sock; +} + +static int readBlock(int fd, char* pData, int size) +{ + int bytesToRead=size; + + do + { + fd_set fdSet; + + FD_ZERO(&fdSet); + FD_SET(fd, &fdSet); + + if(select(fd + 1, &fdSet, NULL, NULL, NULL)<0) + return 0; + + if(FD_ISSET(fd, &fdSet)) + { + int bytesRead=read(fd, &pData[size-bytesToRead], bytesToRead); + + if (bytesRead>0) + bytesToRead-=bytesRead; + else + return 0; + } + } + while(bytesToRead>0); + + return 1; +} + +static int writeBlock(int fd, const char *pData, int size) +{ + int bytesToWrite=size; + + do + { + fd_set fdSet; + + FD_ZERO(&fdSet); + FD_SET(fd, &fdSet); + + if(select(fd + 1, NULL, &fdSet, NULL, NULL)<0) + return 0; + + if(FD_ISSET(fd, &fdSet)) + { + int bytesWritten=write(fd, (char *)&pData[size-bytesToWrite], bytesToWrite); + + if (bytesWritten>0) + bytesToWrite-=bytesWritten; + else + return 0; + } + } + while(bytesToWrite>0); + + return 1; +} + +#ifdef KDIALOGD_APP +/* + So that kdailogd can terminate when the last app exits, need a way of synchronising the Gtk/Qt + apps that may wish to connect, and the removal of the socket. + + To this en, a lockfile is created,and used to guard around the critical sections +*/ +static int lockFd=-1; + +#define LOCK_EXT ".lock" + +const char * getLockName() +{ + static char *lockName=NULL; + + if(!lockName) + { + const char *sock=getSockName(); + + if(sock) + { + lockName=(char *)malloc(strlen(sock)+strlen(LOCK_EXT)+1); + sprintf(lockName, "%s%s", sock, LOCK_EXT); + } + } + + return lockName; +} + +/* Lock is stale if it does not exist or is older than 2 seconds */ +static int isStale(const char *fname) +{ + struct stat stat_buf; + + return 0!=stat(fname, &stat_buf) || + abs(stat_buf.st_mtime-time(NULL))>2; +} + +static int grabLock(int tries) +{ + do + { + lockFd=open(getLockName(), O_WRONLY | O_CREAT | O_EXCL, 0777); + if (lockFd<0 && errno==EEXIST) + { + /* Hmm, lock file already exists. Is it stale? */ + if(isStale(getLockName())) + { + tries++; /* Increment tries so that we try again... */ + unlink(getLockName()); + } + else if(tries) + usleep(100000); + } + } + while(lockFd<0 && --tries); + + return lockFd; +} + +static void releaseLock() +{ + if(lockFd>0) + { + close(lockFd); + unlink(getLockName()); + } +} +#endif + +#endif diff --git a/common/connect.h b/common/connect.h new file mode 100644 index 0000000..2499054 --- /dev/null +++ b/common/connect.h @@ -0,0 +1,311 @@ +#ifndef __CONNECT_H__ +#define __CONNECT_H__ + +#include <string.h> +#include <errno.h> +#include <signal.h> +#include <sys/wait.h> +#include "config.h" +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/stat.h> + +#ifndef SUN_LEN +#define SUN_LEN(ptr) ((socklen_t) (((struct sockaddr_un *) 0)->sun_path) \ + + strlen ((ptr)->sun_path)) +#endif + +#include "common.h" +#include "config.h" + +#ifdef __cplusplus +typedef bool kgtk_bool; +#define KGTK_TRUE true +#define KGTK_FALSE false +#else +typedef gboolean kgtk_bool; +#define KGTK_TRUE TRUE +#define KGTK_FALSE FALSE +#endif + + +static int kdialogdSocket=-1; + +/* From kdelibs/kdesu */ +#ifdef KDIALOGD_APP +static int createSocketConnectionReal() +#else +static int createSocketConnection() +#endif +{ +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection A\n"); +#endif + int sockfd=-1; + const char *sock=getSockName(); + struct sockaddr_un addr; + + if (access(sock, R_OK|W_OK)) + { +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - Could not access socket, %s\n", sock); +#endif + return -1; + } + + sockfd = socket(PF_UNIX, SOCK_STREAM, 0); + if (sockfd < 0) + { +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - Could not create socket, %d\n", errno); +#endif + return -1; + } + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, sock); + + if (connect(sockfd, (struct sockaddr *) &addr, SUN_LEN(&addr)) < 0) + { +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - Could not connect socket, %d\n", errno); +#endif + close(sockfd); + return -1; + } + +#if !defined(SO_PEERCRED) || !defined(HAVE_STRUCT_UCRED) +# if defined(HAVE_GETPEEREID) + { + uid_t euid; + gid_t egid; + /* Security: if socket exists, we must own it */ + if (getpeereid(sockfd, &euid, &egid) == 0) + { + if (euid != getuid()) + { +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - socket not owned by me! socket uid %d\n", euid); +#endif + close(sockfd); + return -1; + } + } + } +# else +# ifdef __GNUC__ +# warning "Using sloppy security checks" +# endif + /* We check the owner of the socket after we have connected. + If the socket was somehow not ours an attacker will be able + to delete it after we connect but shouldn't be able to + create a socket that is owned by us. */ + { + struct stat s; + if (lstat(sock, &s)!=0) + { +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - stat failed %s\n", sock); +#endif + close(sockfd); + return -1; + } + if (s.st_uid != getuid()) + { +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - socket not owned by me! socket uid %d\n", s.st_uid); +#endif + close(sockfd); + return -1; + } + if (!S_ISSOCK(s.st_mode)) + { +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - socket is not a socket %s\n", sock); +#endif + close(sockfd); + return -1; + } + } +# endif +#else + { + struct ucred cred; + socklen_t siz = sizeof(cred); + + /* Security: if socket exists, we must own it */ + if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &siz) == 0) + { + if (cred.uid != getuid()) + { +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - socket not owned by me! socket uid %d\n", cred.uid); +#endif + close(sockfd); + return -1; + } + } + } +#endif + +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - sockfd:%d\n", sockfd); +#endif + return sockfd; +} + +#ifdef KDIALOGD_APP +static int createSocketConnection() +{ + int rv=-1, + tries=0; + + do + { + if(-1==(rv=createSocketConnectionReal())) + usleep(10000); + } + while(-1==rv && ++tries<50); + + if(-1==rv) + fprintf(stderr, "ERROR: Could not talk to KDialogD!!!\n"); + return rv; +} +#endif + +static int kdialogdPid=-1; + +static kgtk_bool processIsRunning() +{ +#ifdef KGTK_DEBUG + printf("KGTK::processIsRunning\n"); +#endif + + if(-1!=kdialogdPid && 0==kill(kdialogdPid, 0)) + { +#ifdef KGTK_DEBUG + printf("KGTK::processIsRunning (%d) YES\n", kdialogdPid); +#endif + return KGTK_TRUE; + } + else + { + FILE *f=fopen(getPidFileName(), "r"); + + if(f) + { + int pid=0; + + if(1==fscanf(f, "%d", &pid)) + { + fclose(f); + + if(-1!=kdialogdPid && kdialogdPid!=pid) + { +#ifdef KGTK_DEBUG + printf("KGTK::processIsRunning pid has changed from:%d to %d - need to reconnect\n", kdialogdPid, pid); +#endif + kdialogdPid=pid; + return KGTK_FALSE; + } +#ifdef KGTK_DEBUG + printf("KGTK::processIsRunning file has pid:%d\n", pid); +#endif + if(0==kill(pid, 0)) + { +#ifdef KGTK_DEBUG + printf("KGTK::processIsRunning (file:%d) YES\n", pid); +#endif + kdialogdPid=pid; + return KGTK_TRUE; + } + + kdialogdPid=-1; /* Process is not running! */ + } + } + } +#ifdef KGTK_DEBUG + printf("KGTK::processIsRunning NO\n"); +#endif + return KGTK_FALSE; +} + +static void closeConnection() +{ +#ifdef KGTK_DEBUG + printf("KGTK::closeConnection\n"); +#endif + close(kdialogdSocket); + kdialogdSocket=-1; +} + +/* Note: Calling 'fork' seems to mess things up with eclipse! */ +#define KGTK_USE_SYSTEM_CALL + +static kgtk_bool connectToKDialogD(const char *appName) +{ +#ifdef KGTK_DEBUG + printf("KGTK::connectToKDialogD %s\n", appName ? appName : "<null>"); +#endif + if(!processIsRunning()) + closeConnection(); + + if(-1!=kdialogdSocket) + return KGTK_TRUE; + else + { + unsigned int slen=strlen(appName); + kgtk_bool rv=KGTK_TRUE; + + if(slen) + slen++; + +#ifdef KGTK_DEBUG + printf("KGTK::connectToKDialogD - start wrapper\n"); +#endif + +#ifdef KDIALOGD_APP + grabLock(5); +#ifdef KGTK_USE_SYSTEM_CALL + system("kdialogd-wrapper &"); +#else + switch(fork()) + { + case -1: + rv=KGTK_FALSE; + printf("ERROR: Could not start fork :-(\n"); + break; + case 0: + execl(KDIALOGD_LOCATION"/kdialogd-wrapper", "kdialogd-wrapper", (char *)NULL); + break; + default: + { + int status=0; + wait(&status); + } + } +#endif + releaseLock(); +#endif + + if(!rv) + return rv; + + rv= +#ifdef KDIALOGD_APP + grabLock(3)>0 && +#else + 0==system("dcop kded kded loadModule kdialogd") && +#endif + -1!=(kdialogdSocket=createSocketConnection()) && + writeBlock(kdialogdSocket, (char *)&slen, 4) && + (0==slen || writeBlock(kdialogdSocket, appName, slen)); +#ifdef KDIALOGD_APP + releaseLock(); +#endif + return rv; + } +} + +#endif diff --git a/config.h.cmake b/config.h.cmake new file mode 100644 index 0000000..7395b46 --- /dev/null +++ b/config.h.cmake @@ -0,0 +1,11 @@ +/* Define to 1 if you have the `getpeereid' function. */ +#cmakedefine HAVE_GETPEEREID 1 + +/* Define if you have the struct ucred */ +#cmakedefine HAVE_STRUCT_UCRED 1 +#cmakedefine HAVE_DLVSYM 1 + +#define VERSION "@KGTK_VERSION_FULL@" + +#define KGTK_DLSYM_VERSION "@KGTK_DLSYM_VERSION@" + diff --git a/debian/cdbs/buildvars.mk b/debian/cdbs/buildvars.mk new file mode 100644 index 0000000..23d4709 --- /dev/null +++ b/debian/cdbs/buildvars.mk @@ -0,0 +1,86 @@ +# -*- mode: makefile; coding: utf-8 -*- +# Copyright © 2002,2003 Colin Walters <[email protected]> +# Description: Defines some useful variables, but no rules +# +# 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. + +_cdbs_scripts_path ?= /usr/lib/cdbs +_cdbs_rules_path ?= /usr/share/cdbs/1/rules +_cdbs_class_path ?= /usr/share/cdbs/1/class + +ifndef _cdbs_rules_buildvars +_cdbs_rules_buildvars = 1 + +CDBS_VERSION = something + +# Common useful variables +DEB_SOURCE_PACKAGE := $(strip $(shell egrep '^Source: ' debian/control | cut -f 2 -d ':')) +DEB_VERSION := $(shell dpkg-parsechangelog | egrep '^Version:' | cut -f 2 -d ' ') +DEB_NOEPOCH_VERSION := $(shell echo $(DEB_VERSION) | cut -d: -f2-) +DEB_UPSTREAM_VERSION := $(shell echo $(DEB_NOEPOCH_VERSION) | sed 's/-[^-]*$$//') +DEB_ISNATIVE := $(shell dpkg-parsechangelog | egrep '^Version:' | perl -ne 'print if not /^Version:\s*.*-/;') + +# Split into arch/indep packages +ifneq ($(DEB_INDEP_PACKAGES),cdbs) +DEB_INDEP_PACKAGES := $(filter-out $(DONT_BUILD), $(strip $(shell $(_cdbs_scripts_path)/list-packages indep))) +DEB_ARCH_PACKAGES := $(filter-out $(DONT_BUILD), $(filter-out $(DEB_INDEP_PACKAGES),$(strip $(shell $(_cdbs_scripts_path)/list-packages same)))) +endif +# Split into normal and udeb packages +ifeq ($(DEB_UDEB_PACKAGES),) +DEB_PACKAGES = $(filter-out $(DONT_BUILD), $(filter-out %-udeb, $(DEB_ARCH_PACKAGES) $(DEB_INDEP_PACKAGES))) +DEB_UDEB_PACKAGES = $(filter-out $(DONT_BUILD),$(filter %-udeb, $(DEB_ARCH_PACKAGES) $(DEB_INDEP_PACKAGES))) +else +DEB_PACKAGES = $(filter-out $(DONT_BUILD), $(filter-out $(DEB_UDEB_PACKAGES), $(DEB_ARCH_PACKAGES) $(DEB_INDEP_PACKAGES))) +endif +# Too much bother for now. If someone complains we'll fix it. +#DEB_ARCH_UDEB_PACKAGES = $(filter %-udeb, $(DEB_ARCH_PACKAGES)) +#DEB_INDEP_UDEB_PACKAGES = $(filter %-udeb, $(DEB_INDEP_PACKAGES)) +# A handy list of every package, udeb or not +DEB_ALL_PACKAGES = $(filter-out $(DONT_BUILD),$(DEB_PACKAGES) $(DEB_UDEB_PACKAGES)) +DEB_INDEP_REGULAR_PACKAGES = $(filter-out $(DONT_BUILD), $(filter-out $(DEB_UDEB_PACKAGES),$(DEB_INDEP_PACKAGES))) +DEB_ARCH_REGULAR_PACKAGES = $(filter-out $(DONT_BUILD), $(filter-out $(DEB_UDEB_PACKAGES),$(DEB_ARCH_PACKAGES))) + +DEB_DBG_PACKAGES = $(filter-out $(DONT_BUILD), $(filter %-dbg, $(DEB_ARCH_PACKAGES) $(DEB_INDEP_PACKAGES))) + +# Some support for srcdir != builddir builds. +# These are relative to the root of the package +DEB_SRCDIR ?= . +DEB_BUILDDIR ?= $(strip $(DEB_SRCDIR)) + +# Miscellaneous bits +DEB_ARCH = $(shell dpkg --print-architecture) +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_HOST_GNU_SYSTEM ?= $(shell dpkg-architecture -qDEB_HOST_GNU_SYSTEM) +DEB_HOST_GNU_CPU ?= $(shell dpkg-architecture -qDEB_HOST_GNU_CPU) +DEB_HOST_ARCH ?= $(shell dpkg-architecture -qDEB_HOST_ARCH) +DEB_HOST_ARCH_CPU ?= $(shell dpkg-architecture -qDEB_HOST_ARCH_CPU) +DEB_HOST_ARCH_OS ?= $(shell dpkg-architecture -qDEB_HOST_ARCH_OS) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) +DEB_BUILD_GNU_SYSTEM ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_SYSTEM) +DEB_BUILD_GNU_CPU ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_CPU) +DEB_BUILD_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH) +DEB_BUILD_ARCH_CPU ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH_CPU) +DEB_BUILD_ARCH_OS ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS) + +ifeq ($(words $(DEB_ALL_PACKAGES)),1) + DEB_DESTDIR = $(CURDIR)/debian/$(strip $(DEB_ALL_PACKAGES))/ +else + DEB_DESTDIR = $(CURDIR)/debian/tmp/ +endif + +CDBS_BUILD_DEPENDS := $(CDBS_BUILD_DEPENDS), cdbs (>= 0.4.23-1.1) + +endif diff --git a/debian/cdbs/debian-qt-kde.mk b/debian/cdbs/debian-qt-kde.mk new file mode 100644 index 0000000..2be8f97 --- /dev/null +++ b/debian/cdbs/debian-qt-kde.mk @@ -0,0 +1,109 @@ +ifndef _cdbs_bootstrap +_cdbs_scripts_path ?= /usr/lib/cdbs +_cdbs_rules_path ?= /usr/share/cdbs/1/rules +_cdbs_class_path ?= /usr/share/cdbs/1/class +endif + +ifndef _cdbs_class_debian-qt-kde +_cdbs_class_debian-qt-kde := 1 + +# Note: This _must_ be included before autotools.mk, or it won't work. +common-configure-arch common-configure-indep:: debian/stamp-cvs-make +debian/stamp-cvs-make: + cp -Rp /usr/share/aclocal/libtool.m4 admin/libtool.m4.in + cp -Rp /usr/share/libtool/config/ltmain.sh admin/ltmain.sh + $(MAKE) -C $(DEB_SRCDIR) -f admin/Makefile.common dist; + touch debian/stamp-cvs-make + +include debian/cdbs/kde.mk$(_cdbs_makefile_suffix) +include debian/cdbs/uploaders.mk + +DEB_PATCHDIRS := debian/patches/common debian/patches + +DEB_KDE_ENABLE_FINAL := yes +DEB_INSTALL_DOCS_ALL := + +DEB_DH_MAKESHLIBS_ARGS_ALL := -V +DEB_SHLIBDEPS_INCLUDE = $(foreach p,$(PACKAGES_WITH_LIBS),debian/$(p)/usr/lib) + +ifeq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + cdbs_treat_me_gently_arches := arm m68k alpha ppc64 armel armeb + ifeq (,$(filter $(DEB_HOST_ARCH_CPU),$(cdbs_treat_me_gently_arches))) + cdbs_kde_enable_final = $(if $(DEB_KDE_ENABLE_FINAL),--enable-final,) + else + cdbs_kde_enable_final = + endif +endif + +common-build-arch:: debian/stamp-man-pages +debian/stamp-man-pages: + if ! test -d debian/man/out; then mkdir -p debian/man/out; fi + for f in $$(find debian/man -name '*.sgml'); do \ + docbook-to-man $$f > debian/man/out/`basename $$f .sgml`.1; \ + done + for f in $$(find debian/man -name '*.man'); do \ + soelim -I debian/man $$f \ + > debian/man/out/`basename $$f .man`.`head -n1 $$f | awk '{print $$NF}'`; \ + done + touch debian/stamp-man-pages + +common-binary-indep:: + ( set -e; \ + tmpf=`mktemp debian/versions.XXXXXX`; \ + perl debian/cdbs/versions.pl >$$tmpf; \ + for p in $(DEB_INDEP_PACKAGES); do \ + cat $$tmpf >>debian/$$p.substvars; \ + done; \ + rm -f $$tmpf ) + +common-binary-arch:: + ( set -e; \ + tmpf=`mktemp debian/versions.XXXXXX`; \ + perl debian/cdbs/versions.pl >$$tmpf; \ + for p in $(DEB_ARCH_PACKAGES); do \ + cat $$tmpf >>debian/$$p.substvars; \ + done; \ + rm -f $$tmpf ) + +clean:: + rm -rf debian/man/out + -rmdir debian/man + rm -f debian/stamp-man-pages + rm -rf debian/shlibs-check + +$(patsubst %,binary-install/%,$(DEB_PACKAGES)) :: binary-install/%: + if test -x /usr/bin/dh_desktop; then dh_desktop -p$(cdbs_curpkg) $(DEB_DH_DESKTOP_ARGS); fi + if test -e debian/$(cdbs_curpkg).lintian; then \ + install -p -D -m644 debian/$(cdbs_curpkg).lintian \ + debian/$(cdbs_curpkg)/usr/share/lintian/overrides/$(cdbs_curpkg); \ + fi + if test -e debian/$(cdbs_curpkg).presubj; then \ + install -p -D -m644 debian/$(cdbs_curpkg).presubj \ + debian/$(cdbs_curpkg)/usr/share/bug/$(cdbs_curpkg)/presubj; \ + fi + +binary-install/$(DEB_SOURCE_PACKAGE)-doc-html:: + set -e; \ + for doc in `cd $(DEB_DESTDIR)/opt/kde3/share/doc/kde/HTML/en; find . -name index.docbook`; do \ + pkg=$${doc%/index.docbook}; pkg=$${pkg#./}; \ + echo Building $$pkg HTML docs...; \ + mkdir -p $(CURDIR)/debian/$(DEB_SOURCE_PACKAGE)-doc-html/opt/kde3/share/doc/kde/HTML/en/$$pkg; \ + cd $(CURDIR)/debian/$(DEB_SOURCE_PACKAGE)-doc-html/opt/kde3/share/doc/kde/HTML/en/$$pkg; \ + /opt/kde3/bin/meinproc $(DEB_DESTDIR)/opt/kde3/share/doc/kde/HTML/en/$$pkg/index.docbook; \ + done + for pkg in $(DOC_HTML_PRUNE) ; do \ + rm -rf debian/$(DEB_SOURCE_PACKAGE)-doc-html/opt/kde3/share/doc/kde/HTML/en/$$pkg; \ + done + +clean:: + if test -n "$(DEB_KDE_CVS_MAKE)" && test -d $(DEB_SRCDIR); then \ + cd $(DEB_SRCDIR); \ + find . -name Makefile.in -print | \ + xargs --no-run-if-empty rm -f; \ + rm -f Makefile.am acinclude.m4 aclocal.m4 config.h.in \ + configure configure.files configure.in stamp-h.in \ + subdirs; \ + fi + rm -f debian/stamp-cvs-make + +endif diff --git a/debian/cdbs/kde.mk b/debian/cdbs/kde.mk new file mode 100644 index 0000000..9e41175 --- /dev/null +++ b/debian/cdbs/kde.mk @@ -0,0 +1,97 @@ +# -*- mode: makefile; coding: utf-8 -*- +# Copyright © 2003 Christopher L Cheney <[email protected]> +# Description: A class for KDE packages; sets KDE environment variables, etc +# +# 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. + +_cdbs_scripts_path ?= /usr/lib/cdbs +_cdbs_rules_path ?= /usr/share/cdbs/1/rules +_cdbs_class_path ?= /usr/share/cdbs/1/class + +ifndef _cdbs_class_kde +_cdbs_class_kde := 1 + +# for dh_icons +CDBS_BUILD_DEPENDS := $(CDBS_BUILD_DEPENDS), debhelper (>= 5.0.7ubuntu4) + +include $(_cdbs_rules_path)/buildcore.mk$(_cdbs_makefile_suffix) + +ifdef _cdbs_tarball_dir +DEB_BUILDDIR = $(_cdbs_tarball_dir)/obj-$(DEB_BUILD_GNU_TYPE) +else +DEB_BUILDDIR = obj-$(DEB_BUILD_GNU_TYPE) +endif + +include $(_cdbs_class_path)/autotools.mk$(_cdbs_makefile_suffix) + +export kde_cgidir = \$${libdir}/cgi-bin +export kde_confdir = \$${sysconfdir}/kde3 +export kde_htmldir = \$${datadir}/doc/kde/HTML + +ifeq (,$(filter noopt,$(DEB_BUILD_OPTIONS))) + cdbs_kde_enable_final = $(if $(DEB_KDE_ENABLE_FINAL),--enable-final,) +endif + +ifneq (,$(filter nostrip,$(DEB_BUILD_OPTIONS))) + cdbs_kde_enable_final = + cdbs_kde_enable_debug = --enable-debug=yes +else + cdbs_kde_enable_debug = --disable-debug +endif + +ifneq (,$(filter debug,$(DEB_BUILD_OPTIONS))) + cdbs_kde_enable_debug = --enable-debug=full +endif + +cdbs_configure_flags += --with-qt-dir=/usr/share/qt3 --disable-rpath --with-xinerama $(cdbs_kde_enable_final) $(cdbs_kde_enable_debug) + +DEB_AC_AUX_DIR = $(DEB_SRCDIR)/admin +DEB_CONFIGURE_INCLUDEDIR = "\$${prefix}/include/kde" +DEB_COMPRESS_EXCLUDE = .dcl .docbook -license .tag .sty .el + +$(patsubst %,binary-install/%,$(DEB_PACKAGES)) :: binary-install/%: + if test -x /usr/bin/dh_icons; then dh_icons -p$(cdbs_curpkg) $(DEB_DH_ICONCACHE_ARGS); fi + +cleanbuilddir:: + -$(if $(call cdbs_streq,$(DEB_BUILDDIR),$(DEB_SRCDIR)),,rm -rf $(DEB_BUILDDIR)) + +common-build-arch common-build-indep:: debian/stamp-kde-apidox +debian/stamp-kde-apidox: + $(if $(DEB_KDE_APIDOX),+$(DEB_MAKE_INVOKE) apidox) + touch $@ + +common-install-prehook-impl:: + mkdir -p po + -XGETTEXT=/usr/bin/kde-xgettext EXTRACTATTR=/opt/kde3/bin/extractattr sh $(DEB_SRCDIR)/admin/cvs.sh extract-messages + -for file in po/*pot; do \ + sed "s/charset=CHARSET/charset=UTF-8/" -i $$file; \ + done + +common-install-arch common-install-indep:: common-install-kde-apidox +common-install-kde-apidox:: + $(if $(DEB_KDE_APIDOX),+$(DEB_MAKE_INVOKE) install-apidox DESTDIR=$(DEB_DESTDIR)) + +clean:: + rm -f debian/stamp-kde-apidox + rm -rf po/*.pot + +# This is a convenience target for calling manually. It's not part of +# the build process. +buildprep: clean apply-patches + $(MAKE) -f admin/Makefile.common dist + debian/rules clean + +endif diff --git a/debian/cdbs/team-members b/debian/cdbs/team-members new file mode 100644 index 0000000..05761af --- /dev/null +++ b/debian/cdbs/team-members @@ -0,0 +1,16 @@ +Sune Vuorela <[email protected]> +Ana Beatriz Guerrero Lopez <[email protected]> +Fathi Boudra <[email protected]> +Modestas Vainius <[email protected]> +Josh Metzler <[email protected]> +Isaac Clerencia <[email protected]> +Adeodato Simó <[email protected]> +Adeodato Simo <[email protected]> +Christopher Martin <[email protected]> +Daniel Schepler <[email protected]> +Sarah Hobbs <[email protected]> +Nacho Barrientos Arias <[email protected]> +Ricardo Javier Cardenes Medina <[email protected]> +Ricardo Cardenes <[email protected]> +Armin Berres <[email protected]> +Francesco Pedrini <[email protected]> diff --git a/debian/cdbs/uploaders.mk b/debian/cdbs/uploaders.mk new file mode 100644 index 0000000..31adfe3 --- /dev/null +++ b/debian/cdbs/uploaders.mk @@ -0,0 +1,29 @@ + +MAINTAINER=Debian Qt/KDE Maintainers <[email protected]> +UPLOADERS=$(shell grep -e +++ -e "^ -- " debian/changelog | grep -v "[email protected]" | head -13 | /bin/sed 's/^\s*//;s/\s*$$//;s/^+++\? Changes by //;s/^+++\? //;s/-- //;s/:$$//;s/ <.*//' | sort -u | while read line ; do grep "$$line" debian/cdbs/team-members ; done | tr "\n" ", " | sed 's/,/, /g;s/, $$//') + + +debian/control.tmp: + @if [ ! -e debian/control.in ] ; then \ + echo "this package is not yet prepared for using automatic update of uploaders"; \ + echo "Please do so."; \ + exit 1; \ + fi + @sed 's/@@@UPLOADERS@@@/$(UPLOADERS)/;s#@@@MAINTAINER@@@#$(MAINTAINER)#' debian/control.in > debian/control.tmp + +check-uploaders: debian/control.tmp + @if ! diff -q debian/control debian/control.tmp ; then \ + echo "WARNING:: Control file differs from manually generated one" ; \ + echo "WARNING:: Please update it manually and check it afterwards" ; \ + echo "WARNING:: Uploaders are updated by debian/rules update-uploaders" ;\ + echo "WARNING:: If this is a binNMU, NMU or security upload, just ignore" ;\ + fi + + +clean:: + rm -f debian/control.tmp + +update-uploaders: debian/control.tmp + @mv -f debian/control.tmp debian/control + +makebuilddir:: check-uploaders diff --git a/debian/cdbs/versions.pl b/debian/cdbs/versions.pl new file mode 100644 index 0000000..9ce11d8 --- /dev/null +++ b/debian/cdbs/versions.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +my $version = `dpkg-parsechangelog | awk '/^Version/ {print \$2}'`; +my ($version3, $version3_next); +my ($version2, $version2_next); + +($version3 = $version) =~ s/-[^-]+$//; +($version2 = $version3) =~ s/\.[^.]+$//; + +($version3_next = $version3) =~ s/(?<=\.)(\d+)[a-z]?$/($1+1)/e; +($version2_next = $version2) =~ s/(?<=\.)(\d+)$/($1+1)/e; + +print "KDE-Version3=$version3\n"; +print "KDE-Version2=$version2\n"; +print "KDE-Next-Version3=$version3_next\n"; +print "KDE-Next-Version2=$version2_next\n"; diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..a69a5a0 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,11 @@ +kgtk-qt3-kde3 (0.10.2-0ubuntu5) maverick; urgency=low + + * Maverick build + + -- Timothy Pearson <[email protected]> Mon, 05 Apr 2010 13:20:00 -0600 + +kgtk-qt3 (0.10.1-0ubuntu1~ppa1) jaunty; urgency=low + + * Initial release + + -- Anthony Mercatante <[email protected]> Mon, 17 Mar 2009 01:24:08 +0100 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +7 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..226eafe --- /dev/null +++ b/debian/control @@ -0,0 +1,19 @@ +Source: kgtk-qt3-kde3 +Section: kde +Priority: optional +Maintainer: Timothy Pearson <[email protected]> +Build-Depends: debhelper (>= 7), cdbs, kdelibs4-kde3-dev, libgtk2.0-dev, libqt3-mt-dev, cmake +Standards-Version: 3.8.3 +Homepage: http://kde-apps.org/content/show.php/KGtk+(Use+KDE+Dialogs+in+Gtk+Apps)?content=36077 + +Package: kgtk-qt3-kde3 +Architecture: any +Depends: ${shlibs:Depends} +Description: Use KDE dialogs in Gtk apps + This is a quick-and-dirty LD_PRELOAD hack that allows *some* Gtk + applications to use KDE's file dialogs when run under KDE. + . + The Gtk file chooser functions have been overridden to communicate + with this KDE module/application. + . + This package includes the kqt3-wrapper diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..0e93ef8 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,37 @@ +This package was debianized by: + + Anthony Mercatante <[email protected]> + +It was downloaded from: + + http://kde-apps.org/content/show.php/KGtk+(Use+KDE+Dialogs+in+Gtk+Apps)?content=36077 + +Upstream Authors: + + Craig Drummond <[email protected]> + +Copyright: + Copyright (C) Craig Drummond, 2006-2007 + +License: + 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + On Debian systems, the complete text of the GNU General + Public License can be found in `/usr/share/common-licenses/GPL-2'. + +The Debian packaging is: + + Copyright C) 2009, Anthony Mercatante <[email protected]> + and is licensed under the GPL-2, see above. diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..a9d9faa --- /dev/null +++ b/debian/rules @@ -0,0 +1,30 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/rules/simple-patchsys.mk + +DEB_CONFIGURE_INCLUDEDIR := /opt/kde3/include/kde +DEB_CONFIGURE_MANDIR := /opt/kde3/share/man +DEB_CONFIGURE_PREFIX := /opt/kde3 +DEB_CONFIGURE_INFODIR := /opt/kde3/share/info +DEB_CMAKE_CUSTOM_FLAGS := -DKGTK_KDE3=true -DKGTK_QT3=true + +cdbs_configure_flags := --with-qt-dir=/usr/share/qt3 --disable-rpath --with-xinerama $(cdbs_kde_enable_final) $(cdbs_kde_enable_debug) + +DEB_CONFIGURE_EXTRA_FLAGS := --prefix=/opt/kde3 --with-extra-libs=/opt/kde3/lib + +configure/kgtk-qt3-kde3:: + env PATH=/opt/kde3/bin:$(PATH) CMAKE_LIBRARY_PATH=/opt/kde3/lib CMAKE_INCLUDE_PATH=/opt/kde3/include/kde cmake -D CMAKE_INSTALL_PREFIX=/opt/kde3 . + +build/kgtk-qt3-kde3:: + env PATH=/opt/kde3/bin:$(PATH) CMAKE_LIBRARY_PATH=/opt/kde3/lib CMAKE_INCLUDE_PATH=/opt/kde3/include/kde $(MAKE) + +install/kgtk-qt3-kde3:: + env PATH=/opt/kde3/bin:$(PATH) CMAKE_LIBRARY_PATH=/opt/kde3/lib CMAKE_INCLUDE_PATH=/opt/kde3/include/kde $(MAKE) install DESTDIR=$(CURDIR)/debian/kgtk-qt3-kde3 + diff --git a/debian/rules.bkp b/debian/rules.bkp new file mode 100755 index 0000000..6a608c7 --- /dev/null +++ b/debian/rules.bkp @@ -0,0 +1,9 @@ +#!/usr/bin/make -f + +DEB_CMAKE_CUSTOM_FLAGS := -DKGTK_KDE3=true -DKGTK_QT3=true + +include debian/cdbs/kde.mk + +binary-install/kgtk-qt3:: + rm -f debian/kgtk-qt3/usr/bin/kdialogd-wrapper + rm -f debian/kgtk-qt3/usr/bin/kgtk-wrapper diff --git a/gtk2/CMakeLists.txt b/gtk2/CMakeLists.txt new file mode 100644 index 0000000..36b3e3f --- /dev/null +++ b/gtk2/CMakeLists.txt @@ -0,0 +1,22 @@ +include(FindPkgConfig) + +pkg_check_modules(GTK gtk+-2.0>=2.6) + +if (GTK_FOUND) + message("** INFORMATION: Gtk2 LD_PRELOAD library will be built.") + + # set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) + set(LIB_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX} CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})" FORCE) + + include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/common ${CMAKE_BINARY_DIR} ${GTK_INCLUDE_DIRS}) + set(kgtk2_SRCS kgtk2.c) + add_library(kgtk2 SHARED ${kgtk2_SRCS}) + target_link_libraries(kgtk2 ${GTK_LDFLAGS} -lgthread-2.0 -lglib-2.0 -lc -ldl) + + install(TARGETS kgtk2 LIBRARY DESTINATION ${LIB_INSTALL_DIR}/kgtk ) + + configure_file (kgtk2-wrapper.cmake ${CMAKE_CURRENT_BINARY_DIR}/kgtk2-wrapper @ONLY) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/kgtk2-wrapper DESTINATION bin) +else (GTK_FOUND) + message("** ERROR : Could not locate Gtk2 headers, Gtk2 LD_PRELOAD library will not be built.") +endif (GTK_FOUND) diff --git a/gtk2/kgtk2-wrapper.cmake b/gtk2/kgtk2-wrapper.cmake new file mode 100755 index 0000000..46865b7 --- /dev/null +++ b/gtk2/kgtk2-wrapper.cmake @@ -0,0 +1,33 @@ +#!/bin/bash + +# +# This script is part of the KGtk package. +# +# (C) Craig Drummond, 2007 +# +# +# -- +# Released under the GPL v2 or later +# -- +# + +if [ "`locale | grep 'LANG=' | grep -i 'utf-8' | wc -l`" = "0" ] ; then + export G_BROKEN_FILENAMES=1 +fi + +app=`basename $0` + +if [ "$app" = "kgtk2-wrapper" ] ; then + LD_PRELOAD=@CMAKE_INSTALL_PREFIX@/lib/kgtk/libkgtk2.so:$LD_PRELOAD "$@" +else + dir=`dirname $0` + oldPath=$PATH + PATH=`echo $PATH | sed s:$dir::g` + real=`which $app` + PATH=$oldPath + + if [ "$real" != "" ] && [ "`dirname $real`" != "$dir" ] ; then + LD_PRELOAD=@CMAKE_INSTALL_PREFIX@/lib@LIB_SUFFIX@/kgtk/libkgtk2.so:$LD_PRELOAD $real "$@" + fi +fi diff --git a/gtk2/kgtk2.c b/gtk2/kgtk2.c new file mode 100644 index 0000000..d0457c5 --- /dev/null +++ b/gtk2/kgtk2.c @@ -0,0 +1,2005 @@ +/************************************************************************ + * + * All dialogs opened are created and used modal. + * + ************************************************************************ + * (C) Craig Drummond, 2006 + ************************************************************************ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + ************************************************************************/ + +/* + NOTES: + + 1. Inkscape does not use the standard Gtk fileters to determine Save type + ...it uses an extra combo, which we try to locate. + 2. Firefox. This has two filters with the same patterns - *.htm and *.html. We + modify this so that one is *.htm and the other is *.html + 3. Glade-2 I noticed this crash a couple of times on loading - but not always. + Not sure if this is a Glade problem or not... +*/ + +/* +TODO + abiword: seems to call gtk_widget_show - but just overriding this cuases the dialog to + appear twice, and then it still donest use result :-( + Overload font picker! + Overload normal old file selector? ie. in addtition to file chooser? + Message boxes: Auto set alternative button order? +*/ + +/* +#define KGTK_DEBUG +*/ + +#define _GNU_SOURCE +#include <dlfcn.h> +#include <gtk/gtk.h> +#include <glib.h> +#include <gdk/gdkx.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <pwd.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdarg.h> +#include "connect.h" +#include "config.h" + +#ifndef KGTK_DLSYM_VERSION +#define KGTK_DLSYM_VERSION "GLIBC_2.0" +#endif + +/* +#define KGTK_DEBUG_DLSYM +*/ + +/* + * For SWT apps (e.g. eclipse) we need to override dlsym, but we can only do this if + * dlvsym is present in libdl. dlvsym is needed so that we can access the real dlsym + * as well as our fake dlsym + */ +#ifdef HAVE_DLVSYM +static void * real_dlsym (void *handle, const char *name); +#else +#define real_dlsym(A, B) dlsym(A, B) +#endif + +typedef enum +{ + APP_ANY, + APP_GIMP, + APP_INKSCAPE, + APP_FIREFOX, + APP_KINO +} Application; + +static const char *kgtkAppName=NULL; +static gboolean useKde=FALSE; +static gboolean kdialogdError=FALSE; +static GMainLoop *kdialogdLoop=NULL; +static gchar *kgtkFileFilter=NULL; +static Application kgtkApp=APP_ANY; + +#define MAX_DATA_LEN 4096 +#define MAX_FILTER_LEN 256 +#define MAX_LINE_LEN 1024 +#define MAX_APP_NAME_LEN 32 + +static char * kgtk_get_app_name(int pid) +{ + static char app_name[MAX_APP_NAME_LEN+1]="\0"; + + int procFile=-1; + char cmdline[MAX_LINE_LEN+1]; + + sprintf(cmdline, "/proc/%d/cmdline",pid); + + if(-1!=(procFile=open(cmdline, O_RDONLY))) + { + if(read(procFile, cmdline, MAX_LINE_LEN)>2) + { + int len=strlen(cmdline), + pos=0; + + for(pos=len-1; pos>0 && cmdline[pos] && cmdline[pos]!='/'; --pos) + ; + + if(pos>=0 && pos<len) + { + strncpy(app_name, &cmdline[pos ? pos+1 : 0], MAX_APP_NAME_LEN); + app_name[MAX_APP_NAME_LEN]='\0'; + } + } + close(procFile); + } + + return app_name; +} + +/* Try to get name of application executable - either from argv[0], or /proc */ +static const gchar *getAppName(const gchar *app) +{ + static const char *appName=NULL; + + if(!appName) + { + /* Is there an app name set? - if not read from /proc */ + const gchar *a=app ? app : kgtk_get_app_name(getpid()); + gchar *slash; + + /* Was the cmdline app java? if so, try to use its parent name - just in case + its run from a shell script, etc. - e.g. as eclipse does */ + if(a && 0==strcmp(a, "java")) + a=kgtk_get_app_name(getppid()); + + if(a && a[0]=='\0') + a=NULL; + + appName=a && (slash=strrchr(a, '/')) && '\0'!=slash[1] + ? &(slash[1]) + : a ? a : "GtkApp"; + } + +#ifdef KGTK_DEBUG + printf("KGTK::getAppName: %s\n", appName); +#endif + return appName; +} + +static gboolean writeString(const char *s) +{ + unsigned int slen=strlen(s)+1; + + return writeBlock(kdialogdSocket, (char *)&slen, 4) && + writeBlock(kdialogdSocket, s, slen); +} + +static gboolean writeBool(gboolean b) +{ + char bv=b ? 1 : 0; + + return writeBlock(kdialogdSocket, (char *)&bv, 1); +} + +typedef struct +{ + GSList *res; + gchar *selFilter; +} KGtkData; + +static gpointer kdialogdMain(gpointer data) +{ + KGtkData *d=(struct KGtkData *)data; + char buffer[MAX_DATA_LEN+1]={'\0'}; + int num=0; + + if(readBlock(kdialogdSocket, (char *)&num, 4)) + { + int n; + + for(n=0; n<num && !kdialogdError; ++n) + { + int size=0; + + if(readBlock(kdialogdSocket, (char *)&size, 4)) + { + if(size>0) + { + if(size<=MAX_DATA_LEN && readBlock(kdialogdSocket, buffer, size)) + { + /*buffer[size-1]='\0'; */ + if('/'==buffer[0]) + d->res=g_slist_prepend(d->res, g_filename_from_utf8(buffer, -1, NULL, NULL, NULL)); + else if(!(d->selFilter)) + d->selFilter=g_strdup(buffer); + } + else + kdialogdError=TRUE; + } + } + else + kdialogdError=TRUE; + } + } + else + kdialogdError=TRUE; + + if(g_main_loop_is_running(kdialogdLoop)) + g_main_loop_quit(kdialogdLoop); + + return 0L; +} + +static gboolean sendMessage(GtkWidget *widget, Operation op, GSList **res, gchar **selFilter, + const char *title, const char *p1, const char *p2, gboolean overWrite) +{ +#ifdef KGTK_DEBUG + printf("KGTK::sendMessage\n"); +#endif + + if(connectToKDialogD(getAppName(kgtkAppName))) + { + char o=(char)op; + int xid=0; + + if(widget) + { + if(widget->parent) + { +#ifdef KGTK_DEBUG + printf("KGTK::Dialog has a parent!\n"); +#endif + xid=GDK_WINDOW_XID(gtk_widget_get_toplevel(widget->parent)); + } + + /* + Inkscape's 0.44 export bitmap filechooser is set to be transient for the main window, and + not the export dialog. This makes the KDE dialog appear underneath it! So, for inkscape + dont try to get the window transient for... + + ...might need to remove this whole section, if it starts to affect too many apps + */ + if(!xid && APP_INKSCAPE!=kgtkApp && GTK_IS_WINDOW(widget)) + { + GtkWindow *win=gtk_window_get_transient_for(GTK_WINDOW(widget)); + +#ifdef KGTK_DEBUG + printf("KGTK::Get window transient for...\n"); +#endif + if(win && win->focus_widget) + xid=GDK_WINDOW_XID(gtk_widget_get_toplevel(win->focus_widget)->window); + } + } + + if(!xid) + { + GList *topWindows, + *node; + int prevX=0; + +#ifdef KGTK_DEBUG + printf("KGTK::No xid, need to traverse window list...\n"); +#endif + for(topWindows=node=gtk_window_list_toplevels(); node; node = node->next) + { + GtkWidget *w=node->data; + + if(w && GTK_IS_WIDGET(w) && w->window) + if(gtk_window_has_toplevel_focus(GTK_WINDOW(w)) && + gtk_window_is_active(GTK_WINDOW(w))) + { + /* If the currently active window is a popup - then assume it is a popup-menu, + * so use the previous window as the one to be transient for...*/ + if(GTK_WINDOW_POPUP==GTK_WINDOW(w)->type && prevX) + xid=prevX; + else + xid=GDK_WINDOW_XID(w->window); + if(xid) + break; + } + else + prevX=GDK_WINDOW_XID(w->window); + } + g_list_free(topWindows); + } + + if(writeBlock(kdialogdSocket, &o, 1) && + writeBlock(kdialogdSocket, (char *)&xid, 4) && + writeString(title) && + (p1 ? writeString(p1) : TRUE) && + (p2 ? writeString(p2) : TRUE) && + (OP_FILE_SAVE==op ? writeBool(overWrite) : TRUE)) + { + GtkWidget *dlg=gtk_dialog_new(); + KGtkData d; + + gtk_widget_set_name(dlg, "--kgtk-modal-dialog-hack--"); + d.res=NULL; + d.selFilter=NULL; + + /* Create a tmporary, hidden, dialog so that the kde dialog appears as modal */ + g_object_ref(dlg); + gtk_window_set_modal(GTK_WINDOW(dlg), TRUE); + gtk_window_iconify(GTK_WINDOW(dlg)); + gtk_dialog_set_has_separator(GTK_DIALOG(dlg), FALSE); + gtk_window_set_has_frame(GTK_WINDOW(dlg), FALSE); + gtk_window_set_decorated(GTK_WINDOW(dlg), FALSE); + gtk_window_set_keep_below(GTK_WINDOW(dlg), TRUE); + gtk_window_set_opacity(GTK_WINDOW(dlg), 100); + gtk_window_set_type_hint(GTK_WINDOW(dlg), GDK_WINDOW_TYPE_HINT_DOCK); + gtk_widget_show(dlg); + gtk_window_move(GTK_WINDOW(dlg), 32768, 32768); + gtk_window_set_skip_taskbar_hint(GTK_WINDOW(dlg), TRUE); + gtk_window_set_skip_pager_hint(GTK_WINDOW(dlg), TRUE); + kdialogdLoop = g_main_loop_new (NULL, FALSE); + kdialogdError=FALSE; + g_thread_create(&kdialogdMain, &d, FALSE, NULL); + + GDK_THREADS_LEAVE(); + g_main_loop_run(kdialogdLoop); + GDK_THREADS_ENTER(); + g_main_loop_unref(kdialogdLoop); + kdialogdLoop = NULL; + gtk_window_set_modal(GTK_WINDOW(dlg), FALSE); + g_object_unref(dlg); + gtk_widget_destroy(dlg); + if(kdialogdError) + { + closeConnection(); + return FALSE; + } + if(d.res) + { + if(res) + *res=d.res; + else + g_slist_free(d.res); + } + if(d.selFilter) + { + if(selFilter) + *selFilter=d.selFilter; + else + g_free(d.selFilter); + } + return TRUE; + } + } + + return FALSE; +} + +static gchar * firstEntry(GSList *files) +{ + gchar *file=NULL; + + if(files) + { + file=(gchar *)(files->data); + files=g_slist_delete_link(files, files); + if(files) + { + g_slist_foreach(files, (GFunc)g_free, NULL); + g_slist_free(files); + files=NULL; + } + } + + return file; +} + +static const char * getTitle(const char *title, Operation op) +{ + if(title && strlen(title)) + return title; + + return "."; +} + +static gboolean openKdeDialog(GtkWidget *widget, const char *title, const char *p1, const char *p2, + Operation op, GSList **res, gchar **selFilter, gboolean overWrite) +{ + gboolean rv=sendMessage(widget, op, res, selFilter, getTitle(title, op), p1, p2, overWrite); + + /* If we failed to talk to, or start kdialogd, then dont keep trying - just fall back to Gtk */ +/* + if(!rv) + useKde=FALSE; +*/ + + return rv; +} + +static void kgtkExit() +{ + if(useKde) + closeConnection(); +} + +static gboolean isApp(const char *str, const char *app) +{ + /* Standard case... */ + if(0==strcmp(str, app)) + return TRUE; + + /* Autopackage'd app */ + #define AUTOPACKAGE_PROXY ".proxy." + #define AUTOPACKAGE_PROXY_LEN 7 + + if(str==strstr(str, ".proxy.") && strlen(str)>AUTOPACKAGE_PROXY_LEN && + 0==strcmp(&str[AUTOPACKAGE_PROXY_LEN], app)) + return TRUE; + + /* gimp and mozilla */ + { + int app_len=strlen(app); + + if(strlen(str)>app_len && str==strstr(str, app) && + (0==memcmp(&str[app_len], "-2", 2) || + 0==memcmp(&str[app_len], "-bin", 4))) + return TRUE; + } + + return FALSE; +} + +static gboolean isMozApp(const char *app, const char *check) +{ + if(0==strcmp(app, check)) + return TRUE; + else if(app==strstr(app, check)) + { + int app_len=strlen(app), + check_len=strlen(check); + + if(check_len+4 == app_len && 0==strcmp(&app[check_len], "-bin")) + return TRUE; + + /* OK check for xulrunner-1.9 */ + { + double dummy; + if(app_len>(check_len+1) && 1==sscanf(&app[check_len+1], "%f", &dummy)) + return TRUE; + } + } + + return FALSE; +} + +static gboolean kgtkInit(const char *appName) +{ + static gboolean initialised=FALSE; +#ifdef KGTK_DEBUG + printf("KGTK::kgtkInit %s\n", appName); +#endif + if(!initialised) + { +#ifdef KGTK_DEBUG + printf("KGTK::Running under KDE? %d\n", NULL!=getenv("KDE_FULL_SESSION")); +#endif + + initialised=TRUE; + kgtkAppName=getAppName(appName); + useKde=NULL!=getenv("KDE_FULL_SESSION") && connectToKDialogD(kgtkAppName); + if(useKde) + { + const gchar *prg=getAppName(NULL); + + if(prg) + { +#ifdef KGTK_DEBUG + printf("KGTK::APP %s\n", prg); +#endif + if(isApp(prg, "inkscape")) + { + kgtkFileFilter="*.svg|Scalable Vector Graphic"; + kgtkApp=APP_INKSCAPE; +#ifdef KGTK_DEBUG + printf("KGTK::Inkscape\n"); +#endif + } + else if(isApp(prg, "gimp")) + { + kgtkApp=APP_GIMP; +#ifdef KGTK_DEBUG + printf("KGTK::GIMP\n"); +#endif + } + else if(isApp(prg, "kino")) + { + kgtkApp=APP_KINO; +#ifdef KGTK_DEBUG + printf("KGTK::kino\n"); +#endif + } + else if(isMozApp(prg, "firefox") || isMozApp(prg, "swiftfox") || isMozApp(prg, "iceweasel") || isMozApp(prg, "xulrunner")) + { + kgtkApp=APP_FIREFOX; +#ifdef KGTK_DEBUG + printf("KGTK::Firefox\n"); +#endif + } + } + + if(!g_threads_got_initialized) + g_thread_init(NULL); + atexit(&kgtkExit); + } + } + +#ifdef KGTK_DEBUG + printf("KGTK::kgtkInit useKde:%d\n", useKde); +#endif + + return useKde; +} + +/* ......................... */ + +typedef struct _GtkFileSystem GtkFileSystem; +typedef struct _GtkFilePath GtkFilePath; +typedef struct _GtkFileSystemModel GtkFileSystemModel; +struct _GtkFileFilter +{ + GtkObject parent_instance; + + gchar *name; + GSList *rules; + + GtkFileFilterFlags needed; +}; + +typedef enum { + FILTER_RULE_PATTERN, + FILTER_RULE_MIME_TYPE, + FILTER_RULE_PIXBUF_FORMATS, + FILTER_RULE_CUSTOM +} FilterRuleType; + +struct _FilterRule +{ + FilterRuleType type; + GtkFileFilterFlags needed; + + union { + gchar *pattern; + gchar *mime_type; + GSList *pixbuf_formats; + struct { + GtkFileFilterFunc func; + gpointer data; + GDestroyNotify notify; + } custom; + } u; +}; + +#if GTK_CHECK_VERSION(2, 6, 0) +struct _GtkFileChooserButtonPrivate +{ + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *image; + GtkWidget *label; + GtkWidget *combo_box; + + GtkCellRenderer *icon_cell; + GtkCellRenderer *name_cell; + + GtkTreeModel *model; + GtkTreeModel *filter_model; + + gchar *backend; + GtkFileSystem *fs; + GtkFilePath *old_path; + + gulong combo_box_changed_id; + gulong dialog_file_activated_id; + gulong dialog_folder_changed_id; + gulong dialog_selection_changed_id; + gulong fs_volumes_changed_id; + gulong fs_bookmarks_changed_id; +}; +#endif + +/* TreeModel Columns */ +enum +{ + ICON_COLUMN, + DISPLAY_NAME_COLUMN, + TYPE_COLUMN, + DATA_COLUMN, + NUM_COLUMNS +}; + +/* TreeModel Row Types */ +typedef enum +{ + ROW_TYPE_SPECIAL, + ROW_TYPE_VOLUME, + ROW_TYPE_SHORTCUT, + ROW_TYPE_BOOKMARK_SEPARATOR, + ROW_TYPE_BOOKMARK, + ROW_TYPE_CURRENT_FOLDER_SEPARATOR, + ROW_TYPE_CURRENT_FOLDER, + ROW_TYPE_OTHER_SEPARATOR, + ROW_TYPE_OTHER, + + ROW_TYPE_INVALID = -1 +} +RowType; + +static GtkWidget * +kgtk_file_chooser_dialog_new_valist (const gchar *title, + GtkWindow *parent, + GtkFileChooserAction action, + const gchar *backend, + const gchar *first_button_text, + va_list varargs) +{ + GtkWidget *result; + const char *button_text = first_button_text; + gint response_id; + + result = g_object_new (GTK_TYPE_FILE_CHOOSER_DIALOG, + "title", title, + "action", action, + "file-system-backend", backend, + NULL); + + if (parent) + gtk_window_set_transient_for (GTK_WINDOW (result), parent); + + while (button_text) + { + response_id = va_arg (varargs, gint); + gtk_dialog_add_button (GTK_DIALOG (result), button_text, response_id); + button_text = va_arg (varargs, const gchar *); + } + + return result; +} +/* ......................... */ + +gboolean gtk_init_check(int *argc, char ***argv) +{ + static void * (*realFunction)() = NULL; + + gboolean rv=FALSE; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_init_check"); + + rv=realFunction(argc, argv); +#ifdef KGTK_DEBUG + printf("KGTK::gtk_init_check\n"); +#endif + if(rv) + kgtkInit(argv && argc ? (*argv)[0] : NULL); + return rv; +} + +void gtk_init(int *argc, char ***argv) +{ + static void * (*realFunction)() = NULL; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_init"); + + realFunction(argc, argv); +#ifdef KGTK_DEBUG + printf("KGTK::gtk_init\n"); +#endif + kgtkInit(argv && argc ? (*argv)[0] : NULL); +} + +/* Store a hash from widget pointer to folder/file list retried from KDialogD */ +static GHashTable *fileDialogHash=NULL; + +typedef struct +{ + gchar *folder; + gchar *name; + GSList *files; + int ok, + cancel; + gboolean setOverWrite, + doOverwrite; +} KGtkFileData; + +static KGtkFileData * lookupHash(void *hash, gboolean create) +{ + KGtkFileData *rv=NULL; + +#ifdef KGTK_DEBUG + printf("KGTK::lookupHash %X\n", (int)hash); +#endif + if(!fileDialogHash) + fileDialogHash=g_hash_table_new(g_int_hash, g_int_equal); + + rv=(KGtkFileData *)g_hash_table_lookup(fileDialogHash, hash); + + if(!rv && create) + { + rv=(KGtkFileData *)malloc(sizeof(KGtkFileData)); + rv->folder=NULL; + rv->files=NULL; + rv->name=NULL; + rv->ok=GTK_RESPONSE_OK; + rv->cancel=GTK_RESPONSE_CANCEL; + rv->setOverWrite=FALSE; + rv->doOverwrite=FALSE; + g_hash_table_insert(fileDialogHash, hash, rv); + rv=g_hash_table_lookup(fileDialogHash, hash); + } + + return rv; +} + +static void freeHash(void *hash) +{ + KGtkFileData *data=NULL; + + if(!fileDialogHash) + fileDialogHash=g_hash_table_new(g_int_hash, g_int_equal); + + data=(KGtkFileData *)g_hash_table_lookup(fileDialogHash, hash); + + if(data) + { + if(data->folder) + g_free(data->folder); + if(data->name) + g_free(data->name); + if(data->files) + { + g_slist_foreach(data->files, (GFunc)g_free, NULL); + g_slist_free(data->files); + } + data->files=NULL; + data->folder=NULL; + data->name=NULL; + g_hash_table_remove(fileDialogHash, hash); + } +} + +/* Some Gtk apps have filter pattern *.[Pp][Nn][Gg] - wherease Qt/KDE prefer *.png */ +#define MAX_PATTERN_LEN 64 +static gchar *modifyFilter(const char *filter) +{ + int i=0; + gboolean brackets=FALSE; + const char *p; + static char res[MAX_PATTERN_LEN+1]; + + for(p=filter; p && *p && i<MAX_PATTERN_LEN; ++p) + switch(*p) + { + case '[': + p++; + if(p) + res[i++]=tolower(*p); + brackets=TRUE; + break; + case ']': + brackets=FALSE; + break; + default: + if(!brackets) + res[i++]=tolower(*p); + } + res[i++]='\0'; + return res; +} + +static GtkWidget * getCombo(GtkWidget *widget) +{ + if(widget && GTK_IS_BOX(widget)) + { + GList *child=GTK_BOX(widget)->children; + + for(; child; child=child->next) + { + GtkBoxChild *boxChild=(GtkBoxChild *)child->data; + + if(GTK_IS_COMBO_BOX(boxChild->widget)) + return boxChild->widget; + else if(GTK_IS_BOX(boxChild->widget)) + { + GtkWidget *box=getCombo(boxChild->widget); + + if(box) + return box; + } + } + + } + + return NULL; +} + +static GString * getFilters(GtkDialog *dialog, GtkFileChooserAction act) +{ + GString *filter=NULL; + GSList *list=gtk_file_chooser_list_filters(GTK_FILE_CHOOSER(dialog)); + +#ifdef KGTK_DEBUG + printf("KGTK::Get list of filters...\n"); +#endif + + if(list) + { + GSList *item; + int filterNum=0; + + filter=g_string_new(""); + for(item=list; item; item=g_slist_next(item), ++filterNum) + { + GtkFileFilter *f=(GtkFileFilter *)(item->data); + + if(f) + { + const gchar *name=gtk_file_filter_get_name(f); + GSList *rule=((struct _GtkFileFilter *)f)->rules; + GString *pattern=g_string_new(""); + + for(; rule; rule=g_slist_next(rule)) + switch(((struct _FilterRule *)rule->data)->type) + { + case FILTER_RULE_PATTERN: + { + const char *modPat= + modifyFilter(((struct _FilterRule *)rule->data)->u.pattern); + + /* + Firefox has: + *.htm *.html | Web page complete + *.htm *.html | HTML only + *.txt *.text | Text + + We modify this to have: + *.htm | Web page complete + *.html | HTML only + *.txt *.text | Text + */ + + if(APP_FIREFOX!=kgtkApp || (strcmp(modPat, "*.html") ? filterNum!=1 + : filterNum)) + { + if(pattern->len) + pattern=g_string_append(pattern, " "); + pattern=g_string_append(pattern, modPat); + } + break; + } + case FILTER_RULE_MIME_TYPE: + if(filter->len) + filter=g_string_append(filter, "\n"); + filter=g_string_append(filter, + ((struct _FilterRule *)rule->data)->u.mime_type); + break; + default: + break; + } + + if(name && pattern && pattern->len) + { + gchar *n=g_strdup(name), + *pat=strstr(n, " (*"); + + if(pat) + *pat='\0'; + + if(filter->len) + filter=g_string_append(filter, "\n"); + filter=g_string_append(filter, pattern->str); + filter=g_string_append(filter, "|"); + filter=g_string_append(filter, n); + g_free(n); + } + g_string_free(pattern, TRUE); + } + } + g_slist_free(list); + } + + if(!filter) + { + /* This is mainly the case for Inkscape save - but try for other apps too... */ + GtkWidget *combo=getCombo(gtk_file_chooser_get_extra_widget(GTK_FILE_CHOOSER(dialog))); + +#ifdef KGTK_DEBUG + printf("KGTK::No filters found, try to look for an extra combo widget...\n"); +#endif + + if(combo) + { + int i; + + filter=g_string_new(""); + for(i=0; i<64; ++i) + { + gchar *text=NULL; + + gtk_combo_box_set_active(GTK_COMBO_BOX(combo), i); + if(i!=gtk_combo_box_get_active(GTK_COMBO_BOX(combo))) + break; + + text=gtk_combo_box_get_active_text(GTK_COMBO_BOX(combo)); + + if(text) + { + gchar *pat=strstr(text, " (*"); + + if(pat) + { + gchar *close=strstr(pat, ")"); + + *pat='\0'; + + if(close) + *close='\0'; + + pat+=2; /* Skip past " (" */ + + if(filter->len) + filter=g_string_append(filter, "\n"); + filter=g_string_append(filter, pat); + filter=g_string_append(filter, "|"); + filter=g_string_append(filter, text); + } + g_free(text); + } + } + } + } + + return filter; +} + +static void setFilter(const gchar *filter, GtkDialog *dialog, GtkFileChooserAction act) +{ + gboolean found=FALSE; + GSList *list=gtk_file_chooser_list_filters(GTK_FILE_CHOOSER(dialog)); + +#ifdef KGTK_DEBUG + printf("KGTK::Need to locate filter:%s\n", filter ? filter : "Null"); +#endif + + if(list) + { + GSList *item; + unsigned int flen=strlen(filter); + int filterNum=0; + + for(item=list; item && !found; item=g_slist_next(item), filterNum++) + { + GtkFileFilter *f=(GtkFileFilter *)(item->data); + + if(f) + { + GSList *rule=((struct _GtkFileFilter *)f)->rules; + char *start=NULL; + + for(; rule && !found; rule=g_slist_next(rule)) + if(FILTER_RULE_PATTERN==((struct _FilterRule *)rule->data)->type) + { + char *filt=modifyFilter(((struct _FilterRule *)rule->data)->u.pattern); + + /* + Firefox has: + *.htm *.html | Web page complete + *.htm *.html | HTML only + *.txt *.text | Text + + We modify this to have: + *.htm | Web page complete + *.html | HTML only + *.txt *.text | Text + */ + + if((APP_FIREFOX!=kgtkApp || (strcmp(filt, "*.html") ? filterNum!=1 + : filterNum)) && + (start=strstr(filter, filt))) + { + unsigned int slen=strlen(filt); + + if(((start-filter)+slen)<=flen && + (' '==start[slen] || '\t'==start[slen] || + '\n'==start[slen] || '\0'==start[slen])) + { +#ifdef KGTK_DEBUG + printf("KGTK::FOUND FILTER\n"); +#endif + found=TRUE; + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), f); + } + } + } + } + } + g_slist_free(list); + } + + if(!found) + { + /* This is mainly the case for Inkscape save - but try for other apps too... */ + GtkWidget *combo=getCombo(gtk_file_chooser_get_extra_widget(GTK_FILE_CHOOSER(dialog))); + +#ifdef KGTK_DEBUG + printf("KGTK::No filters found, try to look for an extra combo widget...\n"); +#endif + if(combo) + { + int i, + flen=strlen(filter); + + for(i=0; i<64; ++i) + { + gchar *text=NULL; + + gtk_combo_box_set_active(GTK_COMBO_BOX(combo), i); + if(i!=gtk_combo_box_get_active(GTK_COMBO_BOX(combo))) + break; + + text=gtk_combo_box_get_active_text(GTK_COMBO_BOX(combo)); + + if(text) + { + gchar *pat=strstr(text, filter); + + if(pat) + { + if(pat>text && (' '==pat[-1] || '('==pat[-1]) && + (' '==pat[flen] || ')'==pat[flen])) + return; /* found a match, so just return - filter is set */ + } + g_free(text); + } + } + + /* No match :-( set to last filter... */ + for(i=0; i<64; ++i) + { + gtk_combo_box_set_active(GTK_COMBO_BOX(combo), i); + if(i!=gtk_combo_box_get_active(GTK_COMBO_BOX(combo))) + break; + } + } + } +} + +static GSList * addProtocols(GSList *files) +{ + GSList *item=files; + + for(; item; item=g_slist_next(item)) + { + gchar *cur=item->data; + item->data=g_filename_to_uri(item->data, NULL, NULL); + g_free(cur); + } + + return files; +} + +void gtk_window_present(GtkWindow *window) +{ + static void * (*realFunction)() = NULL; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_window_present"); + +#ifdef KGTK_DEBUG + printf("KGTK::gtk_window_present %s %d\n", gtk_type_name(GTK_WIDGET_TYPE(window)), + GTK_IS_FILE_CHOOSER(window)); +#endif + if(GTK_IS_FILE_CHOOSER(window)) /* || (APP_GIMP==kgtkApp && + 0==strcmp(gtk_type_name(GTK_WIDGET_TYPE(window)), "GimpFileDialog")))*/ + gtk_dialog_run(GTK_DIALOG(window)); + else + realFunction(window); +} + +void gtk_widget_show(GtkWidget *widget) +{ + static void * (*realFunction)() = NULL; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_widget_show"); + + if(widget && !GTK_IS_FILE_CHOOSER_BUTTON(widget) && GTK_IS_FILE_CHOOSER(widget)) + { +#ifdef KGTK_DEBUG + printf("KGTK::gtk_widget_show %s %d\n", gtk_type_name(GTK_WIDGET_TYPE(widget)), + GTK_IS_FILE_CHOOSER(widget)); +#endif + gtk_dialog_run(GTK_DIALOG(widget)); + GTK_OBJECT_FLAGS(widget)|=GTK_REALIZED; + } + else + realFunction(widget); +} + +void gtk_widget_hide(GtkWidget *widget) +{ + static void * (*realFunction)() = NULL; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_widget_hide"); + + if(widget && !GTK_IS_FILE_CHOOSER_BUTTON(widget) && GTK_IS_FILE_CHOOSER(widget)) + { +#ifdef KGTK_DEBUG + printf("KGTK::gtk_widget_hide %s %d\n", gtk_type_name(GTK_WIDGET_TYPE(widget)), + GTK_IS_FILE_CHOOSER(widget)); +#endif + if(GTK_OBJECT_FLAGS(widget)>K_REALIZED) + GTK_OBJECT_FLAGS(widget)-=GTK_REALIZED; + } + else + realFunction(widget); +} + +gboolean gtk_file_chooser_get_do_overwrite_confirmation(GtkFileChooser *widget) +{ + static void * (*realFunction)() = NULL; + + gboolean rv=FALSE; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_file_chooser_get_do_overwrite_confirmation"); + + if(realFunction) + { + KGtkFileData *data=lookupHash(widget, FALSE); + + if(data) + { + if(!data->setOverWrite) + { + data->setOverWrite=TRUE; + data->doOverwrite=(gboolean) realFunction(widget); + } + rv=data->doOverwrite; + } + else + rv=(gboolean) realFunction(widget); + } + + return rv; +} + +/* ext => called from app, not kgtk */ +void kgtkFileChooserSetDoOverwriteConfirmation(GtkFileChooser *widget, gboolean v, gboolean ext) +{ + static void * (*realFunction)() = NULL; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_file_chooser_set_do_overwrite_confirmation"); + + if(realFunction) + { + realFunction(widget, v); + if(ext) + { + KGtkFileData *data=lookupHash(widget, FALSE); + + if(data) + { + data->setOverWrite=TRUE; + data->doOverwrite=v; + } + } + } +} + +gboolean isOnFileChooser(GtkWidget *w) +{ + return w + ? GTK_IS_FILE_CHOOSER(w) + ? TRUE + : isOnFileChooser(w->parent) + : FALSE; +} + +int gtk_combo_box_get_active(GtkComboBox *combo) +{ + int rv=0; + + if(APP_KINO==kgtkApp && isOnFileChooser(combo)) + return 1; + else + { + static void * (*realFunction)() = NULL; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_combo_box_get_active"); + + rv=(int)realFunction(combo); + } + + return rv; +} + +gint gtk_dialog_run(GtkDialog *dialog) +{ + static void * (*realFunction)() = NULL; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_dialog_run"); + +#ifdef KGTK_DEBUG + printf("KGTK::gtk_dialog_run %s \n", dialog ? gtk_type_name(GTK_WIDGET_TYPE(dialog)) : "<null>"); +#endif + + if(kgtkInit(NULL) && GTK_IS_FILE_CHOOSER(dialog)) + { + static gboolean running=FALSE; + + KGtkFileData *data=lookupHash(dialog, TRUE); + +#ifdef KGTK_DEBUG + printf("KGTK::run file chooser, already running? %d\n", running); +#endif + if(!running) + { + GtkFileChooserAction act=gtk_file_chooser_get_action(GTK_FILE_CHOOSER(dialog)); + gchar *current=NULL, + *selFilter=NULL; + const gchar *title=gtk_window_get_title(GTK_WINDOW(dialog)); + GString *filter=NULL; + gint resp=data->cancel; + gboolean origOverwrite= + gtk_file_chooser_get_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog)); + + running=TRUE; + + if(GTK_FILE_CHOOSER_ACTION_OPEN==act || GTK_FILE_CHOOSER_ACTION_SAVE==act) + filter=getFilters(dialog, act); + else /* GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER==act || + GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER==act */ + if(NULL==(current=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)))) + current=gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog)); + + kgtkFileChooserSetDoOverwriteConfirmation(GTK_FILE_CHOOSER(dialog), FALSE, FALSE); + + switch(act) + { + case GTK_FILE_CHOOSER_ACTION_OPEN: + { +#ifdef KGTK_DEBUG + printf("KGTK::run file chooser GTK_FILE_CHOOSER_ACTION_OPEN\n"); +#endif + if(gtk_file_chooser_get_select_multiple(GTK_FILE_CHOOSER(dialog))) + { + GSList *files=NULL; + + openKdeDialog(GTK_WIDGET(dialog), title ? title : "", + data->folder ? data->folder : "", + filter && filter->len + ? filter->str + : kgtkFileFilter + ? kgtkFileFilter + : "", OP_FILE_OPEN_MULTIPLE, &files, + &selFilter, FALSE); + + if(files) + { + GSList *c; + + gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(dialog)); + for(c=files; c; c=g_slist_next(c)) + gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(dialog), + (gchar *)(c->data)); + g_slist_foreach(files, (GFunc)g_free, NULL); + g_slist_free(files); + + resp=data->ok; + } + } + else + { + gchar *file=NULL; + GSList *res=NULL; + + openKdeDialog(GTK_WIDGET(dialog), title ? title : "", + data->folder ? data->folder : "", + filter && filter->len + ? filter->str + : kgtkFileFilter + ? kgtkFileFilter + : "", OP_FILE_OPEN, &res, &selFilter, FALSE); + file=firstEntry(res); + + if(file) + { + gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(dialog)); + gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(dialog), file); + g_free(file); + resp=data->ok; + } + } + break; + } + case GTK_FILE_CHOOSER_ACTION_SAVE: + { + gchar *file=NULL; + GSList *res=NULL; + +#ifdef KGTK_DEBUG + printf("KGTK::run file chooser GTK_FILE_CHOOSER_ACTION_SAVE\n"); +#endif + if(data->name) + { + GString *cur=g_string_new(data->folder ? data->folder + : get_current_dir_name()); + + cur=g_string_append(cur, "/"); + cur=g_string_append(cur, data->name); + current=g_string_free(cur, FALSE); + } + + openKdeDialog(GTK_WIDGET(dialog), title ? title : "", + current ? current : (data->folder ? data->folder : ""), + filter && filter->len + ? filter->str + : kgtkFileFilter + ? kgtkFileFilter + : "", OP_FILE_SAVE, &res, &selFilter, origOverwrite); + file=firstEntry(res); + + if(file) + { + /* Firefox crashes when we save to an existing name -> so just delete it first! */ + if(APP_FIREFOX==kgtkApp && origOverwrite) + { + struct stat info; + + if(0==lstat(file, &info)) + unlink(file); + } + gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(dialog)); + gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(dialog), file); + g_free(file); + resp=data->ok; + } + break; + } + case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER: + case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER: + { + GSList *res=NULL; + gchar *folder=NULL; + +#ifdef KGTK_DEBUG + if(GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER==act) + printf("KGTK::run file chooser GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER\n"); + else + printf("KGTK::run file chooser GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER\n"); +#endif + openKdeDialog(GTK_WIDGET(dialog), title ? title : "", + data->folder ? data->folder : "", NULL, + OP_FOLDER, &res, NULL, FALSE); + folder=firstEntry(res); + + if(folder) + { + gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(dialog), folder); + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), folder); + g_free(folder); + resp=data->ok; + } + } + } + + if(current) + g_free(current); + + if(filter) + g_string_free(filter, TRUE); + + if(selFilter) + { + setFilter(selFilter, dialog, act); + g_free(selFilter); + } + +#ifdef KGTK_DEBUG + printf("KGTK::RETURN RESP:%d\n", resp); +#endif + g_signal_emit_by_name(dialog, "response", resp); + running=FALSE; + return resp; + } +#ifdef KGTK_DEBUG + printf("KGTK::ALREADY RUNNING SO RETURN RESP:%d\n", data->cancel); +#endif + g_signal_emit_by_name(dialog, "response", data->cancel); + return data->cancel; + } + return realFunction(dialog); +} + +void gtk_widget_destroy(GtkWidget *widget) +{ + static void * (*realFunction)() = NULL; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_widget_destroy"); + + if(fileDialogHash && GTK_IS_FILE_CHOOSER(widget)) + freeHash(widget); + + realFunction(widget); +} + +gchar * gtk_file_chooser_get_filename(GtkFileChooser *chooser) +{ + KGtkFileData *data=lookupHash(chooser, FALSE); + +#ifdef KGTK_DEBUG + printf("KGTK::gtk_file_chooser_get_filename %d %s\n", data ? g_slist_length(data->files) : 12345, + data && data->files && data->files->data ? data->files->data : "<>"); +#endif + return data && data->files && data->files->data ? g_strdup(data->files->data) : NULL; +} + +gboolean gtk_file_chooser_select_filename(GtkFileChooser *chooser, const char *filename) +{ + KGtkFileData *data=lookupHash(chooser, TRUE); + static void * (*realFunction)() = NULL; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_file_chooser_select_filename"); + realFunction(chooser, filename); + +#ifdef KGTK_DEBUG + printf("KGTK::gtk_file_chooser_select_filename %s, %d\n", filename, + data ? g_slist_length(data->files) : 12345); +#endif + if(data && filename) + { + GSList *c=NULL; + + for(c=data->files; c; c=g_slist_next(c)) + if(c->data && 0==strcmp((char *)(c->data), filename)) + break; + + if(!c) + { + gchar *folder=g_path_get_dirname(filename); + + data->files=g_slist_prepend(data->files, g_strdup(filename)); + + if(folder && !data->folder || strcmp(folder, data->folder)) + { + gtk_file_chooser_set_current_folder(chooser, folder); + g_free(folder); + } + } + } + + return TRUE; +} + +void gtk_file_chooser_unselect_all(GtkFileChooser *chooser) +{ + KGtkFileData *data=lookupHash(chooser, TRUE); + static void * (*realFunction)() = NULL; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_file_chooser_unselect_all"); + realFunction(chooser); + +#ifdef KGTK_DEBUG + printf("KGTK::gtk_file_chooser_unselect_all %d\n", data ? g_slist_length(data->files) : 12345); +#endif + if(data && data->files) + { + g_slist_foreach(data->files, (GFunc)g_free, NULL); + g_slist_free(data->files); + data->files=NULL; + } +} + +gboolean gtk_file_chooser_set_filename(GtkFileChooser *chooser, const char *filename) +{ + KGtkFileData *data=lookupHash(chooser, TRUE); + static void * (*realFunction)() = NULL; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_file_chooser_set_filename"); + realFunction(chooser, filename); + +#ifdef KGTK_DEBUG + printf("KGTK::gtk_file_chooser_set_filename %s %d\n", filename, + data ? g_slist_length(data->files) : 12345); +#endif + if(data && filename) + { + gchar *folder=g_path_get_dirname(filename), + *name=g_path_get_basename(filename); + + if(data->files) + { + g_slist_foreach(data->files, (GFunc)g_free, NULL); + g_slist_free(data->files); + data->files=NULL; + } + + data->files=g_slist_prepend(data->files, g_strdup(filename)); + + if(name && (!data->name || strcmp(name, data->name))) + gtk_file_chooser_set_current_name(chooser, name); + if(name) + g_free(name); + if(folder && (!data->folder || strcmp(folder, data->folder))) + gtk_file_chooser_set_current_folder(chooser, folder); + if(folder) + g_free(folder); + } + + return TRUE; +} + +void gtk_file_chooser_set_current_name(GtkFileChooser *chooser, const char *filename) +{ + KGtkFileData *data=lookupHash(chooser, TRUE); + GtkFileChooserAction act=gtk_file_chooser_get_action(chooser); + + if(GTK_FILE_CHOOSER_ACTION_SAVE==act || GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER==act) + { + static void * (*realFunction)() = NULL; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_file_chooser_set_current_name"); + realFunction(chooser, filename); + } + +#ifdef KGTK_DEBUG + printf("KGTK::gtk_file_chooser_set_current_name %s %d\n", filename, + data ? g_slist_length(data->files) : 12345); +#endif + if(data && filename) + { + if(data->name) + g_free(data->name); + data->name=g_strdup(filename); + } +} + +GSList * gtk_file_chooser_get_filenames(GtkFileChooser *chooser) +{ + KGtkFileData *data=lookupHash(chooser, FALSE); + GSList *rv=NULL; + +#ifdef KGTK_DEBUG + printf("KGTK::gtk_file_chooser_get_filenames %d\n", data ? g_slist_length(data->files) : 12345); +#endif + if(data && data->files) + { + GSList *item=data->files; + + for(; item; item=g_slist_next(item)) + { +#ifdef KGTK_DEBUG + printf("KGTK::FILE:%s\n", item->data); +#endif + if(item->data) + rv=g_slist_prepend(rv, g_strdup(item->data)); + } + } +#ifdef KGTK_DEBUG + printf("KGTK::gtk_file_chooser_get_filenames END\n"); +#endif + return rv; +} + +gboolean gtk_file_chooser_set_current_folder(GtkFileChooser *chooser, const gchar *folder) +{ + KGtkFileData *data=lookupHash(chooser, TRUE); + static void * (*realFunction)() = NULL; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_file_chooser_set_current_folder"); + realFunction(chooser, folder); + +#ifdef KGTK_DEBUG + printf("KGTK::gtk_file_chooser_set_current_folder %s %d\n", folder, + data ? g_slist_length(data->files) : 12345); +#endif + if(data && folder) + { + if(data->folder) + g_free(data->folder); + data->folder=g_strdup(folder); + } + g_signal_emit_by_name(chooser, "current-folder-changed", 0); + + return TRUE; +} + +gchar * gtk_file_chooser_get_current_folder(GtkFileChooser *chooser) +{ + KGtkFileData *data=lookupHash(chooser, FALSE); + +#ifdef KGTK_DEBUG + printf("KGTK::gtk_file_chooser_get_current_folder %d\n", + data ? g_slist_length(data->files) : 12345); +#endif + if(!data) + { + gtk_file_chooser_set_current_folder(chooser, get_current_dir_name()); + data=g_hash_table_lookup(fileDialogHash, chooser); + } + + return data && data->folder ? g_strdup(data->folder) : NULL; +} + +gchar * gtk_file_chooser_get_uri(GtkFileChooser *chooser) +{ +#ifdef KGTK_DEBUG + printf("KGTK::gtk_file_chooser_get_uri\n"); +#endif + gchar *filename=gtk_file_chooser_get_filename(chooser); + + if(filename) + { + gchar *uri=g_filename_to_uri(filename, NULL, NULL); + + g_free(filename); + return uri; + } + + return NULL; +} + +gboolean gtk_file_chooser_set_uri(GtkFileChooser *chooser, const char *uri) +{ +#ifdef KGTK_DEBUG + printf("KGTK::gtk_file_chooser_set_uri\n"); +#endif + + gchar *file=g_filename_from_uri(uri, NULL, NULL); + gboolean rv=FALSE; + + if(file) + { + rv=gtk_file_chooser_set_filename(chooser, file); + + g_free(file); + } + return rv; +} + +GSList * gtk_file_chooser_get_uris(GtkFileChooser *chooser) +{ +#ifdef KGTK_DEBUG + printf("KGTK::gtk_file_chooser_get_uris\n"); +#endif + return addProtocols(gtk_file_chooser_get_filenames(chooser)); +} + +gboolean gtk_file_chooser_set_current_folder_uri(GtkFileChooser *chooser, const gchar *uri) +{ +#ifdef KGTK_DEBUG + printf("KGTK::gtk_file_chooser_set_current_folder_uri\n"); +#endif + gchar *folder=g_filename_from_uri(uri, NULL, NULL); + gboolean rv=FALSE; + + if(folder) + { + rv=gtk_file_chooser_set_current_folder(chooser, folder); + + g_free(folder); + } + return rv; +} + +gchar * gtk_file_chooser_get_current_folder_uri(GtkFileChooser *chooser) +{ +#ifdef KGTK_DEBUG + printf("KGTK::gtk_file_chooser_get_current_folder_uri\n"); +#endif + + gchar *folder=gtk_file_chooser_get_current_folder(chooser); + + if(folder) + { + gchar *uri=g_filename_to_uri(folder, NULL, NULL); + + g_free(folder); + return uri; + } + + return NULL; +} + +void g_signal_stop_emission_by_name(gpointer instance, const gchar *detailed_signal) +{ + static void * (*realFunction)() = NULL; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "g_signal_stop_emission_by_name"); + +#ifdef KGTK_DEBUG + printf("KGTK::g_signal_stop_emission_by_name %s %s (check)\n", gtk_type_name(GTK_WIDGET_TYPE(instance)), detailed_signal); +#endif + + if(kgtkApp!=APP_GIMP || !GTK_IS_FILE_CHOOSER(instance) || strcmp(detailed_signal, "response")) + realFunction(instance, detailed_signal); +#ifdef KGTK_DEBUG + else + printf("KGTK::g_signal_stop_emission_by_name %s %s\n", gtk_type_name(GTK_WIDGET_TYPE(instance)), detailed_signal); +#endif +} + +GtkWidget * gtk_file_chooser_dialog_new(const gchar *title, GtkWindow *parent, + GtkFileChooserAction action, const gchar *first_button_text, + ...) +{ + GtkWidget *dlg=NULL; + KGtkFileData *data=NULL; + const char *text=first_button_text; + gint id; + va_list varargs; + + va_start(varargs, first_button_text); + dlg=kgtk_file_chooser_dialog_new_valist(title, parent, action, NULL, first_button_text, varargs); + va_end(varargs); + +#ifdef KGTK_DEBUG + printf("KGTK::gtk_file_chooser_dialog_new\n"); +#endif + data=lookupHash(dlg, TRUE); + va_start(varargs, first_button_text); + while(text) + { + id = va_arg(varargs, gint); + + if(text && (0==strcmp(text, GTK_STOCK_CANCEL) || 0==strcmp(text, GTK_STOCK_CLOSE) || + 0==strcmp(text, GTK_STOCK_QUIT) || 0==strcmp(text, GTK_STOCK_NO))) + data->cancel=id; + else if(text && (0==strcmp(text, GTK_STOCK_OK) || 0==strcmp(text, GTK_STOCK_OPEN) || + 0==strcmp(text, GTK_STOCK_SAVE) || 0==strcmp(text, GTK_STOCK_YES))) + data->ok=id; + text=va_arg(varargs, const gchar *); + } + va_end(varargs); + return dlg; +} + +#if GTK_CHECK_VERSION(2, 6, 0) +static void handleGtkFileChooserButtonClicked(GtkButton *button, gpointer user_data) +{ +#ifdef KGTK_DEBUG + printf("KGTK::handleGtkFileChooserButtonClicked\n"); +#endif + gtk_dialog_run(GTK_FILE_CHOOSER_BUTTON(user_data)->priv->dialog); +} + +static void handleGtkFileChooserComboChanged(GtkComboBox *combo_box, gpointer user_data) +{ + static gboolean handle=TRUE; + GtkTreeIter iter; + +#ifdef KGTK_DEBUG + printf("KGTK::handleGtkFileChooserComboChanged (handle:%d)\n", handle); +#endif + if(!handle) + return; + + if(gtk_combo_box_get_active_iter (combo_box, &iter)) + { + GtkFileChooserButtonPrivate *priv=GTK_FILE_CHOOSER_BUTTON(user_data)->priv; + gchar type=ROW_TYPE_INVALID; + + gtk_tree_model_get(priv->filter_model, &iter, TYPE_COLUMN, &type, -1); + + if(ROW_TYPE_OTHER==type) + gtk_dialog_run(GTK_FILE_CHOOSER_BUTTON(user_data)->priv->dialog); + else + { + g_signal_handler_unblock(priv->combo_box, priv->combo_box_changed_id); + handle=FALSE; + g_signal_emit_by_name(priv->combo_box, "changed"); + handle=TRUE; + g_signal_handler_block(priv->combo_box, priv->combo_box_changed_id); + } + } +} + +GtkWidget * gtk_file_chooser_button_new(const gchar *title, GtkFileChooserAction action) +{ + static void * (*realFunction)() = NULL; + + GtkWidget *button=NULL; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_file_chooser_button_new"); + +#ifdef KGTK_DEBUG + printf("KGTK::gtk_file_chooser_button_new\n"); +#endif + + if(kgtkInit(NULL)) + { + GtkFileChooserButtonPrivate *priv=NULL; + + button=realFunction(title, action); + priv=GTK_FILE_CHOOSER_BUTTON(button)->priv; + + if(priv->button) + { + g_signal_handlers_disconnect_matched(priv->button, + G_SIGNAL_MATCH_DATA,0, 0, NULL, NULL, button); + + g_signal_connect(priv->button, "clicked", + G_CALLBACK(handleGtkFileChooserButtonClicked), + GTK_FILE_CHOOSER_BUTTON(button)); + } + if(priv->combo_box) + { + g_signal_handler_block(priv->combo_box, priv->combo_box_changed_id); + + g_signal_connect(priv->combo_box, "changed", + G_CALLBACK(handleGtkFileChooserComboChanged), + GTK_FILE_CHOOSER_BUTTON(button)); + } + } + return button; +} +#endif + +static gboolean isGtk(const char *str) +{ + return 'g'==str[0] && 't'==str[1] && 'k'==str[2] && '_'==str[3]; +} + +static void * kgtk_get_fnptr(const char *raw_name) +{ + if(raw_name && isGtk(raw_name) && kgtkInit(NULL)) + { + if(0==strcmp(raw_name, "gtk_file_chooser_get_filename")) + return >k_file_chooser_get_filename; + + else if(0==strcmp(raw_name, "gtk_file_chooser_select_filename")) + return >k_file_chooser_select_filename; + + else if(0==strcmp(raw_name, "gtk_file_chooser_unselect_all")) + return >k_file_chooser_unselect_all; + + else if(0==strcmp(raw_name, "gtk_file_chooser_set_filename")) + return >k_file_chooser_set_filename; + + else if(0==strcmp(raw_name, "gtk_file_chooser_set_current_name")) + return >k_file_chooser_set_current_name; + + else if(0==strcmp(raw_name, "gtk_file_chooser_get_filenames")) + return >k_file_chooser_get_filenames; + + else if(0==strcmp(raw_name, "gtk_file_chooser_set_current_folder")) + return >k_file_chooser_set_current_folder; + + else if(0==strcmp(raw_name, "gtk_file_chooser_get_current_folder")) + return >k_file_chooser_get_current_folder; + + else if(0==strcmp(raw_name, "gtk_file_chooser_get_uri")) + return >k_file_chooser_get_uri; + + else if(0==strcmp(raw_name, "gtk_file_chooser_set_uri")) + return >k_file_chooser_set_uri; + + else if(0==strcmp(raw_name, "gtk_file_chooser_get_uris")) + return >k_file_chooser_get_uris; + + else if(0==strcmp(raw_name, "gtk_file_chooser_set_current_folder_uri")) + return >k_file_chooser_set_current_folder_uri; + + else if(0==strcmp(raw_name, "gtk_file_chooser_get_current_folder_uri")) + return >k_file_chooser_get_current_folder_uri; + + else if(0==strcmp(raw_name, "gtk_file_chooser_dialog_new")) + return >k_file_chooser_dialog_new; + + else if(0==strcmp(raw_name, "gtk_file_chooser_button_new")) + return >k_file_chooser_button_new; + +/* + else if(0==strcmp(raw_name, "gtk_init_check")) + return >k_init_check; +*/ + } + + return NULL; +} + +const gchar * kgtk_g_module_check_init(GModule *module) +{ + return gtk_check_version(GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION - GTK_INTERFACE_AGE); +} + +/* Mozilla specific */ +void * PR_FindFunctionSymbol(struct PR_LoadLibrary *lib, const char *raw_name) +{ + static void * (*realFunction)() = NULL; + + void *rv=NULL; + + if(!realFunction) + realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "PR_FindFunctionSymbol"); + +#ifdef KGTK_DEBUG_DLSYM + printf("KGTK::PR_FindFunctionSymbol : %s\n", raw_name); +#endif + + rv=kgtk_get_fnptr(raw_name); + + if(!rv) + { + if (0==strcmp(raw_name, "g_module_check_init")) + rv=&kgtk_g_module_check_init; + else if (isGtk(raw_name)) + rv=real_dlsym(RTLD_NEXT, raw_name); + } + + return rv ? rv : realFunction(lib, raw_name); +} + +#ifdef HAVE_DLVSYM +/* Overriding dlsym is required for SWT - which dlsym's the gtk_file_chooser functions! */ +static void * real_dlsym(void *handle, const char *name) +{ + static void * (*realFunction)() = NULL; + +#ifdef KGTK_DEBUG_DLSYM + printf("KGTK::real_dlsym : %s\n", name); +#endif + + if (!realFunction) + { + void *ldHandle=dlopen("libdl.so", RTLD_NOW); + +#ifdef KGTK_DEBUG_DLSYM + printf("KGTK::real_dlsym : %s\n", name); +#endif + + if(ldHandle) + { + static const char * versions[]={KGTK_DLSYM_VERSION, "GLIBC_2.3", "GLIBC_2.2.5", + "GLIBC_2.2", "GLIBC_2.1", "GLIBC_2.0", NULL}; + + int i; + + for(i=0; versions[i] && !realFunction; ++i) + realFunction=dlvsym(ldHandle, "dlsym", versions[i]); + } + } + + return realFunction(handle, name); +} + +void * dlsym(void *handle, const char *name) +{ + void *rv=NULL; + +#ifdef KGTK_DEBUG_DLSYM + printf("KGTK::dlsym : (%04X) %s\n", (int)handle, name); +#endif + rv=kgtk_get_fnptr(name); + + if(!rv) + rv=real_dlsym(handle, name); + + if(!rv && 0==strcmp(name, "g_module_check_init")) + rv=&kgtk_g_module_check_init; + +#ifdef KGTK_DEBUG_DLSYM + printf("KGTK::dlsym found? %d\n", rv ? 1 : 0); +#endif + return rv; +} +#endif diff --git a/kdialogd-wrapper b/kdialogd-wrapper new file mode 100755 index 0000000..5941e66 --- /dev/null +++ b/kdialogd-wrapper @@ -0,0 +1,27 @@ +#!/bin/bash + +# +# This script is part of the KGtk package. +# +# (C) Craig Drummond, 2007 +# +# +# -- +# Released under the GPL v2 or later +# -- +# +# Wrapper script for kdialogd that removes any LD_PRELOAD. This stops +# KDialogD from trying to connect to itself! +# + +LD_PRELOAD= + +for app in $prefer kdialogd4 kdialogd3 ; do + which $app > /dev/null + if [ $? -eq 0 ] ; then + $app + break; + fi +done + diff --git a/kdialogd3/CMakeLists.txt b/kdialogd3/CMakeLists.txt new file mode 100644 index 0000000..6e054c1 --- /dev/null +++ b/kdialogd3/CMakeLists.txt @@ -0,0 +1,17 @@ +set(QT_MT_REQUIRED TRUE) +find_package(KDE3) +find_package(Qt3) + +if (KDE3_INCLUDE_DIR) + message("** INFORMATION: KDialogD for KDE3 will be built.") + link_directories(${KDE3_LIB_DIR}) + include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/common ${CMAKE_BINARY_DIR} ${KDE3_INCLUDE_DIR} ${QT_INCLUDE_DIR}) + set(kdialogd3_SRCS kdialogd.cpp) + kde3_automoc(${kdialogd3_SRCS}) + add_executable(kdialogd3 ${kdialogd3_SRCS}) + target_link_libraries(kdialogd3 kdeui kio kdecore) + install_targets(/bin kdialogd3) + add_subdirectory(po) +else (KDE3_INCLUDE_DIR) + message("** ERROR : Could not locate Qt3/KDE3 headers, KDialogD for KDE3 will not be built.") +endif (KDE3_INCLUDE_DIR) diff --git a/kdialogd3/kdialogd.cpp b/kdialogd3/kdialogd.cpp new file mode 100644 index 0000000..8aee15e --- /dev/null +++ b/kdialogd3/kdialogd.cpp @@ -0,0 +1,721 @@ +//#define USE_KWIN + +#include "kdialogd.h" +#include <iostream> +#include <kdiroperator.h> +#include <kuniqueapplication.h> +#include <qsocketnotifier.h> +#include <kio/netaccess.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kconfig.h> +#include <kurlcombobox.h> +#ifdef USE_KWIN +#include <kwin.h> +#else +#include <X11/Xlib.h> +#endif +#include <sys/un.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <ksockaddr.h> +#include <kdebug.h> +#include <kdeversion.h> +#include <qtimer.h> +#ifdef KDIALOGD_APP +#include <kcmdlineargs.h> +#include <kaboutdata.h> +#endif +#include <fstream> + +KConfig *KDialogD::theirConfig=NULL; + +#define CFG_KEY_DIALOG_SIZE "KDialogDSize" +#define CFG_TIMEOUT_GROUP "General" +#ifdef KDIALOGD_APP +#define CFG_TIMEOUT_KEY "Timeout" +#define DEFAULT_TIMEOUT 30 +#endif + +static QString groupName(const QString &app, bool fileDialog=true) +{ + return QString(fileDialog ? "KFileDialog " : "KDirSelectDialog ")+app; +} + +// from kdebase/kdesu +static int createSocket() +{ + int sockitsFd; + ksocklen_t addrlen; + struct stat s; + const char *sock=getSockName(); + int stat_err=lstat(sock, &s); + + if(!stat_err && S_ISLNK(s.st_mode)) + { + kdWarning() << "Someone is running a symlink attack on you" << endl; + if(unlink(sock)) + { + kdWarning() << "Could not delete symlink" << endl; + return -1; + } + } + + if (!access(sock, R_OK|W_OK)) + { + kdWarning() << "stale socket exists" << endl; + if (unlink(sock)) + { + kdWarning() << "Could not delete stale socket" << endl; + return -1; + } + } + + sockitsFd = socket(PF_UNIX, SOCK_STREAM, 0); + if (sockitsFd < 0) + { + kdError() << "socket(): " << errno << endl; + return -1; + } + + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, sock, sizeof(addr.sun_path)-1); + addr.sun_path[sizeof(addr.sun_path)-1] = '\000'; + addrlen = SUN_LEN(&addr); + if (bind(sockitsFd, (struct sockaddr *)&addr, addrlen) < 0) + { + kdError() << "bind(): " << errno << endl; + return -1; + } + + struct linger lin; + lin.l_onoff = lin.l_linger = 0; + if (setsockopt(sockitsFd, SOL_SOCKET, SO_LINGER, (char *) &lin, sizeof(linger)) < 0) + { + kdError() << "setsockopt(SO_LINGER): " << errno << endl; + return -1; + } + + int opt = 1; + if (setsockopt(sockitsFd, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt)) < 0) + { + kdError() << "setsockopt(SO_REUSEADDR): " << errno << endl; + return -1; + } + opt = 1; + if (setsockopt(sockitsFd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, sizeof(opt)) < 0) + { + kdError() << "setsockopt(SO_KEEPALIVE): " << errno << endl; + return -1; + } + + if(::listen(sockitsFd, 1)<0) + { + kdError() << "listen(1): " << errno << endl; + return -1; + } + + //chmod(sock, 0600); + return sockitsFd; +} + +static void urls2Local(KURL::List &urls, QStringList &items, QWidget *parent) +{ + KURL::List::Iterator it(urls.begin()), + end(urls.end()); + + for(; it!=end; ++it) + if((*it).isLocalFile()) + items.append((*it).path()); + else + { +#if KDE_IS_VERSION(3, 5, 0) + KURL url(KIO::NetAccess::mostLocalURL(*it, parent)); + + if(url.isLocalFile()) + items.append(url.path()); + else + break; +#else + break; +#endif + } +} + +KDialogD::KDialogD(QObject *parent) + : QObject(parent), +#ifdef KDIALOGD_APP + itsTimer(NULL), + itsTimeoutVal(DEFAULT_TIMEOUT), +#endif + itsFd(::createSocket()), + itsNumConnections(0) +{ + if(itsFd<0) + { + kdError() << "KDialogD could not create socket" << endl; +#ifdef KDIALOGD_APP + kapp->exit(); +#endif + } + else + { + std::ofstream f(getPidFileName()); + + if(f) + { + f << getpid(); + f.close(); + } + if(!theirConfig) + theirConfig=new KConfig("kdialogdrc", false, false); + + connect(new QSocketNotifier(itsFd, QSocketNotifier::Read, this), + SIGNAL(activated(int)), this, SLOT(newConnection())); + +#ifdef KDIALOGD_APP + if(theirConfig->hasGroup(CFG_TIMEOUT_GROUP)) + { + theirConfig->setGroup(CFG_TIMEOUT_GROUP); + itsTimeoutVal=theirConfig->readNumEntry(CFG_TIMEOUT_KEY, DEFAULT_TIMEOUT); + if(itsTimeoutVal<0) + itsTimeoutVal=DEFAULT_TIMEOUT; + theirConfig->setGroup(QString::null); + } + + kdDebug() << "Timeout:" << itsTimeoutVal << endl; + if(itsTimeoutVal) + connect(itsTimer=new QTimer(this), SIGNAL(timeout()), this, SLOT(timeout())); +#endif + } +} + +KDialogD::~KDialogD() +{ + if(-1!=itsFd) + close(itsFd); + if(theirConfig) + delete theirConfig; + theirConfig=NULL; +} + +void KDialogD::newConnection() +{ + kdDebug() << "New connection" << endl; + + ksocklen_t addrlen = 64; + struct sockaddr_un clientname; + int connectedFD; + + if((connectedFD=::accept(itsFd, (struct sockaddr *) &clientname, &addrlen))>=0) + { + int appNameLen; + + if(readBlock(connectedFD, (char *)&appNameLen, 4)) + { + bool ok=true; + QCString appName; + + if(0==appNameLen) + appName="Generic"; + else + { + appName.resize(appNameLen); + ok=readBlock(connectedFD, appName.data(), appNameLen); + } + + if(ok) + { + itsNumConnections++; +#ifdef KDIALOGD_APP + if(itsTimer) + itsTimer->stop(); +#endif + connect(new KDialogDClient(connectedFD, appName, this), + SIGNAL(error(KDialogDClient *)), + this, SLOT(deleteConnection(KDialogDClient *))); + } + } + } +} + +void KDialogD::deleteConnection(KDialogDClient *client) +{ + kdDebug() << "Delete client" << endl; + delete client; + +#ifdef KDIALOGD_APP + if(0==--itsNumConnections) + if(itsTimeoutVal) + itsTimer->start(itsTimeoutVal*1000, true); // Only single shot... + else + timeout(); +#endif +} + +void KDialogD::timeout() +{ +#ifdef KDIALOGD_APP + if(0==itsNumConnections) + if(grabLock(0)>0) // 0=> no wait... + { + kdDebug() << "Timeout occured, and no connections, so exit" << endl; + kapp->exit(); + } + else //...unlock lock file... + { + kdDebug() << "Timeout occured, but unable to grab lock file - app must be connecting" << endl; + releaseLock(); + } +#endif +} + +KDialogDClient::KDialogDClient(int sock, const QString &an, QObject *parent) + : QObject(parent), + itsFd(sock), + itsDlg(NULL), + itsAccepted(false), + itsAppName(an) +{ + kdDebug() << "new client..." << itsAppName << " (" << itsFd << ")" << endl; + connect(new QSocketNotifier(itsFd, QSocketNotifier::Read, this), SIGNAL(activated(int)), this, SLOT(read())); + connect(new QSocketNotifier(itsFd, QSocketNotifier::Exception, this), SIGNAL(activated(int)), this, SLOT(close())); +} + +KDialogDClient::~KDialogDClient() +{ + kdDebug() << "Deleted client" << endl; + if(-1!=itsFd) + ::close(itsFd); + if(KDialogD::config()) + KDialogD::config()->sync(); +} + +void KDialogDClient::close() +{ + kdDebug() << "close " << itsFd << endl; + + ::close(itsFd); + itsFd=-1; + if(itsDlg) + { + itsDlg->close(); + itsDlg->delayedDestruct(); + itsDlg=NULL; + } + emit error(this); +} + +void KDialogDClient::read() +{ + kdDebug() << "read" << endl; + + if(-1==itsFd) + return; + + char request; + QString caption; + unsigned int xid=0; + + if(!itsDlg && readData(&request, 1) && request>=(char)OP_FILE_OPEN && request<=(char)OP_FOLDER && + readData((char *)&xid, 4) && readString(caption)) + { + if("."==caption) + switch((Operation)request) + { + case OP_FILE_OPEN: + case OP_FILE_OPEN_MULTIPLE: + caption=i18n("Open"); + break; + case OP_FILE_SAVE: + caption=i18n("Save As"); + break; + case OP_FOLDER: + caption=i18n("Select Folder"); + break; + default: + break; + } + + if(OP_FOLDER==(Operation)request) + { + QString intialFolder; + + if(readString(intialFolder)) + { + initDialog(caption, new KDialogDDirSelectDialog(itsAppName, intialFolder, true, NULL, + "folderdialog", false), xid); + return; + } + } + else + { + QString intialFolder, + filter; + char overW=0; + + if(readString(intialFolder) && readString(filter) && + (OP_FILE_SAVE!=(Operation)request || readData(&overW, 1))) + { + initDialog(caption, new KDialogDFileDialog(itsAppName, (Operation)request, intialFolder, + filter, overW ? true : false), xid); + return; + } + } + } + + kdDebug() << "Comms error, closing connection..." << itsFd << endl; + // If we get here something was wrong, close connection... + close(); +} + +void KDialogDClient::finished() +{ + if(-1==itsFd) + return; + + // + // * finished is emitted when a dialog is ok'ed/cancel'ed/closed + // * if the user just closes the dialog - neither ok nor cancel are emitted + // * the dir select dialog doesnt seem to set the QDialog result parameter + // when it is accepted - so for this reason if ok is clicked we store an + // 'accepted' value there, and check for that after the dialog is finished. + kdDebug() << "finished" << endl; + if(itsDlg && !(itsAccepted || QDialog::Accepted==itsDlg->result())) + cancel(); +} + +void KDialogDClient::ok(const QStringList &items) +{ + kdDebug() << "ok" << endl; + + int num=items.count(); + QStringList::ConstIterator it(items.begin()), + end(items.end()); + bool error=!writeData((char *)&num, 4); + + for(; !error && it!=end; ++it) + error=!writeString(*it); + + if(error) + close(); + else + itsAccepted=true; + if(itsDlg) + itsDlg->delayedDestruct(); + itsDlg=NULL; +} + +void KDialogDClient::cancel() +{ + if(itsDlg) + { + kdDebug() << "cancel" << endl; + + int rv=0; + + if(!writeData((char *)&rv, 4)) + close(); + if(itsDlg) + itsDlg->delayedDestruct(); + itsDlg=NULL; + } +} + +bool KDialogDClient::readData(QCString &buffer, int size) +{ + buffer.resize(size); + return ::readBlock(itsFd, buffer.data(), size); +} + +bool KDialogDClient::readString(QString &str) +{ + int size; + + if(!readData((char *)&size, 4)) + return false; + + QCString buffer; + buffer.resize(size); + + if(!readData(buffer.data(), size)) + return false; + + str=QString::fromUtf8(buffer.data()); + return true; +} + +bool KDialogDClient::writeString(const QString &str) +{ + QCString utf8(str.utf8()); + + int size=utf8.length()+1; + + return writeData((char *)&size, 4) && writeData(utf8.data(), size); +} + +void KDialogDClient::initDialog(const QString &caption, KDialogBase *d, unsigned int xid) +{ + itsAccepted=false; + itsDlg=d; + + if(!caption.isEmpty()) + itsDlg->setPlainCaption(caption); + + if(xid) + { +#ifdef USE_KWIN + KWin::setMainWindow(itsDlg, xid); + KWin::setState(itsDlg->winId(), NET::Modal); + + KWin::WindowInfo wi(KWin::windowInfo(xid, NET::WMGeometry, NET::WM2UserTime)); + QRect geom(wi.geometry()); + int rx=geom.x(), + ry=geom.y(); + + rx=(rx+(geom.width()/2))-(itsDlg->width()/2); + if(rx<0) + rx=0; + ry=(ry+(geom.height()/2))-(itsDlg->height()/2); + if(ry<0) + ry=0; + itsDlg->move(rx, ry); +#else + XWindowAttributes attr; + int rx, ry; + Window junkwin; + + XSetTransientForHint(qt_xdisplay(), itsDlg->winId(), xid); + if(XGetWindowAttributes(qt_xdisplay(), xid, &attr)) + { + XTranslateCoordinates(qt_xdisplay(), xid, attr.root, + -attr.border_width, -16, + &rx, &ry, &junkwin); + + rx=(rx+(attr.width/2))-(itsDlg->width()/2); + if(rx<0) + rx=0; + ry=(ry+(attr.height/2))-(itsDlg->height()/2); + if(ry<0) + ry=0; + itsDlg->move(rx, ry); + } +#endif + } + + connect(itsDlg, SIGNAL(ok(const QStringList &)), this, SLOT(ok(const QStringList &))); + connect(itsDlg, SIGNAL(finished()), this, SLOT(finished())); + itsDlg->show(); +} + +KDialogDFileDialog::KDialogDFileDialog(QString &an, Operation op, const QString &startDir, + const QString &filter, bool confirmOw) + : KFileDialog(startDir.isEmpty() || "~"==startDir ? QDir::homeDirPath() : startDir, + filter, NULL, NULL, false), + itsConfirmOw(confirmOw), + itsAppName(an) +{ + kdDebug() << "startDir:" << startDir << endl; + + switch(op) + { + case OP_FILE_OPEN: + setOperationMode(KFileDialog::Opening); + setMode((KFile::Mode)(KFile::File | KFile::ExistingOnly)); + break; + case OP_FILE_OPEN_MULTIPLE: + setOperationMode(KFileDialog::Opening); + setMode((KFile::Mode)(KFile::Files | KFile::ExistingOnly)); + break; + case OP_FILE_SAVE: + setOperationMode(KFileDialog::Saving); + setMode(KFile::File); + break; + default: + break; + } + + if(KDialogD::config()) + { + QString oldGrp(KDialogD::config()->group()), + grp(groupName(itsAppName)); + QSize defaultSize(600, 400); + + readConfig(KDialogD::config(), grp); + KDialogD::config()->setGroup(grp); + resize(KDialogD::config()->readSizeEntry(CFG_KEY_DIALOG_SIZE, &defaultSize)); + KDialogD::config()->setGroup(oldGrp); + } + + ops->clearHistory(); +} + +void KDialogDFileDialog::accept() +{ + kdDebug() << "KDialogDFileDialog::accept" << endl; +} + +void KDialogDFileDialog::slotOk() +{ + setResult(QDialog::Accepted); + KFileDialog::slotOk(); + + kdDebug() << "KDialogDFileDialog::slotOk" << endl; + KURL::List urls; + QStringList items; + bool good=true; + + if(mode()&KFile::Files) + urls=selectedURLs(); + else if(!locationEdit->currentText().isEmpty()) + urls.append(selectedURL()); + + if(urls.count()) + { + urls2Local(urls, items, this); + + if(urls.count()!=items.count()) + { + KMessageBox::sorry(this, i18n("You can only select local files."), + i18n("Remote Files Not Accepted")); + good=false; + } + else if(itsConfirmOw && KFileDialog::Saving==operationMode()) + good=!KIO::NetAccess::exists(urls.first(), false, this) || + KMessageBox::Continue==KMessageBox::warningContinueCancel(this, + i18n("File %1 exits.\nDo you want to replace it?") + .arg(urls.first().prettyURL()), + i18n("File Exists"), + KGuiItem(i18n("Replace"), "filesaveas"), QString::null, + KMessageBox::Notify|KMessageBox::PlainCaption); + + if(good) + { + QString filter(currentFilter()); + + if(!filter.isEmpty()) + items.append(filter); + + emit ok(items); + hide(); + KFileDialog::accept(); + } + else + setResult(QDialog::Rejected); + } +} + +KDialogDFileDialog::~KDialogDFileDialog() +{ + kdDebug() << "~KDialogDFileDialog" << endl; + + if(KDialogD::config()) + { + QString oldGrp(KDialogD::config()->group()), + grp(groupName(itsAppName)); + + writeConfig(KDialogD::config(), grp); + KDialogD::config()->setGroup(grp); + KDialogD::config()->writeEntry(CFG_KEY_DIALOG_SIZE, size()); + KDialogD::config()->setGroup(oldGrp); + } +} + +KDialogDDirSelectDialog::KDialogDDirSelectDialog(QString &an, const QString &startDir, bool localOnly, + QWidget *parent, const char *name, bool modal) + : KDirSelectDialog(startDir.isEmpty() || "~"==startDir + ? QDir::homeDirPath() : startDir, + localOnly, parent, name, modal), + itsAppName(an) +{ + kdDebug() << "startDir:" << startDir << endl; + + if(KDialogD::config()) + { + QString oldGrp(KDialogD::config()->group()), + grp(groupName(itsAppName, false)); + QSize defaultSize(600, 400); + + //readConfig(KDialogD::config(), grp); + KDialogD::config()->setGroup(grp); + resize(KDialogD::config()->readSizeEntry(CFG_KEY_DIALOG_SIZE, &defaultSize)); + KDialogD::config()->setGroup(oldGrp); + } +} + +KDialogDDirSelectDialog::~KDialogDDirSelectDialog() +{ + kdDebug() << "~KDialogDDirSelectDialog" << endl; + + if(KDialogD::config()) + { + QString oldGrp(KDialogD::config()->group()), + grp(groupName(itsAppName, false)); + + //writeConfig(KDialogD::config(), grp); + KDialogD::config()->setGroup(grp); + KDialogD::config()->writeEntry(CFG_KEY_DIALOG_SIZE, size()); + KDialogD::config()->setGroup(oldGrp); + } +} + +void KDialogDDirSelectDialog::slotOk() +{ + kdDebug() << "KDialogDDirSelectDialog::slotOk" << endl; + + KURL::List urls; + QStringList items; + + urls.append(url()); + urls2Local(urls, items, this); + + if(urls.count()!=items.count()) + KMessageBox::sorry(this, i18n("You can only select local folders."), + i18n("Remote Folders Not Accepted")); + else + { + emit ok(items); + hide(); + } +} + +#ifdef KDIALOGD_APP +static KAboutData aboutData("kdialogd3", I18N_NOOP("KDialog Daemon"), VERSION, + I18N_NOOP("Use KDE dialogs from non-KDE apps."), + KAboutData::License_GPL, + I18N_NOOP("(c) Craig Drummond, 2006-2007")); + +int main(int argc, char **argv) +{ + KCmdLineArgs::init(argc, argv, &aboutData); + + KUniqueApplication *app=new KUniqueApplication; + KDialogD kdialogd; + int rv=app->exec(); + + delete app; + + unlink(getSockName()); + releaseLock(); + return rv; +} +#else +extern "C" +{ + KDE_EXPORT KDEDModule *create_kdialogd(const QCString &obj) + { + return new KDialogDKDED(obj); + } +}; + +KDialogDKDED::KDialogDKDED(const QCString &obj) + : KDEDModule(obj) +{ + new KDialogD(this); +} +#endif + +#include "kdialogd.moc" + diff --git a/kdialogd3/kdialogd.h b/kdialogd3/kdialogd.h new file mode 100644 index 0000000..7e50580 --- /dev/null +++ b/kdialogd3/kdialogd.h @@ -0,0 +1,145 @@ +#ifndef __KDIALOGD_H__ +#define __KDIALOGD_H__ + +#include <kfile.h> +#include <kfiledialog.h> +#include <kfiledialog.h> +#include <kdirselectdialog.h> +#include "common.h" +#include "config.h" + +#ifdef KDIALOGD_APP +class QTimer; +#else +#include <kdedmodule.h> +#endif +class KDialogBase; +class KConfig; + +class KDialogDFileDialog : public KFileDialog +{ + Q_OBJECT + + public: + + KDialogDFileDialog(QString &an, Operation op, const QString& startDir, const QString& filter, + bool confirmOw); + virtual ~KDialogDFileDialog(); + + public slots: + + void accept(); + void slotOk(); + + signals: + + void ok(const QStringList &items); + + private: + + bool itsConfirmOw; + QString &itsAppName; +}; + +class KDialogDDirSelectDialog : public KDirSelectDialog +{ + Q_OBJECT + + public: + + KDialogDDirSelectDialog(QString &an, const QString &startDir = QString::null, + bool localOnly = false, + QWidget *parent = 0L, + const char *name = 0, bool modal = false); + virtual ~KDialogDDirSelectDialog(); + + public slots: + + void slotOk(); + + signals: + + void ok(const QStringList &items); + + private: + + QString &itsAppName; +}; + +class KDialogDClient : public QObject +{ + Q_OBJECT + + public: + + KDialogDClient(int sock, const QString &an, QObject *parent); + virtual ~KDialogDClient(); + + public slots: + + void read(); + void close(); + void ok(const QStringList &items); + void finished(); + + signals: + + void error(KDialogDClient *); + + private: + + void cancel(); + bool readData(QCString &buffer, int size); + bool readData(char *buffer, int size) { return readBlock(itsFd, buffer, size); } + bool writeData(const char *buffer, int size) { return writeBlock(itsFd, buffer, size); } + bool readString(QString &str); + bool writeString(const QString &str); + void initDialog(const QString &caption, KDialogBase *d, unsigned int xid); + + private: + + int itsFd; + KDialogBase *itsDlg; + bool itsAccepted; + QString itsAppName; +}; + +class KDialogD : public QObject +{ + Q_OBJECT + + public: + + KDialogD(QObject *parent=0L); + virtual ~KDialogD(); + + public slots: + + void newConnection(); + void deleteConnection(KDialogDClient *client); + void timeout(); + + static KConfig * config() { return theirConfig; } + + private: + +#ifdef KDIALOGD_APP + QTimer *itsTimer; + int itsTimeoutVal; +#endif + int itsFd, + itsNumConnections; + + static KConfig *theirConfig; +}; + +#ifndef KDIALOGD_APP +class KDialogDKDED : public KDEDModule +{ + public: + + KDialogDKDED(const QCString &obj); +}; +#endif + +#endif diff --git a/kdialogd3/po/CMakeLists.txt b/kdialogd3/po/CMakeLists.txt new file mode 100644 index 0000000..3f456de --- /dev/null +++ b/kdialogd3/po/CMakeLists.txt @@ -0,0 +1,41 @@ +find_package(Msgfmt REQUIRED) + +# .po to .gmo stuff +file(GLOB _pofiles *.po) + +foreach(_file ${_pofiles}) + get_filename_component(_file_we ${_file} NAME_WE) + set(_out "${CMAKE_CURRENT_BINARY_DIR}/${_file_we}.gmo") + set(_in "${_file_we}.po") + add_custom_command(OUTPUT ${_out} COMMAND ${MSGFMT_EXECUTABLE} -o ${_out} ${_file} DEPENDS ${_file}) + install(FILES ${_out} DESTINATION share/locale/${_file_we}/LC_MESSAGES/ RENAME kdialogd3.mo) + set(_outputs ${_outputs} ${_out}) +endforeach(_file) + +add_custom_target(pofiles ALL DEPENDS ${_outputs}) + +# Stuff to generate the .pot +set(POT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../kdialogd.cpp) +set(POT_OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/kdialogd3.pot) + +# Find xgettext +find_program(XGETTEXT_PATH NAMES "xgettext" PATHS "/usr/bin" "/usr/local/bin") +if(${XGETTEXT_PATH} STREQUAL "XGETTEXT_PATH-NOTFOUND") + message(STATUS "xgettext not found. You will not be able to run 'make extract_messages' in the 'po' directory.") +else(${XGETTEXT_PATH} STREQUAL "XGETTEXT_PATH-NOTFOUND") + message(STATUS "Found xgettext: ${XGETTEXT_PATH}") +endif(${XGETTEXT_PATH} STREQUAL "XGETTEXT_PATH-NOTFOUND") + +if(EXISTS ${KDE3_INCLUDE_DIR}/kde.pot) + add_custom_command( + OUTPUT ${POT_OUTPUT} + COMMAND ${XGETTEXT_PATH} --foreign-user -C -ci18n -ki18n -ktr2i18n -kI18N_NOOP -kI18N_NOOP2 -kaliasLocale -x "${KDE3_INCLUDE_DIR}/kde.pot" -o ${POT_OUTPUT} ${POT_SOURCES} + ) +else (EXISTS ${KDE3_INCLUDE_DIR}/kde.pot) + add_custom_command( + OUTPUT ${POT_OUTPUT} + COMMAND ${XGETTEXT_PATH} --foreign-user -C -ci18n -ki18n -ktr2i18n -kI18N_NOOP -kI18N_NOOP2 -kaliasLocale -o ${POT_OUTPUT} ${POT_SOURCES} + ) +endif (EXISTS ${KDE3_INCLUDE_DIR}/kde.pot) + +add_custom_target(extract_messages DEPENDS ${POT_OUTPUT}) diff --git a/kdialogd3/po/cs.po b/kdialogd3/po/cs.po new file mode 100644 index 0000000..e9dd016 --- /dev/null +++ b/kdialogd3/po/cs.po @@ -0,0 +1,63 @@ +# translation of cs.po to Česky +# This file is put in the public domain. +# +# Marián Kyral <[email protected]>, 2007. +msgid "" +msgstr "" +"Project-Id-Version: cs\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 14:40+0100\n" +"PO-Revision-Date: 2007-10-16 05:26+0200\n" +"Last-Translator: Marián Kyral <[email protected]>\n" +"Language-Team: Česky <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +#: kdialogd.cpp:328 +msgid "Select Folder" +msgstr "Vyberte složku" + +#: kdialogd.cpp:573 +msgid "You can only select local files." +msgstr "Můžete vybrat pouze místní soubory." + +#: kdialogd.cpp:574 +msgid "Remote Files Not Accepted" +msgstr "Vzdálené soubory nejsou akceptovány." + +#: kdialogd.cpp:580 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" +"Soubor %1 existuje.\n" +"Chcete jej přepsat?" + +#: kdialogd.cpp:582 +msgid "File Exists" +msgstr "Soubor existuje." + +#: kdialogd.cpp:667 +msgid "You can only select local folders." +msgstr "Můžete vybrat pouze místní složky." + +#: kdialogd.cpp:668 +msgid "Remote Folders Not Accepted" +msgstr "Vzdálené složky nejsou akceptovány." + +#: kdialogd.cpp:677 +msgid "KDialog Daemon" +msgstr "KDialog Daemon" + +#: kdialogd.cpp:678 +msgid "Use KDE dialogs from non-KDE apps." +msgstr "KDE souborové dialogy v ne-KDE aplikacích." + +#: kdialogd.cpp:680 +msgid "(c) Craig Drummond, 2006-2007" +msgstr "" +"(c) Craig Drummond, 2006-2007\n" +"Český překlad Marián Kyral" diff --git a/kdialogd3/po/de.po b/kdialogd3/po/de.po new file mode 100644 index 0000000..f21775b --- /dev/null +++ b/kdialogd3/po/de.po @@ -0,0 +1,62 @@ +# translation of kdialogd3.po to Deutsch +# This file is put in the public domain. +# +# Jannick Kuhr <[email protected]>, 2007. +msgid "" +msgstr "" +"Project-Id-Version: kdialogd3\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 14:40+0100\n" +"PO-Revision-Date: 2007-10-11 13:24+0200\n" +"Last-Translator: Jannick Kuhr <[email protected]>\n" +"Language-Team: Deutsch <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: kdialogd.cpp:328 +msgid "Select Folder" +msgstr "Ordner wählen" + +#: kdialogd.cpp:573 +msgid "You can only select local files." +msgstr "Sie können nur lokale Dateien auswählen." + +#: kdialogd.cpp:574 +msgid "Remote Files Not Accepted" +msgstr "Dateien von Fremdrechnern werden nicht akzeptiert." + +#: kdialogd.cpp:580 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" +"Die Datei %1 exisitiert bereits.\n" +"Wollen Sie sie ersetzen?" + +#: kdialogd.cpp:582 +msgid "File Exists" +msgstr "Datei existiert bereits" + +#: kdialogd.cpp:667 +msgid "You can only select local folders." +msgstr "Sie können nur lokale Ordner auswählen." + +#: kdialogd.cpp:668 +msgid "Remote Folders Not Accepted" +msgstr "Ordner von Fremdrechnern werden nicht akzeptiert." + +#: kdialogd.cpp:677 +msgid "KDialog Daemon" +msgstr "KDialog-Daemon" + +#: kdialogd.cpp:678 +msgid "Use KDE dialogs from non-KDE apps." +msgstr "KDE-Dialoge in Nicht-KDE-Programmen verwenden." + +#: kdialogd.cpp:680 +msgid "(c) Craig Drummond, 2006-2007" +msgstr "(c) Craig Drummond, 2006-2007" + diff --git a/kdialogd3/po/en_GB.po b/kdialogd3/po/en_GB.po new file mode 100644 index 0000000..18fd77b --- /dev/null +++ b/kdialogd3/po/en_GB.po @@ -0,0 +1,60 @@ +# translation of kdialogd3.po to British English +# Copyright (C) 2007 Craig Drummond <[email protected]> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: kdialogd3\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 14:40+0100\n" +"PO-Revision-Date: 2007-10-05 22:35+0200\n" +"Last-Translator: Craig Drummond <[email protected]>\n" +"Language-Team: Craig Drummond <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=iso-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: kdialogd.cpp:328 +msgid "Select Folder" +msgstr "Select Folder" + +#: kdialogd.cpp:573 +msgid "You can only select local files." +msgstr "You can only select local files." + +#: kdialogd.cpp:574 +msgid "Remote Files Not Accepted" +msgstr "Remote Files Not Accepted" + +#: kdialogd.cpp:580 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" +"File %1 exits.\n" +"Do you want to replace it?" + +#: kdialogd.cpp:582 +msgid "File Exists" +msgstr "File Exists" + +#: kdialogd.cpp:667 +msgid "You can only select local folders." +msgstr "You can only select local folders." + +#: kdialogd.cpp:668 +msgid "Remote Folders Not Accepted" +msgstr "Remote Folders Not Accepted" + +#: kdialogd.cpp:677 +msgid "KDialog Daemon" +msgstr "KDialog Daemon" + +#: kdialogd.cpp:678 +msgid "Use KDE dialogs from non-KDE apps." +msgstr "Use KDE dialogs from non-KDE apps." + +#: kdialogd.cpp:680 +msgid "(c) Craig Drummond, 2006-2007" +msgstr "(c) Craig Drummond, 2006-2007" diff --git a/kdialogd3/po/es.po b/kdialogd3/po/es.po new file mode 100644 index 0000000..5cdc2f4 --- /dev/null +++ b/kdialogd3/po/es.po @@ -0,0 +1,57 @@ +msgid "" +msgstr "" +"Project-Id-Version: kdialogd3\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 14:40+0100\n" +"PO-Revision-Date: 2007-10-19 18:17+0200\n" +"Last-Translator: Marco Antonio Blanco <[email protected]>\n" +"Language-Team: Craig Drummond <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=iso-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Pootle 0.10.1\n" + +#: kdialogd.cpp:328 +msgid "Select Folder" +msgstr "Seleccionar carpeta" + +#: kdialogd.cpp:573 +msgid "You can only select local files." +msgstr "S�lo se pueden seleccionar ficheros locales." + +#: kdialogd.cpp:574 +msgid "Remote Files Not Accepted" +msgstr "No se aceptan ficheros remotos" + +#: kdialogd.cpp:580 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" +"El fichero %1 existe.\n" +"�Quiere sustituirlo?" + +#: kdialogd.cpp:582 +msgid "File Exists" +msgstr "El fichero existe" + +#: kdialogd.cpp:667 +msgid "You can only select local folders." +msgstr "S�lo se pueden seleccionar carpetas locales" + +#: kdialogd.cpp:668 +msgid "Remote Folders Not Accepted" +msgstr "No se aceptan carpetas remotas" + +#: kdialogd.cpp:677 +msgid "KDialog Daemon" +msgstr "Demonio KDialog" + +#: kdialogd.cpp:678 +msgid "Use KDE dialogs from non-KDE apps." +msgstr "Utilizar di�logos KDE en aplicaciones no KDE." + +#: kdialogd.cpp:680 +msgid "(c) Craig Drummond, 2006-2007" +msgstr "(c) Craig Drummond, 2006-2007" diff --git a/kdialogd3/po/fr.po b/kdialogd3/po/fr.po new file mode 100644 index 0000000..6afa160 --- /dev/null +++ b/kdialogd3/po/fr.po @@ -0,0 +1,60 @@ +# translation of kdialogd3.po to French +# Copyright (C) 2007 aul Thomas <[email protected]> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: kdialogd3\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 14:40+0100\n" +"PO-Revision-Date: 2007-10-06 17:54+0200\n" +"Last-Translator: Paul Thomas <[email protected]>\n" +"Language-Team: Paul Thomas <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: kdialogd.cpp:328 +msgid "Select Folder" +msgstr "Sélectionnez le dossier" + +#: kdialogd.cpp:573 +msgid "You can only select local files." +msgstr "Vous ne pouvez sélectionner que des fichiers locaux." + +#: kdialogd.cpp:574 +msgid "Remote Files Not Accepted" +msgstr "Les fichiers distants ne sont pas acceptés" + +#: kdialogd.cpp:580 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" +"Le fichier %1 exite déjà.\n" +"Voulez-vous le remplacer" + +#: kdialogd.cpp:582 +msgid "File Exists" +msgstr "Le Fichier existe déjà" + +#: kdialogd.cpp:667 +msgid "You can only select local folders." +msgstr "Vous ne pouvez sélectionner que des dossiers locaux." + +#: kdialogd.cpp:668 +msgid "Remote Folders Not Accepted" +msgstr "Les dossiers distants ne sont pas acceptés" + +#: kdialogd.cpp:677 +msgid "KDialog Daemon" +msgstr "KDialog Daemon" + +#: kdialogd.cpp:678 +msgid "Use KDE dialogs from non-KDE apps." +msgstr "Utilisez les dialogues KDE à partir d'applications non-KDE." + +#: kdialogd.cpp:680 +msgid "(c) Craig Drummond, 2006-2007" +msgstr "(c) Craig Drummond, 2006-2007" diff --git a/kdialogd3/po/kdialogd3.pot b/kdialogd3/po/kdialogd3.pot new file mode 100644 index 0000000..a59be5f --- /dev/null +++ b/kdialogd3/po/kdialogd3.pot @@ -0,0 +1,58 @@ +# SOME DESCRIPTIVE TITLE. +# This file is put in the public domain. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 14:40+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: kdialogd.cpp:328 +msgid "Select Folder" +msgstr "" + +#: kdialogd.cpp:573 +msgid "You can only select local files." +msgstr "" + +#: kdialogd.cpp:574 +msgid "Remote Files Not Accepted" +msgstr "" + +#: kdialogd.cpp:580 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" + +#: kdialogd.cpp:582 +msgid "File Exists" +msgstr "" + +#: kdialogd.cpp:667 +msgid "You can only select local folders." +msgstr "" + +#: kdialogd.cpp:668 +msgid "Remote Folders Not Accepted" +msgstr "" + +#: kdialogd.cpp:677 +msgid "KDialog Daemon" +msgstr "" + +#: kdialogd.cpp:678 +msgid "Use KDE dialogs from non-KDE apps." +msgstr "" + +#: kdialogd.cpp:680 +msgid "(c) Craig Drummond, 2006-2007" +msgstr "" diff --git a/kdialogd3/po/pt_BR.po b/kdialogd3/po/pt_BR.po new file mode 100644 index 0000000..ac4c524 --- /dev/null +++ b/kdialogd3/po/pt_BR.po @@ -0,0 +1,60 @@ +# translation of kdialogd3.po to Brazillian Portuguese +# This file is put in the public domain. +# +# Márcio Moraes <[email protected]>, 2007. +msgid "" +msgstr "" +"Project-Id-Version: kdialogd3\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 14:40+0100\n" +"PO-Revision-Date: 2008-02-26 11:22-0300\n" +"Last-Translator: Márcio Moraes <[email protected]>\n" +"Language-Team: Márcio Moraes <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=iso-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: kdialogd.cpp:328 +msgid "Select Folder" +msgstr "Selecionar Pasta" + +#: kdialogd.cpp:573 +msgid "You can only select local files." +msgstr "Selecione apenas arquivos locais." + +#: kdialogd.cpp:574 +msgid "Remote Files Not Accepted" +msgstr "Arquivos remotos não são aceitos" + +#: kdialogd.cpp:580 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" +"Arquivo %1 existe.\n" +"Você realmente deseja sobrescrever?" + +#: kdialogd.cpp:582 +msgid "File Exists" +msgstr "Arquivo existe" + +#: kdialogd.cpp:667 +msgid "You can only select local folders." +msgstr "Selecione apenas pastas locais." + +#: kdialogd.cpp:668 +msgid "Remote Folders Not Accepted" +msgstr "Pastas remotas não são aceitas" + +#: kdialogd.cpp:677 +msgid "KDialog Daemon" +msgstr "KDialog Daemon" + +#: kdialogd.cpp:678 +msgid "Use KDE dialogs from non-KDE apps." +msgstr "Uso de diálogos KDE em aplicações não KDE." + +#: kdialogd.cpp:680 +msgid "(c) Craig Drummond, 2006-2007" +msgstr "(c) Craig Drummond, 2006-2007" diff --git a/kdialogd3/po/ru.po b/kdialogd3/po/ru.po new file mode 100644 index 0000000..cf2abd0 --- /dev/null +++ b/kdialogd3/po/ru.po @@ -0,0 +1,62 @@ +# translation of ru.po to +# This file is put in the public domain. +# +# Yarodin <[email protected]>, 2008. +msgid "" +msgstr "" +"Project-Id-Version: kdialogd3\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 14:40+0100\n" +"PO-Revision-Date: 2008-05-01 19:31+0600\n" +"Last-Translator: Yarodin <[email protected]>\n" +"Language-Team: Russian <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: kdialogd.cpp:328 +msgid "Select Folder" +msgstr "Выбор папки" + +#: kdialogd.cpp:573 +msgid "You can only select local files." +msgstr "Вы можете выбрать только локальные файлы." + +#: kdialogd.cpp:574 +msgid "Remote Files Not Accepted" +msgstr "Файлы на удаленной машине недоступны" + +#: kdialogd.cpp:580 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" +"Файл %1 уже существует.\n" +"Хотите его перезаписать?" + +#: kdialogd.cpp:582 +msgid "File Exists" +msgstr "Файл существует" + +#: kdialogd.cpp:667 +msgid "You can only select local folders." +msgstr "Вы можете выбрать только локальные папки." + +#: kdialogd.cpp:668 +msgid "Remote Folders Not Accepted" +msgstr "Сетевые папки недоступны." + +#: kdialogd.cpp:677 +msgid "KDialog Daemon" +msgstr "KDialog-Демон" + +#: kdialogd.cpp:678 +msgid "Use KDE dialogs from non-KDE apps." +msgstr "Использование KDE диалогов в Не-KDE приложениях." + +#: kdialogd.cpp:680 +msgid "(c) Craig Drummond, 2006-2007" +msgstr "(c) Craig Drummond, 2006-2007" + diff --git a/kdialogd3/po/zh_CN.po b/kdialogd3/po/zh_CN.po new file mode 100644 index 0000000..fab0e38 --- /dev/null +++ b/kdialogd3/po/zh_CN.po @@ -0,0 +1,60 @@ +# translation of kdialogd3.po to Chinese Simplified +# Copyright (C) 2007 Free Software Foundation, Inc. +# +# Liang Qi <[email protected]>, 2007. +msgid "" +msgstr "" +"Project-Id-Version: kdialogd3\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 14:40+0100\n" +"PO-Revision-Date: 2007-10-05 13:20+0200\n" +"Last-Translator: Liang Qi <[email protected]>\n" +"Language-Team: zh_CN <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: kdialogd.cpp:328 +msgid "Select Folder" +msgstr "选择文件夹" + +#: kdialogd.cpp:573 +msgid "You can only select local files." +msgstr "仅允许选择本地文件。" + +#: kdialogd.cpp:574 +msgid "Remote Files Not Accepted" +msgstr "无法接受远程文件" + +#: kdialogd.cpp:580 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" +"文件 %1 已经存在。\n" +"您想替换它么?" + +#: kdialogd.cpp:582 +msgid "File Exists" +msgstr "文件已存在" + +#: kdialogd.cpp:667 +msgid "You can only select local folders." +msgstr "仅允许选择本地文件夹。" + +#: kdialogd.cpp:668 +msgid "Remote Folders Not Accepted" +msgstr "无法接受远程文件夹" + +#: kdialogd.cpp:677 +msgid "KDialog Daemon" +msgstr "KDialog 守护进程" + +#: kdialogd.cpp:678 +msgid "Use KDE dialogs from non-KDE apps." +msgstr "在非 KDE 程序中使用 KDE 对话框。" + +#: kdialogd.cpp:680 +msgid "(c) Craig Drummond, 2006-2007" +msgstr "(c) Craig Drummond, 2006-2007" diff --git a/kdialogd4/CMakeLists.txt b/kdialogd4/CMakeLists.txt new file mode 100644 index 0000000..0c0f017 --- /dev/null +++ b/kdialogd4/CMakeLists.txt @@ -0,0 +1,16 @@ +find_package(KDE4) +find_package(Qt4) + +if (KDE4_FOUND) + message("** INFORMATION: KDialogD for KDE4 will be built.") + include (KDE4Defaults) + include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/common ${CMAKE_BINARY_DIR} ${KDE4_INCLUDE_DIR} ${QT_INCLUDE_DIR}) + set(kdialogd4_bin_SRCS kdialogd.cpp) + kde4_add_executable(kdialogd4_bin ${kdialogd4_bin_SRCS}) + set_target_properties(kdialogd4_bin PROPERTIES OUTPUT_NAME kdialogd4) + target_link_libraries(kdialogd4_bin ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${KDE4_KIO_LIBS} ${KDE4_KDECORE_LIBRARY} kfile ) + install(TARGETS kdialogd4_bin ${INSTALL_TARGETS_DEFAULT_ARGS} ) + add_subdirectory(po) +else (KDE4_FOUND) + message("** ERROR : Could not locate Qt4/KDE4 headers, KDialogD for KDE4 will not be built.") +endif (KDE4_FOUND) diff --git a/kdialogd4/kdialogd.cpp b/kdialogd4/kdialogd.cpp new file mode 100644 index 0000000..ddd1142 --- /dev/null +++ b/kdialogd4/kdialogd.cpp @@ -0,0 +1,759 @@ +#define USE_KWIN + +#include "kdialogd.h" +#include <iostream> +#include <kdiroperator.h> +#include <kuniqueapplication.h> +#include <QtCore/QSocketNotifier> +#include <QtGui/QX11Info> +#include <kio/netaccess.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kconfig.h> +#include <kurlcombobox.h> +#ifdef USE_KWIN +#include <kwindowsystem.h> +#else +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <fixx11h.h> +#endif +#include <sys/un.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <kdebug.h> +#include <kdeversion.h> +#ifdef KDIALOGD_APP +#include <QtCore/QTimer> +#include <kcmdlineargs.h> +#include <kaboutdata.h> +#endif +#include <kabstractfilewidget.h> +#include <fstream> + +KConfig *KDialogD::theirConfig=NULL; + +#define CFG_KEY_DIALOG_SIZE "KDialogDSize" +#define CFG_TIMEOUT_GROUP "General" +#ifdef KDIALOGD_APP +#define CFG_TIMEOUT_KEY "Timeout" +#define DEFAULT_TIMEOUT 30 +#endif + +static QString groupName(const QString &app, bool fileDialog=true) +{ + return QString(fileDialog ? "KFileDialog " : "KDirSelectDialog ")+app; +} + +// from kdebase/kdesu +typedef unsigned ksocklen_t; + +static int createSocket() +{ + int socketFd; + ksocklen_t addrlen; + struct stat s; + const char *sock=getSockName(); + int stat_err=lstat(sock, &s); + + if(!stat_err && S_ISLNK(s.st_mode)) + { + kWarning() << "Someone is running a symlink attack on you" ; + if(unlink(sock)) + { + kWarning() << "Could not delete symlink" ; + return -1; + } + } + + if (!access(sock, R_OK|W_OK)) + { + kWarning() << "stale socket exists" ; + if (unlink(sock)) + { + kWarning() << "Could not delete stale socket" ; + return -1; + } + } + + socketFd = socket(PF_UNIX, SOCK_STREAM, 0); + if (socketFd < 0) + { + kError() << "socket(): " << strerror(errno); + return -1; + } + + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, sock, sizeof(addr.sun_path)-1); + addr.sun_path[sizeof(addr.sun_path)-1] = '\000'; + addrlen = SUN_LEN(&addr); + if (bind(socketFd, (struct sockaddr *)&addr, addrlen) < 0) + { + kError() << "bind(): " << strerror(errno); + return -1; + } + + struct linger lin; + lin.l_onoff = lin.l_linger = 0; + if (setsockopt(socketFd, SOL_SOCKET, SO_LINGER, (char *) &lin, + sizeof(linger)) < 0) + { + kError() << "setsockopt(SO_LINGER): " << strerror(errno); + return -1; + } + + int opt = 1; + if (setsockopt(socketFd, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, + sizeof(opt)) < 0) + { + kError() << "setsockopt(SO_REUSEADDR): " << strerror(errno); + return -1; + } + opt = 1; + if (setsockopt(socketFd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, + sizeof(opt)) < 0) + { + kError() << "setsockopt(SO_KEEPALIVE): " << strerror(errno); + return -1; + } + chmod(sock, 0600); + if (listen(socketFd, 1) < 0) + { + kError() << "listen(): " << strerror(errno); + return -1; + } + + return socketFd; +} + +static void urls2Local(KUrl::List &urls, QStringList &items, QWidget *parent) +{ + KUrl::List::Iterator it(urls.begin()), + end(urls.end()); + + for(; it!=end; ++it) + { + kDebug() << "URL:" << *it << " local? " << (*it).isLocalFile(); + if((*it).isLocalFile()) + items.append((*it).path()); + else + { + KUrl url(KIO::NetAccess::mostLocalUrl(*it, parent)); + + kDebug() << "mostLocal:" << url << " local? " << url.isLocalFile(); + if(url.isLocalFile()) + items.append(url.path()); + else + break; + } + } +} + +KDialogD::KDialogD(QObject *parent) + : QObject(parent), +#ifdef KDIALOGD_APP + itsTimer(NULL), + itsTimeoutVal(DEFAULT_TIMEOUT), +#endif + itsFd(::createSocket()), + itsNumConnections(0) +{ + if(itsFd<0) + { + kError() << "KDialogD could not create socket"; +#ifdef KDIALOGD_APP + kapp->exit(); +#endif + } + else + { + std::ofstream f(getPidFileName()); + + if(f) + { + f << getpid(); + f.close(); + } + if(!theirConfig) + theirConfig=new KConfig("kdialogd4rc"); // , KConfig::OnlyLocal); + + connect(new QSocketNotifier(itsFd, QSocketNotifier::Read, this), + SIGNAL(activated(int)), this, SLOT(newConnection())); + +#ifdef KDIALOGD_APP + if(theirConfig->hasGroup(CFG_TIMEOUT_GROUP)) + { + itsTimeoutVal=KConfigGroup(theirConfig, CFG_TIMEOUT_GROUP).readEntry(CFG_TIMEOUT_KEY, DEFAULT_TIMEOUT); + if(itsTimeoutVal<0) + itsTimeoutVal=DEFAULT_TIMEOUT; + } + kDebug() << "Timeout:" << itsTimeoutVal; + if(itsTimeoutVal) + { + connect(itsTimer=new QTimer(this), SIGNAL(timeout()), this, SLOT(timeout())); + itsTimer->setSingleShot(true); + } +#endif + } +} + +KDialogD::~KDialogD() +{ + if(-1!=itsFd) + close(itsFd); + if(theirConfig) + delete theirConfig; + theirConfig=NULL; +} + +void KDialogD::newConnection() +{ + kDebug() << "New connection"; + + ksocklen_t addrlen = 64; + struct sockaddr_un clientname; + int connectedFD; + + if((connectedFD=::accept(itsFd, (struct sockaddr *) &clientname, &addrlen))>=0) + { + int appNameLen; + + if(readBlock(connectedFD, (char *)&appNameLen, 4)) + { + bool ok=true; + QByteArray appName; + + if(0==appNameLen) + appName="Generic"; + else + { + appName.resize(appNameLen); + ok=readBlock(connectedFD, appName.data(), appNameLen); + } + + if(ok) + { + itsNumConnections++; +#ifdef KDIALOGD_APP + if(itsTimer) + itsTimer->stop(); +#endif + connect(new KDialogDClient(connectedFD, appName, this), + SIGNAL(error(KDialogDClient *)), + this, SLOT(deleteConnection(KDialogDClient *))); + } + } + } +} + +void KDialogD::deleteConnection(KDialogDClient *client) +{ + kDebug() << "Delete client"; + delete client; + +#ifdef KDIALOGD_APP + if(0==--itsNumConnections) + if(itsTimeoutVal) + itsTimer->start(itsTimeoutVal*1000); // Only single shot... + else + timeout(); +#endif +} + +void KDialogD::timeout() +{ +#ifdef KDIALOGD_APP + if(0==itsNumConnections) + if(grabLock(0)>0) // 0=> no wait... + { + kDebug() << "Timeout occured, and no connections, so exit"; + kapp->exit(); + } + else //...unlock lock file... + { + kDebug() << "Timeout occured, but unable to grab lock file - app must be connecting"; + releaseLock(); + } +#endif +} + +KDialogDClient::KDialogDClient(int sock, const QString &an, QObject *parent) + : QObject(parent), + itsFd(sock), + itsDlg(NULL), + itsXid(0), + itsAccepted(false), + itsAppName(an) +{ + kDebug() << "new client..." << itsAppName << " (" << itsFd << ")"; + connect(new QSocketNotifier(itsFd, QSocketNotifier::Read, this), SIGNAL(activated(int)), this, SLOT(read())); + connect(new QSocketNotifier(itsFd, QSocketNotifier::Exception, this), SIGNAL(activated(int)), this, SLOT(close())); +} + +KDialogDClient::~KDialogDClient() +{ + kDebug() << "Deleted client"; + if(-1!=itsFd) + ::close(itsFd); + itsDlg=NULL; + if(KDialogD::config()) + KDialogD::config()->sync(); +} + +void KDialogDClient::close() +{ + kDebug() << "close" << itsFd; + + ::close(itsFd); + itsFd=-1; + if(itsDlg) + { + itsDlg->close(); + itsDlg->delayedDestruct(); + itsDlg=NULL; + itsXid=0; + } + + emit error(this); +} + +void KDialogDClient::read() +{ + kDebug() << "read" << itsFd; + + if(-1==itsFd) + return; + + char request; + QString caption; + + if(!itsDlg && readData(&request, 1) && request>=(char)OP_FILE_OPEN && request<=(char)OP_FOLDER && + readData((char *)&itsXid, 4) && readString(caption)) + { + if("."==caption) + switch((Operation)request) + { + case OP_FILE_OPEN: + case OP_FILE_OPEN_MULTIPLE: + caption=i18n("Open"); + break; + case OP_FILE_SAVE: + caption=i18n("Save As"); + break; + case OP_FOLDER: + caption=i18n("Select Folder"); + break; + default: + break; + } + + if(OP_FOLDER==(Operation)request) + { + QString intialFolder; + + if(readString(intialFolder)) + { + initDialog(caption, new KDialogDDirSelectDialog(itsAppName, intialFolder, true, NULL, false)); + return; + } + } + else + { + QString intialFolder, + filter; + char overW=0; + + if(readString(intialFolder) && readString(filter) && + (OP_FILE_SAVE!=(Operation)request || readData(&overW, 1))) + { + initDialog(caption, new KDialogDFileDialog(itsAppName, (Operation)request, intialFolder, + filter, overW ? true : false)); + return; + } + } + } + + kDebug() << "Comms error, closing connection..." << itsFd; + // If we get here something was wrong, close connection... + close(); +} + +void KDialogDClient::finished() +{ + if(-1==itsFd) + return; + + // + // * finished is emitted when a dialog is ok'ed/cancel'ed/closed + // * if the user just closes the dialog - neither ok nor cancel are emitted + // * the dir select dialog doesnt seem to set the QDialog result parameter + // when it is accepted - so for this reason if ok is clicked we store an + // 'accepted' value there, and check for that after the dialog is finished. + kDebug() << "finished " << (void *)itsDlg << itsAccepted << (itsDlg ? QDialog::Accepted==itsDlg->result() : false); + + if(itsDlg && !(itsAccepted || QDialog::Accepted==itsDlg->result())) + cancel(); +} + +void KDialogDClient::ok(const QStringList &items) +{ + kDebug() << "ok"; + + int num=items.count(); + QStringList::ConstIterator it(items.begin()), + end(items.end()); + bool error=!writeData((char *)&num, 4); + + for(; !error && it!=end; ++it) + { + kDebug() << "writeString " << *it; + error=!writeString(*it); + } + + if(error) + close(); + else + itsAccepted=true; + if(itsDlg) + itsDlg->delayedDestruct(); + itsDlg=NULL; +} + +void KDialogDClient::cancel() +{ + kDebug() << "cancel"; + + if(itsDlg) + { + kDebug() << "send cancel"; + + int rv=0; + + if(!writeData((char *)&rv, 4)) + { + kDebug() << "failed to write data!"; + close(); + } + if(itsDlg) + itsDlg->delayedDestruct(); + itsDlg=NULL; + } +} + +bool KDialogDClient::readData(QByteArray &buffer, int size) +{ + kDebug() << "readData" << itsFd; + buffer.resize(size); + return ::readBlock(itsFd, buffer.data(), size); +} + +bool KDialogDClient::readString(QString &str) +{ + kDebug() << "readString" << itsFd; + + int size; + + if(!readData((char *)&size, 4)) + return false; + + QByteArray buffer; + buffer.resize(size); + + if(!readData(buffer.data(), size)) + return false; + + str=QString::fromUtf8(buffer.data()); + return true; +} + +bool KDialogDClient::writeString(const QString &str) +{ + kDebug() << "writeString" << itsFd; + + QByteArray utf8(str.toUtf8()); + + int size=utf8.length()+1; + + return writeData((char *)&size, 4) && writeData(utf8.data(), size); +} + +void KDialogDClient::initDialog(const QString &caption, KDialog *d) +{ + kDebug() << "initDialog" << itsFd; + + itsAccepted=false; + itsDlg=d; + + if(!caption.isEmpty()) + itsDlg->setPlainCaption(caption); + + if(itsXid) + itsDlg->installEventFilter(this); + + connect(itsDlg, SIGNAL(okClicked()), itsDlg, SLOT(slotOk())); + connect(itsDlg, SIGNAL(ok(const QStringList &)), this, SLOT(ok(const QStringList &))); + connect(itsDlg, SIGNAL(finished()), this, SLOT(finished())); + itsDlg->show(); +} + +bool KDialogDClient::eventFilter(QObject *object, QEvent *event) +{ + if(object==itsDlg && QEvent::ShowToParent==event->type()) + { +#ifdef USE_KWIN + KWindowSystem::setMainWindow(itsDlg, itsXid); + KWindowSystem::setState(itsDlg->winId(), NET::Modal|NET::SkipTaskbar|NET::SkipPager); + +#if 0 + KWindowInfo wi(KWindowSystem::windowInfo(itsXid, NET::WMGeometry, NET::WM2UserTime)); + QRect geom(wi.geometry()); + int rx=geom.x(), + ry=geom.y(); + + rx=(rx+(geom.width()/2))-(itsDlg->width()/2); + if(rx<0) + rx=0; + ry=(ry+(geom.height()/2))-(itsDlg->height()/2); + if(ry<0) + ry=0; + itsDlg->move(rx, ry); +#endif + QPixmap icon=KWindowSystem::icon(itsXid, 16, 16, true, KWindowSystem::NETWM | KWindowSystem::WMHints); + if(!icon.isNull()) + itsDlg->setWindowIcon(QIcon(icon)); +#else + XSetTransientForHint(QX11Info::display(), itsDlg->winId(), itsXid); +#if 0 + XWindowAttributes attr; + int rx, ry; + Window junkwin; + + if(XGetWindowAttributes(QX11Info::display(), itsXid, &attr)) + { + XTranslateCoordinates(QX11Info::display(), itsXid, attr.root, + -attr.border_width, -16, + &rx, &ry, &junkwin); + + rx=(rx+(attr.width/2))-(itsDlg->width()/2); + if(rx<0) + rx=0; + ry=(ry+(attr.height/2))-(itsDlg->height()/2); + if(ry<0) + ry=0; + itsDlg->move(rx, ry); + } +#endif + +// unsigned long num; +// unsigned long *data = NULL; +// Atom prop = XInternAtom(QX11Info::display(), "_NET_WM_ICON", False); +// Atom typeRet; +// int formatRet; +// unsigned long afterRet; +// if(XGetWindowProperty(QX11Info::display(), itsXid, prop, 0, 0x7FFFFFFF, False, XA_CARDINAL, +// &typeRet, &formatRet, &num, &afterRet, (unsigned char **)&data)) +// { +// kDebug() << "GOT ICON!!!"; +// } +// else +// kDebug() << "FAILED TO GET ICON!!!"; +#endif + itsDlg->removeEventFilter(this); + } + + return false; +} + +KDialogDFileDialog::KDialogDFileDialog(QString &an, Operation op, const QString &startDir, + const QString &filter, bool confirmOw) + : KFileDialog(KUrl(startDir.isEmpty() || "~"==startDir ? QDir::homePath() : startDir), + filter, NULL), + itsConfirmOw(confirmOw), + itsDone(false), + itsAppName(an) +{ + setModal(false); + setSelection(startDir); + kDebug() << "startDir:" << startDir; + + switch(op) + { + case OP_FILE_OPEN: + setOperationMode(KFileDialog::Opening); + setMode(KFile::File|KFile::ExistingOnly); + break; + case OP_FILE_OPEN_MULTIPLE: + setOperationMode(KFileDialog::Opening); + setMode(KFile::Files|KFile::ExistingOnly); + break; + case OP_FILE_SAVE: + setOperationMode(KFileDialog::Saving); + setMode(KFile::File); + break; + default: + break; + } + + if(KDialogD::config()) + { + KConfigGroup cfg(KDialogD::config(), groupName(itsAppName)); + + //TODO !!! readConfig(KDialogD::config(), grp); + resize(cfg.readEntry(CFG_KEY_DIALOG_SIZE, QSize(600, 400))); + } + + //TODO !!! ops->clearHistory(); +} + +void KDialogDFileDialog::accept() +{ + fileWidget()->accept(); + + kDebug() << "KDialogDFileDialog::slotOk" << selectedUrls().count() << ' ' << mode() << ' ' << selectedUrl().prettyUrl(); + KUrl::List urls(selectedUrls()); + QStringList items; + bool good=true; + + if(urls.count()) + { + urls2Local(urls, items, this); + + if(urls.count()!=items.count()) + { + KMessageBox::sorry(this, i18n("You can only select local files."), + i18n("Remote Files Not Accepted")); + good=false; + } + else if(itsConfirmOw && KFileDialog::Saving==operationMode()) + good=!KIO::NetAccess::exists(urls.first(), KIO::NetAccess::DestinationSide, this) || + KMessageBox::Continue==KMessageBox::warningContinueCancel(this, + i18n("File %1 exits.\nDo you want to replace it?") + .arg(urls.first().prettyUrl()), + i18n("File Exists"), + KGuiItem(i18n("Replace"), "filesaveas"), KStandardGuiItem::cancel(), QString(), + KMessageBox::Notify|KMessageBox::PlainCaption); + + if(good) + { + QString filter(currentFilter()); + + if(!filter.isEmpty()) + items.append(filter); + + emit ok(items); + hide(); + //KFileDialog::accept(); + } + else + setResult(QDialog::Rejected); + } +} + +KDialogDFileDialog::~KDialogDFileDialog() +{ + kDebug() << "~KDialogDFileDialog"; + + if(KDialogD::config()) + { + KConfigGroup cfg(KDialogD::config(), groupName(itsAppName)); + + //TODO !!! writeConfig(KDialogD::config(), grp); + cfg.writeEntry(CFG_KEY_DIALOG_SIZE, size()); + } +} + +KDialogDDirSelectDialog::KDialogDDirSelectDialog(QString &an, const QString &startDir, bool localOnly, + QWidget *parent, bool modal) + : KDirSelectDialog(KUrl(startDir.isEmpty() || "~"==startDir + ? QDir::homePath() : startDir), + localOnly, parent), + itsAppName(an) +{ + kDebug() << "startDir:" << startDir; + + setModal(false); + if(KDialogD::config()) + { + KConfigGroup cfg(KDialogD::config(), groupName(itsAppName, false)); + + //TODO !!! readConfig(KDialogD::config(), grp); + resize(cfg.readEntry(CFG_KEY_DIALOG_SIZE, QSize(600, 400))); + } +} + +KDialogDDirSelectDialog::~KDialogDDirSelectDialog() +{ + kDebug() << "~KDialogDDirSelectDialog"; + + if(KDialogD::config()) + { + KConfigGroup cfg(KDialogD::config(), groupName(itsAppName, false)); + + //TODO !!! writeConfig(KDialogD::config(), grp); + cfg.writeEntry(CFG_KEY_DIALOG_SIZE, size()); + } +} + +void KDialogDDirSelectDialog::slotOk() +{ + kDebug() << "KDialogDDirSelectDialog::slotOk"; + + KUrl::List urls; + QStringList items; + + urls.append(url()); + urls2Local(urls, items, this); + + if(urls.count()!=items.count()) + KMessageBox::sorry(this, i18n("You can only select local folders."), + i18n("Remote Folders Not Accepted")); + else + { + emit ok(items); + hide(); + } +} + +#ifdef KDIALOGD_APP +static KAboutData aboutData("kdialogd4", "kdialogd4", ki18n("KDialog Daemon"), VERSION, + ki18n("Use KDE dialogs from non-KDE apps."), + KAboutData::License_GPL, + ki18n("(c) Craig Drummond, 2006-2007")); + +int main(int argc, char **argv) +{ + KCmdLineArgs::init(argc, argv, &aboutData); + + KUniqueApplication *app=new KUniqueApplication; + KDialogD kdialogd; + + QApplication::setQuitOnLastWindowClosed(false); + + int rv=app->exec(); + + delete app; + + unlink(getSockName()); + releaseLock(); + return rv; +} +#else +extern "C" +{ + KDE_EXPORT KDEDModule *create_kdialogd() + { + return new KDialogDKDED(); + } +}; + +KDialogDKDED::KDialogDKDED() + : KDEDModule() +{ + new KDialogD(this); +} +#endif + +#include "kdialogd.moc" + diff --git a/kdialogd4/kdialogd.h b/kdialogd4/kdialogd.h new file mode 100644 index 0000000..c5e7e7d --- /dev/null +++ b/kdialogd4/kdialogd.h @@ -0,0 +1,146 @@ +#ifndef __KDIALOGD_H__ +#define __KDIALOGD_H__ + +#include <kfile.h> +#include <kfiledialog.h> +#include <kfiledialog.h> +#include <kdirselectdialog.h> +#include "common.h" +#include "config.h" + +#ifdef KDIALOGD_APP +class QTimer; +#else +#include <kdedmodule.h> +#endif +class KDialog; +class KConfig; + +class KDialogDFileDialog : public KFileDialog +{ + Q_OBJECT + + public: + + KDialogDFileDialog(QString &an, Operation op, const QString& startDir, const QString& filter, + bool confirmOw); + virtual ~KDialogDFileDialog(); + + public slots: + + void accept(); + + signals: + + void ok(const QStringList &items); + + private: + + bool itsConfirmOw, + itsDone; + QString &itsAppName; +}; + +class KDialogDDirSelectDialog : public KDirSelectDialog +{ + Q_OBJECT + + public: + + KDialogDDirSelectDialog(QString &an, const QString &startDir = QString(), + bool localOnly = false, QWidget *parent = 0L, + bool modal = false); + virtual ~KDialogDDirSelectDialog(); + + public slots: + + void slotOk(); + + signals: + + void ok(const QStringList &items); + + private: + + QString &itsAppName; +}; + +class KDialogDClient : public QObject +{ + Q_OBJECT + + public: + + KDialogDClient(int sock, const QString &an, QObject *parent); + virtual ~KDialogDClient(); + + public slots: + + void read(); + void close(); + void ok(const QStringList &items); + void finished(); + + signals: + + void error(KDialogDClient *); + + private: + + void cancel(); + bool readData(QByteArray &buffer, int size); + bool readData(char *buffer, int size) { return readBlock(itsFd, buffer, size); } + bool writeData(const char *buffer, int size) { return writeBlock(itsFd, buffer, size); } + bool readString(QString &str); + bool writeString(const QString &str); + void initDialog(const QString &caption, KDialog *d); + bool eventFilter(QObject *object, QEvent *event); + + private: + + int itsFd; + KDialog *itsDlg; + unsigned int itsXid; + bool itsAccepted; + QString itsAppName; +}; + +class KDialogD : public QObject +{ + Q_OBJECT + + public: + + KDialogD(QObject *parent=0L); + virtual ~KDialogD(); + + public slots: + + void newConnection(); + void deleteConnection(KDialogDClient *client); + void timeout(); + + static KConfig * config() { return theirConfig; } + + private: + +#ifdef KDIALOGD_APP + QTimer *itsTimer; + int itsTimeoutVal; +#endif + int itsFd, + itsNumConnections; + + static KConfig *theirConfig; +}; + +#ifndef KDIALOGD_APP +class KDialogDKDED : public KDEDModule +{ + public: + + KDialogDKDED(); +}; +#endif + +#endif diff --git a/kdialogd4/po/CMakeLists.txt b/kdialogd4/po/CMakeLists.txt new file mode 100644 index 0000000..c706aff --- /dev/null +++ b/kdialogd4/po/CMakeLists.txt @@ -0,0 +1,41 @@ +find_package(Msgfmt REQUIRED) + +# .po to .gmo stuff +file(GLOB _pofiles *.po) + +foreach(_file ${_pofiles}) + get_filename_component(_file_we ${_file} NAME_WE) + set(_out "${CMAKE_CURRENT_BINARY_DIR}/${_file_we}.gmo") + set(_in "${_file_we}.po") + add_custom_command(OUTPUT ${_out} COMMAND ${MSGFMT_EXECUTABLE} -o ${_out} ${_file} DEPENDS ${_file}) + install(FILES ${_out} DESTINATION share/locale/${_file_we}/LC_MESSAGES/ RENAME kdialogd4.mo) + set(_outputs ${_outputs} ${_out}) +endforeach(_file) + +add_custom_target(pofiles ALL DEPENDS ${_outputs}) + +# Stuff to generate the .pot +set(POT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../kdialogd.cpp) +set(POT_OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/kdialogd4.pot) + +# Find xgettext +find_program(XGETTEXT_PATH NAMES "xgettext" PATHS "/usr/bin" "/usr/local/bin") +if(${XGETTEXT_PATH} STREQUAL "XGETTEXT_PATH-NOTFOUND") + message(STATUS "xgettext not found. You will not be able to run 'make extract_messages' in the 'po' directory.") +else(${XGETTEXT_PATH} STREQUAL "XGETTEXT_PATH-NOTFOUND") + message(STATUS "Found xgettext: ${XGETTEXT_PATH}") +endif(${XGETTEXT_PATH} STREQUAL "XGETTEXT_PATH-NOTFOUND") + +if(EXISTS ${KDE4_INCLUDE_DIR}/kde.pot) + add_custom_command( + OUTPUT ${POT_OUTPUT} + COMMAND ${XGETTEXT_PATH} --foreign-user -C -ci18n -ki18n -ktr2i18n -kI18N_NOOP -kI18N_NOOP2 -kaliasLocale -x "${KDE4_INCLUDE_DIR}/kde.pot" -o ${POT_OUTPUT} ${POT_SOURCES} + ) +else (EXISTS ${KDE4_INCLUDE_DIR}/kde.pot) + add_custom_command( + OUTPUT ${POT_OUTPUT} + COMMAND ${XGETTEXT_PATH} --foreign-user -C -ci18n -ki18n -ktr2i18n -kI18N_NOOP -kI18N_NOOP2 -kaliasLocale -o ${POT_OUTPUT} ${POT_SOURCES} + ) +endif (EXISTS ${KDE4_INCLUDE_DIR}/kde.pot) + +add_custom_target(extract_messages DEPENDS ${POT_OUTPUT}) diff --git a/kdialogd4/po/cs.po b/kdialogd4/po/cs.po new file mode 100644 index 0000000..9e4d454 --- /dev/null +++ b/kdialogd4/po/cs.po @@ -0,0 +1,61 @@ +# translation of cs.po to Česky +# This file is put in the public domain. +# +# Marián Kyral <[email protected]>, 2007. +msgid "" +msgstr "" +"Project-Id-Version: cs\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 15:08+0100\n" +"PO-Revision-Date: 2007-10-16 05:41+0200\n" +"Last-Translator: Marián Kyral <[email protected]>\n" +"Language-Team: Česky <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +#: kdialogd.cpp:331 +msgid "Open" +msgstr "Otevřít" + +#: kdialogd.cpp:334 +msgid "Save As" +msgstr "Uložit jako" + +#: kdialogd.cpp:337 +msgid "Select Folder" +msgstr "Vyberte složku" + +#: kdialogd.cpp:627 +msgid "You can only select local files." +msgstr "Můžete vybrat pouze místní soubory." + +#: kdialogd.cpp:628 +msgid "Remote Files Not Accepted" +msgstr "Vzdálené soubory nejsou akceptovány." + +#: kdialogd.cpp:634 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" +"Soubor %1 existuje.\n" +"Chcete jej přepsat?" + +#: kdialogd.cpp:636 +msgid "File Exists" +msgstr "Soubor existuje." + +#: kdialogd.cpp:637 +msgid "Replace" +msgstr "Přepiš" + +#: kdialogd.cpp:712 +msgid "You can only select local folders." +msgstr "Můžete vybrat pouze místní složky." + +#: kdialogd.cpp:713 +msgid "Remote Folders Not Accepted" +msgstr "Vzdálené složky nejsou akceptovány." diff --git a/kdialogd4/po/de.po b/kdialogd4/po/de.po new file mode 100644 index 0000000..1d36f03 --- /dev/null +++ b/kdialogd4/po/de.po @@ -0,0 +1,62 @@ +# translation of kdialogd4.po to Deutsch +# This file is put in the public domain. +# +# Jannick Kuhr <[email protected]>, 2007. +msgid "" +msgstr "" +"Project-Id-Version: kdialogd4\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 15:08+0100\n" +"PO-Revision-Date: 2007-10-11 13:28+0200\n" +"Last-Translator: Jannick Kuhr <[email protected]>\n" +"Language-Team: Deutsch <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#:kdialogd.cpp:331 +msgid "Open" +msgstr "Öffnen" + +#:kdialogd.cpp:334 +msgid "Save As" +msgstr "Speichern unter" + +#:kdialogd.cpp:337 +msgid "Select Folder" +msgstr "Ordner wählen" + +#:kdialogd.cpp:627 +msgid "You can only select local files." +msgstr "Sie können nur lokale Dateien auswählen." + +#:kdialogd.cpp:628 +msgid "Remote Files Not Accepted" +msgstr "Dateien von Fremdrechnern werden nicht akzeptiert." + +#:kdialogd.cpp:634 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" +"Die Datei %1 exisitiert bereits.\n" +"Wollen Sie sie ersetzen?" + +#:kdialogd.cpp:636 +msgid "File Exists" +msgstr "Datei existiert bereits" + +#:kdialogd.cpp:637 +msgid "Replace" +msgstr "Ersetzen" + +#:kdialogd.cpp:712 +msgid "You can only select local folders." +msgstr "Sie können nur lokale Ordner auswählen." + +#:kdialogd.cpp:713 +msgid "Remote Folders Not Accepted" +msgstr "Ordner von Fremdrechnern werden nicht akzeptiert." + diff --git a/kdialogd4/po/en_GB.po b/kdialogd4/po/en_GB.po new file mode 100644 index 0000000..b811497 --- /dev/null +++ b/kdialogd4/po/en_GB.po @@ -0,0 +1,60 @@ +# translation of kdialogd4.po to British English +# Copyright (C) 2007 Craig Drummond <[email protected]> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: kdialogd4\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 14:40+0100\n" +"PO-Revision-Date: 2007-10-05 22:35+0200\n" +"Last-Translator: Craig Drummond <[email protected]>\n" +"Language-Team: Craig Drummond <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=iso-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: kdialogd.cpp:328 +msgid "Select Folder" +msgstr "Select Folder" + +#: kdialogd.cpp:573 +msgid "You can only select local files." +msgstr "You can only select local files." + +#: kdialogd.cpp:574 +msgid "Remote Files Not Accepted" +msgstr "Remote Files Not Accepted" + +#: kdialogd.cpp:580 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" +"File %1 exits.\n" +"Do you want to replace it?" + +#: kdialogd.cpp:582 +msgid "File Exists" +msgstr "File Exists" + +#: kdialogd.cpp:667 +msgid "You can only select local folders." +msgstr "You can only select local folders." + +#: kdialogd.cpp:668 +msgid "Remote Folders Not Accepted" +msgstr "Remote Folders Not Accepted" + +#: kdialogd.cpp:677 +msgid "KDialog Daemon" +msgstr "KDialog Daemon" + +#: kdialogd.cpp:678 +msgid "Use KDE dialogs from non-KDE apps." +msgstr "Use KDE dialogs from non-KDE apps." + +#: kdialogd.cpp:680 +msgid "(c) Craig Drummond, 2006-2007" +msgstr "(c) Craig Drummond, 2006-2007" diff --git a/kdialogd4/po/es.po b/kdialogd4/po/es.po new file mode 100644 index 0000000..5de4e58 --- /dev/null +++ b/kdialogd4/po/es.po @@ -0,0 +1,56 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 15:08+0100\n" +"PO-Revision-Date: 2007-10-19 18:06+0200\n" +"Last-Translator: Marco Antonio Blanco <[email protected]>\n" +"Language-Team: LANGUAGE <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Pootle 0.10.1\n" + +#: kdialogd.cpp:331 +msgid "Open" +msgstr "Abrir" + +#: kdialogd.cpp:334 +msgid "Save As" +msgstr "Guardar como" + +#: kdialogd.cpp:337 +msgid "Select Folder" +msgstr "Seleccione carpeta" + +#: kdialogd.cpp:627 +msgid "You can only select local files." +msgstr "Sólo se pueden seleccionar ficheros locales." + +#: kdialogd.cpp:628 +msgid "Remote Files Not Accepted" +msgstr "No se aceptan ficheros remotos" + +#: kdialogd.cpp:634 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" +"El fichero %1 existe.\n" +"¿Quiere sustituirlo?" + +#: kdialogd.cpp:636 +msgid "File Exists" +msgstr "El fichero existe" + +#: kdialogd.cpp:637 +msgid "Replace" +msgstr "Sustituir" + +#: kdialogd.cpp:712 +msgid "You can only select local folders." +msgstr "Sólo se pueden seleccionar carpetas locales." + +#: kdialogd.cpp:713 +msgid "Remote Folders Not Accepted" +msgstr "No se aceptan carpetas remotas" diff --git a/kdialogd4/po/fr.po b/kdialogd4/po/fr.po new file mode 100644 index 0000000..b0c500e --- /dev/null +++ b/kdialogd4/po/fr.po @@ -0,0 +1,60 @@ +# translation of kdialogd4.po to French +# Copyright (C) 2007 aul Thomas <[email protected]> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: kdialogd4\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 14:40+0100\n" +"PO-Revision-Date: 2007-10-06 17:54+0200\n" +"Last-Translator: Paul Thomas <[email protected]>\n" +"Language-Team: Paul Thomas <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: kdialogd.cpp:328 +msgid "Select Folder" +msgstr "Sélectionnez le dossier" + +#: kdialogd.cpp:573 +msgid "You can only select local files." +msgstr "Vous ne pouvez sélectionner que des fichiers locaux." + +#: kdialogd.cpp:574 +msgid "Remote Files Not Accepted" +msgstr "Les fichiers distants ne sont pas acceptés" + +#: kdialogd.cpp:580 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" +"Le fichier %1 exite déjà.\n" +"Voulez-vous le remplacer" + +#: kdialogd.cpp:582 +msgid "File Exists" +msgstr "Le Fichier existe déjà" + +#: kdialogd.cpp:667 +msgid "You can only select local folders." +msgstr "Vous ne pouvez sélectionner que des dossiers locaux." + +#: kdialogd.cpp:668 +msgid "Remote Folders Not Accepted" +msgstr "Les dossiers distants ne sont pas acceptés" + +#: kdialogd.cpp:677 +msgid "KDialog Daemon" +msgstr "KDialog Daemon" + +#: kdialogd.cpp:678 +msgid "Use KDE dialogs from non-KDE apps." +msgstr "Utilisez les dialogues KDE à partir d'applications non-KDE." + +#: kdialogd.cpp:680 +msgid "(c) Craig Drummond, 2006-2007" +msgstr "(c) Craig Drummond, 2006-2007" diff --git a/kdialogd4/po/kdialogd4.pot b/kdialogd4/po/kdialogd4.pot new file mode 100644 index 0000000..abc8249 --- /dev/null +++ b/kdialogd4/po/kdialogd4.pot @@ -0,0 +1,58 @@ +# SOME DESCRIPTIVE TITLE. +# This file is put in the public domain. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 15:08+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: kdialogd.cpp:331 +msgid "Open" +msgstr "" + +#: kdialogd.cpp:334 +msgid "Save As" +msgstr "" + +#: kdialogd.cpp:337 +msgid "Select Folder" +msgstr "" + +#: kdialogd.cpp:627 +msgid "You can only select local files." +msgstr "" + +#: kdialogd.cpp:628 +msgid "Remote Files Not Accepted" +msgstr "" + +#: kdialogd.cpp:634 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" + +#: kdialogd.cpp:636 +msgid "File Exists" +msgstr "" + +#: kdialogd.cpp:637 +msgid "Replace" +msgstr "" + +#: kdialogd.cpp:712 +msgid "You can only select local folders." +msgstr "" + +#: kdialogd.cpp:713 +msgid "Remote Folders Not Accepted" +msgstr "" diff --git a/kdialogd4/po/pt_BR.po b/kdialogd4/po/pt_BR.po new file mode 100644 index 0000000..79a5463 --- /dev/null +++ b/kdialogd4/po/pt_BR.po @@ -0,0 +1,60 @@ +# translation of kdialogd4.po to Brazillian Portuguese +# This file is put in the public domain. +# +# Márcio Moraes <[email protected]>, 2007. +msgid "" +msgstr "" +"Project-Id-Version: kdialogd4\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 15:08+0100\n" +"PO-Revision-Date: 2008-02-26 11:47-0300\n" +"Last-Translator: Márcio Moraes <[email protected]>\n" +"Language-Team: Márcio Moraes <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=iso-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: kdialogd.cpp:331 +msgid "Open" +msgstr "Abrir" + +#: kdialogd.cpp:334 +msgid "Save As" +msgstr "Salvar Como" + +#: kdialogd.cpp:337 +msgid "Select Folder" +msgstr "Selecionar Pasta" + +#: kdialogd.cpp:627 +msgid "You can only select local files." +msgstr "Selecione apenas arquivos locais." + +#: kdialogd.cpp:628 +msgid "Remote Files Not Accepted" +msgstr "Arquivos remotos não são aceitos" + +#: kdialogd.cpp:634 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" +"Arquivo %1 exite.\n" +"Você realmente deseja sobrescrever?" + +#: kdialogd.cpp:636 +msgid "File Exists" +msgstr "Arquivo Existe" + +#: kdialogd.cpp:637 +msgid "Replace" +msgstr "Sobrescrever" + +#: kdialogd.cpp:712 +msgid "You can only select local folders." +msgstr "Selecione apenas pastas locais." + +#: kdialogd.cpp:713 +msgid "Remote Folders Not Accepted" +msgstr "Pastas remotas não são aceitas" diff --git a/kdialogd4/po/ru.po b/kdialogd4/po/ru.po new file mode 100644 index 0000000..cf2abd0 --- /dev/null +++ b/kdialogd4/po/ru.po @@ -0,0 +1,62 @@ +# translation of ru.po to +# This file is put in the public domain. +# +# Yarodin <[email protected]>, 2008. +msgid "" +msgstr "" +"Project-Id-Version: kdialogd3\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 14:40+0100\n" +"PO-Revision-Date: 2008-05-01 19:31+0600\n" +"Last-Translator: Yarodin <[email protected]>\n" +"Language-Team: Russian <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: kdialogd.cpp:328 +msgid "Select Folder" +msgstr "Выбор папки" + +#: kdialogd.cpp:573 +msgid "You can only select local files." +msgstr "Вы можете выбрать только локальные файлы." + +#: kdialogd.cpp:574 +msgid "Remote Files Not Accepted" +msgstr "Файлы на удаленной машине недоступны" + +#: kdialogd.cpp:580 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" +"Файл %1 уже существует.\n" +"Хотите его перезаписать?" + +#: kdialogd.cpp:582 +msgid "File Exists" +msgstr "Файл существует" + +#: kdialogd.cpp:667 +msgid "You can only select local folders." +msgstr "Вы можете выбрать только локальные папки." + +#: kdialogd.cpp:668 +msgid "Remote Folders Not Accepted" +msgstr "Сетевые папки недоступны." + +#: kdialogd.cpp:677 +msgid "KDialog Daemon" +msgstr "KDialog-Демон" + +#: kdialogd.cpp:678 +msgid "Use KDE dialogs from non-KDE apps." +msgstr "Использование KDE диалогов в Не-KDE приложениях." + +#: kdialogd.cpp:680 +msgid "(c) Craig Drummond, 2006-2007" +msgstr "(c) Craig Drummond, 2006-2007" + diff --git a/kdialogd4/po/zh_CN.po b/kdialogd4/po/zh_CN.po new file mode 100644 index 0000000..93d83f7 --- /dev/null +++ b/kdialogd4/po/zh_CN.po @@ -0,0 +1,60 @@ +# translation of kdialogd4.po to Chinese Simplified +# Copyright (C) 2007 Free Software Foundation, Inc. +# +# Liang Qi <[email protected]>, 2007. +msgid "" +msgstr "" +"Project-Id-Version: kdialogd4\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-21 14:40+0100\n" +"PO-Revision-Date: 2007-10-05 13:20+0200\n" +"Last-Translator: Liang Qi <[email protected]>\n" +"Language-Team: zh_CN <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: kdialogd.cpp:328 +msgid "Select Folder" +msgstr "选择文件夹" + +#: kdialogd.cpp:573 +msgid "You can only select local files." +msgstr "仅允许选择本地文件。" + +#: kdialogd.cpp:574 +msgid "Remote Files Not Accepted" +msgstr "无法接受远程文件" + +#: kdialogd.cpp:580 +msgid "" +"File %1 exits.\n" +"Do you want to replace it?" +msgstr "" +"文件 %1 已经存在。\n" +"您想替换它么?" + +#: kdialogd.cpp:582 +msgid "File Exists" +msgstr "文件已存在" + +#: kdialogd.cpp:667 +msgid "You can only select local folders." +msgstr "仅允许选择本地文件夹。" + +#: kdialogd.cpp:668 +msgid "Remote Folders Not Accepted" +msgstr "无法接受远程文件夹" + +#: kdialogd.cpp:677 +msgid "KDialog Daemon" +msgstr "KDialog 守护进程" + +#: kdialogd.cpp:678 +msgid "Use KDE dialogs from non-KDE apps." +msgstr "在非 KDE 程序中使用 KDE 对话框。" + +#: kdialogd.cpp:680 +msgid "(c) Craig Drummond, 2006-2007" +msgstr "(c) Craig Drummond, 2006-2007" diff --git a/kgtk-wrapper b/kgtk-wrapper new file mode 100755 index 0000000..a46c646 --- /dev/null +++ b/kgtk-wrapper @@ -0,0 +1,103 @@ +#!/bin/bash + +# +# This script is part of the KGtk package. +# +# (C) Craig Drummond, 2007 +# +# +# -- +# Released under the GPL v2 or later +# -- +# +# This script attempts to determine which KGtk library (if any) should +# be used when launching the app +# + +if [ "`locale | grep 'LANG=' | grep -i 'utf-8' | wc -l`" = "0" ] ; then + export G_BROKEN_FILENAMES=1 +fi + +app=`basename $0` +useApp=1 + +if [ "$app" = "kgtk-wrapper" ] ; then + app=`basename $1` + useApp=0 +fi + +dir=$(cd "$(dirname "$0")"; pwd) +if [ $useApp -eq 1 ] ; then + oldPath=$PATH + PATH=`echo $PATH | sed s:$dir::g | sed "s|::*|:|g"` +fi + +realApp=`which $app` + +if [ -z $realApp ] ; then + realApp=`which ./$app` +fi + +if [ $useApp -eq 1 ] ; then + PATH=$oldPath +fi + +toolkit=`kreadconfig --file kgtkrc --group 'Apps' --key "$app"` + +if [ "$toolkit" = "" ] ; then + case $app in + eclipse | gimp | inkscape | firefox | kino | iceweasel | swiftfox | azureus | mozilla* ) + toolkit="gtk2" ;; + scribus | scribus-ng | opera | designer-qt3 ) + toolkit="qt3" ;; + designer-qt4 ) + toolkit="qt4" ;; + abiword) # Non-working + toolkit="x" ;; + esac +fi + +if [ "$toolkit" = "" ] && [ ! -z "$realApp" ] ; then + libs=`ldd $realApp 2>/dev/null` + + if [ ! -z "$libs" ] ; then + + if [ "0" != "`echo $libs | grep libgtk-x11-2 | wc -l`" ] ; then + toolkit="gtk2" + elif [ "0" != "`echo $libs | grep libqt-mt | wc -l`" ] ; then + toolkit="qt3" + elif [ "0" != "`echo $libs | grep libQtGui | wc -l`" ] ; then + toolkit="qt4" + fi + + if [ "$toolkit" = "qt3" ] || [ "$toolkit" = "qt4" ] ; then + if [ "0" != "`echo $libs | grep libkio | wc -l`" ] ; then + toolkit="" + fi + fi + + if [ -z "`which k$toolkit-wrapper`" ] ; then + toolkit="" + fi + fi +fi + +if [ "$toolkit" = "x" ] ; then + toolkit="" +fi + +if [ $useApp -eq 1 ] ; then + if [ "$toolkit" = "" ] ; then + $realApp "$@" + else + k$toolkit-wrapper $realApp "$@" + fi +else + if [ "$toolkit" = "" ] ; then + "$@" + else + k$toolkit-wrapper "$@" + fi +fi + diff --git a/mangled.sh b/mangled.sh new file mode 100755 index 0000000..01566ad --- /dev/null +++ b/mangled.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# $1 == C++ compiler +# $2 == output name + +echo "class QApplication { public: int exec(); }; int QApplication::exec() { return 0; } " \ + "class QDialog { public: int exec(); }; int QDialog::exec() { return 0; }" >> "$2.cpp" + +$1 -c "$2.cpp" -o "$2.o" +qdialog=`nm "$2.o" | grep QDialog | grep exec | awk '{print $3}'` +qapplication=`nm "$2.o" | grep QApplication | grep exec | awk '{print $3}'` +rm "$2.o" "$2.cpp" + +echo "#ifndef __KGTK_MANGLED_H__" > "$2" +echo "#define __KGTK_MANGLED_H__" >> "$2" +echo "#define KQT_QDIALOG_EXEC \"$qdialog\"" >> "$2" +echo "#define KQT_QAPPLICATION_EXEC \"$qapplication\"" >> "$2" +echo "#endif" >> "$2" + + + + + diff --git a/qt3/CMakeLists.txt b/qt3/CMakeLists.txt new file mode 100644 index 0000000..b35b6b7 --- /dev/null +++ b/qt3/CMakeLists.txt @@ -0,0 +1,24 @@ +set(QT_MT_REQUIRED TRUE) +find_package(Qt3) + +if (QT_INCLUDE_DIR) + message("** INFORMATION: Qt3 LD_PRELOAD library will be built.") + + # set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) + set(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})" FORCE) + + ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mangled.h + COMMAND ${CMAKE_SOURCE_DIR}/mangled.sh ${CMAKE_CXX_COMPILER} ${CMAKE_CURRENT_BINARY_DIR}/mangled.h) + + include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/common ${CMAKE_BINARY_DIR} ${QT_INCLUDE_DIR}) + set(kqt3_SRCS kqt3.cpp mangled.h) + add_definitions(${QT_DEFINITIONS} -DQT_CLEAN_NAMESPACE -DQT_THREAD_SUPPORT) + add_library(kqt3 SHARED ${kqt3_SRCS}) + target_link_libraries(kqt3 ${QT_LIBRARIES} -lc -ldl) + install(TARGETS kqt3 LIBRARY DESTINATION ${LIB_INSTALL_DIR}/kgtk) + + configure_file (kqt3-wrapper.cmake ${CMAKE_CURRENT_BINARY_DIR}/kqt3-wrapper @ONLY) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/kqt3-wrapper DESTINATION bin) +else (QT_INCLUDE_DIR) + message("** ERROR : Could not locate Qt3 headers, Qt3 LD_PRELOAD library will not be built.") +endif (QT_INCLUDE_DIR) diff --git a/qt3/kqt3-wrapper.cmake b/qt3/kqt3-wrapper.cmake new file mode 100755 index 0000000..e8ba648 --- /dev/null +++ b/qt3/kqt3-wrapper.cmake @@ -0,0 +1,29 @@ +#!/bin/bash + +# +# This script is part of the KGtk package. +# +# (C) Craig Drummond, 2007 +# +# +# -- +# Released under the GPL v2 or later +# -- +# + +app=`basename $0` + +if [ "$app" = "kqt3-wrapper" ] ; then + LD_PRELOAD=@CMAKE_INSTALL_PREFIX@/lib/kgtk/libkqt3.so:$LD_PRELOAD "$@" +else + dir=`dirname $0` + oldPath=$PATH + PATH=`echo $PATH | sed s:$dir::g` + real=`which $app` + PATH=$oldPath + + if [ "$real" != "" ] && [ "`dirname $real`" != "$dir" ] ; then + LD_PRELOAD=@CMAKE_INSTALL_PREFIX@/lib@LIB_SUFFIX@/kgtk/libkqt3.so:$LD_PRELOAD $real "$@" + fi +fi diff --git a/qt3/kqt3.cpp b/qt3/kqt3.cpp new file mode 100644 index 0000000..833b01d --- /dev/null +++ b/qt3/kqt3.cpp @@ -0,0 +1,671 @@ +/************************************************************************ + * + * All dialogs opened are created and used modal. + * + ************************************************************************ + * (C) Craig Drummond, 2006 + ************************************************************************ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + ************************************************************************/ + +#define KQT_OVERLOAD_NON_STATIC_FILEDIALOGS + +#define _GNU_SOURCE +#include <dlfcn.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <signal.h> +#include <sys/wait.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <pwd.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qwidget.h> +#include <qapplication.h> +#ifdef KQT_OVERLOAD_NON_STATIC_FILEDIALOGS +#include <qcombobox.h> +#include <qlineedit.h> +#include <qobjectlist.h> +#define private public // HACK HACK HACK!!! +#endif +#include <qfiledialog.h> +#include <qthread.h> +#include <qnamespace.h> +#include <qeventloop.h> +#include "connect.h" +#include "config.h" +#include "mangled.h" + +static bool useKde=false; + +#define MAX_LINE_LEN 1024 +#define MAX_APP_NAME_LEN 32 + +static char * getAppNameFromPid(int pid) +{ + static char appName[MAX_APP_NAME_LEN+1]="\0"; + + int procFile=-1; + char cmdline[MAX_LINE_LEN+1]; + + sprintf(cmdline, "/proc/%d/cmdline",pid); + + if(-1!=(procFile=open(cmdline, O_RDONLY))) + { + if(read(procFile, cmdline, MAX_LINE_LEN)>7) + { + int len=strlen(cmdline), + pos=0; + + for(pos=len-1; pos>0 && cmdline[pos] && cmdline[pos]!='/'; --pos) + ; + + if(pos>=0 && pos<len) + { + strncpy(appName, &cmdline[pos ? pos+1 : 0], MAX_APP_NAME_LEN); + appName[MAX_APP_NAME_LEN]='\0'; + } + } + close(procFile); + } + + return appName; +} + +static const char * getAppName(bool useQt=true) +{ + static const char *appName=NULL; + + if(!appName) + { + const char *a=useQt && qApp ? qApp->argv()[0] : getAppNameFromPid(getpid()); + const char *slash; + + // Was the cmdline app java? if so, try to use its parent name - just in case + // its run from a shell script, etc. - e.g. as eclipse does + if(a && 0==strcmp(a, "java")) + a=getAppNameFromPid(getppid()); + + if(a && a[0]=='\0') + a=NULL; + + appName=a && (slash=strrchr(a, '/')) && '\0'!=slash[1] + ? &(slash[1]) + : a ? a : "QtApp"; + } + + return appName; +} + +int QApplication::exec() +{ + static bool init=false; + + if(!init) + { + connectToKDialogD(getAppName(false)); + init=true; + } + + static int (*realFunction)(void *); + + if(!realFunction) + realFunction = (int (*)(void *)) dlsym(RTLD_NEXT, KQT_QAPPLICATION_EXEC); + return (int)realFunction(this); +}; + +static QString qt2KdeFilter(const QString &f) +{ + QString filter; + QTextOStream str(&filter); + QStringList list(QStringList::split(";;", f)); + QStringList::Iterator it(list.begin()), + end(list.end()); + bool first=true; + + for(; it!=end; ++it) + { + int ob=(*it).findRev('('), + cb=(*it).findRev(')'); + + if(-1!=cb && ob<cb) + { + if(first) + first=false; + else + str << '\n'; + str << (*it).mid(ob+1, (cb-ob)-1) << '|' << (*it).mid(0, ob); + } + } + + return filter; +} + +static void kde2QtFilter(const QString &orig, QString *sel) +{ + if(sel) + { + QStringList list(QStringList::split(";;", orig)); + QStringList::Iterator it(list.begin()), + end(list.end()); + int pos; + + for(; it!=end; ++it) + if(-1!=(pos=(*it).find(*sel)) && pos>0 && + ('('==(*it)[pos-1] || ' '==(*it)[pos-1]) && + (*it).length()>=sel->length()+pos && + (')'==(*it)[pos+sel->length()] || ' '==(*it)[pos+sel->length()])) + { + *sel=*it; + return; + } + } +} + +#ifdef KQT_OVERLOAD_NON_STATIC_FILEDIALOGS +#ifdef KQT_USE_QFILEDIALOG_PRIVATE +// HACK HACK HACK!!! + +// KGtk versions <=0.9.1 used this copied QFileDialogPrivate to access the file filters +// newer versions walk the file dialogs children... +class QFileDialogPrivate { +public: + ~QFileDialogPrivate(); + + QStringList history; + + bool geometryDirty; + QComboBox * paths; + QComboBox * types; +}; +#endif + +static const QString getFilters(QFileDialog *dlg, bool scribusSave=false) +{ + QString filter; + +#if KQT_USE_QFILEDIALOG_PRIVATE + if(dlg && dlg->d && dlg->d->types) + { + QTextOStream str(&filter); + + for(int i=0; i<dlg->d->types->count(); ++i) + { + if(i) + str << ";;"; + + if(scribusSave && -1!=dlg->d->types->text(i).find("(*.sla *.sla.gz *.scd *scd.gz)")) + str << "Compressed Documents (*.sla.gz *scd.gz);;Documents (*.sla *.scd)"; + else + str << dlg->d->types->text(i); + } + } +#else + if(dlg) + { + const QObjectList *children=((QObject *)dlg)->children(); + + if(children) + { + QObjectList::ConstIterator it(children->begin()), + end(children->end()); + + for(; it!=end; ++it) + if(::qt_cast<QComboBox *>(*it) && 0==qstrcmp((*it)->name(), "file types")) + { + QComboBox *types=(QComboBox *)(*it); + QTextOStream str(&filter); + + for(int i=0; i<types->count(); ++i) + { + if(i) + str << ";;"; + + if(scribusSave && -1!=types->text(i).find("(*.sla *.sla.gz *.scd *scd.gz)")) + str << "Compressed Documents (*.sla.gz *scd.gz);;Documents (*.sla *.scd)"; + else + str << types->text(i); + } + + break; + } + } + } +#endif + + return filter; +} + +static QString getCurrentFileName(QFileDialog *dlg) +{ + if(dlg) + { + const QObjectList *children=((QObject *)dlg)->children(); + + if(children) + { + QObjectList::ConstIterator it(children->begin()), + end(children->end()); + + for(; it!=end; ++it) + if(::qt_cast<QLineEdit *>(*it)) // && 0==qstrcmp((*it)->name(), "name/filter editor")) + return ((QLineEdit *)(*it))->text(); + } + } + + return QString(); +} + +static QString getDir(const QString &f) +{ + QString d(f); + + int slashPos=d.findRev('/'); + + if(slashPos!=-1) + d.remove(slashPos+1, d.length()); + + return d; +} +#endif + +static bool writeString(int fd, const QString &str) +{ + QCString utf8(str.utf8()); + int size=utf8.length()+1; + + return writeBlock(fd, (char *)&size, 4) && writeBlock(fd, utf8.data(), size); +} + +static bool writeBool(int fd, bool b) +{ + char bv=b ? 1 : 0; + + return writeBlock(fd, (char *)&bv, 1); +} + +class KQtDialog : public QDialog +{ + public: + + KQtDialog(QWidget *parent) : QDialog(parent, "kqt", true, WStyle_NoBorder|WX11BypassWM) + { + resize(1, 1); + setWindowOpacity(0.0); + setWindowState(WState_Minimized); + move(32768, 32768); + } + +/* void r() { QDialog::reject(); }*/ +}; + +class KQtThread : public QThread +{ + public: + + KQtThread(QStringList &l, QString &s, int f, KQtDialog *dlg) : dialog(dlg), kdialogdError(false), res(l), selFilter(s), fd(f) + { } + + bool readData(QCString &buffer, int size) + { + buffer.resize(size); + return ::readBlock(fd, buffer.data(), size); + } + + bool readString(QString &str, int size) + { + QCString buffer; + buffer.resize(size); + + if(!readBlock(fd, buffer.data(), size)) + return false; + + str=QString::fromUtf8(buffer.data()); + return true; + } + + void run() + { + QString buffer; + int num=0; + + if(readBlock(fd, (char *)&num, 4)) + { + int n; + + for(n=0; n<num && !kdialogdError; ++n) + { + int size=0; + + if(readBlock(fd, (char *)&size, 4)) + { + if(size>0) + { + if(readString(buffer, size)) + { + //buffer[size-1]='\0'; + if('/'==buffer[0]) + res.append(buffer); + else + selFilter=buffer; + } + else + kdialogdError=true; + } + } + else + kdialogdError=true; + } + } + else + kdialogdError=true; + + QApplication::postEvent(dialog, new QCloseEvent); + } + + KQtDialog *dialog; + bool kdialogdError; + QStringList &res; + QString &selFilter; + int fd; +}; + +static bool sendMessage(QWidget *parent, Operation op, QStringList &res, QString &selFilter, + const QString &title, const QString &p1, const QString *p2, bool ow) +{ + if(connectToKDialogD(getAppName())) + { + char o=(char)op; + int xid=parent ? parent->topLevelWidget()->winId() : qApp->activeWindow()->winId(); + + if(writeBlock(kdialogdSocket, &o, 1) && + writeBlock(kdialogdSocket, (char *)&xid, 4) && + writeString(kdialogdSocket, title) && + writeString(kdialogdSocket, p1) && + (p2? writeString(kdialogdSocket, *p2) : true) && + (OP_FILE_SAVE==op ? writeBool(kdialogdSocket, ow) : true)) + { + KQtDialog dlg(parent); + KQtThread thread(res, selFilter, kdialogdSocket, &dlg); + + thread.start(); + dlg.exec(); + thread.wait(); + if(thread.kdialogdError) + { + closeConnection(); + return false; + } + return true; + } + } + + return false; +} + +static QString getTitle(const QString &title, Operation op) +{ + if(!title.isEmpty()) + return title; + + return "."; +} + +static bool openKdeDialog(QWidget *widget, const QString &title, const QString &p1, const QString *p2, + Operation op, QStringList &res, QString *selFilter, bool ow=false) +{ + QString filter; + bool rv=sendMessage(widget, op, res, filter, getTitle(title, op), p1, p2, ow); + + // If we failed to talk to, or start kdialogd, then dont keep trying - just fall back to Qt + if(!rv) + /*useKde=false*/; + else if(selFilter) + *selFilter=filter; + + return rv; +} + +static void kqtExit() +{ + if(useKde) + closeConnection(); +} + +static bool kqtInit() +{ + static bool initialised=false; + + if(!initialised) + { + initialised=true; + useKde=NULL!=getenv("KDE_FULL_SESSION") && connectToKDialogD(getAppName()); + if(useKde) + atexit(&kqtExit); + } + + return useKde; +} + +static QString lastDir; + +static void storeLastDir(const QString &f) +{ + lastDir=f; + + int slashPos(lastDir.findRev('/')); + + if(slashPos!=-1) + lastDir.remove(slashPos+1, lastDir.length()); +} + +static const QString & startDir(const QString &d) +{ + return d.isEmpty() ? lastDir : d; +} + +QString QFileDialog::getOpenFileName(const QString &initially, const QString &filter, + QWidget *parent, const char *name, const QString &caption, + QString *selectedFilter, bool resolveSymlinks) +{ + QStringList res; + QString f(qt2KdeFilter(filter)); + kqtInit(); + + if(openKdeDialog(parent, caption, startDir(initially), &f, OP_FILE_OPEN, res, selectedFilter)) + { + kde2QtFilter(filter, selectedFilter); + QString fn(res.first()); + + storeLastDir(fn); + return fn; + } + return QString::null; +} + +QString QFileDialog::getSaveFileName(const QString &initially, const QString &filter, QWidget *parent, + const char *name, const QString &caption, + QString *selectedFilter, bool resolveSymlinks) +{ + QStringList res; + QString f(qt2KdeFilter(filter)); + kqtInit(); + + if (openKdeDialog(parent, caption, startDir(initially), &f, OP_FILE_SAVE, res, selectedFilter)) + { + kde2QtFilter(filter, selectedFilter); + QString fn(res.first()); + + storeLastDir(fn); + return fn; + } + return QString::null; +} + +QString QFileDialog::getExistingDirectory(const QString &dir, QWidget *parent, const char *name, + const QString &caption, bool dirOnly, bool resolveSymlinks) +{ + QStringList res; + QString dummy; + + kqtInit(); + + return openKdeDialog(parent, caption, dir, NULL, OP_FOLDER, res, &dummy) + ? res.first() + : QString::null; +} + +QStringList QFileDialog::getOpenFileNames(const QString &filter, const QString &dir, QWidget *parent, + const char *name, const QString &caption, + QString *selectedFilter, bool resolveSymlinks) +{ + QStringList res; + QString f(qt2KdeFilter(filter)); + kqtInit(); + + openKdeDialog(parent, caption, startDir(dir), &f, OP_FILE_OPEN_MULTIPLE, res, selectedFilter); + + if(res.count()) + { + kde2QtFilter(filter, selectedFilter); + storeLastDir(res.first()); + } + return res; +} + +#ifdef KQT_OVERLOAD_NON_STATIC_FILEDIALOGS +static QString getFile(const QString &f) +{ + QString d(f); + + int slashPos=d.findRev('/'); + + if(slashPos!=-1) + d.remove(0, slashPos+1); + + return d; +} + +int QDialog::exec() +{ + int res=QDialog::Rejected; + + if(inherits("QFileDialog")) + { + QFileDialog *that=(QFileDialog *)this; + + const QDir *dirp=that->dir(); + QString dir, + selectedFilter, + file, + initialDir(dirp ? dirp->absPath() : QDir::homeDirPath()); + QStringList files; + + if(dirp) + delete dirp; + + QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput, 1); + switch(that->mode()) + { + case QFileDialog::Directory: + case QFileDialog::DirectoryOnly: + dir=QFileDialog::getExistingDirectory(initialDir, parentWidget(), NULL, + caption(), true, true); + + if(!dir.isEmpty()) + res=QDialog::Accepted; + break; + case QFileDialog::AnyFile: + { + QString app(getFile(qApp->argv()[0])), + initialFile(getCurrentFileName(that)); + + if(!initialFile.isEmpty()) + initialDir=initialDir+QChar('/')+initialFile; + + file=QFileDialog::getSaveFileName(initialDir, + getFilters(that, "scribus"==app || + "scribus-ng"==app), + parentWidget(), NULL, caption(), &selectedFilter, + true); + + if(!file.isEmpty()) + res=QDialog::Accepted; + break; + } + case QFileDialog::ExistingFile: + file=QFileDialog::getOpenFileName(initialDir, getFilters(that), parentWidget(), + NULL, caption(), &selectedFilter, true); + + if(!file.isEmpty()) + res=QDialog::Accepted; + break; + case QFileDialog::ExistingFiles: + files=QFileDialog::getOpenFileNames(getFilters(that), initialDir, parentWidget(), + NULL, caption(), &selectedFilter, true); + + if(files.count()) + res=QDialog::Accepted; + break; + } + + if(QDialog::Accepted==res) + { + if(file.isEmpty() && files.count()) + file=files.first(); + if(dir.isEmpty() && !file.isEmpty()) + dir=getDir(file); + if(!dir.isEmpty()) + that->setDir(dir); + if(!selectedFilter.isEmpty()) + that->setSelectedFilter(selectedFilter); + if(!file.isEmpty()) + that->setSelection(file); + + if(files.count() && that->nameEdit) + { + QStringList::Iterator it(files.begin()), + end(files.end()); + QString filesStr; + QTextOStream str(&filesStr); + + for(; it!=end; ++it) + str << "\"" << (*it) << "\" "; + that->nameEdit->setText(filesStr); + } + QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput, 1); + } + } + else + { + static int (*realFunction)(void *); + + if(!realFunction) + realFunction = (int (*)(void *)) dlsym(RTLD_NEXT, KQT_QDIALOG_EXEC); + return (int)realFunction(this); + } + + return res; +} +#endif diff --git a/qt4/CMakeLists.txt b/qt4/CMakeLists.txt new file mode 100644 index 0000000..3f8dadb --- /dev/null +++ b/qt4/CMakeLists.txt @@ -0,0 +1,22 @@ +find_package(Qt4) + +if (QT4_FOUND) + message("** INFORMATION: Qt4 LD_PRELOAD library will be built.") + # set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) + set(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})" FORCE) + + ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mangled.h + COMMAND ${CMAKE_SOURCE_DIR}/mangled.sh ${CMAKE_CXX_COMPILER} ${CMAKE_CURRENT_BINARY_DIR}/mangled.h) + + include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/common ${CMAKE_BINARY_DIR} ${QT_INCLUDE_DIR}) + set(kqt4_SRCS kqt4.cpp mangled.h) + add_definitions(${QT_DEFINITIONS} -DQT_CLEAN_NAMESPACE -DQT_THREAD_SUPPORT) + add_library(kqt4 SHARED ${kqt4_SRCS}) + target_link_libraries(kqt4 ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY} -lc -ldl) + install(TARGETS kqt4 LIBRARY DESTINATION ${LIB_INSTALL_DIR}/kgtk) + + configure_file (kqt4-wrapper.cmake ${CMAKE_CURRENT_BINARY_DIR}/kqt4-wrapper @ONLY) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/kqt4-wrapper DESTINATION bin) +else (QT4_FOUND) + message("** ERROR : Could not locate Qt4 headers, Qt4 LD_PRELOAD library will not be built.") +endif (QT4_FOUND) diff --git a/qt4/kqt4-wrapper.cmake b/qt4/kqt4-wrapper.cmake new file mode 100755 index 0000000..84205b6 --- /dev/null +++ b/qt4/kqt4-wrapper.cmake @@ -0,0 +1,29 @@ +#!/bin/bash + +# +# This script is part of the KGtk package. +# +# (C) Craig Drummond, 2007 +# +# +# -- +# Released under the GPL v2 or later +# -- +# + +app=`basename $0` + +if [ "$app" = "kqt4-wrapper" ] ; then + LD_PRELOAD=@CMAKE_INSTALL_PREFIX@/lib/kgtk/libkqt4.so:$LD_PRELOAD "$@" +else + dir=`dirname $0` + oldPath=$PATH + PATH=`echo $PATH | sed s:$dir::g` + real=`which $app` + PATH=$oldPath + + if [ "$real" != "" ] && [ "`dirname $real`" != "$dir" ] ; then + LD_PRELOAD=@CMAKE_INSTALL_PREFIX@/lib@LIB_SUFFIX@/kgtk/libkqt4.so:$LD_PRELOAD $real "$@" + fi +fi diff --git a/qt4/kqt4.cpp b/qt4/kqt4.cpp new file mode 100644 index 0000000..4d09f80 --- /dev/null +++ b/qt4/kqt4.cpp @@ -0,0 +1,599 @@ +/************************************************************************ + * + * All dialogs opened are created and used modal. + * + ************************************************************************ + * (C) Craig Drummond, 2006 + ************************************************************************ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + ************************************************************************/ + +#define KQT_OVERLOAD_NON_STATIC_FILEDIALOGS + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include <dlfcn.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <signal.h> +#include <sys/wait.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <pwd.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtGui/QWidget> +#include <QtGui/QApplication> +#include <QtCore/QTextStream> +#include <QtGui/QCloseEvent> +#include <QtGui/QFileDialog> +#include <QtCore/QThread> +#include <QtCore/Qt> +#include <QtCore/QEventLoop> +#include "connect.h" +#include "config.h" +#include "mangled.h" + +static bool useKde=false; + +#define MAX_LINE_LEN 1024 +#define MAX_APP_NAME_LEN 32 + +static char * getAppNameFromPid(int pid) +{ + static char appName[MAX_APP_NAME_LEN+1]="\0"; + + int procFile=-1; + char cmdline[MAX_LINE_LEN+1]; + + sprintf(cmdline, "/proc/%d/cmdline",pid); + + if(-1!=(procFile=open(cmdline, O_RDONLY))) + { + if(read(procFile, cmdline, MAX_LINE_LEN)>7) + { + int len=strlen(cmdline), + pos=0; + + for(pos=len-1; pos>0 && cmdline[pos] && cmdline[pos]!='/'; --pos) + ; + + if(pos>=0 && pos<len) + { + strncpy(appName, &cmdline[pos ? pos+1 : 0], MAX_APP_NAME_LEN); + appName[MAX_APP_NAME_LEN]='\0'; + } + } + close(procFile); + } + + return appName; +} + +static const char * getAppName(bool useQt=true) +{ + static const char *appName=NULL; + + if(!appName) + { + const char *a=useQt && QCoreApplication::arguments().count() + ? QCoreApplication::arguments()[0].toLatin1().constData() : getAppNameFromPid(getpid()); + char *slash; + + // Was the cmdline app java? if so, try to use its parent name - just in case + // its run from a shell script, etc. - e.g. as eclipse does + if(a && 0==strcmp(a, "java")) + a=getAppNameFromPid(getppid()); + + if(a && a[0]=='\0') + a=NULL; + + appName=a && (slash=strrchr(a, '/')) && '\0'!=slash[1] + ? &(slash[1]) + : a ? a : "Qt4App"; + } + + return appName; +} + +int QApplication::exec() +{ + static bool init=false; + + if(!init) + { + connectToKDialogD(getAppName(false)); + init=true; + } + + static int (*realFunction)(void); + + if(!realFunction) + realFunction = (int (*)(void)) dlsym(RTLD_NEXT, KQT_QAPPLICATION_EXEC); + return (int)realFunction(); +}; + +static QString qt2KdeFilter(const QString &f) +{ + QString filter; + QTextStream str(&filter, QIODevice::WriteOnly); + QStringList list(f.split(";;")); + QStringList::Iterator it(list.begin()), + end(list.end()); + bool first=true; + + for(; it!=end; ++it) + { + int ob=(*it).lastIndexOf('('), + cb=(*it).lastIndexOf(')'); + + if(-1!=cb && ob<cb) + { + if(first) + first=false; + else + str << '\n'; + str << (*it).mid(ob+1, (cb-ob)-1) << '|' << (*it).mid(0, ob); + } + } + + return filter; +} + +static void kde2QtFilter(const QString &orig, QString *sel) +{ + if(sel) + { + QStringList list(orig.split(";;")); + QStringList::Iterator it(list.begin()), + end(list.end()); + int pos; + + for(; it!=end; ++it) + if(-1!=(pos=(*it).indexOf(*sel)) && pos>0 && + ('('==(*it)[pos-1] || ' '==(*it)[pos-1]) && + (*it).length()>=sel->length()+pos && + (')'==(*it)[pos+sel->length()] || ' '==(*it)[pos+sel->length()])) + { + *sel=*it; + return; + } + } +} + +#ifdef KQT_OVERLOAD_NON_STATIC_FILEDIALOGS +static const QString getFilters(QFileDialog *dlg, bool scribusSave=false) +{ + QString filter; + + if(dlg) + { + QStringList filters(dlg->filters()); + QStringList::ConstIterator it(filters.begin()), + end(filters.end()); + bool first(true); + QTextStream str(&filter, QIODevice::WriteOnly); + + for(; it!=end; ++it) + { + if(!first) + str << ";;"; + + if(scribusSave && -1!=(*it).indexOf("(*.sla *.sla.gz *.scd *scd.gz)")) + str << "Compressed Documents (*.sla.gz *scd.gz);;Documents (*.sla *.scd)"; + else + str << (*it); + first=false; + } + } + + return filter; +} + +static QString getDir(const QString &f) +{ + QString d(f); + + int slashPos=d.lastIndexOf('/'); + + if(slashPos!=-1) + d.remove(slashPos+1, d.length()); + + return d; +} +#endif + +static bool writeString(int fd, const QString &str) +{ + QByteArray utf8(str.toUtf8()); + int size=utf8.length()+1; + + return writeBlock(fd, (char *)&size, 4) && writeBlock(fd, utf8.data(), size); +} + +static bool writeBool(int fd, bool b) +{ + char bv=b ? 1 : 0; + + return writeBlock(fd, (char *)&bv, 1); +} + +class KQtDialog : public QDialog +{ + public: + + KQtDialog(QWidget *parent) : QDialog(parent, Qt::FramelessWindowHint|Qt::X11BypassWindowManagerHint) + { + setModal(true); + resize(1, 1); + setWindowOpacity(0); + setWindowState(Qt::WindowMinimized); + move(32768, 32768); + } + +/* void r() { QDialog::reject(); }*/ +}; + +class KQtThread : public QThread +{ + public: + + KQtThread(QStringList &l, QString &s, int f, KQtDialog *dlg) : dialog(dlg), kdialogdError(false), res(l), selFilter(s), fd(f) + { } + + bool readData(QByteArray &buffer, int size) + { + buffer.resize(size); + return ::readBlock(fd, buffer.data(), size); + } + + bool readString(QString &str, int size) + { + QByteArray buffer; + buffer.resize(size); + + if(!readBlock(fd, buffer.data(), size)) + return false; + + str=QString::fromUtf8(buffer.data()); + return true; + } + + void run() + { + QString buffer; + int num=0; + + if(readBlock(fd, (char *)&num, 4)) + { + int n; + + for(n=0; n<num && !kdialogdError; ++n) + { + int size=0; + + if(readBlock(fd, (char *)&size, 4)) + { + if(size>0) + { + if(readString(buffer, size)) + { + //buffer[size-1]='\0'; + if('/'==buffer[0]) + res.append(buffer); + else + selFilter=buffer; + } + else + kdialogdError=true; + } + } + else + kdialogdError=true; + } + } + else + kdialogdError=true; + QCoreApplication::postEvent(dialog, new QCloseEvent); + } + + KQtDialog *dialog; + bool kdialogdError; + QStringList &res; + QString &selFilter; + int fd; +}; + +static bool sendMessage(QWidget *parent, Operation op, QStringList &res, QString &selFilter, + const QString &title, const QString &p1, const QString *p2, bool ow) +{ + if(connectToKDialogD(getAppName())) + { + char o=(char)op; + int xid=parent ? parent->topLevelWidget()->winId() : qApp->activeWindow()->winId(); + + if(writeBlock(kdialogdSocket, &o, 1) && + writeBlock(kdialogdSocket, (char *)&xid, 4) && + writeString(kdialogdSocket, title) && + writeString(kdialogdSocket, p1) && + (p2? writeString(kdialogdSocket, *p2) : true) && + (OP_FILE_SAVE==op ? writeBool(kdialogdSocket, ow) : true)) + { + KQtDialog dlg(parent); + KQtThread thread(res, selFilter, kdialogdSocket, &dlg); + + thread.start(); + dlg.exec(); + thread.wait(); + + if(thread.kdialogdError) + { + closeConnection(); + return false; + } + return true; + } + } + + return false; +} + +static QString getTitle(const QString &title, Operation op) +{ + if(!title.isEmpty()) + return title; + + return "."; +} + +static bool openKdeDialog(QWidget *widget, const QString &title, const QString &p1, const QString *p2, + Operation op, QStringList &res, QString *selFilter, bool ow=false) +{ + QString filter; + bool rv=sendMessage(widget, op, res, filter, getTitle(title, op), p1, p2, ow); + + // If we failed to talk to, or start kdialogd, then dont keep trying - just fall back to Qt + if(!rv) + /*useKde=false*/; + else if(selFilter) + *selFilter=filter; + + return rv; +} + +static void kqtExit() +{ + if(useKde) + closeConnection(); +} + +static bool kqtInit() +{ + static bool initialised=false; + + if(!initialised) + { + initialised=true; + useKde=NULL!=getenv("KDE_FULL_SESSION") && connectToKDialogD(getAppName()); + if(useKde) + atexit(&kqtExit); + } + + return useKde; +} + +static QString lastDir; + +static void storeLastDir(const QString &f) +{ + lastDir=f; + + int slashPos(lastDir.lastIndexOf('/')); + + if(slashPos!=-1) + lastDir.remove(slashPos+1, lastDir.length()); +} + +static const QString & startDir(const QString &d) +{ + return d.isEmpty() ? lastDir : d; +} + +QString QFileDialog::getOpenFileName(QWidget *parent, const QString &caption, + const QString &dir, const QString &filter, + QString *selectedFilter, Options options) +{ + QStringList res; + QString f(qt2KdeFilter(filter)); + kqtInit(); + + if(openKdeDialog(parent, caption, startDir(dir), &f, OP_FILE_OPEN, res, selectedFilter) && res.count()) + { + kde2QtFilter(filter, selectedFilter); + QString fn(res.first()); + + storeLastDir(fn); + return fn; + } + return QString(); +} + +QString QFileDialog::getSaveFileName(QWidget *parent, const QString &caption, + const QString &dir, const QString &filter, + QString *selectedFilter, Options options) +{ + QStringList res; + QString f(qt2KdeFilter(filter)); + kqtInit(); + + if (openKdeDialog(parent, caption, startDir(dir), &f, OP_FILE_SAVE, res, selectedFilter) && res.count()) + { + kde2QtFilter(filter, selectedFilter); + QString fn(res.first()); + + storeLastDir(fn); + return fn; + } + return QString(); +} + +QString QFileDialog::getExistingDirectory(QWidget *parent, const QString &caption, + const QString &dir, Options options) +{ + QStringList res; + QString dummy; + + kqtInit(); + + return openKdeDialog(parent, caption, dir, NULL, OP_FOLDER, res, &dummy) && res.count() + ? res.first() + : QString(); +} + +QStringList QFileDialog::getOpenFileNames(QWidget *parent, const QString &caption, + const QString &dir, const QString &filter, + QString *selectedFilter, Options options) +{ + QStringList res; + QString f(qt2KdeFilter(filter)); + kqtInit(); + + openKdeDialog(parent, caption, startDir(dir), &f, OP_FILE_OPEN_MULTIPLE, res, selectedFilter); + + if(res.count()) + { + kde2QtFilter(filter, selectedFilter); + storeLastDir(res.first()); + } + return res; +} + +#ifdef KQT_OVERLOAD_NON_STATIC_FILEDIALOGS +static QString getFile(const QString &f) +{ + QString d(f); + + int slashPos=d.lastIndexOf('/'); + + if(slashPos!=-1) + d.remove(0, slashPos+1); + + return d; +} + +int QDialog::exec() +{ + int res=QDialog::Rejected; + + if(inherits("QFileDialog")) + { + QFileDialog *that=(QFileDialog *)this; + + QDir directory(that->directory()); + QString dir, + selectedFilter, + file; + QStringList files; + + QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1); + switch(that->fileMode()) + { + case QFileDialog::Directory: + case QFileDialog::DirectoryOnly: + dir=QFileDialog::getExistingDirectory(parentWidget(), windowTitle(), directory.absolutePath(), 0); + + if(!dir.isEmpty()) + res=QDialog::Accepted; + break; + case QFileDialog::AnyFile: + { + QString app(getFile(qApp->argv()[0])), + initial(directory.absolutePath()); +/* +TODO!!! + initialFile(getCurrentFileName(that)); + + if(!initialFile.isEmpty()) + initial=initial+QLatin1Char('/')+initialFile; +*/ + + file=QFileDialog::getSaveFileName(parentWidget(), windowTitle(), initial, + getFilters(that, "scribus"==app || + "scribus-ng"==app), &selectedFilter, 0); + if(!file.isEmpty()) + res=QDialog::Accepted; + break; + } + case QFileDialog::ExistingFile: + file=QFileDialog::getOpenFileName(parentWidget(), windowTitle(), directory.absolutePath(), + getFilters(that), &selectedFilter, 0); + + if(!file.isEmpty()) + res=QDialog::Accepted; + break; + case QFileDialog::ExistingFiles: + files=QFileDialog::getOpenFileNames(parentWidget(), windowTitle(), directory.absolutePath(), + getFilters(that), &selectedFilter, 0); + + if(files.count()) + res=QDialog::Accepted; + break; + } + + if(QDialog::Accepted==res) + { + if(file.isEmpty() && files.count()) + file=files.first(); + if(dir.isEmpty() && !file.isEmpty()) + dir=getDir(file); + if(!dir.isEmpty()) + that->setDirectory(dir); + if(!selectedFilter.isEmpty()) + that->selectFilter(selectedFilter); + if(!file.isEmpty()) + that->selectFile(getFile(file)); + + if(files.count()) + { + QStringList::ConstIterator it(files.begin()), + end(files.end()); + + for(; it!=end; ++it) + that->selectFile(getFile(*it)); + } + } + QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1); + } + else + { + static int (*realFunction)(void *); + + if(!realFunction) + realFunction = (int (*)(void *)) dlsym(RTLD_NEXT, KQT_QDIALOG_EXEC); + return (int)realFunction(this); + } + + return res; +} +#endif |