diff --git a/krdc/.directory b/krdc/.directory new file mode 100644 index 00000000..a4f1a101 --- /dev/null +++ b/krdc/.directory @@ -0,0 +1,6 @@ +[Dolphin] +Timestamp=2014,12,27,18,58,21 +Version=3 + +[Settings] +HiddenFilesShown=true diff --git a/krdc/CMakeLists.txt b/krdc/CMakeLists.txt new file mode 100644 index 00000000..26417cf8 --- /dev/null +++ b/krdc/CMakeLists.txt @@ -0,0 +1,132 @@ +project(krdc) + +if(NOT INSIDE_KDENETWORK) + message("Not building inside KDENetwork, loading KDE CMake Macros.") + + find_package(KDE4 REQUIRED) + + include(KDE4Defaults) + include(MacroLibrary) + + include(CheckIncludeFile) + include(CheckIncludeFiles) + include(CheckSymbolExists) + include(CheckFunctionExists) + include(CheckLibraryExists) + include(CheckPrototypeExists) + include(CheckTypeSize) + + set(CMAKE_REQUIRED_DEFINITIONS ${_KDE4_PLATFORM_DEFINITIONS}) + if(WIN32) + set(CMAKE_REQUIRED_LIBRARIES ${KDEWIN32_LIBRARIES}) + set(CMAKE_REQUIRED_INCLUDES ${KDEWIN32_INCLUDES}) + endif(WIN32) + add_definitions(${QT_DEFINITIONS} ${QT_QTDBUS_DEFINITIONS} ${KDE4_DEFINITIONS}) + add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS) + include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES}) +endif(NOT INSIDE_KDENETWORK) + +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH}) + +macro_optional_find_package(LibVNCServer) +macro_log_feature(LIBVNCSERVER_FOUND "libvncserver" "VNC server / client library" "http://libvncserver.sourceforge.net/" FALSE "0.9.8" "Needed to build VNC client support in KRDC") + +FIND_PROGRAM(FREERDP_EXECUTABLE xfreerdp) +if(FREERDP_EXECUTABLE) + set(FREERDP_EXECUTABLE_FOUND true) +endif(FREERDP_EXECUTABLE) +macro_log_feature(FREERDP_EXECUTABLE_FOUND "freerdp" "A free Remote Desktop Protocol (RDP) Implementation" "http://www.freerdp.com" FALSE "1.0.2" "Needed for RDP support in KRDC (at runtime)") + +# NX support is not ready for KDE 4.2; disabled (uwolfer) +# macro_optional_find_package(LibNXCL) +# macro_log_feature(LIBNXCL_FOUND "libnxcl" "NX X compression client library" "http://svn.berlios.de/svnroot/repos/freenx/trunk/freenx-client/nxcl/" FALSE "1.0" "Needed to build Krdc with NX support") + +macro_optional_find_package(TelepathyQt4) +macro_log_feature(TelepathyQt4_FOUND "telepathy-qt" "Telepathy Qt Bindings" "http://telepathy.freedesktop.org" FALSE "0.9" "Needed to build Telepathy Tubes support.") + +if(TelepathyQt4_FOUND) + add_definitions(-DTELEPATHY_SUPPORT) + include_directories(${TELEPATHY_QT4_INCLUDE_DIR}) +endif() + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/core/ + ${CMAKE_CURRENT_BINARY_DIR}/core/ + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_subdirectory(core) +add_subdirectory(vnc) +add_subdirectory(nx) +add_subdirectory(rdp) +add_subdirectory(test) +add_subdirectory(doc) + +if(TelepathyQt4_FOUND) + add_subdirectory(krdc_approver) +endif() + +add_definitions(-DKDE_DEFAULT_DEBUG_AREA=5010) +add_definitions(-DBUILD_ZEROCONF) + +set(krdc_SRCS + config/hostpreferenceslist.cpp + config/preferencesdialog.cpp + floatingtoolbar.cpp + bookmarkmanager.cpp + connectiondelegate.cpp + remotedesktopsmodel.cpp + systemtrayicon.cpp + tabbedviewwidget.cpp + mainwindow.cpp + main.cpp +) + +if(TelepathyQt4_FOUND) + set(krdc_SRCS ${krdc_SRCS} + tubesmanager.cpp + ) +endif() + +kde4_add_ui_files(krdc_SRCS + config/general.ui +) + +kde4_add_app_icon(krdc_SRCS "${KDE4_INSTALL_DIR}/share/icons/oxygen/*/apps/krdc.png") + +kde4_add_executable(krdc ${krdc_SRCS}) + +target_link_libraries(krdc + ${KDE4_KFILE_LIBS} + ${KDE4_KIO_LIBS} + ${KDE4_KNOTIFYCONFIG_LIBS} + ${KDE4_KCMUTILS_LIBS} + krdccore +) + +if(TelepathyQt4_FOUND) + target_link_libraries(krdc + ${TELEPATHY_QT4_LIBRARIES} + ) +endif() + +target_link_libraries(krdc ${KDE4_KDNSSD_LIBS}) + +install(TARGETS krdc ${INSTALL_TARGETS_DEFAULT_ARGS}) +install(FILES krdcui.rc DESTINATION ${DATA_INSTALL_DIR}/krdc) +install(PROGRAMS krdc.desktop DESTINATION ${XDG_APPS_INSTALL_DIR}) +install(FILES pointcursor.png pointcursormask.png DESTINATION ${DATA_INSTALL_DIR}/krdc/pics) + +if(TelepathyQt4_FOUND) + configure_file(org.freedesktop.Telepathy.Client.krdc_rfb_handler.service.in + ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.Telepathy.Client.krdc_rfb_handler.service) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.Telepathy.Client.krdc_rfb_handler.service + DESTINATION ${DBUS_SERVICES_INSTALL_DIR}) + + install(FILES krdc_rfb_handler.client DESTINATION ${SHARE_INSTALL_PREFIX}/telepathy/clients/) +endif() + +if(NOT INSIDE_KDENETWORK) + macro_display_feature_log() +endif(NOT INSIDE_KDENETWORK) diff --git a/krdc/COPYING b/krdc/COPYING new file mode 100644 index 00000000..8900e10b --- /dev/null +++ b/krdc/COPYING @@ -0,0 +1,347 @@ +NOTE! The GPL below is copyrighted by the Free Software Foundation, but +the instance of code that it refers to (the kde programs) are copyrighted +by the authors who actually wrote it. + +--------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + 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. + + + Copyright (C) 19yy + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 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/krdc/COPYING.DOC b/krdc/COPYING.DOC new file mode 100644 index 00000000..4a0fe1c8 --- /dev/null +++ b/krdc/COPYING.DOC @@ -0,0 +1,397 @@ + GNU Free Documentation License + Version 1.2, November 2002 + + + Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + +0. PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document "free" in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. + +This License is a kind of "copyleft", which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + + +1. APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The "Document", below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as "you". You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. + +A "Modified Version" of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A "Secondary Section" is a named appendix or a front-matter section of +the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall subject +(or to related matters) and contains nothing that could fall directly +within that overall subject. (Thus, if the Document is in part a +textbook of mathematics, a Secondary Section may not explain any +mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The "Invariant Sections" are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. + +The "Cover Texts" are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. + +A "Transparent" copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not "Transparent" is called "Opaque". + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input format, SGML +or XML using a publicly available DTD, and standard-conforming simple +HTML, PostScript or PDF designed for human modification. Examples of +transparent image formats include PNG, XCF and JPG. Opaque formats +include proprietary formats that can be read and edited only by +proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the +machine-generated HTML, PostScript or PDF produced by some word +processors for output purposes only. + +The "Title Page" means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, "Title Page" means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. + +A section "Entitled XYZ" means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as "Acknowledgements", +"Dedications", "Endorsements", or "History".) To "Preserve the Title" +of such a section when you modify the Document means that it remains a +section "Entitled XYZ" according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. + + +2. VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + + +3. COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. + + +4. MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +A. Use in the Title Page (and on the covers, if any) a title distinct + from that of the Document, and from those of previous versions + (which should, if there were any, be listed in the History section + of the Document). You may use the same title as a previous version + if the original publisher of that version gives permission. +B. List on the Title Page, as authors, one or more persons or entities + responsible for authorship of the modifications in the Modified + Version, together with at least five of the principal authors of the + Document (all of its principal authors, if it has fewer than five), + unless they release you from this requirement. +C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. +D. Preserve all the copyright notices of the Document. +E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. +F. Include, immediately after the copyright notices, a license notice + giving the public permission to use the Modified Version under the + terms of this License, in the form shown in the Addendum below. +G. Preserve in that license notice the full lists of Invariant Sections + and required Cover Texts given in the Document's license notice. +H. Include an unaltered copy of this License. +I. Preserve the section Entitled "History", Preserve its Title, and add + to it an item stating at least the title, year, new authors, and + publisher of the Modified Version as given on the Title Page. If + there is no section Entitled "History" in the Document, create one + stating the title, year, authors, and publisher of the Document as + given on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence. +J. Preserve the network location, if any, given in the Document for + public access to a Transparent copy of the Document, and likewise + the network locations given in the Document for previous versions + it was based on. These may be placed in the "History" section. + You may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission. +K. For any section Entitled "Acknowledgements" or "Dedications", + Preserve the Title of the section, and preserve in the section all + the substance and tone of each of the contributor acknowledgements + and/or dedications given therein. +L. Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section titles. +M. Delete any section Entitled "Endorsements". Such a section + may not be included in the Modified Version. +N. Do not retitle any existing section to be Entitled "Endorsements" + or to conflict in title with any Invariant Section. +O. Preserve any Warranty Disclaimers. + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled "Endorsements", provided it contains +nothing but endorsements of your Modified Version by various +parties--for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + + +5. COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections Entitled "History" +in the various original documents, forming one section Entitled +"History"; likewise combine any sections Entitled "Acknowledgements", +and any sections Entitled "Dedications". You must delete all sections +Entitled "Endorsements". + + +6. COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. + +You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. + + +7. AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an "aggregate" if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. + + +8. TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. + +If a section in the Document is Entitled "Acknowledgements", +"Dedications", or "History", the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. + + +9. TERMINATION + +You may not copy, modify, sublicense, or distribute the Document except +as expressly provided for under this License. Any other attempt to +copy, modify, sublicense or distribute the Document 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. + + +10. FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions +of the GNU Free Documentation 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. See +http://www.gnu.org/copyleft/. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. + + +ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + + Copyright (c) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled "GNU + Free Documentation License". + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the "with...Texts." line with this: + + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. diff --git a/krdc/COPYING.LIB b/krdc/COPYING.LIB new file mode 100644 index 00000000..2d2d780e --- /dev/null +++ b/krdc/COPYING.LIB @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/krdc/Mainpage.dox b/krdc/Mainpage.dox new file mode 100644 index 00000000..b4978f80 --- /dev/null +++ b/krdc/Mainpage.dox @@ -0,0 +1,5 @@ +/** @mainpage KRDC API Reference + * + * KRDC is a remote desktop client for KDE. + * + */ diff --git a/krdc/Messages.sh b/krdc/Messages.sh new file mode 100755 index 00000000..e7f9a81b --- /dev/null +++ b/krdc/Messages.sh @@ -0,0 +1,6 @@ +#! /bin/sh +$EXTRACTRC *.ui */*.ui >> rc.cpp || exit 11 +$EXTRACTRC *.rc */*.rc >> rc.cpp || exit 12 +$EXTRACTRC */*.kcfg >> rc.cpp +$XGETTEXT *.cpp */*.cpp -o $podir/krdc.pot +rm -f rc.cpp diff --git a/krdc/bookmarkmanager.cpp b/krdc/bookmarkmanager.cpp new file mode 100644 index 00000000..9a5154e6 --- /dev/null +++ b/krdc/bookmarkmanager.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2007 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "bookmarkmanager.h" + +#include "mainwindow.h" + +#include +#include +#include + +BookmarkManager::BookmarkManager(KActionCollection *collection, KMenu *menu, MainWindow *parent) + : QObject(parent), + KBookmarkOwner(), + m_mainWindow(parent) +{ + const QString file = KStandardDirs::locateLocal("data", "krdc/bookmarks.xml"); + + m_manager = KBookmarkManager::managerForFile(file, "krdc"); + m_manager->setUpdate(true); + m_bookmarkMenu = new KBookmarkMenu(m_manager, this, menu, collection); + + KBookmarkGroup root = m_manager->root(); + KBookmark bm = root.first(); + while (!bm.isNull()) { + if (bm.metaDataItem("krdc-history") == "historyfolder") // get it also when user renamed it + break; + bm = root.next(bm); + } + + if (bm.isNull()) { + kDebug(5010) << "History folder not found. Create it."; + bm = m_manager->root().createNewFolder(i18n("History")); + bm.setMetaDataItem("krdc-history", "historyfolder"); + m_manager->emitChanged(); + } + + m_historyGroup = bm.toGroup(); +} + +BookmarkManager::~BookmarkManager() +{ + delete m_bookmarkMenu; +} + +void BookmarkManager::addHistoryBookmark(RemoteView *view) +{ + KBookmark bm = m_historyGroup.first(); + const QString urlString = urlForView(view); + const KUrl url = KUrl(urlString); + while (!bm.isNull()) { + if (bm.url() == url) { + kDebug(5010) << "Found URL. Move it at the history start."; + m_historyGroup.moveBookmark(bm, KBookmark()); + bm.updateAccessMetadata(); + m_manager->emitChanged(m_historyGroup); + return; + } + bm = m_historyGroup.next(bm); + } + + if (bm.isNull()) { + kDebug(5010) << "Add new history bookmark."; + bm = m_historyGroup.addBookmark(titleForUrl(urlString), urlString); + bm.updateAccessMetadata(); + m_historyGroup.moveBookmark(bm, KBookmark()); + m_manager->emitChanged(m_historyGroup); + } +} + +void BookmarkManager::openBookmark(const KBookmark &bm, Qt::MouseButtons, Qt::KeyboardModifiers) +{ + emit openUrl(bm.url()); +} + +void BookmarkManager::openFolderinTabs(const KBookmarkGroup &bookmarkGroup) +{ + KBookmark bm = bookmarkGroup.first(); + while (!bm.isNull()) { + emit openUrl(bm.url()); + bm = bookmarkGroup.next(bm); + } +} + +bool BookmarkManager::addBookmarkEntry() const +{ + return true; +} + +bool BookmarkManager::editBookmarkEntry() const +{ + return true; +} + +QString BookmarkManager::currentUrl() const +{ + RemoteView *view = m_mainWindow->currentRemoteView(); + if (view) + return urlForView(view); + else + return QString(); +} + +QString BookmarkManager::urlForView(RemoteView *view) const +{ + return view->url().prettyUrl(KUrl::RemoveTrailingSlash); + +} + +QString BookmarkManager::currentTitle() const +{ + return titleForUrl(currentUrl()); +} + +QString BookmarkManager::titleForUrl(const QString &url) const +{ + return QUrl::fromPercentEncoding(url.toUtf8()); + +} + +bool BookmarkManager::supportsTabs() const +{ + return true; +} + +QList > BookmarkManager::currentBookmarkList() const +{ + QList > list; + + QMapIterator iter(m_mainWindow->remoteViewList()); + + while (iter.hasNext()) { + RemoteView *next = iter.next().value(); + const QString url = next->url().prettyUrl(KUrl::RemoveTrailingSlash); + list << QPair(url, url); + } + + return list; +} + +void BookmarkManager::addManualBookmark(const QString &url, const QString &text) +{ + m_manager->root().addBookmark(url, text); + emit m_manager->emitChanged(); +} + +KBookmarkManager* BookmarkManager::getManager() +{ + return m_manager; +} + +const QStringList BookmarkManager::findBookmarkAddresses(const KBookmarkGroup &group, const QString &url) +{ + QStringList bookmarkAddresses = QStringList(); + KBookmark bm = group.first(); + while (!bm.isNull()) { + if (bm.isGroup()) { + bookmarkAddresses.append(findBookmarkAddresses(bm.toGroup(), url)); + } + + if (bm.url() == url) { + bookmarkAddresses.append(bm.address()); + } + bm = group.next(bm); + } + return bookmarkAddresses; +} + +void BookmarkManager::removeByUrl(KBookmarkManager *manager, const QString &url, bool ignoreHistory, const QString updateTitle) +{ + foreach(const QString &address, findBookmarkAddresses(manager->root(), url)) { + KBookmark bm = manager->findByAddress(address); + if (ignoreHistory && bm.parentGroup().metaDataItem("krdc-history") == "historyfolder") { + if (!updateTitle.isEmpty()) { + kDebug(5010) << "Update" << bm.fullText(); + bm.setFullText(updateTitle); + } + } else { + if (!bm.isGroup()) { // please don't delete groups... happened in testing + kDebug(5010) << "Delete" << bm.fullText(); + bm.parentGroup().deleteBookmark(bm); + } + } + } + + manager->emitChanged(); +} + +void BookmarkManager::updateTitle(KBookmarkManager *manager, const QString &url, const QString &title) +{ + foreach(const QString &address, findBookmarkAddresses(manager->root(), url)) { + KBookmark bm = manager->findByAddress(address); + bm.setFullText(title); + kDebug(5010) << "Update" << bm.fullText(); + } + manager->emitChanged(); +} + +#include "bookmarkmanager.moc" diff --git a/krdc/bookmarkmanager.h b/krdc/bookmarkmanager.h new file mode 100644 index 00000000..900c1045 --- /dev/null +++ b/krdc/bookmarkmanager.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2007 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef BOOKMARKMANAGER_H +#define BOOKMARKMANAGER_H + +#include "core/remoteview.h" + +#include + +class KActionCollection; +class KBookmarkMenu; + +class MainWindow; + +class BookmarkManager : public QObject, public KBookmarkOwner +{ + Q_OBJECT + +public: + BookmarkManager(KActionCollection *collection, KMenu *menu, MainWindow *parent); + ~BookmarkManager(); + + virtual QString currentUrl() const; + virtual QString currentTitle() const; + virtual bool addBookmarkEntry() const; + virtual bool editBookmarkEntry() const; + virtual bool supportsTabs() const; + virtual QList > currentBookmarkList() const; + void addHistoryBookmark(RemoteView *view); + void addManualBookmark(const QString &url, const QString &text); + KBookmarkManager* getManager(); + // removes all bookmarks with url, possibly ignore the history folder and update it's title there if it's set + static void removeByUrl(KBookmarkManager *manager, const QString &url, bool ignoreHistory = false, const QString updateTitle = QString()); + static void updateTitle(KBookmarkManager *manager, const QString &url, const QString &title); + // returns a QStringList for all bookmarks that point to this url using KBookmark::address() + static const QStringList findBookmarkAddresses(const KBookmarkGroup &group, const QString &url); + +signals: + void openUrl(const KUrl &url); + +private slots: + void openBookmark(const KBookmark &bm, Qt::MouseButtons, Qt::KeyboardModifiers); + void openFolderinTabs(const KBookmarkGroup &bookmarkGroup); + +private: + QString urlForView(RemoteView *view) const; + QString titleForUrl(const QString &url) const; + + KBookmarkMenu *m_bookmarkMenu; + KBookmarkManager *m_manager; + KBookmarkGroup m_historyGroup; + + MainWindow *m_mainWindow; +}; + +#endif diff --git a/krdc/cmake/modules/COPYING-CMAKE-SCRIPTS b/krdc/cmake/modules/COPYING-CMAKE-SCRIPTS new file mode 100644 index 00000000..4b417765 --- /dev/null +++ b/krdc/cmake/modules/COPYING-CMAKE-SCRIPTS @@ -0,0 +1,22 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. diff --git a/krdc/cmake/modules/FindLibNXCL.cmake b/krdc/cmake/modules/FindLibNXCL.cmake new file mode 100644 index 00000000..d2e59a67 --- /dev/null +++ b/krdc/cmake/modules/FindLibNXCL.cmake @@ -0,0 +1,38 @@ +# cmake macro to test LIB NXCL + +# Copyright (c) 2008, David Gross +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +include(CheckStructMember) + +IF (LIBNXCL_INCLUDE_DIR AND LIBNXCL_LIBRARIES) + # Already in cache, be silent + SET(LIBNBXCL_FIND_QUIETLY TRUE) +ENDIF (LIBNXCL_INCLUDE_DIR AND LIBNXCL_LIBRARIES) + +FIND_PATH(LIBNXCL_INCLUDE_DIR nxcl/nxclientlib.h) +FIND_LIBRARY(LIBNXCL_LIBRARIES NAMES nxcl libnxcl) + +IF (LIBNXCL_INCLUDE_DIR AND LIBNXCL_LIBRARIES) + SET(CMAKE_REQUIRED_LIBRARIES "${LIBNXCL_LIBRARIES}" "${CMAKE_REQUIRED_LIBRARIES}") + SET(CMAKE_REQUIRED_INCLUDES "${LIBNXCL_INCLUDE_DIR}" "${CMAKE_REQUIRED_INCLUDES}") + CHECK_STRUCT_MEMBER(nxcl::NXClientLib "getNXSSHProcess()" nxcl/nxclientlib.h LIBNXCL_NXSSHPROCESS_FOUND) + CHECK_STRUCT_MEMBER(nxcl::NXClientLib "getXID()" nxcl/nxclientlib.h LIBNXCL_XID_FOUND) +ENDIF (LIBNXCL_INCLUDE_DIR AND LIBNXCL_LIBRARIES) + +IF (LIBNXCL_NXSSHPROCESS_FOUND AND LIBNXCL_XID_FOUND) + SET(LIBNXCL_FOUND TRUE) + IF (NOT LIBNXCL_FIND_QUIETLY) + MESSAGE(STATUS "Found LibNXCL: ${LIBNXCL_LIBRARIES}") + ENDIF (NOT LIBNXCL_FIND_QUIETLY) +ELSE (LIBNXCL_NXSSHPROCESS_FOUND AND LIBNXCL_XID_FOUND) + SET(LIBNXCL_FOUND FALSE) + IF (LIBNXCL_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could NOT find acceptable version of LibNXCL (version 1.0).") + ENDIF (LIBNXCL_FIND_REQUIRED) +ENDIF (LIBNXCL_NXSSHPROCESS_FOUND AND LIBNXCL_XID_FOUND) + +MARK_AS_ADVANCED(LIBNXCL_INCLUDE_DIR LIBNXCL_LIBRARIES) + diff --git a/krdc/cmake/modules/FindLibVNCServer.cmake b/krdc/cmake/modules/FindLibVNCServer.cmake new file mode 100644 index 00000000..0c260367 --- /dev/null +++ b/krdc/cmake/modules/FindLibVNCServer.cmake @@ -0,0 +1,41 @@ +# cmake macro to test LIBVNCSERVER LIB + +# Copyright (c) 2006, Alessandro Praduroux +# Copyright (c) 2007, Urs Wolfer +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +INCLUDE(CheckPointerMember) + +IF (LIBVNCSERVER_INCLUDE_DIR AND LIBVNCSERVER_LIBRARIES) + # Already in cache, be silent + SET(LIBVNCSERVER_FIND_QUIETLY TRUE) +ENDIF (LIBVNCSERVER_INCLUDE_DIR AND LIBVNCSERVER_LIBRARIES) + +FIND_PATH(LIBVNCSERVER_INCLUDE_DIR rfb/rfb.h) + +FIND_LIBRARY(LIBVNCSERVER_LIBRARIES NAMES vncserver libvncserver) + +# libvncserver and libvncclient are in the same package, so it does +# not make sense to add a new cmake script for finding libvncclient. +# instead just find the libvncclient also in this file. +FIND_PATH(LIBVNCCLIENT_INCLUDE_DIR rfb/rfbclient.h) +FIND_LIBRARY(LIBVNCCLIENT_LIBRARIES NAMES vncclient libvncclient) + +IF (LIBVNCSERVER_INCLUDE_DIR AND LIBVNCSERVER_LIBRARIES) + SET(CMAKE_REQUIRED_INCLUDES "${LIBVNCSERVER_INCLUDE_DIR}" "${CMAKE_REQUIRED_INCLUDES}") + CHECK_POINTER_MEMBER(rfbClient* GotXCutText rfb/rfbclient.h LIBVNCSERVER_FOUND) +ENDIF (LIBVNCSERVER_INCLUDE_DIR AND LIBVNCSERVER_LIBRARIES) + +IF (LIBVNCSERVER_FOUND) + IF (NOT LIBVNCSERVER_FIND_QUIETLY) + MESSAGE(STATUS "Found LibVNCServer: ${LIBVNCSERVER_LIBRARIES}") + ENDIF (NOT LIBVNCSERVER_FIND_QUIETLY) +ELSE (LIBVNCSERVER_FOUND) + IF (LIBVNCSERVER_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could NOT find acceptable version of LibVNCServer (version 0.9 or later required).") + ENDIF (LIBVNCSERVER_FIND_REQUIRED) +ENDIF (LIBVNCSERVER_FOUND) + +MARK_AS_ADVANCED(LIBVNCSERVER_INCLUDE_DIR LIBVNCSERVER_LIBRARIES) diff --git a/krdc/config/CMakeLists.txt b/krdc/config/CMakeLists.txt new file mode 100644 index 00000000..1bdba6cb --- /dev/null +++ b/krdc/config/CMakeLists.txt @@ -0,0 +1 @@ +install(FILES krdc.kcfg DESTINATION ${KCFG_INSTALL_DIR}) diff --git a/krdc/config/general.ui b/krdc/config/general.ui new file mode 100644 index 00000000..4a1f0e06 --- /dev/null +++ b/krdc/config/general.ui @@ -0,0 +1,220 @@ + + + General + + + + 0 + 0 + 363 + 464 + + + + + + + Remember open sessions for next startup + + + + + + + Remember connection history + + + + + + + Remember passwords (KWallet) + + + + + + + Enable system tray icon + + + + + + + Show status bar + + + + + + + Keep aspect ratio when scaling + + + + + + + + + Background color of empty place: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + + + + + + When Connecting + + + + + + Show the preferences dialog for new connections + + + + + + + This option will resize the window to fit the connection size. If it is too big, it will maximize the window. + + + Resize to fit + + + + + + + This option switches to fullscreen only if the connection resolution is the same as the current screen resolution + + + Switch to Fullscreen if appropriate + + + + + + + + + + Tab Settings + + + + + + Always show tab bar + + + + + + + Show close button on tabs + + + + + + + Middle-click on a tab closes it + + + + + + + + + Tab position: + + + + + + + + Top + + + + + Bottom + + + + + Left + + + + + Right + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + KComboBox + QComboBox +
kcombobox.h
+
+ + KColorButton + QPushButton +
kcolorbutton.h
+
+
+ + +
diff --git a/krdc/config/hostpreferenceslist.cpp b/krdc/config/hostpreferenceslist.cpp new file mode 100644 index 00000000..c1ea425d --- /dev/null +++ b/krdc/config/hostpreferenceslist.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2007 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "hostpreferenceslist.h" +#include "hostpreferences.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +HostPreferencesList::HostPreferencesList(QWidget *parent, MainWindow *mainWindow, KConfigGroup hostPrefsConfig) + : QWidget(parent) + , m_hostPrefsConfig(hostPrefsConfig) + , m_mainWindow(mainWindow) +{ + hostList = new QListWidget(this); + connect(hostList, SIGNAL(itemSelectionChanged()), SLOT(selectionChanged())); + connect(hostList, SIGNAL(itemDoubleClicked(QListWidgetItem*)), SLOT(configureHost())); + + configureButton = new KPushButton(this); + configureButton->setEnabled(false); + configureButton->setText(i18n("Configure...")); + configureButton->setIcon(KIcon("configure")); + connect(configureButton, SIGNAL(clicked()), SLOT(configureHost())); + + removeButton = new KPushButton(this); + removeButton->setEnabled(false); + removeButton->setText(i18n("Remove")); + removeButton->setIcon(KIcon("list-remove")); + connect(removeButton, SIGNAL(clicked()), SLOT(removeHost())); + + QVBoxLayout *buttonLayout = new QVBoxLayout; + buttonLayout->addWidget(configureButton); + buttonLayout->addWidget(removeButton); + buttonLayout->addStretch(); + + QHBoxLayout *mainLayout = new QHBoxLayout(this); + mainLayout->addWidget(hostList); + mainLayout->addLayout(buttonLayout); + + setLayout(mainLayout); + + readConfig(); +} + +HostPreferencesList::~HostPreferencesList() +{ +} + +void HostPreferencesList::readConfig() +{ + QStringList urls = m_hostPrefsConfig.groupList(); + + for (int i = 0; i < urls.size(); ++i) + hostList->addItem(new QListWidgetItem(urls.at(i))); +} + +void HostPreferencesList::saveSettings() +{ + m_hostPrefsConfig.sync(); +} + +void HostPreferencesList::configureHost() +{ + QList selectedItems = hostList->selectedItems(); + + foreach(QListWidgetItem *selectedItem, selectedItems) { + const QString url = selectedItem->text(); + + kDebug(5010) << "Configure host: " << url; + + HostPreferences* prefs = 0; + + const QList remoteViewFactories(m_mainWindow->remoteViewFactoriesList()); + foreach(RemoteViewFactory *factory, remoteViewFactories) { + if (factory->supportsUrl(url)) { + prefs = factory->createHostPreferences(m_hostPrefsConfig.group(url), this); + if (prefs) { + kDebug(5010) << "Found plugin to handle url (" + url + "): " + prefs->metaObject()->className(); + } else { + kDebug(5010) << "Found plugin to handle url (" + url + "), but plugin does not provide preferences"; + } + } + } + + if (prefs) { + prefs->showDialog(this); + delete prefs; + } else { + KMessageBox::error(this, + i18n("The selected host cannot be handled."), + i18n("Unusable URL")); + } + } +} + +void HostPreferencesList::removeHost() +{ + const QList selectedItems = hostList->selectedItems(); + + foreach(QListWidgetItem *selectedItem, selectedItems) { + kDebug(5010) << "Remove host: " << selectedItem->text(); + + m_hostPrefsConfig.deleteGroup(selectedItem->text()); + delete(selectedItem); + } + + saveSettings(); + hostList->clearSelection(); +} + +void HostPreferencesList::selectionChanged() +{ + const bool enabled = hostList->selectedItems().isEmpty() ? false : true; + + configureButton->setEnabled(enabled); + removeButton->setEnabled(enabled); +} + +#include "hostpreferenceslist.moc" diff --git a/krdc/config/hostpreferenceslist.h b/krdc/config/hostpreferenceslist.h new file mode 100644 index 00000000..0b515638 --- /dev/null +++ b/krdc/config/hostpreferenceslist.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2007 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef HOSTPREFERENCESLIST_H +#define HOSTPREFERENCESLIST_H + +#include "mainwindow.h" + +#include + +#include +#include + +class KPushButton; + +class QListWidget; + +class HostPreferencesList : public QWidget +{ + Q_OBJECT + +public: + HostPreferencesList(QWidget *parent, MainWindow *mainWindow, KConfigGroup hostPrefsConfig); + ~HostPreferencesList(); + +private slots: + void readConfig(); + void saveSettings(); + void configureHost(); + void removeHost(); + void selectionChanged(); + +private: + KConfigGroup m_hostPrefsConfig; + + KPushButton *configureButton; + KPushButton *removeButton; + QListWidget *hostList; + MainWindow *m_mainWindow; +}; + +#endif // HOSTPREFERENCESLIST_H diff --git a/krdc/config/preferencesdialog.cpp b/krdc/config/preferencesdialog.cpp new file mode 100644 index 00000000..7d5152cf --- /dev/null +++ b/krdc/config/preferencesdialog.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2007 - 2010 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "preferencesdialog.h" + +#include "hostpreferenceslist.h" +#include "ui_general.h" + +#include +#include +#include +#include +#include +#include + +PreferencesDialog::PreferencesDialog(QWidget *parent, KConfigSkeleton *skeleton) + : KConfigDialog(parent, "preferences", skeleton) + , m_settingsChanged(false) +{ + QWidget *generalPage = new QWidget(this); + Ui::General generalUi; + generalUi.setupUi(generalPage); + addPage(generalPage, i18nc("General Config", "General"), "krdc", i18n("General Configuration")); + + HostPreferencesList *hostPreferencesList = new HostPreferencesList(this, + qobject_cast(parent), + skeleton->config()->group("hostpreferences")); + addPage(hostPreferencesList, i18n("Hosts"), "computer", i18n("Host Configuration")); + + m_pluginSelector = new KPluginSelector(); + KService::List offers = KServiceTypeTrader::self()->query("KRDC/Plugin"); + m_pluginSelector->addPlugins(KPluginInfo::fromServices(offers), KPluginSelector::ReadConfigFile, + i18n("Plugins"), "Service", KGlobal::config()); + m_pluginSelector->load(); + addPage(m_pluginSelector, i18n("Plugins"), "preferences-plugin", i18n("Plugin Configuration")); + + connect(this, SIGNAL(accepted()), SLOT(saveState())); + connect(this, SIGNAL(defaultClicked()), SLOT(loadDefaults())); + connect(m_pluginSelector, SIGNAL(changed(bool)), SLOT(settingsChanged())); +} + +void PreferencesDialog::saveState() +{ + //TODO: relaod plugins at runtime? + m_pluginSelector->save(); +} + +void PreferencesDialog::loadDefaults() +{ + m_pluginSelector->defaults(); + enableButton(Default, false); +} + +void PreferencesDialog::settingsChanged() +{ + enableButton(Apply, true); + enableButton(Default, true); +} + +bool PreferencesDialog::isDefault() +{ + return KConfigDialog::isDefault() && m_pluginSelector->isDefault(); +} diff --git a/krdc/config/preferencesdialog.h b/krdc/config/preferencesdialog.h new file mode 100644 index 00000000..13424c66 --- /dev/null +++ b/krdc/config/preferencesdialog.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2007 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef PREFERENCESDIALOG_H +#define PREFERENCESDIALOG_H + +#include + +class KConfigSkeleton; +class KPluginSelector; + +class PreferencesDialog : public KConfigDialog +{ + Q_OBJECT + +public: + PreferencesDialog(QWidget *parent, KConfigSkeleton *config); + +protected: + virtual bool isDefault(); + +private slots: + void saveState(); + void loadDefaults(); + void settingsChanged(); + +private: + KPluginSelector *m_pluginSelector; + bool m_settingsChanged; +}; + +#endif diff --git a/krdc/connectiondelegate.cpp b/krdc/connectiondelegate.cpp new file mode 100644 index 00000000..d6fa9db9 --- /dev/null +++ b/krdc/connectiondelegate.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Tony Murray +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "connectiondelegate.h" +#include "remotedesktopsmodel.h" + +#include +#include +#include +#include +#include + +ConnectionDelegate::ConnectionDelegate(QObject *parent) : + QStyledItemDelegate(parent) +{ +} + +QString ConnectionDelegate::displayText(const QVariant &value, const QLocale& locale) const +{ + if (value.type() == QVariant::DateTime) { + KDateTime lastConnected = KDateTime(value.toDateTime()); + KDateTime currentTime = KDateTime::currentUtcDateTime(); + + int daysAgo = lastConnected.daysTo(currentTime); + if (daysAgo <= 1 && lastConnected.secsTo(currentTime) < 86400) { + int minutesAgo = lastConnected.secsTo(currentTime) / 60; + int hoursAgo = minutesAgo / 60; + if (hoursAgo < 1) { + if (minutesAgo < 1) + return i18n("Less than a minute ago"); + return i18np("A minute ago", "%1 minutes ago", minutesAgo); + } else { + return i18np("An hour ago", "%1 hours ago", hoursAgo); + } + } else { // 1 day or more + if (daysAgo < 30) + return i18np("Yesterday", "%1 days ago", daysAgo); + if (daysAgo < 365) + return i18np("Over a month ago", "%1 months ago", daysAgo / 30); + return i18np("A year ago", "%1 years ago", daysAgo / 365); + } + + } + // These aren't the strings you're looking for, move along. + return QStyledItemDelegate::displayText(value, locale); +} + +void ConnectionDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + if (index.column() == RemoteDesktopsModel::Favorite) { + QVariant value = index.data(Qt::CheckStateRole); + if (value.isValid()) { + Qt::CheckState checkState = static_cast(value.toInt()); + KIcon favIcon = KIcon("bookmarks"); + KIcon::Mode mode = (checkState == Qt::Checked) ? KIcon::Active : KIcon::Disabled; + favIcon.paint(painter, option.rect, option.decorationAlignment, mode); + + } + } else { + QStyledItemDelegate::paint(painter, option, index); + } +} + +QSize ConnectionDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + if (index.column() == RemoteDesktopsModel::Favorite) + return QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall); + return QStyledItemDelegate::sizeHint(option, index); +} diff --git a/krdc/connectiondelegate.h b/krdc/connectiondelegate.h new file mode 100644 index 00000000..b93148e0 --- /dev/null +++ b/krdc/connectiondelegate.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Tony Murray +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef CONNECTIONDELEGATE_H +#define CONNECTIONDELEGATE_H + +#include + +class ConnectionDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + explicit ConnectionDelegate(QObject *parent = 0); + QString displayText(const QVariant &value, const QLocale& locale) const; + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; +signals: + +public slots: + +}; + +#endif // CONNECTIONDELEGATE_H diff --git a/krdc/core/CMakeLists.txt b/krdc/core/CMakeLists.txt new file mode 100644 index 00000000..99ee7693 --- /dev/null +++ b/krdc/core/CMakeLists.txt @@ -0,0 +1,29 @@ + +add_definitions(-DKDE_DEFAULT_DEBUG_AREA=5010) + +set(krdccore_SRCS + remoteviewfactory.cpp + remoteview.cpp + hostpreferences.cpp +) + +kde4_add_kcfg_files(krdccore_SRCS settings.kcfgc) + +kde4_add_library(krdccore SHARED ${krdccore_SRCS}) + +target_link_libraries(krdccore ${KDE4_KDECORE_LIBS} ${KDE4_KDEUI_LIBS}) + +set_target_properties(krdccore PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION}) + +install(TARGETS krdccore ${INSTALL_TARGETS_DEFAULT_ARGS}) + +# Install headers +set(krdccore_HDRS + remoteviewfactory.h + remoteview.h + hostpreferences.h +) + +install(FILES ${krdccore_HDRS} DESTINATION ${INCLUDE_INSTALL_DIR}/krdc COMPONENT Devel) +install(FILES krdc_plugin.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR}) +install(FILES krdc.kcfg DESTINATION ${KCFG_INSTALL_DIR}) diff --git a/krdc/core/hostpreferences.cpp b/krdc/core/hostpreferences.cpp new file mode 100644 index 00000000..64126577 --- /dev/null +++ b/krdc/core/hostpreferences.cpp @@ -0,0 +1,239 @@ +/**************************************************************************** +** +** Copyright (C) 2007 - 2010 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "hostpreferences.h" + +#include "settings.h" + +#include +#include +#include +#include + +#include +#include +#include + +HostPreferences::HostPreferences(KConfigGroup configGroup, QObject *parent) + : QObject(parent), + m_configGroup(configGroup), + m_connected(false), + showAgainCheckBox(0), + walletSupportCheckBox(0) +{ + m_hostConfigured = m_configGroup.hasKey("showConfigAgain"); +} + +HostPreferences::~HostPreferences() +{ +} + +KConfigGroup HostPreferences::configGroup() +{ + return m_configGroup; +} + +void HostPreferences::acceptConfig() +{ + setShowConfigAgain(showAgainCheckBox->isChecked()); + setWalletSupport(walletSupportCheckBox->isChecked()); +} + +bool HostPreferences::hostConfigured() +{ + return m_hostConfigured; +} + +void HostPreferences::setShowConfigAgain(bool show) +{ + m_configGroup.writeEntry("showConfigAgain", show); +} + +bool HostPreferences::showConfigAgain() +{ + return m_configGroup.readEntry("showConfigAgain", true); +} + +void HostPreferences::setWalletSupport(bool walletSupport) +{ + m_configGroup.writeEntry("walletSupport", walletSupport); +} + +bool HostPreferences::walletSupport() +{ + return m_configGroup.readEntry("walletSupport", true); +} + +void HostPreferences::setHeight(int height) +{ + if (height >= 0) + m_configGroup.writeEntry("height", height); +} + +int HostPreferences::height() +{ + return m_configGroup.readEntry("height", Settings::height()); +} + +void HostPreferences::setWidth(int width) +{ + if (width >= 0) + m_configGroup.writeEntry("width", width); +} + +int HostPreferences::width() +{ + return m_configGroup.readEntry("width", Settings::width()); +} + +bool HostPreferences::fullscreenScale() +{ + return m_configGroup.readEntry("fullscreenScale", false); +} + +void HostPreferences::setFullscreenScale(bool scale) +{ + m_configGroup.writeEntry("fullscreenScale", scale); +} + +bool HostPreferences::windowedScale() +{ + return m_configGroup.readEntry("windowedScale", false); +} + +void HostPreferences::setWindowedScale(bool scale) +{ + m_configGroup.writeEntry("windowedScale", scale); +} + +bool HostPreferences::grabAllKeys() +{ + return m_configGroup.readEntry("grabAllKeys", false); +} + +void HostPreferences::setGrabAllKeys(bool grab) +{ + m_configGroup.writeEntry("grabAllKeys", grab); +} + +bool HostPreferences::showLocalCursor() +{ + return m_configGroup.readEntry("showLocalCursor", false); +} + +void HostPreferences::setShowLocalCursor(bool show) +{ + m_configGroup.writeEntry("showLocalCursor", show); +} + +bool HostPreferences::viewOnly() +{ + return m_configGroup.readEntry("viewOnly", false); +} + +void HostPreferences::setViewOnly(bool view) +{ + m_configGroup.writeEntry("viewOnly", view); +} + +bool HostPreferences::showDialogIfNeeded(QWidget *parent) +{ + if (hostConfigured()) { + if (showConfigAgain()) { + kDebug(5010) << "Show config dialog again"; + return showDialog(parent); + } else + return true; // no changes, no need to save + } else { + kDebug(5010) << "No config found, create new"; + if (Settings::showPreferencesForNewConnections()) + return showDialog(parent); + else + return true; + } +} + + +bool HostPreferences::showDialog(QWidget *parent) +{ + // Prepare dialog + KDialog *dialog = new KDialog(parent); + dialog->setCaption(i18n("Host Configuration")); + + QWidget *mainWidget = dialog->mainWidget(); + QVBoxLayout *layout = new QVBoxLayout(mainWidget); + + KTitleWidget *titleWidget = new KTitleWidget(dialog); + titleWidget->setText(i18n("Host Configuration")); + if (m_connected) { + titleWidget->setComment(QString("%1").arg( + i18n("Note that settings might only apply when you connect next time to this host."))); + } + titleWidget->setPixmap(KIcon("krdc")); + layout->addWidget(titleWidget); + + QWidget* widget = createProtocolSpecificConfigPage(); + + if (widget) { + if (widget->layout()) + widget->layout()->setMargin(0); + + layout->addWidget(widget); + } + + showAgainCheckBox = new QCheckBox(mainWidget); + showAgainCheckBox->setText(i18n("Show this dialog again for this host")); + showAgainCheckBox->setChecked(showConfigAgain()); + + walletSupportCheckBox = new QCheckBox(mainWidget); + walletSupportCheckBox->setText(i18n("Remember password (KWallet)")); + walletSupportCheckBox->setChecked(walletSupport()); + + layout->addWidget(showAgainCheckBox); + layout->addWidget(walletSupportCheckBox); + layout->addStretch(1); + + // WORKAROUND: it seems that KDialog does not set the minimum size properly in some cases. + // see for example issue #244539. also it looks like KTitleWidget returns a too small size hint when a comment is shown. + QSize minimumSize = dialog->sizeHint(); + if (m_connected) { + minimumSize += QSize(0, 50); + } + dialog->setMinimumSize(minimumSize); + + // Show dialog + if (dialog->exec() == KDialog::Accepted) { + kDebug(5010) << "HostPreferences config dialog accepted"; + acceptConfig(); + return true; + } else { + return false; + } +} + +void HostPreferences::setShownWhileConnected(bool connected) +{ + m_connected = connected; +} + +#include "hostpreferences.moc" diff --git a/krdc/core/hostpreferences.h b/krdc/core/hostpreferences.h new file mode 100644 index 00000000..cf98b626 --- /dev/null +++ b/krdc/core/hostpreferences.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2007 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef HOSTPREFERENCES_H +#define HOSTPREFERENCES_H + +#include "remoteview.h" + +#include + +#include + +#include + +#include + +class QCheckBox; +class QWidget; +class KConfig; +class KConfigGroup; + +class KRDCCORE_EXPORT HostPreferences : public QObject +{ + Q_OBJECT + +public: + ~HostPreferences(); + + KConfigGroup configGroup(); + + bool walletSupport(); + + /** Whether scaling is enabled when session is full screen. Note: only windowedScale seems to be used. */ + bool fullscreenScale(); + void setFullscreenScale(bool scale); + + /** Whether scaling is enabled when session is not full screen */ + bool windowedScale(); + void setWindowedScale(bool scale); + + bool grabAllKeys(); + void setGrabAllKeys(bool grab); + + bool showLocalCursor(); + void setShowLocalCursor(bool show); + + bool viewOnly(); + void setViewOnly(bool view); + + /** Saved height. Generally used for the viewsize. */ + int height(); + void setHeight(int height); + /** Saved width. Generally used for the viewsize. */ + int width(); + void setWidth(int width); + + /** + * Show the configuration dialog if needed, ie. if the user did + * check "show this dialog again for this host". + * Returns true if user pressed ok. + */ + bool showDialogIfNeeded(QWidget *parent); + + /** Show the configuration dialog */ + bool showDialog(QWidget *parent); + + /** If @p connected is true, a message is shown that settings might only apply after a reconnect. */ + void setShownWhileConnected(bool connected); + +protected: + HostPreferences(KConfigGroup configGroup, QObject *parent); + + virtual QWidget* createProtocolSpecificConfigPage() = 0; + + /** Called when the user validates the config dialog. */ + virtual void acceptConfig(); + + bool hostConfigured(); + bool showConfigAgain(); + + KConfigGroup m_configGroup; + +private: + void setShowConfigAgain(bool show); + void setWalletSupport(bool walletSupport); + + bool m_hostConfigured; + bool m_connected; + + QCheckBox *showAgainCheckBox; + QCheckBox *walletSupportCheckBox; +}; + +#endif diff --git a/krdc/core/krdc.kcfg b/krdc/core/krdc.kcfg new file mode 100644 index 00000000..9b84cbd5 --- /dev/null +++ b/krdc/core/krdc.kcfg @@ -0,0 +1,132 @@ + + + + + + false + + + true + + + + + + true + + + true + + + true + + + false + + + #00417F + + + true + + + false + + + true + + + true + + + true + + + 0 + + + false + + + false + + + 2 + + + 1 + + + + + 1 + + + false + + + 800 + + + 600 + + + + + 800 + + + 600 + + + 7 + + + 2 + + + 0 + + + false + + + + + + + + + true + + + true + + + 2 + + + /media + + + + + 800 + + + 600 + + + 0 + + + 7 + + + default + + + diff --git a/krdc/core/krdc_export.h b/krdc/core/krdc_export.h new file mode 100644 index 00000000..5164997b --- /dev/null +++ b/krdc/core/krdc_export.h @@ -0,0 +1,39 @@ +/* This file is part of the KDE project + Copyright (C) 2006 David Faure + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KRDCCORE_EXPORT_H +#define KRDCCORE_EXPORT_H + +/* needed for KDE_EXPORT and KDE_IMPORT macros */ +#include + +#ifndef KRDCCORE_EXPORT +# if defined(KDELIBS_STATIC_LIBS) + /* No export/import for static libraries */ +# define KRDCCORE_EXPORT +# elif defined(MAKE_KRDCCORE_LIB) + /* We are building this library */ +# define KRDCCORE_EXPORT KDE_EXPORT +# else + /* We are using this library */ +# define KRDCCORE_EXPORT KDE_IMPORT +# endif +#endif + +#endif diff --git a/krdc/core/krdc_plugin.desktop b/krdc/core/krdc_plugin.desktop new file mode 100644 index 00000000..990bedd7 --- /dev/null +++ b/krdc/core/krdc_plugin.desktop @@ -0,0 +1,63 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=KRDC/Plugin +Name=KRDC Plugin +Name[ast]=Complemente KRDC +Name[bg]=Приставка KRDC +Name[bs]=KRDC Dodatak +Name[ca]=Connector del KRDC +Name[ca@valencia]=Connector del KRDC +Name[cs]=Modul KRDC +Name[da]=KRDC-plugin +Name[de]=KRDC-Modul +Name[el]=Πρόσθετο KRDC +Name[en_GB]=KRDC Plugin +Name[es]=Complemento de KRDC +Name[et]=KRDC plugin +Name[eu]=KRDC plugina +Name[fi]=Kopete-liitännäinen +Name[fr]=Module externe KRDC +Name[ga]=Breiseán KRDC +Name[gl]=Engadido KRDC +Name[hr]=Priključak KRDC +Name[hu]=KRDC-bővítmény +Name[ia]=Plug-in de KRDC +Name[is]=KRDC íforrit +Name[it]=Estensione di KRDC +Name[ja]=KRDC プラグイン +Name[kk]=KRDC плагині +Name[km]=កម្មវិធី​ជំនួយ KRDC +Name[ko]=KRDC 플러그인 +Name[lt]=KRDC priedas +Name[lv]=KRDC spraudnis +Name[mr]=के-आर-डी-सी प्लगइन +Name[nb]=KRDC programtillegg +Name[nds]=KRDC-Moduul +Name[nl]=KRDC-plugin +Name[nn]=KRDC-programtillegg +Name[pa]=KRDC ਪਲੱਗਇਨ +Name[pl]=Wtyczka KRDC +Name[pt]='Plugin' do KRDC +Name[pt_BR]=Plugin KRDC +Name[ro]=Extensie KRDC +Name[ru]=Модуль KRDC +Name[si]=KRDC ප්ලගිනය +Name[sk]=Modul KRDC +Name[sl]=Vstavek za KRDC +Name[sr]=Прикључак КРДЦ‑а +Name[sr@ijekavian]=Прикључак КРДЦ‑а +Name[sr@ijekavianlatin]=Priključak KRDC‑a +Name[sr@latin]=Priključak KRDC‑a +Name[sv]=Insticksprogram för KRDC +Name[th]=ส่วนเสริมของ KRDC +Name[tr]=KRDC Eklentisi +Name[ug]=KRDC قىستۇرما +Name[uk]=Додаток KRDC +Name[x-test]=xxKRDC Pluginxx +Name[zh_CN]=KRDC 插件 +Name[zh_TW]=KRDC 外掛程式 + +# Sorting of the plugin. +# 0 is the highest value. +[PropertyDef::X-KDE-KRDC-Sorting] +Type=int diff --git a/krdc/core/remoteview.cpp b/krdc/core/remoteview.cpp new file mode 100644 index 00000000..e45a1a1a --- /dev/null +++ b/krdc/core/remoteview.cpp @@ -0,0 +1,283 @@ +/**************************************************************************** +** +** Copyright (C) 2002-2003 Tim Jansen +** Copyright (C) 2007-2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "remoteview.h" + +#ifndef QTONLY + #include + #include +#endif + +#include + +RemoteView::RemoteView(QWidget *parent) + : QWidget(parent), + m_status(Disconnected), + m_host(QString()), + m_port(0), + m_viewOnly(false), + m_grabAllKeys(false), + m_scale(false), + m_keyboardIsGrabbed(false), +#ifndef QTONLY + m_wallet(0), +#endif + m_dotCursorState(CursorOff) +{ +} + +RemoteView::~RemoteView() +{ +#ifndef QTONLY + delete m_wallet; +#endif +} + +RemoteView::RemoteStatus RemoteView::status() +{ + return m_status; +} + +void RemoteView::setStatus(RemoteView::RemoteStatus s) +{ + if (m_status == s) + return; + + if (((1+ m_status) != s) && (s != Disconnected)) { + // follow state transition rules + + if (s == Disconnecting) { + if (m_status == Disconnected) + return; + } else { + Q_ASSERT(((int) s) >= 0); + if (m_status > s) { + m_status = Disconnected; + emit statusChanged(Disconnected); + } + // smooth state transition + RemoteStatus origState = m_status; + for (int i = origState; i < s; ++i) { + m_status = (RemoteStatus) i; + emit statusChanged((RemoteStatus) i); + } + } + } + m_status = s; + emit statusChanged(m_status); +} + +bool RemoteView::supportsScaling() const +{ + return false; +} + +bool RemoteView::supportsLocalCursor() const +{ + return false; +} + +QString RemoteView::host() +{ + return m_host; +} + +QSize RemoteView::framebufferSize() +{ + return QSize(0, 0); +} + +void RemoteView::startQuitting() +{ +} + +bool RemoteView::isQuitting() +{ + return false; +} + +int RemoteView::port() +{ + return m_port; +} + +void RemoteView::updateConfiguration() +{ +} + +void RemoteView::keyEvent(QKeyEvent *) +{ +} + +bool RemoteView::viewOnly() +{ + return m_viewOnly; +} + +void RemoteView::setViewOnly(bool viewOnly) +{ + m_viewOnly = viewOnly; +} + +bool RemoteView::grabAllKeys() +{ + return m_grabAllKeys; +} + +void RemoteView::setGrabAllKeys(bool grabAllKeys) +{ + m_grabAllKeys = grabAllKeys; + + if (grabAllKeys) { + m_keyboardIsGrabbed = true; + grabKeyboard(); + } else if (m_keyboardIsGrabbed) { + releaseKeyboard(); + } +} + +QPixmap RemoteView::takeScreenshot() +{ + return QPixmap::grabWidget(this); +} + +void RemoteView::showDotCursor(DotCursorState state) +{ + m_dotCursorState = state; +} + +RemoteView::DotCursorState RemoteView::dotCursorState() const +{ + return m_dotCursorState; +} + +bool RemoteView::scaling() const +{ + return m_scale; +} + +void RemoteView::enableScaling(bool scale) +{ + m_scale = scale; +} + +void RemoteView::switchFullscreen(bool) +{ +} + +void RemoteView::scaleResize(int, int) +{ +} + +KUrl RemoteView::url() +{ + return m_url; +} + +#ifndef QTONLY +QString RemoteView::readWalletPassword(bool fromUserNameOnly) +{ + const QString KRDCFOLDER = "KRDC"; + + window()->setDisabled(true); // WORKAROUND: disable inputs so users cannot close the current tab (see #181230) + m_wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), window()->winId()); + window()->setDisabled(false); + + if (m_wallet) { + bool walletOK = m_wallet->hasFolder(KRDCFOLDER); + if (!walletOK) { + walletOK = m_wallet->createFolder(KRDCFOLDER); + kDebug(5010) << "Wallet folder created"; + } + if (walletOK) { + kDebug(5010) << "Wallet OK"; + m_wallet->setFolder(KRDCFOLDER); + QString password; + + QString key; + if (fromUserNameOnly) + key = m_url.userName(); + else + key = m_url.prettyUrl(KUrl::RemoveTrailingSlash); + + if (m_wallet->hasEntry(key) && + !m_wallet->readPassword(key, password)) { + kDebug(5010) << "Password read OK"; + + return password; + } + } + } + return QString(); +} + +void RemoteView::saveWalletPassword(const QString &password, bool fromUserNameOnly) +{ + QString key; + if (fromUserNameOnly) + key = m_url.userName(); + else + key = m_url.prettyUrl(KUrl::RemoveTrailingSlash); + + if (m_wallet && m_wallet->isOpen()) { + kDebug(5010) << "Write wallet password"; + m_wallet->writePassword(key, password); + } +} +#endif + +QCursor RemoteView::localDotCursor() const +{ +#ifdef QTONLY + return QCursor(); //TODO +#else + QBitmap cursorBitmap(KGlobal::dirs()->findResource("appdata", + "pics/pointcursor.png")); + QBitmap cursorMask(KGlobal::dirs()->findResource("appdata", + "pics/pointcursormask.png")); + return QCursor(cursorBitmap, cursorMask); +#endif +} + +void RemoteView::focusInEvent(QFocusEvent *event) +{ + if (m_grabAllKeys) { + m_keyboardIsGrabbed = true; + grabKeyboard(); + } + + QWidget::focusInEvent(event); +} + +void RemoteView::focusOutEvent(QFocusEvent *event) +{ + if (m_grabAllKeys || m_keyboardIsGrabbed) { + m_keyboardIsGrabbed = false; + releaseKeyboard(); + } + + QWidget::focusOutEvent(event); +} + +#include "moc_remoteview.cpp" diff --git a/krdc/core/remoteview.h b/krdc/core/remoteview.h new file mode 100644 index 00000000..3a4866ae --- /dev/null +++ b/krdc/core/remoteview.h @@ -0,0 +1,415 @@ +/**************************************************************************** +** +** Copyright (C) 2002-2003 Tim Jansen +** Copyright (C) 2007-2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef REMOTEVIEW_H +#define REMOTEVIEW_H + +#ifdef QTONLY + #include + #define KUrl QUrl + #define KRDCCORE_EXPORT +#else + #include + #include + #include +#endif + +#include + +class HostPreferences; + +/** + * Generic widget that displays a remote framebuffer. + * Implement this if you want to add another backend. + * + * Things to take care of: + * @li The RemoteView is responsible for its size. In + * non-scaling mode, set the fixed size of the widget + * to the remote resolution. In scaling mode, set the + * maximum size to the remote size and minimum size to the + * smallest resolution that your scaler can handle. + * @li if you override mouseMoveEvent() + * you must ignore the QEvent, because the KRDC widget will + * need it for stuff like toolbar auto-hide and bump + * scrolling. If you use x11Event(), make sure that + * MotionNotify events will be forwarded. + * + */ +class KRDCCORE_EXPORT RemoteView : public QWidget +{ + Q_OBJECT + +public: + + Q_ENUMS(Quality) + + enum Quality { + Unknown, + High, + Medium, + Low + }; + + /** + * Describes the state of a local cursor, if there is such a concept in the backend. + * With local cursors, there are two cursors: the cursor on the local machine (client), + * and the cursor on the remote machine (server). Because there is usually some lag, + * some backends show both cursors simultanously. In the VNC backend the local cursor + * is a dot and the remote cursor is the 'real' cursor, usually an arrow. + */ + + Q_ENUMS(DotCursorState) + + enum DotCursorState { + CursorOn, ///< Always show local cursor (and the remote one). + CursorOff, ///< Never show local cursor, only the remote one. + /// Try to measure the lag and enable the local cursor if the latency is too high. + CursorAuto + }; + + /** + * State of the connection. The state of the connection is returned + * by @ref RemoteView::status(). + * + * Not every state transition is allowed. You are only allowed to transition + * a state to the following state, with three exceptions: + * @li You can move from every state directly to Disconnected + * @li You can move from every state except Disconnected to + * Disconnecting + * @li You can move from Disconnected to Connecting + * + * @ref RemoteView::setStatus() will follow this rules for you. + * (If you add/remove a state here, you must adapt it) + */ + + Q_ENUMS(RemoteStatus) + + enum RemoteStatus { + Connecting = 0, + Authenticating = 1, + Preparing = 2, + Connected = 3, + Disconnecting = -1, + Disconnected = -2 + }; + + Q_ENUMS(ErrorCode) + + enum ErrorCode { + None = 0, + Internal, + Connection, + Protocol, + IO, + Name, + NoServer, + ServerBlocked, + Authentication + }; + + virtual ~RemoteView(); + + /** + * Checks whether the backend supports scaling. The + * default implementation returns false. + * @return true if scaling is supported + * @see scaling() + */ + virtual bool supportsScaling() const; + + /** + * Checks whether the widget is in scale mode. The + * default implementation always returns false. + * @return true if scaling is activated. Must always be + * false if @ref supportsScaling() returns false + * @see supportsScaling() + */ + virtual bool scaling() const; + + /** + * Checks whether the backend supports the concept of local cursors. The + * default implementation returns false. + * @return true if local cursors are supported/known + * @see DotCursorState + * @see showDotCursor() + * @see dotCursorState() + */ + virtual bool supportsLocalCursor() const; + + /** + * Sets the state of the dot cursor, if supported by the backend. + * The default implementation does nothing. + * @param state the new state (CursorOn, CursorOff or + * CursorAuto) + * @see dotCursorState() + * @see supportsLocalCursor() + */ + virtual void showDotCursor(DotCursorState state); + + /** + * Returns the state of the local cursor. The default implementation returns + * always CursorOff. + * @return true if local cursors are supported/known + * @see showDotCursor() + * @see supportsLocalCursor() + */ + virtual DotCursorState dotCursorState() const; + + /** + * Checks whether the view is in view-only mode. This means + * that all input is ignored. + */ + virtual bool viewOnly(); + + /** + * Checks whether grabbing all possible keys is enabled. + */ + virtual bool grabAllKeys(); + + /** + * Returns the resolution of the remote framebuffer. + * It should return a null @ref QSize when the size + * is not known. + * The backend must also emit a @ref framebufferSizeChanged() + * when the size of the framebuffer becomes available + * for the first time or the size changed. + * @return the remote framebuffer size, a null QSize + * if unknown + */ + virtual QSize framebufferSize(); + + /** + * Initiate the disconnection. This doesn't need to happen + * immediately. The call must not block. + * @see isQuitting() + */ + virtual void startQuitting(); + + /** + * Checks whether the view is currently quitting. + * @return true if it is quitting + * @see startQuitting() + * @see setStatus() + */ + virtual bool isQuitting(); + + /** + * @return the host the view is connected to + */ + virtual QString host(); + + /** + * @return the port the view is connected to + */ + virtual int port(); + + /** + * Initialize the view (for example by showing configuration + * dialogs to the user) and start connecting. Should not block + * without running the event loop (so displaying a dialog is ok). + * When the view starts connecting the application must call + * @ref setStatus() with the status Connecting. + * @return true if successful (so far), false + * otherwise + * @see connected() + * @see disconnected() + * @see disconnectedError() + * @see statusChanged() + */ + virtual bool start() = 0; + + /** + * Called when the configuration is changed. + * The default implementation does nothing. + */ + virtual void updateConfiguration(); + + /** + * @return screenshot of the view + */ + virtual QPixmap takeScreenshot(); + +#ifndef QTONLY + /** + * Returns the current host preferences of this view. + */ + virtual HostPreferences* hostPreferences() = 0; +#endif + + /** + * Returns the current status of the connection. + * @return the status of the connection + * @see setStatus() + */ + RemoteStatus status(); + + /** + * @return the current url + */ + KUrl url(); + +public slots: + /** + * Called to enable or disable scaling. + * Ignored if @ref supportsScaling() is false. + * The default implementation does nothing. + * @param s true to enable, false to disable. + * @see supportsScaling() + * @see scaling() + */ + virtual void enableScaling(bool scale); + + /** + * Enables/disables the view-only mode. + * Ignored if @ref supportsScaling() is false. + * The default implementation does nothing. + * @param viewOnly true to enable, false to disable. + * @see supportsScaling() + * @see viewOnly() + */ + virtual void setViewOnly(bool viewOnly); + + /** + * Enables/disables grabbing all possible keys. + * @param grabAllKeys true to enable, false to disable. + * Default is false. + * @see grabAllKeys() + */ + virtual void setGrabAllKeys(bool grabAllKeys); + + /** + * Called to let the backend know it when + * we switch from/to fullscreen. + * @param on true when switching to fullscreen, + * false when switching from fullscreen. + */ + virtual void switchFullscreen(bool on); + + /** + * Sends a QKeyEvent to the remote server. + * @param event the key to send + */ + virtual void keyEvent(QKeyEvent *event); + + /** + * Called when the visible place changed so remote + * view can resize itself. + */ + virtual void scaleResize(int w, int h); + +Q_SIGNALS: + /** + * Emitted when the size of the remote screen changes. Also + * called when the size is known for the first time. + * @param x the width of the screen + * @param y the height of the screen + */ + void framebufferSizeChanged(int w, int h); + + /** + * Emitted when the view connected successfully. + */ + void connected(); + + /** + * Emitted when the view disconnected without error. + */ + void disconnected(); + + /** + * Emitted when the view disconnected with error. + */ + void disconnectedError(); + + /** + * Emitted when the view has a specific error. + */ + void errorMessage(const QString &title, const QString &message); + + /** + * Emitted when the status of the view changed. + * @param s the new status + */ + void statusChanged(RemoteView::RemoteStatus s); + + /** + * Emitted when the password dialog is shown or hidden. + * @param b true when the dialog is shown, false when it has been hidden + */ + void showingPasswordDialog(bool b); + + /** + * Emitted when the mouse on the remote side has been moved. + * @param x the new x coordinate + * @param y the new y coordinate + * @param buttonMask the mask of mouse buttons (bit 0 for first mouse + * button, 1 for second button etc)a + */ + void mouseStateChanged(int x, int y, int buttonMask); + +protected: + RemoteView(QWidget *parent = 0); + + void focusInEvent(QFocusEvent *event); + void focusOutEvent(QFocusEvent *event); + + /** + * The status of the remote view. + */ + RemoteStatus m_status; + + /** + * Set the status of the connection. + * Emits a statusChanged() signal. + * Note that the states need to be set in a certain order, + * see @ref Status. setStatus() will try to do this + * transition automatically, so if you are in Connecting + * and call setStatus(Preparing), setStatus() will + * emit a Authenticating and then Preparing. + * If you transition backwards, it will emit a + * Disconnected before doing the transition. + * @param s the new status + */ + virtual void setStatus(RemoteStatus s); + + QCursor localDotCursor() const; + + QString m_host; + int m_port; + bool m_viewOnly; + bool m_grabAllKeys; + bool m_scale; + bool m_keyboardIsGrabbed; + KUrl m_url; + +#ifndef QTONLY + QString readWalletPassword(bool fromUserNameOnly = false); + void saveWalletPassword(const QString &password, bool fromUserNameOnly = false); + KWallet::Wallet *m_wallet; +#endif + + DotCursorState m_dotCursorState; +}; + +#endif diff --git a/krdc/core/remoteviewfactory.cpp b/krdc/core/remoteviewfactory.cpp new file mode 100644 index 00000000..ddb49b1a --- /dev/null +++ b/krdc/core/remoteviewfactory.cpp @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "remoteviewfactory.h" + +#include + +RemoteViewFactory::RemoteViewFactory(QObject *parent) + : QObject(parent) +{ +} + +RemoteViewFactory::~RemoteViewFactory() +{ +} + +#include "moc_remoteviewfactory.cpp" diff --git a/krdc/core/remoteviewfactory.h b/krdc/core/remoteviewfactory.h new file mode 100644 index 00000000..596705f8 --- /dev/null +++ b/krdc/core/remoteviewfactory.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef REMOTEVIEWFACTORY_H +#define REMOTEVIEWFACTORY_H + +#include "remoteview.h" + +#include +#include +#include + +class KUrl; + +/** + * Convenience macros to export a KRDC plugin. Suppose you created the plugin + * FooRemoteViewFactory. In FooRemoteViewFactory you will have to put the following line: + * + * @code + * KRDC_PLUGIN_EXPORT(FooRemoteViewFactory) + * @endcode + * + * The rest will be done for you. + */ +#define KRDC_PLUGIN_EXPORT( c ) \ + K_PLUGIN_FACTORY( KrdcFactory, registerPlugin< c >(); ) \ + K_EXPORT_PLUGIN( KrdcFactory("c") ) + +/** + * Factory to be implemented by any plugin. + */ +class KRDCCORE_EXPORT RemoteViewFactory : public QObject +{ + Q_OBJECT + +public: + /** + * Deconstructor. + */ + virtual ~RemoteViewFactory(); + + /** + * Returns true if the provided @p url is supported by the current plugin. + */ + virtual bool supportsUrl(const KUrl &url) const = 0; + + /** + * Returns a new RemoteView implementing object. + */ + virtual RemoteView *createView(QWidget *parent, const KUrl &url, KConfigGroup configGroup) = 0; + + /** + * Returns a new HostPreferences implementing object or 0 if no settings are available. + */ + virtual HostPreferences *createHostPreferences(KConfigGroup configGroup, QWidget *parent) = 0; + + /** + * Returns the supported scheme. + * @see KUrl::scheme() + */ + virtual QString scheme() const = 0; + + /** + * Returns the text of the action in the file menu (by default). + */ + virtual QString connectActionText() const = 0; + + /** + * Returns the text of the connect button on the startscreen. + */ + virtual QString connectButtonText() const = 0; + + /** + * Returns the tooltip next to the url navigator when the user presses + * the connect action. + */ + virtual QString connectToolTipText() const = 0; + +protected: + /** + * Protected constructor so it cannot be instantiated. + */ + RemoteViewFactory(QObject *parent = 0); + +}; + +#endif // REMOTEVIEWFACTORY_H diff --git a/krdc/core/settings.kcfgc b/krdc/core/settings.kcfgc new file mode 100644 index 00000000..2173c271 --- /dev/null +++ b/krdc/core/settings.kcfgc @@ -0,0 +1,5 @@ +ClassName=Settings +File=krdc.kcfg +Mutators=true +Singleton=true +Visibility=KDE_EXPORT diff --git a/krdc/doc/CMakeLists.txt b/krdc/doc/CMakeLists.txt new file mode 100644 index 00000000..5af22c26 --- /dev/null +++ b/krdc/doc/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR krdc) diff --git a/krdc/doc/address_input.png b/krdc/doc/address_input.png new file mode 100644 index 00000000..e67b1ea3 Binary files /dev/null and b/krdc/doc/address_input.png differ diff --git a/krdc/doc/bookmarks_menu.png b/krdc/doc/bookmarks_menu.png new file mode 100644 index 00000000..717a5c71 Binary files /dev/null and b/krdc/doc/bookmarks_menu.png differ diff --git a/krdc/doc/general_preferences.png b/krdc/doc/general_preferences.png new file mode 100644 index 00000000..cb85cdf4 Binary files /dev/null and b/krdc/doc/general_preferences.png differ diff --git a/krdc/doc/index.docbook b/krdc/doc/index.docbook new file mode 100644 index 00000000..0c9e46ec --- /dev/null +++ b/krdc/doc/index.docbook @@ -0,0 +1,608 @@ + + + + + + + +]> + + + + + + + +The &krdc; Handbook + + + +&Brad.Hards; +&Brad.Hards.mail; + + + Urs + Wolfer + +
uwolfer @ kde.org
+
+
+ +
+ +&FDLNotice; + +2013-06-19 +&kde; 4.11 + + +2003, 2008 + + + + +&krdc; is a client application that allows you to view or even control +the desktop session on another machine that is running a compatible server. +VNC and RDP is supported. + + + + +KDE +kdenetwork +krfb +VNC +RFB +krdc +Desktop Sharing +Remote Control +Remote Assistance +Remote Desktop +RDP +Remote Administration + + +
+ + +Introduction + + +&krdc; is a client application that allows you to view or even control +the desktop session on another machine that is running a compatible +server. + + + +You would typically use &krdc; with the &kde; VNC server (&krfb;), which is +also known as Krfb, since it closely matches the special features of &krdc;. + + + +If you want to start &krdc; from &konsole;, the command is krdc. + + + +Please report any problems or feature requests to the &kde; mailing +lists or file a bug at http://bugs.kde.org. + + + + +The Remote Frame Buffer protocol + + +This chapter provides a brief description of the Remote Frame Buffer +protocol used by &krdc; and by other compatible systems. If you are +already familiar with Remote Frame Buffer, you can safely skip this +chapter. + + + +The high level implementation of a system using the Remote Frame +Buffer protocol is known as Virtual Network Computer, or more often +just as VNC. + + + +Remote Frame Buffer (or RFB for short) is a simple +protocol for remote access to graphical user interfaces. It works at +the frame-buffer level, which roughly corresponds to the rendered +screen image, which means that it can be applied to all windowing +systems (including X11, &MacOS; and &Microsoft; &Windows;). Remote +Frame Buffer applications exist for many platforms, and can often be +free re-distributed. + + + +In the Remote Frame Buffer protocol, the application that runs on the +machine where the user sits (containing the display, keyboard and +pointer) is called the client. The application that runs on the +machine where the framebuffer is located (which is running the +windowing system and applications that the user is remotely +controlling) is called the server. &krdc; is the &kde; client for the +Remote Frame Buffer protocol. &krfb; is the &kde; server for the +Remote Frame Buffer protocol. + + + +It takes a reasonable amount of network traffic to send an image of +the framebuffer, so Remote Frame Buffer works best over high +bandwidth links, such as a local area network. It is still possible to +use &krdc; over other links, but performance is unlikely to be as good. + + + + + +Using &krdc; + + +It is very easy to use &krdc; - it has a simple interface, as shown in +the screenshot below. + + + + +Here's a screenshot of &krdc; + + + + + + &krdc; main window + + + + + +Connecting &krdc; to compatible servers + + +&krdc; is a client, and it needs to be used with compatible +servers. There are different ways to connect to those servers: + + + + +Directly typing the server name (or IP address) into the +Connect to: input. + + +By using an invitation that you received. &krfb; uses +invitations, and can send them by email. + + + + +Let's look at each of these in turn. + + +Server name entry + +If you know the host name (or IP address) of the server you want to +connect to, you can enter it directly into the Connect to: input. + + + +If you want to connect to a machine named megan, which is +running a VNC server on screen 1 (5901), you can enter +megan:1 or megan:5901 and +choose vnc as the protocol in the +drop down box. + + + +Entering a hostname into &krdc; + + + + + + Entering a hostname into &krdc; + + + + + + +Similary, if you are using a RDP server on that +machine, you can enter megan. Choose rdp as +the protocol. RDP does not need the screen number to be specified. +If the server runs the RDP server not on the default port, you may +specify it in the following way: megan:3910 + +You need to enter an &URL; in percent encoded syntax, i.e. @ as %40, for ⪚ +username%40ad.domain.example + + + + + +Using an invitation + +Within the &krfb; server application, it is possible to send +invitations over email (and in other ways, although email is the most +useful). If you receive this type of email invitation, you can just +click on the link provided in the mail. +This will start &krdc; if it is not already running, and connect to +the server specified in the invitation. + + + + + + +What happens when you connect + + +Notice: Before connecting, ensure that the target computer (server) is +available on the network and, if necessary, that its firewall has +been correctly configured or disabled. + + + +No matter how you select the server to connect to, the next thing that +happens is that &krdc; asks you about the network connection to the +server, as shown below: + + + + +&krdc; connection speed selection + + + + + + &krdc; connection speed selection + + + + + + +There are three speed settings for the VNC protocol: + + + +High Quality (LAN, direct connection), which is the +default, and you should evaluate how well this setting performs before +selecting a lower performance option that uses less bandwidth. + +Medium Quality (DSL, Cable, fast +Internet). +Low Quality (Modem, ISDN, slow +Internet). + + + +If you always operate over the same link type, you can deselect the +checkbox labeled Show this dialog again for this +host, which means that you won't be asked about the +connection type again for this host, providing you identify it in the +same way. For example, if a host has two names, and deselect the +checkbox when connecting using one name, you won't get asked if you +connect using that name, although you will be asked if you use the +other name, or the IP address. + + + +You select the appropriate speed setting, and select the +OK to proceed. + + + +You can see the connection status in the icon in the tab. + + + +Depending on the configuration of the server, you may (and almost +certainly will) need to provide a password to authenticate to the +server. &krdc; will provide a password dialog similar to that shown +below. + + + +&krdc; has the ability to save the password for further connections +to the same host. It uses KWallet for doing this. You need to check the +Remember password (KWallet) check box if you like +to use this feature. + + + + +&krdc; password entry + + + + + + &krdc; password entry + + + + + + +After authentication, you will be connected to the remote server, and +can begin using &krdc; to observe or control the remote desktop. + + + + +Controlling the remote desktop connection + + +Having connected to the remote server, you would normally use the +keyboard and mouse to control the windowing system and applications on +that remote machine. + + + +You can view the remote desktop either as a full screen, or as a +window on the local desktop. You can change between these modes using +icons shown below. + + + + +&krdc; full screen mode selection + + + + + + &krdc; full screen mode selection + + + + + + + +&krdc; window mode selection + + + + + + &krdc; window mode selection + + + + + + +Full screen mode is normally better when you are helping a remote +user, because you can see all of what they can see. Window mode is +most useful when you are working both remotely and locally - perhaps +referring to some local documentation and then using those +instructions on the remote machine. + + +Using window mode + + +In window mode, you can terminate the connection by closing the window, by clicking +on the logout button. + + + + +Using full screen mode + + +In full screen mode, you can change the appearance of the toolbar. +The transparency of the toolbar can be changed with scrollwheel. + + + + + + +Bookmarks + + +&krdc; has the ability to manage bookmarks. If you need to connect often to +the same remote desktop, you can add an entry for this connection to the +bookmark list. You can do so with a click on Bookmarks +Add Bookmark. + + + + +&krdc; bookmarks menu + + + + + + &krdc; bookmarks menu + + + + + + +History Bookmarks + + +&krdc; saves last used remote desktop connections. You can access these special +bookmarks at BookmarksHistory. Of course you can also +delete a bookmark of this list if you don't need it anymore in the list. Just click +Delete Bookmark which appears after a click with the right mouse button on +the bookmark you would like to delete. + + + + + + +Managing &krdc; configuration + +Using SettingsConfigure KRDC..., +you can open a dialog to modify the behavior of &krdc;. Selecting that button brings up a +window as shown below: + + + + +&krdc; preferences - General tab + + + + + + &krdc; preferences - General tab + + + + + + + +&krdc; preferences - VNC Defaults tab + + + + + + &krdc; preferences - VNC +Defaults profiles tab + + + + + + + +&krdc; preferences - RDP Defaults tab + + + + + + &krdc; preferences - RDP +Defaults profiles tab + + + + + + + + + + + +Questions and Answers + + + + +&reporting.bugs; +&updating.documentation; + + + + +Why does RDP support not work? + + +RDP support in &krdc; depends on xfreerdp (FreeRDP). Make sure that you have installed +this runtime dependency. + + + + + + + + + + + +Credits and License + + +&krdc; + + +The &krdc; project has been started by Tim Jansen tim@tjansen.de. +As a Google Summer of Code 2007 project, Urs Wolfer uwolfer @ kde.org +has completely rewritten &krdc;. Thanks to Google for making this possible, and thanks +to the great mentor of this Summer of Code project, &Brad.Hards; &Brad.Hards.mail;. + + + +Documentation Copyright © 2003 &Brad.Hards; &Brad.Hards.mail; +Documentation Copyright © 2007 Urs Wolfer uwolfer @ kde.org + + + + +&underFDL; + +&underGPL; + + + + +Installation + + +How to obtain &krdc; + + + +&install.intro.documentation; + + + + +Compilation and Installation + + + + + +&install.compile.documentation; + + + + + +&documentation.index; +
+ + diff --git a/krdc/doc/krdc_mainwindow.png b/krdc/doc/krdc_mainwindow.png new file mode 100644 index 00000000..aecdbc02 Binary files /dev/null and b/krdc/doc/krdc_mainwindow.png differ diff --git a/krdc/doc/password_entry.png b/krdc/doc/password_entry.png new file mode 100644 index 00000000..60137669 Binary files /dev/null and b/krdc/doc/password_entry.png differ diff --git a/krdc/doc/rdp_preferences.png b/krdc/doc/rdp_preferences.png new file mode 100644 index 00000000..9448ed78 Binary files /dev/null and b/krdc/doc/rdp_preferences.png differ diff --git a/krdc/doc/view-fullscreen.png b/krdc/doc/view-fullscreen.png new file mode 100644 index 00000000..aed8fc36 Binary files /dev/null and b/krdc/doc/view-fullscreen.png differ diff --git a/krdc/doc/view-restore.png b/krdc/doc/view-restore.png new file mode 100644 index 00000000..d1e3f485 Binary files /dev/null and b/krdc/doc/view-restore.png differ diff --git a/krdc/doc/vnc_host_configuration.png b/krdc/doc/vnc_host_configuration.png new file mode 100644 index 00000000..491ee909 Binary files /dev/null and b/krdc/doc/vnc_host_configuration.png differ diff --git a/krdc/doc/vnc_preferences.png b/krdc/doc/vnc_preferences.png new file mode 100644 index 00000000..b1530098 Binary files /dev/null and b/krdc/doc/vnc_preferences.png differ diff --git a/krdc/floatingtoolbar.cpp b/krdc/floatingtoolbar.cpp new file mode 100644 index 00000000..bd95e9b1 --- /dev/null +++ b/krdc/floatingtoolbar.cpp @@ -0,0 +1,486 @@ +/**************************************************************************** +** +** Copyright (C) 2007-2008 Urs Wolfer +** Parts of this file have been take from okular: +** Copyright (C) 2004-2005 Enrico Ros +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "floatingtoolbar.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +static const int actionIconSize = 22; +static const int toolBarRBMargin = 2; +static const double toolBarOpacity = 0.8; +static const int visiblePixelWhenAutoHidden = 6; +static const int autoHideTimeout = 500; +static const int initialAutoHideTimeout = 2000; + +/** + * Denotes the verious states of the animation. + */ +enum AnimState { + Hiding, + Showing, + Still +}; + +class FloatingToolBarPrivate +{ +public: + FloatingToolBarPrivate(FloatingToolBar *qq) + : q(qq) + , anchorSide(FloatingToolBar::Left) + , offsetPlaceHolder(new QWidget(qq)) + , animState(Still) + , toDelete(false) + , visible(false) + , sticky(false) + , opacity(toolBarOpacity) + // set queuedShow to true so we show the toolbar if we get a resize event on the anchorWidget + , queuedShow(true) { + } + + // rebuild contents and reposition then widget + void buildToolBar(); + void reposition(); + // compute the visible and hidden positions along current side + QPoint getInnerPoint() const; + QPoint getOuterPoint() const; + + FloatingToolBar *q; + + QWidget *anchorWidget; + FloatingToolBar::Side anchorSide; + QWidget *offsetPlaceHolder; + + QTimer *animTimer; + QTimer *autoHideTimer; + QPoint currentPosition; + QPoint endPosition; + AnimState animState; + bool toDelete; + bool visible; + bool sticky; + qreal opacity; + bool queuedShow; + + QPixmap backgroundPixmap; +}; + +FloatingToolBar::FloatingToolBar(QWidget *parent, QWidget *anchorWidget) + : QToolBar(parent), d(new FloatingToolBarPrivate(this)) +{ + ; + addWidget(d->offsetPlaceHolder); + + setMouseTracking(true); + setIconSize(QSize(actionIconSize, actionIconSize)); + d->anchorWidget = anchorWidget; + + d->animTimer = new QTimer(this); + connect(d->animTimer, SIGNAL(timeout()), this, SLOT(animate())); + + d->autoHideTimer = new QTimer(this); + connect(d->autoHideTimer, SIGNAL(timeout()), this, SLOT(hide())); + + // apply a filter to get notified when anchor changes geometry + d->anchorWidget->installEventFilter(this); +} + +FloatingToolBar::~FloatingToolBar() +{ + delete d; +} + +void FloatingToolBar::addAction(QAction *action) +{ + QToolBar::addAction(action); + + // rebuild toolbar shape and contents only if the toolbar is already visible, + // otherwise it will be done in showAndAnimate() + if (isVisible()) + d->reposition(); +} + +void FloatingToolBar::setSide(Side side) +{ + d->anchorSide = side; + + if (isVisible()) + d->reposition(); +} + +void FloatingToolBar::setSticky(bool sticky) +{ + d->sticky = sticky; + + if (sticky) + d->autoHideTimer->stop(); +} + +void FloatingToolBar::showAndAnimate() +{ + if (d->animState == Showing) + return; + + d->animState = Showing; + + show(); + + // force update for case when toolbar has not been built yet + d->reposition(); + + // start scrolling in + d->animTimer->start(20); + + // This permits to show the toolbar for a while when going full screen. + if (!d->sticky) + d->autoHideTimer->start(initialAutoHideTimeout); +} + +void FloatingToolBar::hideAndDestroy() +{ + if (d->animState == Hiding) + return; + + // set parameters for sliding out + d->animState = Hiding; + d->toDelete = true; + d->endPosition = d->getOuterPoint(); + + // start scrolling out + d->animTimer->start(20); +} + +void FloatingToolBar::hide() +{ + if (underMouse()) + return; + + if (d->visible) { + QPoint diff; + switch (d->anchorSide) { + case Left: + diff = QPoint(visiblePixelWhenAutoHidden, 0); + break; + case Right: + diff = QPoint(-visiblePixelWhenAutoHidden, 0); + break; + case Top: + diff = QPoint(0, visiblePixelWhenAutoHidden); + break; + case Bottom: + diff = QPoint(0, -visiblePixelWhenAutoHidden); + break; + } + d->animState = Hiding; + d->endPosition = d->getOuterPoint() + diff; + + // start scrolling out + d->animTimer->start(20); + } +} + +bool FloatingToolBar::eventFilter(QObject *obj, QEvent *e) +{ + if (obj == d->anchorWidget && e->type() == QEvent::Resize) { + if (d->queuedShow) { // if the toolbar is not visible yet, try to show it if the anchor widget is in fullscreen already + d->queuedShow = false; + showAndAnimate(); + return true; + } + + // if anchorWidget changed geometry reposition toolbar + d->animTimer->stop(); + if ((d->animState == Hiding || !d->visible) && d->toDelete) + deleteLater(); + else + d->reposition(); + } + + return QToolBar::eventFilter(obj, e); +} + +void FloatingToolBar::paintEvent(QPaintEvent *e) +{ + QToolBar::paintEvent(e); + + // paint the internal pixmap over the widget + QPainter p(this); + p.setOpacity(d->opacity); + p.drawImage(e->rect().topLeft(), d->backgroundPixmap.toImage(), e->rect()); +} + +void FloatingToolBar::mousePressEvent(QMouseEvent *e) +{ + if (e->button() == Qt::LeftButton) + setCursor(Qt::SizeAllCursor); + + QToolBar::mousePressEvent(e); +} + +void FloatingToolBar::mouseMoveEvent(QMouseEvent *e) +{ + // show the toolbar again when it is auto-hidden + if (!d->visible) { + showAndAnimate(); + return; + } + + if ((QApplication::mouseButtons() & Qt::LeftButton) != Qt::LeftButton) + return; + + // compute the nearest side to attach the widget to + const QPoint parentPos = mapToParent(e->pos()); + const float nX = (float)parentPos.x() / (float)d->anchorWidget->width(); + const float nY = (float)parentPos.y() / (float)d->anchorWidget->height(); + if (nX > 0.3 && nX < 0.7 && nY > 0.3 && nY < 0.7) + return; + bool LT = nX < (1.0 - nY); + bool LB = nX < (nY); + Side side = LT ? (LB ? Left : Top) : (LB ? Bottom : Right); + + // check if side changed + if (side == d->anchorSide) + return; + + d->anchorSide = side; + d->reposition(); + emit orientationChanged((int)side); + + QToolBar::mouseMoveEvent(e); +} + +void FloatingToolBar::enterEvent(QEvent *e) +{ + // Stop the autohide timer while the mouse is inside + d->autoHideTimer->stop(); + + if (!d->visible) + showAndAnimate(); + QToolBar::enterEvent(e); +} + +void FloatingToolBar::leaveEvent(QEvent *e) +{ + if (!d->sticky) + d->autoHideTimer->start(autoHideTimeout); + QToolBar::leaveEvent(e); +} + +void FloatingToolBar::mouseReleaseEvent(QMouseEvent *e) +{ + if (e->button() == Qt::LeftButton) + setCursor(Qt::ArrowCursor); + + QToolBar::mouseReleaseEvent(e); +} + +void FloatingToolBar::wheelEvent(QWheelEvent *e) +{ + e->accept(); + + const qreal diff = e->delta() / 100.0 / 15.0; +// kDebug(5010) << diff; + if (((d->opacity <= 1) && (diff > 0)) || ((d->opacity >= 0) && (diff < 0))) + d->opacity += diff; + + update(); + + QToolBar::wheelEvent(e); +} + +void FloatingToolBarPrivate::buildToolBar() +{ + const bool prevUpdates = q->updatesEnabled(); + q->setUpdatesEnabled(false); + + // 1. init numbers we are going to use + const bool topLeft = anchorSide == FloatingToolBar::Left || anchorSide == FloatingToolBar::Top; + const bool vertical = anchorSide == FloatingToolBar::Left || anchorSide == FloatingToolBar::Right; + + if (vertical) { + offsetPlaceHolder->setFixedSize(1, 7); + q->setOrientation(Qt::Vertical); + } else { + offsetPlaceHolder->setFixedSize(7, 1); + q->setOrientation(Qt::Horizontal); + } + + // 2. compute widget size + const int myWidth = q->sizeHint().width() - 1; + const int myHeight = q->sizeHint().height() - 1; + + // 3. resize pixmap, mask and widget + QBitmap mask(myWidth + 1, myHeight + 1); + backgroundPixmap = QPixmap(myWidth + 1, myHeight + 1); + backgroundPixmap.fill(Qt::transparent); + + q->resize(myWidth + 1, myHeight + 1); + + // 4. create and set transparency mask + QPainter maskPainter(&mask); + mask.fill(Qt::white); + maskPainter.setBrush(Qt::black); + if (vertical) + maskPainter.drawRoundRect(topLeft ? -10 : 0, 0, myWidth + 10, myHeight, 2000 / (myWidth + 10), 2000 / myHeight); + else + maskPainter.drawRoundRect(0, topLeft ? -10 : 0, myWidth, myHeight + 10, 2000 / myWidth, 2000 / (myHeight + 10)); + maskPainter.end(); + q->setMask(mask); + + // 5. draw background + QPainter bufferPainter(&backgroundPixmap); + bufferPainter.translate(0.5, 0.5); + QPalette pal = q->palette(); + // 5.1. draw horizontal/vertical gradient + QLinearGradient grad; + switch (anchorSide) { + case FloatingToolBar::Left: + grad = QLinearGradient(0, 1, myWidth + 1, 1); + break; + case FloatingToolBar::Right: + grad = QLinearGradient(myWidth + 1, 1, 0, 1); + break; + case FloatingToolBar::Top: + grad = QLinearGradient(1, 0, 1, myHeight + 1); + break; + case FloatingToolBar::Bottom: + grad = QLinearGradient(1, myHeight + 1, 0, 1); + break; + } + grad.setColorAt(0, pal.color(QPalette::Active, QPalette::Button)); + grad.setColorAt(1, pal.color(QPalette::Active, QPalette::Light)); + bufferPainter.setBrush(QBrush(grad)); + // 5.2. draw rounded border + bufferPainter.setPen( pal.color(QPalette::Active, QPalette::Dark).lighter(40)); + bufferPainter.setRenderHints(QPainter::Antialiasing); + if (vertical) + bufferPainter.drawRoundRect(topLeft ? -10 : 0, 0, myWidth + 10, myHeight, 2000 / (myWidth + 10), 2000 / myHeight); + else + bufferPainter.drawRoundRect(0, topLeft ? -10 : 0, myWidth, myHeight + 10, 2000 / myWidth, 2000 / (myHeight + 10)); + // 5.3. draw handle + bufferPainter.translate(-0.5, -0.5); + bufferPainter.setPen(pal.color(QPalette::Active, QPalette::Mid)); + if (vertical) { + int dx = anchorSide == FloatingToolBar::Left ? 2 : 4; + bufferPainter.drawLine(dx, 6, dx + myWidth - 8, 6); + bufferPainter.drawLine(dx, 9, dx + myWidth - 8, 9); + bufferPainter.setPen(pal.color(QPalette::Active, QPalette::Light)); + bufferPainter.drawLine(dx + 1, 7, dx + myWidth - 7, 7); + bufferPainter.drawLine(dx + 1, 10, dx + myWidth - 7, 10); + } else { + int dy = anchorSide == FloatingToolBar::Top ? 2 : 4; + bufferPainter.drawLine(6, dy, 6, dy + myHeight - 8); + bufferPainter.drawLine(9, dy, 9, dy + myHeight - 8); + bufferPainter.setPen(pal.color(QPalette::Active, QPalette::Light)); + bufferPainter.drawLine(7, dy + 1, 7, dy + myHeight - 7); + bufferPainter.drawLine(10, dy + 1, 10, dy + myHeight - 7); + } + + q->setUpdatesEnabled(prevUpdates); +} + +void FloatingToolBarPrivate::reposition() +{ + // note: hiding widget here will gives better gfx, but ends drag operation + // rebuild widget and move it to its final place + buildToolBar(); + if (!visible) { + currentPosition = getOuterPoint(); + endPosition = getInnerPoint(); + } else { + currentPosition = getInnerPoint(); + endPosition = getOuterPoint(); + } + q->move(currentPosition); +} + +QPoint FloatingToolBarPrivate::getInnerPoint() const +{ + // returns the final position of the widget + if (anchorSide == FloatingToolBar::Left) + return QPoint(0, (anchorWidget->height() - q->height()) / 2); + if (anchorSide == FloatingToolBar::Top) + return QPoint((anchorWidget->width() - q->width()) / 2, 0); + if (anchorSide == FloatingToolBar::Right) + return QPoint(anchorWidget->width() - q->width() + toolBarRBMargin, (anchorWidget->height() - q->height()) / 2); + return QPoint((anchorWidget->width() - q->width()) / 2, anchorWidget->height() - q->height() + toolBarRBMargin); +} + +QPoint FloatingToolBarPrivate::getOuterPoint() const +{ + // returns the point from which the transition starts + if (anchorSide == FloatingToolBar::Left) + return QPoint(-q->width(), (anchorWidget->height() - q->height()) / 2); + if (anchorSide == FloatingToolBar::Top) + return QPoint((anchorWidget->width() - q->width()) / 2, -q->height()); + if (anchorSide == FloatingToolBar::Right) + return QPoint(anchorWidget->width() + toolBarRBMargin, (anchorWidget->height() - q->height()) / 2); + return QPoint((anchorWidget->width() - q->width()) / 2, anchorWidget->height() + toolBarRBMargin); +} + +void FloatingToolBar::animate() +{ + if (KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) { + // move currentPosition towards endPosition + int dX = d->endPosition.x() - d->currentPosition.x(); + int dY = d->endPosition.y() - d->currentPosition.y(); + dX = dX / 6 + qMax(-1, qMin(1, dX)); + dY = dY / 6 + qMax(-1, qMin(1, dY)); + d->currentPosition.setX(d->currentPosition.x() + dX); + d->currentPosition.setY(d->currentPosition.y() + dY); + } else { + d->currentPosition = d->endPosition; + } + + move(d->currentPosition); + + // handle arrival to the end + if (d->currentPosition == d->endPosition) { + d->animTimer->stop(); + switch (d->animState) { + case Hiding: + d->visible = false; + d->animState = Still; + if (d->toDelete) + deleteLater(); + break; + case Showing: + d->visible = true; + d->animState = Still; + break; + default: + kDebug(5010) << "Illegal state"; + } + } +} + +#include "floatingtoolbar.moc" diff --git a/krdc/floatingtoolbar.h b/krdc/floatingtoolbar.h new file mode 100644 index 00000000..99dfa7e9 --- /dev/null +++ b/krdc/floatingtoolbar.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2007-2008 Urs Wolfer +** Parts of this file have been take from okular: +** Copyright (C) 2004-2005 Enrico Ros +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef FLOATINGTOOLBAR_H +#define FLOATINGTOOLBAR_H + +#include + +/** + * @short A toolbar widget that slides in from a side. + * + * This is a shaped widget that slides in from a side of the 'anchor widget' + * it's attached to. It can be dragged and docked on {left,top,right,bottom} + * sides and contains actions. + */ +class FloatingToolBar : public QToolBar +{ + Q_OBJECT +public: + FloatingToolBar(QWidget *parent, QWidget *anchorWidget); + ~FloatingToolBar(); + + Q_ENUMS(Side) + enum Side { Left = 0, Top = 1, Right = 2, Bottom = 3 }; + + void addAction(QAction *action); + void setSide(Side side); + +Q_SIGNALS: + void orientationChanged(int side); + +public Q_SLOTS: + void setSticky(bool sticky); + void showAndAnimate(); + void hideAndDestroy(); + +protected: + bool eventFilter(QObject *o, QEvent *e); + void paintEvent(QPaintEvent *); + void mousePressEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void wheelEvent(QWheelEvent *e); + +private: + class FloatingToolBarPrivate *d; + +private Q_SLOTS: + void animate(); + void hide(); +}; + +#endif diff --git a/krdc/konsole/CMakeLists.txt b/krdc/konsole/CMakeLists.txt new file mode 100644 index 00000000..358c63f9 --- /dev/null +++ b/krdc/konsole/CMakeLists.txt @@ -0,0 +1,20 @@ + +set(BUILD_KONSOLE true) +if(BUILD_KONSOLE) + set(konsoleplugin_SRCS + konsoleviewfactory.cpp + konsoleview.cpp + ) + + kde4_add_plugin(krdc_konsoleplugin ${konsoleplugin_SRCS}) + + target_link_libraries(krdc_konsoleplugin + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + ${KDE4_KPARTS_LIBS} + krdccore + ) + install(TARGETS krdc_konsoleplugin DESTINATION ${PLUGIN_INSTALL_DIR}) + + install(FILES krdc_konsole.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +endif(BUILD_KONSOLE) diff --git a/krdc/konsole/konsoleview.cpp b/krdc/konsole/konsoleview.cpp new file mode 100644 index 00000000..aee295fd --- /dev/null +++ b/krdc/konsole/konsoleview.cpp @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "konsoleview.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +KonsoleView::KonsoleView(QWidget *parent, const KUrl &url, KConfigGroup configGroup) + : RemoteView(parent) +{ + m_url = url; + m_host = url.host(); + m_port = url.port(); + + m_hostPreferences = new KonsoleHostPreferences(configGroup, this); + +// QSize size = QSize(640, 480); + const QSize size = (qobject_cast(parent))->size(); + setStatus(Connected); + setFixedSize(size); + setFixedSize(size); + emit framebufferSizeChanged(size.width(), size.height()); + + KPluginFactory* factory = 0; + KService::Ptr service = KService::serviceByDesktopName("konsolepart"); + if (service) { + factory = KPluginLoader(service->library()).factory(); + } + KParts::ReadOnlyPart* part = factory ? (factory->create(this)) : 0; + if (part != 0) { +// connect(part, SIGNAL(destroyed(QObject*)), this, SLOT(terminalExited())); + QVBoxLayout *mainLayout = new QVBoxLayout(this); + mainLayout->setMargin(0); + mainLayout->setSpacing(0); + m_terminalWidget = part->widget(); + mainLayout->addWidget(m_terminalWidget); + m_terminal = qobject_cast(part); + m_terminal->showShellInDir(QDir::homePath()); + m_terminal->sendInput("echo " + url.user() + '@' + url.host()/* + ':' + url.port()*/ + '\n'); +// m_terminal->sendInput("clear\n"); + m_terminalWidget->resize(size); + } +} + +KonsoleView::~KonsoleView() +{ + emit disconnected(); + setStatus(Disconnected); +} + +bool KonsoleView::eventFilter(QObject *obj, QEvent *event) +{ + if (m_viewOnly) { + if (event->type() == QEvent::KeyPress || + event->type() == QEvent::KeyRelease || + event->type() == QEvent::MouseButtonDblClick || + event->type() == QEvent::MouseButtonPress || + event->type() == QEvent::MouseButtonRelease || + event->type() == QEvent::MouseMove) + return true; + } + return RemoteView::eventFilter(obj, event); +} + +QSize KonsoleView::framebufferSize() +{ + return minimumSizeHint(); +} + +QSize KonsoleView::sizeHint() const +{ + return RemoteView::sizeHint(); + return maximumSize(); +} + +bool KonsoleView::isQuitting() +{ + return false; +} + +bool KonsoleView::start() +{ + setStatus(Connected); + emit connected(); + m_terminalWidget->setFocus(); + return true; +} + +HostPreferences* KonsoleView::hostPreferences() +{ + return m_hostPreferences; +} + +void KonsoleView::switchFullscreen(bool on) +{ + Q_UNUSED(on); +} + +#include "konsoleview.moc" diff --git a/krdc/konsole/konsoleview.h b/krdc/konsole/konsoleview.h new file mode 100644 index 00000000..5f52afcd --- /dev/null +++ b/krdc/konsole/konsoleview.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef KONSOLEVIEW_H +#define KONSOLEVIEW_H + +#include "konsoleview.h" + +#include "remoteview.h" +#include "hostpreferences.h" + +#include + +class KonsoleHostPreferences; +class TerminalInterface; + +class KonsoleView : public RemoteView +{ + Q_OBJECT + +public: + explicit KonsoleView(QWidget *parent = 0, const KUrl &url = KUrl(), KConfigGroup configGroup = KConfigGroup()); + + virtual ~KonsoleView(); + + virtual QSize framebufferSize(); + QSize sizeHint() const; + + virtual bool isQuitting(); + virtual bool start(); + HostPreferences* hostPreferences(); + +public slots: + virtual void switchFullscreen(bool on); + +protected: + bool eventFilter(QObject *obj, QEvent *event); + +private: + KonsoleHostPreferences *m_hostPreferences; + TerminalInterface* m_terminal; + QWidget *m_terminalWidget; +}; + + +class KonsoleHostPreferences : public HostPreferences +{ + Q_OBJECT +public: + explicit KonsoleHostPreferences(KConfigGroup configGroup, QObject *parent = 0) + : HostPreferences(configGroup, parent) {} + +protected: + virtual QWidget* createProtocolSpecificConfigPage() { return 0; }; +}; + +#endif // KONSOLEVIEW_H diff --git a/krdc/konsole/konsoleviewfactory.cpp b/krdc/konsole/konsoleviewfactory.cpp new file mode 100644 index 00000000..f5e63f06 --- /dev/null +++ b/krdc/konsole/konsoleviewfactory.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "konsoleviewfactory.h" + +#include +#include + +KRDC_PLUGIN_EXPORT(KonsoleViewFactory) + +KonsoleViewFactory::KonsoleViewFactory(QObject *parent, const QVariantList &args) + : RemoteViewFactory(parent) +{ + Q_UNUSED(args); + + KGlobal::locale()->insertCatalog("krdc"); +} + +KonsoleViewFactory::~KonsoleViewFactory() +{ +} + +bool KonsoleViewFactory::supportsUrl(const KUrl &url) const +{ + return (url.scheme().compare("konsole", Qt::CaseInsensitive) == 0); +} + +RemoteView *KonsoleViewFactory::createView(QWidget *parent, const KUrl &url, KConfigGroup configGroup) +{ + return new KonsoleView(parent, url, configGroup); +} + +HostPreferences *KonsoleViewFactory::createHostPreferences(KConfigGroup configGroup, QWidget *parent) +{ + Q_UNUSED(configGroup); + Q_UNUSED(parent); + + return 0; +} + +QString KonsoleViewFactory::scheme() const +{ + return "konsole"; +} + +QString KonsoleViewFactory::connectActionText() const +{ + return i18n("New Konsole Connection..."); //FIXME +} + +QString KonsoleViewFactory::connectButtonText() const +{ + return i18n("KRDC Konsole Connection"); +} + +QString KonsoleViewFactory::connectToolTipText() const +{ + return i18n("Enter the address here. Port is optional.
" + "Example: konsoleserver (host)"); +} + +#include "moc_konsoleviewfactory.cpp" diff --git a/krdc/konsole/konsoleviewfactory.h b/krdc/konsole/konsoleviewfactory.h new file mode 100644 index 00000000..8a5f7050 --- /dev/null +++ b/krdc/konsole/konsoleviewfactory.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef KONSOLEVIEWFACTORY_H +#define KONSOLEVIEWFACTORY_H + +#include "remoteviewfactory.h" + +#include "konsoleview.h" + +class KonsoleViewFactory : public RemoteViewFactory +{ + Q_OBJECT + +public: + explicit KonsoleViewFactory(QObject *parent, const QVariantList &args); + + virtual ~KonsoleViewFactory(); + + virtual bool supportsUrl(const KUrl &url) const; + + virtual RemoteView *createView(QWidget *parent, const KUrl &url, KConfigGroup configGroup); + + virtual HostPreferences *createHostPreferences(KConfigGroup configGroup, QWidget *parent); + + virtual QString scheme() const; + + virtual QString connectActionText() const; + + virtual QString connectButtonText() const; + + virtual QString connectToolTipText() const; +}; + +#endif // KONSOLEVIEWFACTORY_H diff --git a/krdc/konsole/krdc_konsole.desktop b/krdc/konsole/krdc_konsole.desktop new file mode 100644 index 00000000..0f3fe4a8 --- /dev/null +++ b/krdc/konsole/krdc_konsole.desktop @@ -0,0 +1,126 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KRDC/Plugin +Icon=krdc +Name=Konsole +Name[ast]=Konsole +Name[bg]=Konsole +Name[bs]=Konzola +Name[ca]=Konsole +Name[ca@valencia]=Konsole +Name[cs]=Konsole +Name[da]=Konsole +Name[de]=Konsole +Name[el]=Konsole +Name[en_GB]=Konsole +Name[eo]=Konsole +Name[es]=Konsole +Name[et]=Konsool +Name[eu]=Konsole +Name[fi]=Konsoli +Name[fr]=Konsole +Name[ga]=Konsole +Name[gl]=Konsole +Name[hr]=Konsole +Name[hsb]=Konsola +Name[hu]=Konsole +Name[ia]=Konsole +Name[is]=Konsole +Name[it]=Konsole +Name[ja]=Konsole +Name[kk]=Konsole +Name[km]=កុងសូល +Name[ko]=Konsole +Name[lt]=Konsole +Name[lv]=Konsole +Name[mai]=कंसोल +Name[mr]=कंसोल +Name[nb]=Konsole +Name[nds]=Konsole +Name[nl]=Konsole +Name[nn]=Konsoll +Name[pa]=ਕਨਸੋਲ +Name[pl]=Konsola +Name[pt]=Konsole +Name[pt_BR]=Konsole +Name[ro]=Konsolă +Name[ru]=Konsole +Name[si]=Konsole +Name[sk]=Konsole +Name[sl]=Konsole +Name[sr]=Конзола +Name[sr@ijekavian]=Конзола +Name[sr@ijekavianlatin]=Konsole +Name[sr@latin]=Konsole +Name[sv]=Terminal +Name[th]=คอนโซล-K +Name[tr]=Konsole +Name[ug]=Konsole +Name[uk]=Konsole +Name[x-test]=xxKonsolexx +Name[zh_CN]=Konsole +Name[zh_TW]=終端機_Konsole +Comment=Allows managing SSH or Telnet sessions through KRDC +Comment[ast]=Permite la xestión de sesiones SSH o Telnet per KRDC +Comment[bg]=Управление на сесии на SSH и Telnet през KRDC +Comment[bs]=Dopušta uređivanje SSH ili Telnet sesija kroz KRDC +Comment[ca]=Permet gestionar sessions SSH o Telnet mitjançant el KRDC +Comment[ca@valencia]=Permet gestionar sessions SSH o Telnet mitjançant el KRDC +Comment[cs]=Umožňuje spravovat sezení SSH nebo Telnet pomocí KRDC +Comment[da]=Muliggør håndtering af SSH- eller Telnet-sessioner via KRDC +Comment[de]=Erlaubt die Verwaltung von SSH- und Telnet-Sitzungen über KRDC +Comment[el]=Επιτρέπει τη διαχείριση συνεδριών SSH ή Telnet μέσω του KRDC +Comment[en_GB]=Allows managing SSH or Telnet sessions through KRDC +Comment[es]=Permite la gestión de sesiones SSH o Telnet mediante KRDC +Comment[et]=SSH- või Telneti seansside haldamise võimaldamine KRDC kaudu +Comment[eu]=SSH edo Telnet saioak KRDC bidez kudeatzea baimentzen du +Comment[fi]=Mahdollistaa SSH- ja Telnet-istuntojen hallinnan KRDC:llä +Comment[fr]=Permet de gérer des sessions « SSH » ou « Telnet » au travers de KRDC +Comment[ga]=Ceadaíonn sé duit seisiúin SSH nó Telnet a bhainistiú trí KRDC +Comment[gl]=Permite a xestión de sesións SSH ou Telnet por medio de KRCC +Comment[hr]=Omogućuje upravljanje sjednicama SSH-a i Telneta kroz KRDC +Comment[hu]=SSH vagy telnet használata a KRDC-n keresztül +Comment[ia]=Permitte gerer sessiones SSH o Telnet per medio de KRDC +Comment[is]=Gefur kost á að stjórna SSH eða Telnet setum með KRDC +Comment[it]=Permette la gestione di sessioni SSH o Telnet con KRDC +Comment[ja]=KRDC から SSH や Telnet セッションを管理できるようにします +Comment[kk]=KRDC арқылы SSH не Telnet сеанстарын басқаруға мүмкіндік беру +Comment[km]=អនុញ្ញាត​ឲ្យ​គ្រប់គ្រង​​សម័យ SSH ឬ Telnet តាមរយៈ KRDC +Comment[ko]=KRDC를 통해서 원격 SSH나 텔넷 세션 관리하기 +Comment[lt]=Leisti valdyti SSH ar Telnet sesijas per KRDC +Comment[lv]=Ļauj pārvaldīt SSH un Telnet sesijas caur KRDC +Comment[nb]=Tillater å styre SSH eller Telnet-økter gjennom KRDC +Comment[nds]=SSH- oder Telnet-Törns över KRDC plegen +Comment[nl]=Staat het beheer van ssh- of telnet-sessies toe via KRDC +Comment[nn]=Lèt deg handtera SSH- eller Telnet-økter gjennom KRDC +Comment[pa]=KRDC ਰਾਹੀਂ SSH ਜਾਂ ਟੇਲਨੈਟ (Telnet) ਸ਼ੈਸ਼ਨ ਮਨਜ਼ੂਰੀ +Comment[pl]=Pozwala zarządzać sesjami SSH lub Telnet za pomocą KRDC +Comment[pt]=Permite a gestão de sessões SSH ou Telnet através do KRDC +Comment[pt_BR]=Permite o gerenciamento de sessões SSH ou Telnet através do KRDC +Comment[ro]=Permite gestiunea sesiunilor SSH sau Telnet prin KRDC +Comment[ru]=Разрешить управление сеансами SSH или Telnet через KRDC +Comment[si]=KRDC හරහා Telnet හෝ SSH වාර පාලනයට ඉඩ දෙයි +Comment[sk]=Umožňuje spravovanie SSH alebo Telnet sedení pomocou KRDC +Comment[sl]=Omogoča upravljanje sej SSH ali Telnet prek KRDC +Comment[sr]=Управљање ССХ и ТЕЛНЕТ везама кроз КРДЦ +Comment[sr@ijekavian]=Управљање ССХ и ТЕЛНЕТ везама кроз КРДЦ +Comment[sr@ijekavianlatin]=Upravljanje SSH i TELNET vezama kroz KRDC +Comment[sr@latin]=Upravljanje SSH i TELNET vezama kroz KRDC +Comment[sv]=Tillåter hantering av SSH- eller Telnet-sessioner via KRDC +Comment[th]=อนุญาตให้ทำการจัดการวาระการเชื่อมต่อ SSH หรือ Telnet ผ่านทางโปรแกรม KRDC +Comment[tr]=KRDC üzerinden SSH ve Telnet oturumlarını yönetmenizi sağlar +Comment[uk]=Надає змогу керувати сеансами SSH або Telnet за допомогою KRDC +Comment[x-test]=xxAllows managing SSH or Telnet sessions through KRDCxx +Comment[zh_CN]=允许用户通过 KRDC 管理 SSH 或 Telnet 会话 +Comment[zh_TW]=允許透過 KRDC 管理 SSH 或 Telnet 工作階段 + +X-KDE-PluginInfo-Author=Urs Wolfer +X-KDE-PluginInfo-Email=uwolfer@kde.org +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Category=Service +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true +X-KDE-Library=krdc_konsoleplugin +X-KDE-PluginInfo-Name=krdc_konsoleplugin + +X-KDE-KRDC-Sorting=70 diff --git a/krdc/krdc.desktop b/krdc/krdc.desktop new file mode 100755 index 00000000..9fe0f265 --- /dev/null +++ b/krdc/krdc.desktop @@ -0,0 +1,126 @@ +# KDE Config File +[Desktop Entry] +Type=Application +Exec=krdc -caption %c %u +Icon=krdc +Terminal=false +Name=KRDC +Name[ar]=KRDC +Name[ast]=KRDC +Name[bg]=KRDC +Name[bs]=KRDC +Name[ca]=KRDC +Name[ca@valencia]=KRDC +Name[cs]=KRDC +Name[da]=KRDC +Name[de]=KRDC +Name[el]=KRDC +Name[en_GB]=KRDC +Name[eo]=KRDC +Name[es]=KRDC +Name[et]=KRDC +Name[eu]=KRDC +Name[fi]=KRDC +Name[fr]=KRDC +Name[ga]=KRDC +Name[gl]=KRDC +Name[hne]=केआरडीसी +Name[hr]=KRDC +Name[hu]=KRDC +Name[ia]=KRDC +Name[is]=KRDC +Name[it]=KRDC +Name[ja]=KRDC +Name[kk]=KRDC +Name[km]=KRDC +Name[ko]=KRDC +Name[lt]=KDE nutolusio darbastalio klientas +Name[lv]=KRDC +Name[ml]=കെആര്‍ഡിസി +Name[mr]=के-आर-डी-सी +Name[nb]=KRDC +Name[nds]=KRDC +Name[nl]=KRDC +Name[nn]=KRDC +Name[pa]=KRDC +Name[pl]=KRDC +Name[pt]=KRDC +Name[pt_BR]=KRDC +Name[ro]=KRDC +Name[ru]=KRDC +Name[si]=KRDC +Name[sk]=KRDC +Name[sl]=KRDC +Name[sq]=KRDC +Name[sr]=КРДЦ +Name[sr@ijekavian]=КРДЦ +Name[sr@ijekavianlatin]=KRDC +Name[sr@latin]=KRDC +Name[sv]=KRDC +Name[tr]=KRDC +Name[ug]=KRDC +Name[uk]=KRDC +Name[wa]=KRDC +Name[x-test]=xxKRDCxx +Name[zh_CN]=KRDC +Name[zh_TW]=遠端桌面_KRDC +GenericName=Remote Desktop Client +GenericName[ar]=عميل سطح المكتب البعيد +GenericName[ast]=Veceru d'escritoriu remotu +GenericName[bg]=Отдалечен работен плот +GenericName[bs]=Klijent udaljene radne površine +GenericName[ca]=Client d'escriptori remot +GenericName[ca@valencia]=Client d'escriptori remot +GenericName[cs]=Klient vzdálené pracovní plochy +GenericName[da]=Klient til fjernskrivebord +GenericName[de]=Verbindung zu entferntem Rechner +GenericName[el]=Πελάτης απομακρυσμένης επιφάνειας εργασίας +GenericName[en_GB]=Remote Desktop Client +GenericName[es]=Cliente de escritorio remoto +GenericName[et]=Kaugtöölaua klient +GenericName[eu]=Urruneko mahaigainaren bezeroa +GenericName[fi]=Etätyöpöytäasiakas +GenericName[fr]=Connexion à un bureau distant +GenericName[ga]=Cliant Deisce Cianda +GenericName[gl]=Cliente de conexión remota ao escritorio +GenericName[hne]=रिमोट डेस्कटाप क्लाएंट +GenericName[hr]=Klijent za udaljeno povezivanje +GenericName[hu]=Távoli asztal +GenericName[ia]=Cliente de scriptorio remote +GenericName[is]=Tengingar við fjarlæg skjáborð +GenericName[it]=Client per connessione a desktop remoto +GenericName[ja]=リモートデスクトップクライアント +GenericName[kk]=Қашықтан үстелге қосылу клиенті +GenericName[km]=កម្មវិធី​មើល​ផ្ទៃតុ​ពី​ចម្ងាយ +GenericName[ko]=원격 데스크톱 클라이언트 +GenericName[lt]=Nutolusio darbastalio klientas +GenericName[lv]=Attālinātās darbvirsmas klients +GenericName[ml]=വിദൂര പണിയിട ക്ലയന്റ് +GenericName[mr]=दूरस्थ डेस्कटॉप ग्राहक +GenericName[nb]=Tilkobling til annet skrivebord +GenericName[nds]=Schriefdisch-Feernverbinnen +GenericName[nl]=Client voor verbinding met extern bureaublad +GenericName[nn]=Skrivebordssamband over nettverket +GenericName[pa]=ਰਿਮੋਟ ਡੈਸਕਟਾਪ ਕਲਾਈਟ +GenericName[pl]=Klient zdalnego dostępu do pulpitu +GenericName[pt]=Cliente de Ecrãs Remotos +GenericName[pt_BR]=Cliente de área de trabalho remota +GenericName[ro]=Client pentru birou la distanță +GenericName[ru]=Удалённый доступ к рабочему столу +GenericName[si]=දුරස්ථ වැඩතල යෙදුම +GenericName[sk]=Klient vzdialenej pracovnej plochy +GenericName[sl]=Odjemalec za oddaljena namizja +GenericName[sr]=Клијент удаљене површи +GenericName[sr@ijekavian]=Клијент удаљене површи +GenericName[sr@ijekavianlatin]=Klijent udaljene površi +GenericName[sr@latin]=Klijent udaljene površi +GenericName[sv]=Fjärranslutning till skrivbord +GenericName[th]=ไคลเอนต์เชื่อมต่อพื้นที่ทำงานทางไกล +GenericName[tr]=Uzak Masaüstü İstemcisi +GenericName[ug]=يىراقتىكى ئۈستەلئۈستى خېرىدارى +GenericName[uk]=Клієнт з'єднання з віддаленою стільницею +GenericName[x-test]=xxRemote Desktop Clientxx +GenericName[zh_CN]=远程桌面客户端 +GenericName[zh_TW]=遠端桌面客戶端 +X-DocPath=krdc/index.html +Categories=Qt;KDE;Network;RemoteAccess; diff --git a/krdc/krdc_approver/CMakeLists.txt b/krdc/krdc_approver/CMakeLists.txt new file mode 100644 index 00000000..3c397275 --- /dev/null +++ b/krdc/krdc_approver/CMakeLists.txt @@ -0,0 +1,23 @@ +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +set (krdc_rfb_approver_SRCS + main.cpp + approvermanager.cpp + approver.cpp +) + +kde4_add_executable(krdc_rfb_approver ${krdc_rfb_approver_SRCS}) +target_link_libraries(krdc_rfb_approver ${KDE4_KDEUI_LIBS} + ${TELEPATHY_QT4_LIBRARIES} +) + +install(TARGETS krdc_rfb_approver ${INSTALL_TARGETS_DEFAULT_ARGS}) +install(FILES krdc_rfb_approver.notifyrc DESTINATION ${DATA_INSTALL_DIR}/krdc_rfb_approver) + +configure_file(org.freedesktop.Telepathy.Client.krdc_rfb_approver.service.in + ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.Telepathy.Client.krdc_rfb_approver.service) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.Telepathy.Client.krdc_rfb_approver.service + DESTINATION ${DBUS_SERVICES_INSTALL_DIR}) + +# FIXME any better macro for ${XDG_DATA_DIRS} ? +install(FILES krdc_rfb_approver.client DESTINATION ${SHARE_INSTALL_PREFIX}/telepathy/clients/) diff --git a/krdc/krdc_approver/approver.cpp b/krdc/krdc_approver/approver.cpp new file mode 100644 index 00000000..8ab5368b --- /dev/null +++ b/krdc/krdc_approver/approver.cpp @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Collabora Ltd +** Copyright (C) 2009 Abner Silva +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "approver.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +Approver::Approver(const Tp::MethodInvocationContextPtr<> &context, + const QList &channels, + const Tp::ChannelDispatchOperationPtr &dispatchOperation, + QObject *parent) + : QObject(parent), + m_context(context), + m_channels(channels), + m_dispatchOp(dispatchOperation), + m_notification(0) +{ + kDebug() << "Initializing approver"; + + connect(m_dispatchOp->becomeReady(), + SIGNAL(finished(Tp::PendingOperation*)), + SLOT(onDispatchOperationReady(Tp::PendingOperation*))); +} + +void Approver::onDispatchOperationReady(Tp::PendingOperation *op) +{ + if (op->isError()) { + kError() << "Dispatch operation failed to become ready" + << op->errorName() << op->errorMessage(); + m_context->setFinishedWithError(op->errorName(), op->errorMessage()); + emit finished(); + return; + } + + kDebug() << "DispatchOp ready!"; + + Tp::ChannelPtr channel = m_dispatchOp->channels()[0]; + connect(channel->becomeReady(), + SIGNAL(finished(Tp::PendingOperation*)), + SLOT(onChannelReady(Tp::PendingOperation*))); +} + +void Approver::onChannelReady(Tp::PendingOperation *op) +{ + if (op->isError()) { + kError() << "Channel failed to become ready" + << op->errorName() << op->errorMessage(); + m_context->setFinishedWithError(op->errorName(), op->errorMessage()); + emit finished(); + return; + } + + kDebug() << "Channel ready!"; + + Tp::ContactPtr contact = m_dispatchOp->channels()[0]->initiatorContact(); + + KNotification *notification = new KNotification("newrfb", NULL, KNotification::Persistent); + notification->setTitle(i18n("Invitation to view remote desktop")); + notification->setText(i18n("%1 wants to share his/her desktop with you", contact->alias())); + notification->setActions(QStringList() << i18n("Accept") << i18n("Reject")); + + Tp::Client::ConnectionInterfaceAvatarsInterface *avatarIface = + m_dispatchOp->channels()[0]->connection()->optionalInterface(); + + if (avatarIface) { + QDBusPendingReply reply = avatarIface->RequestAvatar( + contact->handle().takeFirst()); + + reply.waitForFinished(); + + if (!reply.isError()) { + QPixmap avatar; + avatar.loadFromData(reply.value()); + notification->setPixmap(avatar); + } + } + + connect(notification, SIGNAL(action1Activated()), SLOT(onAccepted())); + connect(notification, SIGNAL(action2Activated()), SLOT(onRejected())); + connect(notification, SIGNAL(ignored()), SLOT(onRejected())); + + notification->sendEvent(); + + m_notification = notification; + + m_context->setFinished(); +} + +Approver::~Approver() +{ + kDebug() << "Destroying approver"; +} + +void Approver::onAccepted() +{ + kDebug() << "Channel approved"; + m_dispatchOp->handleWith(TP_QT_IFACE_CLIENT + ".krdc_rfb_handler"); + + emit finished(); +} + +void Approver::onRejected() +{ + kDebug() << "Channel rejected"; + connect(m_dispatchOp->claim(), SIGNAL(finished(Tp::PendingOperation*)), + SLOT(onClaimFinished(Tp::PendingOperation*))); +} + +void Approver::onClaimFinished(Tp::PendingOperation *op) +{ + if (op->isError()) { + kError() << "Claim operation failed" + << op->errorName() << op->errorMessage(); + m_context->setFinishedWithError(op->errorName(), op->errorMessage()); + } + else { + foreach(const Tp::ChannelPtr &channel, m_channels) + channel->requestClose(); + } + + emit finished(); +} diff --git a/krdc/krdc_approver/approver.h b/krdc/krdc_approver/approver.h new file mode 100644 index 00000000..84be8416 --- /dev/null +++ b/krdc/krdc_approver/approver.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Collabora Ltd +** Copyright (C) 2009 Abner Silva +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef APPROVER_H +#define APPROVER_H + +#include + +#include + +class KNotification; + +class Approver : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(Approver) + +public: + ~Approver(); + +private Q_SLOTS: + void onAccepted(); + void onRejected(); + void onDispatchOperationReady(Tp::PendingOperation*); + void onChannelReady(Tp::PendingOperation*); + void onClaimFinished(Tp::PendingOperation*); + +Q_SIGNALS: + void finished(); + +private: + Approver(const Tp::MethodInvocationContextPtr<> &context, + const QList &channels, + const Tp::ChannelDispatchOperationPtr &dispatchOperation, + QObject *parent); + +private: + Tp::MethodInvocationContextPtr<> m_context; + QList m_channels; + Tp::ChannelDispatchOperationPtr m_dispatchOp; + QPointer m_notification; + + friend class ApproverManager; +}; +#endif diff --git a/krdc/krdc_approver/approvermanager.cpp b/krdc/krdc_approver/approvermanager.cpp new file mode 100644 index 00000000..5e78fca1 --- /dev/null +++ b/krdc/krdc_approver/approvermanager.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Collabora Ltd +** Copyright (C) 2009 Abner Silva +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "approvermanager.h" +#include "approver.h" + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static inline Tp::ChannelClassSpecList channelClassSpecList() +{ + Tp::ChannelClassSpec spec = Tp::ChannelClassSpec(); + spec.setChannelType(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE); + spec.setTargetHandleType(Tp::HandleTypeContact); + spec.setRequested(false); + spec.setProperty(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + ".Service", + QVariant("rfb")); + return Tp::ChannelClassSpecList() << spec; +} + +ApproverManager::ApproverManager(QObject *parent) + : QObject(parent), + AbstractClientApprover(channelClassSpecList()) +{ + kDebug() << "Initializing approver manager"; +} + +ApproverManager::~ApproverManager() +{ + kDebug() << "Destroying approver manager"; +} + +void ApproverManager::addDispatchOperation(const Tp::MethodInvocationContextPtr<> &context, + const Tp::ChannelDispatchOperationPtr &dispatchOperation) +{ + kDebug() << "New channel for approving arrived"; + + Approver *approver = new Approver(context, dispatchOperation->channels(), dispatchOperation, this); + connect(approver, SIGNAL(finished()), SLOT(onFinished())); + + m_approvers << approver; +} + +void ApproverManager::onFinished() +{ + kDebug() << "Approver finished"; + + Approver *approver = qobject_cast(sender()); + m_approvers.removeOne(approver); + approver->deleteLater(); + + if (m_approvers.empty()) { + kDebug() << "Quitting approver manager"; + KApplication::kApplication()->quit(); + } +} diff --git a/krdc/krdc_approver/approvermanager.h b/krdc/krdc_approver/approvermanager.h new file mode 100644 index 00000000..569c64d6 --- /dev/null +++ b/krdc/krdc_approver/approvermanager.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Collabora Ltd +** Copyright (C) 2009 Abner Silva +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef APPROVERMANAGER_H +#define APPROVERMANAGER_H + +#include + +class Approver; + +class ApproverManager : public QObject, public Tp::AbstractClientApprover +{ + Q_OBJECT + +public: + explicit ApproverManager(QObject *parent); + virtual ~ApproverManager(); + + virtual void addDispatchOperation(const Tp::MethodInvocationContextPtr<> &context, + const Tp::ChannelDispatchOperationPtr &dispatchOperation); + +private Q_SLOTS: + void onFinished(); + +private: + QList m_approvers; +}; +#endif diff --git a/krdc/krdc_approver/krdc_rfb_approver.client b/krdc/krdc_approver/krdc_rfb_approver.client new file mode 100644 index 00000000..e080644b --- /dev/null +++ b/krdc/krdc_approver/krdc_rfb_approver.client @@ -0,0 +1,8 @@ +[org.freedesktop.Telepathy.Client] +Interfaces=org.freedesktop.Telepathy.Client.Approver; + +[org.freedesktop.Telepathy.Client.Approver.ApproverChannelFilter 0] +org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.StreamTube +org.freedesktop.Telepathy.Channel.Type.StreamTube.Service s=rfb +org.freedesktop.Telepathy.Channel.Requested b=false + diff --git a/krdc/krdc_approver/krdc_rfb_approver.notifyrc b/krdc/krdc_approver/krdc_rfb_approver.notifyrc new file mode 100644 index 00000000..ee8d139c --- /dev/null +++ b/krdc/krdc_approver/krdc_rfb_approver.notifyrc @@ -0,0 +1,173 @@ +[Global] +IconName=krdc +Comment=KRDC +Comment[ast]=KRDC +Comment[bg]=KRDC +Comment[bs]=KRDC +Comment[ca]=KRDC +Comment[ca@valencia]=KRDC +Comment[cs]=KRDC +Comment[da]=KRDC +Comment[de]=KRDC +Comment[el]=KRDC +Comment[en_GB]=KRDC +Comment[eo]=KRDC +Comment[es]=KRDC +Comment[et]=KRDC +Comment[eu]=KRDC +Comment[fi]=KRDC +Comment[fr]=KRDC +Comment[ga]=KRDC +Comment[gl]=KRDC +Comment[hr]=KRDC +Comment[hu]=KRDC +Comment[ia]=KRDC +Comment[is]=KRDC +Comment[it]=KRDC +Comment[ja]=KRDC +Comment[kk]=KRDC +Comment[km]=KRDC +Comment[ko]=KRDC +Comment[lt]=KRDC +Comment[lv]=KRDC +Comment[mr]=के-आर-डी-सी +Comment[nb]=KRDC +Comment[nds]=KRDC +Comment[nl]=KRDC +Comment[nn]=KRDC +Comment[pa]=KRDC +Comment[pl]=KRDC +Comment[pt]=KRDC +Comment[pt_BR]=KRDC +Comment[ro]=KRDC +Comment[ru]=KRDC +Comment[si]=KRDC +Comment[sk]=KRDC +Comment[sl]=KRDC +Comment[sr]=КРДЦ +Comment[sr@ijekavian]=КРДЦ +Comment[sr@ijekavianlatin]=KRDC +Comment[sr@latin]=KRDC +Comment[sv]=KRDC +Comment[tr]=KRDC +Comment[ug]=KRDC +Comment[uk]=KRDC +Comment[wa]=KRDC +Comment[x-test]=xxKRDCxx +Comment[zh_CN]=KRDC +Comment[zh_TW]=KRDC 遠端桌面連線遙控 +Name=KRDC +Name[ar]=KRDC +Name[ast]=KRDC +Name[bg]=KRDC +Name[bs]=KRDC +Name[ca]=KRDC +Name[ca@valencia]=KRDC +Name[cs]=KRDC +Name[da]=KRDC +Name[de]=KRDC +Name[el]=KRDC +Name[en_GB]=KRDC +Name[eo]=KRDC +Name[es]=KRDC +Name[et]=KRDC +Name[eu]=KRDC +Name[fi]=KRDC +Name[fr]=KRDC +Name[ga]=KRDC +Name[gl]=KRDC +Name[hne]=केआरडीसी +Name[hr]=KRDC +Name[hu]=KRDC +Name[ia]=KRDC +Name[is]=KRDC +Name[it]=KRDC +Name[ja]=KRDC +Name[kk]=KRDC +Name[km]=KRDC +Name[ko]=KRDC +Name[lt]=KDE nutolusio darbastalio klientas +Name[lv]=KRDC +Name[ml]=കെആര്‍ഡിസി +Name[mr]=के-आर-डी-सी +Name[nb]=KRDC +Name[nds]=KRDC +Name[nl]=KRDC +Name[nn]=KRDC +Name[pa]=KRDC +Name[pl]=KRDC +Name[pt]=KRDC +Name[pt_BR]=KRDC +Name[ro]=KRDC +Name[ru]=KRDC +Name[si]=KRDC +Name[sk]=KRDC +Name[sl]=KRDC +Name[sq]=KRDC +Name[sr]=КРДЦ +Name[sr@ijekavian]=КРДЦ +Name[sr@ijekavianlatin]=KRDC +Name[sr@latin]=KRDC +Name[sv]=KRDC +Name[tr]=KRDC +Name[ug]=KRDC +Name[uk]=KRDC +Name[wa]=KRDC +Name[x-test]=xxKRDCxx +Name[zh_CN]=KRDC +Name[zh_TW]=遠端桌面_KRDC + +[Event/newrfb] +Name=Incoming RFB Tube +Name[ast]=RFB Tube entrante +Name[bg]=Входяща връзка RFB +Name[bs]=Dolazna RFB cijev +Name[ca]=Tub RFB entrant +Name[ca@valencia]=Tub RFB entrant +Name[cs]=Příchozí kanál RFB +Name[da]=Indkommende RFB-tube +Name[de]=Eingehender RFB-Tunnel +Name[el]=Δίαυλος εισερχόμενου RFB +Name[en_GB]=Incoming RFB Tube +Name[es]=RFB Tube entrante +Name[et]=Sisenev RFB-tube +Name[eu]=Sarrerako RFB hodia +Name[fi]=Saapuva RFB-putki +Name[fr]=Canal entrant « RFB » +Name[ga]=Tiúb RFB Isteach +Name[gl]=Tubo RFB entrante +Name[hr]=Dolazeći RFB Tube +Name[hu]=Bejövő RFB-csatorna +Name[ia]=RFB Tube in arrivata +Name[is]=Innsend RFB-túba +Name[it]=Canale RFB in arrivo +Name[kk]=Кіріс RFB арнасы +Name[km]=RFB Tube ចូល +Name[ko]=들어오는 RFB Tube +Name[lt]=Įeinantis RFB kanalas +Name[lv]=Ienākoša RFB truba +Name[nb]=Innkommende RFB-rør +Name[nds]=Ankamen RFB-Kanaal +Name[nl]=Inkomende RFB-buis +Name[nn]=Innkommande RFB-tube +Name[pa]=ਆ ਰਹੀ RFB ਟਿਊਬ +Name[pl]=Przychodząca RFB Tube +Name[pt]=Ligação de RFB Recebida +Name[pt_BR]=Ligação de RFB recebida +Name[ro]=Tub RFB de intrare +Name[ru]=Входящее подключение RFB +Name[si]=පැමිණෙන RFB නලය +Name[sk]=Prichádzajúci RFB kanál +Name[sl]=Prejet oddaljen slikovni medpomnilnik +Name[sr]=Долазна РФБ цев +Name[sr@ijekavian]=Долазна РФБ цев +Name[sr@ijekavianlatin]=Dolazna RFB cev +Name[sr@latin]=Dolazna RFB cev +Name[sv]=Inkommande RFB-rör +Name[tr]=Gelen RFB Tube +Name[uk]=Вхідний канал RFB +Name[x-test]=xxIncoming RFB Tubexx +Name[zh_CN]=收到的 RFB 点对点请求 +Name[zh_TW]=進來的 RFB Tube +Action=Popup +Flags=Persistent diff --git a/krdc/krdc_approver/main.cpp b/krdc/krdc_approver/main.cpp new file mode 100644 index 00000000..fc39d741 --- /dev/null +++ b/krdc/krdc_approver/main.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Collabora Ltd +** Copyright (C) 2009 Abner Silva +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "approvermanager.h" + +#include +#include +#include +#include + +#include +#include +#include + +int main(int argc, char **argv) +{ + KAboutData aboutData("krdc_rfb_approver", "KRDC", ki18n("KRDC"), "0.1", + ki18n("Approver for KRDC"), KAboutData::License_GPL, + ki18n("(C) 2009, Abner Silva")); + aboutData.setProgramIconName("krdc"); + aboutData.addAuthor(ki18nc("@info:credit", "Abner Silva"), KLocalizedString(), + "abner.silva@kdemail.net"); + + KCmdLineArgs::init(argc, argv, &aboutData); + + if (!KUniqueApplication::start()) + return 0; + + KUniqueApplication app; + app.disableSessionManagement(); + + Tp::registerTypes(); + Tp::enableDebug(true); + Tp::enableWarnings(true); + + Tp::ClientRegistrarPtr registrar = Tp::ClientRegistrar::create(); + Tp::SharedPtr approverManager; + approverManager = Tp::SharedPtr(new ApproverManager(0)); + registrar->registerClient(Tp::AbstractClientPtr::dynamicCast(approverManager), "krdc_rfb_approver"); + + return app.exec(); +} diff --git a/krdc/krdc_approver/org.freedesktop.Telepathy.Client.krdc_rfb_approver.service.in b/krdc/krdc_approver/org.freedesktop.Telepathy.Client.krdc_rfb_approver.service.in new file mode 100644 index 00000000..9b1633aa --- /dev/null +++ b/krdc/krdc_approver/org.freedesktop.Telepathy.Client.krdc_rfb_approver.service.in @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.freedesktop.Telepathy.Client.krdc_rfb_approver +Exec=@CMAKE_INSTALL_PREFIX@/bin/krdc_rfb_approver diff --git a/krdc/krdc_rfb_handler.client b/krdc/krdc_rfb_handler.client new file mode 100644 index 00000000..539a1d4e --- /dev/null +++ b/krdc/krdc_rfb_handler.client @@ -0,0 +1,7 @@ +[org.freedesktop.Telepathy.Client] +Interfaces=org.freedesktop.Telepathy.Client.Handler; + +[org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 0] +org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.StreamTube +org.freedesktop.Telepathy.Channel.Type.StreamTube.Service s=rfb +org.freedesktop.Telepathy.Channel.Requested b=false diff --git a/krdc/krdcui.rc b/krdc/krdcui.rc new file mode 100644 index 00000000..997a32d4 --- /dev/null +++ b/krdc/krdcui.rc @@ -0,0 +1,33 @@ + + + + + + + + &Session + + + + + + + + + + + + + +Remote View Toolbar + + + + + + + + + + + diff --git a/krdc/main.cpp b/krdc/main.cpp new file mode 100644 index 00000000..afc4531b --- /dev/null +++ b/krdc/main.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2001-2003 Tim Jansen +** Copyright (C) 2007 - 2012 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "mainwindow.h" + +#include +#include +#include +#include +#include + +#include + +int main(int argc, char **argv) +{ + QTime startupTimer; + startupTimer.start(); + KAboutData aboutData("krdc", 0, ki18n("KRDC"), KDE_VERSION_STRING, + ki18n("KDE Remote Desktop Client"), KAboutData::License_GPL, + ki18n("(c) 2007-2013, Urs Wolfer\n" + "(c) 2001-2003, Tim Jansen\n" + "(c) 2002-2003, Arend van Beelen jr.\n" + "(c) 2000-2002, Const Kaplinsky\n" + "(c) 2000, Tridia Corporation\n" + "(c) 1999, AT&T Laboratories Boston\n" + "(c) 1999-2003, Matthew Chapman\n" + "(c) 2009, Collabora Ltd")); + + aboutData.addAuthor(ki18n("Urs Wolfer"), ki18n("Developer, Maintainer"), "uwolfer@kde.org"); + aboutData.addAuthor(ki18n("Tony Murray"), ki18n("Developer"), "murraytony@gmail.com"); + aboutData.addAuthor(ki18n("Tim Jansen"), ki18n("Former Developer"), "tim@tjansen.de"); + aboutData.addAuthor(ki18n("Arend van Beelen jr."), ki18n("Initial RDP backend"), "arend@auton.nl"); + aboutData.addCredit(ki18n("Brad Hards"), ki18n("Google Summer of Code 2007 KRDC project mentor"), + "bradh@frogmouth.net"); + aboutData.addCredit(ki18n("LibVNCServer / LibVNCClient developers"), ki18n("VNC client library"), + "libvncserver-common@lists.sf.net", "http://libvncserver.sourceforge.net/"); + aboutData.addAuthor(ki18n("Abner Silva"), ki18n("Telepathy Tubes Integration"), "abner.silva@kdemail.net"); + + KCmdLineArgs::init(argc, argv, &aboutData); + + KCmdLineOptions options; + options.add("fullscreen", ki18n("Start KRDC with the provided URL in fullscreen mode (works only with one URL)")); + options.add("!+[URL]", ki18n("URLs to connect after startup")); + + KCmdLineArgs::addCmdLineOptions(options); + + KApplication app; + + MainWindow *mainwindow = new MainWindow; + mainwindow->show(); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if (args->count() > 0) { + for (int i = 0; i < args->count(); ++i) { + KUrl u(args->url(i)); + + if (u.scheme().isEmpty() || u.host().isEmpty()) { // unusable url; try to recover it... + QString arg(args->url(i).url()); + + kDebug(5010) << "unusable url; try to recover it:" << arg; + + if (arg.lastIndexOf('/') != 0) + arg = arg.right(arg.length() - arg.lastIndexOf('/') - 1); + + if (!arg.contains("://")) + arg.prepend("vnc://"); // vnc was default in kde3 times... + + kDebug(5010) << "recovered url:" << arg; + + u = arg; + } + + if (!u.isValid()) + continue; + + mainwindow->newConnection(u, ((args->isSet("fullscreen")) && (args->count() == 1))); + } + } + + kDebug(5010) << "########## KRDC ready:" << startupTimer.elapsed() << "ms ##########"; + + return app.exec(); +} diff --git a/krdc/mainwindow.cpp b/krdc/mainwindow.cpp new file mode 100644 index 00000000..91271e85 --- /dev/null +++ b/krdc/mainwindow.cpp @@ -0,0 +1,1229 @@ +/**************************************************************************** +** +** Copyright (C) 2007 - 2013 Urs Wolfer +** Copyright (C) 2009 - 2010 Tony Murray +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "mainwindow.h" + +#include "remoteview.h" +#include "settings.h" +#include "config/preferencesdialog.h" +#include "floatingtoolbar.h" +#include "bookmarkmanager.h" +#include "connectiondelegate.h" +#include "remotedesktopsmodel.h" +#include "systemtrayicon.h" +#include "tabbedviewwidget.h" +#include "hostpreferences.h" + +#ifdef TELEPATHY_SUPPORT +#include "tubesmanager.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MainWindow::MainWindow(QWidget *parent) + : KXmlGuiWindow(parent), + m_fullscreenWindow(0), + m_protocolInput(0), + m_addressInput(0), + m_toolBar(0), + m_currentRemoteView(-1), + m_systemTrayIcon(0), + m_dockWidgetTableView(0), + m_newConnectionTableView(0), +#ifdef TELEPATHY_SUPPORT + m_tubesManager(0), +#endif + m_newConnectionWidget(0) +{ + loadAllPlugins(); + + setupActions(); + + setStandardToolBarMenuEnabled(true); + + m_tabWidget = new TabbedViewWidget(this); + m_tabWidget->setMovable(true); + m_tabWidget->setTabPosition((KTabWidget::TabPosition) Settings::tabPosition()); + +#if QT_VERSION >= 0x040500 + m_tabWidget->setTabsClosable(Settings::tabCloseButton()); +#else + m_tabWidget->setCloseButtonEnabled(Settings::tabCloseButton()); +#endif + + connect(m_tabWidget, SIGNAL(closeRequest(QWidget*)), SLOT(closeTab(QWidget*))); + + if (Settings::tabMiddleClick()) + connect(m_tabWidget, SIGNAL(mouseMiddleClick(QWidget*)), SLOT(closeTab(QWidget*))); + + connect(m_tabWidget, SIGNAL(mouseDoubleClick(QWidget*)), SLOT(openTabSettings(QWidget*))); + connect(m_tabWidget, SIGNAL(mouseDoubleClick()), SLOT(newConnectionPage())); + connect(m_tabWidget, SIGNAL(contextMenu(QWidget*,QPoint)), SLOT(tabContextMenu(QWidget*,QPoint))); + + m_tabWidget->setMinimumSize(600, 400); + setCentralWidget(m_tabWidget); + + createDockWidget(); + + setupGUI(ToolBar | Keys | Save | Create); + + if (Settings::systemTrayIcon()) { + m_systemTrayIcon = new SystemTrayIcon(this); + if(m_fullscreenWindow) m_systemTrayIcon->setAssociatedWidget(m_fullscreenWindow); + } + + connect(m_tabWidget, SIGNAL(currentChanged(int)), SLOT(tabChanged(int))); + + if (Settings::showStatusBar()) + statusBar()->showMessage(i18n("KDE Remote Desktop Client started")); + + updateActionStatus(); // disable remote view actions + + if (Settings::openSessions().count() == 0) // just create a new connection tab if there are no open sessions + m_tabWidget->addTab(newConnectionWidget(), i18n("New Connection")); + + if (Settings::rememberSessions()) // give some time to create and show the window first + QTimer::singleShot(100, this, SLOT(restoreOpenSessions())); +} + +MainWindow::~MainWindow() +{ +} + +void MainWindow::setupActions() +{ + QAction *connectionAction = actionCollection()->addAction("new_connection"); + connectionAction->setText(i18n("New Connection")); + connectionAction->setIcon(KIcon("network-connect")); + connect(connectionAction, SIGNAL(triggered()), SLOT(newConnectionPage())); + + QAction *screenshotAction = actionCollection()->addAction("take_screenshot"); + screenshotAction->setText(i18n("Copy Screenshot to Clipboard")); + screenshotAction->setIconText(i18n("Screenshot")); + screenshotAction->setIcon(KIcon("ksnapshot")); + connect(screenshotAction, SIGNAL(triggered()), SLOT(takeScreenshot())); + + KAction *fullscreenAction = actionCollection()->addAction("switch_fullscreen"); // note: please do not switch to KStandardShortcut unless you know what you are doing (see history of this file) + fullscreenAction->setText(i18n("Switch to Full Screen Mode")); + fullscreenAction->setIconText(i18n("Full Screen")); + fullscreenAction->setIcon(KIcon("view-fullscreen")); + fullscreenAction->setShortcut(KStandardShortcut::fullScreen()); + connect(fullscreenAction, SIGNAL(triggered()), SLOT(switchFullscreen())); + + QAction *viewOnlyAction = actionCollection()->addAction("view_only"); + viewOnlyAction->setCheckable(true); + viewOnlyAction->setText(i18n("View Only")); + viewOnlyAction->setIcon(KIcon("document-preview")); + connect(viewOnlyAction, SIGNAL(triggered(bool)), SLOT(viewOnly(bool))); + + KAction *disconnectAction = actionCollection()->addAction("disconnect"); + disconnectAction->setText(i18n("Disconnect")); + disconnectAction->setIcon(KIcon("network-disconnect")); + disconnectAction->setShortcut(QKeySequence::Close); + connect(disconnectAction, SIGNAL(triggered()), SLOT(disconnectHost())); + + QAction *showLocalCursorAction = actionCollection()->addAction("show_local_cursor"); + showLocalCursorAction->setCheckable(true); + showLocalCursorAction->setIcon(KIcon("input-mouse")); + showLocalCursorAction->setText(i18n("Show Local Cursor")); + showLocalCursorAction->setIconText(i18n("Local Cursor")); + connect(showLocalCursorAction, SIGNAL(triggered(bool)), SLOT(showLocalCursor(bool))); + + QAction *grabAllKeysAction = actionCollection()->addAction("grab_all_keys"); + grabAllKeysAction->setCheckable(true); + grabAllKeysAction->setIcon(KIcon("configure-shortcuts")); + grabAllKeysAction->setText(i18n("Grab All Possible Keys")); + grabAllKeysAction->setIconText(i18n("Grab Keys")); + connect(grabAllKeysAction, SIGNAL(triggered(bool)), SLOT(grabAllKeys(bool))); + + QAction *scaleAction = actionCollection()->addAction("scale"); + scaleAction->setCheckable(true); + scaleAction->setIcon(KIcon("zoom-fit-best")); + scaleAction->setText(i18n("Scale Remote Screen to Fit Window Size")); + scaleAction->setIconText(i18n("Scale")); + connect(scaleAction, SIGNAL(triggered(bool)), SLOT(scale(bool))); + + KStandardAction::quit(this, SLOT(quit()), actionCollection()); + KStandardAction::preferences(this, SLOT(preferences()), actionCollection()); + QAction *configNotifyAction = KStandardAction::configureNotifications(this, SLOT(configureNotifications()), actionCollection()); + configNotifyAction->setVisible(false); + m_menubarAction = KStandardAction::showMenubar(this, SLOT(showMenubar()), actionCollection()); + m_menubarAction->setChecked(!menuBar()->isHidden()); + + KActionMenu *bookmarkMenu = new KActionMenu(i18n("Bookmarks"), actionCollection()); + m_bookmarkManager = new BookmarkManager(actionCollection(), bookmarkMenu->menu(), this); + actionCollection()->addAction("bookmark" , bookmarkMenu); + connect(m_bookmarkManager, SIGNAL(openUrl(KUrl)), SLOT(newConnection(KUrl))); +} + +void MainWindow::loadAllPlugins() +{ + const KService::List offers = KServiceTypeTrader::self()->query("KRDC/Plugin"); + + KConfigGroup conf(KGlobal::config(), "Plugins"); + + for (int i = 0; i < offers.size(); i++) { + KService::Ptr offer = offers[i]; + + RemoteViewFactory *remoteView; + + KPluginInfo description(offer); + description.load(conf); + + const bool selected = description.isPluginEnabled(); + + if (selected) { + if ((remoteView = createPluginFromService(offer)) != 0) { + kDebug(5010) << "### Plugin " + description.name() + " found ###"; + kDebug(5010) << "# Version:" << description.version(); + kDebug(5010) << "# Description:" << description.comment(); + kDebug(5010) << "# Author:" << description.author(); + const int sorting = offer->property("X-KDE-KRDC-Sorting").toInt(); + kDebug(5010) << "# Sorting:" << sorting; + + m_remoteViewFactories.insert(sorting, remoteView); + } else { + kDebug(5010) << "Error loading KRDC plugin (" << (offers[i])->library() << ')'; + } + } else { + kDebug(5010) << "# Plugin " + description.name() + " found, however it's not activated, skipping..."; + continue; + } + } + +#ifdef TELEPATHY_SUPPORT + /* Start tube handler */ + m_tubesManager = new TubesManager(this); + connect(m_tubesManager, SIGNAL(newConnection(KUrl)), SLOT(newConnection(KUrl))); +#endif +} + +RemoteViewFactory *MainWindow::createPluginFromService(const KService::Ptr &service) +{ + //try to load the specified library + KPluginFactory *factory = KPluginLoader(service->library()).factory(); + + if (!factory) { + kError(5010) << "KPluginFactory could not load the plugin:" << service->library(); + return 0; + } + + RemoteViewFactory *plugin = factory->create(); + + return plugin; +} + +void MainWindow::restoreOpenSessions() +{ + const QStringList list = Settings::openSessions(); + QStringList::ConstIterator it = list.begin(); + QStringList::ConstIterator end = list.end(); + while (it != end) { + newConnection(*it); + ++it; + } +} + +KUrl MainWindow::getInputUrl() +{ + return KUrl(m_protocolInput->currentText() + "://" + m_addressInput->text()); +} + +void MainWindow::newConnection(const KUrl &newUrl, bool switchFullscreenWhenConnected, const QString &tabName) +{ + m_switchFullscreenWhenConnected = switchFullscreenWhenConnected; + + const KUrl url = newUrl.isEmpty() ? getInputUrl() : newUrl; + + if (!url.isValid() || (url.host().isEmpty() && url.port() < 0) + || (!url.path().isEmpty() && url.path() != QLatin1String("/"))) { + KMessageBox::error(this, + i18n("The entered address does not have the required form.\n Syntax: [username@]host[:port]"), + i18n("Malformed URL")); + return; + } + + if (m_protocolInput && m_addressInput) { + int index = m_protocolInput->findText(url.protocol()); + if (index>=0) m_protocolInput->setCurrentIndex(index); + m_addressInput->setText(url.authority()); + } + + RemoteView *view = 0; + KConfigGroup configGroup = Settings::self()->config()->group("hostpreferences").group(url.prettyUrl(KUrl::RemoveTrailingSlash)); + + foreach(RemoteViewFactory *factory, m_remoteViewFactories) { + if (factory->supportsUrl(url)) { + view = factory->createView(this, url, configGroup); + kDebug(5010) << "Found plugin to handle url (" + url.url() + "): " + view->metaObject()->className(); + break; + } + } + + if (!view) { + KMessageBox::error(this, + i18n("The entered address cannot be handled."), + i18n("Unusable URL")); + return; + } + + // Configure the view + HostPreferences* prefs = view->hostPreferences(); + if (! prefs->showDialogIfNeeded(this)) { + delete view; + return; + } + + view->showDotCursor(prefs->showLocalCursor() ? RemoteView::CursorOn : RemoteView::CursorOff); + view->setViewOnly(prefs->viewOnly()); + if (! switchFullscreenWhenConnected) view->enableScaling(prefs->windowedScale()); + + connect(view, SIGNAL(framebufferSizeChanged(int,int)), this, SLOT(resizeTabWidget(int,int))); + connect(view, SIGNAL(statusChanged(RemoteView::RemoteStatus)), this, SLOT(statusChanged(RemoteView::RemoteStatus))); + connect(view, SIGNAL(disconnected()), this, SLOT(disconnectHost())); + + view->winId(); // native widget workaround for bug 253365 + QScrollArea *scrollArea = createScrollArea(m_tabWidget, view); + + const int indexOfNewConnectionWidget = m_tabWidget->indexOf(m_newConnectionWidget); + if (indexOfNewConnectionWidget >= 0) + m_tabWidget->removeTab(indexOfNewConnectionWidget); + + const int newIndex = m_tabWidget->addTab(scrollArea, KIcon("krdc"), tabName.isEmpty() ? url.prettyUrl(KUrl::RemoveTrailingSlash) : tabName); + m_tabWidget->setCurrentIndex(newIndex); + m_remoteViewMap.insert(m_tabWidget->widget(newIndex), view); + tabChanged(newIndex); // force to update m_currentRemoteView (tabChanged is not emitted when start page has been disabled) + + view->start(); +} + +void MainWindow::openFromRemoteDesktopsModel(const QModelIndex &index) +{ + const QString urlString = index.data(10001).toString(); + const QString nameString = index.data(10003).toString(); + if (!urlString.isEmpty()) { + const KUrl url(urlString); + // first check if url has already been opened; in case show the tab + foreach (QWidget *widget, m_remoteViewMap.keys()) { + if (m_remoteViewMap.value(widget)->url() == url) { + m_tabWidget->setCurrentWidget(widget); + return; + } + } + + newConnection(url, false, nameString); + } +} + +void MainWindow::resizeTabWidget(int w, int h) +{ + kDebug(5010) << "tabwidget resize, view size: w: " << w << ", h: " << h; + if (m_fullscreenWindow) { + kDebug(5010) << "in fullscreen mode, refusing to resize"; + return; + } + + const QSize viewSize = QSize(w,h); + QDesktopWidget *desktop = QApplication::desktop(); + + if (Settings::fullscreenOnConnect()) { + int currentScreen = desktop->screenNumber(this); + const QSize screenSize = desktop->screenGeometry(currentScreen).size(); + + if (screenSize == viewSize) { + kDebug(5010) << "screen size equal to target view size -> switch to fullscreen mode"; + switchFullscreen(); + return; + } + } + + if (Settings::resizeOnConnect()) { + QWidget* currentWidget = m_tabWidget->currentWidget(); + const QSize newWindowSize = size() - currentWidget->frameSize() + viewSize; + + const QSize desktopSize = desktop->availableGeometry().size(); + kDebug(5010) << "new window size: " << newWindowSize << " available space:" << desktopSize; + + if ((newWindowSize.width() >= desktopSize.width()) || (newWindowSize.height() >= desktopSize.height())) { + kDebug(5010) << "remote desktop needs more space than available -> show window maximized"; + setWindowState(windowState() | Qt::WindowMaximized); + return; + } + + resize(newWindowSize); + } +} + +void MainWindow::statusChanged(RemoteView::RemoteStatus status) +{ + kDebug(5010) << status; + + // the remoteview is already deleted, so don't show it; otherwise it would crash + if (status == RemoteView::Disconnecting || status == RemoteView::Disconnected) + return; + + RemoteView *view = qobject_cast(QObject::sender()); + const QString host = view->host(); + + QString iconName = "krdc"; + QString message; + + switch (status) { + case RemoteView::Connecting: + iconName = "network-connect"; + message = i18n("Connecting to %1", host); + break; + case RemoteView::Authenticating: + iconName = "dialog-password"; + message = i18n("Authenticating at %1", host); + break; + case RemoteView::Preparing: + iconName = "view-history"; + message = i18n("Preparing connection to %1", host); + break; + case RemoteView::Connected: + iconName = "krdc"; + message = i18n("Connected to %1", host); + + if (view->grabAllKeys() != view->hostPreferences()->grabAllKeys()) { + view->setGrabAllKeys(view->hostPreferences()->grabAllKeys()); + updateActionStatus(); + } + + // when started with command line fullscreen argument + if (m_switchFullscreenWhenConnected) { + m_switchFullscreenWhenConnected = false; + switchFullscreen(); + } + + if (Settings::rememberHistory()) { + m_bookmarkManager->addHistoryBookmark(view); + } + + break; + default: + break; + } + + m_tabWidget->setTabIcon(m_tabWidget->indexOf(view), KIcon(iconName)); + if (Settings::showStatusBar()) + statusBar()->showMessage(message); +} + +void MainWindow::takeScreenshot() +{ + const QPixmap snapshot = currentRemoteView()->takeScreenshot(); + + QApplication::clipboard()->setPixmap(snapshot); +} + +void MainWindow::switchFullscreen() +{ + kDebug(5010); + + if (m_fullscreenWindow) { + // Leaving full screen mode + m_fullscreenWindow->setWindowState(0); + m_fullscreenWindow->hide(); + + m_tabWidget->setTabBarHidden(m_tabWidget->count() <= 1 && !Settings::showTabBar()); + m_tabWidget->setDocumentMode(false); + setCentralWidget(m_tabWidget); + + show(); + restoreGeometry(m_mainWindowGeometry); + if (m_systemTrayIcon) m_systemTrayIcon->setAssociatedWidget(this); + + foreach (RemoteView * view, m_remoteViewMap.values()) { + view->enableScaling(view->hostPreferences()->windowedScale()); + } + + if (m_toolBar) { + m_toolBar->hideAndDestroy(); + m_toolBar->deleteLater(); + m_toolBar = 0; + } + + actionCollection()->action("switch_fullscreen")->setIcon(KIcon("view-fullscreen")); + actionCollection()->action("switch_fullscreen")->setText(i18n("Switch to Full Screen Mode")); + actionCollection()->action("switch_fullscreen")->setIconText(i18n("Full Screen")); + + m_fullscreenWindow->deleteLater(); + m_fullscreenWindow = 0; + } else { + // Entering full screen mode + m_fullscreenWindow = new QWidget(this, Qt::Window); + m_fullscreenWindow->setWindowTitle(i18nc("window title when in full screen mode (for example displayed in tasklist)", + "KDE Remote Desktop Client (Full Screen)")); + + m_mainWindowGeometry = saveGeometry(); + + m_tabWidget->setTabBarHidden(true); + m_tabWidget->setDocumentMode(true); + + foreach(RemoteView *currentView, m_remoteViewMap) { + currentView->enableScaling(currentView->hostPreferences()->fullscreenScale()); + } + + QVBoxLayout *fullscreenLayout = new QVBoxLayout(m_fullscreenWindow); + fullscreenLayout->setContentsMargins(QMargins(0, 0, 0, 0)); + fullscreenLayout->addWidget(m_tabWidget); + + KToggleFullScreenAction::setFullScreen(m_fullscreenWindow, true); + + MinimizePixel *minimizePixel = new MinimizePixel(m_fullscreenWindow); + minimizePixel->winId(); // force it to be a native widget (prevents problem with QX11EmbedContainer) + connect(minimizePixel, SIGNAL(rightClicked()), m_fullscreenWindow, SLOT(showMinimized())); + m_fullscreenWindow->installEventFilter(this); + + m_fullscreenWindow->show(); + hide(); // hide after showing the new window so it stays on the same screen + + if (m_systemTrayIcon) m_systemTrayIcon->setAssociatedWidget(m_fullscreenWindow); + + actionCollection()->action("switch_fullscreen")->setIcon(KIcon("view-restore")); + actionCollection()->action("switch_fullscreen")->setText(i18n("Switch to Window Mode")); + actionCollection()->action("switch_fullscreen")->setIconText(i18n("Window Mode")); + showRemoteViewToolbar(); + } + if (m_tabWidget->currentWidget() == m_newConnectionWidget) { + m_addressInput->setFocus(); + } +} + +QScrollArea *MainWindow::createScrollArea(QWidget *parent, RemoteView *remoteView) +{ + RemoteViewScrollArea *scrollArea = new RemoteViewScrollArea(parent); + scrollArea->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + + connect(scrollArea, SIGNAL(resized(int,int)), remoteView, SLOT(scaleResize(int,int))); + + QPalette palette = scrollArea->palette(); + palette.setColor(QPalette::Dark, Settings::backgroundColor()); + scrollArea->setPalette(palette); + + scrollArea->setBackgroundRole(QPalette::Dark); + scrollArea->setFrameStyle(QFrame::NoFrame); + + scrollArea->setWidget(remoteView); + + return scrollArea; +} + +void MainWindow::disconnectHost() +{ + kDebug(5010); + + RemoteView *view = qobject_cast(QObject::sender()); + + QWidget *widgetToDelete; + if (view) { + widgetToDelete = (QWidget*) view->parent()->parent(); + m_remoteViewMap.remove(m_remoteViewMap.key(view)); + } else { + widgetToDelete = m_tabWidget->currentWidget(); + view = currentRemoteView(); + m_remoteViewMap.remove(m_remoteViewMap.key(view)); + } + + saveHostPrefs(view); + view->startQuitting(); // some deconstructors can't properly quit, so quit early + m_tabWidget->removePage(widgetToDelete); + widgetToDelete->deleteLater(); +#ifdef TELEPATHY_SUPPORT + m_tubesManager->closeTube(view->url()); +#endif + + // if closing the last connection, create new connection tab + if (m_tabWidget->count() == 0) { + newConnectionPage(false); + } + + // if the newConnectionWidget is the only tab and we are fullscreen, switch to window mode + if (m_fullscreenWindow && m_tabWidget->count() == 1 && m_tabWidget->currentWidget() == m_newConnectionWidget) { + switchFullscreen(); + } +} + +void MainWindow::closeTab(QWidget *widget) +{ + bool isNewConnectionPage = widget == m_newConnectionWidget; + + if (!isNewConnectionPage) { + RemoteView *view = m_remoteViewMap.value(widget); + m_remoteViewMap.remove(m_remoteViewMap.key(view)); + view->startQuitting(); +#ifdef TELEPATHY_SUPPORT + m_tubesManager->closeTube(view->url()); +#endif + widget->deleteLater(); + } + + m_tabWidget->removePage(widget); + + // if closing the last connection, create new connection tab + if (m_tabWidget->count() == 0) { + newConnectionPage(false); + } + + // if the newConnectionWidget is the only tab and we are fullscreen, switch to window mode + if (m_fullscreenWindow && m_tabWidget->count() == 1 && m_tabWidget->currentWidget() == m_newConnectionWidget) { + switchFullscreen(); + } +} + +void MainWindow::openTabSettings(QWidget *widget) +{ + RemoteViewScrollArea *scrollArea = qobject_cast(widget); + if (!scrollArea) return; + RemoteView *view = qobject_cast(scrollArea->widget()); + if (!view) return; + + const QString url = view->url().url(); + kDebug(5010) << url; + + showSettingsDialog(url); +} + +void MainWindow::showSettingsDialog(const QString &url) +{ + HostPreferences *prefs = 0; + + foreach(RemoteViewFactory *factory, remoteViewFactoriesList()) { + if (factory->supportsUrl(url)) { + prefs = factory->createHostPreferences(Settings::self()->config()->group("hostpreferences").group(url), this); + if (prefs) { + kDebug(5010) << "Found plugin to handle url (" + url + "): " + prefs->metaObject()->className(); + } else { + kDebug(5010) << "Found plugin to handle url (" + url + "), but plugin does not provide preferences"; + } + } + } + + if (prefs) { + prefs->setShownWhileConnected(true); + prefs->showDialog(this); + } else { + KMessageBox::error(this, + i18n("The selected host cannot be handled."), + i18n("Unusable URL")); + } +} + +void MainWindow::showConnectionContextMenu(const QPoint &pos) +{ + // QTableView does not take headers into account when it does mapToGlobal(), so calculate the offset + QPoint offset = QPoint(m_newConnectionTableView->verticalHeader()->size().width(), + m_newConnectionTableView->horizontalHeader()->size().height()); + QModelIndex index = m_newConnectionTableView->indexAt(pos); + + if (!index.isValid()) + return; + + const QString url = index.data(10001).toString(); + const QString title = index.model()->index(index.row(), RemoteDesktopsModel::Title).data(Qt::DisplayRole).toString(); + const QString source = index.model()->index(index.row(), RemoteDesktopsModel::Source).data(Qt::DisplayRole).toString(); + + KMenu *menu = new KMenu(m_newConnectionTableView); + menu->addTitle(url); + + QAction *connectAction = menu->addAction(KIcon("network-connect"), i18n("Connect")); + QAction *renameAction = menu->addAction(KIcon("edit-rename"), i18n("Rename")); + QAction *settingsAction = menu->addAction(KIcon("configure"), i18n("Settings")); + QAction *deleteAction = menu->addAction(KIcon("edit-delete"), i18n("Delete")); + + // not very clean, but it works, + if (!(source == i18nc("Where each displayed link comes from", "Bookmarks") || + source == i18nc("Where each displayed link comes from", "History"))) { + renameAction->setEnabled(false); + deleteAction->setEnabled(false); + } + + QAction *selectedAction = menu->exec(m_newConnectionTableView->mapToGlobal(pos + offset)); + + if (selectedAction == connectAction) { + openFromRemoteDesktopsModel(index); + } else if (selectedAction == renameAction) { + //TODO: use inline editor if possible + bool ok = false; + const QString newTitle = KInputDialog::getText(i18n("Rename %1", title), i18n("Rename %1 to", title), title, &ok, this); + if (ok && !newTitle.isEmpty()) { + BookmarkManager::updateTitle(m_bookmarkManager->getManager(), url, newTitle); + } + } else if (selectedAction == settingsAction) { + showSettingsDialog(url); + } else if (selectedAction == deleteAction) { + + if (KMessageBox::warningContinueCancel(this, i18n("Are you sure you want to delete %1?", url), i18n("Delete %1", title), + KStandardGuiItem::del()) == KMessageBox::Continue) { + BookmarkManager::removeByUrl(m_bookmarkManager->getManager(), url); + } + } + + menu->deleteLater(); +} + +void MainWindow::tabContextMenu(QWidget *widget, const QPoint &point) +{ + RemoteViewScrollArea *scrollArea = qobject_cast(widget); + if (!scrollArea) return; + RemoteView *view = qobject_cast(scrollArea->widget()); + if (!view) return; + + const QString url = view->url().prettyUrl(KUrl::RemoveTrailingSlash); + kDebug(5010) << url; + + KMenu *menu = new KMenu(this); + menu->addTitle(url); + QAction *bookmarkAction = menu->addAction(KIcon("bookmark-new"), i18n("Add Bookmark")); + QAction *closeAction = menu->addAction(KIcon("tab-close"), i18n("Close Tab")); + QAction *selectedAction = menu->exec(point); + if (selectedAction) { + if (selectedAction == closeAction) { + closeTab(widget); + } else if (selectedAction == bookmarkAction) { + m_bookmarkManager->addManualBookmark(url, url); + } + } + menu->deleteLater(); +} + +void MainWindow::showLocalCursor(bool showLocalCursor) +{ + kDebug(5010) << showLocalCursor; + + RemoteView* view = currentRemoteView(); + view->showDotCursor(showLocalCursor ? RemoteView::CursorOn : RemoteView::CursorOff); + view->hostPreferences()->setShowLocalCursor(showLocalCursor); + saveHostPrefs(view); +} + +void MainWindow::viewOnly(bool viewOnly) +{ + kDebug(5010) << viewOnly; + + RemoteView* view = currentRemoteView(); + view->setViewOnly(viewOnly); + view->hostPreferences()->setViewOnly(viewOnly); + saveHostPrefs(view); +} + +void MainWindow::grabAllKeys(bool grabAllKeys) +{ + kDebug(5010); + + RemoteView* view = currentRemoteView(); + view->setGrabAllKeys(grabAllKeys); + view->hostPreferences()->setGrabAllKeys(grabAllKeys); + saveHostPrefs(view); +} + +void MainWindow::scale(bool scale) +{ + kDebug(5010); + + RemoteView* view = currentRemoteView(); + view->enableScaling(scale); + if (m_fullscreenWindow) + view->hostPreferences()->setFullscreenScale(scale); + else + view->hostPreferences()->setWindowedScale(scale); + + saveHostPrefs(view); +} + +void MainWindow::showRemoteViewToolbar() +{ + kDebug(5010); + + if (!m_toolBar) { + m_toolBar = new FloatingToolBar(m_fullscreenWindow, m_fullscreenWindow); + m_toolBar->winId(); // force it to be a native widget (prevents problem with QX11EmbedContainer) + m_toolBar->setSide(FloatingToolBar::Top); + + KComboBox *sessionComboBox = new KComboBox(m_toolBar); + sessionComboBox->setStyleSheet("QComboBox:!editable{background:transparent;}"); + sessionComboBox->setModel(m_tabWidget->getModel()); + sessionComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + sessionComboBox->setCurrentIndex(m_tabWidget->currentIndex()); + connect(sessionComboBox, SIGNAL(activated(int)), m_tabWidget, SLOT(setCurrentIndex(int))); + connect(m_tabWidget, SIGNAL(currentChanged(int)), sessionComboBox, SLOT(setCurrentIndex(int))); + m_toolBar->addWidget(sessionComboBox); + + QToolBar *buttonBox = new QToolBar(m_toolBar); + + buttonBox->addAction(actionCollection()->action("new_connection")); + buttonBox->addAction(actionCollection()->action("switch_fullscreen")); + + QAction *minimizeAction = new QAction(m_toolBar); + minimizeAction->setIcon(KIcon("go-down")); + minimizeAction->setText(i18n("Minimize Full Screen Window")); + connect(minimizeAction, SIGNAL(triggered()), m_fullscreenWindow, SLOT(showMinimized())); + buttonBox->addAction(minimizeAction); + + buttonBox->addAction(actionCollection()->action("take_screenshot")); + buttonBox->addAction(actionCollection()->action("view_only")); + buttonBox->addAction(actionCollection()->action("show_local_cursor")); + buttonBox->addAction(actionCollection()->action("grab_all_keys")); + buttonBox->addAction(actionCollection()->action("scale")); + buttonBox->addAction(actionCollection()->action("disconnect")); + buttonBox->addAction(actionCollection()->action("file_quit")); + + QAction *stickToolBarAction = new QAction(m_toolBar); + stickToolBarAction->setCheckable(true); + stickToolBarAction->setIcon(KIcon("object-locked")); + stickToolBarAction->setText(i18n("Stick Toolbar")); + connect(stickToolBarAction, SIGNAL(triggered(bool)), m_toolBar, SLOT(setSticky(bool))); + buttonBox->addAction(stickToolBarAction); + + m_toolBar->addWidget(buttonBox); + } +} + +void setActionStatus(QAction* action, bool enabled, bool visible, bool checked) +{ + action->setEnabled(enabled); + action->setVisible(visible); + action->setChecked(checked); +} + +void MainWindow::updateActionStatus() +{ + kDebug(5010) << m_tabWidget->currentIndex(); + + bool enabled = true; + + if (m_tabWidget->currentWidget() == m_newConnectionWidget) + enabled = false; + + RemoteView* view = (m_currentRemoteView >= 0 && enabled) ? currentRemoteView() : 0; + + actionCollection()->action("take_screenshot")->setEnabled(enabled); + actionCollection()->action("disconnect")->setEnabled(enabled); + + setActionStatus(actionCollection()->action("view_only"), + enabled, + true, + view ? view->viewOnly() : false); + + setActionStatus(actionCollection()->action("show_local_cursor"), + enabled, + view ? view->supportsLocalCursor() : false, + view ? view->dotCursorState() == RemoteView::CursorOn : false); + + setActionStatus(actionCollection()->action("scale"), + enabled, + view ? view->supportsScaling() : false, + view ? view->scaling() : false); + + setActionStatus(actionCollection()->action("grab_all_keys"), + enabled, + enabled, + view ? view->grabAllKeys() : false); +} + +void MainWindow::preferences() +{ + // An instance of your dialog could be already created and could be + // cached, in which case you want to display the cached dialog + // instead of creating another one + if (PreferencesDialog::showDialog("preferences")) + return; + + // KConfigDialog didn't find an instance of this dialog, so lets + // create it: + PreferencesDialog *dialog = new PreferencesDialog(this, Settings::self()); + + // User edited the configuration - update your local copies of the + // configuration data + connect(dialog, SIGNAL(settingsChanged(QString)), + this, SLOT(updateConfiguration())); + + dialog->show(); +} + +void MainWindow::updateConfiguration() +{ + if (!Settings::showStatusBar()) + statusBar()->deleteLater(); + else + statusBar()->showMessage(""); // force creation of statusbar + + m_tabWidget->setTabBarHidden((m_tabWidget->count() <= 1 && !Settings::showTabBar()) || m_fullscreenWindow); + m_tabWidget->setTabPosition((KTabWidget::TabPosition) Settings::tabPosition()); +#if QT_VERSION >= 0x040500 + m_tabWidget->setTabsClosable(Settings::tabCloseButton()); +#else + m_tabWidget->setCloseButtonEnabled(Settings::tabCloseButton()); +#endif + disconnect(m_tabWidget, SIGNAL(mouseMiddleClick(QWidget*)), this, SLOT(closeTab(QWidget*))); // just be sure it is not connected twice + if (Settings::tabMiddleClick()) + connect(m_tabWidget, SIGNAL(mouseMiddleClick(QWidget*)), SLOT(closeTab(QWidget*))); + + if (Settings::systemTrayIcon() && !m_systemTrayIcon) { + m_systemTrayIcon = new SystemTrayIcon(this); + if(m_fullscreenWindow) m_systemTrayIcon->setAssociatedWidget(m_fullscreenWindow); + } else if (m_systemTrayIcon) { + delete m_systemTrayIcon; + m_systemTrayIcon = 0; + } + + // update the scroll areas background color + for (int i = 0; i < m_tabWidget->count(); ++i) { + QPalette palette = m_tabWidget->widget(i)->palette(); + palette.setColor(QPalette::Dark, Settings::backgroundColor()); + m_tabWidget->widget(i)->setPalette(palette); + } + + // Send update configuration message to all views + foreach (RemoteView *view, m_remoteViewMap.values()) { + view->updateConfiguration(); + } + +} + +void MainWindow::quit(bool systemEvent) +{ + const bool haveRemoteConnections = !m_remoteViewMap.isEmpty(); + if (systemEvent || !haveRemoteConnections || KMessageBox::warningContinueCancel(this, + i18n("Are you sure you want to quit the KDE Remote Desktop Client?"), + i18n("Confirm Quit"), + KStandardGuiItem::quit(), KStandardGuiItem::cancel(), + "DoNotAskBeforeExit") == KMessageBox::Continue) { + + if (Settings::rememberSessions()) { // remember open remote views for next startup + QStringList list; + foreach (RemoteView *view, m_remoteViewMap.values()) { + kDebug(5010) << view->url(); + list.append(view->url().prettyUrl(KUrl::RemoveTrailingSlash)); + } + Settings::setOpenSessions(list); + } + + saveHostPrefs(); + + foreach (RemoteView *view, m_remoteViewMap.values()) { + view->startQuitting(); + } + + Settings::self()->writeConfig(); + + qApp->quit(); + } +} + +void MainWindow::configureNotifications() +{ + KNotifyConfigWidget::configure(this); +} + +void MainWindow::showMenubar() +{ + if (m_menubarAction->isChecked()) + menuBar()->show(); + else + menuBar()->hide(); +} + +bool MainWindow::eventFilter(QObject *obj, QEvent *event) +{ + // check for close events from the fullscreen window. + if (obj == m_fullscreenWindow && event->type() == QEvent::Close) { + quit(true); + } + // allow other events to pass through. + return QObject::eventFilter(obj, event); +} + +void MainWindow::closeEvent(QCloseEvent *event) +{ + if (event->spontaneous()) { // Returns true if the event originated outside the application (a system event); otherwise returns false. + event->ignore(); + if (Settings::systemTrayIcon()) { + hide(); // just hide the mainwindow, keep it in systemtray + } else { + quit(); + } + } else { + quit(true); + } +} + +void MainWindow::saveProperties(KConfigGroup &group) +{ + kDebug(5010); + KMainWindow::saveProperties(group); + saveHostPrefs(); +} + + +void MainWindow::saveHostPrefs() +{ + foreach (RemoteView *view, m_remoteViewMap.values()) { + saveHostPrefs(view); + view->startQuitting(); + } +} + +void MainWindow::saveHostPrefs(RemoteView* view) +{ + // should saving this be a user option? + if (view && view->scaling()) { + QSize viewSize = m_tabWidget->currentWidget()->size(); + kDebug(5010) << "saving window size:" << viewSize; + view->hostPreferences()->setWidth(viewSize.width()); + view->hostPreferences()->setHeight(viewSize.height()); + } + + Settings::self()->config()->sync(); +} + +void MainWindow::tabChanged(int index) +{ + kDebug(5010) << index; + + m_tabWidget->setTabBarHidden((m_tabWidget->count() <= 1 && !Settings::showTabBar()) || m_fullscreenWindow); + + m_currentRemoteView = index; + + if (m_tabWidget->currentWidget() == m_newConnectionWidget) { + m_currentRemoteView = -1; + if(m_addressInput) m_addressInput->setFocus(); + } + + const QString tabTitle = m_tabWidget->tabText(index).remove('&'); + setCaption(tabTitle == i18n("New Connection") ? QString() : tabTitle); + + updateActionStatus(); +} + +QWidget* MainWindow::newConnectionWidget() +{ + if (m_newConnectionWidget) + return m_newConnectionWidget; + + m_newConnectionWidget = new QWidget(this); + + QVBoxLayout *startLayout = new QVBoxLayout(m_newConnectionWidget); + startLayout->setContentsMargins(QMargins(8, 12, 8, 4)); + + QLabel *headerLabel = new QLabel(m_newConnectionWidget); + headerLabel->setText(i18n("

KDE Remote Desktop Client


Enter or select the address of the desktop you would like to connect to.")); + + QLabel *headerIconLabel = new QLabel(m_newConnectionWidget); + headerIconLabel->setPixmap(KIcon("krdc").pixmap(80)); + + QHBoxLayout *headerLayout = new QHBoxLayout; + headerLayout->addWidget(headerLabel, 1, Qt::AlignTop); + headerLayout->addWidget(headerIconLabel); + startLayout->addLayout(headerLayout); + + QSortFilterProxyModel *remoteDesktopsModelProxy = new QSortFilterProxyModel(this); + remoteDesktopsModelProxy->setSourceModel(m_remoteDesktopsModel); + remoteDesktopsModelProxy->setFilterCaseSensitivity(Qt::CaseInsensitive); + remoteDesktopsModelProxy->setFilterRole(10002); + + { + QHBoxLayout *connectLayout = new QHBoxLayout; + + QLabel *addressLabel = new QLabel(i18n("Connect to:"), m_newConnectionWidget); + m_protocolInput = new KComboBox(m_newConnectionWidget); + m_addressInput = new KLineEdit(m_newConnectionWidget); + m_addressInput->setClearButtonShown(true); + m_addressInput->setClickMessage(i18n("Type here to connect to an address and filter the list.")); + connect(m_addressInput, SIGNAL(textChanged(QString)), remoteDesktopsModelProxy, SLOT(setFilterFixedString(QString))); + + foreach(RemoteViewFactory *factory, m_remoteViewFactories) { + m_protocolInput->addItem(factory->scheme()); + } + + connect(m_addressInput, SIGNAL(returnPressed()), SLOT(newConnection())); + m_addressInput->setToolTip(i18n("Type an IP or DNS Name here. Clear the line to get a list of connection methods.")); + + KPushButton *connectButton = new KPushButton(m_newConnectionWidget); + connectButton->setToolTip(i18n("Goto Address")); + connectButton->setIcon(KIcon("go-jump-locationbar")); + connect(connectButton, SIGNAL(clicked()), SLOT(newConnection())); + + connectLayout->addWidget(addressLabel); + connectLayout->addWidget(m_protocolInput); + connectLayout->addWidget(m_addressInput, 1); + connectLayout->addWidget(connectButton); + connectLayout->setContentsMargins(QMargins(0, 6, 0, 10)); + startLayout->addLayout(connectLayout); + } + + { + m_newConnectionTableView = new QTableView(m_newConnectionWidget); + m_newConnectionTableView->setModel(remoteDesktopsModelProxy); + + // set up the view so it looks nice + m_newConnectionTableView->setItemDelegate(new ConnectionDelegate(m_newConnectionTableView)); + m_newConnectionTableView->setShowGrid(false); + m_newConnectionTableView->setSelectionMode(QAbstractItemView::NoSelection); + m_newConnectionTableView->verticalHeader()->hide(); + m_newConnectionTableView->verticalHeader()->setDefaultSectionSize( + m_newConnectionTableView->fontMetrics().height() + 3); + m_newConnectionTableView->horizontalHeader()->setStretchLastSection(true); + m_newConnectionTableView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents); + m_newConnectionTableView->resizeColumnsToContents(); + m_newConnectionTableView->setAlternatingRowColors(true); + // set up sorting and actions (double click open, right click custom menu) + m_newConnectionTableView->setSortingEnabled(true); + m_newConnectionTableView->sortByColumn(Settings::connectionListSortColumn(), Qt::SortOrder(Settings::connectionListSortOrder())); + connect(m_newConnectionTableView->horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), + SLOT(saveConnectionListSort(int,Qt::SortOrder))); + connect(m_newConnectionTableView, SIGNAL(doubleClicked(QModelIndex)), + SLOT(openFromRemoteDesktopsModel(QModelIndex))); + m_newConnectionTableView->setContextMenuPolicy(Qt::CustomContextMenu); + connect(m_newConnectionTableView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(showConnectionContextMenu(QPoint))); + + startLayout->addWidget(m_newConnectionTableView); + } + + return m_newConnectionWidget; +} + +void MainWindow::saveConnectionListSort(const int logicalindex, const Qt::SortOrder order) +{ + Settings::setConnectionListSortColumn(logicalindex); + Settings::setConnectionListSortOrder(order); + Settings::self()->writeConfig(); +} + +void MainWindow::newConnectionPage(bool clearInput) +{ + const int indexOfNewConnectionWidget = m_tabWidget->indexOf(m_newConnectionWidget); + if (indexOfNewConnectionWidget >= 0) + m_tabWidget->setCurrentIndex(indexOfNewConnectionWidget); + else { + const int index = m_tabWidget->addTab(newConnectionWidget(), i18n("New Connection")); + m_tabWidget->setCurrentIndex(index); + } + if(clearInput) { + m_addressInput->clear(); + } else { + m_addressInput->selectAll(); + } + m_addressInput->setFocus(); +} + +QMap MainWindow::remoteViewList() const +{ + return m_remoteViewMap; +} + +QList MainWindow::remoteViewFactoriesList() const +{ + return m_remoteViewFactories.values(); +} + +RemoteView* MainWindow::currentRemoteView() const +{ + if (m_currentRemoteView >= 0) { + return m_remoteViewMap.value(m_tabWidget->widget(m_currentRemoteView)); + } else { + return 0; + } +} + +void MainWindow::createDockWidget() +{ + QDockWidget *remoteDesktopsDockWidget = new QDockWidget(this); + QWidget *remoteDesktopsDockLayoutWidget = new QWidget(remoteDesktopsDockWidget); + QVBoxLayout *remoteDesktopsDockLayout = new QVBoxLayout(remoteDesktopsDockLayoutWidget); + remoteDesktopsDockWidget->setObjectName("remoteDesktopsDockWidget"); // required for saving position / state + remoteDesktopsDockWidget->setWindowTitle(i18n("Remote Desktops")); + QFontMetrics fontMetrics(remoteDesktopsDockWidget->font()); + remoteDesktopsDockWidget->setMinimumWidth(fontMetrics.width("vnc://192.168.100.100:6000")); + actionCollection()->addAction("remote_desktop_dockwidget", + remoteDesktopsDockWidget->toggleViewAction()); + + m_dockWidgetTableView = new QTableView(remoteDesktopsDockLayoutWidget); + m_remoteDesktopsModel = new RemoteDesktopsModel(this); + QSortFilterProxyModel *remoteDesktopsModelProxy = new QSortFilterProxyModel(this); + remoteDesktopsModelProxy->setSourceModel(m_remoteDesktopsModel); + remoteDesktopsModelProxy->setFilterCaseSensitivity(Qt::CaseInsensitive); + remoteDesktopsModelProxy->setFilterRole(10002); + m_dockWidgetTableView->setModel(remoteDesktopsModelProxy); + + m_dockWidgetTableView->setShowGrid(false); + m_dockWidgetTableView->verticalHeader()->hide(); + m_dockWidgetTableView->verticalHeader()->setDefaultSectionSize( + m_dockWidgetTableView->fontMetrics().height() + 2); + m_dockWidgetTableView->horizontalHeader()->hide(); + m_dockWidgetTableView->horizontalHeader()->setStretchLastSection(true); + // hide all columns, then show the one we want + for (int i=0; i < remoteDesktopsModelProxy->columnCount(); i++) { + m_dockWidgetTableView->hideColumn(i); + } + m_dockWidgetTableView->showColumn(RemoteDesktopsModel::Title); + m_dockWidgetTableView->sortByColumn(RemoteDesktopsModel::Title, Qt::AscendingOrder); + + connect(m_dockWidgetTableView, SIGNAL(doubleClicked(QModelIndex)), + SLOT(openFromRemoteDesktopsModel(QModelIndex))); + + KLineEdit *filterLineEdit = new KLineEdit(remoteDesktopsDockLayoutWidget); + filterLineEdit->setClickMessage(i18n("Filter")); + filterLineEdit->setClearButtonShown(true); + connect(filterLineEdit, SIGNAL(textChanged(QString)), remoteDesktopsModelProxy, SLOT(setFilterFixedString(QString))); + remoteDesktopsDockLayout->addWidget(filterLineEdit); + remoteDesktopsDockLayout->addWidget(m_dockWidgetTableView); + remoteDesktopsDockWidget->setWidget(remoteDesktopsDockLayoutWidget); + addDockWidget(Qt::LeftDockWidgetArea, remoteDesktopsDockWidget); +} + +#include "mainwindow.moc" diff --git a/krdc/mainwindow.h b/krdc/mainwindow.h new file mode 100644 index 00000000..7f15bb1b --- /dev/null +++ b/krdc/mainwindow.h @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2007 - 2013 Urs Wolfer +** Copyright (C) 2009 - 2010 Tony Murray +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "remoteview.h" +#include "remoteviewfactory.h" + +#include +#include + +class KComboBox; +class KLineEdit; +class KPushButton; +class KToggleAction; +class KTabWidget; + +class BookmarkManager; +class FloatingToolBar; +class RemoteDesktopsModel; +class RemoteView; +class SystemTrayIcon; +class TabbedViewWidget; + +class QScrollArea; +class QModelIndex; +class QTableView; + +#ifdef TELEPATHY_SUPPORT +class TubesManager; +#endif + +class MainWindow : public KXmlGuiWindow +{ + Q_OBJECT +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + + QMap remoteViewList() const; + QList remoteViewFactoriesList() const; + RemoteView* currentRemoteView() const; + +public slots: + void newConnection(const KUrl &newUrl = KUrl(), bool switchFullscreenWhenConnected = false, const QString &tabName = QString()); + +protected: + virtual void closeEvent(QCloseEvent *event); + bool eventFilter(QObject *obj, QEvent *event); // checks for close events on fs window + virtual void saveProperties(KConfigGroup &group); + void saveHostPrefs(); + void saveHostPrefs(RemoteView *view); + +private slots: + void restoreOpenSessions(); + void quit(bool systemEvent = false); + void preferences(); + void configureNotifications(); + void showMenubar(); + void resizeTabWidget(int w, int h); + void statusChanged(RemoteView::RemoteStatus status); + void showRemoteViewToolbar(); + void takeScreenshot(); + void switchFullscreen(); + void disconnectHost(); + void closeTab(QWidget *widget); + void openTabSettings(QWidget *widget); + void tabContextMenu(QWidget *widget, const QPoint &point); + void viewOnly(bool viewOnly); + void showLocalCursor(bool showLocalCursor); + void grabAllKeys(bool grabAllKeys); + void scale(bool scale); + void updateActionStatus(); + void updateConfiguration(); + void tabChanged(int index); + QWidget* newConnectionWidget(); + void newConnectionPage(bool clearInput = true); + void openFromRemoteDesktopsModel(const QModelIndex &index); + void createDockWidget(); + void showConnectionContextMenu(const QPoint &pos); + void saveConnectionListSort(const int logicalindex, const Qt::SortOrder order); + +private: + void setupActions(); + void loadAllPlugins(); + RemoteViewFactory *createPluginFromService(const KService::Ptr &service); + void showSettingsDialog(const QString &url); + QScrollArea *createScrollArea(QWidget *parent, RemoteView *remoteView); + KUrl getInputUrl(); + + QWidget *m_fullscreenWindow; + QByteArray m_mainWindowGeometry; + + KToggleAction *m_menubarAction; + TabbedViewWidget *m_tabWidget; + KComboBox *m_protocolInput; + KLineEdit *m_addressInput; + + FloatingToolBar *m_toolBar; + + BookmarkManager *m_bookmarkManager; + + QMap m_remoteViewMap; + QMap m_remoteViewFactories; + + int m_currentRemoteView; + bool m_switchFullscreenWhenConnected; + + SystemTrayIcon *m_systemTrayIcon; + QTableView *m_dockWidgetTableView; + QTableView *m_newConnectionTableView; + RemoteDesktopsModel *m_remoteDesktopsModel; +#ifdef TELEPATHY_SUPPORT + TubesManager *m_tubesManager; +#endif + QWidget *m_newConnectionWidget; +}; + +#include +#include +#include + +class MinimizePixel : public QWidget +{ + Q_OBJECT +public: + explicit MinimizePixel(QWidget *parent) + : QWidget(parent) { + setFixedSize(1, 1); + move(QApplication::desktop()->screenGeometry().width() - 1, 0); + } + +signals: + void rightClicked(); + +protected: + void mousePressEvent(QMouseEvent *event) { + if (event->button() == Qt::RightButton) + emit rightClicked(); + } +}; + +#include + +class RemoteViewScrollArea : public QScrollArea +{ + Q_OBJECT +public: + explicit RemoteViewScrollArea(QWidget *parent) + : QScrollArea(parent) { + } + +signals: + void resized(int w, int h); + +protected: + void resizeEvent(QResizeEvent *event) { + QScrollArea::resizeEvent(event); + emit resized(width() - 2*frameWidth(), height() - 2*frameWidth()); + } +}; + +#endif diff --git a/krdc/nx/CMakeLists.txt b/krdc/nx/CMakeLists.txt new file mode 100644 index 00000000..5bbe21ca --- /dev/null +++ b/krdc/nx/CMakeLists.txt @@ -0,0 +1,55 @@ + +if(LIBNXCL_FOUND) + add_definitions(-DKDE_DEFAULT_DEBUG_AREA=5013) + + include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${LIBNXCL_INCLUDE_DIR} + ) + + set(nxplugin_SRCS + nxhostpreferences.cpp + nxclientthread.cpp + nxviewfactory.cpp + nxview.cpp + nxcallbacks.cpp + nxresumesessions.cpp + ) + + kde4_add_ui_files(nxplugin_SRCS + nxpreferences.ui + nxresumesessions.ui + ) + + kde4_add_plugin(krdc_nxplugin ${nxplugin_SRCS}) + + target_link_libraries(krdc_nxplugin + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + ${KDE4_KIO_LIBS} + ${LIBNXCL_LIBRARIES} + krdccore + ) + + set(kcm_krdc_nxplugin_SRCS + nxpreferences.cpp + ) + + kde4_add_plugin(kcm_krdc_nxplugin ${kcm_krdc_nxplugin_SRCS}) + + target_link_libraries(kcm_krdc_nxplugin + ${KDE4_KDEUI_LIBS} + krdccore + ) + + add_dependencies(kcm_krdc_nxplugin krdc_nxplugin) + + install(TARGETS kcm_krdc_nxplugin DESTINATION ${PLUGIN_INSTALL_DIR}) + install(TARGETS krdc_nxplugin DESTINATION ${PLUGIN_INSTALL_DIR}) + + install(FILES krdc_nx.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + install(FILES krdc_nx_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + + install(FILES nx.protocol DESTINATION ${SERVICES_INSTALL_DIR}) + install(FILES default.dsa.key DESTINATION ${DATA_INSTALL_DIR}/krdc) +endif(LIBNXCL_FOUND) diff --git a/krdc/nx/default.dsa.key b/krdc/nx/default.dsa.key new file mode 100644 index 00000000..c74b03a4 --- /dev/null +++ b/krdc/nx/default.dsa.key @@ -0,0 +1,12 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCXv9AzQXjxvXWC1qu3CdEqskX9YomTfyG865gb4D02ZwWuRU/9 +C3I9/bEWLdaWgJYXIcFJsMCIkmWjjeSZyTmeoypI1iLifTHUxn3b7WNWi8AzKcVF +aBsBGiljsop9NiD1mEpA0G+nHHrhvTXz7pUvYrsrXcdMyM6rxqn77nbbnwIVALCi +xFdHZADw5KAVZI7r6QatEkqLAoGBAI4L1TQGFkq5xQ/nIIciW8setAAIyrcWdK/z +5/ZPeELdq70KDJxoLf81NL/8uIc4PoNyTRJjtT3R4f8Az1TsZWeh2+ReCEJxDWgG +fbk2YhRqoQTtXPFsI4qvzBWct42WonWqyyb1bPBHk+JmXFscJu5yFQ+JUVNsENpY ++Gkz3HqTAoGANlgcCuA4wrC+3Cic9CFkqiwO/Rn1vk8dvGuEQqFJ6f6LVfPfRTfa +QU7TGVLk2CzY4dasrwxJ1f6FsT8DHTNGnxELPKRuLstGrFY/PR7KeafeFZDf+fJ3 +mbX5nxrld3wi5titTnX+8s4IKv29HJguPvOK/SI7cjzA+SqNfD7qEo8CFDIm1xRf +8xAPsSKs6yZ6j1FNklfu +-----END DSA PRIVATE KEY----- diff --git a/krdc/nx/krdc_nx.desktop b/krdc/nx/krdc_nx.desktop new file mode 100644 index 00000000..1b71a912 --- /dev/null +++ b/krdc/nx/krdc_nx.desktop @@ -0,0 +1,123 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KRDC/Plugin +Icon=krdc +Name=NX +Name[ast]=NX +Name[bg]=NX +Name[bs]=NX +Name[ca]=NX +Name[ca@valencia]=NX +Name[cs]=NX +Name[da]=NX +Name[de]=NX +Name[el]=NX +Name[en_GB]=NX +Name[eo]=NX +Name[es]=NX +Name[et]=NX +Name[eu]=NX +Name[fi]=NX +Name[fr]=NX +Name[ga]=NX +Name[gl]=NX +Name[hr]=NX +Name[hu]=NX +Name[ia]=NX +Name[is]=NX +Name[it]=NX +Name[ja]=NX +Name[kk]=NX +Name[km]=NX +Name[ko]=NX +Name[lt]=NX +Name[lv]=NX +Name[mr]=एन-एक्स +Name[nb]=NX +Name[nds]=NX +Name[nl]=NX +Name[nn]=NX +Name[pa]=NX +Name[pl]=NX +Name[pt]=NX +Name[pt_BR]=NX +Name[ro]=NX +Name[ru]=NX +Name[si]=NX +Name[sk]=NX +Name[sl]=NX +Name[sr]=НИкс +Name[sr@ijekavian]=НИкс +Name[sr@ijekavianlatin]=NX +Name[sr@latin]=NX +Name[sv]=NX +Name[tr]=NX +Name[ug]=NX +Name[uk]=NX +Name[wa]=NX +Name[x-test]=xxNXxx +Name[zh_CN]=NX +Name[zh_TW]=NX +Comment=Allows managing NX sessions through KRDC +Comment[ast]=Permite la xestión de sesiones NX per KRDC +Comment[bg]=Управление на сесии на NX с KRDC +Comment[bs]=Dopušta upravljanje NX sesijama kroz KRDC +Comment[ca]=Permet gestionar sessions NX mitjançant el KRDC +Comment[ca@valencia]=Permet gestionar sessions NX mitjançant el KRDC +Comment[cs]=Umožňuje spravování sezení NX pomocí KRDC +Comment[da]=Muliggør håndtering af NX-sessioner via KRDC +Comment[de]=Erlaubt die Verwaltung von NX-Sitzungen über KRDC +Comment[el]=Επιτρέπει τη διαχείριση συνεδριών NX μέσω του KRDC +Comment[en_GB]=Allows managing NX sessions through KRDC +Comment[es]=Permite la gestión de sesiones NX mediante KRDC +Comment[et]=NX-seansside haldamise võimaldamine KRDC kaudu +Comment[eu]=NX saioak KRDC bidez kudeatzea baimentzen du +Comment[fi]=Mahdollistaa NX-istuntojen hallinnan KRDC:llä +Comment[fr]=Permet de gérer des sessions « NX » au travers de KRDC +Comment[ga]=Ceadaíonn sé duit seisiúin NX a bhainistiú trí KRDC +Comment[gl]=Permite xestionar sesións NX por medio de KRDC +Comment[hr]=Omogućuje upravljanje sjednicama NX-a kroz KRDC +Comment[hu]=NX-elérés KRDC-ből +Comment[ia]=Permitte gerer sessiones NX per medio de KRDC +Comment[is]=Gefur kost á að stjórna NX setum með KRDC +Comment[it]=Permette di gestire sessioni NX con KRDC +Comment[ja]=KRDC から NX セッションを管理できるようにします +Comment[kk]=KRDC арқылы NX сеанстарын басқаруға мүмкіндік беру +Comment[km]=អនុញ្ញាត​ឲ្យ​គ្រប់គ្រង​សម័យ NX តាមរយៈ KRDC +Comment[ko]=KRDC를 통해서 NX 세션 관리하기 +Comment[lt]=Leidžia valdyti NX sesijas per KRDC +Comment[lv]=Ļauj pārvaldīt NX sesijas caur KRDC +Comment[nb]=Tillater å styre NX-økter gjennom KRDC +Comment[nds]=NX-Törns över KRDC plegen +Comment[nl]=Staat het beheren van NX-sessies toe via KRDC +Comment[nn]=Lèt deg handtera NX-økter gjennom KRDC +Comment[pl]=Pozwala na zarządzanie sesjami NX przez KRDC +Comment[pt]=Permite a gestão de sessões NX através do KRDC +Comment[pt_BR]=Permite o gerenciamento de sessões NX através do KRDC +Comment[ro]=Permite gestiunea sesiunilor NX prin KRDC +Comment[ru]=Разрешить управление сеансами NX через KRDC +Comment[si]=KRDC හරහා NX වාර පාලනයට ඉඩ දෙයි +Comment[sk]=Umožňuje spravovanie NX sedení pomocou KRDC +Comment[sl]=Omogoča upravljanje sej NX prek KRDC +Comment[sr]=Управљање НИкс сесијама кроз КРДЦ +Comment[sr@ijekavian]=Управљање НИкс сесијама кроз КРДЦ +Comment[sr@ijekavianlatin]=Upravljanje NX sesijama kroz KRDC +Comment[sr@latin]=Upravljanje NX sesijama kroz KRDC +Comment[sv]=Tillåter hantering av NX-sessioner via KRDC +Comment[th]=อนุญาตให้ทำการจัดการวาระการเชื่อมต่อ NX ผ่านทางโปรแกรม KRDC +Comment[tr]=NX oturumlarını KRDC üzerinden yönetmeye izin verir +Comment[uk]=Надає змогу керувати сеансами NX за допомогою KRDC +Comment[x-test]=xxAllows managing NX sessions through KRDCxx +Comment[zh_CN]=允许用户通过 KRDC 管理 NX 会话 +Comment[zh_TW]=允許透過 KRDC 管理 NX 工作階段 + +X-KDE-PluginInfo-Author=David Gross +X-KDE-PluginInfo-Email=gdavid.devel@gmail.com +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Category=Service +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true +X-KDE-Library=krdc_nxplugin +X-KDE-PluginInfo-Name=krdc_nxplugin + +X-KDE-KRDC-Sorting=40 diff --git a/krdc/nx/krdc_nx_config.desktop b/krdc/nx/krdc_nx_config.desktop new file mode 100644 index 00000000..e56114c5 --- /dev/null +++ b/krdc/nx/krdc_nx_config.desktop @@ -0,0 +1,62 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KCModule +Name=NX +Name[ast]=NX +Name[bg]=NX +Name[bs]=NX +Name[ca]=NX +Name[ca@valencia]=NX +Name[cs]=NX +Name[da]=NX +Name[de]=NX +Name[el]=NX +Name[en_GB]=NX +Name[eo]=NX +Name[es]=NX +Name[et]=NX +Name[eu]=NX +Name[fi]=NX +Name[fr]=NX +Name[ga]=NX +Name[gl]=NX +Name[hr]=NX +Name[hu]=NX +Name[ia]=NX +Name[is]=NX +Name[it]=NX +Name[ja]=NX +Name[kk]=NX +Name[km]=NX +Name[ko]=NX +Name[lt]=NX +Name[lv]=NX +Name[mr]=एन-एक्स +Name[nb]=NX +Name[nds]=NX +Name[nl]=NX +Name[nn]=NX +Name[pa]=NX +Name[pl]=NX +Name[pt]=NX +Name[pt_BR]=NX +Name[ro]=NX +Name[ru]=NX +Name[si]=NX +Name[sk]=NX +Name[sl]=NX +Name[sr]=НИкс +Name[sr@ijekavian]=НИкс +Name[sr@ijekavianlatin]=NX +Name[sr@latin]=NX +Name[sv]=NX +Name[tr]=NX +Name[ug]=NX +Name[uk]=NX +Name[wa]=NX +Name[x-test]=xxNXxx +Name[zh_CN]=NX +Name[zh_TW]=NX + +X-KDE-Library=kcm_krdc_nxplugin +X-KDE-ParentComponents=krdc_nxplugin diff --git a/krdc/nx/nx.protocol b/krdc/nx/nx.protocol new file mode 100644 index 00000000..9c939e97 --- /dev/null +++ b/krdc/nx/nx.protocol @@ -0,0 +1,12 @@ +[Protocol] +exec=krdc '%u' +protocol=nx +input=none +output=none +helper=true +listing= +reading=false +writing=false +makedir=false +deleting=false +Icon=krdc diff --git a/krdc/nx/nxcallbacks.cpp b/krdc/nx/nxcallbacks.cpp new file mode 100644 index 00000000..e42355f7 --- /dev/null +++ b/krdc/nx/nxcallbacks.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** + * ** + * ** Copyright (C) 2008 David Gross + * ** + * ** This file is part of KDE. + * ** + * ** 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; see the file COPYING. If not, write to + * ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * ** Boston, MA 02110-1301, USA. + * ** + * ****************************************************************************/ + +#include "nxcallbacks.h" + +NxCallbacks::NxCallbacks() +{ +} + +NxCallbacks::~NxCallbacks() +{ +} + +void NxCallbacks::write(std::string msg) +{ + Q_UNUSED(msg); +} + +void NxCallbacks::write(int num, std::string msg) +{ + emit progress(num, QString(msg.c_str())); +} + +void NxCallbacks::error(std::string msg) +{ + Q_UNUSED(msg); +} + +void NxCallbacks::debug(std::string msg) +{ + Q_UNUSED(msg); +} + +void NxCallbacks::stdoutSignal(std::string msg) +{ + Q_UNUSED(msg); +} + +void NxCallbacks::stderrSignal(std::string msg) +{ + Q_UNUSED(msg); +} + +void NxCallbacks::stdinSignal(std::string msg) +{ + Q_UNUSED(msg); +} + +void NxCallbacks::resumeSessionsSignal(std::list sessions) +{ + QList qsessions; + + for (std::list::const_iterator it = sessions.begin(); it != sessions.end(); ++it) + qsessions << (*it); + + emit suspendedSessions(qsessions); +} + +void NxCallbacks::noSessionsSignal() +{ + emit noSessions(); +} + +void NxCallbacks::serverCapacitySignal() +{ + emit atCapacity(); +} + +void NxCallbacks::connectedSuccessfullySignal() +{ +} diff --git a/krdc/nx/nxcallbacks.h b/krdc/nx/nxcallbacks.h new file mode 100644 index 00000000..abb994b1 --- /dev/null +++ b/krdc/nx/nxcallbacks.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2008 David Gross +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef NXCALLBACKS_H +#define NXCALLBACKS_H + +#include +#include + +#include +#include +#include +#include + +class NxCallbacks : public QObject, public nxcl::NXClientLibExternalCallbacks +{ + Q_OBJECT + +public: + NxCallbacks(); + virtual ~NxCallbacks(); + + virtual void write(std::string msg); + virtual void write(int num, std::string msg); + virtual void error(std::string msg); + virtual void debug(std::string msg); + virtual void stdoutSignal(std::string msg); + virtual void stderrSignal(std::string msg); + virtual void stdinSignal(std::string msg); + virtual void resumeSessionsSignal(std::list sessions); + virtual void noSessionsSignal(); + virtual void serverCapacitySignal(); + virtual void connectedSuccessfullySignal(); + +signals: + void progress(int, QString); + void suspendedSessions(QList); + void noSessions(); + void atCapacity(); + +}; + + +#endif diff --git a/krdc/nx/nxclientthread.cpp b/krdc/nx/nxclientthread.cpp new file mode 100644 index 00000000..b85bec3c --- /dev/null +++ b/krdc/nx/nxclientthread.cpp @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** Copyright (C) 2008 David Gross +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "nxclientthread.h" +#include "nxcallbacks.h" + +#include +#include + +#include +#include +#include + +NxClientThread::NxClientThread(QObject *parent) + : QThread(parent), + m_host(std::string()), + m_port(0), + m_privateKey(std::string()), + m_xid(0), + m_stopped(false) +{ + m_client.setSessionData(&m_data); + + QDesktopWidget *desktop = QApplication::desktop(); + int currentScreen = desktop->screenNumber(); + QRect rect = desktop->screenGeometry(currentScreen); + m_client.setResolution(rect.width(), rect.height()); + m_client.setDepth(24); + m_client.setRender(true); + + m_data.sessionName = "krdcSession"; + m_data.cache = 8; + m_data.images = 32; + m_data.linkType = "adsl"; + m_data.render = true; + m_data.backingstore = "when_requested"; + m_data.imageCompressionMethod = 2; + m_data.keyboard = "defkeymap"; + m_data.media = false; + m_data.agentServer = ""; + m_data.agentUser = ""; + m_data.agentPass = ""; + m_data.cups = 0; + m_data.suspended = false; + m_data.fullscreen = false; + m_data.encryption = true; + m_data.terminate = false; +} + +NxClientThread::~NxClientThread() +{ + stop(); + wait(500); +} + +void NxClientThread::setCallbacks(NxCallbacks *callbacks) +{ + m_client.setExternalCallbacks(callbacks); +} + +void NxClientThread::setHost(const QString &host) +{ + QMutexLocker locker(&m_mutex); + QByteArray tmp = host.toAscii(); + m_host = tmp.data(); +} + +void NxClientThread::setPort(int port) +{ + QMutexLocker locker(&m_mutex); + m_port = port; +} + +void NxClientThread::setUserName(const QString &userName) +{ + QMutexLocker locker(&m_mutex); + std::string userNameStr = std::string(userName.toAscii().data()); + m_client.setUsername(userNameStr); +} + +void NxClientThread::setPassword(const QString &password) +{ + QMutexLocker locker(&m_mutex); + std::string passwordStr = std::string(password.toAscii()); + m_client.setPassword(passwordStr); +} + +void NxClientThread::setResolution(int width, int height) +{ + QMutexLocker locker(&m_mutex); + m_data.geometry = width + 'x' + height + "+0+0"; +} + +void NxClientThread::setDesktopType(const QString &desktopType) +{ + QMutexLocker locker(&m_mutex); + QByteArray tmp = desktopType.toAscii(); + m_data.sessionType = tmp.data(); +} + +void NxClientThread::setKeyboardLayout(const QString &keyboardLayout) +{ + QMutexLocker locker(&m_mutex); + QByteArray tmp = keyboardLayout.toAscii(); + m_data.kbtype = tmp.data(); +} + +void NxClientThread::setPrivateKey(const QString &privateKey) +{ + QMutexLocker locker(&m_mutex); + QByteArray tmp = privateKey.toAscii(); + m_privateKey = tmp.data(); +} + +void NxClientThread::setSuspended(bool suspended) +{ + QMutexLocker locker(&m_mutex); + m_data.suspended = suspended; +} + +void NxClientThread::setId(const QString &id) +{ + QMutexLocker locker(&m_mutex); + QByteArray tmp = id.toAscii(); + m_data.id = tmp.data(); +} + +void NxClientThread::stop() +{ + QMutexLocker locker(&m_mutex); + m_stopped = true; +} + +void NxClientThread::run() +{ + if (m_privateKey.compare("default") == 0) { + const QString keyfilename = QString("default.dsa.key"); + const QString keyfilepath = KGlobal::dirs()->findResource("appdata", keyfilename); + + QFile file(keyfilepath); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return; + + QByteArray key; + while (!file.atEnd()) + key += file.readLine(); + + m_client.invokeNXSSH("supplied", m_host, true, key.data(), m_port); + } else + m_client.invokeNXSSH("supplied", m_host, true, m_privateKey, m_port); + + nxcl::notQProcess* p; + while (!m_client.getIsFinished() && !m_stopped) { + if (!m_client.getReadyForProxy()) { + p = m_client.getNXSSHProcess(); + p->probeProcess(); + } else { + p = m_client.getNXSSHProcess(); + p->probeProcess(); + p = m_client.getNXProxyProcess(); + p->probeProcess(); + } + + if (!this->m_xid) { + this->m_xid = m_client.getXID(); + + if (this->m_xid) + emit hasXid(this->m_xid); + } + + usleep(1000); + } +} + +void NxClientThread::startSession() +{ + m_client.runSession(); +} + +#include "moc_nxclientthread.cpp" diff --git a/krdc/nx/nxclientthread.h b/krdc/nx/nxclientthread.h new file mode 100644 index 00000000..00724786 --- /dev/null +++ b/krdc/nx/nxclientthread.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2008 David Gross +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef NXCLIENTTHREAD_H +#define NXCLIENTTHREAD_H + +#include +#include +#include + +#include "remoteview.h" + +#include +#include +#include + +#include + +#include +#include + +class NxCallbacks; + +class NxClientThread: public QThread +{ + Q_OBJECT + +public: + explicit NxClientThread(QObject *parent = 0); + ~NxClientThread(); + + void setCallbacks(NxCallbacks *callbacks); + void setHost(const QString &host); + void setPort(int port); + void setUserName(const QString &userName); + void setPassword(const QString &password); + void setResolution(int width, int height); + void setDesktopType(const QString &desktopType); + void setKeyboardLayout(const QString &keyboardLayout); + void setPrivateKey(const QString &privateKey); + void setSuspended(bool suspended); + void setId(const QString &id); + void stop(); + void startSession(); + +protected: + void run(); + +signals: + /** + * Emitted when the X Window ID of the main NX + * window is received. + * @param xid the X Window ID of the main NX window + */ + void hasXid(int xid); + +private: + nxcl::NXClientLib m_client; + nxcl::NXSessionData m_data; + + std::string m_host; + int m_port; + std::string m_privateKey; + int m_xid; + + bool m_stopped; + QMutex m_mutex; +}; + +#endif diff --git a/krdc/nx/nxhostpreferences.cpp b/krdc/nx/nxhostpreferences.cpp new file mode 100644 index 00000000..baa7f0fd --- /dev/null +++ b/krdc/nx/nxhostpreferences.cpp @@ -0,0 +1,298 @@ +/**************************************************************************** +** +** Copyright (C) 2008 David Gross +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "nxhostpreferences.h" + +#include "settings.h" + +#include +#include + +#include +#include +#include +#include + +static const QStringList keymaps = (QStringList() + << "ar" + << "cs" + << "da" + << "de" + << "de-ch" + << "en-dv" + << "en-gb" + << "en-us" + << "es" + << "et" + << "fi" + << "fo" + << "fr" + << "fr-be" + << "fr-ca" + << "fr-ch" + << "he" + << "hr" + << "hu" + << "is" + << "it" + << "ja" + << "ko" + << "lt" + << "lv" + << "mk" + << "nl" + << "nl-be" + << "no" + << "pl" + << "pt" + << "pt-br" + << "ru" + << "sl" + << "sv" + << "th" + << "tr" +); + +static const int defaultKeymap = 7; // en-us + +inline int keymap2int(const QString &keymap) +{ + const int index = keymaps.lastIndexOf(keymap); + return (index == -1) ? defaultKeymap : index; +} + +inline QString int2keymap(int layout) +{ + if (layout >= 0 && layout < keymaps.count()) + return keymaps.at(layout); + else + return keymaps.at(defaultKeymap); +} + +static const QStringList desktopTypes = (QStringList() + << "unix-kde" + << "unix-gnome" + << "unix-cde" + << "unix-xdm" +); + +static const int defaultDesktopType = 0; + +inline int desktopType2int(const QString &desktopType) +{ + const int index = desktopTypes.lastIndexOf(desktopType); + return (index == -1) ? defaultDesktopType : index; +} + +inline QString int2desktopType(int index) +{ + if (index >= 0 && index < desktopTypes.count()) + return desktopTypes.at(index); + else + return desktopTypes.at(defaultDesktopType); +} + +NxHostPreferences::NxHostPreferences(KConfigGroup configGroup, QObject *parent) + : HostPreferences(configGroup, parent) +{ +} + +NxHostPreferences::~NxHostPreferences() +{ +} + +QWidget* NxHostPreferences::createProtocolSpecificConfigPage() +{ + nxPage = new QWidget(); + nxUi.setupUi(nxPage); + + nxUi.kcfg_NxHeight->setValue(height()); + nxUi.kcfg_NxWidth->setValue(width()); + nxUi.kcfg_NxDesktopType->setCurrentIndex(desktopType2int(desktopType())); + nxUi.kcfg_NxKeyboardLayout->setCurrentIndex(keymap2int(keyboardLayout())); + + if (privateKey() == "default") { + nxUi.checkboxDefaultPrivateKey->setChecked(true); + nxUi.groupboxPrivateKey->setEnabled(false); + setDefaultPrivateKey(Qt::Checked); + } else { + nxUi.checkboxDefaultPrivateKey->setChecked(false); + nxUi.groupboxPrivateKey->setEnabled(true); + setDefaultPrivateKey(Qt::Unchecked); + } + + connect(nxUi.resolutionComboBox, SIGNAL(currentIndexChanged(int)), SLOT(updateWidthHeight(int))); + connect(nxUi.checkboxDefaultPrivateKey, SIGNAL(stateChanged(int)), SLOT(setDefaultPrivateKey(int))); + connect(nxUi.buttonImportPrivateKey, SIGNAL(pressed()), SLOT(chooseKeyFile())); + connect(nxUi.kcfg_NxPrivateKey, SIGNAL(textChanged()), SLOT(updatePrivateKey())); + + const QString resolutionString = QString::number(width()) + 'x' + QString::number(height()); + const int resolutionIndex = nxUi.resolutionComboBox->findText(resolutionString, Qt::MatchContains); + nxUi.resolutionComboBox->setCurrentIndex((resolutionIndex == -1) ? 5 : resolutionIndex); + + return nxPage; +} + +void NxHostPreferences::updateWidthHeight(int index) +{ + switch (index) { + case 0: + nxUi.kcfg_NxHeight->setValue(480); + nxUi.kcfg_NxWidth->setValue(640); + break; + case 1: + nxUi.kcfg_NxHeight->setValue(600); + nxUi.kcfg_NxWidth->setValue(800); + break; + case 2: + nxUi.kcfg_NxHeight->setValue(768); + nxUi.kcfg_NxWidth->setValue(1024); + break; + case 3: + nxUi.kcfg_NxHeight->setValue(1024); + nxUi.kcfg_NxWidth->setValue(1280); + break; + case 4: + nxUi.kcfg_NxHeight->setValue(1200); + nxUi.kcfg_NxWidth->setValue(1600); + break; + case 5: { + QDesktopWidget *desktop = QApplication::desktop(); + int currentScreen = desktop->screenNumber(nxUi.kcfg_NxHeight); + nxUi.kcfg_NxHeight->setValue(desktop->screenGeometry(currentScreen).height()); + nxUi.kcfg_NxWidth->setValue(desktop->screenGeometry(currentScreen).width()); + break; + } + case 6: + default: + break; + } + + bool enabled = (index == 6) ? true : false; + + nxUi.kcfg_NxHeight->setEnabled(enabled); + nxUi.kcfg_NxWidth->setEnabled(enabled); + nxUi.heightLabel->setEnabled(enabled); + nxUi.widthLabel->setEnabled(enabled); +} + +void NxHostPreferences::setDefaultPrivateKey(int state) +{ + if (state == Qt::Checked) { + setPrivateKey("default"); + nxUi.groupboxPrivateKey->setEnabled(false); + } else if (state == Qt::Unchecked) { + setPrivateKey(""); + nxUi.groupboxPrivateKey->setEnabled(true); + } +} + +void NxHostPreferences::updatePrivateKey() +{ + m_privateKey = nxUi.kcfg_NxPrivateKey->toPlainText(); +} + +void NxHostPreferences::chooseKeyFile() +{ + const QString fileName = KFileDialog::getOpenFileName(KUrl(QDir::homePath()), + "*.key|" + i18n("Key Files (*.key)"), + nxPage, i18n("Open DSA Key File")); + + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return; + + QByteArray key; + while (!file.atEnd()) + key += file.readLine(); + + nxUi.kcfg_NxPrivateKey->setPlainText(QString(key)); + setPrivateKey(QString(key)); +} + +void NxHostPreferences::acceptConfig() +{ + HostPreferences::acceptConfig(); + + setHeight(nxUi.kcfg_NxHeight->value()); + setWidth(nxUi.kcfg_NxWidth->value()); + setDesktopType(int2desktopType(nxUi.kcfg_NxDesktopType->currentIndex())); + setKeyboardLayout(int2keymap(nxUi.kcfg_NxKeyboardLayout->currentIndex())); +} + +void NxHostPreferences::setHeight(int height) +{ + if (height >= 0) + m_configGroup.writeEntry("height", height); +} + +int NxHostPreferences::height() +{ + return m_configGroup.readEntry("height", Settings::nxHeight()); +} + +void NxHostPreferences::setWidth(int width) +{ + if (width >= 0) + m_configGroup.writeEntry("width", width); +} + +int NxHostPreferences::width() +{ + return m_configGroup.readEntry("width", Settings::nxWidth()); +} + +void NxHostPreferences::setDesktopType(const QString &desktopType) +{ + if (!desktopType.isNull()) + m_configGroup.writeEntry("desktopType", desktopType2int(desktopType)); +} + +QString NxHostPreferences::desktopType() const +{ + return int2desktopType(m_configGroup.readEntry("desktopType", Settings::nxDesktopType())); +} + +void NxHostPreferences::setKeyboardLayout(const QString &keyboardLayout) +{ + if (!keyboardLayout.isNull()) + m_configGroup.writeEntry("keyboardLayout", keymap2int(keyboardLayout)); +} + +QString NxHostPreferences::keyboardLayout() const +{ + return int2keymap(m_configGroup.readEntry("keyboardLayout", Settings::nxKeyboardLayout())); +} + +void NxHostPreferences::setPrivateKey(const QString &privateKey) +{ + if (!privateKey.isNull()) + m_configGroup.writeEntry("privateKey", privateKey); +} + +QString NxHostPreferences::privateKey() const +{ + return m_configGroup.readEntry("privateKey", Settings::nxPrivateKey()); +} + +#include "nxhostpreferences.moc" diff --git a/krdc/nx/nxhostpreferences.h b/krdc/nx/nxhostpreferences.h new file mode 100644 index 00000000..f2d5bf8a --- /dev/null +++ b/krdc/nx/nxhostpreferences.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2008 David Gross +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef NXHOSTPREFERENCES_H +#define NXHOSTPREFERENCES_H + +#include "hostpreferences.h" +#include "ui_nxpreferences.h" + +class NxHostPreferences : public HostPreferences +{ + Q_OBJECT + +public: + explicit NxHostPreferences(KConfigGroup configGroup, QObject *parent = 0); + ~NxHostPreferences(); + + void setHeight(int height); + int height(); + void setWidth(int width); + int width(); + void setDesktopType(const QString &desktopType); + QString desktopType() const; + void setKeyboardLayout(const QString &keyboardLayout); + QString keyboardLayout() const; + void setPrivateKey(const QString &privateKey); + QString privateKey() const; + +protected: + QWidget* createProtocolSpecificConfigPage(); + void acceptConfig(); + +private: + QString m_privateKey; + Ui::NxPreferences nxUi; + QWidget *nxPage; + +private slots: + void updateWidthHeight(int index); + void setDefaultPrivateKey(int state); + void updatePrivateKey(); + void chooseKeyFile(); +}; + +#endif diff --git a/krdc/nx/nxpreferences.cpp b/krdc/nx/nxpreferences.cpp new file mode 100644 index 00000000..70713282 --- /dev/null +++ b/krdc/nx/nxpreferences.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "nxpreferences.h" +#include "remoteviewfactory.h" +#include "settings.h" + +#include "ui_nxpreferences.h" + +#include + +KRDC_PLUGIN_EXPORT(NxPreferences) + +NxPreferences::NxPreferences(QWidget *parent, const QVariantList &args) + : KCModule(KrdcFactory::componentData(), parent, args) +{ + Ui::NxPreferences nxUi; + nxUi.setupUi(this); + nxUi.resolutionComboBox->hide(); + nxUi.checkboxDefaultPrivateKey->hide(); + nxUi.buttonImportPrivateKey->hide(); + nxUi.labelPrivateKey->hide(); + nxUi.groupboxPrivateKey->hide(); + nxUi.kcfg_NxHeight->setEnabled(true); + nxUi.kcfg_NxWidth->setEnabled(true); + nxUi.heightLabel->setEnabled(true); + nxUi.widthLabel->setEnabled(true); + + addConfig(Settings::self(), this); +} + +NxPreferences::~NxPreferences() +{ +} + +void NxPreferences::load() +{ + KCModule::load(); +} + +void NxPreferences::save() +{ + KCModule::save(); +} + +#include "nxpreferences.moc" diff --git a/krdc/nx/nxpreferences.h b/krdc/nx/nxpreferences.h new file mode 100644 index 00000000..d85ff690 --- /dev/null +++ b/krdc/nx/nxpreferences.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef NXPREFERENCES_H +#define NXPREFERENCES_H + +#include "nxhostpreferences.h" + +#include + +class NxPreferences : public KCModule +{ + Q_OBJECT + +public: + explicit NxPreferences(QWidget *parent = 0, const QVariantList &args = QVariantList()); + ~NxPreferences(); + + virtual void save(); + virtual void load(); + +}; + +#endif // NXPREFERENCES_H diff --git a/krdc/nx/nxpreferences.ui b/krdc/nx/nxpreferences.ui new file mode 100644 index 00000000..3a0bed15 --- /dev/null +++ b/krdc/nx/nxpreferences.ui @@ -0,0 +1,533 @@ + + NxPreferences + + + + 0 + 0 + 561 + 471 + + + + + 0 + 0 + + + + + + + Connection + + + + + + + + Desktop &resolution: + + + resolutionComboBox + + + + + + + + + + + + + + + 280 + 0 + + + + Here you can specify the resolution of the remote desktop. This resolution determines the size of the desktop that will be presented to you. + + + 1 + + + + Minimal (640x480) + + + + + Small (800x600) + + + + + Normal (1024x768) + + + + + Large (1280x1024) + + + + + Very Large (1600x1200) + + + + + Current Screen Resolution + + + + + Custom Resolution (...) + + + + + + + + + + false + + + &Width: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + kcfg_NxWidth + + + + + + + false + + + This is the width of the remote desktop. You can only change this value manually if you select Custom as desktop resolution above. + + + 9999 + + + 800 + + + + + + + false + + + H&eight: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + kcfg_NxHeight + + + + + + + false + + + This is the height of the remote desktop. You can only change this value manually if you select Custom as desktop resolution above. + + + 9999 + + + 600 + + + + + + + + + + + Desktop &type: + + + kcfg_NxDesktopType + + + + + + + + 280 + 0 + + + + Here you can specify the desktop environment of the remote desktop. + + + + KDE + + + + + Gnome + + + + + CDE + + + + + XDM + + + + + + + + &Keyboard layout: + + + kcfg_NxKeyboardLayout + + + + + + + + 280 + 0 + + + + Use this to specify your keyboard layout. This layout setting is used to send the correct keyboard codes to the server. + + + 7 + + + + Arabic (ar) + + + + + Czech (cs) + + + + + Danish (da) + + + + + German (de) + + + + + Swiss German (de-ch) + + + + + American Dvorak (en-dv) + + + + + British English (en-gb) + + + + + US English (en-us) + + + + + Spanish (es) + + + + + Estonian (et) + + + + + Finnish (fi) + + + + + Faroese (fo) + + + + + French (fr) + + + + + Belgian (fr-be) + + + + + French Canadian (fr-ca) + + + + + Swiss French (fr-ch) + + + + + Hebrew (he) + + + + + Croatian (hr) + + + + + Hungarian (hu) + + + + + Icelandic (is) + + + + + Italian (it) + + + + + Japanese (ja) + + + + + Korean (ko) + + + + + Lithuanian (lt) + + + + + Latvian (lv) + + + + + Macedonian (mk) + + + + + Dutch (nl) + + + + + Belgian Dutch (nl-be) + + + + + Norwegian (no) + + + + + Polish (pl) + + + + + Portuguese (pt) + + + + + Brazilian (pt-br) + + + + + Russian (ru) + + + + + Slovenian (sl) + + + + + Swedish (sv) + + + + + Thai (th) + + + + + Turkish (tr) + + + + + + + + Private key: + + + + + + + + + The authentication on the NX server requires a private key. By default, it is the NoMachine DSA key. Use this box to choose the default key, or configure it by importing from a file or editing directly the textbox. + + + NoMachine Key + + + true + + + + + + + + + + + + Private Key Management + + + + + + + 0 + 0 + + + + Use this textbox to edit the private key for the authentication on the NX server. + + + + + + + + + + 0 + 0 + + + + Private DSA Key : + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + Use this button to import the private key from a file. + + + Import ... + + + + + + + + + + + + Qt::Vertical + + + + 428 + 16 + + + + + + + + + KComboBox + QComboBox +
kcombobox.h
+
+ + KTextEdit + QTextEdit +
ktextedit.h
+
+
+ + resolutionComboBox + kcfg_NxWidth + kcfg_NxHeight + kcfg_NxKeyboardLayout + + + +
diff --git a/krdc/nx/nxresumesessions.cpp b/krdc/nx/nxresumesessions.cpp new file mode 100644 index 00000000..329b02a9 --- /dev/null +++ b/krdc/nx/nxresumesessions.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2008 David Gross +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "nxresumesessions.h" + +#include +#include +#include + +#include + +NxResumeSessions::NxResumeSessions() +{ + QWidget *nxPage = new QWidget(); + nxUi.setupUi(nxPage); + + setCaption(i18n("Available NX Sessions")); + setButtons(KDialog::None); + + QVBoxLayout *layout = new QVBoxLayout(); + + KTitleWidget *titleWidget = new KTitleWidget(); + titleWidget->setText(i18n("Available NX Sessions")); + titleWidget->setPixmap(KIcon("krdc")); + layout->addWidget(titleWidget); + layout->addWidget(nxPage); + + QWidget *mainWidget = new QWidget(); + mainWidget->setLayout(layout); + setMainWidget(mainWidget); + + connect(nxUi.buttonNew, SIGNAL(pressed()), this, SLOT(pressedNew())); + connect(nxUi.buttonResume, SIGNAL(pressed()), this, SLOT(pressedResume())); +} + +NxResumeSessions::~NxResumeSessions() +{ + if (!empty()) + clear(); +} + +bool NxResumeSessions::empty() const +{ + return nxUi.sessionsList->topLevelItemCount() == 0; +} + +void NxResumeSessions::clear() +{ + nxUi.sessionsList->clear(); +} + +void NxResumeSessions::addSessions(QList sessions) +{ + for (int i = 0; i < sessions.size(); ++i) { + const nxcl::NXResumeData session = sessions.at(i); + QTreeWidgetItem *tmp = new QTreeWidgetItem(); + tmp->setText(0, QString::number(session.display)); + tmp->setText(1, QString(session.sessionType.c_str())); + tmp->setText(2, QString(session.sessionID.c_str())); + tmp->setText(3, QString::number(session.depth)); + tmp->setText(4, QString(session.screen.c_str())); + tmp->setText(5, QString(session.sessionName.c_str())); + + nxUi.sessionsList->addTopLevelItem(tmp); + } +} + +void NxResumeSessions::show() +{ + adjustSize(); + + if (exec() == KDialog::Rejected) + pressedNew(); +} + +void NxResumeSessions::pressedNew() +{ + emit newSession(); +} + +void NxResumeSessions::pressedResume() +{ + emit resumeSession(QString("")); +} + diff --git a/krdc/nx/nxresumesessions.h b/krdc/nx/nxresumesessions.h new file mode 100644 index 00000000..b54e8504 --- /dev/null +++ b/krdc/nx/nxresumesessions.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2008 David Gross +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef NXRESUMESESSIONS_H +#define NXRESUMESESSIONS_H + +#include "ui_nxresumesessions.h" + +#include +#include +#include +#include + +class NxResumeSessions : public KDialog +{ + Q_OBJECT + +public: + explicit NxResumeSessions(); + ~NxResumeSessions(); + bool empty() const; + void clear(); + void addSessions(QList sessions); + void show(); + +private: + Ui::NxSessions nxUi; + +private slots: + void pressedNew(); + void pressedResume(); + +signals: + void newSession(); + void resumeSession(QString); +}; + +#endif diff --git a/krdc/nx/nxresumesessions.ui b/krdc/nx/nxresumesessions.ui new file mode 100644 index 00000000..83d0da96 --- /dev/null +++ b/krdc/nx/nxresumesessions.ui @@ -0,0 +1,94 @@ + + NxSessions + + + + 0 + 0 + 725 + 260 + + + + + 9 + + + 6 + + + + + + Display + + + + + Type + + + + + Session ID + + + + + Colour Depth + + + + + Resolution + + + + + Session Name + + + + + + + + 0 + + + 6 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + &New + + + + + + + &Resume + + + + + + + + + + diff --git a/krdc/nx/nxview.cpp b/krdc/nx/nxview.cpp new file mode 100644 index 00000000..ffe3658f --- /dev/null +++ b/krdc/nx/nxview.cpp @@ -0,0 +1,278 @@ +/**************************************************************************** +** +** Copyright (C) 2008 David Gross +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "nxview.h" +#include "settings.h" + +#include + +#include +#include +#include + +#include +#include + +NxView::NxView(QWidget *parent, const KUrl &url, KConfigGroup configGroup) + : RemoteView(parent), + m_quitFlag(false), + m_container(NULL), + m_hostPreferences(NULL) +{ + m_url = url; + m_host = url.host(); + m_port = url.port(); + + if (m_port <= 0 || m_port >= 65536) + m_port = TCP_PORT_NX; + + m_container = new QX11EmbedContainer(this); + m_container->installEventFilter(this); + + qRegisterMetaType >("QList"); + + m_clientThread.setCallbacks(&m_callbacks); + + connect(&m_clientThread, SIGNAL(hasXid(int)), this, SLOT(hasXid(int))); + connect(&m_callbacks, SIGNAL(progress(int,QString)), this, SLOT(handleProgress(int,QString))); + connect(&m_callbacks, SIGNAL(suspendedSessions(QList)), this, SLOT(handleSuspendedSessions(QList))); + connect(&m_callbacks, SIGNAL(noSessions()), this, SLOT(handleNoSessions())); + connect(&m_callbacks, SIGNAL(atCapacity()), this, SLOT(handleAtCapacity())); + connect(&m_resumeSessions, SIGNAL(newSession()), this, SLOT(handleNewSession())); + connect(&m_resumeSessions, SIGNAL(resumeSession(QString)), this, SLOT(handleResumeSession(QString))); + + m_hostPreferences = new NxHostPreferences(configGroup, this); +} + +NxView::~NxView() +{ +} + +// filter out key and mouse events to the container if we are view only +//FIXME: X11 events are passed to the app before getting caught in the Qt event processing +bool NxView::eventFilter(QObject *obj, QEvent *event) +{ + if (m_viewOnly) { + if (event->type() == QEvent::KeyPress || + event->type() == QEvent::KeyRelease || + event->type() == QEvent::MouseButtonDblClick || + event->type() == QEvent::MouseButtonPress || + event->type() == QEvent::MouseButtonRelease || + event->type() == QEvent::MouseMove) + return true; + } + + return RemoteView::eventFilter(obj, event); +} + +void NxView::startQuitting() +{ + kDebug(5013) << "about to quit"; + + const bool connected = status() == RemoteView::Connected; + setStatus(Disconnecting); + m_quitFlag = true; + + if (connected) + m_clientThread.stop(); + else + m_clientThread.quit(); + + m_clientThread.wait(500); + setStatus(Disconnected); + m_container->discardClient(); +} + +bool NxView::isQuitting() +{ + return m_quitFlag; +} + +bool NxView::start() +{ + m_clientThread.setResolution(m_hostPreferences->width(), m_hostPreferences->height()); + m_clientThread.setDesktopType(m_hostPreferences->desktopType()); + m_clientThread.setKeyboardLayout(m_hostPreferences->keyboardLayout()); + m_clientThread.setPrivateKey(m_hostPreferences->privateKey()); + + m_container->show(); + + if (m_hostPreferences->walletSupport()) { + if (m_url.userName().isEmpty()) { + QString userName; + bool ok = false; + + userName = KInputDialog::getText(i18n("Enter Username"), + i18n("Please enter the username you would like to use for login."), + QString(), &ok, this); + + if (ok) + m_url.setUserName(userName); + } + + if (!m_url.userName().isEmpty()) { + QString walletPassword = readWalletPassword(); + + if (!walletPassword.isNull()) + m_url.setPassword(walletPassword); + else { + KPasswordDialog dialog(this); + dialog.setPrompt(i18n("Access to the system requires a password.")); + if (dialog.exec() == KPasswordDialog::Accepted) { + m_url.setPassword(dialog.password()); + + if (m_hostPreferences->walletSupport()) + saveWalletPassword(dialog.password()); + } + } + } + } + + m_clientThread.setHost(m_host); + m_clientThread.setPort(m_port); + m_clientThread.setUserName(m_url.userName()); + m_clientThread.setPassword(m_url.password()); + m_clientThread.setResolution(m_hostPreferences->width(), m_hostPreferences->height()); + + setStatus(Connecting); + m_clientThread.start(); + + connect(m_container, SIGNAL(clientIsEmbedded()), SLOT(connectionOpened())); + connect(m_container, SIGNAL(clientClosed()), SLOT(connectionClosed())); + + return true; +} + +HostPreferences* NxView::hostPreferences() +{ + return m_hostPreferences; +} + +QSize NxView::framebufferSize() +{ + return m_container->minimumSizeHint(); +} + +QSize NxView::sizeHint() const +{ + return maximumSize(); +} + + +void NxView::switchFullscreen(bool on) +{ + setGrabAllKeys(on); +} + +void NxView::setGrabAllKeys(bool grabAllKeys) +{ + m_grabAllKeys = grabAllKeys; + + if (grabAllKeys) { + m_keyboardIsGrabbed = true; + m_container->grabKeyboard(); + } else if (m_keyboardIsGrabbed) + m_container->releaseKeyboard(); +} + +void NxView::hasXid(int xid) +{ + m_container->embedClient(xid); +} + +void NxView::handleProgress(int id, QString msg) +{ + Q_UNUSED(msg); + switch (id) { + case NXCL_AUTH_FAILED: + KMessageBox::error(this, i18n("The authentication key is invalid."), i18n("Invalid authentication key")); + break; + case NXCL_LOGIN_FAILED: + KMessageBox::error(this, i18n("The username or password that you have entered is invalid."), i18n("Invalid username or password")); + break; + case NXCL_HOST_KEY_VERIFAILED: + KMessageBox::error(this, i18n("The host key verification has failed."), i18n("Host key verification failed")); + break; + case NXCL_PROCESS_ERROR: + KMessageBox::error(this, i18n("An error has occurred during the connection to the NX server."), i18n("Process error")); + break; + default: + break; + } +} + +void NxView::handleSuspendedSessions(QList sessions) +{ + if (!m_resumeSessions.empty()) + m_resumeSessions.clear(); + + m_resumeSessions.addSessions(sessions); + m_resumeSessions.show(); +} + +void NxView::handleNoSessions() +{ + m_clientThread.setSuspended(false); + m_clientThread.startSession(); +} + +void NxView::handleAtCapacity() +{ + KMessageBox::error(this, i18n("This NX server is running at capacity."), i18n("Server at capacity")); +} + +void NxView::handleNewSession() +{ + m_clientThread.setSuspended(false); + m_clientThread.startSession(); +} + +void NxView::handleResumeSession(QString id) +{ + m_clientThread.setId(id); + m_clientThread.setSuspended(true); + m_clientThread.startSession(); +} + +void NxView::connectionOpened() +{ + kDebug(5013) << "Connection opened"; + QSize size(m_hostPreferences->width(), m_hostPreferences->height()); + kDebug(5013) << "Size hint: " << size.width() << size.height(); + setStatus(Connected); + setFixedSize(size); + resize(size); + m_container->setFixedSize(size); + emit framebufferSizeChanged(size.width(), size.height()); + emit connected(); + setFocus(); +} + +void NxView::connectionClosed() +{ + emit disconnected(); + setStatus(Disconnected); + m_quitFlag = true; +} + +#include "nxview.moc" diff --git a/krdc/nx/nxview.h b/krdc/nx/nxview.h new file mode 100644 index 00000000..6a975f76 --- /dev/null +++ b/krdc/nx/nxview.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2008 David Gross +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef NXVIEW_H +#define NXVIEW_H + +#include "remoteview.h" +#include "nxcallbacks.h" +#include "nxclientthread.h" +#include "nxhostpreferences.h" +#include "nxresumesessions.h" + +#include + +#define TCP_PORT_NX 22 + +class NxView : public RemoteView +{ + Q_OBJECT + +public: + explicit NxView(QWidget *parent = 0, const KUrl &url = KUrl(), KConfigGroup configGroup = KConfigGroup()); + virtual ~NxView(); + + // Start closing the connection + virtual void startQuitting(); + // If we are currently closing the connection + virtual bool isQuitting(); + // Open a connection + virtual bool start(); + + // Returns the size of the remote view + virtual QSize framebufferSize(); + // Returns the suggested size of the remote view + QSize sizeHint() const; + virtual void setGrabAllKeys(bool grabAllKeys); + + HostPreferences* hostPreferences(); + +public slots: + void switchFullscreen(bool on); + void hasXid(int xid); + void handleProgress(int id, QString msg); + void handleSuspendedSessions(QList sessions); + void handleNoSessions(); + void handleAtCapacity(); + void handleNewSession(); + void handleResumeSession(QString id); + void connectionOpened(); + void connectionClosed(); + +protected: + bool eventFilter(QObject *obj, QEvent *event); + +private: + // Thread that manage NX connection + NxClientThread m_clientThread; + // NX Callbacks + NxCallbacks m_callbacks; + // If we are currently closing the connection + bool m_quitFlag; + // Widget which contains the NX Window + QX11EmbedContainer *m_container; + // Dialog which allows user to choose NX preferences. + NxHostPreferences *m_hostPreferences; + // Dialog which allows user to resume NX sessions. + NxResumeSessions m_resumeSessions; +}; + +#endif diff --git a/krdc/nx/nxviewfactory.cpp b/krdc/nx/nxviewfactory.cpp new file mode 100644 index 00000000..de87678b --- /dev/null +++ b/krdc/nx/nxviewfactory.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "nxviewfactory.h" + +#include + +KRDC_PLUGIN_EXPORT(NxViewFactory) + +NxViewFactory::NxViewFactory(QObject *parent, const QVariantList &args) + : RemoteViewFactory(parent) +{ + Q_UNUSED(args); + + KGlobal::locale()->insertCatalog("krdc"); +} + +NxViewFactory::~NxViewFactory() +{ +} + +bool NxViewFactory::supportsUrl(const KUrl &url) const +{ + return (url.scheme().compare("nx", Qt::CaseInsensitive) == 0); +} + +RemoteView *NxViewFactory::createView(QWidget *parent, const KUrl &url, KConfigGroup configGroup) +{ + return new NxView(parent, url, configGroup); +} + +HostPreferences *NxViewFactory::createHostPreferences(KConfigGroup configGroup, QWidget *parent) +{ + return new NxHostPreferences(configGroup, parent); +} + +QString NxViewFactory::scheme() const +{ + return "nx"; +} + +QString NxViewFactory::connectActionText() const +{ + return i18n("New NX Connection..."); +} + +QString NxViewFactory::connectButtonText() const +{ + return i18n("Connect to a NX Remote Desktop"); +} + +QString NxViewFactory::connectToolTipText() const +{ + return i18n("Enter the address here.
" + "Example: nxserver (host)"); +} + +#include "moc_nxviewfactory.cpp" diff --git a/krdc/nx/nxviewfactory.h b/krdc/nx/nxviewfactory.h new file mode 100644 index 00000000..824919c6 --- /dev/null +++ b/krdc/nx/nxviewfactory.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef NXVIEWFACTORY_H +#define NXVIEWFACTORY_H + +#include "remoteviewfactory.h" + +#include "nxview.h" +#include "nxpreferences.h" + +class NxViewFactory : public RemoteViewFactory +{ + Q_OBJECT + +public: + explicit NxViewFactory(QObject *parent, const QVariantList &args); + + virtual ~NxViewFactory(); + + virtual bool supportsUrl(const KUrl &url) const; + + virtual RemoteView *createView(QWidget *parent, const KUrl &url, KConfigGroup configGroup); + + virtual HostPreferences *createHostPreferences(KConfigGroup configGroup, QWidget *parent); + + virtual QString scheme() const; + + virtual QString connectActionText() const; + + virtual QString connectButtonText() const; + + virtual QString connectToolTipText() const; +}; + +#endif // NXVIEWFACTORY_H diff --git a/krdc/org.freedesktop.Telepathy.Client.krdc_rfb_handler.service.in b/krdc/org.freedesktop.Telepathy.Client.krdc_rfb_handler.service.in new file mode 100644 index 00000000..891a3d9f --- /dev/null +++ b/krdc/org.freedesktop.Telepathy.Client.krdc_rfb_handler.service.in @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.freedesktop.Telepathy.Client.krdc_rfb_handler +Exec=@CMAKE_INSTALL_PREFIX@/bin/krdc diff --git a/krdc/pointcursor.png b/krdc/pointcursor.png new file mode 100644 index 00000000..d441027d Binary files /dev/null and b/krdc/pointcursor.png differ diff --git a/krdc/pointcursormask.png b/krdc/pointcursormask.png new file mode 100644 index 00000000..ceb6afae Binary files /dev/null and b/krdc/pointcursormask.png differ diff --git a/krdc/rdp/CMakeLists.txt b/krdc/rdp/CMakeLists.txt new file mode 100644 index 00000000..19138ec0 --- /dev/null +++ b/krdc/rdp/CMakeLists.txt @@ -0,0 +1,52 @@ + +if(Q_WS_X11) + set(HAVE_XFREERDP true) +endif(Q_WS_X11) + +if(HAVE_XFREERDP) + add_definitions(-DKDE_DEFAULT_DEBUG_AREA=5012) + + include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ) + + set(rdpplugin_SRCS + rdphostpreferences.cpp + rdpviewfactory.cpp + rdpview.cpp + ) + + kde4_add_ui_files(rdpplugin_SRCS + rdppreferences.ui + ) + + kde4_add_plugin(krdc_rdpplugin ${rdpplugin_SRCS}) + + target_link_libraries(krdc_rdpplugin + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + krdccore + ) + + set(kcm_krdc_rdpplugin_SRCS + rdppreferences.cpp + ) + + kde4_add_plugin(kcm_krdc_rdpplugin ${kcm_krdc_rdpplugin_SRCS}) + + target_link_libraries(kcm_krdc_rdpplugin + ${KDE4_KDEUI_LIBS} + krdccore + ) + + add_dependencies(kcm_krdc_rdpplugin krdc_rdpplugin) + + install(TARGETS kcm_krdc_rdpplugin DESTINATION ${PLUGIN_INSTALL_DIR}) + install(TARGETS krdc_rdpplugin DESTINATION ${PLUGIN_INSTALL_DIR}) + + install(FILES krdc_rdp.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + install(FILES krdc_rdp_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + + install(FILES rdp.protocol DESTINATION ${SERVICES_INSTALL_DIR}) + install(FILES smb2rdc.desktop DESTINATION ${SERVICES_INSTALL_DIR}/ServiceMenus) +endif(HAVE_XFREERDP) diff --git a/krdc/rdp/krdc_rdp.desktop b/krdc/rdp/krdc_rdp.desktop new file mode 100644 index 00000000..66aab74b --- /dev/null +++ b/krdc/rdp/krdc_rdp.desktop @@ -0,0 +1,124 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KRDC/Plugin +Icon=krdc +Name=RDP +Name[ast]=RDP +Name[bg]=RDP +Name[bs]=RDP +Name[ca]=RDP +Name[ca@valencia]=RDP +Name[cs]=RDP +Name[da]=RDP +Name[de]=RDP +Name[el]=RDP +Name[en_GB]=RDP +Name[eo]=RDP +Name[es]=RDP +Name[et]=RDP +Name[eu]=RDP +Name[fi]=RDP +Name[fr]=RDP +Name[ga]=RDP +Name[gl]=RDP +Name[hr]=RDP +Name[hu]=RDP +Name[ia]=RDP +Name[is]=RDP +Name[it]=RDP +Name[ja]=RDP +Name[kk]=RDP +Name[km]=RDP +Name[ko]=RDP +Name[lt]=RDP +Name[lv]=RDP +Name[mr]=आर-डी-पी +Name[nb]=RDP +Name[nds]=RDP +Name[nl]=RDP +Name[nn]=RDP +Name[pa]=RDP +Name[pl]=RDP +Name[pt]=RDP +Name[pt_BR]=RDP +Name[ro]=RDP +Name[ru]=Базовая программа RDP +Name[si]=RDP +Name[sk]=RDP +Name[sl]=RDP +Name[sr]=РДП +Name[sr@ijekavian]=РДП +Name[sr@ijekavianlatin]=RDP +Name[sr@latin]=RDP +Name[sv]=RDP +Name[tr]=RDP +Name[ug]=RDP +Name[uk]=RDP +Name[wa]=RDP +Name[x-test]=xxRDPxx +Name[zh_CN]=RDP +Name[zh_TW]=RDP +Comment=Allows managing RDP sessions through KRDC +Comment[ast]=Permite la xestión de sesiones RDP per KRDC +Comment[bg]=Управление на сесии на RDP с KRDC +Comment[bs]=Dopušta upravljanje RPD sesijama kroz KRDC +Comment[ca]=Permet gestionar sessions RDP mitjançant el KRDC +Comment[ca@valencia]=Permet gestionar sessions RDP mitjançant el KRDC +Comment[cs]=Umožňuje spravování sezení RDP pomocí KRDC +Comment[da]=Muliggør håndtering af RDP-sessioner via KRDC +Comment[de]=Erlaubt die Verwaltung von RDP-Sitzungen über KRDC +Comment[el]=Επιτρέπει τη διαχείριση συνεδριών RDP μέσω του KRDC +Comment[en_GB]=Allows managing RDP sessions through KRDC +Comment[es]=Permite la gestión de sesiones RDP mediante KRDC +Comment[et]=RDP-seansside haldamise võimaldamine KRDC kaudu +Comment[eu]=RDP saioak KRDC bidez kudeatzea baimentzen du +Comment[fi]=Sallii RDP-istuntojen hallinnan KRDC:n kautta +Comment[fr]=Permet de gérer des sessions « RDP » au travers de KRDC +Comment[ga]=Ceadaíonn sé duit seisiúin RDP a bhainistiú trí KRDC +Comment[gl]=Permite xestionar sesións RDP por medio de KRDC +Comment[hr]=Omogućuje upravljanje sjednicama RDP-a kroz KRDC +Comment[hu]=RDP-kezelés KRDC-ből +Comment[ia]=Permitte gerer sessiones RDP per medio de KRDC +Comment[is]=Gefur kost á að stjórna RDP setum með KRDC +Comment[it]=Permette di gestire sessioni RDP con KRDC +Comment[ja]=KRDC から RDP セッションを管理できるようにします +Comment[kk]=KRDC арқылы RDP сеанстарын басқаруға мүмкіндік беру +Comment[km]=អនុញ្ញាត​ឲ្យ​គ្រប់គ្រង​សម័យ​របស់ RDP តាមរយៈ KRDC +Comment[ko]=KRDC를 통해서 RDP 세션 관리하기 +Comment[lt]=Leidžia valdyti RDP sesijas per KRDC +Comment[lv]=Ļauj pārvaldīt RDP sesijas caur KRDC +Comment[nb]=Tillater å styre RDP-økter gjennom KRDC +Comment[nds]=RDP-Törns över KRDC plegen +Comment[nl]=Staat het beheer van RDP-sessies toe via KRDC +Comment[nn]=Lèt deg handtera RDP-økter gjennom KRDC +Comment[pa]=KRDC ਰਾਹੀਂ RDP ਸ਼ੈਸ਼ਨਾਂ ਦੇ ਪਰਬੰਧ ਦੀ ਮਨਜ਼ੂਰੀ +Comment[pl]=Pozwala na zarządzanie sesjami RDP przez KRDC +Comment[pt]=Permite a gestão de sessões RDP através do KRDC +Comment[pt_BR]=Permite o gerenciamento de sessões RDP através do KRDC +Comment[ro]=Permite gestiunea sesiunilor RDP prin KRDC +Comment[ru]=Разрешить управление сеансами RDP через KRDC +Comment[si]=KRDC හරහා RDP වාර පාලනයට ඉඩ දෙයි +Comment[sk]=Umožňuje spravovanie RDP sedení pomocou KRDC +Comment[sl]=Omogoča upravljanje sej RDP prek KRDC +Comment[sr]=Управљање РДП сесијама кроз КРДЦ +Comment[sr@ijekavian]=Управљање РДП сесијама кроз КРДЦ +Comment[sr@ijekavianlatin]=Upravljanje RDP sesijama kroz KRDC +Comment[sr@latin]=Upravljanje RDP sesijama kroz KRDC +Comment[sv]=Tillåter hantering av RDP-sessioner via KRDC +Comment[th]=อนุญาตให้ทำการจัดการวาระการเชื่อมต่อ RDP ผ่านทางโปรแกรม KRDC +Comment[tr]=RDP oturumlarını KRDC üzerinden yönetmeye izin verir +Comment[uk]=Надає змогу керувати сеансами RDP за допомогою KRDC +Comment[x-test]=xxAllows managing RDP sessions through KRDCxx +Comment[zh_CN]=允许用户通过 KRDC 管理 RDP会话 +Comment[zh_TW]=允許透過 KRDC 管理 RDP 工作階段 + +X-KDE-PluginInfo-Author=Urs Wolfer +X-KDE-PluginInfo-Email=uwolfer@kde.org +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Category=Service +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true +X-KDE-Library=krdc_rdpplugin +X-KDE-PluginInfo-Name=krdc_rdpplugin + +X-KDE-KRDC-Sorting=60 diff --git a/krdc/rdp/krdc_rdp_config.desktop b/krdc/rdp/krdc_rdp_config.desktop new file mode 100644 index 00000000..9b7ea4ce --- /dev/null +++ b/krdc/rdp/krdc_rdp_config.desktop @@ -0,0 +1,62 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KCModule +Name=RDP +Name[ast]=RDP +Name[bg]=RDP +Name[bs]=RDP +Name[ca]=RDP +Name[ca@valencia]=RDP +Name[cs]=RDP +Name[da]=RDP +Name[de]=RDP +Name[el]=RDP +Name[en_GB]=RDP +Name[eo]=RDP +Name[es]=RDP +Name[et]=RDP +Name[eu]=RDP +Name[fi]=RDP +Name[fr]=RDP +Name[ga]=RDP +Name[gl]=RDP +Name[hr]=RDP +Name[hu]=RDP +Name[ia]=RDP +Name[is]=RDP +Name[it]=RDP +Name[ja]=RDP +Name[kk]=RDP +Name[km]=RDP +Name[ko]=RDP +Name[lt]=RDP +Name[lv]=RDP +Name[mr]=आर-डी-पी +Name[nb]=RDP +Name[nds]=RDP +Name[nl]=RDP +Name[nn]=RDP +Name[pa]=RDP +Name[pl]=RDP +Name[pt]=RDP +Name[pt_BR]=RDP +Name[ro]=RDP +Name[ru]=Базовая программа RDP +Name[si]=RDP +Name[sk]=RDP +Name[sl]=RDP +Name[sr]=РДП +Name[sr@ijekavian]=РДП +Name[sr@ijekavianlatin]=RDP +Name[sr@latin]=RDP +Name[sv]=RDP +Name[tr]=RDP +Name[ug]=RDP +Name[uk]=RDP +Name[wa]=RDP +Name[x-test]=xxRDPxx +Name[zh_CN]=RDP +Name[zh_TW]=RDP + +X-KDE-Library=kcm_krdc_rdpplugin +X-KDE-ParentComponents=krdc_rdpplugin diff --git a/krdc/rdp/rdp.protocol b/krdc/rdp/rdp.protocol new file mode 100644 index 00000000..340ec57b --- /dev/null +++ b/krdc/rdp/rdp.protocol @@ -0,0 +1,12 @@ +[Protocol] +exec=krdc '%u' +protocol=rdp +input=none +output=none +helper=true +listing= +reading=false +writing=false +makedir=false +deleting=false +Icon=krdc diff --git a/krdc/rdp/rdphostpreferences.cpp b/krdc/rdp/rdphostpreferences.cpp new file mode 100644 index 00000000..8bcde738 --- /dev/null +++ b/krdc/rdp/rdphostpreferences.cpp @@ -0,0 +1,274 @@ +/**************************************************************************** +** +** Copyright (C) 2007 - 2012 Urs Wolfer +** Copyright (C) 2012 AceLan Kao +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "rdphostpreferences.h" + +#include "settings.h" + +#include + +#include + +static const QStringList keymaps = (QStringList() + << "ar" + << "cs" + << "da" + << "de" + << "de-ch" + << "en-dv" + << "en-gb" + << "en-us" + << "es" + << "et" + << "fi" + << "fo" + << "fr" + << "fr-be" + << "fr-ca" + << "fr-ch" + << "he" + << "hr" + << "hu" + << "is" + << "it" + << "ja" + << "ko" + << "lt" + << "lv" + << "mk" + << "nl" + << "nl-be" + << "no" + << "pl" + << "pt" + << "pt-br" + << "ru" + << "sl" + << "sv" + << "th" + << "tr" +); + +static const int defaultKeymap = 7; // en-us + +inline int keymap2int(const QString &keymap) +{ + const int index = keymaps.lastIndexOf(keymap); + return (index == -1) ? defaultKeymap : index; +} + +inline QString int2keymap(int layout) +{ + if (layout >= 0 && layout < keymaps.count()) + return keymaps.at(layout); + else + return keymaps.at(defaultKeymap); +} + +RdpHostPreferences::RdpHostPreferences(KConfigGroup configGroup, QObject *parent) + : HostPreferences(configGroup, parent) +{ +} + +RdpHostPreferences::~RdpHostPreferences() +{ +} + +QWidget* RdpHostPreferences::createProtocolSpecificConfigPage() +{ + QWidget *rdpPage = new QWidget(); + rdpUi.setupUi(rdpPage); + + rdpUi.loginGroupBox->setVisible(false); + + rdpUi.kcfg_Height->setValue(height()); + rdpUi.kcfg_Width->setValue(width()); + rdpUi.kcfg_ColorDepth->setCurrentIndex(colorDepth()); + rdpUi.kcfg_KeyboardLayout->setCurrentIndex(keymap2int(keyboardLayout())); + rdpUi.kcfg_Sound->setCurrentIndex(sound()); + rdpUi.kcfg_Console->setChecked(console()); + rdpUi.kcfg_ExtraOptions->setText(extraOptions()); + rdpUi.kcfg_RemoteFX->setChecked(remoteFX()); + rdpUi.kcfg_Performance->setCurrentIndex(performance()); + rdpUi.kcfg_ShareMedia->setText(shareMedia()); + + connect(rdpUi.resolutionComboBox, SIGNAL(currentIndexChanged(int)), SLOT(updateWidthHeight(int))); + + const QString resolutionString = QString::number(width()) + 'x' + QString::number(height()); + const int resolutionIndex = rdpUi.resolutionComboBox->findText(resolutionString, Qt::MatchContains); + rdpUi.resolutionComboBox->setCurrentIndex((resolutionIndex == -1) ? rdpUi.resolutionComboBox->count() - 2 : resolutionIndex); // - 2 is index of custom resolution + + return rdpPage; +} + +void RdpHostPreferences::updateWidthHeight(int index) +{ + switch (index) { + case 0: + rdpUi.kcfg_Height->setValue(480); + rdpUi.kcfg_Width->setValue(640); + break; + case 1: + rdpUi.kcfg_Height->setValue(600); + rdpUi.kcfg_Width->setValue(800); + break; + case 2: + rdpUi.kcfg_Height->setValue(768); + rdpUi.kcfg_Width->setValue(1024); + break; + case 3: + rdpUi.kcfg_Height->setValue(1024); + rdpUi.kcfg_Width->setValue(1280); + break; + case 4: + rdpUi.kcfg_Height->setValue(1200); + rdpUi.kcfg_Width->setValue(1600); + break; + case 5: { + QDesktopWidget *desktop = QApplication::desktop(); + int currentScreen = desktop->screenNumber(rdpUi.kcfg_Height); + rdpUi.kcfg_Height->setValue(desktop->screenGeometry(currentScreen).height()); + rdpUi.kcfg_Width->setValue(desktop->screenGeometry(currentScreen).width()); + break; + } + case 7: + rdpUi.kcfg_Height->setValue(0); + rdpUi.kcfg_Width->setValue(0); + break; + case 6: + default: + break; + } + + const bool enabled = (index == 6) ? true : false; + + rdpUi.kcfg_Height->setEnabled(enabled); + rdpUi.kcfg_Width->setEnabled(enabled); + rdpUi.heightLabel->setEnabled(enabled); + rdpUi.widthLabel->setEnabled(enabled); +} + +void RdpHostPreferences::acceptConfig() +{ + HostPreferences::acceptConfig(); + + setHeight(rdpUi.kcfg_Height->value()); + setWidth(rdpUi.kcfg_Width->value()); + setColorDepth(rdpUi.kcfg_ColorDepth->currentIndex()); + setKeyboardLayout(int2keymap(rdpUi.kcfg_KeyboardLayout->currentIndex())); + setSound(rdpUi.kcfg_Sound->currentIndex()); + setConsole(rdpUi.kcfg_Console->isChecked()); + setExtraOptions(rdpUi.kcfg_ExtraOptions->text()); + setRemoteFX(rdpUi.kcfg_RemoteFX->isChecked()); + setPerformance(rdpUi.kcfg_Performance->currentIndex()); + setShareMedia(rdpUi.kcfg_ShareMedia->text()); +} + +void RdpHostPreferences::setColorDepth(int colorDepth) +{ + if (colorDepth >= 0) + m_configGroup.writeEntry("colorDepth", colorDepth); +} + +int RdpHostPreferences::colorDepth() const +{ + return m_configGroup.readEntry("colorDepth", Settings::colorDepth()); +} + +void RdpHostPreferences::setKeyboardLayout(const QString &keyboardLayout) +{ + if (!keyboardLayout.isNull()) + m_configGroup.writeEntry("keyboardLayout", keymap2int(keyboardLayout)); +} + +QString RdpHostPreferences::keyboardLayout() const +{ + return int2keymap(m_configGroup.readEntry("keyboardLayout", Settings::keyboardLayout())); +} + +void RdpHostPreferences::setSound(int sound) +{ + if (sound >= 0) + m_configGroup.writeEntry("sound", sound); +} + +int RdpHostPreferences::sound() const +{ + return m_configGroup.readEntry("sound", Settings::sound()); +} + +void RdpHostPreferences::setConsole(bool console) +{ + m_configGroup.writeEntry("console", console); +} + +bool RdpHostPreferences::console() const +{ + return m_configGroup.readEntry("console", Settings::console()); +} + +void RdpHostPreferences::setExtraOptions(const QString &extraOptions) +{ + if (!extraOptions.isNull()) + m_configGroup.writeEntry("extraOptions", extraOptions); +} + +QString RdpHostPreferences::extraOptions() const +{ + return m_configGroup.readEntry("extraOptions", Settings::extraOptions()); +} + +void RdpHostPreferences::setRemoteFX(bool remoteFX) +{ + m_configGroup.writeEntry("remoteFX", remoteFX); +} + +bool RdpHostPreferences::remoteFX() const +{ + return m_configGroup.readEntry("remoteFX", Settings::remoteFX()); +} + +void RdpHostPreferences::setPerformance(int performance) +{ + if (performance >= 0) + m_configGroup.writeEntry("performance", performance); +} + +int RdpHostPreferences::performance() const +{ + return m_configGroup.readEntry("performance", Settings::performance()); +} + +void RdpHostPreferences::setShareMedia(const QString &shareMedia) +{ + if (!shareMedia.isNull()) + m_configGroup.writeEntry("shareMedia", shareMedia); +} + +QString RdpHostPreferences::shareMedia() const +{ + return m_configGroup.readEntry("shareMedia", Settings::shareMedia()); +} + +#include "rdphostpreferences.moc" diff --git a/krdc/rdp/rdphostpreferences.h b/krdc/rdp/rdphostpreferences.h new file mode 100644 index 00000000..4fdc18df --- /dev/null +++ b/krdc/rdp/rdphostpreferences.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2007 - 2012 Urs Wolfer +** Copyright (C) 2012 AceLan Kao +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef RDPHOSTPREFERENCES_H +#define RDPHOSTPREFERENCES_H + +#include "hostpreferences.h" +#include "ui_rdppreferences.h" + +class RdpHostPreferences : public HostPreferences +{ + Q_OBJECT + +public: + explicit RdpHostPreferences(KConfigGroup configGroup, QObject *parent = 0); + ~RdpHostPreferences(); + + void setColorDepth(int colorDepth); + int colorDepth() const; + void setKeyboardLayout(const QString &keyboardLayout); + QString keyboardLayout() const; + void setSound(int sound); + int sound() const; + void setConsole(bool console); + bool console() const; + void setExtraOptions(const QString &extraOptions); + QString extraOptions() const; + void setRemoteFX(bool remoteFX); + bool remoteFX() const; + void setPerformance(int performance); + int performance() const; + void setShareMedia(const QString &shareMedia); + QString shareMedia() const; + +protected: + QWidget* createProtocolSpecificConfigPage(); + void acceptConfig(); + +private: + Ui::RdpPreferences rdpUi; + +private slots: + void updateWidthHeight(int index); +}; + +#endif diff --git a/krdc/rdp/rdppreferences.cpp b/krdc/rdp/rdppreferences.cpp new file mode 100644 index 00000000..2cbeea58 --- /dev/null +++ b/krdc/rdp/rdppreferences.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "rdppreferences.h" +#include "remoteviewfactory.h" +#include "settings.h" + +#include "ui_rdppreferences.h" + +#include + +KRDC_PLUGIN_EXPORT(RdpPreferences) + +RdpPreferences::RdpPreferences(QWidget *parent, const QVariantList &args) + : KCModule(KrdcFactory::componentData(), parent, args) +{ + Ui::RdpPreferences rdpUi; + rdpUi.setupUi(this); + // would need a lot of code duplication. find a solution, bit it's not + // that important because you will not change this configuration each day... + // see rdp/rdphostpreferences.cpp + rdpUi.resolutionComboBox->hide(); + rdpUi.resolutionDummyLabel->hide(); + rdpUi.kcfg_Height->setEnabled(true); + rdpUi.kcfg_Width->setEnabled(true); + rdpUi.heightLabel->setEnabled(true); + rdpUi.widthLabel->setEnabled(true); + + addConfig(Settings::self(), this); +} + +RdpPreferences::~RdpPreferences() +{ +} + +void RdpPreferences::load() +{ + KCModule::load(); +} + +void RdpPreferences::save() +{ + KCModule::save(); +} + +#include "rdppreferences.moc" diff --git a/krdc/rdp/rdppreferences.h b/krdc/rdp/rdppreferences.h new file mode 100644 index 00000000..a9c78e7e --- /dev/null +++ b/krdc/rdp/rdppreferences.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef RDPPREFERENCES_H +#define RDPPREFERENCES_H + +#include "rdphostpreferences.h" + +#include + +class RdpPreferences : public KCModule +{ + Q_OBJECT + +public: + explicit RdpPreferences(QWidget *parent = 0, const QVariantList &args = QVariantList()); + ~RdpPreferences(); + + virtual void save(); + virtual void load(); + +}; + +#endif // RDPPREFERENCES_H diff --git a/krdc/rdp/rdppreferences.ui b/krdc/rdp/rdppreferences.ui new file mode 100644 index 00000000..789094ef --- /dev/null +++ b/krdc/rdp/rdppreferences.ui @@ -0,0 +1,668 @@ + + + RdpPreferences + + + + 0 + 0 + 484 + 452 + + + + + + + Connection + + + + + + + + Desktop &resolution: + + + resolutionComboBox + + + + + + + + + + + + + + + 280 + 0 + + + + Here you can specify the resolution of the remote desktop. This resolution determines the size of the desktop that will be presented to you. + + + 1 + + + + Minimal (640x480) + + + + + Small (800x600) + + + + + Normal (1024x768) + + + + + Large (1280x1024) + + + + + Very Large (1600x1200) + + + + + Current Screen Resolution + + + + + Custom Resolution (...) + + + + + Current KRDC Size + + + + + + + + + + false + + + &Width: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + kcfg_Width + + + + + + + false + + + This is the width of the remote desktop. You can only change this value manually if you select Custom as desktop resolution above. + + + 9999 + + + 800 + + + + + + + false + + + H&eight: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + kcfg_Height + + + + + + + false + + + This is the height of the remote desktop. You can only change this value manually if you select Custom as desktop resolution above. + + + 9999 + + + 600 + + + + + + + + + + + Color &depth: + + + kcfg_ColorDepth + + + + + + + + 280 + 0 + + + + + Low Color (8 Bit) + + + + + High Color (16 Bit) + + + + + True Color (24 Bit) + + + + + True Color with Alpha (32 Bit) + + + + + + + + &Keyboard layout: + + + kcfg_KeyboardLayout + + + + + + + + 280 + 0 + + + + Use this to specify your keyboard layout. This layout setting is used to send the correct keyboard codes to the server. + + + 7 + + + + Arabic (ar) + + + + + Czech (cs) + + + + + Danish (da) + + + + + German (de) + + + + + Swiss German (de-ch) + + + + + American Dvorak (en-dv) + + + + + British English (en-gb) + + + + + US English (en-us) + + + + + Spanish (es) + + + + + Estonian (et) + + + + + Finnish (fi) + + + + + Faroese (fo) + + + + + French (fr) + + + + + Belgian (fr-be) + + + + + French Canadian (fr-ca) + + + + + Swiss French (fr-ch) + + + + + Hebrew (he) + + + + + Croatian (hr) + + + + + Hungarian (hu) + + + + + Icelandic (is) + + + + + Italian (it) + + + + + Japanese (ja) + + + + + Korean (ko) + + + + + Lithuanian (lt) + + + + + Latvian (lv) + + + + + Macedonian (mk) + + + + + Dutch (nl) + + + + + Belgian Dutch (nl-be) + + + + + Norwegian (no) + + + + + Polish (pl) + + + + + Portuguese (pt) + + + + + Brazilian (pt-br) + + + + + Russian (ru) + + + + + Slovenian (sl) + + + + + Swedish (sv) + + + + + Thai (th) + + + + + Turkish (tr) + + + + + + + + Sound: + + + kcfg_Sound + + + + + + + + 280 + 0 + + + + + On This Computer + + + + + On Remote Computer + + + + + Disable Sound + + + + + + + + Performance: + + + kcfg_Performance + + + + + + + + 280 + 0 + + + + + Modem + + + + + Broadband + + + + + LAN + + + + + + + + RemoteFX: + + + kcfg_RemoteFX + + + + + + + Enhanced visual experience + + + RemoteFX covers a set of technologies that enhance visual experience of the Remote Desktop Protocol. + + + + + + + Share Media: + + + kcfg_ShareMedia + + + + + + + + 280 + 0 + + + + Share a local media directory with the remote host. + + + true + + + + + + + + + + Expert Options + + + + + + Console login: + + + kcfg_Console + + + + + + + Attach to Windows Server console + + + + + + + Extra options: + + + kcfg_ExtraOptions + + + + + + + + 280 + 0 + + + + Here you can enter additional xfreerdp (FreeRDP) options. + + + true + + + + + + + + + + Login + + + + + + + + Default user name: + + + + + + + No default user name + + + true + + + + + + + + + Automatically recognize "LDAP"-Logins and share passwords + + + + + + + + + + Qt::Vertical + + + + 428 + 16 + + + + + + + + + KComboBox + QComboBox +
kcombobox.h
+
+ + KLineEdit + QLineEdit +
klineedit.h
+
+
+ + resolutionComboBox + kcfg_Width + kcfg_Height + kcfg_ColorDepth + kcfg_KeyboardLayout + kcfg_Sound + kcfg_Performance + kcfg_RemoteFX + kcfg_ShareMedia + kcfg_Console + kcfg_ExtraOptions + kcfg_DefaultRdpUserName + kcfg_RecognizeLdapLogins + + + +
diff --git a/krdc/rdp/rdpview.cpp b/krdc/rdp/rdpview.cpp new file mode 100644 index 00000000..0d14e046 --- /dev/null +++ b/krdc/rdp/rdpview.cpp @@ -0,0 +1,555 @@ +/**************************************************************************** +** +** Copyright (C) 2002 Arend van Beelen jr. +** Copyright (C) 2007 - 2012 Urs Wolfer +** Copyright (C) 2012 AceLan Kao +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "rdpview.h" + +#include "settings.h" + +#include +#include +#include +#include + +#include +#include + +RdpView::RdpView(QWidget *parent, + const KUrl &url, + KConfigGroup configGroup, + const QString &user, const QString &password) + : RemoteView(parent), + m_user(user), + m_password(password), + m_quitFlag(false), + m_process(NULL) +{ + m_url = url; + m_host = url.host(); + m_port = url.port(); + + if (m_port <= 0) { + m_port = TCP_PORT_RDP; + } + + m_container = new QX11EmbedContainer(this); + m_container->installEventFilter(this); + + m_hostPreferences = new RdpHostPreferences(configGroup, this); +} + +RdpView::~RdpView() +{ + startQuitting(); +} + +// filter out key and mouse events to the container if we are view only +//FIXME: X11 events are passed to the app before getting caught in the Qt event processing +bool RdpView::eventFilter(QObject *obj, QEvent *event) +{ + if (m_viewOnly) { + if (event->type() == QEvent::KeyPress || + event->type() == QEvent::KeyRelease || + event->type() == QEvent::MouseButtonDblClick || + event->type() == QEvent::MouseButtonPress || + event->type() == QEvent::MouseButtonRelease || + event->type() == QEvent::MouseMove) + return true; + } + return RemoteView::eventFilter(obj, event); +} + +QSize RdpView::framebufferSize() +{ + return m_container->minimumSizeHint(); +} + +QSize RdpView::sizeHint() const +{ + return maximumSize(); +} + +void RdpView::startQuitting() +{ + kDebug(5012) << "About to quit"; + m_quitFlag = true; + if (m_process) { + m_process->terminate(); + m_process->waitForFinished(1000); + m_container->discardClient(); + } +} + +bool RdpView::isQuitting() +{ + return m_quitFlag; +} + +bool RdpView::start() +{ + m_container->show(); + + if (m_url.userName().isEmpty()) { + QString userName; + bool ok = false; + + userName = KInputDialog::getText(i18n("Enter Username"), + i18n("Please enter the username you would like to use for login."), + Settings::defaultRdpUserName(), &ok, this); + + if (ok) { + m_url.setUserName(userName); + } + } + + if (!m_url.userName().isEmpty()) { + const bool useLdapLogin = Settings::recognizeLdapLogins() && m_url.userName().contains('\\'); + kDebug(5012) << "Is LDAP login:" << useLdapLogin << m_url.userName(); + + QString walletPassword = QString(); + if (m_hostPreferences->walletSupport()) { + walletPassword = readWalletPassword(useLdapLogin); + } + if (!walletPassword.isNull()) { + m_url.setPassword(walletPassword); + } else { + KPasswordDialog dialog(this); + dialog.setPrompt(i18n("Access to the system requires a password.")); + if (dialog.exec() == KPasswordDialog::Accepted) { + m_url.setPassword(dialog.password()); + + if (m_hostPreferences->walletSupport()) { + saveWalletPassword(dialog.password(), useLdapLogin); + } + } + } + } + + m_process = new QProcess(m_container); + + QStringList arguments; + + int width, height; + if (m_hostPreferences->width() > 0) { + width = m_hostPreferences->width(); + height = m_hostPreferences->height(); + } else { + width = this->parentWidget()->size().width(); + height = this->parentWidget()->size().height(); + } + arguments << "-g" << QString::number(width) + 'x' + QString::number(height); + + arguments << "-k" << keymapToXfreerdp(m_hostPreferences->keyboardLayout()); + + if (!m_url.userName().isEmpty()) { + // if username contains a domain, it needs to be set with another parameter + if (m_url.userName().contains('\\')) { + const QStringList splittedName = m_url.userName().split('\\'); + arguments << "-d" << splittedName.at(0); + arguments << "-u" << splittedName.at(1); + } else { + arguments << "-u" << m_url.userName(); + } + } else { + arguments << "-u" << ""; + } + + if (!m_url.password().isNull()) + arguments << "-p" << m_url.password(); + + arguments << "-D"; // request the window has no decorations + arguments << "-X" << QString::number(m_container->winId()); + arguments << "-a" << QString::number((m_hostPreferences->colorDepth() + 1) * 8); + + switch (m_hostPreferences->sound()) { + case 1: + arguments << "-o"; + break; + case 0: + arguments << "--plugin" << "rdpsnd"; + break; + case 2: + default: + break; + } + + if (!m_hostPreferences->shareMedia().isEmpty()) { + QStringList shareMedia; + shareMedia << "--plugin" << "rdpdr" << "--data" << "disk:media:" + m_hostPreferences->shareMedia() << "--"; + arguments += shareMedia; + } + + QString performance; + switch (m_hostPreferences->performance()) { + case 0: + performance = 'm'; + break; + case 1: + performance = 'b'; + break; + case 2: + performance = 'l'; + break; + default: + break; + } + + arguments << "-x" << performance; + + if (m_hostPreferences->console()) { + arguments << "-0"; + } + + if (m_hostPreferences->remoteFX()) { + arguments << "--rfx"; + } + + if (!m_hostPreferences->extraOptions().isEmpty()) { + const QStringList additionalArguments = KShell::splitArgs(m_hostPreferences->extraOptions()); + arguments += additionalArguments; + } + + // krdc has no support for certificate management yet; it would not be possbile to connect to any host: + // "The host key for example.com has changed" ... + // "Add correct host key in ~/.freerdp/known_hosts to get rid of this message." + arguments << "--ignore-certificate"; + + // clipboard sharing is activated in KRDC; user can disable it at runtime + arguments << "--plugin" << "cliprdr"; + + arguments << "-t" << QString::number(m_port); + arguments << m_host; + + kDebug(5012) << "Starting xfreerdp with arguments:" << arguments; + + setStatus(Connecting); + + connect(m_process, SIGNAL(error(QProcess::ProcessError)), SLOT(processError(QProcess::ProcessError))); + connect(m_process, SIGNAL(readyReadStandardError()), SLOT(receivedStandardError())); + connect(m_process, SIGNAL(readyReadStandardOutput()), SLOT(receivedStandardOutput())); + connect(m_container, SIGNAL(clientClosed()), SLOT(connectionClosed())); + connect(m_container, SIGNAL(clientIsEmbedded()), SLOT(connectionOpened())); + + m_process->start("xfreerdp", arguments); + + return true; +} + +HostPreferences* RdpView::hostPreferences() +{ + return m_hostPreferences; +} + +void RdpView::switchFullscreen(bool on) +{ + if (on == true) { + m_container->grabKeyboard(); + } +} + +void RdpView::connectionOpened() +{ + kDebug(5012) << "Connection opened"; + const QSize size = m_container->minimumSizeHint(); + kDebug(5012) << "Size hint: " << size.width() << " " << size.height(); + setStatus(Connected); + setFixedSize(size); + resize(size); + m_container->setFixedSize(size); + emit framebufferSizeChanged(size.width(), size.height()); + emit connected(); + setFocus(); +} + +QPixmap RdpView::takeScreenshot() +{ + return QPixmap::grabWindow(m_container->clientWinId()); +} + +void RdpView::connectionClosed() +{ + emit disconnected(); + setStatus(Disconnected); + m_quitFlag = true; +} + +void RdpView::connectionError() +{ + emit disconnectedError(); + connectionClosed(); +} + +void RdpView::processError(QProcess::ProcessError error) +{ + kDebug(5012) << "processError:" << error; + if (m_quitFlag) // do not try to show error messages while quitting (prevent crashes) + return; + + if (m_status == Connecting) { + if (error == QProcess::FailedToStart) { + KMessageBox::error(0, i18n("Could not start \"xfreerdp\"; make sure xfreerdp is properly installed."), + i18n("RDP Failure")); + connectionError(); + return; + } + } +} + +void RdpView::receivedStandardError() +{ + const QString output(m_process->readAllStandardError()); + kDebug(5012) << "receivedStandardError:" << output; + QString line; + int i = 0; + while (!(line = output.section('\n', i, i)).isEmpty()) { + + // the following error is issued by freerdp because of a bug in freerdp 1.0.1 and below; + // see: https://github.com/FreeRDP/FreeRDP/pull/576 + //"X Error of failed request: BadWindow (invalid Window parameter) + // Major opcode of failed request: 7 (X_ReparentWindow) + // Resource id in failed request: 0x71303348 + // Serial number of failed request: 36 + // Current serial number in output stream: 36" + if (line.contains(QLatin1String("X_ReparentWindow"))) { + KMessageBox::error(0, i18n("The version of \"xfreerdp\" you are using is too old.\n" + "xfreerdp 1.0.2 or greater is required."), + i18n("RDP Failure")); + connectionError(); + return; + } + i++; + } +} + +void RdpView::receivedStandardOutput() +{ + const QString output(m_process->readAllStandardOutput()); + kDebug(5012) << "receivedStandardOutput:" << output; + QString line; + int i = 0; + while (!(line = output.section('\n', i, i)).isEmpty()) { + + // full xfreerdp message: "transport_connect: getaddrinfo (Name or service not known)" + if (line.contains(QLatin1String("Name or service not known"))) { + KMessageBox::error(0, i18n("Name or service not known."), + i18n("Connection Failure")); + connectionError(); + return; + + // full xfreerdp message: "unable to connect to example.com:3389" + } else if (line.contains(QLatin1String("unable to connect to"))) { + KMessageBox::error(0, i18n("Connection attempt to host failed."), + i18n("Connection Failure")); + connectionError(); + return; + + // looks like some generic xfreerdp error message, handle it if nothing was handled: + // "Error: protocol security negotiation failure" + } else if (line.contains(QLatin1String("Error: protocol security negotiation failure"))) { + KMessageBox::error(0, i18n("Connection attempt to host failed."), + i18n("Connection Failure")); + connectionError(); + return; + } + + i++; + } +} + +void RdpView::setGrabAllKeys(bool grabAllKeys) +{ + Q_UNUSED(grabAllKeys); + // do nothing.. grabKeyboard seems not to be supported in QX11EmbedContainer +} + +QString RdpView::keymapToXfreerdp(const QString &keyboadLayout) +{ + if (keymapToXfreerdpHash.isEmpty()) { + keymapToXfreerdpHash = initKeymapToXfreerdp(); + } + return keymapToXfreerdpHash[keyboadLayout]; +} + +// list of xfreerdp --kbd-list +// this is a mapping for rdesktop comptibilty (old settings will still work) +// needs to be completed (when not in message freeze; needs new localization) +QHash RdpView::initKeymapToXfreerdp() +{ + QHash keymapToXfreerdpHash; + + // Keyboard Layouts + keymapToXfreerdpHash["ar"] = "0x00000401"; // Arabic (101) + // keymapToXfreerdpHash[""] = "0x00000402"; // Bulgarian + // keymapToXfreerdpHash[""] = "0x00000404"; // Chinese (Traditional) - US Keyboard + keymapToXfreerdpHash["cs"] = "0x00000405"; // Czech + keymapToXfreerdpHash["da"] = "0x00000406"; // Danish + keymapToXfreerdpHash["fo"] = "0x00000406"; // Danish, Faroese; legacy for rdesktop + keymapToXfreerdpHash["de"] = "0x00000407"; // German + // keymapToXfreerdpHash[""] = "0x00000408"; // Greek + keymapToXfreerdpHash["en-us"] = "0x00000409"; // US + keymapToXfreerdpHash["es"] = "0x0000040A"; // Spanish + keymapToXfreerdpHash["fi"] = "0x0000040B"; // Finnish + keymapToXfreerdpHash["fr"] = "0x0000040C"; // French + keymapToXfreerdpHash["he"] = "0x0000040D"; // Hebrew + keymapToXfreerdpHash["hu"] = "0x0000040E"; // Hungarian + keymapToXfreerdpHash["is"] = "0x0000040F"; // Icelandic + keymapToXfreerdpHash["it"] = "0x00000410"; // Italian + keymapToXfreerdpHash["ja"] = "0x00000411"; // Japanese + keymapToXfreerdpHash["ko"] = "0x00000412"; // Korean + keymapToXfreerdpHash["nl"] = "0x00000413"; // Dutch + keymapToXfreerdpHash["no"] = "0x00000414"; // Norwegian + keymapToXfreerdpHash["pl"] = "0x00000415"; // Polish (Programmers) + keymapToXfreerdpHash["pt-br"] = "0x00000416"; // Portuguese (Brazilian ABNT) + // keymapToXfreerdpHash[""] = "0x00000418"; // Romanian + keymapToXfreerdpHash["ru"] = "0x00000419"; // Russian + keymapToXfreerdpHash["hr"] = "0x0000041A"; // Croatian + // keymapToXfreerdpHash[""] = "0x0000041B"; // Slovak + // keymapToXfreerdpHash[""] = "0x0000041C"; // Albanian + keymapToXfreerdpHash["sv"] = "0x0000041D"; // Swedish + keymapToXfreerdpHash["th"] = "0x0000041E"; // Thai Kedmanee + keymapToXfreerdpHash["tr"] = "0x0000041F"; // Turkish Q + // keymapToXfreerdpHash[""] = "0x00000420"; // Urdu + // keymapToXfreerdpHash[""] = "0x00000422"; // Ukrainian + // keymapToXfreerdpHash[""] = "0x00000423"; // Belarusian + keymapToXfreerdpHash["sl"] = "0x00000424"; // Slovenian + keymapToXfreerdpHash["et"] = "0x00000425"; // Estonian + keymapToXfreerdpHash["lv"] = "0x00000426"; // Latvian + keymapToXfreerdpHash["lt"] = "0x00000427"; // Lithuanian IBM + // keymapToXfreerdpHash[""] = "0x00000429"; // Farsi + // keymapToXfreerdpHash[""] = "0x0000042A"; // Vietnamese + // keymapToXfreerdpHash[""] = "0x0000042B"; // Armenian Eastern + // keymapToXfreerdpHash[""] = "0x0000042C"; // Azeri Latin + keymapToXfreerdpHash["mk"] = "0x0000042F"; // FYRO Macedonian + // keymapToXfreerdpHash[""] = "0x00000437"; // Georgian + // keymapToXfreerdpHash[""] = "0x00000438"; // Faeroese + // keymapToXfreerdpHash[""] = "0x00000439"; // Devanagari - INSCRIPT + // keymapToXfreerdpHash[""] = "0x0000043A"; // Maltese 47-key + // keymapToXfreerdpHash[""] = "0x0000043B"; // Norwegian with Sami + // keymapToXfreerdpHash[""] = "0x0000043F"; // Kazakh + // keymapToXfreerdpHash[""] = "0x00000440"; // Kyrgyz Cyrillic + // keymapToXfreerdpHash[""] = "0x00000444"; // Tatar + // keymapToXfreerdpHash[""] = "0x00000445"; // Bengali + // keymapToXfreerdpHash[""] = "0x00000446"; // Punjabi + // keymapToXfreerdpHash[""] = "0x00000447"; // Gujarati + // keymapToXfreerdpHash[""] = "0x00000449"; // Tamil + // keymapToXfreerdpHash[""] = "0x0000044A"; // Telugu + // keymapToXfreerdpHash[""] = "0x0000044B"; // Kannada + // keymapToXfreerdpHash[""] = "0x0000044C"; // Malayalam + // keymapToXfreerdpHash[""] = "0x0000044E"; // Marathi + // keymapToXfreerdpHash[""] = "0x00000450"; // Mongolian Cyrillic + // keymapToXfreerdpHash[""] = "0x00000452"; // United Kingdom Extended + // keymapToXfreerdpHash[""] = "0x0000045A"; // Syriac + // keymapToXfreerdpHash[""] = "0x00000461"; // Nepali + // keymapToXfreerdpHash[""] = "0x00000463"; // Pashto + // keymapToXfreerdpHash[""] = "0x00000465"; // Divehi Phonetic + // keymapToXfreerdpHash[""] = "0x0000046E"; // Luxembourgish + // keymapToXfreerdpHash[""] = "0x00000481"; // Maori + // keymapToXfreerdpHash[""] = "0x00000804"; // Chinese (Simplified) - US Keyboard + keymapToXfreerdpHash["de-ch"] = "0x00000807"; // Swiss German + keymapToXfreerdpHash["en-gb"] = "0x00000809"; // United Kingdom + // keymapToXfreerdpHash[""] = "0x0000080A"; // Latin American + keymapToXfreerdpHash["fr-be"] = "0x0000080C"; // Belgian French + keymapToXfreerdpHash["nl-be"] = "0x00000813"; // Belgian (Period) + keymapToXfreerdpHash["pt"] = "0x00000816"; // Portuguese + // keymapToXfreerdpHash[""] = "0x0000081A"; // Serbian (Latin) + // keymapToXfreerdpHash[""] = "0x0000082C"; // Azeri Cyrillic + // keymapToXfreerdpHash[""] = "0x0000083B"; // Swedish with Sami + // keymapToXfreerdpHash[""] = "0x00000843"; // Uzbek Cyrillic + // keymapToXfreerdpHash[""] = "0x0000085D"; // Inuktitut Latin + // keymapToXfreerdpHash[""] = "0x00000C0C"; // Canadian French (legacy) + // keymapToXfreerdpHash[""] = "0x00000C1A"; // Serbian (Cyrillic) + keymapToXfreerdpHash["fr-ca"] = "0x00001009"; // Canadian French + keymapToXfreerdpHash["fr-ch"] = "0x0000100C"; // Swiss French + // keymapToXfreerdpHash[""] = "0x0000141A"; // Bosnian + // keymapToXfreerdpHash[""] = "0x00001809"; // Irish + // keymapToXfreerdpHash[""] = "0x0000201A"; // Bosnian Cyrillic + + // Keyboard Layout Variants + // keymapToXfreerdpHash[""] = "0x00010401"; // Arabic (102) + // keymapToXfreerdpHash[""] = "0x00010402"; // Bulgarian (Latin) + // keymapToXfreerdpHash[""] = "0x00010405"; // Czech (QWERTY) + // keymapToXfreerdpHash[""] = "0x00010407"; // German (IBM) + // keymapToXfreerdpHash[""] = "0x00010408"; // Greek (220) + keymapToXfreerdpHash["en-dv"] = "0x00010409"; // United States-Dvorak + // keymapToXfreerdpHash[""] = "0x0001040A"; // Spanish Variation + // keymapToXfreerdpHash[""] = "0x0001040E"; // Hungarian 101-key + // keymapToXfreerdpHash[""] = "0x00010410"; // Italian (142) + // keymapToXfreerdpHash[""] = "0x00010415"; // Polish (214) + // keymapToXfreerdpHash[""] = "0x00010416"; // Portuguese (Brazilian ABNT2) + // keymapToXfreerdpHash[""] = "0x00010419"; // Russian (Typewriter) + // keymapToXfreerdpHash[""] = "0x0001041B"; // Slovak (QWERTY) + // keymapToXfreerdpHash[""] = "0x0001041E"; // Thai Pattachote + // keymapToXfreerdpHash[""] = "0x0001041F"; // Turkish F + // keymapToXfreerdpHash[""] = "0x00010426"; // Latvian (QWERTY) + // keymapToXfreerdpHash[""] = "0x00010427"; // Lithuanian + // keymapToXfreerdpHash[""] = "0x0001042B"; // Armenian Western + // keymapToXfreerdpHash[""] = "0x00010439"; // Hindi Traditional + // keymapToXfreerdpHash[""] = "0x0001043A"; // Maltese 48-key + // keymapToXfreerdpHash[""] = "0x0001043B"; // Sami Extended Norway + // keymapToXfreerdpHash[""] = "0x00010445"; // Bengali (Inscript) + // keymapToXfreerdpHash[""] = "0x0001045A"; // Syriac Phonetic + // keymapToXfreerdpHash[""] = "0x00010465"; // Divehi Typewriter + // keymapToXfreerdpHash[""] = "0x0001080C"; // Belgian (Comma) + // keymapToXfreerdpHash[""] = "0x0001083B"; // Finnish with Sami + // keymapToXfreerdpHash[""] = "0x00011009"; // Canadian Multilingual Standard + // keymapToXfreerdpHash[""] = "0x00011809"; // Gaelic + // keymapToXfreerdpHash[""] = "0x00020401"; // Arabic (102) AZERTY + // keymapToXfreerdpHash[""] = "0x00020405"; // Czech Programmers + // keymapToXfreerdpHash[""] = "0x00020408"; // Greek (319) + // keymapToXfreerdpHash[""] = "0x00020409"; // United States-International + // keymapToXfreerdpHash[""] = "0x0002041E"; // Thai Kedmanee (non-ShiftLock) + // keymapToXfreerdpHash[""] = "0x0002083B"; // Sami Extended Finland-Sweden + // keymapToXfreerdpHash[""] = "0x00030408"; // Greek (220) Latin + // keymapToXfreerdpHash[""] = "0x00030409"; // United States-Dvorak for left hand + // keymapToXfreerdpHash[""] = "0x0003041E"; // Thai Pattachote (non-ShiftLock) + // keymapToXfreerdpHash[""] = "0x00040408"; // Greek (319) Latin + // keymapToXfreerdpHash[""] = "0x00040409"; // United States-Dvorak for right hand + // keymapToXfreerdpHash[""] = "0x00050408"; // Greek Latin + // keymapToXfreerdpHash[""] = "0x00050409"; // US English Table for IBM Arabic 238_L + // keymapToXfreerdpHash[""] = "0x00060408"; // Greek Polytonic + // keymapToXfreerdpHash[""] = "0xB0000407"; // German Neo + + // Keyboard Input Method Editors (IMEs) + // keymapToXfreerdpHash[""] = "0xE0010404"; // Chinese (Traditional) - Phonetic + // keymapToXfreerdpHash[""] = "0xE0010411"; // Japanese Input System (MS-IME2002) + // keymapToXfreerdpHash[""] = "0xE0010412"; // Korean Input System (IME 2000) + // keymapToXfreerdpHash[""] = "0xE0010804"; // Chinese (Simplified) - QuanPin + // keymapToXfreerdpHash[""] = "0xE0020404"; // Chinese (Traditional) - ChangJie + // keymapToXfreerdpHash[""] = "0xE0020804"; // Chinese (Simplified) - ShuangPin + // keymapToXfreerdpHash[""] = "0xE0030404"; // Chinese (Traditional) - Quick + // keymapToXfreerdpHash[""] = "0xE0030804"; // Chinese (Simplified) - ZhengMa + // keymapToXfreerdpHash[""] = "0xE0040404"; // Chinese (Traditional) - Big5 Code + // keymapToXfreerdpHash[""] = "0xE0050404"; // Chinese (Traditional) - Array + // keymapToXfreerdpHash[""] = "0xE0050804"; // Chinese (Simplified) - NeiMa + // keymapToXfreerdpHash[""] = "0xE0060404"; // Chinese (Traditional) - DaYi + // keymapToXfreerdpHash[""] = "0xE0070404"; // Chinese (Traditional) - Unicode + // keymapToXfreerdpHash[""] = "0xE0080404"; // Chinese (Traditional) - New Phonetic + // keymapToXfreerdpHash[""] = "0xE0090404"; // Chinese (Traditional) - New ChangJie + // keymapToXfreerdpHash[""] = "0xE00E0804"; // Chinese (Traditional) - Microsoft Pinyin IME 3.0 + // keymapToXfreerdpHash[""] = "0xE00F0404"; // Chinese (Traditional) - Alphanumeric + + return keymapToXfreerdpHash; +} + +#include "rdpview.moc" diff --git a/krdc/rdp/rdpview.h b/krdc/rdp/rdpview.h new file mode 100644 index 00000000..d548879a --- /dev/null +++ b/krdc/rdp/rdpview.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2002 Arend van Beelen jr. +** Copyright (C) 2007 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef RDPVIEW_H +#define RDPVIEW_H + +#include "remoteview.h" + +#include "rdphostpreferences.h" + +#include + +#define TCP_PORT_RDP 3389 + +class RdpView; + +class QX11EmbedContainer; + +class RdpView : public RemoteView +{ + Q_OBJECT + +public: + explicit RdpView(QWidget *parent = 0, + const KUrl &url = KUrl(), + KConfigGroup configGroup = KConfigGroup(), + const QString &user = QString(), + const QString &password = QString()); + + virtual ~RdpView(); + + // functions regarding the window + virtual QSize framebufferSize(); // returns the size of the remote view + QSize sizeHint() const; // returns the suggested size + + // functions regarding the connection + virtual void startQuitting(); // start closing the connection + virtual bool isQuitting(); // are we currently closing the connection? + virtual bool start(); // open a connection + void setGrabAllKeys(bool grabAllKeys); + + HostPreferences* hostPreferences(); + + virtual QPixmap takeScreenshot(); + +public slots: + virtual void switchFullscreen(bool on); + +protected: + bool eventFilter(QObject *obj, QEvent *event); + +private: + QString keymapToXfreerdp(const QString &keyboadLayout); + QHash initKeymapToXfreerdp(); + + QString m_name; + QString m_user; + QString m_password; + + bool m_quitFlag; + QX11EmbedContainer *m_container; // container for the xfreerdp window + QProcess *m_process; // xfreerdp process + + RdpHostPreferences *m_hostPreferences; + +private slots: + void connectionOpened(); // called if xfreerdp started + void connectionClosed(); // called if xfreerdp quits + void connectionError(); // called if xfreerdp quits with error + void processError(QProcess::ProcessError error); // called if xfreerdp dies + void receivedStandardError(); // catches xfreerdp debug output + void receivedStandardOutput(); // catches xfreerdp output +}; + +static QHash keymapToXfreerdpHash; + +#endif diff --git a/krdc/rdp/rdpviewfactory.cpp b/krdc/rdp/rdpviewfactory.cpp new file mode 100644 index 00000000..606801f8 --- /dev/null +++ b/krdc/rdp/rdpviewfactory.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "rdpviewfactory.h" + +#include +#include + +KRDC_PLUGIN_EXPORT(RdpViewFactory) + +RdpViewFactory::RdpViewFactory(QObject *parent, const QVariantList &args) + : RemoteViewFactory(parent) +{ + Q_UNUSED(args); + + KGlobal::locale()->insertCatalog("krdc"); + + m_connectToolTipString = i18n("Connect to a Windows Remote Desktop (RDP)"); + + QMetaObject::invokeMethod(this, "checkFreerdpAvailability", Qt::DirectConnection); +} + +RdpViewFactory::~RdpViewFactory() +{ +} + +bool RdpViewFactory::supportsUrl(const KUrl &url) const +{ + return (url.scheme().compare("rdp", Qt::CaseInsensitive) == 0); +} + +RemoteView *RdpViewFactory::createView(QWidget *parent, const KUrl &url, KConfigGroup configGroup) +{ + return new RdpView(parent, url, configGroup); +} + +HostPreferences *RdpViewFactory::createHostPreferences(KConfigGroup configGroup, QWidget *parent) +{ + return new RdpHostPreferences(configGroup, parent); +} + +QString RdpViewFactory::scheme() const +{ + return "rdp"; +} + +QString RdpViewFactory::connectActionText() const +{ + return i18n("New RDP Connection..."); +} + +QString RdpViewFactory::connectButtonText() const +{ + return m_connectToolTipString; +} + +QString RdpViewFactory::connectToolTipText() const +{ + return i18n("Enter the address here. Port is optional.
" + "Example: rdpserver:3389 (host:port)"); +} + +void RdpViewFactory::checkFreerdpAvailability() +{ + if (KStandardDirs::findExe("xfreerdp").isEmpty()) { + m_connectToolTipString += '\n' + i18n("The application \"xfreerdp\" cannot be found on your system; make sure it is properly installed " + "if you need RDP support."); + } +} + +#include "moc_rdpviewfactory.cpp" diff --git a/krdc/rdp/rdpviewfactory.h b/krdc/rdp/rdpviewfactory.h new file mode 100644 index 00000000..2a3ce9ee --- /dev/null +++ b/krdc/rdp/rdpviewfactory.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef RDPVIEWFACTORY_H +#define RDPVIEWFACTORY_H + +#include "remoteviewfactory.h" + +#include "rdpview.h" +#include "rdppreferences.h" + +class RdpViewFactory : public RemoteViewFactory +{ + Q_OBJECT + +public: + explicit RdpViewFactory(QObject *parent, const QVariantList &args); + + virtual ~RdpViewFactory(); + + virtual bool supportsUrl(const KUrl &url) const; + + virtual RemoteView *createView(QWidget *parent, const KUrl &url, KConfigGroup configGroup); + + virtual HostPreferences *createHostPreferences(KConfigGroup configGroup, QWidget *parent); + + virtual QString scheme() const; + + virtual QString connectActionText() const; + + virtual QString connectButtonText() const; + + virtual QString connectToolTipText() const; + +private Q_SLOTS: + void checkFreerdpAvailability(); + +private: + QString m_connectToolTipString; +}; + +#endif // RDPVIEWFACTORY_H diff --git a/krdc/rdp/smb2rdc.desktop b/krdc/rdp/smb2rdc.desktop new file mode 100644 index 00000000..b6d48866 --- /dev/null +++ b/krdc/rdp/smb2rdc.desktop @@ -0,0 +1,74 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KonqPopupMenu/Plugin +MimeType=application/x-smb-server; +Actions=smb2rdc; + +[Desktop Action smb2rdc] +Name=Open Remote Desktop Connection to This Machine +Name[ar]=افتح عن بعد سطح المكتب الاتصال إلى هذه الآلة +Name[ast]=Abrir conexón remota d'escritoriu a esti sistema +Name[bg]=Връзка с отдалечен работно място с избрания компютър +Name[bn]=এই মেশিনে প্রত্যন্ত ডেস্কটপের সংযোগ খোলো +Name[bs]=Otvara udaljenu vezu površi ka ovoj mašini +Name[ca]=Obre una connexió remota d'escriptori a aquesta màquina +Name[ca@valencia]=Obri una connexió remota d'escriptori a esta màquina +Name[cs]=Otevřít vzdálené připojení plochy k tomuto počítači +Name[da]=Åbn forbindelse til fjernskrivebord til denne maskine +Name[de]=Verbindung zur Arbeitsfläche dieses Rechners herstellen +Name[el]=Δημιουργία σύνδεσης σε απομακρυσμένη επιφάνεια εργασίας σε αυτό το μηχάνημα +Name[en_GB]=Open Remote Desktop Connection to This Machine +Name[eo]=Malfermi deforan tabulan konekton al tiu maŝino +Name[es]=Abrir conexión remota de escritorio a este sistema +Name[et]=Kaugtöölaua ühenduse avamine sellesse arvutisse +Name[eu]=Ireki urruneko mahaigainaren konexioa makina honetara +Name[fa]=باز کردن اتصال رومیزی راه دور برای این ماشین +Name[fi]=Avaa etätyöpöytäyhteys tähän koneeseen +Name[fr]=Ouvrir une connexion distante au bureau de cette machine +Name[ga]=Oscail Ceangal Deisce Cianda leis an Ríomhaire Seo +Name[gl]=Abrir unha conexión remota co escritorio desta máquina +Name[he]=פתח חיבור שולחן עבודה מרוחק למכונה זו +Name[hi]=इस मशीन के लिए रिमोट डेस्कटॉप कनेक्शन खोलें +Name[hne]=ये मसीन बर रिमोट डेस्कटाप कनेक्सन खोलव +Name[hr]=Otvorena veza udaljenog pristupa prema ovom uređaju +Name[hu]=Távoli munkaasztal nyitása itt +Name[ia]=Aperi connexion de scriptorio remote a iste machina +Name[is]=Opna fjarlæga skjáborðtengingu til þessarar vélar +Name[it]=Apri connessione a desktop remoto a questa macchina +Name[ja]=このホストへリモートデスクトップ接続を開く +Name[kk]=Осы компьютердегі үстелге қашық қосылымды ашу +Name[km]=បើក​ការ​ត​ភ្ជាប់​ផ្ទៃ​តុ​ពី​ចម្ងាយ​ទៅ​ម៉ាស៊ីន​នេះ +Name[ko]=이 시스템으로의 원격 데스크톱 연결 열기 +Name[lt]=Užmegzti nutolusio darbastalio prijungimą prie šio kompiuterio +Name[lv]=Avērt attālinātās darbirsmas savienojumu uz šo datoru +Name[ml]=വിദൂര പണിയിടത്തിന് ഈ യന്ത്രവുമായുള്ള ബന്ധം തുടങ്ങുക +Name[mr]=या यंत्राकरिता दूरस्थ डेस्कटॉप जुळवणी उघडा +Name[nb]=Åpne fjerntilkobling til skrivebord til denne maskinen +Name[nds]=Schriefdisch-Feernverbinnen na dissen Reekner opmaken +Name[ne]=यो मेशिनमा टाढाको डेस्कटप जडान खोल्नुहोस् +Name[nl]=Externe bureaubladverbinding met deze computer openen +Name[nn]=Opna samband til skrivebordet over nettverket til denne maskina +Name[pa]=ਇਸ ਮਸ਼ੀਨ ਨਾਲ ਰਿਮੋਟ ਡੈਸਕਟਾਪ ਕੁਨੈਕਸ਼ਨ ਖੋਲ੍ਹੋ +Name[pl]=Otwórz zdalne połączenie z pulpitem na tej maszynie +Name[pt]=Abrir uma Ligação Remota ao Ecrã deste Computador +Name[pt_BR]=Abrir conexões remotas para essa máquina +Name[ro]=Deschideți conexiune de birou distant spre această mașină +Name[ru]=Открыть соединение Remote Desktop с этой машиной +Name[si]=මෙම යන්ත්‍රය සඳහා දුරස්ථ වැඩතල සබඳතාව විවෘත කරන්න +Name[sk]=Otvoriť vzdialené pripojenie pracovnej plochy k tomuto počítaču +Name[sl]=Odpri povezavo z oddaljenim namizjem na tem računalniku +Name[sr]=Отворите удаљену везу површи ка овој машини +Name[sr@ijekavian]=Отворите удаљену везу површи ка овој машини +Name[sr@ijekavianlatin]=Otvorite udaljenu vezu površi ka ovoj mašini +Name[sr@latin]=Otvorite udaljenu vezu površi ka ovoj mašini +Name[sv]=Öppna fjärrskrivbordsanslutning till den här datorn +Name[th]=เปิดการเชื่อมต่อพื้นที่ทำงานทางไกลมายังเครื่องนี้ +Name[tr]=Bu Makineye Uzak Masaüstü Bağlantısı Aç +Name[uk]=Відкрити з'єднання з віддаленою стільницею до цього комп'ютера +Name[vi]=Mở kết nối màn hình nền từ xa đến máy này +Name[x-test]=xxOpen Remote Desktop Connection to This Machinexx +Name[zh_CN]=打开到此计算机的远程桌面连接 +Name[zh_HK]=開放遠端桌面連線到這電腦 +Name[zh_TW]=在此主機上開啟遠端桌面 +Exec=krdc %u +Icon=krdc diff --git a/krdc/remotedesktopsmodel.cpp b/krdc/remotedesktopsmodel.cpp new file mode 100644 index 00000000..0d2b6a40 --- /dev/null +++ b/krdc/remotedesktopsmodel.cpp @@ -0,0 +1,303 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** Copyright (C) 2009 Tony Murray +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "remotedesktopsmodel.h" +#include "bookmarkmanager.h" + +#include +#include +#include + +RemoteDesktopsModel::RemoteDesktopsModel(QObject *parent) + : QAbstractTableModel(parent) +{ + const QString file = KStandardDirs::locateLocal("data", "krdc/bookmarks.xml"); + m_manager = KBookmarkManager::managerForFile(file, "krdc"); + m_manager->setUpdate(true); + connect(m_manager, SIGNAL(changed(QString,QString)), SLOT(bookmarksChanged())); + buildModelFromBookmarkGroup(m_manager->root()); + +#ifdef BUILD_ZEROCONF + // Add RDP and NX if they start announcing via Zeroconf: + m_protocols["_rfb._tcp"] = "vnc"; + + zeroconfBrowser = new DNSSD::ServiceBrowser("_rfb._tcp", true); + connect(zeroconfBrowser, SIGNAL(finished()), this, SLOT(servicesChanged())); + zeroconfBrowser->startBrowse(); + kDebug(5010) << "Browsing for zeroconf hosts."; +#endif +} + +RemoteDesktopsModel::~RemoteDesktopsModel() +{ +} + +int RemoteDesktopsModel::columnCount(const QModelIndex &) const +{ + return 6; // same as count of RemoteDesktopsModel::DisplayItems enum +} + +int RemoteDesktopsModel::rowCount(const QModelIndex &) const +{ + return remoteDesktops.size(); +} + +Qt::ItemFlags RemoteDesktopsModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return 0; + if (index.column() == RemoteDesktopsModel::Favorite) { + return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; + } + return Qt::ItemIsEnabled; +} + +bool RemoteDesktopsModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (index.isValid() && role == Qt::CheckStateRole && index.column() == RemoteDesktopsModel::Favorite) { + bool checked = (Qt::CheckState)value.toUInt() == Qt::Checked; + remoteDesktops[index.row()].favorite = checked; + + RemoteDesktop rd = remoteDesktops.at(index.row()); + if (checked) { + KBookmarkGroup root = m_manager->root(); + root.addBookmark(rd.title, rd.url); + m_manager->emitChanged(root); + } else { + BookmarkManager::removeByUrl(m_manager, rd.url, true, rd.title); + } + return true; + } + return false; +} + +QVariant RemoteDesktopsModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + RemoteDesktop item = remoteDesktops.at(index.row()); + + switch (role) { + case Qt::DisplayRole: + switch (index.column()) { + case RemoteDesktopsModel::Favorite: + return item.favorite; + case RemoteDesktopsModel::Title: + return item.title; + case RemoteDesktopsModel::LastConnected: + return QVariant(item.lastConnected.dateTime()); + case RemoteDesktopsModel::VisitCount: + return item.visits; + case RemoteDesktopsModel::Created: + if (item.created.isNull()) return QVariant(); + return KGlobal::locale()->formatDateTime(item.created.toLocalZone(), KLocale::ShortDate); + case RemoteDesktopsModel::Source: + switch (item.source) { + case RemoteDesktop::Bookmarks: + return i18nc("Where each displayed link comes from", "Bookmarks"); + case RemoteDesktop::History: + return i18nc("Where each displayed link comes from", "History"); + case RemoteDesktop::Zeroconf: + return i18nc("Where each displayed link comes from", "Zeroconf"); + case RemoteDesktop::None: + return i18nc("Where each displayed link comes from", "None"); + } + default: + return QVariant(); + } + + case Qt::CheckStateRole: + if (index.column() == RemoteDesktopsModel::Favorite) + return item.favorite ? Qt::Checked : Qt::Unchecked; + return QVariant(); + + case Qt::ToolTipRole: + switch(index.column()) { + case RemoteDesktopsModel::Favorite: + if (item.favorite) { + return i18nc("Remove the selected url from the bookarks menu", "Remove the bookmark for %1.", item.title); + } else { + return i18nc("Add the selected url to the bookmarks menu", "Bookmark %1.", item.title); + } + case RemoteDesktopsModel::LastConnected: + if (!item.lastConnected.isNull()) { + return KGlobal::locale()->formatDateTime(item.lastConnected.toLocalZone(), KLocale::FancyLongDate); + } + break; // else show default tooltip + case RemoteDesktopsModel::Created: + if (!item.created.isNull()) { + return KGlobal::locale()->formatDateTime(item.created.toLocalZone(), KLocale::FancyLongDate); + } + break; // else show default tooltip + default: + break; + } + return item.url; //use the url for the tooltip + + case 10001: //url for dockwidget + return item.url; + + case 10002: //filter + return QUrl::fromPercentEncoding(QString(item.url + item.title).toUtf8()); // return both user visible title and url data, percent encoded + + case 10003: //title for dockwidget + return item.title; + + default: + return QVariant(); + } +} + +QVariant RemoteDesktopsModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + switch (section) { + case RemoteDesktopsModel::Favorite: + return QVariant(); // the favorite column is to small for a header + case RemoteDesktopsModel::Title: + return i18nc("Header of the connections list, title/url for remote connection", "Remote Desktop"); + case RemoteDesktopsModel::LastConnected: + return i18nc("Header of the connections list, the last time this connection was initiated", "Last Connected"); + case RemoteDesktopsModel::VisitCount: + return i18nc("Header of the connections list, the number of times this connection has been visited", "Visits"); + case RemoteDesktopsModel::Created: + return i18nc("Header of the connections list, the time when this entry was created", "Created"); + case RemoteDesktopsModel::Source: + return i18nc("Header of the connections list, where this entry comes from", "Source"); + } + } + return QVariant(); +} + +// does not trigger view update, you must do this by hand after using this function +void RemoteDesktopsModel::removeAllItemsFromSources(RemoteDesktop::Sources sources) +{ + QMutableListIterator iter(remoteDesktops); + while (iter.hasNext()) { + iter.next(); + // if it matches any of the specified sources, remove it + if ((iter.value().source & sources) > 0) + iter.remove(); + } +} + +void RemoteDesktopsModel::bookmarksChanged() +{ + kDebug(5010); + removeAllItemsFromSources(RemoteDesktop::Bookmarks | RemoteDesktop::History); + buildModelFromBookmarkGroup(m_manager->root()); + reset(); +} + +// Danger Will Roobinson, confusing code ahead! +void RemoteDesktopsModel::buildModelFromBookmarkGroup(const KBookmarkGroup &group) +{ + KBookmark bm = group.first(); + while (!bm.isNull()) { + if (bm.isGroup()) { + // recurse subfolders and treat it special if it is the history folder + buildModelFromBookmarkGroup(bm.toGroup()); + } else { // not a group + + RemoteDesktop item; + item.title = bm.fullText(); + item.url = bm.url().url(); + int index = remoteDesktops.indexOf(item); //search for this url to see if we need to update it + bool newItem = index < 0; // do we need to create a new item? + + // we want to merge all copies of a url into one link, so if the item exists, update it + if (group.metaDataItem("krdc-history") == "historyfolder") { + // set source and favorite (will override later if needed) + item.source = RemoteDesktop::History; + item.favorite = false; + + // since we are in the history folder collect statitics and add them + KDateTime connected = KDateTime(); + KDateTime created = KDateTime(); + bool ok = false; + // first the created datetime + created.setTime_t(bm.metaDataItem("time_added").toLongLong(&ok)); + if (ok) (newItem ? item : remoteDesktops[index]).created = created; + // then the last visited datetime + ok = false; + connected.setTime_t(bm.metaDataItem("time_visited").toLongLong(&ok)); + if (ok) (newItem ? item : remoteDesktops[index]).lastConnected = connected; + // finally the visited count + ok = false; + int visits = bm.metaDataItem("visit_count").toInt(&ok); + if (ok) (newItem ? item : remoteDesktops[index]).visits = visits; + } else { + if (newItem) { + // if this is a new item, just add the rest of the required data + item.lastConnected = KDateTime(); + item.created = KDateTime(); + item.visits = 0; + item.favorite = true; + item.source = RemoteDesktop::Bookmarks; + } else { + // otherwise override these fields with the info from the bookmark + remoteDesktops[index].title = bm.fullText(); + remoteDesktops[index].favorite = true; + remoteDesktops[index].source = RemoteDesktop::Bookmarks; + } + } + // if we have a new item, add it + if (newItem) + remoteDesktops.append(item); + } + bm = group.next(bm); // next item in the group + } +} + +#ifdef BUILD_ZEROCONF +void RemoteDesktopsModel::servicesChanged() +{ + //redo list because it is easier than finding and removing one that disappeared + QList services = zeroconfBrowser->services(); + KUrl url; + removeAllItemsFromSources(RemoteDesktop::Zeroconf); + foreach(DNSSD::RemoteService::Ptr service, services) { + url.setProtocol(m_protocols[service->type()].toLower()); + url.setHost(service->hostName()); + url.setPort(service->port()); + + RemoteDesktop item; + item.url = url.url(); + + if (!remoteDesktops.contains(item)) { + item.title = service->serviceName(); + item.source = RemoteDesktop::Zeroconf; + item.created = KDateTime::currentLocalDateTime(); + item.favorite = false; + item.visits = 0; + remoteDesktops.append(item); + } + } + reset(); +} +#endif + +#include "remotedesktopsmodel.moc" diff --git a/krdc/remotedesktopsmodel.h b/krdc/remotedesktopsmodel.h new file mode 100644 index 00000000..d7f1d84f --- /dev/null +++ b/krdc/remotedesktopsmodel.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** Copyright (C) 2009 Tony Murray +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef REMOTEDESKTOPSMODEL_H +#define REMOTEDESKTOPSMODEL_H + +#include +#include + +#ifdef BUILD_ZEROCONF +#include +#endif + +class KBookmarkGroup; +class KBookmarkManager; + +struct RemoteDesktop { +public: + enum Source { None = 0x0, Bookmarks = 0x1, History = 0x2, Zeroconf = 0x4 }; + Q_DECLARE_FLAGS(Sources, Source) + QString title; + QString url; + KDateTime lastConnected; + KDateTime created; + int visits; + RemoteDesktop::Source source; + bool favorite; + bool operator<(const RemoteDesktop &rd) const { + if (lastConnected == rd.lastConnected) + return url < rd.url; + return rd.lastConnected < lastConnected; // seems backward but gets the desired result + } + bool operator==(const RemoteDesktop &rd) const { + return url == rd.url; + } +}; + +class RemoteDesktopsModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + explicit RemoteDesktopsModel(QObject *parent); + ~RemoteDesktopsModel(); + + enum DisplayItems { Favorite, Title, LastConnected, VisitCount, Created, Source }; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + +private: + QList remoteDesktops; + QString getLastConnectedString(KDateTime lastConnected, bool fuzzy = false) const; + void removeAllItemsFromSources(RemoteDesktop::Sources sources); + void buildModelFromBookmarkGroup(const KBookmarkGroup &group); + KBookmarkManager *m_manager; + +#ifdef BUILD_ZEROCONF + DNSSD::ServiceBrowser *zeroconfBrowser; + QHash m_protocols; +#endif + +private slots: + void bookmarksChanged(); +#ifdef BUILD_ZEROCONF + void servicesChanged(); +#endif +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(RemoteDesktop::Sources) + +#endif diff --git a/krdc/systemtrayicon.cpp b/krdc/systemtrayicon.cpp new file mode 100644 index 00000000..5dd5f71d --- /dev/null +++ b/krdc/systemtrayicon.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "systemtrayicon.h" + +#include "mainwindow.h" + +#include +#include +#include + +SystemTrayIcon::SystemTrayIcon(MainWindow *parent) + : KStatusNotifierItem(parent), + m_mainWindow(parent) +{ + setIconByName("krdc"); + setStatus(KStatusNotifierItem::Active); + setCategory(KStatusNotifierItem::ApplicationStatus); + + setToolTipIconByName("krdc"); + setToolTipTitle(i18n("KDE Remote Desktop Client")); + + contextMenu()->addSeparator(); + contextMenu()->addAction(parent->actionCollection()->action("bookmark")); + contextMenu()->addSeparator(); + + connect(this, SIGNAL(activateRequested(bool,QPoint)), this, SLOT(checkActivatedWindow(bool))); +} + +void SystemTrayIcon::checkActivatedWindow(bool active) +{ + // make sure the fullscreen window stays fullscreen by restoring the FullScreen state upon restore. + if(active && associatedWidget() != m_mainWindow) { + associatedWidget()->setWindowState(Qt::WindowFullScreen); + } +} + +SystemTrayIcon::~SystemTrayIcon() +{ +} + +#include "systemtrayicon.moc" diff --git a/krdc/systemtrayicon.h b/krdc/systemtrayicon.h new file mode 100644 index 00000000..af433c87 --- /dev/null +++ b/krdc/systemtrayicon.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef SYSTEMTRAYICON_H +#define SYSTEMTRAYICON_H + +#include + +class MainWindow; + +class SystemTrayIcon : public KStatusNotifierItem +{ + Q_OBJECT + +public: + explicit SystemTrayIcon(MainWindow *parent); + ~SystemTrayIcon(); + +public slots: + void checkActivatedWindow(bool active); + +private: + MainWindow *m_mainWindow; +}; + +#endif diff --git a/krdc/tabbedviewwidget.cpp b/krdc/tabbedviewwidget.cpp new file mode 100644 index 00000000..47f9d74f --- /dev/null +++ b/krdc/tabbedviewwidget.cpp @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Tony Murray +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "tabbedviewwidget.h" + +TabbedViewWidgetModel::TabbedViewWidgetModel(KTabWidget *modelTarget) + : QAbstractItemModel(modelTarget), m_tabWidget(modelTarget) +{ +} + +QModelIndex TabbedViewWidgetModel::index(int row, int column, const QModelIndex &parent) const +{ + if (!hasIndex(row, column, parent)) { + return QModelIndex(); + } + return createIndex(row, column, m_tabWidget->widget(row)); +} + +QModelIndex TabbedViewWidgetModel::parent(const QModelIndex &) const +{ + return QModelIndex(); +} + +int TabbedViewWidgetModel::columnCount(const QModelIndex &) const +{ + return 1; +} + + +int TabbedViewWidgetModel::rowCount(const QModelIndex &) const +{ + return m_tabWidget->count(); +} + +Qt::ItemFlags TabbedViewWidgetModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) { + return Qt::ItemIsEnabled; + } + return QAbstractItemModel::flags(index) | Qt::ItemIsEditable; +} + +bool TabbedViewWidgetModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (index.isValid() && role == Qt::EditRole) { + m_tabWidget->setTabText(index.row(), value.toString()); + emit dataChanged(index, index); + return true; + } + return false; +} + +QVariant TabbedViewWidgetModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) { + return QVariant(); + } + + switch (role) { + case Qt::EditRole: + case Qt::DisplayRole: + return m_tabWidget->tabText(index.row()).remove(QRegExp("&(?!&)")); //remove accelerator string + case Qt::ToolTipRole: + return m_tabWidget->tabToolTip(index.row()); + case Qt::DecorationRole: + return m_tabWidget->tabIcon(index.row()); + default: + return QVariant(); + } +} + +void TabbedViewWidgetModel::emitLayoutAboutToBeChanged() +{ + emit layoutAboutToBeChanged(); +} + +void TabbedViewWidgetModel::emitLayoutChanged() +{ + emit layoutChanged(); +} + +void TabbedViewWidgetModel::emitDataChanged(int index) +{ + QModelIndex modelIndex = createIndex(index, 1); + emit dataChanged(modelIndex, modelIndex); +} + +TabbedViewWidget::TabbedViewWidget(QWidget *parent, Qt::WFlags flags) + : KTabWidget(parent, flags), m_model(new TabbedViewWidgetModel(this)) +{ +} + +TabbedViewWidget::~TabbedViewWidget() +{ +} + +TabbedViewWidgetModel* TabbedViewWidget::getModel() +{ + return m_model; +} + +int TabbedViewWidget::addTab(QWidget *page, const QString &label) +{ + int count = KTabWidget::count(); + m_model->beginInsertRows(QModelIndex(), count, count); + int ret = KTabWidget::addTab(page, label); + m_model->endInsertRows(); + return ret; +} + +int TabbedViewWidget::addTab(QWidget *page, const QIcon &icon, const QString &label) +{ + int count = KTabWidget::count(); + m_model->beginInsertRows(QModelIndex(), count, count); + int ret = KTabWidget::addTab(page, icon, label); + m_model->endInsertRows(); + return ret; +} + +int TabbedViewWidget::insertTab(int index, QWidget *page, const QString &label) +{ + m_model->beginInsertRows(QModelIndex(), index, index); + int ret = KTabWidget::insertTab(index, page, label); + m_model->endInsertRows(); + return ret; +} + +int TabbedViewWidget::insertTab(int index, QWidget *page, const QIcon &icon, const QString &label) +{ + m_model->beginInsertRows(QModelIndex(), index, index); + int ret = KTabWidget::insertTab(index, page, icon, label); + m_model->endInsertRows(); + return ret; +} + +void TabbedViewWidget::removePage(QWidget *page) +{ + int index = KTabWidget::indexOf(page); + m_model->beginRemoveRows(QModelIndex(), index, index); + KTabWidget::removePage(page); + m_model->endRemoveRows(); +} + +void TabbedViewWidget::removeTab(int index) +{ + m_model->beginRemoveRows(QModelIndex(), index, index); + KTabWidget::removeTab(index); + m_model->endRemoveRows(); +} + +void TabbedViewWidget::moveTab(int from, int to) +{ + m_model->emitLayoutAboutToBeChanged(); + KTabWidget::moveTab(from, to); + m_model->emitLayoutChanged(); +} + +void TabbedViewWidget::setTabText(int index, const QString &label) +{ + KTabWidget::setTabText(index, label); + m_model->emitDataChanged(index); +} + +#include "tabbedviewwidget.moc" diff --git a/krdc/tabbedviewwidget.h b/krdc/tabbedviewwidget.h new file mode 100644 index 00000000..4cfd141f --- /dev/null +++ b/krdc/tabbedviewwidget.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Tony Murray +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef TABBEDVIEWWIDGET_H +#define TABBEDVIEWWIDGET_H + +#include +#include + +class TabbedViewWidgetModel : public QAbstractItemModel +{ + friend class TabbedViewWidget; + Q_OBJECT +public: + explicit TabbedViewWidgetModel(KTabWidget *modelTarget); + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &index) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + bool setData(const QModelIndex &index, const QVariant &value, int role); + QVariant data(const QModelIndex &index, int role) const; +protected: + void emitLayoutAboutToBeChanged(); + void emitLayoutChanged(); + void emitDataChanged(int index); +private: + KTabWidget *m_tabWidget; +}; + +class TabbedViewWidget : public KTabWidget +{ + Q_OBJECT +public: + explicit TabbedViewWidget(QWidget *parent = 0, Qt::WFlags flags = 0); + virtual ~TabbedViewWidget(); + TabbedViewWidgetModel* getModel(); + int addTab(QWidget *page, const QString &label); + int addTab(QWidget *page, const QIcon &icon, const QString &label); + int insertTab(int index, QWidget *page, const QString &label); + int insertTab(int index, QWidget *page, const QIcon &icon, const QString &label); + void removeTab(int index); + void removePage(QWidget *page); + void moveTab(int from, int to); + void setTabText(int index, const QString &label); +private: + TabbedViewWidgetModel *m_model; +}; + +#endif // FULLSCREENWINDOW_H + diff --git a/krdc/test/CMakeLists.txt b/krdc/test/CMakeLists.txt new file mode 100644 index 00000000..19a96f35 --- /dev/null +++ b/krdc/test/CMakeLists.txt @@ -0,0 +1,26 @@ + +if(NOT NDEBUG) + set(BUILD_TEST true) +endif(NOT NDEBUG) +if(BUILD_TEST) + + include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ) + + set(testplugin_SRCS + testviewfactory.cpp + testview.cpp + ) + + kde4_add_plugin(krdc_testplugin ${testplugin_SRCS}) + + target_link_libraries(krdc_testplugin + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + krdccore + ) + install(TARGETS krdc_testplugin DESTINATION ${PLUGIN_INSTALL_DIR}) + + install(FILES krdc_test.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +endif(BUILD_TEST) diff --git a/krdc/test/krdc_test.desktop b/krdc/test/krdc_test.desktop new file mode 100644 index 00000000..c1f7a453 --- /dev/null +++ b/krdc/test/krdc_test.desktop @@ -0,0 +1,124 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KRDC/Plugin +Icon=krdc +Name=Test +Name[ast]=Preba +Name[bg]=Проба +Name[bs]=Test +Name[ca]=Prova +Name[ca@valencia]=Prova +Name[cs]=Test +Name[da]=Test +Name[de]=Test +Name[el]=Δοκιμή +Name[en_GB]=Test +Name[es]=Prueba +Name[et]=Test +Name[eu]=Proba +Name[fi]=Testi +Name[fr]=Test +Name[ga]=Tástáil +Name[gl]=Proba +Name[hr]=Test +Name[hsb]=Test +Name[hu]=Teszt +Name[ia]=Essaya +Name[is]=Prófun +Name[it]=Prova +Name[ja]=テスト +Name[kk]=Тест +Name[km]=សាកល្បង +Name[ko]=테스트 +Name[lt]=Testavimas +Name[lv]=Tests +Name[mai]=जाँच +Name[mr]=चाचणी +Name[nb]=Test +Name[nds]=Test +Name[nl]=Test +Name[nn]=Test +Name[pa]=ਟੈਸਟ +Name[pl]=Test +Name[pt]=Teste +Name[pt_BR]=Testar +Name[ro]=Test +Name[ru]=Проверка +Name[si]=පිරික්සුම +Name[sk]=Test +Name[sl]=Preizkus +Name[sr]=Проба +Name[sr@ijekavian]=Проба +Name[sr@ijekavianlatin]=Proba +Name[sr@latin]=Proba +Name[sv]=Prov +Name[th]=ทดสอบ +Name[tr]=Test +Name[ug]=سىنا +Name[uk]=Тест +Name[wa]=Asprouvaedje +Name[x-test]=xxTestxx +Name[zh_CN]=测试 +Name[zh_TW]=測試 +Comment=Testplugin for KRDC development +Comment[ast]=Complementu de preba pal desendolcu de KRDC +Comment[bg]=Пробна приставка за KRDC +Comment[bs]=Probni priključak za razvoj KRDC +Comment[ca]=Connector de prova del desenvolupament del KRDC +Comment[ca@valencia]=Connector de prova del desenvolupament del KRDC +Comment[cs]=Demonstrační modul pro vývoj KRDC +Comment[da]=Test-plugin til KRDC-udvikling +Comment[de]=Testmodul für die KRDC-Entwicklung +Comment[el]=Πρόσθετο δοκιμής για την ανάπτυξη του KRDC +Comment[en_GB]=Testplugin for KRDC development +Comment[es]=Complemento de prueba para el desarrollo de KRDC +Comment[et]=Plugin KRDC arendustegevuse testimiseks +Comment[eu]=Probako plugina KRDC garatzeko +Comment[fi]=KRDC-kehityksen testiliitännäinen +Comment[fr]=Module externe de test pour le développement de KRDC +Comment[ga]=Breiseán tástála le haghaidh fhorbairt KRDC +Comment[gl]=Engadido de proba para o desenvolvemento de KRDC +Comment[hr]=Testni priključak za razvoj KRDC-a +Comment[hu]=Tesztmodul KRDC-fejlesztőknek +Comment[ia]=Plug-in de essayo pro disveloppamento de KRDC +Comment[is]=Prófunaríforrit fyrir KRDC forritun +Comment[it]=Estensione di prova per lo sviluppo di KRDC +Comment[ja]=KRDC 開発のためのテスト用プラグイン +Comment[kk]=KRDC-құрастыруын үйрету үшін сынақ плагині +Comment[km]=ការ​អភិវឌ្ឍន៍ Testplugin សម្រាប់ KRDC +Comment[ko]=KRDC 개발을 위한 테스트 플러그인 +Comment[lt]=Įskiepis, skirtas KRDC programavimui +Comment[lv]=Demonstrācijas spraudnis KRDC izstrādei +Comment[nb]=Test-programtillegg for KRDC-utvikling +Comment[nds]=Testmoduul för't Utwickeln vun KRDC +Comment[nl]=Testplugin voor KRDC-ontwikkeling +Comment[nn]=Programtillegg for demonstrasjon og opplæring i KRDC-utvikling +Comment[pl]=Wtyczka demonstracyjna do nauki programowania KRDC +Comment[pt]='Plugin' de demonstração para o desenvolvimento com o KRDC +Comment[pt_BR]=Plugin de teste para o desenvolvimento no KRDC +Comment[ro]=Modul de testare pentru dezvoltarea KRDC +Comment[ru]=Демонстрационный модуль для изучения программирования модулей KRDC +Comment[si]=KRDC සංවර්ධනයක් සඳහා පිරික්සුම් ප්ලගිනය +Comment[sk]=Testovací modul pre vývoj KRDC +Comment[sl]=Preizkusni vstavek za razvoj KRDC +Comment[sr]=Пробни прикључак за развој КРДЦ‑а +Comment[sr@ijekavian]=Пробни прикључак за развој КРДЦ‑а +Comment[sr@ijekavianlatin]=Probni priključak za razvoj KRDC‑a +Comment[sr@latin]=Probni priključak za razvoj KRDC‑a +Comment[sv]=Testinsticksprogram för utveckling av KRDC +Comment[tr]=KRDC geliştirmesi için örnek eklenti +Comment[uk]=Тестовий додаток для розробки KRDC +Comment[x-test]=xxTestplugin for KRDC developmentxx +Comment[zh_CN]=KRDC 开发用的测试插件 +Comment[zh_TW]=KRDC 開發的測試外掛程式 + +X-KDE-PluginInfo-Author=Urs Wolfer +X-KDE-PluginInfo-Email=uwolfer@kde.org +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Category=Service +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=false +X-KDE-Library=krdc_testplugin +X-KDE-PluginInfo-Name=krdc_testplugin + +X-KDE-KRDC-Sorting=80 diff --git a/krdc/test/testview.cpp b/krdc/test/testview.cpp new file mode 100644 index 00000000..f99f76ee --- /dev/null +++ b/krdc/test/testview.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "testview.h" + +#include + +TestView::TestView(QWidget *parent, const KUrl &url, KConfigGroup configGroup) + : RemoteView(parent) +{ + m_hostPreferences = new TestHostPreferences(configGroup, this); + + Q_UNUSED(url); + + setAutoFillBackground(true); + + QPalette pal = palette(); + pal.setColor(QPalette::Dark, Qt::yellow); + setPalette(pal); + + const QSize size = QSize(640, 480); + setStatus(Connected); + setFixedSize(size); + setFixedSize(size); + emit framebufferSizeChanged(size.width(), size.height()); + emit connected(); +} + +TestView::~TestView() +{ + emit disconnected(); + setStatus(Disconnected); +} + +bool TestView::eventFilter(QObject *obj, QEvent *event) +{ + if (m_viewOnly) { + if (event->type() == QEvent::KeyPress || + event->type() == QEvent::KeyRelease || + event->type() == QEvent::MouseButtonDblClick || + event->type() == QEvent::MouseButtonPress || + event->type() == QEvent::MouseButtonRelease || + event->type() == QEvent::MouseMove) + return true; + } + return RemoteView::eventFilter(obj, event); +} + +QSize TestView::framebufferSize() +{ + return minimumSizeHint(); +} + +QSize TestView::sizeHint() const +{ + return maximumSize(); +} + +bool TestView::isQuitting() +{ + return false; +} + +bool TestView::start() +{ + return true; +} + +HostPreferences* TestView::hostPreferences() +{ + return m_hostPreferences; +} + +void TestView::switchFullscreen(bool on) +{ + Q_UNUSED(on); +} + +#include "testview.moc" diff --git a/krdc/test/testview.h b/krdc/test/testview.h new file mode 100644 index 00000000..75600cb7 --- /dev/null +++ b/krdc/test/testview.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef TESTVIEW_H +#define TESTVIEW_H + +#include "testview.h" + +#include "remoteview.h" +#include "hostpreferences.h" + +#include + +class TestHostPreferences; + +class TestView : public RemoteView +{ + Q_OBJECT + +public: + explicit TestView(QWidget *parent = 0, const KUrl &url = KUrl(), KConfigGroup configGroup = KConfigGroup()); + + virtual ~TestView(); + + virtual QSize framebufferSize(); + QSize sizeHint() const; + + virtual bool isQuitting(); + virtual bool start(); + HostPreferences* hostPreferences(); + +public slots: + virtual void switchFullscreen(bool on); + +protected: + bool eventFilter(QObject *obj, QEvent *event); + +private: + TestHostPreferences *m_hostPreferences; +}; + + +class TestHostPreferences : public HostPreferences +{ + Q_OBJECT +public: + explicit TestHostPreferences(KConfigGroup configGroup, QObject *parent = 0) + : HostPreferences(configGroup, parent) {} + +protected: + virtual QWidget* createProtocolSpecificConfigPage() { return 0; }; +}; + +#endif // TESTVIEW_H diff --git a/krdc/test/testviewfactory.cpp b/krdc/test/testviewfactory.cpp new file mode 100644 index 00000000..1cad4759 --- /dev/null +++ b/krdc/test/testviewfactory.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "testviewfactory.h" + +#include +#include + +KRDC_PLUGIN_EXPORT(TestViewFactory) + +TestViewFactory::TestViewFactory(QObject *parent, const QVariantList &args) + : RemoteViewFactory(parent) +{ + Q_UNUSED(args); + + KGlobal::locale()->insertCatalog("krdc"); +} + +TestViewFactory::~TestViewFactory() +{ +} + +bool TestViewFactory::supportsUrl(const KUrl &url) const +{ + return (url.scheme().compare("test", Qt::CaseInsensitive) == 0); +} + +RemoteView *TestViewFactory::createView(QWidget *parent, const KUrl &url, KConfigGroup configGroup) +{ + return new TestView(parent, url, configGroup); +} + +HostPreferences *TestViewFactory::createHostPreferences(KConfigGroup configGroup, QWidget *parent) +{ + Q_UNUSED(configGroup); + Q_UNUSED(parent); + + return 0; +} + +QString TestViewFactory::scheme() const +{ + return "test"; +} + +QString TestViewFactory::connectActionText() const +{ + return ("New Test Connection..."); // no i18n required, just internal test plugin! +} + +QString TestViewFactory::connectButtonText() const +{ + return ("KRDC Test Connection"); // no i18n required, just internal test plugin! +} + +QString TestViewFactory::connectToolTipText() const +{ + return ("Enter the address here. Port is optional.
" + "Example: testserver (host)"); // no i18n required, just internal test plugin! +} + +#include "moc_testviewfactory.cpp" diff --git a/krdc/test/testviewfactory.h b/krdc/test/testviewfactory.h new file mode 100644 index 00000000..a5df4ec5 --- /dev/null +++ b/krdc/test/testviewfactory.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef TESTVIEWFACTORY_H +#define TESTVIEWFACTORY_H + +#include "remoteviewfactory.h" + +#include "testview.h" + +class TestViewFactory : public RemoteViewFactory +{ + Q_OBJECT + +public: + explicit TestViewFactory(QObject *parent, const QVariantList &args); + + virtual ~TestViewFactory(); + + virtual bool supportsUrl(const KUrl &url) const; + + virtual RemoteView *createView(QWidget *parent, const KUrl &url, KConfigGroup configGroup); + + virtual HostPreferences *createHostPreferences(KConfigGroup configGroup, QWidget *parent); + + virtual QString scheme() const; + + virtual QString connectActionText() const; + + virtual QString connectButtonText() const; + + virtual QString connectToolTipText() const; +}; + +#endif // TESTVIEWFACTORY_H diff --git a/krdc/tubesmanager.cpp b/krdc/tubesmanager.cpp new file mode 100644 index 00000000..0a7f31af --- /dev/null +++ b/krdc/tubesmanager.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009-2011 Collabora Ltd +** Copyright (C) 2009 Abner Silva +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "tubesmanager.h" + +#include +#include + +#include + + +TubesManager::TubesManager(QObject *parent) + : QObject(parent) +{ + kDebug() << "Initializing tubes manager"; + + Tp::enableDebug(true); + Tp::enableWarnings(true); + + /* Registering telepathy types */ + Tp::registerTypes(); + + m_stubeClient = Tp::StreamTubeClient::create( + QStringList() << QLatin1String("rfb"), + QStringList(), + QLatin1String("krdc_rfb_handler")); + + m_stubeClient->setToAcceptAsTcp(); + + connect(m_stubeClient.data(), + SIGNAL(tubeAcceptedAsTcp(QHostAddress,quint16,QHostAddress,quint16, + Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)), + SLOT(onTubeAccepted(QHostAddress,quint16,QHostAddress,quint16, + Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr))); +} + +TubesManager::~TubesManager() +{ + kDebug() << "Destroying tubes manager"; +} + +void TubesManager::closeTube(const KUrl& url) +{ + if (m_tubes.contains(url)) { + m_tubes.take(url)->requestClose(); + } +} + +void TubesManager::onTubeAccepted( + const QHostAddress & listenAddress, quint16 listenPort, + const QHostAddress & sourceAddress, quint16 sourcePort, + const Tp::AccountPtr & account, + const Tp::IncomingStreamTubeChannelPtr & tube) +{ + Q_UNUSED(sourceAddress); + Q_UNUSED(sourcePort); + Q_UNUSED(account); + + KUrl url; + url.setScheme("vnc"); + url.setHost(listenAddress.toString()); + url.setPort(listenPort); + + kDebug() << "newConnection:" << url; + m_tubes.insert(url, tube); + emit newConnection(url); +} diff --git a/krdc/tubesmanager.h b/krdc/tubesmanager.h new file mode 100644 index 00000000..a66a4613 --- /dev/null +++ b/krdc/tubesmanager.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2009-2011 Collabora Ltd +** Copyright (C) 2009 Abner Silva +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef TUBESMANAGER_H +#define TUBESMANAGER_H + +#include +#include +#include + +class TubesManager : public QObject +{ + Q_OBJECT + +public: + explicit TubesManager(QObject *parent); + virtual ~TubesManager(); + + void closeTube(const KUrl & url); + +Q_SIGNALS: + void newConnection(KUrl); + +private Q_SLOTS: + void onTubeAccepted( + const QHostAddress & listenAddress, + quint16 listenPort, + const QHostAddress & sourceAddress, + quint16 sourcePort, + const Tp::AccountPtr & account, + const Tp::IncomingStreamTubeChannelPtr & tube); + +private: + Tp::StreamTubeClientPtr m_stubeClient; + QHash m_tubes; +}; + +#endif diff --git a/krdc/vnc/CMakeLists.txt b/krdc/vnc/CMakeLists.txt new file mode 100644 index 00000000..bfbd26fa --- /dev/null +++ b/krdc/vnc/CMakeLists.txt @@ -0,0 +1,54 @@ + +if(LIBVNCSERVER_FOUND) + add_definitions(-DKDE_DEFAULT_DEBUG_AREA=5011) + + include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${LIBVNCCLIENT_INCLUDE_DIR} + ) + + set(vncplugin_SRCS + vnchostpreferences.cpp + vncclientthread.cpp + vncviewfactory.cpp + vncview.cpp + ) + + kde4_add_ui_files(vncplugin_SRCS + vncpreferences.ui + ) + + kde4_add_plugin(krdc_vncplugin ${vncplugin_SRCS}) + + target_link_libraries(krdc_vncplugin + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + ${LIBVNCCLIENT_LIBRARIES} + krdccore + ) + + if(JPEG_FOUND) + target_link_libraries(krdc_vncplugin ${JPEG_LIBRARIES}) + endif(JPEG_FOUND) + + set(kcm_krdc_vncplugin_SRCS + vncpreferences.cpp + ) + + kde4_add_plugin(kcm_krdc_vncplugin ${kcm_krdc_vncplugin_SRCS}) + + target_link_libraries(kcm_krdc_vncplugin + ${KDE4_KDEUI_LIBS} + krdccore + ) + + add_dependencies(kcm_krdc_vncplugin krdc_vncplugin) + + install(TARGETS kcm_krdc_vncplugin DESTINATION ${PLUGIN_INSTALL_DIR}) + install(TARGETS krdc_vncplugin DESTINATION ${PLUGIN_INSTALL_DIR}) + + install(FILES krdc_vnc.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + install(FILES krdc_vnc_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + + install(FILES vnc.protocol DESTINATION ${SERVICES_INSTALL_DIR}) +endif(LIBVNCSERVER_FOUND) diff --git a/krdc/vnc/krdc_vnc.desktop b/krdc/vnc/krdc_vnc.desktop new file mode 100644 index 00000000..dd4e9298 --- /dev/null +++ b/krdc/vnc/krdc_vnc.desktop @@ -0,0 +1,122 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KRDC/Plugin +Icon=krdc +Name=VNC +Name[ast]=VNC +Name[bg]=VNC +Name[bs]=VNC +Name[ca]=VNC +Name[ca@valencia]=VNC +Name[cs]=VNC +Name[da]=VNC +Name[de]=VNC +Name[el]=VNC +Name[en_GB]=VNC +Name[eo]=VNC +Name[es]=VNC +Name[et]=VNC +Name[eu]=VNC +Name[fi]=VNC +Name[fr]=VNC +Name[ga]=VNC +Name[gl]=VNC +Name[hr]=VNC +Name[hu]=VNC +Name[ia]=VNC +Name[is]=VNC +Name[it]=VNC +Name[ja]=VNC +Name[kk]=VNC +Name[km]=VNC +Name[ko]=VNC +Name[lt]=VNC +Name[lv]=VNC +Name[nb]=VNC +Name[nds]=VNC +Name[nl]=VNC +Name[nn]=VNC +Name[pa]=VNC +Name[pl]=VNC +Name[pt]=VNC +Name[pt_BR]=VNC +Name[ro]=VNC +Name[ru]=VNC +Name[si]=VNC +Name[sk]=VNC +Name[sl]=VNC +Name[sr]=ВНЦ +Name[sr@ijekavian]=ВНЦ +Name[sr@ijekavianlatin]=VNC +Name[sr@latin]=VNC +Name[sv]=VNC +Name[tr]=VNC +Name[ug]=VNC +Name[uk]=VNC +Name[wa]=VNC +Name[x-test]=xxVNCxx +Name[zh_CN]=VNC +Name[zh_TW]=VNC +Comment=Allows managing VNC sessions through KRDC +Comment[ast]=Permite la xestión de sesiones VNC per KRDC +Comment[bg]=Управление на сесии на VNC с KRDC +Comment[bs]=Dopušta upravljanje VNC sesijama kroz KRDC +Comment[ca]=Permet gestionar sessions VNC mitjançant el KRDC +Comment[ca@valencia]=Permet gestionar sessions VNC mitjançant el KRDC +Comment[cs]=Umožňuje spravování sezení VNC pomocí KRDC +Comment[da]=Muliggør håndtering af VNC-sessioner via KRDC +Comment[de]=Erlaubt die Verwaltung von VNC-Sitzungen über KRDC +Comment[el]=Επιτρέπει τη διαχείριση συνεδριών VNC μέσω του KRDC +Comment[en_GB]=Allows managing VNC sessions through KRDC +Comment[es]=Permite la gestión de sesiones VNC mediante KRDC +Comment[et]=VNC-seansside haldamise võimaldamine KRDC kaudu +Comment[eu]=VNC saioak KRDC bidez kudeatzea baimentzen du +Comment[fi]=Mahdollistaa VNC-istuntojen hallinnan KRDC:llä +Comment[fr]=Permet de gérer des sessions « VNC » au travers de KRDC +Comment[ga]=Ceadaíonn sé duit seisiúin VNC a bhainistiú trí KRDC +Comment[gl]=Permite xestionar sesións VNC por medio de KRDC +Comment[hr]=Omogućuje upravljanje sjednicama VNC-a kroz KRDC +Comment[hu]=VNC-elérés KRDC-ből +Comment[ia]=Permitte gerer sessiones VNC per medio de KRDC +Comment[is]=Gefur kost á að stjórna VNC setum með KRDC +Comment[it]=Permette di gestire sessioni VNC con KRDC +Comment[ja]=KRDC から VNC セッションを管理できるようにします +Comment[kk]=KRDC арқылы VNC сеанстарын басқаруға мүмкіндік беру +Comment[km]=អនុញ្ញាត​ឲ្យ​គ្រប់គ្រង​សម័យ​របស់ VNC តាមរយៈ KRDC +Comment[ko]=KRDC를 통해서 VNC 세션 관리하기 +Comment[lt]=Leidžia valdyti VNC sesijas per KRDC +Comment[lv]=Ļauj pārvaldīt VNC sesijas caur KRDC +Comment[nb]=Tillater å styre VNC-økter gjennom KRDC +Comment[nds]=VNC-Törns över KRDC plegen +Comment[nl]=Staat het beheer van VNC-sessies toe via KRDC +Comment[nn]=Lèt deg handtera VNC-økter gjennom KRDC +Comment[pa]=KRDC ਰਾਹੀਂ VNC ਸ਼ੈਸ਼ਨਾਂ ਦੇ ਪਰਬੰਧ ਦੀ ਮਨਜ਼ੂਰੀ +Comment[pl]=Pozwala na zarządzanie sesjami VNC przez KRDC +Comment[pt]=Permite a gestão de sessões VNC através do KRDC +Comment[pt_BR]=Permite o gerenciamento de sessões VNC através do KRDC +Comment[ro]=Permite gestiunea sesiunilor VNC prin KRDC +Comment[ru]=Разрешить управление сеансами VNC через KRDC +Comment[si]=KRDC හරහා VNC වාර පාලනයට ඉඩ දෙයි +Comment[sk]=Umožňuje spravovanie VNC sedení pomocou KRDC +Comment[sl]=Omogoča upravljanje sej VNC prek KRDC +Comment[sr]=Управљање ВНЦ сесијама кроз КРДЦ +Comment[sr@ijekavian]=Управљање ВНЦ сесијама кроз КРДЦ +Comment[sr@ijekavianlatin]=Upravljanje VNC sesijama kroz KRDC +Comment[sr@latin]=Upravljanje VNC sesijama kroz KRDC +Comment[sv]=Tillåter hantering av VNC-sessioner via KRDC +Comment[tr]=VNC oturumlarını KRDC üzerinden yönetmeye izin verir +Comment[uk]=Надає змогу керувати сеансами VNC за допомогою KRDC +Comment[x-test]=xxAllows managing VNC sessions through KRDCxx +Comment[zh_CN]=允许用户通过 KRDC 管理 VNC 会话 +Comment[zh_TW]=允許透過 KRDC 管理 VNC 工作階段 + +X-KDE-PluginInfo-Author=Urs Wolfer +X-KDE-PluginInfo-Email=uwolfer@kde.org +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Category=Service +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true +X-KDE-Library=krdc_vncplugin +X-KDE-PluginInfo-Name=krdc_vncplugin + +X-KDE-KRDC-Sorting=20 diff --git a/krdc/vnc/krdc_vnc_config.desktop b/krdc/vnc/krdc_vnc_config.desktop new file mode 100644 index 00000000..548f6486 --- /dev/null +++ b/krdc/vnc/krdc_vnc_config.desktop @@ -0,0 +1,61 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KCModule +Name=VNC +Name[ast]=VNC +Name[bg]=VNC +Name[bs]=VNC +Name[ca]=VNC +Name[ca@valencia]=VNC +Name[cs]=VNC +Name[da]=VNC +Name[de]=VNC +Name[el]=VNC +Name[en_GB]=VNC +Name[eo]=VNC +Name[es]=VNC +Name[et]=VNC +Name[eu]=VNC +Name[fi]=VNC +Name[fr]=VNC +Name[ga]=VNC +Name[gl]=VNC +Name[hr]=VNC +Name[hu]=VNC +Name[ia]=VNC +Name[is]=VNC +Name[it]=VNC +Name[ja]=VNC +Name[kk]=VNC +Name[km]=VNC +Name[ko]=VNC +Name[lt]=VNC +Name[lv]=VNC +Name[nb]=VNC +Name[nds]=VNC +Name[nl]=VNC +Name[nn]=VNC +Name[pa]=VNC +Name[pl]=VNC +Name[pt]=VNC +Name[pt_BR]=VNC +Name[ro]=VNC +Name[ru]=VNC +Name[si]=VNC +Name[sk]=VNC +Name[sl]=VNC +Name[sr]=ВНЦ +Name[sr@ijekavian]=ВНЦ +Name[sr@ijekavianlatin]=VNC +Name[sr@latin]=VNC +Name[sv]=VNC +Name[tr]=VNC +Name[ug]=VNC +Name[uk]=VNC +Name[wa]=VNC +Name[x-test]=xxVNCxx +Name[zh_CN]=VNC +Name[zh_TW]=VNC + +X-KDE-Library=kcm_krdc_vncplugin +X-KDE-ParentComponents=krdc_vncplugin diff --git a/krdc/vnc/qtonly/README b/krdc/vnc/qtonly/README new file mode 100644 index 00000000..51fa9943 --- /dev/null +++ b/krdc/vnc/qtonly/README @@ -0,0 +1,30 @@ +Qt-only version of the KRDC VNC backend +======================================= + +In order to build it, you need the LibVNCClient (LibVNCServer) +library (version 0.9.1 or newer required): + http://sourceforge.net/project/showfiles.php?group_id=32584&package_id=24717 + +The following files from KRDC are required: + krdc/core/remoteview.{cpp,h} + krdc/vnc/vncview.{cpp,h} + krdc/vnc/vncclientthread.{cpp,h} + krdc/vnc/qtonly/main.cpp + krdc/vnc/qtonly/krdc-vnc-qtonly.pro + +Copy these files into a folder and run: + qmake + make + +In order to try it out, type: + ./krdc-vnc-qtonly vnc://:password@server:1 1 + (the last argument defines the quality as second argument (1-3, where 1 is + the best). Default is 2.) + +If you use these code in your project, make sure that QTONLY is defined (see +krdc-vnc-qtonly.pro). + +IMPORTANT NOTICE +================ +If you do any fixes or improvements in these files, please backport them to the original sources. +Please send a patch with the changes to . Thanks a lot! diff --git a/krdc/vnc/qtonly/krdc-vnc-qtonly.pro b/krdc/vnc/qtonly/krdc-vnc-qtonly.pro new file mode 100644 index 00000000..20510e35 --- /dev/null +++ b/krdc/vnc/qtonly/krdc-vnc-qtonly.pro @@ -0,0 +1,9 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . +LIBS += -lvncclient -lgnutls +DEFINES += QTONLY + +HEADERS += remoteview.h vncclientthread.h vncview.h +SOURCES += main.cpp remoteview.cpp vncclientthread.cpp vncview.cpp diff --git a/krdc/vnc/qtonly/main.cpp b/krdc/vnc/qtonly/main.cpp new file mode 100644 index 00000000..bb753578 --- /dev/null +++ b/krdc/vnc/qtonly/main.cpp @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include + +#include "vncview.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + if (QCoreApplication::arguments().count() < 2) { + qFatal("Please define an URL as argument. Example: vnc://:password@server:1\n" + "Optionally, you can define the quality as second argument (1-3, where 1 is the best). Default is 2."); + return 1; + } + VncView vncView(0, QCoreApplication::arguments().at(1)); + vncView.show(); + vncView.start(); + return app.exec(); +} diff --git a/krdc/vnc/vnc.protocol b/krdc/vnc/vnc.protocol new file mode 100644 index 00000000..90a9624a --- /dev/null +++ b/krdc/vnc/vnc.protocol @@ -0,0 +1,12 @@ +[Protocol] +exec=krdc '%u' +protocol=vnc +input=none +output=none +helper=true +listing= +reading=false +writing=false +makedir=false +deleting=false +Icon=krdc diff --git a/krdc/vnc/vncclientthread.cpp b/krdc/vnc/vncclientthread.cpp new file mode 100644 index 00000000..e85898ea --- /dev/null +++ b/krdc/vnc/vncclientthread.cpp @@ -0,0 +1,685 @@ +/**************************************************************************** +** +** Copyright (C) 2007 - 2013 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "vncclientthread.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +//for detecting intel AMT KVM vnc server +static const QString INTEL_AMT_KVM_STRING= "Intel(r) AMT KVM"; +static QThreadStorage instances; + +// Dispatch from this static callback context to the member context. +rfbBool VncClientThread::newclientStatic(rfbClient *cl) +{ + VncClientThread *t = (VncClientThread *)rfbClientGetClientData(cl, 0); + Q_ASSERT(t); + + return t->newclient(); +} + +// Dispatch from this static callback context to the member context. +void VncClientThread::updatefbStatic(rfbClient *cl, int x, int y, int w, int h) +{ + VncClientThread *t = (VncClientThread *)rfbClientGetClientData(cl, 0); + Q_ASSERT(t); + + return t->updatefb(x, y, w, h); +} + +// Dispatch from this static callback context to the member context. +void VncClientThread::cuttextStatic(rfbClient *cl, const char *text, int textlen) +{ + VncClientThread *t = (VncClientThread *)rfbClientGetClientData(cl, 0); + Q_ASSERT(t); + + t->cuttext(text, textlen); +} + +// Dispatch from this static callback context to the member context. +char *VncClientThread::passwdHandlerStatic(rfbClient *cl) +{ + VncClientThread *t = (VncClientThread *)rfbClientGetClientData(cl, 0); + Q_ASSERT(t); + + return t->passwdHandler(); +} + +// Dispatch from this static callback context to the member context. +rfbCredential *VncClientThread::credentialHandlerStatic(rfbClient *cl, int credentialType) +{ + VncClientThread *t = (VncClientThread *)rfbClientGetClientData(cl, 0); + Q_ASSERT(t); + + return t->credentialHandler(credentialType); +} + +// Dispatch from this static callback context to the member context. +void VncClientThread::outputHandlerStatic(const char *format, ...) +{ + VncClientThread **t = instances.localData(); + + va_list args; + va_start(args, format); + (*t)->outputHandler(format, args); + va_end(args); +} + +void VncClientThread::setClientColorDepth(rfbClient* cl, VncClientThread::ColorDepth cd) +{ + switch(cd) { + case bpp8: + if (m_colorTable.isEmpty()) { + m_colorTable.resize(256); + int r,g,b; + for (int i = 0; i < 256; ++i) { + //pick out the red (3 bits), green (3 bits) and blue (2 bits) bits and make them maximum significant in 8bits + //this gives a colortable for 8bit true colors + r= (i & 0x07) << 5; + g= (i & 0x38) << 2; + b= i & 0xc0; + m_colorTable[i] = qRgb(r, g, b); + } + } + cl->format.depth = 8; + cl->format.bitsPerPixel = 8; + cl->format.redShift = 0; + cl->format.greenShift = 3; + cl->format.blueShift = 6; + cl->format.redMax = 7; + cl->format.greenMax = 7; + cl->format.blueMax = 3; + break; + case bpp16: + cl->format.depth = 16; + cl->format.bitsPerPixel = 16; + cl->format.redShift = 11; + cl->format.greenShift = 5; + cl->format.blueShift = 0; + cl->format.redMax = 0x1f; + cl->format.greenMax = 0x3f; + cl->format.blueMax = 0x1f; + break; + case bpp32: + default: + cl->format.depth = 24; + cl->format.bitsPerPixel = 32; + cl->format.redShift = 16; + cl->format.greenShift = 8; + cl->format.blueShift = 0; + cl->format.redMax = 0xff; + cl->format.greenMax = 0xff; + cl->format.blueMax = 0xff; + } +} + +rfbBool VncClientThread::newclient() +{ + //8bit color hack for Intel(r) AMT KVM "classic vnc" = vnc server built in in Intel Vpro chipsets. + if (INTEL_AMT_KVM_STRING == cl->desktopName) { + kDebug(5011) << "Intel(R) AMT KVM: switching to 8 bit color depth (workaround, recent libvncserver needed)"; + setColorDepth(bpp8); + } + setClientColorDepth(cl, colorDepth()); + + const int width = cl->width, height = cl->height, depth = cl->format.bitsPerPixel; + const int size = width * height * (depth / 8); + if (frameBuffer) + delete [] frameBuffer; // do not leak if we get a new framebuffer size + frameBuffer = new uint8_t[size]; + cl->frameBuffer = frameBuffer; + memset(cl->frameBuffer, '\0', size); + + switch (quality()) { + case RemoteView::High: + cl->appData.encodingsString = "copyrect zlib hextile raw"; + cl->appData.compressLevel = 0; + cl->appData.qualityLevel = 9; + break; + case RemoteView::Medium: + cl->appData.encodingsString = "copyrect tight zrle ultra zlib hextile corre rre raw"; + cl->appData.compressLevel = 5; + cl->appData.qualityLevel = 7; + break; + case RemoteView::Low: + case RemoteView::Unknown: + default: + cl->appData.encodingsString = "copyrect tight zrle ultra zlib hextile corre rre raw"; + cl->appData.compressLevel = 9; + cl->appData.qualityLevel = 1; + } + + SetFormatAndEncodings(cl); + kDebug(5011) << "Client created"; + return true; +} + +void VncClientThread::updatefb(int x, int y, int w, int h) +{ +// kDebug(5011) << "updated client: x: " << x << ", y: " << y << ", w: " << w << ", h: " << h; + + const int width = cl->width, height = cl->height; + QImage img; + switch(colorDepth()) { + case bpp8: + img = QImage(cl->frameBuffer, width, height, QImage::Format_Indexed8); + img.setColorTable(m_colorTable); + break; + case bpp16: + img = QImage(cl->frameBuffer, width, height, QImage::Format_RGB16); + break; + case bpp32: + img = QImage(cl->frameBuffer, width, height, QImage::Format_RGB32); + break; + } + + if (img.isNull()) { + kDebug(5011) << "image not loaded"; + } + + if (m_stopped) { + return; // sending data to a stopped thread is not a good idea + } + + setImage(img); + + emitUpdated(x, y, w, h); +} + +void VncClientThread::cuttext(const char *text, int textlen) +{ + const QString cutText = QString::fromUtf8(text, textlen); + kDebug(5011) << cutText; + + if (!cutText.isEmpty()) { + emitGotCut(cutText); + } +} + +char *VncClientThread::passwdHandler() +{ + kDebug(5011) << "password request"; + + // Never request a password during a reconnect attempt. + if (!m_keepalive.failed) { + passwordRequest(); + m_passwordError = true; + } + return strdup(m_password.toUtf8()); +} + +rfbCredential *VncClientThread::credentialHandler(int credentialType) +{ + kDebug(5011) << "credential request" << credentialType; + + rfbCredential *cred = 0; + + switch (credentialType) { + case rfbCredentialTypeUser: + passwordRequest(true); + m_passwordError = true; + + cred = new rfbCredential; + cred->userCredential.username = strdup(username().toUtf8()); + cred->userCredential.password = strdup(password().toUtf8()); + break; + default: + kError(5011) << "credential request failed, unspported credentialType:" << credentialType; + outputErrorMessage(i18n("VNC authentication type is not supported.")); + break; + } + return cred; +} + +void VncClientThread::outputHandler(const char *format, ...) +{ + va_list args; + va_start(args, format); + + QString message; + message.vsprintf(format, args); + + va_end(args); + + message = message.trimmed(); + + kDebug(5011) << message; + + if ((message.contains("Couldn't convert ")) || + (message.contains("Unable to connect to VNC server"))) { + // Don't show a dialog if a reconnection is needed. Never contemplate + // reconnection if we don't have a password. + QString tmp = i18n("Server not found."); + if (m_keepalive.set && !m_password.isNull()) { + m_keepalive.failed = true; + if (m_previousDetails != tmp) { + m_previousDetails = tmp; + clientStateChange(RemoteView::Disconnected, tmp); + } + } else { + outputErrorMessageString = tmp; + } + } + + // Process general authentication failures before more specific authentication + // failures. All authentication failures cancel any auto-reconnection that + // may be in progress. + if (message.contains("VNC connection failed: Authentication failed")) { + m_keepalive.failed = false; + outputErrorMessageString = i18n("VNC authentication failed."); + } + if ((message.contains("VNC connection failed: Authentication failed, too many tries")) || + (message.contains("VNC connection failed: Too many authentication failures"))) { + m_keepalive.failed = false; + outputErrorMessageString = i18n("VNC authentication failed because of too many authentication tries."); + } + + if (message.contains("VNC server closed connection")) + outputErrorMessageString = i18n("VNC server closed connection."); + + // If we are not going to attempt a reconnection, at least tell the user + // the connection went away. + if (message.contains("read (")) { + // Don't show a dialog if a reconnection is needed. Never contemplate + // reconnection if we don't have a password. + QString tmp = i18n("Disconnected: %1.", message); + if (m_keepalive.set && !m_password.isNull()) { + m_keepalive.failed = true; + clientStateChange(RemoteView::Disconnected, tmp); + } else { + outputErrorMessageString = tmp; + } + } + + // internal messages, not displayed to user + if (message.contains("VNC server supports protocol version 3.889")) // see http://bugs.kde.org/162640 + outputErrorMessageString = "INTERNAL:APPLE_VNC_COMPATIBILTY"; +} + +VncClientThread::VncClientThread(QObject *parent) + : QThread(parent) + , frameBuffer(0) + , cl(0) + , m_stopped(false) +{ + // We choose a small value for interval...after all if the connection is + // supposed to sustain a VNC session, a reasonably frequent ping should + // be perfectly supportable. + m_keepalive.intervalSeconds = 1; + m_keepalive.failedProbes = 3; + m_keepalive.set = false; + m_keepalive.failed = false; + m_previousDetails = QString::null; + outputErrorMessageString.clear(); //don't deliver error messages of old instances... + QMutexLocker locker(&mutex); + + QTimer *outputErrorMessagesCheckTimer = new QTimer(this); + outputErrorMessagesCheckTimer->setInterval(500); + connect(outputErrorMessagesCheckTimer, SIGNAL(timeout()), this, SLOT(checkOutputErrorMessage())); + outputErrorMessagesCheckTimer->start(); +} + +VncClientThread::~VncClientThread() +{ + if(isRunning()) { + stop(); + terminate(); + const bool quitSuccess = wait(1000); + kDebug(5011) << "Attempting to stop in deconstructor, will crash if this fails:" << quitSuccess; + } + + clientDestroy(); + + delete [] frameBuffer; +} + +void VncClientThread::checkOutputErrorMessage() +{ + if (!outputErrorMessageString.isEmpty()) { + kDebug(5011) << outputErrorMessageString; + QString errorMessage = outputErrorMessageString; + outputErrorMessageString.clear(); + // show authentication failure error only after the 3rd unsuccessful try + if ((errorMessage != i18n("VNC authentication failed.")) || m_passwordError) + outputErrorMessage(errorMessage); + } +} + +void VncClientThread::setHost(const QString &host) +{ + QMutexLocker locker(&mutex); + m_host = host; +} + +void VncClientThread::setPort(int port) +{ + QMutexLocker locker(&mutex); + m_port = port; +} + +void VncClientThread::setQuality(RemoteView::Quality quality) +{ + m_quality = quality; + //set color depth dependent on quality + switch(quality) { + case RemoteView::Low: + setColorDepth(bpp8); + break; + case RemoteView::High: + setColorDepth(bpp32); + break; + case RemoteView::Medium: + default: + setColorDepth(bpp16); + } +} + +void VncClientThread::setColorDepth(ColorDepth colorDepth) +{ + m_colorDepth= colorDepth; +} + +RemoteView::Quality VncClientThread::quality() const +{ + return m_quality; +} + +VncClientThread::ColorDepth VncClientThread::colorDepth() const +{ + return m_colorDepth; +} + +void VncClientThread::setImage(const QImage &img) +{ + QMutexLocker locker(&mutex); + m_image = img; +} + +const QImage VncClientThread::image(int x, int y, int w, int h) +{ + QMutexLocker locker(&mutex); + + if (w == 0) // full image requested + return m_image; + else + return m_image.copy(x, y, w, h); +} + +void VncClientThread::emitUpdated(int x, int y, int w, int h) +{ + emit imageUpdated(x, y, w, h); +} + +void VncClientThread::emitGotCut(const QString &text) +{ + emit gotCut(text); +} + +void VncClientThread::stop() +{ + QMutexLocker locker(&mutex); + m_stopped = true; +} + +void VncClientThread::run() +{ + QMutexLocker locker(&mutex); + + VncClientThread **threadTls = new VncClientThread *(); + *threadTls = this; + instances.setLocalData(threadTls); + while (!m_stopped) { // try to connect as long as the server allows + locker.relock(); + m_passwordError = false; + locker.unlock(); + + if (clientCreate(false)) { + // The initial connection attempt worked! + break; + } + + locker.relock(); + if (m_passwordError) { + locker.unlock(); + // Try again. + continue; + } + + // The initial connection attempt failed, and not because of a + // password problem. Bail out. + m_stopped = true; + locker.unlock(); + } + + locker.relock(); + kDebug(5011) << "--------------------- Starting main VNC event loop ---------------------"; + while (!m_stopped) { + locker.unlock(); + const int i = WaitForMessage(cl, 500); + if (m_stopped || i < 0) { + break; + } + if (i) { + if (!HandleRFBServerMessage(cl)) { + if (m_keepalive.failed) { + do { + // Reconnect after a short delay. That way, if the + // attempt fails very quickly, we don't sit in a very + // tight loop. + clientDestroy(); + msleep(1000); + clientStateChange(RemoteView::Connecting, i18n("Reconnecting.")); + } while (!clientCreate(true)); + continue; + } + kError(5011) << "HandleRFBServerMessage failed"; + break; + } + } + + locker.relock(); + while (!m_eventQueue.isEmpty()) { + ClientEvent* clientEvent = m_eventQueue.dequeue(); + locker.unlock(); + clientEvent->fire(cl); + delete clientEvent; + locker.relock(); + } + } + + m_stopped = true; +} + +/** + * Factor out the initialisation of the VNC client library. Notice this has + * both static parts as in @see rfbClientLog and @see rfbClientErr, + * as well as instance local data @see rfbGetClient(). + * + * On return from here, if cl is set, the connection will have been made else + * cl will not be set. + */ +bool VncClientThread::clientCreate(bool reinitialising) +{ + rfbClientLog = outputHandlerStatic; + rfbClientErr = outputHandlerStatic; + + //24bit color dept in 32 bits per pixel = default. Will change colordepth and bpp later if needed + cl = rfbGetClient(8, 3, 4); + setClientColorDepth(cl, this->colorDepth()); + cl->MallocFrameBuffer = newclientStatic; + cl->canHandleNewFBSize = true; + cl->GetPassword = passwdHandlerStatic; + cl->GetCredential = credentialHandlerStatic; + cl->GotFrameBufferUpdate = updatefbStatic; + cl->GotXCutText = cuttextStatic; + rfbClientSetClientData(cl, 0, this); + + cl->serverHost = strdup(m_host.toUtf8().constData()); + + if (m_port < 0 || !m_port) // port is invalid or empty... + m_port = 5900; // fallback: try an often used VNC port + + if (m_port >= 0 && m_port < 100) // the user most likely used the short form (e.g. :1) + m_port += 5900; + cl->serverPort = m_port; + + kDebug(5011) << "--------------------- trying init ---------------------"; + + if (!rfbInitClient(cl, 0, 0)) { + if (!reinitialising) { + // Don't whine on reconnection failure: presumably the network + // is simply still down. + kError(5011) << "rfbInitClient failed"; + } + cl = 0; + return false; + } + + if (reinitialising) { + clientStateChange(RemoteView::Connected, i18n("Reconnected.")); + } else { + clientStateChange(RemoteView::Connected, i18n("Connected.")); + } + clientSetKeepalive(); + return true; +} + +/** + * Undo @see clientCreate(). + */ +void VncClientThread::clientDestroy() +{ + + if (cl) { + // Disconnect from vnc server & cleanup allocated resources + rfbClientCleanup(cl); + cl = 0; + } +} + +/** + * The VNC client library does not make use of keepalives. We go behind its + * back to set it up. + */ +void VncClientThread::clientSetKeepalive() +{ + // If keepalive is disabled, do nothing. + m_keepalive.set = false; + m_keepalive.failed = false; + if (!m_keepalive.intervalSeconds) { + return; + } + int optval; + socklen_t optlen = sizeof(optval); + + // Try to set the option active + optval = 1; + if (setsockopt(cl->sock, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) { + kError(5011) << "setsockopt(SO_KEEPALIVE)" << strerror(errno); + return; + } + + optval = m_keepalive.intervalSeconds; + if (setsockopt(cl->sock, IPPROTO_TCP, TCP_KEEPIDLE, &optval, optlen) < 0) { + kError(5011) << "setsockopt(TCP_KEEPIDLE)" << strerror(errno); + return; + } + + optval = m_keepalive.intervalSeconds; + if (setsockopt(cl->sock, IPPROTO_TCP, TCP_KEEPINTVL, &optval, optlen) < 0) { + kError(5011) << "setsockopt(TCP_KEEPINTVL)" << strerror(errno); + return; + } + + optval = m_keepalive.failedProbes; + if(setsockopt(cl->sock, IPPROTO_TCP, TCP_KEEPCNT, &optval, optlen) < 0) { + kError(5011) << "setsockopt(TCP_KEEPCNT)" << strerror(errno); + return; + } + m_keepalive.set = true; + kDebug(5011) << "TCP keepalive set"; +} + +/** + * The VNC client state changed. + */ +void VncClientThread::clientStateChange(RemoteView::RemoteStatus status, const QString &details) +{ + kDebug(5011) << status << details << m_host << ":" << m_port; + emit clientStateChanged(status, details); +} + +ClientEvent::~ClientEvent() +{ +} + +void PointerClientEvent::fire(rfbClient* cl) +{ + SendPointerEvent(cl, m_x, m_y, m_buttonMask); +} + +void KeyClientEvent::fire(rfbClient* cl) +{ + SendKeyEvent(cl, m_key, m_pressed); +} + +void ClientCutEvent::fire(rfbClient* cl) +{ + SendClientCutText(cl, text.toUtf8().data(), text.size()); +} + +void VncClientThread::mouseEvent(int x, int y, int buttonMask) +{ + QMutexLocker lock(&mutex); + if (m_stopped) + return; + + m_eventQueue.enqueue(new PointerClientEvent(x, y, buttonMask)); +} + +void VncClientThread::keyEvent(int key, bool pressed) +{ + QMutexLocker lock(&mutex); + if (m_stopped) + return; + + m_eventQueue.enqueue(new KeyClientEvent(key, pressed)); +} + +void VncClientThread::clientCut(const QString &text) +{ + QMutexLocker lock(&mutex); + if (m_stopped) + return; + + m_eventQueue.enqueue(new ClientCutEvent(text)); +} + +#include "moc_vncclientthread.cpp" diff --git a/krdc/vnc/vncclientthread.h b/krdc/vnc/vncclientthread.h new file mode 100644 index 00000000..3cc7e9c7 --- /dev/null +++ b/krdc/vnc/vncclientthread.h @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** Copyright (C) 2007 - 2013 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef VNCCLIENTTHREAD_H +#define VNCCLIENTTHREAD_H + +#ifdef QTONLY + #include + #define kDebug(n) qDebug() + #define kError(n) qDebug() + #define kBacktrace() "" + #define i18n tr +#else + #include + #include +#endif + +#include "remoteview.h" + +#include +#include +#include +#include + +extern "C" { +#include +} + +class ClientEvent +{ +public: + virtual ~ClientEvent(); + + virtual void fire(rfbClient*) = 0; +}; + +class KeyClientEvent : public ClientEvent +{ +public: + KeyClientEvent(int key, int pressed) + : m_key(key), m_pressed(pressed) {} + + void fire(rfbClient*); + +private: + int m_key; + int m_pressed; +}; + +class PointerClientEvent : public ClientEvent +{ +public: + PointerClientEvent(int x, int y, int buttonMask) + : m_x(x), m_y(y), m_buttonMask(buttonMask) {} + + void fire(rfbClient*); + +private: + int m_x; + int m_y; + int m_buttonMask; +}; + +class ClientCutEvent : public ClientEvent +{ +public: + explicit ClientCutEvent(const QString &text) + : text(text) {} + + void fire(rfbClient*); + +private: + QString text; +}; + +class VncClientThread: public QThread +{ + Q_OBJECT + +public: + Q_ENUMS(ColorDepth) + + enum ColorDepth { + bpp32, + bpp16, + bpp8 + }; + + explicit VncClientThread(QObject *parent = 0); + ~VncClientThread(); + const QImage image(int x = 0, int y = 0, int w = 0, int h = 0); + void setImage(const QImage &img); + void emitUpdated(int x, int y, int w, int h); + void emitGotCut(const QString &text); + void stop(); + void setHost(const QString &host); + void setPort(int port); + void setQuality(RemoteView::Quality quality); + void setPassword(const QString &password) { + m_password = password; + } + const QString password() const { + return m_password; + } + void setUsername(const QString &username) { + m_username = username; + } + const QString username() const { + return m_username; + } + + RemoteView::Quality quality() const; + ColorDepth colorDepth() const; + uint8_t *frameBuffer; + +signals: + void imageUpdated(int x, int y, int w, int h); + void gotCut(const QString &text); + void passwordRequest(bool includingUsername = false); + void outputErrorMessage(const QString &message); + + /** + * When we connect/disconnect/reconnect/etc., this signal will be emitted. + * + * @param status Is the client connected? + * @param details A sentence describing what happened. + */ + void clientStateChanged(RemoteView::RemoteStatus status, const QString &details); + +public slots: + void mouseEvent(int x, int y, int buttonMask); + void keyEvent(int key, bool pressed); + void clientCut(const QString &text); + +protected: + void run(); + +private: + void setClientColorDepth(rfbClient *cl, ColorDepth cd); + void setColorDepth(ColorDepth colorDepth); + + // These static methods are callback functions for libvncclient. Each + // of them calls back into the corresponding member function via some + // TLS-based logic. + static rfbBool newclientStatic(rfbClient *cl); + static void updatefbStatic(rfbClient *cl, int x, int y, int w, int h); + static void cuttextStatic(rfbClient *cl, const char *text, int textlen); + static char *passwdHandlerStatic(rfbClient *cl); + static rfbCredential *credentialHandlerStatic(rfbClient *cl, int credentialType); + static void outputHandlerStatic(const char *format, ...); + + // Member functions corresponding to the above static methods. + rfbBool newclient(); + void updatefb(int x, int y, int w, int h); + void cuttext(const char *text, int textlen); + char *passwdHandler(); + rfbCredential *credentialHandler(int credentialType); + void outputHandler(const char *format, ...); + + QImage m_image; + rfbClient *cl; + QString m_host; + QString m_password; + QString m_username; + int m_port; + QMutex mutex; + RemoteView::Quality m_quality; + ColorDepth m_colorDepth; + QQueue m_eventQueue; + //color table for 8bit indexed colors + QVector m_colorTable; + QString outputErrorMessageString; + + volatile bool m_stopped; + volatile bool m_passwordError; + + /** + * Connection keepalive/reconnection support. + */ + struct { + /** + * Number of seconds between probes. If zero, we will not attempt + * to enable it. + */ + int intervalSeconds; + /** + * Number of failed probes required to recognise a disconnect. + */ + int failedProbes; + /** + * Was keepalive successfully set? + */ + bool set; + /** + * Did keepalive detect a disconnect? + */ + volatile bool failed; + } m_keepalive; + + // Initialise the VNC client library object. + bool clientCreate(bool reinitialising); + + // Uninitialise the VNC client library object. + void clientDestroy(); + + // Turn on keepalive support. + void clientSetKeepalive(); + + // Record a state change. + void clientStateChange(RemoteView::RemoteStatus status, const QString &details); + QString m_previousDetails; + +private slots: + void checkOutputErrorMessage(); +}; + +#endif diff --git a/krdc/vnc/vnchostpreferences.cpp b/krdc/vnc/vnchostpreferences.cpp new file mode 100644 index 00000000..422910b6 --- /dev/null +++ b/krdc/vnc/vnchostpreferences.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2007 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "vnchostpreferences.h" + +#include "settings.h" + +#include + +#include + +VncHostPreferences::VncHostPreferences(KConfigGroup configGroup, QObject *parent) + : HostPreferences(configGroup, parent) +{ +} + +VncHostPreferences::~VncHostPreferences() +{ +} + +QWidget* VncHostPreferences::createProtocolSpecificConfigPage() +{ + QWidget *vncPage = new QWidget(); + vncUi.setupUi(vncPage); + + vncUi.kcfg_Quality->setCurrentIndex(quality() - 1); + vncUi.kcfg_Scaling->setChecked(windowedScale()); + vncUi.kcfg_ScalingWidth->setValue(width()); + vncUi.kcfg_ScalingHeight->setValue(height()); + + connect(vncUi.resolutionComboBox, SIGNAL(currentIndexChanged(int)), SLOT(updateScalingWidthHeight(int))); + connect(vncUi.kcfg_Scaling, SIGNAL(toggled(bool)), SLOT(updateScaling(bool))); + + const QString resolutionString = QString::number(width()) + 'x' + QString::number(height()); + const int resolutionIndex = vncUi.resolutionComboBox->findText(resolutionString, Qt::MatchContains); + vncUi.resolutionComboBox->setCurrentIndex((resolutionIndex == -1) ? vncUi.resolutionComboBox->count() - 1 : resolutionIndex); + + updateScaling(windowedScale()); + + return vncPage; +} + +void VncHostPreferences::updateScalingWidthHeight(int index) +{ + switch (index) { + case 0: + vncUi.kcfg_ScalingHeight->setValue(480); + vncUi.kcfg_ScalingWidth->setValue(640); + break; + case 1: + vncUi.kcfg_ScalingHeight->setValue(600); + vncUi.kcfg_ScalingWidth->setValue(800); + break; + case 2: + vncUi.kcfg_ScalingHeight->setValue(768); + vncUi.kcfg_ScalingWidth->setValue(1024); + break; + case 3: + vncUi.kcfg_ScalingHeight->setValue(1024); + vncUi.kcfg_ScalingWidth->setValue(1280); + break; + case 4: + vncUi.kcfg_ScalingHeight->setValue(1200); + vncUi.kcfg_ScalingWidth->setValue(1600); + break; + case 5: { + QDesktopWidget *desktop = QApplication::desktop(); + int currentScreen = desktop->screenNumber(vncUi.kcfg_ScalingHeight); + vncUi.kcfg_ScalingHeight->setValue(desktop->screenGeometry(currentScreen).height()); + vncUi.kcfg_ScalingWidth->setValue(desktop->screenGeometry(currentScreen).width()); + break; + } + case 6: + default: + break; + } + + checkEnableCustomSize(index); +} + +void VncHostPreferences::updateScaling(bool enabled) +{ + vncUi.resolutionComboBox->setEnabled(enabled); + if(enabled) { + checkEnableCustomSize(vncUi.resolutionComboBox->currentIndex()); + } else { + checkEnableCustomSize(-1); + } +} + +void VncHostPreferences::checkEnableCustomSize(int index) +{ + const bool enabled = (index == 6); + + vncUi.kcfg_ScalingHeight->setEnabled(enabled); + vncUi.kcfg_ScalingWidth->setEnabled(enabled); + vncUi.heightLabel->setEnabled(enabled); + vncUi.widthLabel->setEnabled(enabled); +} + +void VncHostPreferences::acceptConfig() +{ + HostPreferences::acceptConfig(); + setQuality((RemoteView::Quality)(vncUi.kcfg_Quality->currentIndex() + 1)); + setWindowedScale(vncUi.kcfg_Scaling->isChecked()); + if(vncUi.kcfg_Scaling->isChecked()) { + setHeight(vncUi.kcfg_ScalingHeight->value()); + setWidth(vncUi.kcfg_ScalingWidth->value()); + } +} + +void VncHostPreferences::setQuality(RemoteView::Quality quality) +{ + if (quality >= 0 && quality <= 3) + m_configGroup.writeEntry("quality", (int) quality); +} + +RemoteView::Quality VncHostPreferences::quality() +{ + return (RemoteView::Quality) m_configGroup.readEntry("quality", (int) Settings::quality() + 1); +} + +#include "vnchostpreferences.moc" diff --git a/krdc/vnc/vnchostpreferences.h b/krdc/vnc/vnchostpreferences.h new file mode 100644 index 00000000..4ff100b3 --- /dev/null +++ b/krdc/vnc/vnchostpreferences.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2007 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef VNCHOSTPREFERENCES_H +#define VNCHOSTPREFERENCES_H + +#include "hostpreferences.h" +#include "ui_vncpreferences.h" + +class VncHostPreferences : public HostPreferences +{ + Q_OBJECT + +public: + explicit VncHostPreferences(KConfigGroup configGroup, QObject *parent = 0); + ~VncHostPreferences(); + + void setQuality(RemoteView::Quality quality); + RemoteView::Quality quality(); + +protected: + void acceptConfig(); + + virtual QWidget* createProtocolSpecificConfigPage(); + +private: + Ui::VncPreferences vncUi; + void checkEnableCustomSize(int index); + +private slots: + void updateScalingWidthHeight(int index); + void updateScaling(bool enabled); +}; + +#endif diff --git a/krdc/vnc/vncpreferences.cpp b/krdc/vnc/vncpreferences.cpp new file mode 100644 index 00000000..c6b81774 --- /dev/null +++ b/krdc/vnc/vncpreferences.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "vncpreferences.h" +#include "remoteviewfactory.h" +#include "settings.h" + +#include "ui_vncpreferences.h" + +#include + +KRDC_PLUGIN_EXPORT(VncPreferences) + +VncPreferences::VncPreferences(QWidget *parent, const QVariantList &args) + : KCModule(KrdcFactory::componentData(), parent, args) +{ + Ui::VncPreferences vncUi; + vncUi.setupUi(this); + + // copying the RDP preferences... need to create generic code for the plugins. + vncUi.resolutionDummyLabel->hide(); + vncUi.resolutionComboBox->hide(); + vncUi.kcfg_ScalingHeight->setEnabled(true); + vncUi.kcfg_ScalingWidth->setEnabled(true); + vncUi.heightLabel->setEnabled(true); + vncUi.widthLabel->setEnabled(true); + + addConfig(Settings::self(), this); +} + +VncPreferences::~VncPreferences() +{ +} + +void VncPreferences::load() +{ + KCModule::load(); +} + +void VncPreferences::save() +{ + KCModule::save(); +} + +#include "vncpreferences.moc" diff --git a/krdc/vnc/vncpreferences.h b/krdc/vnc/vncpreferences.h new file mode 100644 index 00000000..54923f8f --- /dev/null +++ b/krdc/vnc/vncpreferences.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef VNCPREFERENCES_H +#define VNCPREFERENCES_H + +#include "vnchostpreferences.h" + +#include + +class VncPreferences : public KCModule +{ + Q_OBJECT + +public: + explicit VncPreferences(QWidget *parent = 0, const QVariantList &args = QVariantList()); + ~VncPreferences(); + + virtual void save(); + virtual void load(); + +}; + +#endif // VNCPREFERENCES_H diff --git a/krdc/vnc/vncpreferences.ui b/krdc/vnc/vncpreferences.ui new file mode 100644 index 00000000..02081ce0 --- /dev/null +++ b/krdc/vnc/vncpreferences.ui @@ -0,0 +1,225 @@ + + + VncPreferences + + + + 0 + 0 + 436 + 151 + + + + + + + Connection + + + + + + Connection type: + + + kcfg_Quality + + + + + + + + 280 + 0 + + + + Use this to specify the performance of your connection. Note that you should select the speed of the weakest link - even if you have a high speed connection, it will not help you if the remote computer uses a slow modem. Choosing a level of quality that is too high on a slow link will cause slower response times. Choosing a lower quality will increase latencies in high speed connections and results in lower image quality, especially in 'Low Quality' mode. + + + + High Quality (LAN, direct connection) + + + + + Medium Quality (DSL, Cable, fast Internet) + + + + + Low Quality (Modem, ISDN, slow Internet) + + + + + + + + + + Scale to Size: + + + + + + + + + + + + + + false + + + + 280 + 0 + + + + Here you can specify the resolution of the remote desktop. This resolution determines the size of the desktop that will be presented to you. + + + 1 + + + + Minimal (640x480) + + + + + Small (800x600) + + + + + Normal (1024x768) + + + + + Large (1280x1024) + + + + + Very Large (1600x1200) + + + + + Current Screen Resolution + + + + + Custom Resolution (...) + + + + + + + + + + false + + + &Width: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + kcfg_ScalingWidth + + + + + + + false + + + This is the width of the remote desktop. You can only change this value manually if you select Custom as desktop resolution above. + + + 9999 + + + 800 + + + + + + + false + + + H&eight: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + kcfg_ScalingHeight + + + + + + + false + + + This is the height of the remote desktop. You can only change this value manually if you select Custom as desktop resolution above. + + + 9999 + + + 600 + + + + + + + + + + + + + + Qt::Vertical + + + + 428 + 16 + + + + + + + + + KComboBox + QComboBox +
kcombobox.h
+
+
+ + +
diff --git a/krdc/vnc/vncview.cpp b/krdc/vnc/vncview.cpp new file mode 100644 index 00000000..a1e0b0a0 --- /dev/null +++ b/krdc/vnc/vncview.cpp @@ -0,0 +1,616 @@ +/**************************************************************************** +** +** Copyright (C) 2007 - 2013 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "vncview.h" + +#include +#include +#include +#include + +#ifdef QTONLY + #include + #include + #define KMessageBox QMessageBox + #define error(parent, message, caption) \ + critical(parent, caption, message) +#else + #include "settings.h" + #include + #include + #include + #include + #include +#endif + +// Definition of key modifier mask constants +#define KMOD_Alt_R 0x01 +#define KMOD_Alt_L 0x02 +#define KMOD_Meta_L 0x04 +#define KMOD_Control_L 0x08 +#define KMOD_Shift_L 0x10 + +VncView::VncView(QWidget *parent, const KUrl &url, KConfigGroup configGroup) + : RemoteView(parent), + m_initDone(false), + m_buttonMask(0), + m_repaint(false), + m_quitFlag(false), + m_firstPasswordTry(true), + m_dontSendClipboard(false), + m_horizontalFactor(1.0), + m_verticalFactor(1.0), + m_forceLocalCursor(false) +{ + m_url = url; + m_host = url.host(); + m_port = url.port(); + + // BlockingQueuedConnection can cause deadlocks when exiting, handled in startQuitting() + connect(&vncThread, SIGNAL(imageUpdated(int,int,int,int)), this, SLOT(updateImage(int,int,int,int)), Qt::BlockingQueuedConnection); + connect(&vncThread, SIGNAL(gotCut(QString)), this, SLOT(setCut(QString)), Qt::BlockingQueuedConnection); + connect(&vncThread, SIGNAL(passwordRequest(bool)), this, SLOT(requestPassword(bool)), Qt::BlockingQueuedConnection); + connect(&vncThread, SIGNAL(outputErrorMessage(QString)), this, SLOT(outputErrorMessage(QString))); + + m_clipboard = QApplication::clipboard(); + connect(m_clipboard, SIGNAL(dataChanged()), this, SLOT(clipboardDataChanged())); + +#ifndef QTONLY + m_hostPreferences = new VncHostPreferences(configGroup, this); +#else + Q_UNUSED(configGroup); +#endif +} + +VncView::~VncView() +{ + if (!m_quitFlag) startQuitting(); +} + +bool VncView::eventFilter(QObject *obj, QEvent *event) +{ + if (m_viewOnly) { + if (event->type() == QEvent::KeyPress || + event->type() == QEvent::KeyRelease || + event->type() == QEvent::MouseButtonDblClick || + event->type() == QEvent::MouseButtonPress || + event->type() == QEvent::MouseButtonRelease || + event->type() == QEvent::Wheel || + event->type() == QEvent::MouseMove) + return true; + } + + return RemoteView::eventFilter(obj, event); +} + +QSize VncView::framebufferSize() +{ + return m_frame.size(); +} + +QSize VncView::sizeHint() const +{ + return size(); +} + +QSize VncView::minimumSizeHint() const +{ + return size(); +} + +void VncView::scaleResize(int w, int h) +{ + RemoteView::scaleResize(w, h); + + kDebug(5011) << w << h; + if (m_scale) { + m_verticalFactor = (qreal) h / m_frame.height(); + m_horizontalFactor = (qreal) w / m_frame.width(); + +#ifndef QTONLY + if (Settings::keepAspectRatio()) { + m_verticalFactor = m_horizontalFactor = qMin(m_verticalFactor, m_horizontalFactor); + } +#else + m_verticalFactor = m_horizontalFactor = qMin(m_verticalFactor, m_horizontalFactor); +#endif + + const qreal newW = m_frame.width() * m_horizontalFactor; + const qreal newH = m_frame.height() * m_verticalFactor; + setMaximumSize(newW, newH); //This is a hack to force Qt to center the view in the scroll area + resize(newW, newH); + } +} + +void VncView::updateConfiguration() +{ + RemoteView::updateConfiguration(); + + // Update the scaling mode in case KeepAspectRatio changed + scaleResize(parentWidget()->width(), parentWidget()->height()); +} + +void VncView::startQuitting() +{ + kDebug(5011) << "about to quit"; + + setStatus(Disconnecting); + + m_quitFlag = true; + + vncThread.stop(); + + unpressModifiers(); + + // Disconnect all signals so that we don't get any more callbacks from the client thread + vncThread.disconnect(); + + vncThread.quit(); + + const bool quitSuccess = vncThread.wait(500); + if (!quitSuccess) { + // happens when vncThread wants to call a slot via BlockingQueuedConnection, + // needs an event loop in this thread so execution continues after 'emit' + QEventLoop loop; + if (!loop.processEvents()) { + kDebug(5011) << "BUG: deadlocked, but no events to deliver?"; + } + vncThread.wait(500); + } + + kDebug(5011) << "Quit VNC thread success:" << quitSuccess; + + setStatus(Disconnected); +} + +bool VncView::isQuitting() +{ + return m_quitFlag; +} + +bool VncView::start() +{ + vncThread.setHost(m_host); + vncThread.setPort(m_port); + RemoteView::Quality quality; +#ifdef QTONLY + quality = (RemoteView::Quality)((QCoreApplication::arguments().count() > 2) ? + QCoreApplication::arguments().at(2).toInt() : 2); +#else + quality = m_hostPreferences->quality(); +#endif + + vncThread.setQuality(quality); + + // set local cursor on by default because low quality mostly means slow internet connection + if (quality == RemoteView::Low) { + showDotCursor(RemoteView::CursorOn); +#ifndef QTONLY + // KRDC does always just have one main window, so at(0) is safe + KXMLGUIClient *mainWindow = dynamic_cast(KMainWindow::memberList().at(0)); + if (mainWindow) + mainWindow->actionCollection()->action("show_local_cursor")->setChecked(true); +#endif + } + + setStatus(Connecting); + + vncThread.start(); + return true; +} + +bool VncView::supportsScaling() const +{ + return true; +} + +bool VncView::supportsLocalCursor() const +{ + return true; +} + +void VncView::requestPassword(bool includingUsername) +{ + kDebug(5011) << "request password"; + + setStatus(Authenticating); + + if (m_firstPasswordTry && !m_url.userName().isNull()) { + vncThread.setUsername(m_url.userName()); + } + +#ifndef QTONLY + // just try to get the passwort from the wallet the first time, otherwise it will loop (see issue #226283) + if (m_firstPasswordTry && m_hostPreferences->walletSupport()) { + QString walletPassword = readWalletPassword(); + + if (!walletPassword.isNull()) { + vncThread.setPassword(walletPassword); + m_firstPasswordTry = false; + return; + } + } +#endif + + if (m_firstPasswordTry && !m_url.password().isNull()) { + vncThread.setPassword(m_url.password()); + m_firstPasswordTry = false; + return; + } + +#ifdef QTONLY + bool ok; + if (includingUsername) { + QString username = QInputDialog::getText(this, //krazy:exclude=qclasses (code not used in kde build) + tr("Username required"), + tr("Please enter the username for the remote desktop:"), + QLineEdit::Normal, m_url.userName(), &ok); //krazy:exclude=qclasses + if (ok) + vncThread.setUsername(username); + else + startQuitting(); + } + + QString password = QInputDialog::getText(this, //krazy:exclude=qclasses + tr("Password required"), + tr("Please enter the password for the remote desktop:"), + QLineEdit::Password, QString(), &ok); //krazy:exclude=qclasses + m_firstPasswordTry = false; + if (ok) + vncThread.setPassword(password); + else + startQuitting(); +#else + KPasswordDialog dialog(this, includingUsername ? KPasswordDialog::ShowUsernameLine : KPasswordDialog::NoFlags); + dialog.setPrompt(m_firstPasswordTry ? i18n("Access to the system requires a password.") + : i18n("Authentication failed. Please try again.")); + if (includingUsername) dialog.setUsername(m_url.userName()); + if (dialog.exec() == KPasswordDialog::Accepted) { + m_firstPasswordTry = false; + vncThread.setPassword(dialog.password()); + if (includingUsername) vncThread.setUsername(dialog.username()); + } else { + kDebug(5011) << "password dialog not accepted"; + startQuitting(); + } +#endif +} + +void VncView::outputErrorMessage(const QString &message) +{ + kDebug(5011) << message; + + if (message == "INTERNAL:APPLE_VNC_COMPATIBILTY") { + setCursor(localDotCursor()); + m_forceLocalCursor = true; + return; + } + + startQuitting(); + + KMessageBox::error(this, message, i18n("VNC failure")); + + emit errorMessage(i18n("VNC failure"), message); +} + +#ifndef QTONLY +HostPreferences* VncView::hostPreferences() +{ + return m_hostPreferences; +} +#endif + +void VncView::updateImage(int x, int y, int w, int h) +{ +// kDebug(5011) << "got update" << width() << height(); + + m_x = x; + m_y = y; + m_w = w; + m_h = h; + + if (m_horizontalFactor != 1.0 || m_verticalFactor != 1.0) { + // If the view is scaled, grow the update rectangle to avoid artifacts + m_x-=1; + m_y-=1; + m_w+=2; + m_h+=2; + } + + m_frame = vncThread.image(); + + if (!m_initDone) { + if (!vncThread.username().isEmpty()) { + m_url.setUserName(vncThread.username()); + } + setAttribute(Qt::WA_StaticContents); + setAttribute(Qt::WA_OpaquePaintEvent); + installEventFilter(this); + + setCursor(((m_dotCursorState == CursorOn) || m_forceLocalCursor) ? localDotCursor() : Qt::BlankCursor); + + setMouseTracking(true); // get mouse events even when there is no mousebutton pressed + setFocusPolicy(Qt::WheelFocus); + setStatus(Connected); + emit connected(); + + if (m_scale) { +#ifndef QTONLY + kDebug(5011) << "Setting initial size w:" <width() << " h:" << m_hostPreferences->height(); + emit framebufferSizeChanged(m_hostPreferences->width(), m_hostPreferences->height()); + scaleResize(m_hostPreferences->width(), m_hostPreferences->height()); + kDebug() << "m_frame.size():" << m_frame.size() << "size()" << size(); +#else +//TODO: qtonly alternative +#endif + } + + m_initDone = true; + +#ifndef QTONLY + if (m_hostPreferences->walletSupport()) { + saveWalletPassword(vncThread.password()); + } +#endif + } + + if ((y == 0 && x == 0) && (m_frame.size() != size())) { + kDebug(5011) << "Updating framebuffer size"; + if (m_scale) { + setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); + if (parentWidget()) + scaleResize(parentWidget()->width(), parentWidget()->height()); + } else { + kDebug(5011) << "Resizing: " << m_frame.width() << m_frame.height(); + resize(m_frame.width(), m_frame.height()); + setMaximumSize(m_frame.width(), m_frame.height()); //This is a hack to force Qt to center the view in the scroll area + setMinimumSize(m_frame.width(), m_frame.height()); + emit framebufferSizeChanged(m_frame.width(), m_frame.height()); + } + } + + m_repaint = true; + repaint(qRound(m_x * m_horizontalFactor), qRound(m_y * m_verticalFactor), qRound(m_w * m_horizontalFactor), qRound(m_h * m_verticalFactor)); + m_repaint = false; +} + +void VncView::setViewOnly(bool viewOnly) +{ + RemoteView::setViewOnly(viewOnly); + + m_dontSendClipboard = viewOnly; + + if (viewOnly) + setCursor(Qt::ArrowCursor); + else + setCursor(m_dotCursorState == CursorOn ? localDotCursor() : Qt::BlankCursor); +} + +void VncView::showDotCursor(DotCursorState state) +{ + RemoteView::showDotCursor(state); + + setCursor(state == CursorOn ? localDotCursor() : Qt::BlankCursor); +} + +void VncView::enableScaling(bool scale) +{ + RemoteView::enableScaling(scale); + + if (scale) { + setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); + setMinimumSize(1, 1); + if (parentWidget()) + scaleResize(parentWidget()->width(), parentWidget()->height()); + } else { + m_verticalFactor = 1.0; + m_horizontalFactor = 1.0; + + setMaximumSize(m_frame.width(), m_frame.height()); //This is a hack to force Qt to center the view in the scroll area + setMinimumSize(m_frame.width(), m_frame.height()); + resize(m_frame.width(), m_frame.height()); + } +} + +void VncView::setCut(const QString &text) +{ + m_dontSendClipboard = true; + m_clipboard->setText(text, QClipboard::Clipboard); + m_dontSendClipboard = false; +} + +void VncView::paintEvent(QPaintEvent *event) +{ +// kDebug(5011) << "paint event: x: " << m_x << ", y: " << m_y << ", w: " << m_w << ", h: " << m_h; + if (m_frame.isNull() || m_frame.format() == QImage::Format_Invalid) { + kDebug(5011) << "no valid image to paint"; + RemoteView::paintEvent(event); + return; + } + + event->accept(); + + QPainter painter(this); + + if (m_repaint) { +// kDebug(5011) << "normal repaint"; + painter.drawImage(QRect(qRound(m_x*m_horizontalFactor), qRound(m_y*m_verticalFactor), + qRound(m_w*m_horizontalFactor), qRound(m_h*m_verticalFactor)), + m_frame.copy(m_x, m_y, m_w, m_h).scaled(qRound(m_w*m_horizontalFactor), + qRound(m_h*m_verticalFactor), + Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + } else { +// kDebug(5011) << "resize repaint"; + QRect rect = event->rect(); + if (rect.width() != width() || rect.height() != height()) { +// kDebug(5011) << "Partial repaint"; + const int sx = rect.x()/m_horizontalFactor; + const int sy = rect.y()/m_verticalFactor; + const int sw = rect.width()/m_horizontalFactor; + const int sh = rect.height()/m_verticalFactor; + painter.drawImage(rect, + m_frame.copy(sx, sy, sw, sh).scaled(rect.width(), rect.height(), + Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + } else { +// kDebug(5011) << "Full repaint" << width() << height() << m_frame.width() << m_frame.height(); + painter.drawImage(QRect(0, 0, width(), height()), + m_frame.scaled(m_frame.width() * m_horizontalFactor, m_frame.height() * m_verticalFactor, + Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + } + } + + RemoteView::paintEvent(event); +} + +void VncView::resizeEvent(QResizeEvent *event) +{ + RemoteView::resizeEvent(event); + update(); +} + +bool VncView::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::KeyPress: + case QEvent::KeyRelease: +// kDebug(5011) << "keyEvent"; + keyEventHandler(static_cast(event)); + return true; + break; + case QEvent::MouseButtonDblClick: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: +// kDebug(5011) << "mouseEvent"; + mouseEventHandler(static_cast(event)); + return true; + break; + case QEvent::Wheel: +// kDebug(5011) << "wheelEvent"; + wheelEventHandler(static_cast(event)); + return true; + break; + default: + return RemoteView::event(event); + } +} + +void VncView::mouseEventHandler(QMouseEvent *e) +{ + if (e->type() != QEvent::MouseMove) { + if ((e->type() == QEvent::MouseButtonPress) || + (e->type() == QEvent::MouseButtonDblClick)) { + if (e->button() & Qt::LeftButton) + m_buttonMask |= 0x01; + if (e->button() & Qt::MidButton) + m_buttonMask |= 0x02; + if (e->button() & Qt::RightButton) + m_buttonMask |= 0x04; + } else if (e->type() == QEvent::MouseButtonRelease) { + if (e->button() & Qt::LeftButton) + m_buttonMask &= 0xfe; + if (e->button() & Qt::MidButton) + m_buttonMask &= 0xfd; + if (e->button() & Qt::RightButton) + m_buttonMask &= 0xfb; + } + } + + vncThread.mouseEvent(qRound(e->x() / m_horizontalFactor), qRound(e->y() / m_verticalFactor), m_buttonMask); +} + +void VncView::wheelEventHandler(QWheelEvent *event) +{ + int eb = 0; + if (event->delta() < 0) + eb |= 0x10; + else + eb |= 0x8; + + const int x = qRound(event->x() / m_horizontalFactor); + const int y = qRound(event->y() / m_verticalFactor); + + vncThread.mouseEvent(x, y, eb | m_buttonMask); + vncThread.mouseEvent(x, y, m_buttonMask); +} + +void VncView::keyEventHandler(QKeyEvent *e) +{ + // strip away autorepeating KeyRelease; see bug #206598 + if (e->isAutoRepeat() && (e->type() == QEvent::KeyRelease)) + return; + +// parts of this code are based on http://italc.sourcearchive.com/documentation/1.0.9.1/vncview_8cpp-source.html + rfbKeySym k = e->nativeVirtualKey(); + + // we do not handle Key_Backtab separately as the Shift-modifier + // is already enabled + if (e->key() == Qt::Key_Backtab) { + k = XK_Tab; + } + + const bool pressed = (e->type() == QEvent::KeyPress); + + // handle modifiers + if (k == XK_Shift_L || k == XK_Control_L || k == XK_Meta_L || k == XK_Alt_L) { + if (pressed) { + m_mods[k] = true; + } else if (m_mods.contains(k)) { + m_mods.remove(k); + } else { + unpressModifiers(); + } + } + + if (k) { + vncThread.keyEvent(k, pressed); + } +} + +void VncView::unpressModifiers() +{ + const QList keys = m_mods.keys(); + QList::const_iterator it = keys.constBegin(); + while (it != keys.end()) { + vncThread.keyEvent(*it, false); + it++; + } + m_mods.clear(); +} + +void VncView::clipboardDataChanged() +{ + kDebug(5011); + + if (m_status != Connected) + return; + + if (m_clipboard->ownsClipboard() || m_dontSendClipboard) + return; + + const QString text = m_clipboard->text(QClipboard::Clipboard); + + vncThread.clientCut(text); +} + +#include "moc_vncview.cpp" diff --git a/krdc/vnc/vncview.h b/krdc/vnc/vncview.h new file mode 100644 index 00000000..2cf72f22 --- /dev/null +++ b/krdc/vnc/vncview.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2007 - 2013 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef VNCVIEW_H +#define VNCVIEW_H + +#include "remoteview.h" +#include "vncclientthread.h" + +#ifdef QTONLY + class KConfigGroup{}; +#else + #include "vnchostpreferences.h" +#endif + +#include + +extern "C" { +#include +} + +class VncView: public RemoteView +{ + Q_OBJECT + +public: + explicit VncView(QWidget *parent = 0, const KUrl &url = KUrl(), KConfigGroup configGroup = KConfigGroup()); + ~VncView(); + + QSize framebufferSize(); + QSize sizeHint() const; + QSize minimumSizeHint() const; + void startQuitting(); + bool isQuitting(); + bool start(); + bool supportsScaling() const; + bool supportsLocalCursor() const; + +#ifndef QTONLY + HostPreferences* hostPreferences(); +#endif + + void setViewOnly(bool viewOnly); + void showDotCursor(DotCursorState state); + void enableScaling(bool scale); + + virtual void updateConfiguration(); + +public slots: + void scaleResize(int w, int h); + +protected: + void paintEvent(QPaintEvent *event); + bool event(QEvent *event); + void resizeEvent(QResizeEvent *event); + bool eventFilter(QObject *obj, QEvent *event); + +private: + VncClientThread vncThread; + QClipboard *m_clipboard; + bool m_initDone; + int m_buttonMask; + QMap m_mods; + int m_x, m_y, m_w, m_h; + bool m_repaint; + bool m_quitFlag; + bool m_firstPasswordTry; + bool m_dontSendClipboard; + qreal m_horizontalFactor; + qreal m_verticalFactor; +#ifndef QTONLY + VncHostPreferences *m_hostPreferences; +#endif + QImage m_frame; + bool m_forceLocalCursor; + + void keyEventHandler(QKeyEvent *e); + void unpressModifiers(); + void wheelEventHandler(QWheelEvent *event); + void mouseEventHandler(QMouseEvent *event); + +private slots: + void updateImage(int x, int y, int w, int h); + void setCut(const QString &text); + void requestPassword(bool includingUsername); + void outputErrorMessage(const QString &message); + void clipboardDataChanged(); +}; + +#endif diff --git a/krdc/vnc/vncviewfactory.cpp b/krdc/vnc/vncviewfactory.cpp new file mode 100644 index 00000000..c06f474e --- /dev/null +++ b/krdc/vnc/vncviewfactory.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#include "vncviewfactory.h" + +#include + +KRDC_PLUGIN_EXPORT(VncViewFactory) + +VncViewFactory::VncViewFactory(QObject *parent, const QVariantList &args) + : RemoteViewFactory(parent) +{ + Q_UNUSED(args); + + KGlobal::locale()->insertCatalog("krdc"); +} + +VncViewFactory::~VncViewFactory() +{ +} + +bool VncViewFactory::supportsUrl(const KUrl &url) const +{ + return (url.scheme().compare("vnc", Qt::CaseInsensitive) == 0); +} + +RemoteView *VncViewFactory::createView(QWidget *parent, const KUrl &url, KConfigGroup configGroup) +{ + return new VncView(parent, url, configGroup); +} + +HostPreferences *VncViewFactory::createHostPreferences(KConfigGroup configGroup, QWidget *parent) +{ + return new VncHostPreferences(configGroup, parent); +} + +QString VncViewFactory::scheme() const +{ + return "vnc"; +} + +QString VncViewFactory::connectActionText() const +{ + return i18n("New VNC Connection..."); +} + +QString VncViewFactory::connectButtonText() const +{ + return i18n("Connect to a VNC Remote Desktop"); +} + +QString VncViewFactory::connectToolTipText() const +{ + return i18n("Enter the address here.
" + "Example: vncserver:1 (host:port / screen)"); +} + +#include "moc_vncviewfactory.cpp" diff --git a/krdc/vnc/vncviewfactory.h b/krdc/vnc/vncviewfactory.h new file mode 100644 index 00000000..8fd2bbb9 --- /dev/null +++ b/krdc/vnc/vncviewfactory.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Urs Wolfer +** +** This file is part of KDE. +** +** 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; see the file COPYING. If not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +** Boston, MA 02110-1301, USA. +** +****************************************************************************/ + +#ifndef VNCVIEWFACTORY_H +#define VNCVIEWFACTORY_H + +#include "remoteviewfactory.h" + +#include "vncview.h" +#include "vncpreferences.h" + +class VncViewFactory : public RemoteViewFactory +{ + Q_OBJECT + +public: + explicit VncViewFactory(QObject *parent, const QVariantList &args); + + virtual ~VncViewFactory(); + + virtual bool supportsUrl(const KUrl &url) const; + + virtual RemoteView *createView(QWidget *parent, const KUrl &url, KConfigGroup configGroup); + + virtual HostPreferences *createHostPreferences(KConfigGroup configGroup, QWidget *parent); + + virtual QString scheme() const; + + virtual QString connectActionText() const; + + virtual QString connectButtonText() const; + + virtual QString connectToolTipText() const; +}; + +#endif // VNCVIEWFACTORY_H diff --git a/krfb/.directory b/krfb/.directory new file mode 100644 index 00000000..e9cc08e7 --- /dev/null +++ b/krfb/.directory @@ -0,0 +1,6 @@ +[Dolphin] +Timestamp=2014,12,27,18,58,34 +Version=3 + +[Settings] +HiddenFilesShown=true diff --git a/krfb/.krazy b/krfb/.krazy new file mode 100644 index 00000000..3a80b611 --- /dev/null +++ b/krfb/.krazy @@ -0,0 +1 @@ +SKIP /kinetd/ diff --git a/krfb/AUTHORS b/krfb/AUTHORS new file mode 100644 index 00000000..adf3d018 --- /dev/null +++ b/krfb/AUTHORS @@ -0,0 +1,2 @@ +Tim Jansen +Ian Reinhart Geiser \ No newline at end of file diff --git a/krfb/CMakeLists.txt b/krfb/CMakeLists.txt new file mode 100644 index 00000000..999c1a69 --- /dev/null +++ b/krfb/CMakeLists.txt @@ -0,0 +1,62 @@ +project(krfb) + +if(NOT INSIDE_KDENETWORK) + message("Not building inside KDENetwork, loading KDE CMake Macros.") + + find_package(KDE4 REQUIRED) + + include(KDE4Defaults) + include(MacroLibrary) + + include(CheckIncludeFile) + include(CheckIncludeFiles) + include(CheckSymbolExists) + include(CheckFunctionExists) + include(CheckLibraryExists) + include(CheckPrototypeExists) + include(CheckTypeSize) + + set(CMAKE_REQUIRED_DEFINITIONS ${_KDE4_PLATFORM_DEFINITIONS}) + if(WIN32) + set(CMAKE_REQUIRED_LIBRARIES ${KDEWIN32_LIBRARIES}) + set(CMAKE_REQUIRED_INCLUDES ${KDEWIN32_INCLUDES}) + endif(WIN32) + add_definitions(${QT_DEFINITIONS} ${QT_QTDBUS_DEFINITIONS} ${KDE4_DEFINITIONS}) + add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS) + include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES}) +endif(NOT INSIDE_KDENETWORK) + +set(IS_KTP_INTERNAL_MODULE TRUE) +set(CMAKE_MODULE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" + ${CMAKE_MODULE_PATH} +) + +find_package(LibVNCServer REQUIRED) + +macro_optional_find_package(TelepathyQt4) +macro_log_feature(TelepathyQt4_FOUND "telepathy-qt" "Telepathy Qt Bindings" "http://telepathy.freedesktop.org" FALSE "0.9" "Needed to build Telepathy Tubes support.") + +macro_optional_find_package(KTp) +macro_log_feature(KTP_FOUND "KTP" "KDE Telepathy" "https://projects.kde.org/projects/extragear/network/telepathy" FALSE "" "Needed to build KDE IM Contacts Display in KRFB.") + +macro_bool_to_01(X11_Xdamage_FOUND HAVE_XDAMAGE) +macro_bool_to_01(X11_XShm_FOUND HAVE_XSHM) + +include_directories ("${CMAKE_CURRENT_BINARY_DIR}/krfb" + "${CMAKE_CURRENT_SOURCE_DIR}/krfb" + "${CMAKE_CURRENT_SOURCE_DIR}/krfb/ui" +) + +if(Q_WS_X11) + if(NOT X11_XTest_FOUND) + message(FATAL_ERROR "krfb requires the libXtst (http://xorg.freedesktop.org) to be built") + endif(NOT X11_XTest_FOUND) +endif(Q_WS_X11) + +add_subdirectory(krfb) +add_subdirectory(framebuffers) + +if (NOT INSIDE_KDENETWORK) + macro_display_feature_log() +endif () diff --git a/krfb/COPYING b/krfb/COPYING new file mode 100644 index 00000000..8900e10b --- /dev/null +++ b/krfb/COPYING @@ -0,0 +1,347 @@ +NOTE! The GPL below is copyrighted by the Free Software Foundation, but +the instance of code that it refers to (the kde programs) are copyrighted +by the authors who actually wrote it. + +--------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + 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. + + + Copyright (C) 19yy + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 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/krfb/COPYING.DOC b/krfb/COPYING.DOC new file mode 100644 index 00000000..4a0fe1c8 --- /dev/null +++ b/krfb/COPYING.DOC @@ -0,0 +1,397 @@ + GNU Free Documentation License + Version 1.2, November 2002 + + + Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + +0. PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document "free" in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. + +This License is a kind of "copyleft", which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + + +1. APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The "Document", below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as "you". You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. + +A "Modified Version" of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A "Secondary Section" is a named appendix or a front-matter section of +the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall subject +(or to related matters) and contains nothing that could fall directly +within that overall subject. (Thus, if the Document is in part a +textbook of mathematics, a Secondary Section may not explain any +mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The "Invariant Sections" are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. + +The "Cover Texts" are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. + +A "Transparent" copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not "Transparent" is called "Opaque". + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input format, SGML +or XML using a publicly available DTD, and standard-conforming simple +HTML, PostScript or PDF designed for human modification. Examples of +transparent image formats include PNG, XCF and JPG. Opaque formats +include proprietary formats that can be read and edited only by +proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the +machine-generated HTML, PostScript or PDF produced by some word +processors for output purposes only. + +The "Title Page" means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, "Title Page" means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. + +A section "Entitled XYZ" means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as "Acknowledgements", +"Dedications", "Endorsements", or "History".) To "Preserve the Title" +of such a section when you modify the Document means that it remains a +section "Entitled XYZ" according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. + + +2. VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + + +3. COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. + + +4. MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +A. Use in the Title Page (and on the covers, if any) a title distinct + from that of the Document, and from those of previous versions + (which should, if there were any, be listed in the History section + of the Document). You may use the same title as a previous version + if the original publisher of that version gives permission. +B. List on the Title Page, as authors, one or more persons or entities + responsible for authorship of the modifications in the Modified + Version, together with at least five of the principal authors of the + Document (all of its principal authors, if it has fewer than five), + unless they release you from this requirement. +C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. +D. Preserve all the copyright notices of the Document. +E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. +F. Include, immediately after the copyright notices, a license notice + giving the public permission to use the Modified Version under the + terms of this License, in the form shown in the Addendum below. +G. Preserve in that license notice the full lists of Invariant Sections + and required Cover Texts given in the Document's license notice. +H. Include an unaltered copy of this License. +I. Preserve the section Entitled "History", Preserve its Title, and add + to it an item stating at least the title, year, new authors, and + publisher of the Modified Version as given on the Title Page. If + there is no section Entitled "History" in the Document, create one + stating the title, year, authors, and publisher of the Document as + given on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence. +J. Preserve the network location, if any, given in the Document for + public access to a Transparent copy of the Document, and likewise + the network locations given in the Document for previous versions + it was based on. These may be placed in the "History" section. + You may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission. +K. For any section Entitled "Acknowledgements" or "Dedications", + Preserve the Title of the section, and preserve in the section all + the substance and tone of each of the contributor acknowledgements + and/or dedications given therein. +L. Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section titles. +M. Delete any section Entitled "Endorsements". Such a section + may not be included in the Modified Version. +N. Do not retitle any existing section to be Entitled "Endorsements" + or to conflict in title with any Invariant Section. +O. Preserve any Warranty Disclaimers. + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled "Endorsements", provided it contains +nothing but endorsements of your Modified Version by various +parties--for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + + +5. COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections Entitled "History" +in the various original documents, forming one section Entitled +"History"; likewise combine any sections Entitled "Acknowledgements", +and any sections Entitled "Dedications". You must delete all sections +Entitled "Endorsements". + + +6. COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. + +You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. + + +7. AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an "aggregate" if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. + + +8. TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. + +If a section in the Document is Entitled "Acknowledgements", +"Dedications", or "History", the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. + + +9. TERMINATION + +You may not copy, modify, sublicense, or distribute the Document except +as expressly provided for under this License. Any other attempt to +copy, modify, sublicense or distribute the Document 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. + + +10. FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions +of the GNU Free Documentation 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. See +http://www.gnu.org/copyleft/. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. + + +ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + + Copyright (c) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled "GNU + Free Documentation License". + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the "with...Texts." line with this: + + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. diff --git a/krfb/COPYING.LIB b/krfb/COPYING.LIB new file mode 100644 index 00000000..2d2d780e --- /dev/null +++ b/krfb/COPYING.LIB @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/krfb/NOTES b/krfb/NOTES new file mode 100644 index 00000000..24b30178 --- /dev/null +++ b/krfb/NOTES @@ -0,0 +1,27 @@ +Comments on various aspects of KRfb: + +- KRfb has been designed for three use cases: + * a user who needs help from an administrator or friend. The adminstrator can + connect to the user and change settings and so on while both are talking + on the telephone or using VoIP. + * a user who wants to show something to a friend, so he lets his friend + connect to his computer + * (advanced use case) somebody with several computers, that are running + GUIs, wants to control them. +- cases 1&2 are probably more mainstream and more important for novice users, + so KRfb is pre-configured for them. Case 3 is for advanced users and + therefore a little bit more difficult to configure. +- design goal of KRfb is to make it as easy to use as possible. I tried to + limit functionality whereever possible. +- the new-connection-dialog is extra large and has the pixmap on the left + side to capture the attention of the user before allowing a connection. +- the RFBController class is a mess. The interactions between the threaded, + callback-using libvncserver and the event-driven, single thread qt GUI are + quite complicated and I can only hope that it works. +- most limitations and problems of KRfb are caused either by limitations of + Rfb (for example no proper authentication of users, no encryption) or + by lack of a framework in Linux in general (no way to connect through a + NAT device). In the next months I am going to concentrate on improving the + latter. + +tim@tjansen.de diff --git a/krfb/README b/krfb/README new file mode 100644 index 00000000..ada74b6d --- /dev/null +++ b/krfb/README @@ -0,0 +1,19 @@ +KDE Desktop Sharing (krfb) +========================== + +KDE Desktop Sharing (krfb) is a small server for the RFB protocol, better +known as VNC. Unlike most other Unix/Linux RFB servers, KRfb allows you to +share your X11 session instead of creating a new X11 session. +It was originally based on x0rfbserver +(ttp://www.hexonet.de/software/x0rfbserver/), but there is not much code of +x0rfbserver left. Since version 0.6 it uses libvncserver +(http://libvncserver.sf.net) as backend. + + +Guide to documentation: +TODO - things to be done +INSTALL - Very short installation instructions +NOTES - reasons for various decisions +DCOP-INTERFACE - short documentation of the DCOP interface + + diff --git a/krfb/TODO b/krfb/TODO new file mode 100644 index 00000000..1258e590 --- /dev/null +++ b/krfb/TODO @@ -0,0 +1,28 @@ + +For 3.2: +- write SLP service template for remote desktop protocols + (documentation) +- enhance RFB with SASL authentication (Kerberos) +- encrypted connections (using SASL and/or SSL/TLS) +- with kerberos/ssl: display name of remote user in connection dialog, + kpassivepopup and systray (if name is available) +- mention that invitations are one-time on personal invitation dialog + +Todo (unscheduled features): +- when krfb is started with URL arguments and without connection + quality, add some kind of smart algorithm to determine whether the + other host is local (maybe using SLP to announce the connectivity + of a LAN) +- NAT traversal support if I can find an acceptable implementation + (probably using TURN, as soon as there is a server and newer spec for that) +- when OpenSLP supports this, allow scope configuration +- split krfb into 2 separate programs (server and invitation) +- look into adding an extension to xfree to improve speed (get noticed of + screen updates) +- cut & paste support + +Known bugs/problems: +- the IP address sent in invitation may be wrong on multi-homed machines, + and it is always incorrect behind a NAT. Right now it is not possible + to solve these problems. + diff --git a/krfb/cmake/modules/COPYING-CMAKE-SCRIPTS b/krfb/cmake/modules/COPYING-CMAKE-SCRIPTS new file mode 100644 index 00000000..4b417765 --- /dev/null +++ b/krfb/cmake/modules/COPYING-CMAKE-SCRIPTS @@ -0,0 +1,22 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. diff --git a/krfb/cmake/modules/FindKTp.cmake b/krfb/cmake/modules/FindKTp.cmake new file mode 100644 index 00000000..8facd12f --- /dev/null +++ b/krfb/cmake/modules/FindKTp.cmake @@ -0,0 +1,38 @@ +# Try to find the KTp library +# KTP_FOUND +# KTP_INCLUDE_DIR +# KTP_LIBRARIES +# KTP_MODELS_LIBRARIES +# KTP_WIDGETS_LIBRARIES + +# Copyright (c) 2011, Dario Freddi +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +if (NOT IS_KTP_INTERNAL_MODULE) + message (FATAL_ERROR "KTp can be used just from internal components at this time") +endif (NOT IS_KTP_INTERNAL_MODULE) + +SET (KTP_FIND_REQUIRED ${KTp_FIND_REQUIRED}) +if (KTP_INCLUDE_DIRS AND KTP_LIBRARIES) + # Already in cache, be silent + set(KTP_FIND_QUIETLY TRUE) +endif (KTP_INCLUDE_DIRS AND KTP_LIBRARIES) + +find_path(KTP_INCLUDE_DIR + NAMES KTp/presence.h + PATHS ${KDE4_INCLUDE_DIR} +) + +find_library(KTP_LIBRARIES NAMES ktpcommoninternalsprivate ) +find_library(KTP_MODELS_LIBRARIES NAMES ktpmodelsprivate ) +find_library(KTP_WIDGETS_LIBRARIES NAMES ktpwidgetsprivate ) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(KTp DEFAULT_MSG + KTP_LIBRARIES + KTP_MODELS_LIBRARIES + KTP_INCLUDE_DIR) + +mark_as_advanced(KTP_INCLUDE_DIRS KTP_LIBRARIES) diff --git a/krfb/cmake/modules/FindLibVNCServer.cmake b/krfb/cmake/modules/FindLibVNCServer.cmake new file mode 100644 index 00000000..5927ab26 --- /dev/null +++ b/krfb/cmake/modules/FindLibVNCServer.cmake @@ -0,0 +1,41 @@ +# cmake macro to test LIBVNCSERVER LIB + +# Copyright (c) 2006, Alessandro Praduroux +# Copyright (c) 2007, Urs Wolfer +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +INCLUDE(CheckPointerMember) + +IF (LIBVNCSERVER_INCLUDE_DIR AND LIBVNCSERVER_LIBRARIES) + # Already in cache, be silent + SET(LIBVNCSERVER_FIND_QUIETLY TRUE) +ENDIF (LIBVNCSERVER_INCLUDE_DIR AND LIBVNCSERVER_LIBRARIES) + +FIND_PATH(LIBVNCSERVER_INCLUDE_DIR rfb/rfb.h) + +FIND_LIBRARY(LIBVNCSERVER_LIBRARIES NAMES vncserver libvncserver) + +# libvncserver and libvncclient are in the same package, so it does +# not make sense to add a new cmake script for finding libvncclient. +# instead just find the libvncclient also in this file. +FIND_PATH(LIBVNCCLIENT_INCLUDE_DIR rfb/rfbclient.h) +FIND_LIBRARY(LIBVNCCLIENT_LIBRARIES NAMES vncclient libvncclient) + +IF (LIBVNCSERVER_INCLUDE_DIR AND LIBVNCSERVER_LIBRARIES) + SET(CMAKE_REQUIRED_INCLUDES "${LIBVNCSERVER_INCLUDE_DIR}" "${CMAKE_REQUIRED_INCLUDES}") + CHECK_POINTER_MEMBER(rfbClient* GotXCutText rfb/rfbclient.h LIBVNCSERVER_FOUND) +ENDIF (LIBVNCSERVER_INCLUDE_DIR AND LIBVNCSERVER_LIBRARIES) + +IF (LIBVNCSERVER_FOUND) + IF (NOT LIBVNCSERVER_FIND_QUIETLY) + MESSAGE(STATUS "Found LibVNCServer: ${LIBVNCSERVER_LIBRARIES}") + ENDIF (NOT LIBVNCSERVER_FIND_QUIETLY) +ELSE (LIBVNCSERVER_FOUND) + IF (LIBVNCSERVER_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could NOT find acceptable version of LibVNCServer (version 0.9 or later required).") + ENDIF (LIBVNCSERVER_FIND_REQUIRED) +ENDIF (LIBVNCSERVER_FOUND) + +MARK_AS_ADVANCED(LIBVNCSERVER_INCLUDE_DIR LIBVNCSERVER_LIBRARIES) \ No newline at end of file diff --git a/krfb/framebuffers/CMakeLists.txt b/krfb/framebuffers/CMakeLists.txt new file mode 100644 index 00000000..32f42c3a --- /dev/null +++ b/krfb/framebuffers/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory (qt) +add_subdirectory (x11) + diff --git a/krfb/framebuffers/qt/CMakeLists.txt b/krfb/framebuffers/qt/CMakeLists.txt new file mode 100644 index 00000000..194b405f --- /dev/null +++ b/krfb/framebuffers/qt/CMakeLists.txt @@ -0,0 +1,28 @@ +include_directories (${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} +) + +set (krfb_framebuffer_qt_SRCS + qtframebuffer.cpp + qtframebufferplugin.cpp +) + +kde4_add_plugin (krfb_framebuffer_qt + ${krfb_framebuffer_qt_SRCS} +) + +target_link_libraries (krfb_framebuffer_qt + ${QT_QTCORE_LIBRARY} + ${QT_QTGUI_LIBRARY} + ${KDE4_KDEUI_LIBS} + krfbprivate +) + +install (TARGETS krfb_framebuffer_qt + DESTINATION ${PLUGIN_INSTALL_DIR} +) + +install (FILES krfb_framebuffer_qt.desktop + DESTINATION ${SERVICES_INSTALL_DIR} +) + diff --git a/krfb/framebuffers/qt/krfb_framebuffer_qt.desktop b/krfb/framebuffers/qt/krfb_framebuffer_qt.desktop new file mode 100644 index 00000000..dc1972e4 --- /dev/null +++ b/krfb/framebuffers/qt/krfb_framebuffer_qt.desktop @@ -0,0 +1,107 @@ +[Desktop Entry] +Encoding=UTF-8 +Comment=Qt based Framebuffer for KRfb. +Comment[ast]=Esquema Qt de buffer pa KRfb +Comment[bg]=Основан на Qt фреймбуфер за KRfb. +Comment[bs]=Kadrobafer za KRfb na osnovu Qt +Comment[ca]=«Framebuffer» basat en Qt per al KRfb. +Comment[ca@valencia]=«Framebuffer» basat en Qt per al KRfb. +Comment[cs]=Framebuffer založený na Qt pro KRfb. +Comment[da]=Qt-baseret framebuffer til KRfb. +Comment[de]=Qt-basierter Framebuffer für KRfb +Comment[el]=Μνήμη εξόδου βίντεο καρέ με βάση το Qt για το KRfb. +Comment[en_GB]=Qt based Framebuffer for KRfb. +Comment[es]=Memoria intermedia de vídeo basada en Qt para KRfb. +Comment[et]=KRfb Qt põhine kaadripuhver +Comment[eu]=Qt-n oinarritutako KRfb-ren irteerako bideoa +Comment[fi]=QT-perustainen Kehyspuskuri KRfb:lle +Comment[fr]=Sortie vidéo fondée sur Qt pour Krfb. +Comment[ga]=Maolán fráma le haghaidh KRfb, bunaithe ar Qt. +Comment[gl]=Framebuffer baseado en Qt para KRfb. +Comment[hr]=Međuspremnik okvira baziran na Qt-u za KRfb. +Comment[hu]=Qt-alapú framebuffer a Krfb-hez. +Comment[ia]=Framebuffer basate sur Qt per KRfb +Comment[it]=Framebuffer basato su Qt per KRfb. +Comment[kk]=Qt негіздеген KRfb-нің кадр буфері. +Comment[km]=Framebuffer មាន​មូលដ្ឋាន​លើ Qt សម្រាប់ KRfb ។ +Comment[ko]=KRfb를 위한 Qt 기반 프레임버퍼. +Comment[lt]=Qt pagrindu veikiantis Framebuffer skirtas KRfb. +Comment[lv]=Qt balstīts kadrbuferis priekš KRfb. +Comment[nb]=Qt-basert rammebuffer for KRfb. +Comment[nds]=Op Qt opbuut Bildpuffer för KRfb +Comment[nl]=Op Qt gebaseerd framebuffer voor KRfb. +Comment[nn]=Qt basert framebuffer for KRfb. +Comment[pl]=Bufor ramki na podstawie Qt dla KRfb. +Comment[pt]='Framebuffer' baseado no Qt para o KRfb. +Comment[pt_BR]=Framebuffer baseado no Qt para o KRfb. +Comment[ru]=Буфер экрана для KRfb на базе Qt. +Comment[si]=KRfb සඳහා Qt මත පදනම් වූ රාමු බෆරය +Comment[sk]=Framebuffer založený na Qt pre KRfb. +Comment[sl]=Slikovni medpomnilnik za KRFB, ki temelji na Qt +Comment[sr]=Кадробафер за КРФБ на основу КуТ‑у +Comment[sr@ijekavian]=Кадробафер за КРФБ на основу КуТ‑у +Comment[sr@ijekavianlatin]=Kadrobafer za KRFB na osnovu Qt‑u +Comment[sr@latin]=Kadrobafer za KRFB na osnovu Qt‑u +Comment[sv]=Qt-baserad rambuffert för Krfb. +Comment[tr]=KRfb için Qt temelli Çerçeve tamponu. +Comment[uk]=Заснований на Qt буфер кадрів для KRfb. +Comment[x-test]=xxQt based Framebuffer for KRfb.xx +Comment[zh_CN]=基于 Qt 的 KRfb 帧缓冲机制 +Comment[zh_TW]=KRfb 的 Qt-based Framebuffer +Name=Qt Framebuffer for KRfb +Name[ast]=Esquema Qt de buffer pa KRfb +Name[bg]=Qt фреймбуфер за KRfb +Name[bs]=Qt-ov kadrobafer za KRFB +Name[ca]=«Framebuffer» Qt per al KRfb. +Name[ca@valencia]=«Framebuffer» Qt per al KRfb. +Name[cs]=Qt Framebuffer pro KRfb +Name[da]=Qt-framebuffer til KRfb +Name[de]=Qt-Framebuffer für KRfb +Name[el]=Qt Framebuffer for KRfb +Name[en_GB]=Qt Framebuffer for KRfb +Name[es]=Memoria intermedia de vídeo Qt para KRfb +Name[et]=KRfb Qt kaadripuhver +Name[eu]=KRfb-ren Qt-ko irteerako bideoa +Name[fi]=QT-kehyspuskuri KRfb:lle +Name[fr]=Sortie vidéo Qt pour Krfb +Name[ga]=Maolán fráma Qt le haghaidh KRfb +Name[gl]=Framebuffer de Qt para KRfb +Name[hr]=Qt Framebuffer za KRfb +Name[hu]=Qt framebuffer a Krfb-hez +Name[ia]=Framebuffer Qt per KRfb +Name[it]=Framebuffer Qt per KRfb +Name[kk]=Qt KRfb кадр буфері +Name[km]=Qt Framebuffer សម្រាប់for KRfb +Name[ko]=KRfb를 위한 Qt 프레임버퍼 +Name[lt]=Qt Framebufferis skirtas KRfb +Name[lv]=Qt kadrbuferis priekš KRfb. +Name[nb]=Qt rammebuffer for KRfb +Name[nds]=Qt-Bildpuffer för KRfb +Name[nl]=Qt-framebuffer voor KRfb +Name[nn]=Qt-framebuffer for KRfb +Name[pl]=Bufor ramki Qt dla KRfb +Name[pt]='Framebuffer' do Qt para o KRfb +Name[pt_BR]=Framebuffer do Qt para o KRfb +Name[ru]=Буфер экрана Qt для KRfb +Name[si]=KRfb සඳහා වන Qt රාමුබෆරය +Name[sk]=Qt Framebuffer pre KRfb +Name[sl]=Slikovni medpomnilnik Qt za KRFB +Name[sr]=КуТ‑ов кадробафер за КРФБ +Name[sr@ijekavian]=КуТ‑ов кадробафер за КРФБ +Name[sr@ijekavianlatin]=Qt‑ov kadrobafer za KRFB +Name[sr@latin]=Qt‑ov kadrobafer za KRFB +Name[sv]=Qt-rambuffert för Krfb +Name[tr]=KRfb için Qt Çerçeve tamponu +Name[uk]=Буфер кадрів на Qt для KRfb +Name[x-test]=xxQt Framebuffer for KRfbxx +Name[zh_CN]=KRfb 的 Qt 帧缓冲机制 +Name[zh_TW]=Krfb 的 Qt Framebuffer +Type=Service +ServiceTypes=krfb/framebuffer + +X-KDE-Library=krfb_framebuffer_qt +X-KDE-PluginInfo-Name=qt +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://www.kde.org +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/krfb/framebuffers/qt/qtframebuffer.cpp b/krfb/framebuffers/qt/qtframebuffer.cpp new file mode 100644 index 00000000..823b6c8c --- /dev/null +++ b/krfb/framebuffers/qt/qtframebuffer.cpp @@ -0,0 +1,116 @@ +/* This file is part of the KDE project + Copyright (C) 2007 Alessandro Praduroux + + 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. +*/ + +#include "qtframebuffer.h" +#include "qtframebuffer.moc" + +#include +#include +#include +#include + + +const int UPDATE_TIME = 500; + +QtFrameBuffer::QtFrameBuffer(WId id, QObject *parent) + : FrameBuffer(id, parent) +{ + fbImage = QPixmap::grabWindow(win).toImage(); + fb = new char[fbImage.numBytes()]; + t = new QTimer(this); + connect(t, SIGNAL(timeout()), SLOT(updateFrameBuffer())); +} + + +QtFrameBuffer::~QtFrameBuffer() +{ + delete [] fb; + fb = 0; +} + +int QtFrameBuffer::depth() +{ + return fbImage.depth(); +} + +int QtFrameBuffer::height() +{ + return fbImage.height(); +} + +int QtFrameBuffer::width() +{ + return fbImage.width(); +} + +void QtFrameBuffer::getServerFormat(rfbPixelFormat &format) +{ + format.bitsPerPixel = 32; + format.depth = 32; + format.trueColour = true; + + format.bigEndian = false; + format.redShift = 16; + format.greenShift = 8; + format.blueShift = 0; + format.redMax = 0xff; + format.greenMax = 0xff; + format.blueMax = 0xff; +} + +void QtFrameBuffer::updateFrameBuffer() +{ + QImage img = QPixmap::grabWindow(win).toImage(); + QSize imgSize = img.size(); + + + // verify what part of the image need to be marked as changed + // fbImage is the previous version of the image, + // img is the current one + +#if 0 // This is actually slower than updating the whole desktop... + + QImage map(imgSize, QImage::Format_Mono); + map.fill(0); + + for (int x = 0; x < imgSize.width(); x++) { + for (int y = 0; y < imgSize.height(); y++) { + if (img.pixel(x, y) != fbImage.pixel(x, y)) { + map.setPixel(x, y, 1); + } + } + } + + QRegion r(QBitmap::fromImage(map)); + tiles = tiles + r.rects(); + +#else + tiles.append(img.rect()); +#endif + + memcpy(fb, (const char *)img.bits(), img.numBytes()); + fbImage = img; + +} + +int QtFrameBuffer::paddedWidth() +{ + return fbImage.width() * 4; +} + +void QtFrameBuffer::startMonitor() +{ + t->start(UPDATE_TIME); +} + +void QtFrameBuffer::stopMonitor() +{ + t->stop(); +} + diff --git a/krfb/framebuffers/qt/qtframebuffer.h b/krfb/framebuffers/qt/qtframebuffer.h new file mode 100644 index 00000000..ee97ea79 --- /dev/null +++ b/krfb/framebuffers/qt/qtframebuffer.h @@ -0,0 +1,44 @@ +/* This file is part of the KDE project + Copyright (C) 2007 Alessandro Praduroux + + 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. +*/ + +#ifndef KRFB_FRAMEBUFFER_QT_QTFRAMEBUFFER_H +#define KRFB_FRAMEBUFFER_QT_QTFRAMEBUFFER_H + +#include +#include "framebuffer.h" + +class QTimer; +/** + @author Alessandro Praduroux +*/ +class QtFrameBuffer : public FrameBuffer +{ + Q_OBJECT +public: + explicit QtFrameBuffer(WId id, QObject *parent = 0); + + ~QtFrameBuffer(); + + virtual int depth(); + virtual int height(); + virtual int width(); + virtual int paddedWidth(); + virtual void getServerFormat(rfbPixelFormat &format); + virtual void startMonitor(); + virtual void stopMonitor(); + +public Q_SLOTS: + void updateFrameBuffer(); + +private: + QImage fbImage; + QTimer *t; +}; + +#endif diff --git a/krfb/framebuffers/qt/qtframebufferplugin.cpp b/krfb/framebuffers/qt/qtframebufferplugin.cpp new file mode 100644 index 00000000..05711168 --- /dev/null +++ b/krfb/framebuffers/qt/qtframebufferplugin.cpp @@ -0,0 +1,47 @@ +/* This file is part of the KDE project + Copyright (C) 2009 Collabora Ltd + @author George Goldberg + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "qtframebufferplugin.h" + +#include "qtframebuffer.h" + +#include + + +QtFrameBufferPlugin::QtFrameBufferPlugin(QObject *parent, const QVariantList &args) + : FrameBufferPlugin(parent, args) +{ +} + +QtFrameBufferPlugin::~QtFrameBufferPlugin() +{ +} + +FrameBuffer *QtFrameBufferPlugin::frameBuffer(WId id) +{ + return new QtFrameBuffer(id); +} + +K_PLUGIN_FACTORY(factory, registerPlugin();) \ +K_EXPORT_PLUGIN(factory("krfb_framebuffer_qt")) + + +#include "qtframebufferplugin.moc" + diff --git a/krfb/framebuffers/qt/qtframebufferplugin.h b/krfb/framebuffers/qt/qtframebufferplugin.h new file mode 100644 index 00000000..a69e7d97 --- /dev/null +++ b/krfb/framebuffers/qt/qtframebufferplugin.h @@ -0,0 +1,48 @@ +/* This file is part of the KDE project + Copyright (C) 2009 Collabora Ltd + @author George Goldberg + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KRFB_FRAMEBUFFER_QT_QTFRAMEBUFFERPLUGIN_H +#define KRFB_FRAMEBUFFER_QT_QTFRAMEBUFFERPLUGIN_H + +#include "framebufferplugin.h" + +#include + +#include + +class FrameBuffer; + +class QtFrameBufferPlugin : public FrameBufferPlugin +{ + Q_OBJECT + +public: + QtFrameBufferPlugin(QObject *parent, const QVariantList &args); + virtual ~QtFrameBufferPlugin(); + + virtual FrameBuffer *frameBuffer(WId id); + +private: + Q_DISABLE_COPY(QtFrameBufferPlugin) +}; + + +#endif // Header guard + diff --git a/krfb/framebuffers/x11/CMakeLists.txt b/krfb/framebuffers/x11/CMakeLists.txt new file mode 100644 index 00000000..8a46445a --- /dev/null +++ b/krfb/framebuffers/x11/CMakeLists.txt @@ -0,0 +1,31 @@ +include_directories (${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} +) + +set (krfb_framebuffer_x11_SRCS + x11framebuffer.cpp + x11framebufferplugin.cpp +) + +kde4_add_plugin (krfb_framebuffer_x11 + ${krfb_framebuffer_x11_SRCS} +) + +target_link_libraries (krfb_framebuffer_x11 + ${KDE4_KDEUI_LIBS} + ${QT_QTCORE_LIBRARY} + ${QT_QTGUI_LIBRARY} + ${X11_X11_LIB} + ${X11_Xdamage_LIB} + ${X11_Xext_LIB} + krfbprivate +) + +install (TARGETS krfb_framebuffer_x11 + DESTINATION ${PLUGIN_INSTALL_DIR} +) + +install (FILES krfb_framebuffer_x11.desktop + DESTINATION ${SERVICES_INSTALL_DIR} +) + diff --git a/krfb/framebuffers/x11/krfb_framebuffer_x11.desktop b/krfb/framebuffers/x11/krfb_framebuffer_x11.desktop new file mode 100644 index 00000000..c9f56bad --- /dev/null +++ b/krfb/framebuffers/x11/krfb_framebuffer_x11.desktop @@ -0,0 +1,107 @@ +[Desktop Entry] +Encoding=UTF-8 +Comment=X11 XDamage/XShm based Framebuffer for KRfb. +Comment[ast]=Esquema de buffer pa KRfb basáu en XDamage/XShm +Comment[bg]=Основан на X11 XDamage/XShm фреймбуфер за KRfb. +Comment[bs]=X11 XDamage/XShm baziran framebafer za KRfb. +Comment[ca]=«Framebuffer» basat en XDamage/XShmQt de l'X11 per al KRfb. +Comment[ca@valencia]=«Framebuffer» basat en XDamage/XShmQt de l'X11 per al KRfb. +Comment[cs]=Framebuffer založený na X11 XDamage/XShm pro KRfb. +Comment[da]=X11 XDamage/XShm-baseret framebuffer til KRfb. +Comment[de]=X11 XDamage/XShm-basierter Framebuffer für KRfb. +Comment[el]=Μνήμη εξόδου βίντεο καρέ με βάση το X11 XDamage/XShm για το KRfb. +Comment[en_GB]=X11 XDamage/XShm based Framebuffer for KRfb. +Comment[es]=Memoria intermedia de vídeo basada en X11 Damage/XShm para KRfb. +Comment[et]=KRfb X11 XDamage/XShm põhine kaadripuhver +Comment[eu]=X11 XDamage/XShm oinarritutako KRfb-ren irteerako bideoa. +Comment[fi]=X11 XDamage/XShm-perustainen kehyspuskui KRfb:lle. +Comment[fr]=Sortie vidéo fondée sur X11 « XDamage / XShm » pour Krfb. +Comment[ga]=Maolán fráma le haghaidh KRfb, bunaithe ar X11 XDamage/XShm +Comment[gl]=Framebuffer baseado en Xll XDamage/Xshm para XRfb. +Comment[hr]=Međuspreminik okvira baziran na X11 XDamage/XShm za KRfb. +Comment[hu]=X11 XDamage/XShm-alapú framebuffer a Krfb-hez. +Comment[ia]=Framebuffer basate sur X11 XDamage/XShm per KRfb. +Comment[it]=Framebuffer basato su XDamage/XShm di X11 per KRfb. +Comment[kk]=X11 XDamage/XShm негіздеген KRfb кадр буфері. +Comment[km]=X11 XDamage/XShm based Framebuffer សម្រាប់ KRfb ។ +Comment[ko]=KRfb를 위한 X11 XDamage/XShm 기반 프레임버퍼. +Comment[lt]=X11 XDamage/XShm paremtas Framebuffer skirtas KRfb. +Comment[lv]=X11 XDamage/XShm balstīts kadrbuferis priekš KRfb. +Comment[nb]=Rammebuffer for KRfb basert på X11 XDamage/XShm. +Comment[nds]=Op X11-XDamage/-XShm opbuut Bildpuffer för KRfb +Comment[nl]=Op X11 XDamage/XShm gebaseerd framebuffer voor KRfb. +Comment[nn]=X11 XDamage/XShm basert framebuffer for KRfb. +Comment[pl]=Bufor ramki na podstawie X11 XDamage/XShm dla KRfb. +Comment[pt]='Framebuffer' baseado no XDamage/XShm do X11 para o KRfb. +Comment[pt_BR]=Framebuffer baseado no XDamage/XShm do X11 para o KRfb. +Comment[ru]=Буфер экрана для KRfb на базе X11 XDamage/XShm +Comment[si]=KRfb සඳහා වන රාමු බෆරය මත පදනම් වූ X11 XDamage/XShm. +Comment[sk]=Framebuffer založený na X11 XDamage/XShm pre KRfb. +Comment[sl]=Slikovni medpomnilnik za KRFB, ki temelji na X11 XDamage/XShm +Comment[sr]=Кадробафер за КРФБ на основу Икс‑демиџа/Икс‑схма у Иксу11. +Comment[sr@ijekavian]=Кадробафер за КРФБ на основу Икс‑демиџа/Икс‑схма у Иксу11. +Comment[sr@ijekavianlatin]=Kadrobafer za KRFB na osnovu XDamagea/XShma u X11. +Comment[sr@latin]=Kadrobafer za KRFB na osnovu XDamagea/XShma u X11. +Comment[sv]=X11 XDamage/XShm-baserad rambuffert för Krfb. +Comment[tr]=KRfb için X11 XDamage/XShm temelli Çerçeve Tamponu. +Comment[uk]=Заснований на XDamage/XShm X11 буфер кадрів для KRfb. +Comment[x-test]=xxX11 XDamage/XShm based Framebuffer for KRfb.xx +Comment[zh_CN]=基于 X11 XDamage/XShm 扩展的 KRfb 帧缓冲机制。 +Comment[zh_TW]=KRfb 的 X11 XDamage/XShm based Framebuffer +Name=X11 Framebuffer for KRfb +Name[ast]=Buffer de X11 pa KRfb +Name[bg]=X11 фреймбуфер за KRfb +Name[bs]=X11 frame bafer za KRfb +Name[ca]=«Framebuffer» de l'X11 per al KRfb. +Name[ca@valencia]=«Framebuffer» de l'X11 per al KRfb. +Name[cs]=X11 Framebuffer pro KRfb +Name[da]=X11-framebuffer til KRfb +Name[de]=X11-Framebuffer für KRfb +Name[el]=X11 Framebuffer for KRfb +Name[en_GB]=X11 Framebuffer for KRfb +Name[es]=Memoria intermedia de vídeo X11 para KRfb +Name[et]=KRfb X11 kaadripuhver +Name[eu]=KRfb-ren X11-ko irteerako bideoa +Name[fi]=X11-kehyspuskuri KRfb:lle +Name[fr]=Sortie vidéo X11 pour Krfb +Name[ga]=Maolán fráma X11 le haghaidh KRfb +Name[gl]=Framebuffer de X11 para KRfb +Name[hr]=Međuspremnik okvira X11 za KRfb +Name[hu]=X11 framebuffer a Krfb-hez +Name[ia]=Framebuffer X11 per KRfb +Name[it]=Framebuffer X11 per KRfb +Name[kk]=X11 KRfb кадр буфері +Name[km]=X11 Framebuffer សម្រាប់ KRfb +Name[ko]=KRfb를 위한 X11 프레임버퍼 +Name[lt]=X11 Framebuffer skirtas KRfb +Name[lv]=X11 kadrbuferis priekš KRfb +Name[nb]=X11 rammebuffer for KRfb +Name[nds]=X11-Bildpuffer för KRfb +Name[nl]=X11 framebuffer voor KRfb +Name[nn]=X11-framebuffer for KRfb +Name[pl]=Bufor ramki X11 dla KRfb +Name[pt]='Framebuffer' do X11 para o KRfb +Name[pt_BR]=Framebuffer do X11 para o KRfb +Name[ru]=Буфер экрана X11 для KRfb +Name[si]=KRfb සඳහා X11 රාමු බෆරය +Name[sk]=X11 Framebuffer pre KRfb +Name[sl]=Slikovni medpomnilnik X11 za KRFB +Name[sr]=Икс11 кадробафер за КРФБ. +Name[sr@ijekavian]=Икс11 кадробафер за КРФБ. +Name[sr@ijekavianlatin]=X11 kadrobafer za KRFB. +Name[sr@latin]=X11 kadrobafer za KRFB. +Name[sv]=X11-rambuffert för Krfb +Name[tr]=KRfb için X11 Çerçeve Tamponu +Name[uk]=Буфер кадрів X11 для KRfb +Name[x-test]=xxX11 Framebuffer for KRfbxx +Name[zh_CN]=KRfb 的 X11 帧缓冲机制 +Name[zh_TW]=KRfb 的 X11 Framebuffer +Type=Service +ServiceTypes=krfb/framebuffer + +X-KDE-Library=krfb_framebuffer_x11 +X-KDE-PluginInfo-Name=x11 +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://www.kde.org +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/krfb/framebuffers/x11/x11framebuffer.cpp b/krfb/framebuffers/x11/x11framebuffer.cpp new file mode 100644 index 00000000..517d4eb8 --- /dev/null +++ b/krfb/framebuffers/x11/x11framebuffer.cpp @@ -0,0 +1,388 @@ +/* This file is part of the KDE project + Copyright (C) 2007 Alessandro Praduroux + + 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. +*/ + +#include "x11framebuffer.h" +#include "x11framebuffer.moc" + +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#ifdef HAVE_XDAMAGE +#include +#endif + +#ifdef HAVE_XSHM +#include +#include +#include +#endif + +class X11FrameBuffer::P +{ + +public: +#ifdef HAVE_XDAMAGE + Damage damage; +#endif +#ifdef HAVE_XSHM + XShmSegmentInfo shminfo; +#endif + + XImage *framebufferImage; + XImage *updateTile; + EvWidget *ev; + bool useShm; + int xdamageBaseEvent; + bool running; +}; + +X11FrameBuffer::X11FrameBuffer(WId id, QObject *parent) + : FrameBuffer(id, parent), d(new X11FrameBuffer::P) +{ +#ifdef HAVE_XSHM + d->useShm = XShmQueryExtension(QX11Info::display()); + kDebug() << "shm: " << d->useShm; +#else + d->useShm = false; +#endif + d->running = false; + d->framebufferImage = XGetImage(QX11Info::display(), + id, + 0, + 0, + QApplication::desktop()->width(), //arg, must get a widget ??? + QApplication::desktop()->height(), + AllPlanes, + ZPixmap); + + if (d->useShm) { +#ifdef HAVE_XSHM + d->updateTile = XShmCreateImage(QX11Info::display(), + DefaultVisual(QX11Info::display(), 0), + d->framebufferImage->bits_per_pixel, + ZPixmap, + NULL, + &d->shminfo, + 32, + 32); + d->shminfo.shmid = shmget(IPC_PRIVATE, + d->updateTile->bytes_per_line * d->updateTile->height, + IPC_CREAT | 0777); + + d->shminfo.shmaddr = d->updateTile->data = (char *) + shmat(d->shminfo.shmid, 0, 0); + d->shminfo.readOnly = False; + + XShmAttach(QX11Info::display(), &d->shminfo); +#endif + } else { + ; + } + + kDebug() << "Got image. bpp: " << d->framebufferImage->bits_per_pixel + << ", depth: " << d->framebufferImage->depth + << ", padded width: " << d->framebufferImage->bytes_per_line + << " (sent: " << d->framebufferImage->width * 4 << ")" + << endl; + + fb = d->framebufferImage->data; +#ifdef HAVE_XDAMAGE + d->ev = new EvWidget(this); + kapp->installX11EventFilter(d->ev); +#endif +} + + +X11FrameBuffer::~X11FrameBuffer() +{ + XDestroyImage(d->framebufferImage); +#ifdef HAVE_XDAMAGE + kapp->removeX11EventFilter(d->ev); +#endif +#ifdef HAVE_XSHM + XShmDetach(QX11Info::display(), &d->shminfo); + XDestroyImage(d->updateTile); + shmdt(d->shminfo.shmaddr); + shmctl(d->shminfo.shmid, IPC_RMID, 0); +#endif + delete d; + fb = 0; // already deleted by XDestroyImage +} + + +int X11FrameBuffer::depth() +{ + return d->framebufferImage->depth; +} + +int X11FrameBuffer::height() +{ + return d->framebufferImage->height; +} + +int X11FrameBuffer::width() +{ + return d->framebufferImage->width; +} + +int X11FrameBuffer::paddedWidth() +{ + return d->framebufferImage->bytes_per_line; +} + +void X11FrameBuffer::getServerFormat(rfbPixelFormat &format) +{ + format.bitsPerPixel = d->framebufferImage->bits_per_pixel; + format.depth = d->framebufferImage->depth; + format.trueColour = true; + format.bigEndian = ((d->framebufferImage->bitmap_bit_order == MSBFirst) ? true : false); + + if (format.bitsPerPixel == 8) { + format.redShift = 0; + format.greenShift = 3; + format.blueShift = 6; + format.redMax = 7; + format.greenMax = 7; + format.blueMax = 3; + } else { + format.redShift = 0; + + if (d->framebufferImage->red_mask) + while (!(d->framebufferImage->red_mask & (1 << format.redShift))) { + format.redShift++; + } + + format.greenShift = 0; + + if (d->framebufferImage->green_mask) + while (!(d->framebufferImage->green_mask & (1 << format.greenShift))) { + format.greenShift++; + } + + format.blueShift = 0; + + if (d->framebufferImage->blue_mask) + while (!(d->framebufferImage->blue_mask & (1 << format.blueShift))) { + format.blueShift++; + } + + format.redMax = d->framebufferImage->red_mask >> format.redShift; + format.greenMax = d->framebufferImage->green_mask >> format.greenShift; + format.blueMax = d->framebufferImage->blue_mask >> format.blueShift; + } +} + +void X11FrameBuffer::handleXDamage(XEvent *event) +{ +#ifdef HAVE_XDAMAGE + XDamageNotifyEvent *dev = (XDamageNotifyEvent *)event; + QRect r(dev->area.x, dev->area.y, dev->area.width, dev->area.height); + tiles.append(r); + + /*if (!dev->more) { + XDamageSubtract(QX11Info::display(),d->damage, None, None); + }*/ +#endif +} + + +void X11FrameBuffer::cleanupRects() +{ + + QList cpy = tiles; + bool inserted = false; + tiles.clear(); +// kDebug() << "before cleanup: " << cpy.size(); + foreach(const QRect & r, cpy) { + if (tiles.size() > 0) { + for (int i = 0; i < tiles.size(); i++) { + // kDebug() << r << tiles[i]; + if (r.intersects(tiles[i])) { + tiles[i] |= r; + inserted = true; + break; + // kDebug() << "merged into " << tiles[i]; + } + } + + if (!inserted) { + tiles.append(r); + // kDebug() << "appended " << r; + } + } else { + // kDebug() << "appended " << r; + tiles.append(r); + } + } + + for (int i = 0; i < tiles.size(); i++) { + tiles[i].adjust(-30, -30, 30, 30); + + if (tiles[i].top() < 0) { + tiles[i].setTop(0); + } + + if (tiles[i].left() < 0) { + tiles[i].setLeft(0); + } + + if (tiles[i].bottom() > d->framebufferImage->height) { + tiles[i].setBottom(d->framebufferImage->height); + } + + if (tiles[i].right() > d->framebufferImage->width) { + tiles[i].setRight(d->framebufferImage->width); + } + } + +// kDebug() << "after cleanup: " << tiles.size(); +} + +void X11FrameBuffer::acquireEvents() +{ + + XEvent ev; + + while (XCheckTypedEvent(QX11Info::display(), d->xdamageBaseEvent + XDamageNotify, &ev)) { + handleXDamage(&ev); + } + + XDamageSubtract(QX11Info::display(), d->damage, None, None); +} + +QList< QRect > X11FrameBuffer::modifiedTiles() +{ + QList ret; + + if (!d->running) { + return ret; + } + + kapp->processEvents(); // try to make sure every damage event goes trough; + cleanupRects(); + QRect gl; + + //d->useShm = false; + if (tiles.size() > 0) { + if (d->useShm) { +#ifdef HAVE_XSHM + + foreach(const QRect & r, tiles) { +// kDebug() << r; + gl |= r; + int y = r.y(); + int x = r.x(); + + while (x < r.right()) { + while (y < r.bottom()) { + if (y + d->updateTile->height > d->framebufferImage->height) { + y = d->framebufferImage->height - d->updateTile->height; + } + + if (x + d->updateTile->width > d->framebufferImage->width) { + x = d->framebufferImage->width - d->updateTile->width; + } + +// kDebug() << "x: " << x << " (" << r.x() << ") y: " << y << " (" << r.y() << ") " << r; + XShmGetImage(QX11Info::display(), win, d->updateTile, x, y, AllPlanes); + int pxsize = d->framebufferImage->bits_per_pixel / 8; + char *dest = fb + ((d->framebufferImage->bytes_per_line * y) + (x * pxsize)); + char *src = d->updateTile->data; + + for (int i = 0; i < d->updateTile->height; i++) { + memcpy(dest, src, d->updateTile->bytes_per_line); + dest += d->framebufferImage->bytes_per_line; + src += d->updateTile->bytes_per_line; + } + + y += d->updateTile->height; + } + + x += d->updateTile->width; + y = r.y(); + } + } +#endif + } else { + foreach(const QRect & r, tiles) { + XGetSubImage(QX11Info::display(), + win, + r.left(), + r.top(), + r.width(), + r.height(), + AllPlanes, + ZPixmap, + d->framebufferImage, + r.left(), + r.top() + ); + } + } + } + +// kDebug() << "tot: " << gl; +// kDebug() << tiles.size(); + ret = tiles; + tiles.clear(); + return ret; +} + +void X11FrameBuffer::startMonitor() +{ + d->running = true; +#ifdef HAVE_XDAMAGE + d->damage = XDamageCreate(QX11Info::display(), win, XDamageReportRawRectangles); + XDamageSubtract(QX11Info::display(), d->damage, None, None); +#endif +} + +void X11FrameBuffer::stopMonitor() +{ + d->running = false; +#ifdef HAVE_XDAMAGE + XDamageDestroy(QX11Info::display(), d->damage); +#endif +} + + + +EvWidget::EvWidget(X11FrameBuffer *x11fb) + : QWidget(0), fb(x11fb) +{ +#ifdef HAVE_XDAMAGE + int er; + XDamageQueryExtension(QX11Info::display(), &xdamageBaseEvent, &er); +#endif +} + +bool EvWidget::x11Event(XEvent *event) +{ +#ifdef HAVE_XDAMAGE + + if (event->type == xdamageBaseEvent + XDamageNotify) { + fb->handleXDamage(event); + return true; + } + +#endif + return false; +} + + + diff --git a/krfb/framebuffers/x11/x11framebuffer.h b/krfb/framebuffers/x11/x11framebuffer.h new file mode 100644 index 00000000..7b70e1ef --- /dev/null +++ b/krfb/framebuffers/x11/x11framebuffer.h @@ -0,0 +1,62 @@ +/* This file is part of the KDE project + Copyright (C) 2007 Alessandro Praduroux + + 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. +*/ +#ifndef KRFB_FRAMEBUFFER_X11_X11FRAMEBUFFER_H +#define KRFB_FRAMEBUFFER_X11_X11FRAMEBUFFER_H + +#include +#include + +class X11FrameBuffer; + +class EvWidget: public QWidget +{ + Q_OBJECT + +public: + EvWidget(X11FrameBuffer *x11fb); + +protected: + bool x11Event(XEvent *event); + +private: + X11FrameBuffer *fb; + int xdamageBaseEvent; +}; + +/** + @author Alessandro Praduroux +*/ +class X11FrameBuffer : public FrameBuffer +{ + Q_OBJECT +public: + X11FrameBuffer(WId id, QObject *parent = 0); + + ~X11FrameBuffer(); + + virtual QList modifiedTiles(); + virtual int depth(); + virtual int height(); + virtual int width(); + virtual int paddedWidth(); + virtual void getServerFormat(rfbPixelFormat &format); + virtual void startMonitor(); + virtual void stopMonitor(); + + + void handleXDamage(XEvent *event); +private: + void cleanupRects(); + void acquireEvents(); + + class P; + P *const d; +}; + +#endif diff --git a/krfb/framebuffers/x11/x11framebufferplugin.cpp b/krfb/framebuffers/x11/x11framebufferplugin.cpp new file mode 100644 index 00000000..6b298ac6 --- /dev/null +++ b/krfb/framebuffers/x11/x11framebufferplugin.cpp @@ -0,0 +1,47 @@ +/* This file is part of the KDE project + Copyright (C) 2009 Collabora Ltd + @author George Goldberg + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "x11framebufferplugin.h" + +#include "x11framebuffer.h" + +#include + + +X11FrameBufferPlugin::X11FrameBufferPlugin(QObject *parent, const QVariantList &args) + : FrameBufferPlugin(parent, args) +{ +} + +X11FrameBufferPlugin::~X11FrameBufferPlugin() +{ +} + +FrameBuffer *X11FrameBufferPlugin::frameBuffer(WId id) +{ + return new X11FrameBuffer(id); +} + +K_PLUGIN_FACTORY(factory, registerPlugin();) \ +K_EXPORT_PLUGIN(factory("krfb_framebuffer_x11")) + + +#include "x11framebufferplugin.moc" + diff --git a/krfb/framebuffers/x11/x11framebufferplugin.h b/krfb/framebuffers/x11/x11framebufferplugin.h new file mode 100644 index 00000000..01b72e8f --- /dev/null +++ b/krfb/framebuffers/x11/x11framebufferplugin.h @@ -0,0 +1,48 @@ +/* This file is part of the KDE project + Copyright (C) 2009 Collabora Ltd + @author George Goldberg + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KRFB_FRAMEBUFFER_X11_X11FRAMEBUFFERPLUGIN_H +#define KRFB_FRAMEBUFFER_X11_X11FRAMEBUFFERPLUGIN_H + +#include "framebufferplugin.h" + +#include + +#include + +class FrameBuffer; + +class X11FrameBufferPlugin : public FrameBufferPlugin +{ + Q_OBJECT + +public: + X11FrameBufferPlugin(QObject *parent, const QVariantList &args); + virtual ~X11FrameBufferPlugin(); + + virtual FrameBuffer *frameBuffer(WId id); + +private: + Q_DISABLE_COPY(X11FrameBufferPlugin) +}; + + +#endif // Header guard + diff --git a/krfb/krfb/CMakeLists.txt b/krfb/krfb/CMakeLists.txt new file mode 100644 index 00000000..100b49b6 --- /dev/null +++ b/krfb/krfb/CMakeLists.txt @@ -0,0 +1,152 @@ +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/config-krfb.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/config-krfb.h +) + +##################################### +# First target: libkrfbprivate - a library +# for linking plugins against. + +set (krfbprivate_SRCS + framebuffer.cpp + framebufferplugin.cpp +) + +kde4_add_library (krfbprivate + SHARED + ${krfbprivate_SRCS} +) + +target_link_libraries (krfbprivate + ${QT_QTCORE_LIBRARY} + ${QT_QTGUI_LIBRARY} + ${X11_X11_LIB} + ${LIBVNCSERVER_LIBRARIES} +) + +set_target_properties (krfbprivate PROPERTIES + VERSION ${GENERIC_LIB_VERSION} + SOVERSION ${GENERIC_LIB_VERSION} +) + +install (TARGETS krfbprivate + ${INSTALL_TARGETS_DEFAULT_ARGS} + LIBRARY NAMELINK_SKIP +) + +install (FILES + krfb-framebuffer.desktop + DESTINATION ${SERVICETYPES_INSTALL_DIR} +) + +##################################### +# Second target: krfb - the app +# itself. + +if(TelepathyQt4_FOUND) + add_definitions(-DKRFB_WITH_TELEPATHY_TUBES) + include_directories(${TELEPATHY_QT4_INCLUDE_DIR}) +endif() + +if(KTP_FOUND) + add_definitions(-DKRFB_WITH_KDE_TELEPATHY) + include_directories(${KTP_INCLUDE_DIR}) +endif() + +set (krfb_SRCS + connectiondialog.cpp + events.cpp + framebuffermanager.cpp + main.cpp + mainwindow.cpp + sockethelpers.cpp + trayicon.cpp + rfbservermanager.cpp + rfbserver.cpp + rfbclient.cpp + invitationsrfbserver.cpp + invitationsrfbclient.cpp +) + +if(TelepathyQt4_FOUND) + set (krfb_SRCS + ${krfb_SRCS} + tubesrfbserver.cpp + tubesrfbclient.cpp + ) +endif() + +kde4_add_kcfg_files (krfb_SRCS + krfbconfig.kcfgc +) + +kde4_add_ui_files (krfb_SRCS + ui/configtcp.ui + ui/configsecurity.ui + ui/connectionwidget.ui + ui/mainwidget.ui +) + +if(TelepathyQt4_FOUND) + kde4_add_ui_files(krfb_SRCS ui/tubesconnectionwidget.ui) +endif() + +kde4_add_executable (krfb + ${krfb_SRCS} +) + +target_link_libraries (krfb + krfbprivate + vncserver + ${JPEG_LIBRARIES} + ${X11_Xext_LIB} + ${X11_X11_LIB} + ${X11_Xdamage_LIB} + ${QT_QTNETWORK_LIBRARY} + ${KDE4_KDNSSD_LIBS} + ${KDE4_KDEUI_LIBS} + ${LIBVNCSERVER_LIBRARIES} +) + +if(TelepathyQt4_FOUND) + target_link_libraries(krfb + ${TELEPATHY_QT4_LIBRARIES} + ) +endif() + +if(KTP_FOUND) + target_link_libraries(krfb + ${KTP_LIBRARIES} + ${KTP_MODELS_LIBRARIES} + ${KTP_WIDGETS_LIBRARIES} + ) +endif() + +if (X11_XTest_FOUND) + target_link_libraries (krfb + ${X11_XTest_LIB} + ) +endif (X11_XTest_FOUND) + +install (TARGETS krfb + ${INSTALL_TARGETS_DEFAULT_ARGS} +) + +if(TelepathyQt4_FOUND) + configure_file(org.freedesktop.Telepathy.Client.krfb_rfb_handler.service.in + org.freedesktop.Telepathy.Client.krfb_rfb_handler.service) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.Telepathy.Client.krfb_rfb_handler.service + DESTINATION ${DBUS_SERVICES_INSTALL_DIR}) + + install(FILES krfb_rfb_handler.client DESTINATION ${CMAKE_INSTALL_PREFIX}/share/telepathy/clients/) +endif() + +########### install files ############### + +install (PROGRAMS krfb.desktop + DESTINATION ${XDG_APPS_INSTALL_DIR} +) + +install (FILES krfb.notifyrc + DESTINATION ${DATA_INSTALL_DIR}/krfb +) + diff --git a/krfb/krfb/Messages.sh b/krfb/krfb/Messages.sh new file mode 100644 index 00000000..ce9a4562 --- /dev/null +++ b/krfb/krfb/Messages.sh @@ -0,0 +1,3 @@ +#! /bin/sh +$EXTRACTRC ui/*.ui *.kcfg >> rc.cpp +$XGETTEXT *.cpp -o $podir/krfb.pot diff --git a/krfb/krfb/config-krfb.h.cmake b/krfb/krfb/config-krfb.h.cmake new file mode 100644 index 00000000..38d479c6 --- /dev/null +++ b/krfb/krfb/config-krfb.h.cmake @@ -0,0 +1,11 @@ +/* Define to 1 if you have the `getifaddrs' function. */ +#cmakedefine HAVE_GETIFADDRS 1 + +/* Define if SLP is available */ +#cmakedefine HAVE_SLP 1 + +/* Define if XDamage is available */ +#cmakedefine HAVE_XDAMAGE 1 + +/* Define if XShm is available */ +#cmakedefine HAVE_XSHM 1 diff --git a/krfb/krfb/connectiondialog.cpp b/krfb/krfb/connectiondialog.cpp new file mode 100644 index 00000000..5975a8c2 --- /dev/null +++ b/krfb/krfb/connectiondialog.cpp @@ -0,0 +1,88 @@ +/* This file is part of the KDE project + Copyright (C) 2010 Collabora Ltd + @author George Kiagiadakis + Copyright (C) 2004 Nadeem Hasan + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "connectiondialog.h" + +#include +#include +#include + +#include +#include + +template +ConnectionDialog::ConnectionDialog(QWidget *parent) + : KDialog(parent) +{ + setCaption(i18n("New Connection")); + setButtons(Ok | Cancel); + setDefaultButton(Cancel); + setModal(true); + + setMinimumSize(500, 200); + + m_connectWidget = new QWidget(this); + m_ui.setupUi(m_connectWidget); + + m_ui.pixmapLabel->setPixmap(KIcon("krfb").pixmap(128)); + + KGuiItem accept = KStandardGuiItem::ok(); + accept.setText(i18n("Accept Connection")); + setButtonGuiItem(Ok, accept); + + KGuiItem refuse = KStandardGuiItem::cancel(); + refuse.setText(i18n("Refuse Connection")); + setButtonGuiItem(Cancel, refuse); + + setMainWidget(m_connectWidget); +} + +//********** + +InvitationsConnectionDialog::InvitationsConnectionDialog(QWidget *parent) + : ConnectionDialog(parent) +{ +} + +void InvitationsConnectionDialog::setRemoteHost(const QString &host) +{ + m_ui.remoteHost->setText(host); +} + +//********** + +#ifdef KRFB_WITH_TELEPATHY_TUBES + +TubesConnectionDialog::TubesConnectionDialog(QWidget *parent) + : ConnectionDialog(parent) +{ +} + +void TubesConnectionDialog::setContactName(const QString & name) +{ + QString txt = i18n("You have requested to share your desktop with %1. If you proceed, " + "you will allow the remote user to watch your desktop.", name); + m_ui.mainTextLabel->setText(txt); +} + +#endif // KRFB_WITH_TELEPATHY_TUBES + +#include "connectiondialog.moc" diff --git a/krfb/krfb/connectiondialog.h b/krfb/krfb/connectiondialog.h new file mode 100644 index 00000000..f29b7bcc --- /dev/null +++ b/krfb/krfb/connectiondialog.h @@ -0,0 +1,82 @@ +/* This file is part of the KDE project + Copyright (C) 2010 Collabora Ltd + @author George Kiagiadakis + Copyright (C) 2004 Nadeem Hasan + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef CONNECTIONDIALOG_H +#define CONNECTIONDIALOG_H + +#include "ui_connectionwidget.h" +#include + +template +class ConnectionDialog : public KDialog +{ +public: + ConnectionDialog(QWidget *parent); + ~ConnectionDialog() {}; + + void setAllowRemoteControl(bool b); + bool allowRemoteControl(); + +protected: + QWidget *m_connectWidget; + UI m_ui; +}; + +template +void ConnectionDialog::setAllowRemoteControl(bool b) +{ + m_ui.cbAllowRemoteControl->setChecked(b); + m_ui.cbAllowRemoteControl->setVisible(b); +} + +template +bool ConnectionDialog::allowRemoteControl() +{ + return m_ui.cbAllowRemoteControl->isChecked(); +} + +//********* + +class InvitationsConnectionDialog : public ConnectionDialog +{ + Q_OBJECT +public: + InvitationsConnectionDialog(QWidget *parent); + void setRemoteHost(const QString & host); +}; + +//********* + +#ifdef KRFB_WITH_TELEPATHY_TUBES +# include "ui_tubesconnectionwidget.h" + +class TubesConnectionDialog : public ConnectionDialog +{ + Q_OBJECT +public: + TubesConnectionDialog(QWidget *parent); + void setContactName(const QString & name); +}; + +#endif // KRFB_WITH_TELEPATHY_TUBES + +#endif // CONNECTIONDIALOG_H + diff --git a/krfb/krfb/events.cpp b/krfb/krfb/events.cpp new file mode 100644 index 00000000..3d9e8d27 --- /dev/null +++ b/krfb/krfb/events.cpp @@ -0,0 +1,200 @@ +/* + This file is part of the KDE project + + Copyright (C) 2010 Collabora Ltd. + @author George Kiagiadakis + Copyright (C) 2007 Alessandro Praduroux + Copyright (C) 2001-2003 by Tim Jansen + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "events.h" + +#include +#include +#include +#include + +#include +#include +#include + +enum { + LEFTSHIFT = 1, + RIGHTSHIFT = 2, + ALTGR = 4 +}; + +class EventData +{ +public: + EventData(); + + //keyboard + Display *dpy; + signed char modifiers[0x100]; + KeyCode keycodes[0x100]; + KeyCode leftShiftCode; + KeyCode rightShiftCode; + KeyCode altGrCode; + char modifierState; + + //mouse + int buttonMask; + +private: + void init(); +}; + +K_GLOBAL_STATIC(EventData, data) + +EventData::EventData() +{ + init(); +} + +void EventData::init() +{ + dpy = QX11Info::display(); + buttonMask = 0; + + //initialize keycodes + KeySym key, *keymap; + int i, j, minkey, maxkey, syms_per_keycode; + + memset(modifiers, -1, sizeof(modifiers)); + + XDisplayKeycodes(dpy, &minkey, &maxkey); + Q_ASSERT(minkey >= 8); + Q_ASSERT(maxkey < 256); + keymap = (KeySym *) XGetKeyboardMapping(dpy, minkey, + (maxkey - minkey + 1), + &syms_per_keycode); + Q_ASSERT(keymap); + + for (i = minkey; i <= maxkey; i++) { + for (j = 0; j < syms_per_keycode; j++) { + key = keymap[(i-minkey)*syms_per_keycode+j]; + + if (key >= ' ' && key < 0x100 && i == XKeysymToKeycode(dpy, key)) { + keycodes[key] = i; + modifiers[key] = j; + } + } + } + + leftShiftCode = XKeysymToKeycode(dpy, XK_Shift_L); + rightShiftCode = XKeysymToKeycode(dpy, XK_Shift_R); + altGrCode = XKeysymToKeycode(dpy, XK_Mode_switch); + + XFree((char *)keymap); +} + +/* this function adjusts the modifiers according to mod (as from modifiers) and data->modifierState */ +static void tweakModifiers(signed char mod, bool down) +{ + bool isShift = data->modifierState & (LEFTSHIFT | RIGHTSHIFT); + + if (mod < 0) { + return; + } + + if (isShift && mod != 1) { + if (data->modifierState & LEFTSHIFT) { + XTestFakeKeyEvent(data->dpy, data->leftShiftCode, + down, CurrentTime); + } + + if (data->modifierState & RIGHTSHIFT) { + XTestFakeKeyEvent(data->dpy, data->rightShiftCode, + down, CurrentTime); + } + } + + if (!isShift && mod == 1) { + XTestFakeKeyEvent(data->dpy, data->leftShiftCode, + down, CurrentTime); + } + + if ((data->modifierState & ALTGR) && mod != 2) { + XTestFakeKeyEvent(data->dpy, data->altGrCode, + !down, CurrentTime); + } + + if (!(data->modifierState & ALTGR) && mod == 2) { + XTestFakeKeyEvent(data->dpy, data->altGrCode, + down, CurrentTime); + } +} + +void EventHandler::handleKeyboard(bool down, rfbKeySym keySym) +{ +#define ADJUSTMOD(sym,state) \ + if(keySym==sym) { if(down) data->modifierState|=state; else data->modifierState&=~state; } + + ADJUSTMOD(XK_Shift_L, LEFTSHIFT); + ADJUSTMOD(XK_Shift_R, RIGHTSHIFT); + ADJUSTMOD(XK_Mode_switch, ALTGR); + + if (keySym >= ' ' && keySym < 0x100) { + KeyCode k; + + if (down) { + tweakModifiers(data->modifiers[keySym], True); + } + + k = data->keycodes[keySym]; + + if (k != NoSymbol) { + XTestFakeKeyEvent(data->dpy, k, down, CurrentTime); + } + + if (down) { + tweakModifiers(data->modifiers[keySym], False); + } + } else { + KeyCode k = XKeysymToKeycode(data->dpy, keySym); + + if (k != NoSymbol) { + XTestFakeKeyEvent(data->dpy, k, down, CurrentTime); + } + } +} + +void EventHandler::handlePointer(int buttonMask, int x, int y) +{ + QDesktopWidget *desktopWidget = QApplication::desktop(); + + int screen = desktopWidget->screenNumber(); + + if (screen < 0) { + screen = 0; + } + + XTestFakeMotionEvent(data->dpy, screen, x, y, CurrentTime); + + for (int i = 0; i < 5; i++) { + if ((data->buttonMask&(1 << i)) != (buttonMask&(1 << i))) { + XTestFakeButtonEvent(data->dpy, + i + 1, + (buttonMask&(1 << i)) ? True : False, + CurrentTime); + } + } + + data->buttonMask = buttonMask; +} diff --git a/krfb/krfb/events.h b/krfb/krfb/events.h new file mode 100644 index 00000000..ac5a230e --- /dev/null +++ b/krfb/krfb/events.h @@ -0,0 +1,37 @@ +/* + This file is part of the KDE project + + Copyright (C) 2010 Collabora Ltd. + @author George Kiagiadakis + Copyright (C) 2007 Alessandro Praduroux + Copyright (C) 2001-2003 by Tim Jansen + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef EVENTS_H +#define EVENTS_H + +#include "rfb.h" + +class EventHandler +{ +public: + static void handleKeyboard(bool down, rfbKeySym key); + static void handlePointer(int buttonMask, int x, int y); +}; + +#endif diff --git a/krfb/krfb/framebuffer.cpp b/krfb/krfb/framebuffer.cpp new file mode 100644 index 00000000..75b2eaae --- /dev/null +++ b/krfb/krfb/framebuffer.cpp @@ -0,0 +1,73 @@ +/* This file is part of the KDE project + Copyright (C) 2007 Alessandro Praduroux + + 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. +*/ + +#include "framebuffer.h" + +#include "config-krfb.h" + +#include + + +FrameBuffer::FrameBuffer(WId id, QObject *parent) + : QObject(parent), win(id) +{ +} + +FrameBuffer::~FrameBuffer() +{ + delete fb; +} + +char *FrameBuffer::data() +{ + return fb; +} + +QList< QRect > FrameBuffer::modifiedTiles() +{ + QList ret = tiles; + tiles.clear(); + return ret; +} + +int FrameBuffer::width() +{ + return 0; +} + +int FrameBuffer::height() +{ + return 0; +} + +void FrameBuffer::getServerFormat(rfbPixelFormat &) +{ +} + +int FrameBuffer::depth() +{ + return 32; +} + +int FrameBuffer::paddedWidth() +{ + return width() * depth() / 8; +} + +void FrameBuffer::startMonitor() +{ +} + +void FrameBuffer::stopMonitor() +{ +} + + +#include "framebuffer.moc" + diff --git a/krfb/krfb/framebuffer.h b/krfb/krfb/framebuffer.h new file mode 100644 index 00000000..db8fe399 --- /dev/null +++ b/krfb/krfb/framebuffer.h @@ -0,0 +1,57 @@ +/* This file is part of the KDE project + Copyright (C) 2007 Alessandro Praduroux + + 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. +*/ + +#ifndef FRAMEBUFFER_H +#define FRAMEBUFFER_H + +#include "rfb.h" + +#include + +#include +#include +#include + +#include + +class FrameBuffer; +/** + @author Alessandro Praduroux +*/ +class KDE_EXPORT FrameBuffer : public QObject +{ + Q_OBJECT +public: + explicit FrameBuffer(WId id, QObject *parent = 0); + + virtual ~FrameBuffer(); + + char *data(); + + virtual QList modifiedTiles(); + virtual int paddedWidth(); + virtual int width(); + virtual int height(); + virtual int depth(); + virtual void startMonitor(); + virtual void stopMonitor(); + + virtual void getServerFormat(rfbPixelFormat &format); + +protected: + WId win; + char *fb; + QList tiles; + +private: + Q_DISABLE_COPY(FrameBuffer) + +}; + +#endif diff --git a/krfb/krfb/framebuffermanager.cpp b/krfb/krfb/framebuffermanager.cpp new file mode 100644 index 00000000..7527532f --- /dev/null +++ b/krfb/krfb/framebuffermanager.cpp @@ -0,0 +1,134 @@ +/* This file is part of the KDE project + Copyright (C) 2009 Collabora Ltd + @author George Goldberg + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "framebuffermanager.h" + +#include "framebufferplugin.h" +#include "krfbconfig.h" + +#include +#include +#include + +#include + +class FrameBufferManagerStatic +{ +public: + FrameBufferManager instance; +}; + +K_GLOBAL_STATIC(FrameBufferManagerStatic, frameBufferManagerStatic) + +FrameBufferManager::FrameBufferManager() +{ + kDebug(); + + loadPlugins(); +} + +FrameBufferManager::~FrameBufferManager() +{ + kDebug(); +} + +FrameBufferManager *FrameBufferManager::instance() +{ + kDebug(); + + return &frameBufferManagerStatic->instance; +} + +void FrameBufferManager::loadPlugins() +{ + kDebug(); + + // Load the all the plugin factories here, for use later. + KService::List offers = KServiceTypeTrader::self()->query("krfb/framebuffer"); + + KService::List::const_iterator iter; + + for (iter = offers.constBegin(); iter < offers.constEnd(); ++iter) { + QString error; + KService::Ptr service = *iter; + + KPluginFactory *factory = KPluginLoader(service->library()).factory(); + + if (!factory) { + kWarning() << "KPluginFactory could not load the plugin:" << service->library(); + continue; + } + + FrameBufferPlugin *plugin = factory->create(this); + + if (plugin) { + kDebug() << "Loaded plugin:" << service->name(); + m_plugins.insert(service->library(), plugin); + } else { + kDebug() << error; + } + } +} + +QSharedPointer FrameBufferManager::frameBuffer(WId id) +{ + kDebug(); + + // See if there is still an existing framebuffer to this WId. + if (m_frameBuffers.contains(id)) { + QWeakPointer weakFrameBuffer = m_frameBuffers.value(id); + + if (weakFrameBuffer) { + kDebug() << "Found cached frame buffer."; + return weakFrameBuffer.toStrongRef(); + } else { + kDebug() << "Found deleted cached frame buffer. Don't use."; + m_frameBuffers.remove(id); + } + } + + // We don't already have that frame buffer. + QMap::const_iterator iter = m_plugins.constBegin(); + + while (iter != m_plugins.constEnd()) { + + if (iter.key() == KrfbConfig::preferredFrameBufferPlugin()) { + kDebug() << "Using FrameBuffer:" << KrfbConfig::preferredFrameBufferPlugin(); + + QSharedPointer frameBuffer(iter.value()->frameBuffer(id)); + + if (frameBuffer) { + m_frameBuffers.insert(id, frameBuffer.toWeakRef()); + + return frameBuffer; + } + } + + ++iter; + } + + // No valid framebuffer plugin found. + kDebug() << "No valid framebuffer found. returning null."; + return QSharedPointer(); +} + + +#include "framebuffermanager.moc" + diff --git a/krfb/krfb/framebuffermanager.h b/krfb/krfb/framebuffermanager.h new file mode 100644 index 00000000..d018c6aa --- /dev/null +++ b/krfb/krfb/framebuffermanager.h @@ -0,0 +1,63 @@ +/* This file is part of the KDE project + Copyright (C) 2009 Collabora Ltd + @author George Goldberg + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KRFB_FRAMEBUFFERMANAGER_H +#define KRFB_FRAMEBUFFERMANAGER_H + +#include "framebuffer.h" + +#include + +#include +#include +#include +#include + +#include + +class FrameBufferPlugin; +class KPluginFactory; + +class KDE_EXPORT FrameBufferManager : public QObject +{ + Q_OBJECT + friend class FrameBufferManagerStatic; + +public: + static FrameBufferManager *instance(); + + virtual ~FrameBufferManager(); + + QSharedPointer frameBuffer(WId id); + +private: + Q_DISABLE_COPY(FrameBufferManager) + + FrameBufferManager(); + + void loadPlugins(); + + QMap m_plugins; + QMap > m_frameBuffers; +}; + + +#endif // Header guard + diff --git a/krfb/krfb/framebufferplugin.cpp b/krfb/krfb/framebufferplugin.cpp new file mode 100644 index 00000000..8312a487 --- /dev/null +++ b/krfb/krfb/framebufferplugin.cpp @@ -0,0 +1,36 @@ +/* This file is part of the KDE project + Copyright (C) 2009 Collabora Ltd + @author George Goldberg + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "framebufferplugin.h" + +#include "framebuffer.h" + +FrameBufferPlugin::FrameBufferPlugin(QObject *parent, const QVariantList &) + : QObject(parent) +{ +} + +FrameBufferPlugin::~FrameBufferPlugin() +{ +} + + +#include "framebufferplugin.moc" + diff --git a/krfb/krfb/framebufferplugin.h b/krfb/krfb/framebufferplugin.h new file mode 100644 index 00000000..11ab081e --- /dev/null +++ b/krfb/krfb/framebufferplugin.h @@ -0,0 +1,45 @@ +/* This file is part of the KDE project + Copyright (C) 2009 Collabora Ltd + @author George Goldberg + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef LIB_KRFB_FRAMEBUFFERPLUGIN_H +#define LIB_KRFB_FRAMEBUFFERPLUGIN_H + +#include + +#include + +#include + +class FrameBuffer; + +class KDE_EXPORT FrameBufferPlugin : public QObject +{ + Q_OBJECT + +public: + FrameBufferPlugin(QObject *parent, const QVariantList &args); + virtual ~FrameBufferPlugin(); + + virtual FrameBuffer *frameBuffer(WId id) = 0; +}; + + +#endif // Header guard + diff --git a/krfb/krfb/invitationsrfbclient.cpp b/krfb/krfb/invitationsrfbclient.cpp new file mode 100644 index 00000000..588763b6 --- /dev/null +++ b/krfb/krfb/invitationsrfbclient.cpp @@ -0,0 +1,149 @@ +/* + Copyright (C) 2009-2010 Collabora Ltd + @author George Goldberg + @author George Kiagiadakis + Copyright (C) 2007 Alessandro Praduroux + Copyright (C) 2001-2003 by Tim Jansen + + 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 Lesser General Public License + along with this program. If not, see . +*/ +#include "rfb.h" +#include "invitationsrfbclient.h" +#include "invitationsrfbserver.h" +#include "krfbconfig.h" +#include "sockethelpers.h" +#include "connectiondialog.h" +#include +#include +#include +#include + +struct PendingInvitationsRfbClient::Private +{ + Private(rfbClientPtr client) : + client(client), + askOnConnect(true) + {} + + rfbClientPtr client; + QSocketNotifier *notifier; + bool askOnConnect; +}; + +static void clientGoneHookNoop(rfbClientPtr cl) { Q_UNUSED(cl); } + +PendingInvitationsRfbClient::PendingInvitationsRfbClient(rfbClientPtr client, QObject *parent) : + PendingRfbClient(client, parent), + d(new Private(client)) +{ + d->client->clientGoneHook = clientGoneHookNoop; + d->notifier = new QSocketNotifier(client->sock, QSocketNotifier::Read, this); + d->notifier->setEnabled(true); + connect(d->notifier, SIGNAL(activated(int)), + this, SLOT(onSocketActivated())); +} + +PendingInvitationsRfbClient::~PendingInvitationsRfbClient() +{ + delete d; +} + +void PendingInvitationsRfbClient::processNewClient() +{ + QString host = peerAddress(m_rfbClient->sock) + ":" + QString::number(peerPort(m_rfbClient->sock)); + + if (d->askOnConnect == false) { + + KNotification::event("NewConnectionAutoAccepted", + i18n("Accepted connection from %1", host)); + accept(new InvitationsRfbClient(m_rfbClient, parent())); + + } else { + + KNotification::event("NewConnectionOnHold", + i18n("Received connection from %1, on hold (waiting for confirmation)", + host)); + + InvitationsConnectionDialog *dialog = new InvitationsConnectionDialog(0); + dialog->setRemoteHost(host); + dialog->setAllowRemoteControl(KrfbConfig::allowDesktopControl()); + + connect(dialog, SIGNAL(okClicked()), SLOT(dialogAccepted())); + connect(dialog, SIGNAL(cancelClicked()), SLOT(reject())); + + dialog->show(); + } +} + +void PendingInvitationsRfbClient::onSocketActivated() +{ + //Process not only one, but all pending messages. + //poll() idea/code copied from vino: + // Copyright (C) 2003 Sun Microsystems, Inc. + // License: GPL v2 or later + struct pollfd pollfd = { d->client->sock, POLLIN|POLLPRI, 0 }; + + while(poll(&pollfd, 1, 0) == 1) { + + if(d->client->state == rfbClientRec::RFB_INITIALISATION) { + d->notifier->setEnabled(false); + //Client is Authenticated + processNewClient(); + break; + } + rfbProcessClientMessage(d->client); + + //This is how we handle disconnection. + //if rfbProcessClientMessage() finds out that it can't read the socket, + //it closes it and sets it to -1. So, we just have to check this here + //and call rfbClientConnectionGone() if necessary. This will call + //the clientGoneHook which in turn will remove this RfbClient instance + //from the server manager and will call deleteLater() to delete it + if (d->client->sock == -1) { + kDebug() << "disconnected from socket signal"; + d->notifier->setEnabled(false); + rfbClientConnectionGone(d->client); + break; + } + } +} + +bool PendingInvitationsRfbClient::checkPassword(const QByteArray & encryptedPassword) +{ + QByteArray password ; + kDebug() << "about to start autentication"; + + if(InvitationsRfbServer::instance->allowUnattendedAccess() && vncAuthCheckPassword( + InvitationsRfbServer::instance->unattendedPassword().toLocal8Bit(), + encryptedPassword) ) { + d->askOnConnect = false; + return true; + } + + return vncAuthCheckPassword( + InvitationsRfbServer::instance->desktopPassword().toLocal8Bit(), + encryptedPassword); +} + +void PendingInvitationsRfbClient::dialogAccepted() +{ + InvitationsConnectionDialog *dialog = qobject_cast(sender()); + Q_ASSERT(dialog); + + InvitationsRfbClient *client = new InvitationsRfbClient(m_rfbClient, parent()); + client->setControlEnabled(dialog->allowRemoteControl()); + accept(client); +} + +#include "invitationsrfbclient.moc" diff --git a/krfb/krfb/invitationsrfbclient.h b/krfb/krfb/invitationsrfbclient.h new file mode 100644 index 00000000..3a598802 --- /dev/null +++ b/krfb/krfb/invitationsrfbclient.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2010 Collabora Ltd + @author George Kiagiadakis + + 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 Lesser General Public License + along with this program. If not, see . +*/ +#ifndef INVITATIONSRFBCLIENT_H +#define INVITATIONSRFBCLIENT_H + +#include "rfbclient.h" + +class InvitationsRfbClient : public RfbClient +{ +public: + InvitationsRfbClient(rfbClientPtr client, QObject* parent = 0) + : RfbClient(client, parent) {} +}; + + +class PendingInvitationsRfbClient : public PendingRfbClient +{ + Q_OBJECT +public: + PendingInvitationsRfbClient(rfbClientPtr client, QObject *parent = 0); + virtual ~PendingInvitationsRfbClient(); + +protected Q_SLOTS: + virtual void processNewClient(); + virtual void onSocketActivated(); + virtual bool checkPassword(const QByteArray & encryptedPassword); + +private Q_SLOTS: + void dialogAccepted(); + +private: + struct Private; + Private* const d; +}; + +#endif // INVITATIONSRFBCLIENT_H diff --git a/krfb/krfb/invitationsrfbserver.cpp b/krfb/krfb/invitationsrfbserver.cpp new file mode 100644 index 00000000..386fed57 --- /dev/null +++ b/krfb/krfb/invitationsrfbserver.cpp @@ -0,0 +1,223 @@ +/* + Copyright (C) 2009-2010 Collabora Ltd + @author George Goldberg + @author George Kiagiadakis + Copyright (C) 2007 Alessandro Praduroux + Copyright (C) 2001-2003 by Tim Jansen + + 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 Lesser General Public License + along with this program. If not, see . +*/ +#include "invitationsrfbserver.h" +#include "invitationsrfbclient.h" +#include "krfbconfig.h" +#include "rfbservermanager.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using KWallet::Wallet; + +//static +InvitationsRfbServer *InvitationsRfbServer::instance; + +//static +void InvitationsRfbServer::init() +{ + instance = new InvitationsRfbServer; + instance->m_publicService = new DNSSD::PublicService( + i18n("%1@%2 (shared desktop)", + KUser().loginName(), + QHostInfo::localHostName()), + "_rfb._tcp", + KrfbConfig::port()); + instance->setListeningAddress("0.0.0.0"); + instance->setListeningPort(KrfbConfig::port()); + instance->setPasswordRequired(true); + + instance->m_wallet = Wallet::openWallet( + Wallet::NetworkWallet(), 0, Wallet::Asynchronous); + if(instance->m_wallet) { + connect(instance->m_wallet, SIGNAL(walletOpened(bool)), + instance, SLOT(walletOpened(bool))); + } +} + +const QString& InvitationsRfbServer::desktopPassword() const +{ + return m_desktopPassword; +} + +void InvitationsRfbServer::setDesktopPassword(const QString& password) +{ + m_desktopPassword = password; +} + +const QString& InvitationsRfbServer::unattendedPassword() const +{ + return m_unattendedPassword; +} + +void InvitationsRfbServer::setUnattendedPassword(const QString& password) +{ + m_unattendedPassword = password; +} + +bool InvitationsRfbServer::allowUnattendedAccess() const +{ + return m_allowUnattendedAccess; +} + +bool InvitationsRfbServer::start() +{ + if(RfbServer::start()) { + if(KrfbConfig::publishService()) + m_publicService->publishAsync(); + return true; + } + return false; +} + +void InvitationsRfbServer::stop(bool disconnectClients) +{ + if(m_publicService->isPublished()) + m_publicService->stop(); + RfbServer::stop(disconnectClients); +} + +void InvitationsRfbServer::toggleUnattendedAccess(bool allow) +{ + m_allowUnattendedAccess = allow; +} + +InvitationsRfbServer::InvitationsRfbServer() +{ + m_desktopPassword = readableRandomString(4)+"-"+readableRandomString(3); + m_unattendedPassword = readableRandomString(4)+"-"+readableRandomString(3); + KSharedConfigPtr config = KGlobal::config(); + KConfigGroup krfbConfig(config,"Security"); + m_allowUnattendedAccess = krfbConfig.readEntry( + "allowUnattendedAccess", QVariant(false)).toBool(); +} + +InvitationsRfbServer::~InvitationsRfbServer() +{ + stop(); + KSharedConfigPtr config = KGlobal::config(); + KConfigGroup krfbConfig(config,"Security"); + krfbConfig.writeEntry("allowUnattendedAccess",m_allowUnattendedAccess); + if(m_wallet && m_wallet->isOpen()) { + + if( (m_wallet->currentFolder()=="krfb") || + ((m_wallet->hasFolder("krfb") || m_wallet->createFolder("krfb")) && + m_wallet->setFolder("krfb")) ) { + + m_wallet->writePassword("desktopSharingPassword",m_desktopPassword); + m_wallet->writePassword("unattendedAccessPassword",m_unattendedPassword); + } + + } else { + krfbConfig.writeEntry("desktopPassword", + KStringHandler::obscure(m_desktopPassword)); + krfbConfig.writeEntry("unattendedPassword", + KStringHandler::obscure(m_unattendedPassword)); + krfbConfig.writeEntry("allowUnattendedAccess", + m_allowUnattendedAccess); + } +} + +PendingRfbClient* InvitationsRfbServer::newClient(rfbClientPtr client) +{ + return new PendingInvitationsRfbClient(client, this); +} + +void InvitationsRfbServer::walletOpened(bool opened) +{ + QString desktopPassword; + QString unattendedPassword; + Q_ASSERT(m_wallet); + if( opened && + ( m_wallet->hasFolder("krfb") || m_wallet->createFolder("krfb") ) && + m_wallet->setFolder("krfb") ) { + + if(m_wallet->readPassword("desktopSharingPassword", desktopPassword)==0 && + !desktopPassword.isEmpty()) { + m_desktopPassword = desktopPassword; + emit passwordChanged(m_desktopPassword); + } + + if(m_wallet->readPassword("unattendedAccessPassword", unattendedPassword)==0 && + !unattendedPassword.isEmpty()) { + m_unattendedPassword = unattendedPassword; + } + + } else { + + kDebug() << "Could not open KWallet, Falling back to config file"; + KSharedConfigPtr config = KGlobal::config(); + KConfigGroup krfbConfig(config,"Security"); + + desktopPassword = KStringHandler::obscure(krfbConfig.readEntry( + "desktopPassword", QString())); + if(!desktopPassword.isEmpty()) { + m_desktopPassword = desktopPassword; + emit passwordChanged(m_desktopPassword); + } + + unattendedPassword = KStringHandler::obscure(krfbConfig.readEntry( + "unattendedPassword", QString())); + if(!unattendedPassword.isEmpty()) { + m_unattendedPassword = unattendedPassword; + } + + } +} + +// a random string that doesn't contain i, I, o, O, 1, l, 0 +// based on KRandom::randomString() +QString InvitationsRfbServer::readableRandomString(int length) +{ + QString str; + while (length) { + int r = KRandom::random() % 62; + r += 48; + if (r > 57) { + r += 7; + } + if (r > 90) { + r += 6; + } + char c = char(r); + if ((c == 'i') || + (c == 'I') || + (c == '1') || + (c == 'l') || + (c == 'o') || + (c == 'O') || + (c == '0')) { + continue; + } + str += c; + length--; + } + return str; +} + +#include "invitationsrfbserver.moc" diff --git a/krfb/krfb/invitationsrfbserver.h b/krfb/krfb/invitationsrfbserver.h new file mode 100644 index 00000000..bba830a4 --- /dev/null +++ b/krfb/krfb/invitationsrfbserver.h @@ -0,0 +1,73 @@ +/* + Copyright (C) 2009-2010 Collabora Ltd + @author George Goldberg + @author George Kiagiadakis + Copyright (C) 2007 Alessandro Praduroux + + 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 Lesser General Public License + along with this program. If not, see . +*/ +#ifndef INVITATIONSRFBSERVER_H +#define INVITATIONSRFBSERVER_H + +#include "rfbserver.h" + +namespace KWallet { + class Wallet; +} + +namespace DNSSD { + class PublicService; +} + +class InvitationsRfbServer : public RfbServer +{ + Q_OBJECT +public: + static InvitationsRfbServer *instance; + static void init(); + + const QString& desktopPassword() const; + void setDesktopPassword(const QString&); + const QString& unattendedPassword() const; + void setUnattendedPassword(const QString&); + bool allowUnattendedAccess() const; + +Q_SIGNALS: + void passwordChanged(const QString&); + +public Q_SLOTS: + bool start(); + void stop(bool disconnectClients=true); + void toggleUnattendedAccess(bool allow=true); + +protected: + InvitationsRfbServer(); + virtual ~InvitationsRfbServer(); + virtual PendingRfbClient* newClient(rfbClientPtr client); + +private Q_SLOTS: + void walletOpened(bool); + +private: + DNSSD::PublicService *m_publicService; + bool m_allowUnattendedAccess; + QString m_desktopPassword; + QString m_unattendedPassword; + KWallet::Wallet *m_wallet; + + QString readableRandomString(int); + Q_DISABLE_COPY(InvitationsRfbServer) +}; + +#endif // INVITATIONSRFBSERVER_H diff --git a/krfb/krfb/krfb-framebuffer.desktop b/krfb/krfb/krfb-framebuffer.desktop new file mode 100644 index 00000000..35efd14d --- /dev/null +++ b/krfb/krfb/krfb-framebuffer.desktop @@ -0,0 +1,55 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=krfb/framebuffer + +Comment=Frame Buffer plugins for KRfb +Comment[ast]=Complementu de buffer pa KRfb +Comment[bg]=Приставки за фреймбуфер за KRfb +Comment[bs]=Priključci framebafera za KRfb +Comment[ca]=Connectors de «framebuffer» per al KRfb. +Comment[ca@valencia]=Connectors de «framebuffer» per al KRfb. +Comment[cs]=Moduly Frame bufferu pro KRfb +Comment[da]=Framebuffer-plugins til KRfb +Comment[de]=Framebuffer-Module für KRfb +Comment[el]=Πρόσθετα μνήμης εξόδου βίντεο καρέ για το KRfb +Comment[en_GB]=Frame Buffer plugins for KRfb +Comment[es]=Complementos de memoria intermedia de vídeo para KRfb +Comment[et]=KRfb kaadripuhvri plugin +Comment[eu]=Irteerako bideoaren pluginak KRfb-rentzako +Comment[fi]=Kehyspuskuriliitännäinen kohteelle KRfb +Comment[fr]=Modules externes de sortie vidéo pour Krfb +Comment[ga]=Breiseáin Mhaoláin Fráma le haghaidh KRfb +Comment[gl]=Engadido de frame buffer para KRfb +Comment[hr]=Priključci za međuspremnike okvira za KRfb +Comment[hu]=Framebuffer bővítmények a Krfb-hez +Comment[ia]=Plug-ins de Frame Buffer per KRfb +Comment[it]=Estensioni del framebuffer per KRfb +Comment[ja]=KRfb の フレームバッファプラグイン +Comment[kk]=KRfb кадр буфер плагині +Comment[km]=កម្មវិធី​ជំនួយ​ Frame Buffer សម្រាប់ KRfb +Comment[ko]=KRfb 프레임버퍼 플러그인 +Comment[lt]=Frame Buffer priedai skirti KRfb +Comment[lv]=Kadru bufera sprudņi priekš KRfb +Comment[nb]=Rammebuffer-programtillegg for KRfb +Comment[nds]=Bildpuffer-Modulen för KRfb +Comment[nl]=Framebuffer-plugins voor KRfb +Comment[nn]=Framebuffer-tillegg KRfb +Comment[pa]=KRfb ਲਈ ਫਰੇਮ ਬਫ਼ਰ ਪਲੱਗਇਨ +Comment[pl]=Wtyczki buforów ramek dla KRfb +Comment[pt]='Plugins' de 'framebuffers' para o KRfb +Comment[pt_BR]=Plugins de framebuffers para o KRfb +Comment[ru]=Модуль буфера кадров для KRfb +Comment[si]=KRfb සඳහා රාමු බෆර ප්ලගින +Comment[sk]=Frame Buffer modul pre KRfb +Comment[sl]=Vstavki slikovnih medpomnilnikov za KRFB +Comment[sr]=Прикључци кадробафера за КРФБ +Comment[sr@ijekavian]=Прикључци кадробафера за КРФБ +Comment[sr@ijekavianlatin]=Priključci kadrobafera za KRFB +Comment[sr@latin]=Priključci kadrobafera za KRFB +Comment[sv]=Insticksprogram med rambuffert för Krfb +Comment[th]=ส่วนเสริมของ KRfb สำหรับจัดการเฟรมบัฟเฟอร์ +Comment[tr]=KRfb için Çerçeve Tamponu eklentileri +Comment[uk]=Додатки буфера кадрів для KRfb +Comment[x-test]=xxFrame Buffer plugins for KRfbxx +Comment[zh_CN]=KRfb 帧缓冲插件 +Comment[zh_TW]=KRfb 的 Frame Buffer 外掛程式 diff --git a/krfb/krfb/krfb.desktop b/krfb/krfb/krfb.desktop new file mode 100755 index 00000000..397d10e9 --- /dev/null +++ b/krfb/krfb/krfb.desktop @@ -0,0 +1,147 @@ +# KDE Config File +[Desktop Entry] +Type=Application +Exec=krfb -caption %c %i +Icon=krfb +X-DBUS-StartupType=Unique +X-DocPath=krfb/index.html +Terminal=false +Name=Krfb +Name[ar]=Krfb +Name[ast]=Krfb +Name[bg]=Krfb +Name[bn]=কে-আর-এফ-বি +Name[br]=Krfb +Name[bs]=Krfb +Name[ca]=Krfb +Name[ca@valencia]=Krfb +Name[cs]=Krfb +Name[da]=Krfb +Name[de]=Krfb +Name[el]=Krfb +Name[en_GB]=Krfb +Name[eo]=Krfb +Name[es]=Krfb +Name[et]=Krfb +Name[eu]=Krfb +Name[fi]=Krfb +Name[fr]=Krfb +Name[ga]=Krfb +Name[gl]=Krfb +Name[he]=Krfb +Name[hi]=केआरएफबी +Name[hne]=केआरएफबी +Name[hr]=Krfb +Name[hu]=Krfb +Name[ia]=Krfb +Name[is]=Krfb +Name[it]=Krfb +Name[ja]=Krfb +Name[kk]=Krfb +Name[km]=Krfb +Name[ko]=Krfb +Name[lt]=Krfb +Name[lv]=Krfb +Name[ml]=കെആര്‍എഫ്ബി +Name[mr]=के-आर-एफ-बी +Name[nb]=Krfb +Name[nds]=KRfb +Name[ne]=Krfb +Name[nl]=Krfb +Name[nn]=Krfb +Name[pa]=Krfb +Name[pl]=Krfb +Name[pt]=Krfb +Name[pt_BR]=Krfb +Name[ro]=Krfb +Name[ru]=Krfb +Name[si]=Krfb +Name[sk]=Krfb +Name[sl]=Krfb +Name[sq]=Krfb +Name[sr]=КРФБ +Name[sr@ijekavian]=КРФБ +Name[sr@ijekavianlatin]=KRFB +Name[sr@latin]=KRFB +Name[sv]=Krfb +Name[tr]=Krfb +Name[ug]=Krfb +Name[uk]=Krfb +Name[uz]=Krfb +Name[uz@cyrillic]=Krfb +Name[vi]=Krfb +Name[x-test]=xxKrfbxx +Name[zh_CN]=Krfb +Name[zh_HK]=Krfb +Name[zh_TW]=桌面分享_Krfb +GenericName=Desktop Sharing +GenericName[ar]=مشاركة سطح المكتب +GenericName[ast]=Escritoriu compartíu +GenericName[bg]=Споделяне на работния плот +GenericName[bn]=ডেস্কটপ ভাগাভাগি +GenericName[br]=Rannañ ar vurev +GenericName[bs]=Dijeljenje radne površine +GenericName[ca]=Compartició de l'escriptori +GenericName[ca@valencia]=Compartició de l'escriptori +GenericName[cs]=Sdílení pracovní plochy +GenericName[cy]=Rhannu Penbwrdd +GenericName[da]=Skrivebordsdeling +GenericName[de]=Arbeitsfläche freigeben +GenericName[el]=Κοινή χρήση επιφάνειας εργασίας +GenericName[en_GB]=Desktop Sharing +GenericName[eo]=Tabula komunigado +GenericName[es]=Escritorio compartido +GenericName[et]=Töölaua jagamine +GenericName[eu]=Mahaigaina partekatzea +GenericName[fa]=اشتراک رومیزی +GenericName[fi]=Työpöydän jakaminen +GenericName[fr]=Partage de bureaux +GenericName[ga]=Roinnt Deisce +GenericName[gl]=Compartimento de escritorio +GenericName[he]=שיתוף שולחנות עבודה +GenericName[hi]=डेस्कटॉप साझेदारी +GenericName[hne]=डेस्कटाप साझेदारी +GenericName[hr]=Dijeljenje radne površine +GenericName[hu]=Munkaasztal-megosztás +GenericName[ia]=Compartir de scriptorio +GenericName[is]=Skjáborðsmiðlun +GenericName[it]=Condivisione del desktop +GenericName[ja]=デスクトップ共有 +GenericName[kk]=Үстелді ортақтастыру +GenericName[km]=ការ​ចែក​រំលែក​ផ្ទៃ​តុ +GenericName[ko]=데스크톱 공유 +GenericName[lt]=Dalinimasis darbastaliu +GenericName[lv]=Darbvirsmas koplietošana +GenericName[ml]=പണിയിടം പങ്കുവെക്കല്‍ +GenericName[mr]=डेस्कटॉप शेअरींग +GenericName[nb]=Delte skrivebord +GenericName[nds]=Schriefdisch-Freegaav +GenericName[ne]=डेस्कटप साझेदारी +GenericName[nl]=Bureaublad delen +GenericName[nn]=Skrivebordsdeling +GenericName[pa]=ਡੈਸਕਟਾਪ ਸ਼ੇਅਰਿੰਗ +GenericName[pl]=Współdzielenie pulpitu +GenericName[pt]=Partilha do Ecrã +GenericName[pt_BR]=Compartilhamento de ambiente de trabalho +GenericName[ro]=Partajare birou +GenericName[ru]=Общий рабочий стол +GenericName[si]=වැඩතල හවුල් +GenericName[sk]=Zdieľanie pracovnej plochy +GenericName[sl]=Souporaba namizja +GenericName[sr]=Дељење површи +GenericName[sr@ijekavian]=Дијељење површи +GenericName[sr@ijekavianlatin]=Dijeljenje površi +GenericName[sr@latin]=Deljenje površi +GenericName[sv]=Dela ut skrivbordet +GenericName[th]=ใช้งานพื้นที่ทำงานร่วมกัน +GenericName[tr]=Masaüstü Paylaşımı +GenericName[ug]=ئۈستەلئۈستىنى ھەمبەھىرلەش +GenericName[uk]=Спільні стільниці +GenericName[uz]=Ish stoli bilan boʻlishish +GenericName[uz@cyrillic]=Иш столи билан бўлишиш +GenericName[vi]=Chia sẻ màn hình nền +GenericName[x-test]=xxDesktop Sharingxx +GenericName[zh_CN]=桌面共享 +GenericName[zh_HK]=桌面分享 +GenericName[zh_TW]=桌面分享 +Categories=Qt;KDE;System;Network;RemoteAccess; diff --git a/krfb/krfb/krfb.kcfg b/krfb/krfb/krfb.kcfg new file mode 100644 index 00000000..bd0affd8 --- /dev/null +++ b/krfb/krfb/krfb.kcfg @@ -0,0 +1,42 @@ + + + + + + + + true + + + + 5900 + + + + true + + + + + + true + + + + false + + + + + + + + + + + + krfb_framebuffer_x11 + + + diff --git a/krfb/krfb/krfb.notifyrc b/krfb/krfb/krfb.notifyrc new file mode 100644 index 00000000..bfb5e73a --- /dev/null +++ b/krfb/krfb/krfb.notifyrc @@ -0,0 +1,1278 @@ +[Global] +IconName=krfb +Comment=Desktop Sharing +Comment[af]=Werkskerm Deeling +Comment[ar]=مشاركة سطح المكتب +Comment[ast]=Escritoriu compartíu +Comment[bg]=Споделяне на работния плот +Comment[bn]=ডেস্কটপ ভাগাভাগি +Comment[br]=Rannañ ar vurev +Comment[bs]=Dijeljenje radne površine +Comment[ca]=Compartició de l'escriptori +Comment[ca@valencia]=Compartició de l'escriptori +Comment[cs]=Sdílení pracovní plochy +Comment[cy]=Rhannu Penbwrdd +Comment[da]=Skrivebordsdeling +Comment[de]=Arbeitsflächen-Freigabe +Comment[el]=Κοινή χρήση επιφάνειας εργασίας +Comment[en_GB]=Desktop Sharing +Comment[eo]=Tabula komunigado +Comment[es]=Escritorio compartido +Comment[et]=Töölaua jagamine +Comment[eu]=Mahaigaina partekatzea +Comment[fi]=Työpöydän jakaminen +Comment[fr]=Partage de bureaux +Comment[ga]=Roinnt Deisce +Comment[gl]=Compartición do escritorio +Comment[he]=שיתוף שולחנות עבודה +Comment[hi]=डेस्कटॉप साझेदारी +Comment[hne]=डेस्कटाप साझेदारी +Comment[hr]=Dijeljenje radne površine +Comment[hu]=Munkaasztal-megosztás +Comment[ia]=Compartir de scriptorio +Comment[is]=Skjáborðamiðlun +Comment[it]=Condivisione del desktop +Comment[ja]=デスクトップ共有 +Comment[kk]=Үстелді ортақтастыру +Comment[km]=ការ​ចែក​រំលែក​ផ្ទែ​តុ +Comment[ko]=데스크톱 공유 +Comment[lt]=Dalinimasis darbastaliu +Comment[lv]=Darbvirsmas koplietošana +Comment[mk]=Делење на работната површина +Comment[ml]=പണിയിടം പങ്കുവെക്കല്‍ +Comment[mr]=डेस्कटॉप शेअरींग +Comment[ms]=Perkongsian Ruang Kerja +Comment[nb]=Delte skrivebord +Comment[nds]=Schriefdisch-Freegaav +Comment[nl]=Bureaublad delen +Comment[nn]=Skrivebordsdeling +Comment[pa]=ਡੈਸਕਟਾਪ ਸ਼ੇਅਰਿੰਗ +Comment[pl]=Współdzielenie pulpitu +Comment[pt]=Partilha do Ecrã +Comment[pt_BR]=Compartilhamento do ambiente de trabalho +Comment[ro]=Partajare birou +Comment[ru]=Параметры общего рабочего стола +Comment[si]=වැඩතල හවුල් +Comment[sk]=Zdieľanie pracovnej plochy +Comment[sl]=Souporaba namizja +Comment[sr]=Дељење површи +Comment[sr@ijekavian]=Дијељење површи +Comment[sr@ijekavianlatin]=Dijeljenje površi +Comment[sr@latin]=Deljenje površi +Comment[sv]=Dela ut skrivbordet +Comment[ta]=பணிமேடை பகிர்வு +Comment[tg]=Истифодаи Муштараки Мизи Корӣ +Comment[th]=ใช้งานพื้นที่ทำงานร่วมกัน +Comment[tr]=Masaüstü Paylaşımı +Comment[ug]=ئۈستەلئۈستىنى ھەمبەھىرلەش +Comment[uk]=Спільні стільниці +Comment[xh]=Ulwahlulelano lwe Desktop +Comment[x-test]=xxDesktop Sharingxx +Comment[zh_CN]=桌面共享 +Comment[zh_HK]=桌面分享 +Comment[zh_TW]=桌面分享 + +[Event/UserAcceptsConnection] +Name=User Accepts Connection +Name[ar]=المستخدم يقبل الاتصال +Name[ast]=L'usuariu aceuta la conexón +Name[bg]=Потребителят приема връзката +Name[bs]=Korisnik prihvata vezu +Name[ca]=L'usuari accepta la connexió +Name[ca@valencia]=L'usuari accepta la connexió +Name[cs]=Uživatel přijímá spojení +Name[da]=Bruger accepterer forbindelse +Name[de]=Benutzer akzeptiert Verbindung +Name[el]=Ο χρήστης δέχεται τη σύνδεση +Name[en_GB]=User Accepts Connection +Name[eo]=Uzanto akceptas la konekton +Name[es]=El usuario acepta la conexión +Name[et]=Kasutaja nõustub ühendusega +Name[eu]=Erabiltzaileak konexioa onartu du +Name[fi]=Käyttäjä hyväksyy yhteyden +Name[fr]=L'utilisateur accepte la connexion +Name[ga]=Glacann an tÚsáideoir Le Ceangal +Name[gl]=O usuario acepta a conexión +Name[hi]=उपयोक्ता ने कनेक्शन स्वीकारा +Name[hne]=कमइया हर कनेक्सन स्वीकारा +Name[hr]=Korisnik prihvaća vezu +Name[hu]=A felhasználó engedélyezi a csatlakozást +Name[ia]=Usator da acceptation a connexion +Name[is]=Notandi samþykkir tengingar +Name[it]=L'utente accetta la connessione +Name[ja]=ユーザが接続を許可 +Name[kk]=Пайдаланушы қосылымды қабылдайды +Name[km]=អ្នក​ប្រើ​ទទួល​យក​ការ​ត​ភ្ជាប់ +Name[ko]=사용자가 연결을 수락함 +Name[lt]=Naudotojas priėmė kvietimą +Name[lv]=Lietotājs atļauj savienojumu +Name[ml]=ഉപയോക്താവ് ബന്ധം സ്വീകരിക്കുന്നു +Name[mr]=वापरकर्ता जुळवणी स्वीकारतो +Name[nb]=Bruker godtar tilkobling +Name[nds]=Bruker lett tokoppeln to +Name[nl]=Gebruiker accepteert de verbinding +Name[nn]=Brukar godtek tilkopling +Name[pa]=ਯੂਜ਼ਰ ਨੇ ਕੁਨੈਕਸ਼ਨ ਮਨਜ਼ੂਰ ਕੀਤਾ +Name[pl]=Połączenie zaakceptowane przez użytkownika +Name[pt]=O Utilizador Aceita a Ligação +Name[pt_BR]=O usuário aceita a conexão +Name[ro]=Utilizatorul acceptă conexiunea +Name[ru]=Пользователь принимает соединения +Name[si]=සබැඳිය පරිශීලකයා තහවුරු කරයි +Name[sk]=Užívateľ akceptuje pripojenie +Name[sl]=Uporabnik sprejema povezavo +Name[sr]=Корисник прихвата везу +Name[sr@ijekavian]=Корисник прихвата везу +Name[sr@ijekavianlatin]=Korisnik prihvata vezu +Name[sr@latin]=Korisnik prihvata vezu +Name[sv]=Användaren accepterar anslutning +Name[th]=ผู้ใช้ยอมรับการเชื่อมต่อ +Name[tr]=Kullanıcı Bağlantıyı Kabul Etti +Name[ug]=ئىشلەتكۈچى باغلىنىشقا قوشۇلدى +Name[uk]=Користувач приймає з’єднання +Name[x-test]=xxUser Accepts Connectionxx +Name[zh_CN]=用户接受连接 +Name[zh_TW]=使用者接受連線 +Comment=User accepts connection +Comment[af]=Gebruiker aanvaar verbinding +Comment[ar]=المستخدم يقبل الاتصال +Comment[ast]=L'usuariu aceuta la conexón +Comment[bg]=Потребителят приема връзката +Comment[bn]=ব্যবহারকারী সংযোগ গ্রহণ করে +Comment[bs]=Korisnik prihvata vezu +Comment[ca]=L'usuari accepta la connexió +Comment[ca@valencia]=L'usuari accepta la connexió +Comment[cs]=Uživatel přijímá spojení +Comment[cy]=Mae'r defnyddiwr yn derbyn y cysylltiad +Comment[da]=Bruger accepterer forbindelse +Comment[de]=Der Benutzer akzeptiert die Verbindung +Comment[el]=Ο χρήστης δέχεται τη σύνδεση +Comment[en_GB]=User accepts connection +Comment[eo]=Uzanto akceptas la konekton +Comment[es]=El usuario acepta la conexión +Comment[et]=Kasutaja nõustub ühendusega +Comment[eu]=Erabiltzaileak konexioa onartu du +Comment[fi]=Käyttäjä hyväksyy yhteyden +Comment[fr]=L'utilisateur accepte la connexion +Comment[ga]=Glacann úsáideoir le ceangal +Comment[gl]=O usuario acepta a conexión +Comment[he]=המשתמש מקבל את החיבור +Comment[hi]=उपयोक्ता ने कनेक्शन स्वीकारा +Comment[hne]=कमइया हर कनेक्सन स्वीकारा +Comment[hr]=Korisnik prihvaća vezu +Comment[hu]=A felhasználó engedélyezi a csatlakozást +Comment[ia]=Usator da acceptation a connexion +Comment[is]=Notandi samþykkir tengingu +Comment[it]=L'utente accetta la connessione +Comment[ja]=ユーザが接続を許可 +Comment[kk]=Пайдаланушы қосылымды қабылдайды +Comment[km]=អ្នក​ប្រើ​ទទួល​យក​ការ​ត​ភ្ជាប់ +Comment[ko]=사용자가 연결을 수락함 +Comment[lt]=Naudotojas priėmė kvietimą +Comment[lv]=Lietotājs atļauj savienojumu +Comment[mk]=Корисникот прифаќа поврзување +Comment[ml]=ഉപയോക്താവ് ബന്ധം സ്വീകരിക്കുന്നു +Comment[mr]=वापरकर्ता जुळवणी स्वीकारतो +Comment[ms]= Pengguna menerima sambungan +Comment[nb]=Bruker godtar tilkobling +Comment[nds]=Bruker nimmt Tokoppelanfraag an +Comment[nl]=Gebruiker accepteert de verbinding +Comment[nn]=Brukaren godtek tilkoplinga +Comment[pa]=ਯੂਜ਼ਰ ਨੇ ਕੁਨੈਕਸ਼ਨ ਮੰਨਿਆ +Comment[pl]=Użytkownik akceptuje połączenie +Comment[pt]=O utilizador aceita a ligação +Comment[pt_BR]=O usuário aceita a conexão +Comment[ro]=Utilizatorul acceptă conexiunea +Comment[ru]=Пользователь принимает соединения +Comment[si]=සබැඳිය පරිශීලකයා තහවුරු කරයි +Comment[sk]=Užívateľ akceptuje pripojenie +Comment[sl]=Uporabnik sprejema povezavo +Comment[sr]=Корисник прихвата везу +Comment[sr@ijekavian]=Корисник прихвата везу +Comment[sr@ijekavianlatin]=Korisnik prihvata vezu +Comment[sr@latin]=Korisnik prihvata vezu +Comment[sv]=Användaren accepterar anslutning +Comment[ta]=பயனர் இணைப்பு ஏற்றுக்கொள்ளப்பட்டது +Comment[tg]=Корванд пайвастшавиро қабул мекунад +Comment[th]=ผู้ใช้ยอมรับการเชื่อมต่อ +Comment[tr]=Kullanıcı bağlantıyı kabul etti +Comment[ug]=ئىشلەتكۈچى باغلىنىشقا قوشۇلدى +Comment[uk]=Користувач приймає з’єднання +Comment[xh]=Umsebenzisi wamkela uxhulumaniso +Comment[x-test]=xxUser accepts connectionxx +Comment[zh_CN]=用户接受连接 +Comment[zh_HK]=用戶接受連線 +Comment[zh_TW]=使用者接受連線 +Action=Popup + +[Event/UserRefusesConnection] +Name=User Refuses Connection +Name[ar]=المستخدم يرفض الاتصال +Name[ast]=L'usuariu refuga la conexón +Name[bg]=Потребителят отказва връзката +Name[bs]=Korisnik odbija vezu +Name[ca]=L'usuari refusa la connexió +Name[ca@valencia]=L'usuari refusa la connexió +Name[cs]=Uživatel odmítá spojení +Name[da]=Bruger afslår forbindelse +Name[de]=Benutzer verweigert Verbindung +Name[el]=Ο χρήστης απέρριψε τη σύνδεση +Name[en_GB]=User Refuses Connection +Name[eo]=Uzanto rifuzas la konekton +Name[es]=El usuario rechaza la conexión +Name[et]=Kasutaja keeldub ühendusest +Name[eu]=Erabiltzaileak konexioa ukatu du +Name[fi]=Käyttäjä hylkää yhteyden +Name[fr]=L'utilisateur refuse la connexion +Name[ga]=Diúltaíonn an tÚsáideoir Le Ceangal +Name[gl]=O usuario rexeita a conexión +Name[hi]=उपयोक्ता ने कनेक्शन अस्वीकारा +Name[hne]=कमइया हर कनेक्सन अस्वीकारा +Name[hr]=Korisnik odbija vezu +Name[hu]=A felhasználó elutasítja a csatlakozást +Name[ia]=Usator refuta connexion +Name[is]=Notandi hafnar tengingum +Name[it]=L'utente rifiuta la connessione +Name[ja]=ユーザが接続を拒否 +Name[kk]=Пайдаланушы қосылымдан бас тартады +Name[km]=អ្នក​ប្រើ​បដិសេធ​ការ​ត​ភ្ជាប់ +Name[ko]=사용자가 연결을 거부함 +Name[lt]=Naudotojas atmetė kvietimą +Name[lv]=Lietotājs noraida savienojumu +Name[ml]=ഉപയോക്താവ് ബന്ധം തിരസ്കരിക്കുന്നു +Name[mr]=वापरकर्ता जुळवणी अस्वीकारतो +Name[nb]=Bruker nekter tilkobling +Name[nds]=Bruker wiest tokoppeln af +Name[nl]=Gebruiker weigert de verbinding +Name[nn]=Brukar avslår tilkopling +Name[pa]=ਯੂਜ਼ਰ ਨੇ ਕੁਨੈਕਸ਼ਨ ਤੋਂ ਇਨਕਾਰ ਕੀਤਾ +Name[pl]=Połączenie odrzucone przez użytkownika +Name[pt]=O Utilizador Recusa a Ligação +Name[pt_BR]=O usuário rejeita a conexão +Name[ro]=Utilizatorul refuză conexiunea +Name[ru]=Пользователь отклоняет соединения +Name[si]=සබැඳිය පරිශීලකයා තහවුරු නොකරයි +Name[sk]=Užívateľ odmieta pripojenie +Name[sl]=Uporabnik zavrača povezavo +Name[sr]=Корисник одбија везу +Name[sr@ijekavian]=Корисник одбија везу +Name[sr@ijekavianlatin]=Korisnik odbija vezu +Name[sr@latin]=Korisnik odbija vezu +Name[sv]=Användaren vägrar anslutning +Name[th]=ผู้ใช้ปฏิเสธการเชื่อมต่อ +Name[tr]=Kullanıcı Bağlantıyı Reddetti +Name[ug]=ئىشلەتكۈچى باغلىنىشنى رەت قىلدى +Name[uk]=Користувач не приймає з’єднання +Name[x-test]=xxUser Refuses Connectionxx +Name[zh_CN]=用户拒绝连接 +Name[zh_TW]=使用者拒絕連線 +Comment=User refuses connection +Comment[af]=Gebruiker weier verbinding +Comment[ar]=المستخدم يرفض الاتصال +Comment[ast]=L'usuariu refuga la conexón +Comment[bg]=Потребителят отказва връзката +Comment[bn]=ব্যবহারকারী সংযোগ অস্বীকার করে +Comment[bs]=Korisnik odbija vezu +Comment[ca]=L'usuari refusa la connexió +Comment[ca@valencia]=L'usuari refusa la connexió +Comment[cs]=Uživatel odmítá spojení +Comment[cy]=Mae'r defnyddiwr yn gwrthod y cysylltiad +Comment[da]=Bruger afslår forbindelse +Comment[de]=Der Benutzer verweigert die Verbindung +Comment[el]=Ο χρήστης απέρριψε τη σύνδεση +Comment[en_GB]=User refuses connection +Comment[eo]=Uzanto rifuzas konektojn +Comment[es]=El usuario rechaza la conexión +Comment[et]=Kasutaja keeldub ühendusest +Comment[eu]=Erabiltzaileak konexioa ukatu du +Comment[fi]=Käyttäjä hylkää yhteyden +Comment[fr]=L'utilisateur refuse la connexion +Comment[ga]=Diúltaíonn úsáideoir ceangal +Comment[gl]=O usuario rexeita a conexión +Comment[he]=המשתמש מסרב לחיבור +Comment[hi]=उपयोक्ता ने कनेक्शन अस्वीकारा +Comment[hne]=कमइया हर कनेक्सन अस्वीकारा +Comment[hr]=Korisnik odbija vezu +Comment[hu]=A felhasználó elutasítja a csatlakozást +Comment[ia]=Usator refuta connexion +Comment[is]=Notandi hafnar tengingu +Comment[it]=L'utente rifiuta la connessione +Comment[ja]=ユーザが接続を拒否 +Comment[kk]=Пайдаланушы қосылымды қабылдамайды +Comment[km]=អ្នក​ប្រើ​បដិសេធ​ការ​ត​ភ្ជាប់ +Comment[ko]=사용자가 연결을 거부함 +Comment[lt]=Naudotojas atmetė kvietimą +Comment[lv]=Lietotājs noraida savienojumu +Comment[mk]=Корисникот одбива поврзување +Comment[ml]=ഉപയോക്താവ് ബന്ധം തിരസ്കരിക്കുന്നു +Comment[mr]=वापरकर्ता जुळवणी अस्वीकारतो +Comment[ms]=Pengguna menolak sambungan +Comment[nb]=Bruker nekter tilkobling +Comment[nds]=Bruker wiest Tokoppelanfraag af +Comment[nl]=Gebruiker weigert de verbinding +Comment[nn]=Brukaren avslår tilkoplinga +Comment[pa]=ਯੂਜ਼ਰ ਨੇ ਕੁਨੈਕਸ਼ਨ ਤੋਂ ਇਨਕਾਰ ਕੀਤਾ +Comment[pl]=Użytkownik odrzuca połączenie +Comment[pt]=O utilizador recusa a ligação +Comment[pt_BR]=O usuário rejeita a conexão +Comment[ro]=Utilizatorul refuză conexiunea +Comment[ru]=Пользователь отклоняет соединения +Comment[si]=සබැඳිය පරිශීලකයා තහවුරු නොකරයි +Comment[sk]=Užívateľ odmieta pripojenie +Comment[sl]=Uporabnik zavrača povezavo +Comment[sr]=Корисник одбија везу +Comment[sr@ijekavian]=Корисник одбија везу +Comment[sr@ijekavianlatin]=Korisnik odbija vezu +Comment[sr@latin]=Korisnik odbija vezu +Comment[sv]=Användaren vägrar anslutning +Comment[ta]=பயனர் இணைப்பு ஏற்க மறுக்கப்பட்டது +Comment[tg]=Корванд пайвастшавиро рад мекунад +Comment[th]=ผู้ใช้ปฏิเสธการเชื่อมต่อ +Comment[tr]=Kullanıcı bağlantıyı reddetti +Comment[ug]=ئىشلەتكۈچى باغلىنىشنى رەت قىلدى +Comment[uk]=Користувач не приймає з’єднання +Comment[xh]=Umsebenzisi wala uxhulumaniso +Comment[x-test]=xxUser refuses connectionxx +Comment[zh_CN]=用户拒绝连接 +Comment[zh_HK]=用戶拒絕連線 +Comment[zh_TW]=使用者拒絕連線使用者 +Action=Popup + +[Event/ConnectionClosed] +Name=Connection Closed +Name[ar]=الاتصال أغلق +Name[ast]=Conexón zarrada +Name[bg]=Връзката е прекъсната +Name[bs]=Konekcija zatvorena +Name[ca]=Connexió tancada +Name[ca@valencia]=Connexió tancada +Name[cs]=Spojení ukončeno +Name[da]=Forbindelse lukket +Name[de]=Verbindung geschlossen +Name[el]=Η σύνδεση έκλεισε +Name[en_GB]=Connection Closed +Name[eo]=Konekto fermita +Name[es]=Conexión cerrada +Name[et]=Ühendus suletud +Name[eu]=Konexioa itxi da +Name[fi]=Yhteys suljettu +Name[fr]=Connexion fermée +Name[ga]=Ceangal Dúnta +Name[gl]=Conexión fechada +Name[hi]=कनेक्शन बन्द +Name[hne]=कनेक्सन बन्द +Name[hr]=Veza prekinuta +Name[hu]=A kapcsolat megszűnt +Name[ia]=Connexion claudite +Name[is]=Tengingu lokað +Name[it]=Connessione chiusa +Name[ja]=接続切断 +Name[kk]=Қосылымдан жабылды +Name[km]=បាន​បិទ​ការ​ត​ភ្ជាប់ +Name[ko]=연결이 닫힘 +Name[lt]=Ryšys baigtas +Name[lv]=Savienojums slēgts +Name[mai]=संबंधन बन्न भ' गेल +Name[ml]=ബന്ധം അടച്ചു +Name[mr]=जुळवणी बंद केली +Name[nb]=Forbindelsen lukket +Name[nds]=Afkoppelt +Name[nl]=Verbinding gesloten +Name[nn]=Tilkopling vart avslutta +Name[pa]=ਕੁਨੈਕਸ਼ਨ ਬੰਦ ਕੀਤਾ +Name[pl]=Połączenia zakończone +Name[pt]=Ligação Fechada +Name[pt_BR]=Conexão encerrada +Name[ro]=Conexiune închisă +Name[ru]=Соединение закрыто +Name[si]=සබඳතාව වසා දැමිනි +Name[sk]=Pripojenie bolo ukončené +Name[sl]=Povezava zaprta +Name[sq]=Lidhja u Mbyll +Name[sr]=Веза затворена +Name[sr@ijekavian]=Веза затворена +Name[sr@ijekavianlatin]=Veza zatvorena +Name[sr@latin]=Veza zatvorena +Name[sv]=Anslutning stängd +Name[th]=การเชื่อมต่อยุติ +Name[tr]=Bağlantı Kapatıldı +Name[ug]=باغلىنىش يېپىلدى +Name[uk]=З'єднання закрито +Name[x-test]=xxConnection Closedxx +Name[zh_CN]=连接关闭 +Name[zh_TW]=連線已關閉 +Comment=Connection closed +Comment[af]=Verbinding gesluit +Comment[ar]=تمّ غلق الاتصال +Comment[ast]=Conexón zarrada +Comment[bg]=Връзката е прекъсната +Comment[bn]=সংযোগ বন্ধ করা হল +Comment[br]=Serret eo ar gevreadenn +Comment[bs]=Veza je zatvorena +Comment[ca]=Connexió tancada +Comment[ca@valencia]=Connexió tancada +Comment[cs]=Spojení ukončeno +Comment[cy]=Mae'r cysylltiad ar gau +Comment[da]=Forbindelse lukket +Comment[de]=Verbindung geschlossen +Comment[el]=Η σύνδεση έκλεισε +Comment[en_GB]=Connection closed +Comment[eo]=Konekto fermita +Comment[es]=Conexión cerrada +Comment[et]=Ühendus suletud +Comment[eu]=Konexioa itxi da +Comment[fi]=Yhteys suljettu +Comment[fr]=Connexion fermée +Comment[ga]=Ceangal dúnta +Comment[gl]=A conexión está fechada +Comment[he]=החיבור נסגר +Comment[hi]=कनेक्शन बन्द +Comment[hne]=कनेक्सन बन्द +Comment[hr]=Veza prekinuta +Comment[hu]=A kapcsolat megszűnt +Comment[ia]=Connexion claudite +Comment[is]=Tengingu lokað +Comment[it]=Connessione chiusa +Comment[ja]=接続が閉じられました +Comment[kk]=Қосылым жабылды +Comment[km]=បាន​បិទ​ការ​ត​ភ្ជាប់ +Comment[ko]=연결이 닫힘 +Comment[lt]=Ryšys baigtas +Comment[lv]=Savienojums tika slēgts +Comment[mk]=Поврзувањето е затворено +Comment[ml]=ബന്ധം അടച്ചു +Comment[mr]=जुळवणी बंद केली +Comment[ms]=Sambungan ditutup +Comment[nb]=Forbindelsen lukket +Comment[nds]=Afkoppelt +Comment[nl]=Verbinding gesloten +Comment[nn]=Tilkoplinga vart avslutta +Comment[pa]=ਕੁਨੈਕਸ਼ਨ ਬੰਦ ਕੀਤਾ +Comment[pl]=Połączenie zakończone +Comment[pt]=A ligação foi encerrada +Comment[pt_BR]=Conexão encerrada +Comment[ro]=Conexiune închisă +Comment[ru]=Соединение закрыто +Comment[si]=සබඳතාව වසාදැමිනි +Comment[sk]=Pripojenie bolo ukončené +Comment[sl]=Povezava zaprta +Comment[sq]=Lidhja u mbyll +Comment[sr]=Веза је затворена +Comment[sr@ijekavian]=Веза је затворена +Comment[sr@ijekavianlatin]=Veza je zatvorena +Comment[sr@latin]=Veza je zatvorena +Comment[sv]=Anslutning stängd +Comment[ta]=இணைப்புகள் மூடப்பட்டது +Comment[tg]=Пайвастшавӣ пӯшида аст +Comment[th]=การเชื่อมต่อยุติ +Comment[tr]=Bağlantı kapatıldı +Comment[ug]=باغلىنىش تاقالدى +Comment[uk]=З'єднання закрито +Comment[uz]=Aloqa uzildi +Comment[uz@cyrillic]=Алоқа узилди +Comment[xh]=Uxhulumaniso luvaliwe +Comment[x-test]=xxConnection closedxx +Comment[zh_CN]=连接关闭 +Comment[zh_HK]=連線已關閉 +Comment[zh_TW]=連線已關閉 +Action=Popup + +[Event/InvalidPassword] +Name=Invalid Password +Name[ar]=كلمة المرور غير صحيحة +Name[ast]=Contraseña incorreuta +Name[bg]=Неправилна парола +Name[bs]=Neispravna šifra +Name[ca]=Contrasenya no vàlida +Name[ca@valencia]=Contrasenya no vàlida +Name[cs]=Neplatné heslo +Name[da]=Ugyldig adgangskode +Name[de]=Passwort ungültig +Name[el]=Μη έγκυρος κωδικός πρόσβασης +Name[en_GB]=Invalid Password +Name[eo]=Nevalida pasvorto +Name[es]=Contraseña incorrecta +Name[et]=Vale parool +Name[eu]=Baliogabeko pasahitza +Name[fi]=Virheellinen salasana +Name[fr]=Mot de passe non valable +Name[ga]=Focal Faire Neamhbhailí +Name[gl]=O contrasinal non é válido +Name[hi]=अवैध पासवर्ड +Name[hne]=अवैध पासवर्ड +Name[hr]=Nevažeća zaporka +Name[hu]=Érvénytelen jelszó +Name[ia]=Contrasigno invalide +Name[is]=Ógilt lykilorð +Name[it]=Password non valida +Name[ja]=無効なパスワード +Name[kk]=Жарамсыз паролі +Name[km]=ពាក្យ​សម្ងាត់​មិន​ត្រឹមត្រូវ +Name[ko]=잘못된 암호 +Name[lt]=Neteisingas slaptažodžis +Name[lv]=Nederīga parole +Name[ml]=അസാധുവായ അടയാളവാക്ക് +Name[mr]=अवैध गुप्तशब्द +Name[nb]=Ugyldig passord +Name[nds]=Leeg Passwoort +Name[nl]=Ongeldig wachtwoord +Name[nn]=Ugyldig passord +Name[pa]=ਗਲਤ ਪਾਸਵਰਡ +Name[pl]=Błędne hasło +Name[pt]=Senha Inválida +Name[pt_BR]=Senha inválida +Name[ro]=Parolă nevalidă +Name[ru]=Неверный пароль +Name[si]=වැරදි මුරපදය +Name[sk]=Neplatné heslo +Name[sl]=Neveljavno geslo +Name[sq]=Fjalëkalim i Pavlefshëm +Name[sr]=Неисправна лозинка +Name[sr@ijekavian]=Неисправна лозинка +Name[sr@ijekavianlatin]=Neispravna lozinka +Name[sr@latin]=Neispravna lozinka +Name[sv]=Ogiltigt lösenord +Name[th]=รหัสผ่านไม่ถูกต้อง +Name[tr]=Geçersiz Parola +Name[ug]=ئىناۋەتسىز ئىم +Name[uk]=Неправильний пароль +Name[wa]=Sicret nén valåbe +Name[x-test]=xxInvalid Passwordxx +Name[zh_CN]=无效密码 +Name[zh_TW]=不正確的密碼 +Comment=Invalid password +Comment[af]=Ongeldige wagwoord +Comment[ar]=كلمة المرور غير صحيحة +Comment[ast]=Contraseña incorreuta +Comment[bg]=Неправилна парола +Comment[bn]=অবৈধ পাসওয়ার্ড +Comment[br]=Tremenger siek +Comment[bs]=Neispravna šifra +Comment[ca]=Contrasenya no vàlida +Comment[ca@valencia]=Contrasenya no vàlida +Comment[cs]=Neplatné heslo +Comment[cy]=Cyfrinair annilys +Comment[da]=Ugyldig adgangskode +Comment[de]=Passwort ungültig +Comment[el]=Μη έγκυρος κωδικός πρόσβασης +Comment[en_GB]=Invalid password +Comment[eo]=Nevalida pasvorto +Comment[es]=Contraseña incorrecta +Comment[et]=Vale parool +Comment[eu]=Baliogabeko pasahitza +Comment[fi]=Virheellinen salasana +Comment[fr]=Mot de passe non valable +Comment[ga]=Focal faire neamhbhailí +Comment[gl]=Este contrasinal non é válido +Comment[he]=הסיסמה שגויה +Comment[hi]=अवैध पासवर्ड +Comment[hne]=अवैध पासवर्ड +Comment[hr]=Nevažeća šifra +Comment[hu]=Érvénytelen jelszó +Comment[ia]=Contrasigno invalide +Comment[is]=Lykilorð ógilt +Comment[it]=Password non valida +Comment[ja]=無効なパスワード +Comment[kk]=Паролі дұрыс емес +Comment[km]=ពាក្យ​សម្ងាត់​មិន​ត្រឹមត្រូវ +Comment[ko]=잘못된 암호 +Comment[lt]=Neteisingas slaptažodis +Comment[lv]=Parole nav derīga +Comment[mai]=अवैध कूटशब्द +Comment[mk]=Невалидна лозинка +Comment[ml]=അസാധുവായ അടയാളവാക്ക് +Comment[mr]=अवैध गुप्तशब्द +Comment[ms]=Kata laluan tidak sah +Comment[nb]=Ugyldig passord +Comment[nds]=Leeg Passwoort +Comment[nl]=Ongeldig wachtwoord +Comment[nn]=Passordet var ugyldig +Comment[oc]=Mot de pas invalid +Comment[pa]=ਗਲਤ ਪਾਸਵਰਡ +Comment[pl]=Błędne hasło +Comment[pt]=A senha é inválida +Comment[pt_BR]=Senha inválida +Comment[ro]=Parolă nevalidă +Comment[ru]=Неверный пароль +Comment[si]=වැරදි මුරපදය +Comment[sk]=Neplatné heslo +Comment[sl]=Neveljavno geslo +Comment[sq]=Fjalëkalim i pavlefshëm +Comment[sr]=Неисправна лозинка +Comment[sr@ijekavian]=Неисправна лозинка +Comment[sr@ijekavianlatin]=Neispravna lozinka +Comment[sr@latin]=Neispravna lozinka +Comment[sv]=Ogiltigt lösenord +Comment[ta]=செல்லாத கடவுச்சொல் +Comment[tg]=Гузарвожаи нодуруст +Comment[th]=รหัสผ่านไม่ถูกต้อง +Comment[tr]=Geçersiz parola +Comment[ug]=ئىناۋەتسىز ئىم +Comment[uk]=Неправильний пароль +Comment[uz]=Maxfiy soʻz haqiqiy emas +Comment[uz@cyrillic]=Махфий сўз ҳақиқий эмас +Comment[wa]=Sicret nén valide +Comment[xh]=Igama lokugqitha elingasebenziyo +Comment[x-test]=xxInvalid passwordxx +Comment[zh_CN]=无效密码 +Comment[zh_HK]=無效的密碼 +Comment[zh_TW]=不正確的密碼 +Action=Popup + +[Event/InvalidPasswordInvitations] +Name=Invalid Password Invitations +Name[ar]=كلمة المرور الدعوات غير صحيحة +Name[ast]=Contraseñas d'invitaciones incorreutes +Name[bg]=Неправилна парола за покана +Name[bs]=Neispravna šifra pozivnice +Name[ca]=Contrasenya de les invitacions no vàlides +Name[ca@valencia]=Contrasenya de les invitacions no vàlides +Name[cs]=Neplatné hesla výzev +Name[da]=Ugyldige adgangskodeinvitationer +Name[de]=Ungültiges Einladungs-Passwort +Name[el]=Μη έγκυρος κωδικός πρόσβασης πρόσκλησης +Name[en_GB]=Invalid Password Invitations +Name[eo]=Nevalidaj pasvortaj invitoj +Name[es]=Contraseñas de invitaciones incorrectas +Name[et]=Kutsutu vale parool +Name[eu]=Gonbitearen pasahitza baliogabea +Name[fi]=Virheellinen salasana kutsuun +Name[fr]=Invitations de mots de passe non valables +Name[ga]=Cuirí Neamhbhailí Focal Faire +Name[gl]=O contrasinal de convidado non válido +Name[hi]=अवैध पासवर्ड निमंत्रण +Name[hne]=अवैध पासवर्ड निमंत्रन +Name[hr]=Pozivnice s nevažećim zaporkama +Name[hu]=Érvénytelen jelszavas meghívó +Name[ia]=Invitationes de contrasigno invalide +Name[is]=Ógild lykilorðsboð +Name[it]=Password di invito non valida +Name[ja]=招待に対する無効なパスワード +Name[kk]=Жарамсыз паролімен шақыру +Name[km]=ការ​អញ្ជើញ​ពាក្យ​សម្ងាត់​មិន​ត្រឹមត្រូវ +Name[ko]=잘못된 암호 초대장 +Name[lt]=Neteisingas kvietimo slaptažodis +Name[lv]=Nepareiza parole ar ielūgumu +Name[ml]=അസാധുവായ അടയാളവാക്ക് ക്ഷണങ്ങള്‍ +Name[mr]=अवैध गुप्तशब्द निमंत्रण +Name[nb]=Ugyldig invitasjonspassord +Name[nds]=Leeg Passwoort bi Inladen +Name[nl]=Ongeldig wachtwoord uitnodiging +Name[nn]=Ugyldig invitasjonspassord +Name[pa]=ਗਲਤ ਪਾਸਵਰਡ ਸੱਦਾ +Name[pl]=Informacja o błędnym haśle +Name[pt]=Convites de Senha Inválidos +Name[pt_BR]=Avisos de senha inválida +Name[ro]=Parolă nevalidă Invitații +Name[ru]=Неверный пароль приглашения +Name[si]=වැරදි මුරපද ආරාධනාවක් +Name[sk]=Neplatné heslo pozvánky +Name[sl]=Povabila z neveljavnimi gesli +Name[sr]=Неисправна лозинка позивнице +Name[sr@ijekavian]=Неисправна лозинка позивнице +Name[sr@ijekavianlatin]=Neispravna lozinka pozivnice +Name[sr@latin]=Neispravna lozinka pozivnice +Name[sv]=Ogiltigt lösenord vid inbjudan +Name[th]=รหัสผ่านของการเชื้อเชิญไม่ถูกต้อง +Name[tr]=Geçersiz Parola Daveti +Name[ug]=ئىناۋەتسىز ئىم تەكلىپلىرى +Name[uk]=Запрошення з некоректними паролями +Name[x-test]=xxInvalid Password Invitationsxx +Name[zh_CN]=无效密码邀请 +Name[zh_TW]=不合法的密碼邀請 +Comment=The invited party sent an invalid password. Connection refused. +Comment[af]=Die uitgenooi party gestuur 'n ongeldige wagwoord. Verbinding geweier. +Comment[ar]=المدعو أرسل كلمة مرور غير صحيحة. رفض الإتصال. +Comment[ast]=L'invitáu unvió una contraseña incorreuta. Conexón refugada. +Comment[bg]=Поканената страна изпрати неправилна парола. Връзката е отказана. +Comment[bn]=আমন্ত্রিত দল একটি অবৈধ পাসওয়ার্ড পাঠাল। সংযোগ অস্বীকার করা হল। +Comment[bs]=Pozvana strana je poslala pogrešnu šifru. Veza je odbijena. +Comment[ca]=La part invitada ha enviat una contrasenya no vàlida. Connexió refusada. +Comment[ca@valencia]=La part invitada ha enviat una contrasenya no vàlida. Connexió refusada. +Comment[cs]=Pozvaná strana poslala neplatné heslo. Spojení odmítnuto. +Comment[cy]=Anfonodd y person gwahodd cyfrinair annilys. Gwrthodwyd y cysylltiad. +Comment[da]=Den inviterede part sendte en ugyldig adgangskode. Forbindelse afslået. +Comment[de]=Die eingeladene Person hat ein ungültiges Passwort gesendet: Verbindung abgelehnt. +Comment[el]=Η πρόσκληση περιέχει μη έγκυρο κωδικό πρόσβασης. Η σύνδεση απορρίφθηκε. +Comment[en_GB]=The invited party sent an invalid password. Connection refused. +Comment[eo]=La invitita kliento sendis nevalidan pasvorton. Konekto rifuzita. +Comment[es]=El invitado envió una contraseña incorrecta. Conexión rechazada. +Comment[et]=Kutsutu saatis vigase parooli. Ühendusest keelduti. +Comment[eu]=Gonbidatutako parekoak baliogabeko pasahitza bidali du. Konexioa ukatuta. +Comment[fi]=Kutsuttu taho lähetti virheellisen salasanan. Yhteys hylättiin. +Comment[fr]=La partie invitée a envoyé un mot de passe non valable. Connexion refusée. +Comment[ga]=Sheol an duine le cuireadh focal faire neamhbhailí. Diúltaíodh an ceangal. +Comment[gl]=A parte convidada envioulle un contrasinal non válido. A conexión foi rexeitada. +Comment[he]=הצד המוזמן שלח סיסמה שגויה. החיבור נדחה. +Comment[hi]=निमंत्रित पार्टी ने अवैध पासवर्ड भेजा. कनेक्शन अस्वीकृत. +Comment[hne]=निमंत्रित पार्टी हर अवैध पासवर्ड भेजिस. कनेक्सन अस्वीकृत. +Comment[hr]=Stranka koju ste pozvali je poslala nevažeću šifru. Veza odbijena. +Comment[hu]=A meghívott fél érvénytelen jelszót küldött. A csatlakozási kérés elutasítva. +Comment[ia]=Le partita invitate inviava un contrasigno invalide. Connexion refusate. +Comment[is]=Boðinn aðili sendi ógilt lykilorð. Tengingu hafnað +Comment[it]=La parte invitata ha inviato una password non valida. Connessione rifiutata. +Comment[ja]=招待された人が無効なパスワードを送ってきました。接続を拒否しました。 +Comment[kk]=Шқырылған жақ дұрыс емес парольді жіберді. Қосылымдан бас тартылды.. +Comment[km]=ភាគី​ដែល​បាន​អញ្ជើញ បាន​ផ្ញើ​ពាក្យ​សម្ងាត់​មិន​ត្រឹមត្រូវ ។ ការ​តភ្ជាប់​ត្រូវ​បាន​បដិសេធ ។ +Comment[ko]=초대한 사람이 잘못된 암호를 보냈습니다. 연결이 잘못되었습니다. +Comment[lt]=Pakviestoji pusė atsiuntė neteisingą slaptažodį. Ryšys nutrauktas. +Comment[lv]=Ielūgtā persona nosūtīja nepareizu paroli. Savienojums noraidīts. +Comment[mk]=Поканетата страна испрати невалидна лозинка. Поврзувањето е одбиено. +Comment[ml]=ക്ഷണിച്ച പാര്‍ട്ടി അസാധുവായ അടയാളവാക്കാണ് അയച്ചത്. ബന്ധം നിഷേധിച്ചു. +Comment[ms]=Pihak yang dijemput telah menghantar kata laluan yang salah. Sambungan ditolak. +Comment[nb]=Den inviterte brukeren sendte et ugyldig passord. Tilkobling nektet. +Comment[nds]=De inlaadt Deel hett en leeg Passwoort angeven. Tokoppeln torüchwiest. +Comment[nl]=De uitgenodigde partij stuurde een ongeldig wachtwoord. De verbinding is geweigerd. +Comment[nn]=Ugyldig passordsvar på invitasjon. Tilkoplinga vart avslått. +Comment[pl]=Z drugiej strony podano błędne hasło. Połączenie odrzucone. +Comment[pt]=O utilizador convidado enviou uma senha inválida. A ligação foi recusada. +Comment[pt_BR]=A parte "convidada" enviou uma senha inválida. Conexão recusada. +Comment[ro]=Partea care invită a trimis o parolă nevalidă. Conexiune refuzată. +Comment[ru]=Приглашённый пользователь ввёл неправильный пароль. Соединение отклонено. +Comment[si]=ආරාධිත පාර්‍ශවය වැරදි මුරපදයක් එවන ලද බැවින් සබඳතාව ප්‍රතික්‍ෂේප විය. +Comment[sk]=Pozvaná strana poslala neplatné heslo. Pripojenie bolo odmietnuté. +Comment[sl]=Povabljena stranka je poslala neveljavno geslo. Povezava zavrnjena. +Comment[sr]=Позвана страна је послала погрешну лозинку. Веза је одбијена. +Comment[sr@ijekavian]=Позвана страна је послала погрешну лозинку. Веза је одбијена. +Comment[sr@ijekavianlatin]=Pozvana strana je poslala pogrešnu lozinku. Veza je odbijena. +Comment[sr@latin]=Pozvana strana je poslala pogrešnu lozinku. Veza je odbijena. +Comment[sv]=Den inbjudna personen skickade ett ogiltigt lösenord. Anslutning vägrades. +Comment[ta]=அழைத்த நபர் தவறான கடவுச்சொல்லை அனுப்பியுள்ளார். இணைப்பு நிராகரிக்கப்பட்டது. +Comment[tg]=Корванди дурдаст гузарвожаи нодурустро фиристод. Пайвастшавӣ манъ шудааст. +Comment[th]=ผู้เข้าร่วมการเชิญชวนส่งรหัสผ่านมาไม่ถูกต้อง ทำการปฏิเสธการเชื่อมต่อ +Comment[tr]=Davet edilenden gönderilmiş geçersiz parola. Bağlantı reddedildi. +Comment[ug]=تەكلىپ قىلغۇچى ئەۋەتكەن ئىم ئىناۋەتسىز. باغلىنىش رەت قىلىندى. +Comment[uk]=Запрошений учасник надіслав некоректний пароль. У з’єднанні відмовлено. +Comment[xh]=Umhlangano omenyiweyo uthumele igama lokugqitha elisebenzayo. Uxhulumano lwa liwe. +Comment[x-test]=xxThe invited party sent an invalid password. Connection refused.xx +Comment[zh_CN]=受邀请方发送的密码不对。连接被拒绝。 +Comment[zh_HK]=被邀請的一方送出無效的密碼。已拒絕連線。 +Comment[zh_TW]=邀請的人送出了不合法的密碼邀請。連線已拒絕。 +Action=Popup + +[Event/NewConnectionOnHold] +Name=New Connection on Hold +Name[ar]=اتصال جديد على التوقف +Name[ast]=Conexón nueva a la espera +Name[bg]=Изчакване на новата връзка +Name[bs]=Nova veza je na čekanju +Name[ca]=Nova connexió en espera +Name[ca@valencia]=Nova connexió en espera +Name[cs]=Nové spojení pozdrženo +Name[da]=Ny forbindelse sat til at vente +Name[de]=Neue Verbindung wartet +Name[el]=Νέα σύνδεση σε αναμονή +Name[en_GB]=New Connection on Hold +Name[eo]=Nova konekto atendante +Name[es]=Conexión nueva a la espera +Name[et]=Uus ühendus ootel +Name[eu]=Konexio berria itxarote moduan +Name[fi]=Uusi yhteys odottaa +Name[fr]=Nouvelle connexion en attente +Name[ga]=Ceangal Nua Ag Fanacht +Name[gl]=Nova conexión en espera +Name[hi]=नया कनेक्शन होल्ड पर रखा +Name[hne]=नवा कनेक्सन होल्ड मं रखा +Name[hr]=Nova veza na čekanju +Name[hu]=Új kapcsolat tartva +Name[ia]=Nove connexion in pausa +Name[is]=Ný tenging á bið +Name[it]=Nuova connessione in attesa +Name[ja]=保留中の新しい接続 +Name[kk]=Жаңа қосылым күтілуде +Name[km]=ការ​តភ្ជាប់​ថ្មី កំពុង​ស្ថិត​នៅ​ក្នុង​ការ​រង់ចាំ +Name[ko]=새 연결 대기 중 +Name[lt]=Naujas kvietimas ryšiui sulaikytas +Name[lv]=Jauns savienojums gaida +Name[ml]=പുതിയ ബന്ധം തത്കാലം നിര്‍ത്തിയിരിയ്ക്കുന്നു +Name[mr]=नवीन जुळवणी थांबविलेली आहे +Name[nb]=Ny tilkobling venter +Name[nds]=Nieg Verbinnen töövt +Name[nl]=Nieuwe verbinding in de wacht +Name[nn]=Ny tilkopling ventar +Name[pa]=ਨਵਾਂ ਕੁਨੈਕਸ਼ਨ ਹੋਲਡ ਉੱਤੇ ਹੈ +Name[pl]=Nowe połączenie wstrzymane +Name[pt]=Ligação Nova em Espera +Name[pt_BR]=Nova conexão ativa +Name[ro]=Conexiune nouă în așteptare +Name[ru]=Новое соединение приостановлено +Name[si]=නව සබඳතාවක් රඳවා ඇත +Name[sk]=Nové pripojenie bolo pozdržané +Name[sl]=Nova povezava na čakanju +Name[sr]=Нова веза је на чекању +Name[sr@ijekavian]=Нова веза је на чекању +Name[sr@ijekavianlatin]=Nova veza je na čekanju +Name[sr@latin]=Nova veza je na čekanju +Name[sv]=Ny anslutning väntar +Name[th]=การเชื่อมต่อใหม่ถูกพักรอไว้ก่อน +Name[tr]=Yeni Açık Bağlantı +Name[uk]=Очікування на нове з’єднання +Name[x-test]=xxNew Connection on Holdxx +Name[zh_CN]=新连接已搁置 +Name[zh_TW]=新連線等待處理 +Comment=Connection requested, user must accept +Comment[af]=Verbinding versoekte, gebruiker moet aanvaar +Comment[ar]=الاتصال طلب، يجب موافقة المستخدم +Comment[ast]=Conexón solicitada, l'usuario tien d'aceutala +Comment[bg]=Поискана е връзка, следва потребителят да приеме +Comment[bn]=সংযোগ অনুরোধ করা হল, ব্যবহারকারীকে অবশ্যই স্বীকার করতে হবে +Comment[bs]=Veza je zahtijevana, korinik mora da je prihvati +Comment[ca]=Connexió sol·licitada, l'usuari ha d'acceptar-la +Comment[ca@valencia]=Connexió sol·licitada, l'usuari ha d'acceptar-la +Comment[cs]=Vyžadováno spojení, uživatel musí přijmout +Comment[cy]=Cais wedi'i wneud am gysylltiad,rhaid i'r ddefnyddiwr ei dderbyn +Comment[da]=Forbindelse forespurgt, bruger skal acceptere +Comment[de]=Verbindungsanfrage, Benutzer muss bestätigen +Comment[el]=Αίτηση για σύνδεση, απαιτείται παρέμβαση του χρήστη +Comment[en_GB]=Connection requested, user must accept +Comment[eo]=Konekto pridemandita, la uzanto devas akcepti +Comment[es]=Conexión solicitada, el usuario debe aceptarla +Comment[et]=Nõutakse ühendust, kasutaja peab seda lubama +Comment[eu]=Konexioa eskatuta, erabiltzaileak onartu behar du +Comment[fi]=Pyydettiin yhteyttä, käyttäjän tulee hyväksyä +Comment[fr]=Connexion demandée. L'utilisateur doit accepter +Comment[ga]=Ceangal iarrtha; ní mór don úsáideoir glacadh leis +Comment[gl]=Pediuse a conexión; o usuario debe aceptar +Comment[he]=נתבקש חיבור, על המשתמש לקבלו +Comment[hi]=कनेक्शन निवेदित. उपयोक्ता को स्वीकार होना चाहिए +Comment[hne]=कनेक्सन निवेदित. कमइया ल स्वीकार होना चाही +Comment[hr]=Veza je zatražena, korisnik mora prihvatiti +Comment[hu]=Csatlakozási kérés, a felhasználónak el kell fogadnia +Comment[ia]=Connexion requirite, usator debe dar acceptation +Comment[is]=Beiðni um tengingu, notandi verður að samþykkja +Comment[it]=Connessione richiesta, l'utente deve accettare +Comment[ja]=接続が要求されています。ユーザが許可しなければなりません。 +Comment[kk]=Қосылым сұралды, пайдаланушы жауап беруге тиіс +Comment[km]=បាន​ស្នើ​ការ​ត​ភ្ជាប់​​ អ្នក​ប្រើ​ត្រូវ​តែ​ទទួល​យក +Comment[ko]=연결 요청됨, 사용자가 수락해야 함 +Comment[lt]=Kvietimas ryšiui išsiųstas, naudotojas turi priimti kvietimą +Comment[lv]=Ir pieprasīts jauns savienojums, kurš lietotājam ir jāapstiprina +Comment[mk]=Побарано е поврзување, корисникот мора да прифати +Comment[ml]=ബന്ധം ആവശ്യ‌പ്പെട്ടിട്ടുണ്ട്, ഉപയോക്താവ് സ്വീകരിക്കണം +Comment[ms]=Sambungan diminta, pengguna mesti menerima +Comment[nb]=Anmodning om tilkobling, bruker må godta +Comment[nds]=Tokoppeln anfraagt, Bruker mutt verlöven +Comment[nl]=Verbindingsverzoek, gebruiker dient toe te stemmen +Comment[nn]=Ei tilkopling er førespurd. Brukaren må godta. +Comment[pa]=ਕੁਨੈਕਸ਼ਨ ਦੀ ਮੰਗ ਕੀਤੀ ਗਈ, ਯੂਜ਼ਰ ਵਲੋਂ ਮਨਜ਼ੂਰ ਲਾਜ਼ਮੀ +Comment[pl]=Próba połączenia, musi być zaakceptowana przez użytkownika +Comment[pt]=Foi pedida uma ligação que o utilizador deverá aceitar +Comment[pt_BR]=Conexão requisitada; o usuário deve aceitar +Comment[ro]=Conexiune cerută, utilizatorul trebuie să accepte +Comment[ru]=Запрос на соединение, требуется подтверждение пользователя +Comment[si]=සබඳතාව ඉල්ලා ඇත, පරිශීලක තහවුරු කල යුතුයි +Comment[sk]=Vyžiadané pripojenie, užívateľ ho musí akceptovať +Comment[sl]=Povezava zahtevana, uporabnik mora sprejeti +Comment[sr]=Захтевана је веза, корисник мора да је прихвати +Comment[sr@ijekavian]=Захтијевана је веза, корисник мора да је прихвати +Comment[sr@ijekavianlatin]=Zahtijevana je veza, korisnik mora da je prihvati +Comment[sr@latin]=Zahtevana je veza, korisnik mora da je prihvati +Comment[sv]=Anslutning begärd, användaren måste acceptera +Comment[ta]=இணைப்பு கோரப்பட்டது, பயனர் கண்டிப்பாக ஏற்றுக்கொள்ள வேண்டும் +Comment[tg]=Пайвастшавӣ дархоста шудааст, корванд бояд қабул кунад +Comment[th]=มีการร้องขอเชื่อมต่อมา ผู้ใช้ต้องทำการยอมรับก่อน +Comment[tr]=Bağlantı isteği, kullanıcı kabul etmeli +Comment[ug]=باغلىنىش ئىلتىماس قىلىندى، ئىشلەتكۈچى قوشۇلۇشى كېرەك +Comment[uk]=Отримано запит на з’єднання, користувач має його прийняти +Comment[xh]=Uxhulumaniso luceliwe, umsebenzisi kufanele amkele +Comment[x-test]=xxConnection requested, user must acceptxx +Comment[zh_CN]=连接已请求,用户必须接受 +Comment[zh_HK]=已請求連線,用戶必須接受 +Comment[zh_TW]=連線已要求,必須等使用者接受 +Action=Popup + +[Event/NewConnectionAutoAccepted] +Name=New Connection Auto Accepted +Name[ar]=اتصال جديد مقبول تلقائيا +Name[ast]=Conexón nueva aceutada automáticamente +Name[bg]=Автоматично приемане на новата връзка +Name[bs]=Nova veza je automatski prihvaćena +Name[ca]=Nova connexió acceptada automàticament +Name[ca@valencia]=Nova connexió acceptada automàticament +Name[cs]=Nové spojení automaticky přijato +Name[da]=Ny forbindelse automatisk accepteret +Name[de]=Neue Verbindung automatisch angenommen +Name[el]=Αυτόματη αποδοχή νέας σύνδεσης +Name[en_GB]=New Connection Auto Accepted +Name[eo]=Nova konekto aŭtomate akceptita +Name[es]=Conexión nueva aceptada automáticamente +Name[et]=Uue ühendusega automaatselt nõus +Name[eu]=Konexio berria automatikoki onartuta +Name[fi]=Uusi yhteys hyväksyttiin automaattisesti +Name[fr]=Nouvelle connexion acceptée automatiquement +Name[ga]=Ceangal nua bunaithe go huathoibríoch +Name[gl]=Nova conexión aceptada automaticamente +Name[hi]=नय कनेक्शन स्वचालित स्वीकारा +Name[hne]=नय कनेक्सन अपने अपन स्वीकारा +Name[hr]=Nova veza automatski prihvaćena +Name[hu]=Új kapcsolat automatikusan engedélyezve +Name[ia]=Nove connexion con acceptation automatic +Name[is]=Ný tenging sjálfvirkt samþykkt +Name[it]=Nuova connessione accettata automaticamente +Name[ja]=新しい接続の自動受け入れ +Name[kk]=Жаңа қосылым автоқабылданды +Name[km]=បាន​ទទួល​យក​ការ​តភ្ជាប់​ថ្មី​ដោយ​ស្វ័យ​ប្រវត្តិ +Name[ko]=새 연결 자동 수락 +Name[lt]=Naujas kvietimas ryšiui automatiškai priimtas +Name[lv]=Automātiski pieņemts jauns savienojums +Name[ml]=പുതിയ ബന്ധം തനിയെ സ്വീകരിക്കപ്പെട്ടു +Name[nb]=Ny tilkobling automatisk godtatt +Name[nds]=Nieg Verbinnen automaatsch tolaten +Name[nl]=Nieuwe verbinding automatisch accepteren +Name[nn]=Ny tilkopling automatisk godteken +Name[pa]=ਨਵਾਂ ਕੁਨੈਕਸ਼ਨ ਆਟੋ ਮਨਜ਼ੂਰ +Name[pl]=Nowe połączenie automatycznie przyjęte +Name[pt]=Nova Ligação Aceite Automaticamente +Name[pt_BR]=Nova conexão com aceitação automática +Name[ro]=Conexiune nouă acceptată automat +Name[ru]=Новое соединение принимается автоматически +Name[si]=නව සබඳතාව ස්වයංක්‍රීයව පිළිගැණිනි +Name[sk]=Nové pripojenie bolo automaticky akceptované +Name[sl]=Nova povezava samodejno sprejeta +Name[sr]=Нова веза је аутоматски прихваћена +Name[sr@ijekavian]=Нова веза је аутоматски прихваћена +Name[sr@ijekavianlatin]=Nova veza je automatski prihvaćena +Name[sr@latin]=Nova veza je automatski prihvaćena +Name[sv]=Ny anslutning accepterades automatiskt +Name[th]=รับการเชื่อมต่อใหม่โดยอัตโนมัติ +Name[tr]=Yeni Bağlantı Otomatik olarak Kabul Edildi +Name[ug]=يېڭى باغلىنىش ئۆزلۈكىدىن قوشۇلدى +Name[uk]=Нове з’єднання автоматично прийнято +Name[x-test]=xxNew Connection Auto Acceptedxx +Name[zh_CN]=新连接自动接受 +Name[zh_TW]=新連線自動接受 +Comment=New connection automatically established +Comment[af]=Nuwe verbinding automaties vasgestel +Comment[ar]=اتصال جديد مفعل تلقائيا +Comment[ast]=Conexón nueva afitada automáticamente +Comment[bg]=Новата връзка е автоматично приета +Comment[bn]=নতুন সংযোগ স্বয়ংক্রীয়ভাবে স্থাপন করা হল +Comment[bs]=Nova veza je automatski uspostavljena +Comment[ca]=Nova connexió establerta automàticament +Comment[ca@valencia]=Nova connexió establerta automàticament +Comment[cs]=Automaticky navázáno nové spojení +Comment[cy]=Sefydlwyd cysylltiad newydd yn awtomatig +Comment[da]=Ny forbindelse automatisk etableret +Comment[de]=Neue Verbindung automatisch hergestellt +Comment[el]=Μια νέα σύνδεση δημιουργήθηκε αυτόματα +Comment[en_GB]=New connection automatically established +Comment[eo]=Nova konekto aŭtomate establita +Comment[es]=Conexión nueva establecida automáticamente +Comment[et]=Uus ühendus automaatselt loodud +Comment[eu]=Konexio berria automatikoki ezarrita +Comment[fi]=Uusi yhteys muodostettiin automaattisesti +Comment[fr]=Nouvelle connexion établie automatiquement +Comment[ga]=Ceangal nua bunaithe go huathoibríoch +Comment[gl]=Estabeleceuse automaticamente unha conexión nova +Comment[he]=נוצר חיבור חדש באופן אוטומטי +Comment[hi]=नया कनेक्शन स्वचलित स्थापित +Comment[hne]=नवा कनेक्सन अपने अपन स्थापित +Comment[hr]=Nova veza automatski prihvaćena +Comment[hu]=Automatikusan létrejött egy új kapcsolat +Comment[ia]=Nove connexion establite automaticamente +Comment[is]=Nýjar tengingar sjálfkrafa samþykktar +Comment[it]=Nuova connessione stabilita automaticamente +Comment[ja]=新しい接続を自動的に確立しました +Comment[kk]=Жаңа қосылым автоматты түрде орнатылды +Comment[km]=បាន​បង្កើត​ការ​ត​ភ្ជាប់​ថ្មី​ដោយ​ស្វ័យ​ប្រវត្តិ +Comment[ko]=새 연결이 자동으로 성립됨 +Comment[lt]=Naujas ryšys užmegztas automatiškai +Comment[lv]=Automātiski izveidots jauns savienojums +Comment[mk]=Автоматски е воспоставено ново поврзување +Comment[ml]=പുതിയ ബന്ധം യാന്ത്രികമായി സ്ഥാപിക്കപ്പെട്ടു +Comment[ms]=Sambungan baru secara automatik terjalin +Comment[nb]=En ny tilkobling er automatisk opprettet +Comment[nds]=Nieg Verbinnen automaatsch inricht +Comment[nl]=Nieuwe verbinding automatisch opgebouwd +Comment[nn]=Ei ny tilkopling vart automatisk starta +Comment[pa]=ਨਵਾਂ ਕੁਨੈਕਸ਼ਨ ਆਟੋਮੈਟਿਕ ਹੀ ਬਣਾਇਆ ਗਿਆ +Comment[pl]=Nowe połączenie ustanowiono automatycznie +Comment[pt]=Foi estabelecida automaticamente uma nova ligação +Comment[pt_BR]=Nova conexão estabelecida automaticamente +Comment[ro]=Conexiune nouă stabilită automat +Comment[ru]=Новое соединение устанавливается автоматически +Comment[si]=නව සබඳතාව ස්වයංක්‍රීයව සැකසිනි +Comment[sk]=Nové pripojenie bolo automaticky nadviazané +Comment[sl]=Nova povezava samodejno vzpostavljena +Comment[sr]=Нова веза је аутоматски успостављена +Comment[sr@ijekavian]=Нова веза је аутоматски успостављена +Comment[sr@ijekavianlatin]=Nova veza je automatski uspostavljena +Comment[sr@latin]=Nova veza je automatski uspostavljena +Comment[sv]=Ny anslutning automatiskt upprättad +Comment[ta]=இணைப்புகள் தானாக உருவாக்கப்பட்டது +Comment[tg]=Пайвастшавии нав ба таври худкор барпо мегардад +Comment[th]=การเชื่อมต่อใหม่จะถูกทำการเชื่อมต่อโดยอัตโนมัติ +Comment[tr]=Yeni bağlantı otomatik olarak kuruldu +Comment[ug]=يېڭى باغلىنىش ئۆزلۈكىدىن قۇرۇلدى +Comment[uk]=Автоматично встановлено нове з’єднання +Comment[xh]=Uxhulumaniso olutsha lufunyenwe ngokuzenzekelayo +Comment[x-test]=xxNew connection automatically establishedxx +Comment[zh_CN]=自动建立新连接 +Comment[zh_HK]=已自動建立新連線 +Comment[zh_TW]=新連線自動建立 +Action=Popup + +[Event/TooManyConnections] +Name=Too Many Connections +Name[ar]=اتصالات عديدة +Name[ast]=Abondes conexones +Name[bg]=Твърде много връзки +Name[bs]=Previše veza +Name[ca]=Massa connexions +Name[ca@valencia]=Massa connexions +Name[cs]=Příliš mnoho spojení +Name[da]=For mange forbindelser +Name[de]=Zu viele Verbindungen +Name[el]=Πάρα πολλές συνδέσεις +Name[en_GB]=Too Many Connections +Name[eo]=Tro multaj konektoj +Name[es]=Demasiadas conexiones +Name[et]=Liiga palju ühendusi +Name[eu]=Konexio gehiegi +Name[fi]=Liikaa yhteyksiä +Name[fr]=Trop de connexions +Name[ga]=An Iomarca Ceangal +Name[gl]=Demasiadas conexións +Name[hi]=बहुत सारे कनेक्शन +Name[hne]=बहुत अकन कनेक्सन +Name[hr]=Previše veza +Name[hu]=Túl sok kapcsolat +Name[ia]=Nimie connexiones +Name[is]=Of margar tengingar +Name[it]=Troppe connessioni +Name[ja]=多すぎる接続 +Name[kk]=Тым көп қосылым +Name[km]=ការ​តភ្ជាប់​ច្រើន​ពេក +Name[ko]=너무 많은 연결 +Name[lt]=Per daug užmegztų ryšių +Name[lv]=Pārāk daudz savienojumu +Name[ml]=വളരെ അധികം ബന്ധങ്ങള്‍ +Name[nb]=For mange tilkoblinger +Name[nds]=To vele Verbinnen +Name[nl]=Teveel verbindingen +Name[nn]=For mange tilkoplingar +Name[pa]=ਬਹੁਤ ਸਾਰੇ ਕੁਨੈਕਸ਼ਨ +Name[pl]=Zbyt wiele połączeń +Name[pt]=Demasiadas Ligações +Name[pt_BR]=Conexões em excesso +Name[ro]=Prea multe conexiuni +Name[ru]=Слишком много соединений +Name[si]=වඩා වැඩි සබඳතා ගණනක් +Name[sk]=Príliš veľa pripojení +Name[sl]=Preveč povezav +Name[sr]=Исувише веза +Name[sr@ijekavian]=Исувише веза +Name[sr@ijekavianlatin]=Isuviše veza +Name[sr@latin]=Isuviše veza +Name[sv]=För många anslutningar +Name[th]=มีการเชื่อมต่อมากเกินไป +Name[tr]=Çok Fazla Bağlantı +Name[ug]=باغلىنىش بەك كۆپ +Name[uk]=Забагато з’єднань +Name[x-test]=xxToo Many Connectionsxx +Name[zh_CN]=连接过多 +Name[zh_TW]=太多連線 +Comment=Busy, connection refused +Comment[af]=Besig, verbinding geweier +Comment[ar]=مشغول، الإتصال رفض +Comment[ast]=Ocupáu, conexón refugada +Comment[bg]=Заето. Връзката е отказана. +Comment[bn]=ব্যস্ত, সংযোগ অস্বীকার করল +Comment[br]=Dalc'het, kevreadenn disteuleret +Comment[bs]=Zauzeto, veza je odbijena +Comment[ca]=Ocupat, connexió rebutjada +Comment[ca@valencia]=Ocupat, connexió rebutjada +Comment[cs]=Zaneprázdněn, spojení odmítnuto +Comment[cy]=Prysur, gwrthodwyd y cysylltiad +Comment[da]=Optaget, forbindelse afslået +Comment[de]=Beschäftigt, Verbindung abgelehnt +Comment[el]=Απασχολημένος, η σύνδεση απορρίφθηκε +Comment[en_GB]=Busy, connection refused +Comment[eo]=Okupata, konekto rifuzita +Comment[es]=Ocupado, conexión rechazada +Comment[et]=Hõivatud, ühendusest keelduti +Comment[eu]=Lanpetuta, konexioa ukatu da +Comment[fi]=Varattu, yhteys hylättiin +Comment[fr]=Occupé. Connexion refusée +Comment[ga]=Gnóthach; ceangal diúltaithe +Comment[gl]=Ocupado; a conexión foi rexeitada +Comment[he]=תפוס, החיבור נדחה +Comment[hi]=व्यस्त, कनेक्शन अस्वीकृत +Comment[hne]=व्यस्त, कनेक्सन अस्वीकृत +Comment[hr]=Zauzeto, veza odbijena +Comment[hu]=A csatlakozási kérés elutasítva túlterhelés miatt +Comment[ia]=Occupate, connexion refusate +Comment[is]=Uptekinn, tengingu hafnað +Comment[it]=Occupato, connessione rifiutata +Comment[ja]=ビジーです、接続を拒否しました +Comment[kk]=Бос емес, қосылым болмады +Comment[km]=រវល់ បដិសេធ​ការ​ត​ភ្ជាប់ +Comment[ko]=바쁨, 연결 거부됨 +Comment[lt]=Užimta, kvietimas ryšiui atmestas +Comment[lv]=Aizņemts, savienojums noraidīts +Comment[mk]=Зафатено, поврзувањето е одбиено +Comment[ml]=തിരക്കിലാണ്, ബന്ധം നിഷേധിച്ചു +Comment[ms]=Sibuk, sambungan ditolak +Comment[nb]=Opptatt, tilkobling nektet +Comment[nds]=Bunnen, Verbinnen torüchwiest +Comment[nl]=Bezet, verbinding geweigerd +Comment[nn]=Oppteken, så tilkoplinga vart avslått +Comment[pa]=ਬਿਜ਼ੀ, ਕੁਨੈਕਸ਼ਨ ਤੋਂ ਇਨਕਾਰ +Comment[pl]=Zajęte, połączenie odrzucone +Comment[pt]=Ocupado, pelo a ligação foi recusada +Comment[pt_BR]=Ocupado; conexão recusada +Comment[ro]=Ocupat, conexiune refuzată +Comment[ru]=Занят, соединение отклонено +Comment[si]=කාර්‍යබහුලයි, සබඳතාව නොපිළිගැණිනි +Comment[sk]=Zaneprázdnený, pripojenie bolo odmietnuté +Comment[sl]=Zaposlen, povezava zavrnjena +Comment[sr]=Заузето, веза је одбијена +Comment[sr@ijekavian]=Заузето, веза је одбијена +Comment[sr@ijekavianlatin]=Zauzeto, veza je odbijena +Comment[sr@latin]=Zauzeto, veza je odbijena +Comment[sv]=Upptagen, anslutning vägras +Comment[ta]=வேலையில் உள்ளது, இணைப்பு நிராகரிக்கப்பட்டது +Comment[tg]=Банд, пайвастшавӣ рад гардидааст +Comment[th]=ยังไม่ว่าง ทำการปฏิเสธการเชื่อมต่อ +Comment[tr]=Meşgul, bağlantı reddedildi +Comment[ug]=ئالدىراش، باغلىنىش رەت قىلىندى +Comment[uk]=Зайнято, у з’єднанні відмовлено +Comment[uz]=Band, aloqa rad etildi +Comment[uz@cyrillic]=Банд, алоқа рад этилди +Comment[xh]=Uxhulumaniso, olu xakekileyo lwaliwe +Comment[x-test]=xxBusy, connection refusedxx +Comment[zh_CN]=对方处于忙碌状态,连接被拒绝 +Comment[zh_HK]=忙碌,已拒絕連線 +Comment[zh_TW]=忙碌,連線被拒 +Action=Popup + +[Event/UnexpectedConnection] +Name=Unexpected Connection +Name[ar]=الاتصال غير متوقّع +Name[ast]=Conexón inesperada +Name[bg]=Неочаквана връзка +Name[bs]=Neočekivana veza +Name[ca]=Connexió inesperada +Name[ca@valencia]=Connexió inesperada +Name[cs]=Neočekávané spojení +Name[da]=Uventet forbindelse +Name[de]=Unerwartete Verbindung +Name[el]=Μη αναμενόμενη σύνδεση +Name[en_GB]=Unexpected Connection +Name[eo]=Neatendita konekto +Name[es]=Conexión inesperada +Name[et]=Ootamatu ühendus +Name[eu]=Ustekabeko konexioa +Name[fi]=Odottamaton yhteys +Name[fr]=Connexion inattendue +Name[ga]=Ceangal Gan Choinne +Name[gl]=Conexión non agardada +Name[hi]=अप्रत्याशित कनेक्शन +Name[hne]=अप्रत्यासित कनेक्सन +Name[hr]=Neočekivana veza +Name[hu]=Nem várt kapcsolat +Name[ia]=Connexion impreviste +Name[is]=Óvænt Tenging +Name[it]=Connessione inattesa +Name[ja]=予期しない接続 +Name[kk]=Күтпеген қосылым +Name[km]=ការ​តភ្ជាប់​ដែល​មិន​បាន​រំពឹង​ទុក +Name[ko]=예상하지 않은 연결 +Name[lt]=Netikėtas kvietimas ryšiui +Name[lv]=Negaidīts savienojums +Name[ml]=അപ്രതീക്ഷിതമായ ബന്ധം +Name[nb]=Uventet tilkobling +Name[nds]=Nich verwacht Tokoppeln +Name[nl]=Onverwachte verbinding +Name[nn]=Uventa tilkopling +Name[pa]=ਅਣਜਾਣ ਕੁਨੈਕਸ਼ਨ +Name[pl]=Niespodziewane połączenie +Name[pt]=Ligação Inesperada +Name[pt_BR]=Conexão inesperada +Name[ro]=Conexiune neașteptată +Name[ru]=Неожиданное соединение +Name[si]=බලාපොරොත්තු රහිත සබඳතාවක් +Name[sk]=Neočakávané pripojenie +Name[sl]=Nepričakovana povezava +Name[sq]=Lidhje e Papritur +Name[sr]=Неочекивана веза +Name[sr@ijekavian]=Неочекивана веза +Name[sr@ijekavianlatin]=Neočekivana veza +Name[sr@latin]=Neočekivana veza +Name[sv]=Oväntad anslutning +Name[th]=เกิดการเชื่อมต่อที่ไม่คาดคิด +Name[tr]=Beklenmeyen Bağlantı +Name[ug]=كۈتۈلمىگەن باغلىنىش +Name[uk]=Неочікуване з’єднання +Name[x-test]=xxUnexpected Connectionxx +Name[zh_CN]=未预料的连接 +Name[zh_TW]=未知的連線 +Comment=Received unexpected connection, abort +Comment[af]=Ontvang onverwagte verbinding, staak +Comment[ar]=استقبال اتصال غير متوقع، إنهاء +Comment[ast]=Recibióse conexón inesperada, albortando +Comment[bg]=Получена е неочаквана връзка. Прекъсване. +Comment[bn]=অপ্রত্যাশিত সংযোগ গ্রহণ করল, বাতিল করুন +Comment[bs]=Primljena je neočekivana veza, prekini +Comment[ca]=Rebuda una connexió inesperada, avortant +Comment[ca@valencia]=Rebuda una connexió inesperada, avortant +Comment[cs]=Obdrženo neočekávané spojení, přerušeno +Comment[cy]=Derbynwyd cysylltiad annisgwyl,terfynu +Comment[da]=Modtog uventet forbindelse, afbrød +Comment[de]=Unerwartete Verbindung hergestellt, Abbruch +Comment[el]=Λήφθηκε μια μη αναμενόμενη σύνδεση· εγκατάλειψη +Comment[en_GB]=Received unexpected connection, abort +Comment[eo]=Ricevis neatenditan konekton, ĉesi +Comment[es]=Recibida conexión inesperada, interrumpir +Comment[et]=Saadi ootamatu ühendus, loobuti +Comment[eu]=Ustekabeko konexioa jaso da, abortatzen +Comment[fi]=Vastaanotettiin odottamaton yhteys, lopeta +Comment[fr]=Connexion inattendue reçue. Annulation +Comment[ga]=Fuarthas ceangal gan choinne, á thobscor +Comment[gl]=Recibiuse unha conexión non agardada; cancélase +Comment[he]=נתקבל חיבור בלתי צפוי, בוטל +Comment[hi]=अप्रत्याशित कनेक्शन प्राप्त. छोड़ा +Comment[hne]=अप्रत्यासित कनेक्सन प्राप्त. छोड़ा +Comment[hr]=Primio sam neočekivanu vezu, prekid +Comment[hu]=Nem várt csatlakozási kérés érkezett, megszakítás +Comment[ia]=On recipeva connexion impreviste, aborta +Comment[is]=Tók á móti óvæntri tengingu, hætti +Comment[it]=Ricevuta connessione inattesa, terminata +Comment[ja]=予期しない接続を受信しました。廃棄します。 +Comment[kk]=Күтпеген қосылым ұсынысы, доғарылды +Comment[km]=បាន​ទទួល​យក​ការ​តភ្ជាប់​ដែល​មិន​បាន​រំពឹង​ទុក ​បោះបង់ +Comment[ko]=예상하지 않은 연결을 받았습니다, 중지합니다 +Comment[lt]=Sulaukta netikėto kvietimo ryšiui, nutraukiama +Comment[lv]=Saņemts negaidīts savienojums, pārtraukts +Comment[mk]=Примено е неочекувано поврзување, се прекинува +Comment[ml]=അപ്രതീക്ഷിതമായ ബന്ധം ലഭിച്ചു, നിരസിക്കുക +Comment[ms]=Menerima sambungan luar jangka, menamatkan +Comment[nb]=Mottok uventet tilkobling, avbrutt +Comment[nds]=Unverwacht Verbinnen kregen, afbraken +Comment[nl]=Ontving een onverwachte verbinding, afgebroken +Comment[nn]=Fekk ei uventa tilkopling, så avbryt no +Comment[pl]=Otrzymano niespodziewane połączenie. Przerwane. +Comment[pt]=Foi recebida uma ligação inesperada, pelo que foi interrompida +Comment[pt_BR]=Conexão recebida inesperadamente; abortar +Comment[ro]=Conexiune neașteptată recepționată, abandonare +Comment[ru]=Получено неожиданное соединение. Отключение +Comment[si]=බලාපොරොත්තු රහිත සබඳතාවක් ලැබිනි, පිටවෙමින් +Comment[sk]=Prijaté neočakávané pripojenie, prerušené +Comment[sl]=Prejeta nepričakovana povezava, prekinjeno +Comment[sr]=Примљена је неочекивана веза, прекидам +Comment[sr@ijekavian]=Примљена је неочекивана веза, прекидам +Comment[sr@ijekavianlatin]=Primljena je neočekivana veza, prekidam +Comment[sr@latin]=Primljena je neočekivana veza, prekidam +Comment[sv]=Tog emot oväntad anslutning, avbryter +Comment[ta]=எதிர்பாராத இணைப்பு, நிறுத்தப்பட்டது +Comment[tg]=Пайвастшавии ғайричашмдош қабул гардид, кандашавӣ +Comment[th]=ได้รับการเชื่อมต่อมาอย่างไม่คาดคิด ทำการยกเลิก +Comment[tr]=Beklenmeyen bir bağlantı alındı, vazgeçiliyor +Comment[ug]=ئويلاشمىغان باغلىنىشنى تاپشۇرۇۋالدى، توختات +Comment[uk]=Отримано з’єднання, яке не очікувалось, припиняється +Comment[xh]=Ufumene uxhulumaniso olungalindelekanga, lahla +Comment[x-test]=xxReceived unexpected connection, abortxx +Comment[zh_CN]=收到意外连接,已中止 +Comment[zh_HK]=接收到非預期的連線,中止 +Comment[zh_TW]=已接收到未知的連線,中止。 +Action=Popup diff --git a/krfb/krfb/krfb_rfb_handler.client b/krfb/krfb/krfb_rfb_handler.client new file mode 100644 index 00000000..07a26701 --- /dev/null +++ b/krfb/krfb/krfb_rfb_handler.client @@ -0,0 +1,7 @@ +[org.freedesktop.Telepathy.Client] +Interfaces=org.freedesktop.Telepathy.Client.Handler; + +[org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 0] +org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.StreamTube +org.freedesktop.Telepathy.Channel.Type.StreamTube.Service s=rfb +org.freedesktop.Telepathy.Channel.Requested b=true diff --git a/krfb/krfb/krfbconfig.kcfgc b/krfb/krfb/krfbconfig.kcfgc new file mode 100644 index 00000000..7bbb14fa --- /dev/null +++ b/krfb/krfb/krfbconfig.kcfgc @@ -0,0 +1,3 @@ +File=krfb.kcfg +ClassName=KrfbConfig +Singleton=true diff --git a/krfb/krfb/main.cpp b/krfb/krfb/main.cpp new file mode 100644 index 00000000..eb9952cc --- /dev/null +++ b/krfb/krfb/main.cpp @@ -0,0 +1,127 @@ +/*************************************************************************** + main.cpp + ------------------- + begin : Sat Dec 8 03:23:02 CET 2001 + copyright : (C) 2001-2003 by Tim Jansen + email : tim@tjansen.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "mainwindow.h" +#include "trayicon.h" +#include "invitationsrfbserver.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef KRFB_WITH_TELEPATHY_TUBES +# include "tubesrfbserver.h" +#endif + +#include +#include + +static const char description[] = I18N_NOOP("VNC-compatible server to share " + "KDE desktops"); + +static bool checkX11Capabilities() +{ + int bp1, bp2, majorv, minorv; + Bool r = XTestQueryExtension(QX11Info::display(), &bp1, &bp2, + &majorv, &minorv); + + if ((!r) || (((majorv * 1000) + minorv) < 2002)) { + KMessageBox::error(0, + i18n("Your X11 Server does not support the required XTest extension " + "version 2.2. Sharing your desktop is not possible."), + i18n("Desktop Sharing Error")); + return false; + } + + return true; +} + +int main(int argc, char *argv[]) +{ + KAboutData aboutData("krfb", 0, ki18n("Desktop Sharing"), KDE_VERSION_STRING, + ki18n(description), KAboutData::License_GPL, + ki18n("(c) 2009-2010, Collabora Ltd.\n" + "(c) 2007, Alessandro Praduroux\n" + "(c) 2001-2003, Tim Jansen\n" + "(c) 2001, Johannes E. Schindelin\n" + "(c) 2000-2001, Const Kaplinsky\n" + "(c) 2000, Tridia Corporation\n" + "(c) 1999, AT&T Laboratories Boston\n")); + aboutData.addAuthor(ki18n("George Goldberg"), + ki18n("Telepathy tubes support"), + "george.goldberg@collabora.co.uk"); + aboutData.addAuthor(ki18n("George Kiagiadakis"), + KLocalizedString(), + "george.kiagiadakis@collabora.co.uk"); + aboutData.addAuthor(ki18n("Alessandro Praduroux"), ki18n("KDE4 porting"), "pradu@pradu.it"); + aboutData.addAuthor(ki18n("Tim Jansen"), ki18n("Original author"), "tim@tjansen.de"); + aboutData.addCredit(ki18n("Johannes E. Schindelin"), + ki18n("libvncserver")); + aboutData.addCredit(ki18n("Const Kaplinsky"), + ki18n("TightVNC encoder")); + aboutData.addCredit(ki18n("Tridia Corporation"), + ki18n("ZLib encoder")); + aboutData.addCredit(ki18n("AT&T Laboratories Boston"), + ki18n("original VNC encoders and " + "protocol design")); + KCmdLineArgs::init(argc, argv, &aboutData); + + KCmdLineOptions options; + options.add("nodialog", ki18n("Do not show the invitations management dialog at startup")); + KCmdLineArgs::addCmdLineOptions(options); + + KUniqueApplication app; + app.setQuitOnLastWindowClosed(false); + + if (!checkX11Capabilities()) { + return 1; + } + + //init the core + InvitationsRfbServer::init(); + +#ifdef KRFB_WITH_TELEPATHY_TUBES + TubesRfbServer::init(); +#endif + + //init the GUI + MainWindow mainWindow; + TrayIcon trayicon(&mainWindow); + + if (app.isSessionRestored() && KMainWindow::canBeRestored(1)) { + mainWindow.restore(1, false); + } else if (KCmdLineArgs::parsedArgs()->isSet("dialog")) { + mainWindow.show(); + } + + sigset_t sigs; + sigemptyset(&sigs); + sigaddset(&sigs, SIGPIPE); + sigprocmask(SIG_BLOCK, &sigs, 0); + + return app.exec(); +} + diff --git a/krfb/krfb/mainwindow.cpp b/krfb/krfb/mainwindow.cpp new file mode 100644 index 00000000..55dc2af8 --- /dev/null +++ b/krfb/krfb/mainwindow.cpp @@ -0,0 +1,264 @@ +/* This file is part of the KDE project + Copyright (C) 2007 Alessandro Praduroux + Copyright (C) 2013 Amandeep Singh + + 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. +*/ +#include "mainwindow.h" +#include "invitationsrfbserver.h" + +#include "krfbconfig.h" +#include "ui_configtcp.h" +#include "ui_configsecurity.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef KRFB_WITH_KDE_TELEPATHY +#include "tubesrfbserver.h" +#include +#include +#include +#include +#include +#include +#endif + +class TCP: public QWidget, public Ui::TCP +{ +public: + TCP(QWidget *parent = 0) : QWidget(parent) { + setupUi(this); + } +}; + +class Security: public QWidget, public Ui::Security +{ +public: + Security(QWidget *parent = 0) : QWidget(parent) { + setupUi(this); + } +}; + + +MainWindow::MainWindow(QWidget *parent) + : KXmlGuiWindow(parent) +{ + setAttribute(Qt::WA_DeleteOnClose, false); + + m_passwordEditable = false; + m_passwordLineEdit = new KLineEdit(this); + m_passwordLineEdit->setVisible(false); + m_passwordLineEdit->setAlignment(Qt::AlignHCenter); + + QWidget *mainWidget = new QWidget; + m_ui.setupUi(mainWidget); + m_ui.krfbIconLabel->setPixmap(KIcon("krfb").pixmap(128)); + m_ui.enableUnattendedCheckBox->setChecked( + InvitationsRfbServer::instance->allowUnattendedAccess()); + + setCentralWidget(mainWidget); + + connect(m_ui.passwordEditButton,SIGNAL(clicked()), + this,SLOT(editPassword())); + connect(m_ui.enableSharingCheckBox,SIGNAL(toggled(bool)), + this, SLOT(toggleDesktopSharing(bool))); + connect(m_ui.enableUnattendedCheckBox, SIGNAL(toggled(bool)), + InvitationsRfbServer::instance, SLOT(toggleUnattendedAccess(bool))); + connect(m_ui.unattendedPasswordButton, SIGNAL(clicked()), + this, SLOT(editUnattendedPassword())); + connect(m_ui.addressAboutButton, SIGNAL(clicked()), + this, SLOT(aboutConnectionAddress())); + connect(m_ui.unattendedAboutButton, SIGNAL(clicked()), + this, SLOT(aboutUnattendedMode())); + connect(InvitationsRfbServer::instance, SIGNAL(passwordChanged(const QString&)), + this, SLOT(passwordChanged(const QString&))); + + // Figure out the address + int port = KrfbConfig::port(); + QList interfaceList = QNetworkInterface::allInterfaces(); + foreach(const QNetworkInterface & interface, interfaceList) { + if(interface.flags() & QNetworkInterface::IsLoopBack) + continue; + + if(interface.flags() & QNetworkInterface::IsRunning && + !interface.addressEntries().isEmpty()) + m_ui.addressDisplayLabel->setText(QString("%1 : %2") + .arg(interface.addressEntries().first().ip().toString()) + .arg(port)); + } + + //Figure out the password + m_ui.passwordDisplayLabel->setText( + InvitationsRfbServer::instance->desktopPassword()); + + +#ifdef KRFB_WITH_KDE_TELEPATHY + + m_contactViewWidget = new KTp::ContactViewWidget( + TubesRfbServer::instance->contactsListModel(), this); + + m_contactViewWidget->setEnabled(false); + connect(m_ui.enableSharingCheckBox, SIGNAL(toggled(bool)), + m_contactViewWidget, SLOT(setEnabled(bool))); + m_contactViewWidget->setIconSize(QSize(32,32)); + m_contactViewWidget->setMinimumWidth(120); + m_contactViewWidget->setMaximumWidth(360); + m_contactViewWidget->setMinimumHeight(300); + m_contactViewWidget->contactFilterLineEdit()->setClickMessage(i18n("Search in Contacts...")); + m_contactViewWidget->filter()->setPresenceTypeFilterFlags(KTp::ContactsFilterModel::ShowOnlyConnected); + m_contactViewWidget->filter()->setTubesFilterStrings(QStringList("rfb")); + m_contactViewWidget->filter()->setCapabilityFilterFlags(KTp::ContactsFilterModel::FilterByTubes); + + m_contactViewWidget->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding)); + m_ui.tpContactsLayout->addWidget(m_contactViewWidget); + connect(m_contactViewWidget, SIGNAL(contactDoubleClicked(const Tp::AccountPtr &, const KTp::ContactPtr &)), + this, SLOT(onContactDoubleClicked(const Tp::AccountPtr &, const KTp::ContactPtr &))); +#endif + + + KStandardAction::quit(QCoreApplication::instance(), SLOT(quit()), actionCollection()); + KStandardAction::preferences(this, SLOT(showConfiguration()), actionCollection()); + + setupGUI(); + + setAutoSaveSettings(); +} + +MainWindow::~MainWindow() +{ +} + +void MainWindow::editPassword() +{ + if(m_passwordEditable) { + m_passwordEditable = false; + m_ui.passwordEditButton->setIcon(KIcon("document-properties")); + m_ui.passwordGridLayout->removeWidget(m_passwordLineEdit); + InvitationsRfbServer::instance->setDesktopPassword( + m_passwordLineEdit->text()); + m_ui.passwordDisplayLabel->setText( + InvitationsRfbServer::instance->desktopPassword()); + m_passwordLineEdit->setVisible(false); + } else { + m_passwordEditable = true; + m_ui.passwordEditButton->setIcon(KIcon("document-save")); + m_ui.passwordGridLayout->addWidget(m_passwordLineEdit,0,0); + m_passwordLineEdit->setText( + InvitationsRfbServer::instance->desktopPassword()); + m_passwordLineEdit->setVisible(true); + m_passwordLineEdit->setFocus(Qt::MouseFocusReason); + } +} + +void MainWindow::editUnattendedPassword() +{ + KNewPasswordDialog dialog(this); + dialog.setPrompt(i18n("Enter a new password for Unattended Access")); + if(dialog.exec()) { + InvitationsRfbServer::instance->setUnattendedPassword(dialog.password()); + } +} + +void MainWindow::toggleDesktopSharing(bool enable) +{ + if(enable) { + if(!InvitationsRfbServer::instance->start()) { + KMessageBox::error(this, + i18n("Failed to start the krfb server. Desktop sharing " + "will not work. Try setting another port in the settings " + "and restart krfb.")); + } + } else { + InvitationsRfbServer::instance->stop(); + if(m_passwordEditable) { + m_passwordEditable = false; + m_passwordLineEdit->setVisible(false); + m_ui.passwordEditButton->setIcon(KIcon("document-properties")); + } + } +} + +void MainWindow::passwordChanged(const QString& password) +{ + m_passwordLineEdit->setText(password); + m_ui.passwordDisplayLabel->setText(password); +} + +void MainWindow::aboutConnectionAddress() +{ + KMessageBox::about(this, + i18n("This field contains the address of your computer and the port number, separated by a colon.\n\nThe address is just a hint - you can use any address that can reach your computer.\n\nDesktop Sharing tries to guess your address from your network configuration, but does not always succeed in doing so.\n\nIf your computer is behind a firewall it may have a different address or be unreachable for other computers."), + i18n("KDE Desktop Sharing")); +} + +void MainWindow::aboutUnattendedMode() +{ + KMessageBox::about(this, + i18n("Any remote user with normal desktop sharing password will have to be authenticated.\n\nIf unattended access is on, and the remote user provides unattended mode password, desktop sharing access will be granted without explicit confirmation."), + i18n("KDE Desktop Sharing")); +} + +#ifdef KRFB_WITH_KDE_TELEPATHY + +void MainWindow::onContactDoubleClicked(const Tp::AccountPtr &account, const KTp::ContactPtr &contact) +{ + Tp::PendingOperation *op = KTp::Actions::startDesktopSharing(account, contact); + connect(op, SIGNAL(finished(Tp::PendingOperation*)), + this, SLOT(pendingDesktopShareFinished(Tp::PendingOperation*))); +} + +void MainWindow::pendingDesktopShareFinished(Tp::PendingOperation *operation) +{ + if(operation->isError()) { + KMessageBox::error(this, + operation->errorName() + ": " + operation->errorMessage()); + } +} + +#endif + +void MainWindow::showConfiguration() +{ + if (KConfigDialog::showDialog("settings")) { + return; + } + + KConfigDialog *dialog = new KConfigDialog(this, "settings", KrfbConfig::self()); + dialog->addPage(new TCP, i18n("Network"), "network-workgroup"); + dialog->addPage(new Security, i18n("Security"), "security-high"); + dialog->setHelp(QString(), "krfb"); + dialog->show(); +} + +void MainWindow::readProperties(const KConfigGroup& group) +{ + if (group.readEntry("Visible", true)) { + show(); + } + KMainWindow::readProperties(group); +} + +void MainWindow::saveProperties(KConfigGroup& group) +{ + group.writeEntry("Visible", isVisible()); + KMainWindow::saveProperties(group); +} + +#include "mainwindow.moc" diff --git a/krfb/krfb/mainwindow.h b/krfb/krfb/mainwindow.h new file mode 100644 index 00000000..97b8a5a8 --- /dev/null +++ b/krfb/krfb/mainwindow.h @@ -0,0 +1,68 @@ +/* This file is part of the KDE project + Copyright (C) 2007 Alessandro Praduroux + Copyright (C) 2013 Amandeep Singh + + 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. +*/ + +#ifndef MANAGEINVITATIONSDIALOG_H +#define MANAGEINVITATIONSDIALOG_H + +#include "ui_mainwidget.h" + +#include + +#ifdef KRFB_WITH_KDE_TELEPATHY +#include +#include +namespace KTp { + class ContactViewWidget; +} +namespace Tp { + class PendingOperation; +} +#endif + +class KLineEdit; + +class MainWindow : public KXmlGuiWindow +{ + Q_OBJECT + + public: + MainWindow(QWidget *parent = 0); + ~MainWindow(); + + public Q_SLOTS: + void showConfiguration(); + + protected: + virtual void readProperties(const KConfigGroup & group); + virtual void saveProperties(KConfigGroup & group); + + private Q_SLOTS: + void editPassword(); + void editUnattendedPassword(); + void toggleDesktopSharing(bool enable); + void passwordChanged(const QString&); + void aboutConnectionAddress(); + void aboutUnattendedMode(); +#ifdef KRFB_WITH_KDE_TELEPATHY + void onContactDoubleClicked(const Tp::AccountPtr &, const KTp::ContactPtr &); + void pendingDesktopShareFinished(Tp::PendingOperation*); +#endif + + private: + Ui::MainWidget m_ui; + bool m_passwordEditable; + KLineEdit *m_passwordLineEdit; +#ifdef KRFB_WITH_KDE_TELEPATHY + KTp::ContactViewWidget *m_contactViewWidget; +#endif + +}; + +#endif diff --git a/krfb/krfb/org.freedesktop.Telepathy.Client.krfb_rfb_handler.service.in b/krfb/krfb/org.freedesktop.Telepathy.Client.krfb_rfb_handler.service.in new file mode 100644 index 00000000..46189632 --- /dev/null +++ b/krfb/krfb/org.freedesktop.Telepathy.Client.krfb_rfb_handler.service.in @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.freedesktop.Telepathy.Client.krfb_rfb_handler +Exec=@CMAKE_INSTALL_PREFIX@/bin/krfb --nodialog diff --git a/krfb/krfb/rfb.h b/krfb/krfb/rfb.h new file mode 100644 index 00000000..fa94edad --- /dev/null +++ b/krfb/krfb/rfb.h @@ -0,0 +1,15 @@ +/** + * This file should always be included instead of because otherwise it's redefinition + * of TRUE and FALSE plays havoc with other things. + */ + +#ifndef KRFB_RFB_H +#define KRFB_RFB_H + +#include "rfb/rfb.h" + +#undef TRUE +#undef FALSE + +#endif // Header guard + diff --git a/krfb/krfb/rfbclient.cpp b/krfb/krfb/rfbclient.cpp new file mode 100644 index 00000000..dc002d41 --- /dev/null +++ b/krfb/krfb/rfbclient.cpp @@ -0,0 +1,233 @@ +/* + Copyright (C) 2009-2010 Collabora Ltd + @author George Goldberg + @author George Kiagiadakis + Copyright (C) 2007 Alessandro Praduroux + + 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 Lesser General Public License + along with this program. If not, see . +*/ +#include "rfbclient.h" +#include "connectiondialog.h" +#include "krfbconfig.h" +#include "sockethelpers.h" +#include "events.h" +#include +#include +#include +#include +#include //for bzero() + +struct RfbClient::Private +{ + Private(rfbClientPtr client) : + controlEnabled(KrfbConfig::allowDesktopControl()), + client(client) + {} + + bool controlEnabled; + rfbClientPtr client; + QSocketNotifier *notifier; + QString remoteAddressString; +}; + +RfbClient::RfbClient(rfbClientPtr client, QObject* parent) + : QObject(parent), d(new Private(client)) +{ + d->remoteAddressString = peerAddress(d->client->sock) + ":" + + QString::number(peerPort(d->client->sock)); + + d->notifier = new QSocketNotifier(client->sock, QSocketNotifier::Read, this); + d->notifier->setEnabled(false); + connect(d->notifier, SIGNAL(activated(int)), this, SLOT(onSocketActivated())); +} + +RfbClient::~RfbClient() +{ + kDebug(); + delete d; +} + +QString RfbClient::name() const +{ + return d->remoteAddressString; +} + +//static +bool RfbClient::controlCanBeEnabled() +{ + return KrfbConfig::allowDesktopControl(); +} + +bool RfbClient::controlEnabled() const +{ + return d->controlEnabled; +} + +void RfbClient::setControlEnabled(bool enabled) +{ + if (controlCanBeEnabled() && d->controlEnabled != enabled) { + d->controlEnabled = enabled; + Q_EMIT controlEnabledChanged(enabled); + } +} + +bool RfbClient::isOnHold() const +{ + return d->client->onHold ? true : false; +} + +void RfbClient::setOnHold(bool onHold) +{ + if (isOnHold() != onHold) { + d->client->onHold = onHold; + d->notifier->setEnabled(!onHold); + Q_EMIT holdStatusChanged(onHold); + } +} + +void RfbClient::closeConnection() +{ + d->notifier->setEnabled(false); + rfbCloseClient(d->client); + rfbClientConnectionGone(d->client); +} + +rfbClientPtr RfbClient::getRfbClientPtr() +{ + return d->client; +} + +void RfbClient::handleKeyboardEvent(bool down, rfbKeySym keySym) +{ + if (d->controlEnabled) { + EventHandler::handleKeyboard(down, keySym); + } +} + +void RfbClient::handleMouseEvent(int buttonMask, int x, int y) +{ + if (d->controlEnabled) { + EventHandler::handlePointer(buttonMask, x, y); + } +} + +void RfbClient::onSocketActivated() +{ + //Process not only one, but all pending messages. + //poll() idea/code copied from vino: + // Copyright (C) 2003 Sun Microsystems, Inc. + // License: GPL v2 or later + struct pollfd pollfd = { d->client->sock, POLLIN|POLLPRI, 0 }; + + while(poll(&pollfd, 1, 0) == 1) { + rfbProcessClientMessage(d->client); + + //This is how we handle disconnection. + //if rfbProcessClientMessage() finds out that it can't read the socket, + //it closes it and sets it to -1. So, we just have to check this here + //and call rfbClientConnectionGone() if necessary. This will call + //the clientGoneHook which in turn will remove this RfbClient instance + //from the server manager and will call deleteLater() to delete it + if (d->client->sock == -1) { + kDebug() << "disconnected from socket signal"; + d->notifier->setEnabled(false); + rfbClientConnectionGone(d->client); + break; + } + } +} + +void RfbClient::update() +{ + rfbUpdateClient(d->client); + + //This is how we handle disconnection. + //if rfbUpdateClient() finds out that it can't write to the socket, + //it closes it and sets it to -1. So, we just have to check this here + //and call rfbClientConnectionGone() if necessary. This will call + //the clientGoneHook which in turn will remove this RfbClient instance + //from the server manager and will call deleteLater() to delete it + if (d->client->sock == -1) { + kDebug() << "disconnected during update"; + d->notifier->setEnabled(false); + rfbClientConnectionGone(d->client); + } +} + +//************* + +PendingRfbClient::PendingRfbClient(rfbClientPtr client, QObject *parent) + : QObject(parent), m_rfbClient(client) +{ + m_rfbClient->clientData = this; +} + +PendingRfbClient::~PendingRfbClient() +{} + +void PendingRfbClient::accept(RfbClient *newClient) +{ + kDebug() << "accepted connection"; + + m_rfbClient->clientData = newClient; + newClient->setOnHold(false); + + Q_EMIT finished(newClient); + deleteLater(); +} + +static void clientGoneHookNoop(rfbClientPtr cl) { Q_UNUSED(cl); } + +void PendingRfbClient::reject() +{ + kDebug() << "refused connection"; + + //override the clientGoneHook that was previously set by RfbServer + m_rfbClient->clientGoneHook = clientGoneHookNoop; + rfbCloseClient(m_rfbClient); + rfbClientConnectionGone(m_rfbClient); + + Q_EMIT finished(NULL); + deleteLater(); +} + +bool PendingRfbClient::checkPassword(const QByteArray & encryptedPassword) +{ + Q_UNUSED(encryptedPassword); + + return m_rfbClient->screen->authPasswdData == (void*)0; +} + +bool PendingRfbClient::vncAuthCheckPassword(const QByteArray& password, const QByteArray& encryptedPassword) const +{ + if (password.isEmpty() && encryptedPassword.isEmpty()) { + return true; + } + + char passwd[MAXPWLEN]; + unsigned char challenge[CHALLENGESIZE]; + + memcpy(challenge, m_rfbClient->authChallenge, CHALLENGESIZE); + bzero(passwd, MAXPWLEN); + + if (!password.isEmpty()) { + strncpy(passwd, password, + (MAXPWLEN <= password.size()) ? MAXPWLEN : password.size()); + } + + rfbEncryptBytes(challenge, passwd); + return memcmp(challenge, encryptedPassword, encryptedPassword.size()) == 0; +} + +#include "rfbclient.moc" diff --git a/krfb/krfb/rfbclient.h b/krfb/krfb/rfbclient.h new file mode 100644 index 00000000..9c43f01a --- /dev/null +++ b/krfb/krfb/rfbclient.h @@ -0,0 +1,109 @@ +/* + Copyright (C) 2009-2010 Collabora Ltd + @author George Goldberg + @author George Kiagiadakis + Copyright (C) 2007 Alessandro Praduroux + + 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 Lesser General Public License + along with this program. If not, see . +*/ +#ifndef RFBCLIENT_H +#define RFBCLIENT_H + +#include "rfb.h" +#include + +class RfbClient : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool controlEnabled READ controlEnabled WRITE setControlEnabled NOTIFY controlEnabledChanged) + Q_PROPERTY(bool onHold READ isOnHold WRITE setOnHold NOTIFY holdStatusChanged) +public: + RfbClient(rfbClientPtr client, QObject *parent = 0); + virtual ~RfbClient(); + + /** Returns a name for the client, to be shown to the user */ + virtual QString name() const; + + static bool controlCanBeEnabled(); + bool controlEnabled() const; + bool isOnHold() const; + +public Q_SLOTS: + void setControlEnabled(bool enabled); + void setOnHold(bool onHold); + void closeConnection(); + +Q_SIGNALS: + void controlEnabledChanged(bool enabled); + void holdStatusChanged(bool onHold); + +protected: + friend class RfbServer; //the following event handling methods are called by RfbServer + + rfbClientPtr getRfbClientPtr(); + virtual void handleKeyboardEvent(bool down, rfbKeySym keySym); + virtual void handleMouseEvent(int buttonMask, int x, int y); + +private Q_SLOTS: + void onSocketActivated(); + +private: + ///called by RfbServerManager to send framebuffer updates + ///and check for possible disconnection + void update(); + friend class RfbServerManager; + + struct Private; + Private *const d; +}; + + +class PendingRfbClient : public QObject +{ + Q_OBJECT +public: + PendingRfbClient(rfbClientPtr client, QObject *parent = 0); + virtual ~PendingRfbClient(); + +Q_SIGNALS: + void finished(RfbClient *client); + +protected Q_SLOTS: + virtual void processNewClient() = 0; + + void accept(RfbClient *newClient); + void reject(); + +protected: + + friend class RfbServer; //Following two methods are handled by RfbServer + + /** This method is supposed to check if the provided \a encryptedPassword + * matches the criteria for authenticating the client. + * The default implementation returns false if a password is required. + * Reimplement to do more useful stuff. + */ + virtual bool checkPassword(const QByteArray & encryptedPassword); + + /** This method checks if the \a encryptedPassword that was sent from the remote + * user matches the \a password that you have specified localy to be the password + * for this connection. This assumes that the standard VNC authentication mechanism + * is used. Returns true if the password matches or false otherwise. + */ + bool vncAuthCheckPassword(const QByteArray & password, const QByteArray & encryptedPassword) const; + + rfbClientPtr m_rfbClient; +}; + +#endif // RFBCLIENT_H diff --git a/krfb/krfb/rfbserver.cpp b/krfb/krfb/rfbserver.cpp new file mode 100644 index 00000000..f8d0b456 --- /dev/null +++ b/krfb/krfb/rfbserver.cpp @@ -0,0 +1,281 @@ +/* + Copyright (C) 2009-2010 Collabora Ltd + @author George Goldberg + @author George Kiagiadakis + Copyright (C) 2007 Alessandro Praduroux + + 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 Lesser General Public License + along with this program. If not, see . +*/ +#include "rfbserver.h" +#include "rfbservermanager.h" +#include +#include +#include +#include + +struct RfbServer::Private +{ + QByteArray listeningAddress; + int listeningPort; + bool passwordRequired; + rfbScreenInfoPtr screen; + QSocketNotifier *notifier; +}; + +RfbServer::RfbServer(QObject *parent) + : QObject(parent), d(new Private) +{ + d->listeningAddress = "0.0.0.0"; + d->listeningPort = 0; + d->passwordRequired = true; + d->screen = NULL; + d->notifier = NULL; + + RfbServerManager::instance()->registerServer(this); +} + +RfbServer::~RfbServer() +{ + if (d->screen) { + rfbScreenCleanup(d->screen); + } + delete d; + + RfbServerManager::instance()->unregisterServer(this); +} + +QByteArray RfbServer::listeningAddress() const +{ + return d->listeningAddress; +} + +int RfbServer::listeningPort() const +{ + return d->listeningPort; +} + +bool RfbServer::passwordRequired() const +{ + return d->passwordRequired; +} + +void RfbServer::setListeningAddress(const QByteArray& address) +{ + d->listeningAddress = address; +} + +void RfbServer::setListeningPort(int port) +{ + d->listeningPort = port; +} + +void RfbServer::setPasswordRequired(bool passwordRequired) +{ + d->passwordRequired = passwordRequired; +} + +bool RfbServer::start() +{ + if (!d->screen) { + d->screen = RfbServerManager::instance()->newScreen(); + if (!d->screen) { + return false; + } + + // server hooks + d->screen->screenData = this; + d->screen->newClientHook = newClientHook; + d->screen->kbdAddEvent = keyboardHook; + d->screen->ptrAddEvent = pointerHook; + d->screen->passwordCheck = passwordCheck; + d->screen->setXCutText = clipboardHook; + } else { + //if we already have a screen, stop listening first + rfbShutdownServer(d->screen, false); + } + + if (listeningAddress() != "0.0.0.0") { + strncpy(d->screen->thisHost, listeningAddress().data(), 254); + } + + if (listeningPort() == 0) { + d->screen->autoPort = 1; + } + + d->screen->port = listeningPort(); + + // Disable/Enable password checking + if (passwordRequired()) { + d->screen->authPasswdData = (void *)1; + } else { + d->screen->authPasswdData = (void *)0; + } + + kDebug() << "Starting server. Listen port:" << listeningPort() + << "Listen Address:" << listeningAddress() + << "Password enabled:" << passwordRequired(); + + rfbInitServer(d->screen); + + if (!rfbIsActive(d->screen)) { + kDebug() << "Failed to start server"; + rfbShutdownServer(d->screen, false); + return false; + }; + + d->notifier = new QSocketNotifier(d->screen->listenSock, QSocketNotifier::Read, this); + d->notifier->setEnabled(true); + connect(d->notifier, SIGNAL(activated(int)), this, SLOT(onListenSocketActivated())); + connect(QApplication::clipboard(), SIGNAL(dataChanged()), + this, SLOT(krfbSendServerCutText())); + + return true; +} + +void RfbServer::stop(bool disconnectClients) +{ + if (d->screen) { + rfbShutdownServer(d->screen, disconnectClients); + if (d->notifier) { + d->notifier->setEnabled(false); + d->notifier->deleteLater(); + d->notifier = NULL; + } + } +} + +void RfbServer::updateScreen(const QList & modifiedTiles) +{ + if (d->screen) { + QList::const_iterator it = modifiedTiles.constBegin(); + for(; it != modifiedTiles.constEnd(); ++it) { + rfbMarkRectAsModified(d->screen, it->x(), it->y(), it->right(), it->bottom()); + } + } +} + +/* + * Code copied from vino's bundled libvncserver: + * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved. + * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. + * License: GPL v2 or later + */ +void krfb_rfbSetCursorPosition(rfbScreenInfoPtr screen, rfbClientPtr client, int x, int y) +{ + rfbClientIteratorPtr iterator; + rfbClientPtr cl; + + if (x == screen->cursorX || y == screen->cursorY) + return; + + LOCK(screen->cursorMutex); + screen->cursorX = x; + screen->cursorY = y; + UNLOCK(screen->cursorMutex); + + /* Inform all clients about this cursor movement. */ + iterator = rfbGetClientIterator(screen); + while ((cl = rfbClientIteratorNext(iterator)) != NULL) { + cl->cursorWasMoved = TRUE; + } + rfbReleaseClientIterator(iterator); + + /* The cursor was moved by this client, so don't send CursorPos. */ + if (client) { + client->cursorWasMoved = FALSE; + } +} + +void RfbServer::updateCursorPosition(const QPoint & position) +{ + if (d->screen) { + krfb_rfbSetCursorPosition(d->screen, NULL, position.x(), position.y()); + } +} + +void RfbServer::krfbSendServerCutText() +{ + if(d->screen) { + QString text = QApplication::clipboard()->text(); + rfbSendServerCutText(d->screen, + text.toLocal8Bit().data(),text.length()); + } +} + +void RfbServer::onListenSocketActivated() +{ + rfbProcessNewConnection(d->screen); +} + +void RfbServer::pendingClientFinished(RfbClient *client) +{ + kDebug(); + if (client) { + RfbServerManager::instance()->addClient(client); + client->getRfbClientPtr()->clientGoneHook = clientGoneHook; + } +} + +//static +rfbNewClientAction RfbServer::newClientHook(rfbClientPtr cl) +{ + kDebug() << "New client"; + RfbServer *server = static_cast(cl->screen->screenData); + + PendingRfbClient *pendingClient = server->newClient(cl); + connect(pendingClient, SIGNAL(finished(RfbClient*)), + server, SLOT(pendingClientFinished(RfbClient*))); + + return RFB_CLIENT_ON_HOLD; +} + +//static +void RfbServer::clientGoneHook(rfbClientPtr cl) +{ + kDebug() << "client gone"; + RfbClient *client = static_cast(cl->clientData); + + RfbServerManager::instance()->removeClient(client); + client->deleteLater(); +} + +//static +rfbBool RfbServer::passwordCheck(rfbClientPtr cl, const char *encryptedPassword, int len) +{ + PendingRfbClient *client = static_cast(cl->clientData); + Q_ASSERT(client); + return client->checkPassword(QByteArray::fromRawData(encryptedPassword, len)); +} + +//static +void RfbServer::keyboardHook(rfbBool down, rfbKeySym keySym, rfbClientPtr cl) +{ + RfbClient *client = static_cast(cl->clientData); + client->handleKeyboardEvent(down ? true : false, keySym); +} + +//static +void RfbServer::pointerHook(int bm, int x, int y, rfbClientPtr cl) +{ + RfbClient *client = static_cast(cl->clientData); + client->handleMouseEvent(bm, x, y); +} + +//static +void RfbServer::clipboardHook(char *str, int len, rfbClientPtr cl) +{ + QApplication::clipboard()->setText(QString::fromLocal8Bit(str,len)); +} + +#include "rfbserver.moc" diff --git a/krfb/krfb/rfbserver.h b/krfb/krfb/rfbserver.h new file mode 100644 index 00000000..6a9fe397 --- /dev/null +++ b/krfb/krfb/rfbserver.h @@ -0,0 +1,72 @@ +/* + Copyright (C) 2009-2010 Collabora Ltd + @author George Goldberg + @author George Kiagiadakis + Copyright (C) 2007 Alessandro Praduroux + + 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 Lesser General Public License + along with this program. If not, see . +*/ +#ifndef RFBSERVER_H +#define RFBSERVER_H + +#include "rfb.h" +#include "rfbclient.h" +#include + +class RfbServer : public QObject +{ + Q_OBJECT +public: + RfbServer(QObject *parent = 0); + virtual ~RfbServer(); + + QByteArray listeningAddress() const; + int listeningPort() const; + bool passwordRequired() const; + + void setListeningAddress(const QByteArray & address); + void setListeningPort(int port); + void setPasswordRequired(bool passwordRequired); + +public Q_SLOTS: + virtual bool start(); + virtual void stop(bool disconnectClients = true); + + void updateScreen(const QList & modifiedTiles); + void updateCursorPosition(const QPoint & position); + +private Q_SLOTS: + void krfbSendServerCutText(); + void onListenSocketActivated(); + void pendingClientFinished(RfbClient *client); + +protected: + virtual PendingRfbClient *newClient(rfbClientPtr client) = 0; + +private: + static rfbNewClientAction newClientHook(rfbClientPtr cl); + static void clientGoneHook(rfbClientPtr cl); + + static rfbBool passwordCheck(rfbClientPtr cl, const char *encryptedPassword, int len); + static void keyboardHook(rfbBool down, rfbKeySym keySym, rfbClientPtr cl); + static void pointerHook(int bm, int x, int y, rfbClientPtr cl); + static void clipboardHook(char *str, int len, rfbClientPtr cl); + + Q_DISABLE_COPY(RfbServer) + + struct Private; + Private *const d; +}; + +#endif // RFBSERVER_H diff --git a/krfb/krfb/rfbservermanager.cpp b/krfb/krfb/rfbservermanager.cpp new file mode 100644 index 00000000..6447b96d --- /dev/null +++ b/krfb/krfb/rfbservermanager.cpp @@ -0,0 +1,235 @@ +/* + Copyright (C) 2009-2010 Collabora Ltd + @author George Goldberg + @author George Kiagiadakis + Copyright (C) 2007 Alessandro Praduroux + Copyright (C) 2001-2003 by Tim Jansen + + 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 Lesser General Public License + along with this program. If not, see . +*/ +#include "rfbservermanager.h" +#include "rfbserver.h" +#include "framebuffer.h" +#include "framebuffermanager.h" +#include "sockethelpers.h" +#include "krfbconfig.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char *cur = + " " + " x " + " xx " + " xxx " + " xxxx " + " xxxxx " + " xxxxxx " + " xxxxxxx " + " xxxxxxxx " + " xxxxxxxxx " + " xxxxxxxxxx " + " xxxxx " + " xx xxx " + " x xxx " + " xxx " + " xxx " + " xxx " + " xxx " + " "; + +static const char *mask = + "xx " + "xxx " + "xxxx " + "xxxxx " + "xxxxxx " + "xxxxxxx " + "xxxxxxxx " + "xxxxxxxxx " + "xxxxxxxxxx " + "xxxxxxxxxxx " + "xxxxxxxxxxxx " + "xxxxxxxxxx " + "xxxxxxxx " + "xxxxxxxx " + "xx xxxxx " + " xxxxx " + " xxxxx " + " xxxxx " + " xxx "; + + +struct RfbServerManagerStatic +{ + RfbServerManager server; +}; + +K_GLOBAL_STATIC(RfbServerManagerStatic, s_instance) + +RfbServerManager* RfbServerManager::instance() +{ + return &s_instance->server; +} + + +struct RfbServerManager::Private +{ + QSharedPointer fb; + rfbCursorPtr myCursor; + QByteArray desktopName; + QTimer rfbUpdateTimer; + QSet servers; + QSet clients; +}; + + +RfbServerManager::RfbServerManager() + : QObject(), d(new Private) +{ + init(); +} + +RfbServerManager::~RfbServerManager() +{ + delete d; +} + +void RfbServerManager::init() +{ + kDebug(); + + d->fb = FrameBufferManager::instance()->frameBuffer(QApplication::desktop()->winId()); + d->myCursor = rfbMakeXCursor(19, 19, (char *) cur, (char *) mask); + d->myCursor->cleanup = false; + d->desktopName = QString("%1@%2 (shared desktop)") //FIXME check if we can use utf8 + .arg(KUser().loginName(),QHostInfo::localHostName()).toLatin1(); + + connect(&d->rfbUpdateTimer, SIGNAL(timeout()), SLOT(updateScreens())); + connect(qApp, SIGNAL(aboutToQuit()), SLOT(cleanup())); +} + +void RfbServerManager::updateScreens() +{ + QList rects = d->fb->modifiedTiles(); + QPoint currentCursorPos = QCursor::pos(); + + Q_FOREACH(RfbServer *server, d->servers) { + server->updateScreen(rects); + server->updateCursorPosition(currentCursorPos); + } + + //update() might disconnect some of the clients, which will synchronously + //call the removeClient() method and will change d->clients, so we need + //to copy the set here to avoid problems. + QSet clients = d->clients; + Q_FOREACH(RfbClient *client, clients) { + client->update(); + } +} + +void RfbServerManager::cleanup() +{ + kDebug(); + + //copy because d->servers is going to be modified while we delete the servers + QSet servers = d->servers; + Q_FOREACH(RfbServer *server, servers) { + delete server; + } + + Q_ASSERT(d->servers.isEmpty()); + Q_ASSERT(d->clients.isEmpty()); + + d->myCursor->cleanup = true; + rfbFreeCursor(d->myCursor); + d->fb.clear(); +} + +void RfbServerManager::registerServer(RfbServer* server) +{ + d->servers.insert(server); +} + +void RfbServerManager::unregisterServer(RfbServer* server) +{ + d->servers.remove(server); +} + +rfbScreenInfoPtr RfbServerManager::newScreen() +{ + rfbScreenInfoPtr screen = NULL; + + if (!d->fb.isNull()) { + int w = d->fb->width(); + int h = d->fb->height(); + int depth = d->fb->depth(); + int bpp = depth >> 3; + + if (bpp != 1 && bpp != 2 && bpp != 4) { + bpp = 4; + } + + kDebug() << "bpp: " << bpp; + + rfbLogEnable(0); + + screen = rfbGetScreen(0, 0, w, h, 8, 3, bpp); + screen->paddedWidthInBytes = d->fb->paddedWidth(); + d->fb->getServerFormat(screen->serverFormat); + screen->frameBuffer = d->fb->data(); + + screen->desktopName = d->desktopName.constData(); + screen->cursor = d->myCursor; + } + + return screen; +} + +void RfbServerManager::addClient(RfbClient* cc) +{ + if (d->clients.size() == 0) { + kDebug() << "Starting framebuffer monitor"; + d->fb->startMonitor(); + d->rfbUpdateTimer.start(50); + } + d->clients.insert(cc); + + KNotification::event("UserAcceptsConnection", + i18n("The remote user %1 is now connected.", cc->name())); + + Q_EMIT clientConnected(cc); +} + +void RfbServerManager::removeClient(RfbClient* cc) +{ + d->clients.remove(cc); + if (d->clients.size() == 0) { + kDebug() << "Stopping framebuffer monitor"; + d->fb->stopMonitor(); + d->rfbUpdateTimer.stop(); + } + + KNotification::event("ConnectionClosed", i18n("The remote user %1 disconnected.", cc->name())); + + Q_EMIT clientDisconnected(cc); +} + +#include "rfbservermanager.moc" diff --git a/krfb/krfb/rfbservermanager.h b/krfb/krfb/rfbservermanager.h new file mode 100644 index 00000000..7790458c --- /dev/null +++ b/krfb/krfb/rfbservermanager.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2009-2010 Collabora Ltd + @author George Goldberg + @author George Kiagiadakis + Copyright (C) 2007 Alessandro Praduroux + + 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 Lesser General Public License + along with this program. If not, see . +*/ +#ifndef RFBSERVERMANAGER_H +#define RFBSERVERMANAGER_H + +#include "rfb.h" +#include + +class RfbClient; +class RfbServerManagerStatic; +class RfbServer; + +class RfbServerManager : public QObject +{ + Q_OBJECT +public: + static RfbServerManager *instance(); + +Q_SIGNALS: + void clientConnected(RfbClient *cc); + void clientDisconnected(RfbClient *cc); + +private Q_SLOTS: + void init(); + void updateScreens(); + void cleanup(); + +private: + void registerServer(RfbServer *server); + void unregisterServer(RfbServer *server); + + rfbScreenInfoPtr newScreen(); + + void addClient(RfbClient *cc); + void removeClient(RfbClient *cc); + + RfbServerManager(); + virtual ~RfbServerManager(); + Q_DISABLE_COPY(RfbServerManager) + + friend class RfbServer; + friend class RfbServerManagerStatic; + + struct Private; + Private *const d; +}; + +#endif // RFBSERVERMANAGER_H diff --git a/krfb/krfb/sockethelpers.cpp b/krfb/krfb/sockethelpers.cpp new file mode 100644 index 00000000..97fcc87b --- /dev/null +++ b/krfb/krfb/sockethelpers.cpp @@ -0,0 +1,106 @@ +/* This file is part of the KDE project + Copyright (C) 2009 Collabora Ltd + @author George Goldberg + Copyright (C) 2007 Alessandro Praduroux + Copyright (C) 2001-2003 by Tim Jansen + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "sockethelpers.h" + +#include +#include +#include + +QString peerAddress(int sock) +{ + + const int ADDR_SIZE = 50; + struct sockaddr sa; + socklen_t salen = sizeof(struct sockaddr); + + if (getpeername(sock, &sa, &salen) == 0) { + if (sa.sa_family == AF_INET) { + struct sockaddr_in *si = (struct sockaddr_in *)&sa; + return QString(inet_ntoa(si->sin_addr)); + } + + if (sa.sa_family == AF_INET6) { + char inetbuf[ADDR_SIZE]; + inet_ntop(sa.sa_family, &sa, inetbuf, ADDR_SIZE); + return QString(inetbuf); + } + + return QString("not a network address"); + } + + return QString("unable to determine..."); +} + +unsigned short peerPort(int sock) +{ + + struct sockaddr sa; + socklen_t salen = sizeof(struct sockaddr); + + if (getpeername(sock, &sa, &salen) == 0) { + struct sockaddr_in *si = (struct sockaddr_in *)&sa; + return ntohs(si->sin_port); + } + + return 0; +} + +QString localAddress(int sock) +{ + + const int ADDR_SIZE = 50; + struct sockaddr sa; + socklen_t salen = sizeof(struct sockaddr); + + if (getsockname(sock, &sa, &salen) == 0) { + if (sa.sa_family == AF_INET) { + struct sockaddr_in *si = (struct sockaddr_in *)&sa; + return QString(inet_ntoa(si->sin_addr)); + } + + if (sa.sa_family == AF_INET6) { + char inetbuf[ADDR_SIZE]; + inet_ntop(sa.sa_family, &sa, inetbuf, ADDR_SIZE); + return QString(inetbuf); + } + + return QString("not a network address"); + } + + return QString("unable to determine..."); +} + +unsigned short localPort(int sock) +{ + + struct sockaddr sa; + socklen_t salen = sizeof(struct sockaddr); + + if (getsockname(sock, &sa, &salen) == 0) { + struct sockaddr_in *si = (struct sockaddr_in *)&sa; + return ntohs(si->sin_port); + } + + return 0; +} + diff --git a/krfb/krfb/sockethelpers.h b/krfb/krfb/sockethelpers.h new file mode 100644 index 00000000..dae2dccd --- /dev/null +++ b/krfb/krfb/sockethelpers.h @@ -0,0 +1,30 @@ +/* This file is part of the KDE project + Copyright (C) 2009 Collabora Ltd + @author George Goldberg + Copyright (C) 2007 Alessandro Praduroux + Copyright (C) 2001-2003 by Tim Jansen + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include + +QString peerAddress(int sock); +unsigned short peerPort(int sock); + +QString localAddress(int sock); +unsigned short localPort(int sock); + diff --git a/krfb/krfb/trayicon.cpp b/krfb/krfb/trayicon.cpp new file mode 100644 index 00000000..eb6df8a4 --- /dev/null +++ b/krfb/krfb/trayicon.cpp @@ -0,0 +1,152 @@ +/* + Copyright (C) 2010 Collabora Ltd + @author George Kiagiadakis + Copyright (C) 2001-2002 Tim Jansen + + 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 Lesser General Public License + along with this program. If not, see . +*/ +#include "trayicon.h" + +#include "mainwindow.h" +#include "rfbservermanager.h" +#include "rfbclient.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +class ClientActions +{ +public: + ClientActions(RfbClient *client, KMenu *menu, QAction *before); + virtual ~ClientActions(); + +private: + KMenu *m_menu; + QAction *m_title; + QAction *m_disconnectAction; + QAction *m_enableControlAction; + QAction *m_separator; +}; + +ClientActions::ClientActions(RfbClient* client, KMenu* menu, QAction* before) + : m_menu(menu) +{ + m_title = m_menu->addTitle(client->name(), before); + + m_disconnectAction = new KAction(i18n("Disconnect"), m_menu); + m_menu->insertAction(before, m_disconnectAction); + + QObject::connect(m_disconnectAction, SIGNAL(triggered()), client, SLOT(closeConnection())); + + if (client->controlCanBeEnabled()) { + m_enableControlAction = new KToggleAction(i18n("Enable Remote Control"), m_menu); + m_enableControlAction->setChecked(client->controlEnabled()); + m_menu->insertAction(before, m_enableControlAction); + + QObject::connect(m_enableControlAction, SIGNAL(triggered(bool)), + client, SLOT(setControlEnabled(bool))); + QObject::connect(client, SIGNAL(controlEnabledChanged(bool)), + m_enableControlAction, SLOT(setChecked(bool))); + } else { + m_enableControlAction = NULL; + } + + m_separator = m_menu->insertSeparator(before); +} + +ClientActions::~ClientActions() +{ + kDebug(); + + m_menu->removeAction(m_title); + delete m_title; + + m_menu->removeAction(m_disconnectAction); + delete m_disconnectAction; + + if (m_enableControlAction) { + m_menu->removeAction(m_enableControlAction); + delete m_enableControlAction; + } + + m_menu->removeAction(m_separator); + delete m_separator; +} + +//********** + +TrayIcon::TrayIcon(QWidget *mainWindow) + : KStatusNotifierItem(mainWindow) +{ + setIconByPixmap(KIcon("krfb").pixmap(22, 22, KIcon::Disabled)); + + setToolTipTitle(i18n("Desktop Sharing - disconnected")); + setCategory(KStatusNotifierItem::ApplicationStatus); + + connect(RfbServerManager::instance(), SIGNAL(clientConnected(RfbClient*)), + this, SLOT(onClientConnected(RfbClient*))); + connect(RfbServerManager::instance(), SIGNAL(clientDisconnected(RfbClient*)), + this, SLOT(onClientDisconnected(RfbClient*))); + + m_aboutAction = KStandardAction::aboutApp(this, SLOT(showAbout()), actionCollection()); + contextMenu()->addAction(m_aboutAction); +} + +void TrayIcon::onClientConnected(RfbClient* client) +{ + kDebug(); + + if (m_clientActions.isEmpty()) { //first client connected + setIconByName("krfb"); + setToolTipTitle(i18n("Desktop Sharing - connected with %1", client->name())); + setStatus(KStatusNotifierItem::Active); + } else { //Nth client connected, N != 1 + setToolTipTitle(i18n("Desktop Sharing - connected")); + } + + m_clientActions[client] = new ClientActions(client, contextMenu(), m_aboutAction); +} + +void TrayIcon::onClientDisconnected(RfbClient* client) +{ + kDebug(); + + ClientActions *actions = m_clientActions.take(client); + delete actions; + + if (m_clientActions.isEmpty()) { + setIconByPixmap(KIcon("krfb").pixmap(22, 22, KIcon::Disabled)); + setToolTipTitle(i18n("Desktop Sharing - disconnected")); + setStatus(KStatusNotifierItem::Passive); + } else if (m_clientActions.size() == 1) { //clients number dropped back to 1 + RfbClient *client = m_clientActions.constBegin().key(); + setToolTipTitle(i18n("Desktop Sharing - connected with %1", client->name())); + } +} + +void TrayIcon::showAbout() +{ + KDialog *dlg = new KAboutApplicationDialog(KGlobal::mainComponent().aboutData()); + dlg->setAttribute(Qt::WA_DeleteOnClose, true); + dlg->show(); +} + +#include "trayicon.moc" diff --git a/krfb/krfb/trayicon.h b/krfb/krfb/trayicon.h new file mode 100644 index 00000000..499893d3 --- /dev/null +++ b/krfb/krfb/trayicon.h @@ -0,0 +1,49 @@ +/*************************************************************************** + trayicon.h - description + ------------------- + begin : Tue Dec 11 2001 + copyright : (C) 2001-2002 by Tim Jansen + email : tim@tjansen.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef TRAYICON_H +#define TRAYICON_H + +#include +#include + +class KDialog; +class RfbClient; +class ClientActions; + +/** + * Implements the trayicon. + * @author Tim Jansen + */ + +class TrayIcon : public KStatusNotifierItem +{ + Q_OBJECT +public: + TrayIcon(QWidget *mainWindow); + +public Q_SLOTS: + void onClientConnected(RfbClient *client); + void onClientDisconnected(RfbClient *client); + void showAbout(); + +private: + KAction *m_aboutAction; + QHash m_clientActions; +}; + +#endif diff --git a/krfb/krfb/tubesrfbclient.cpp b/krfb/krfb/tubesrfbclient.cpp new file mode 100644 index 00000000..d2eae4b7 --- /dev/null +++ b/krfb/krfb/tubesrfbclient.cpp @@ -0,0 +1,87 @@ +/* + Copyright (C) 2009-2010 Collabora Ltd. + @author George Goldberg + @author George Kiagiadakis + + 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 Lesser General Public License + along with this program. If not, see . +*/ +#include "tubesrfbclient.h" +#include "krfbconfig.h" +#include "connectiondialog.h" +#include +#include + +QString TubesRfbClient::name() const +{ + return m_contact->alias(); +} + +//******** + +PendingTubesRfbClient::PendingTubesRfbClient(rfbClientPtr client, QObject* parent) : + PendingRfbClient(client, parent), + m_processNewClientCalled(false) +{ + processNewClient(); +} + +void PendingTubesRfbClient::setContact(const Tp::ContactPtr & contact) +{ + m_contact = contact; + if (m_processNewClientCalled) { + //processNewClient has already been called, so we need to act here + showConfirmationDialog(); + } +} + +void PendingTubesRfbClient::processNewClient() +{ + if (!m_contact) { + //no associated contact yet, hold. + m_processNewClientCalled = true; //act when a contact is set + } else { + //we have a contact, begin handling + showConfirmationDialog(); + } +} + +void PendingTubesRfbClient::showConfirmationDialog() +{ + QString name = m_contact->alias(); + + KNotification::event("NewConnectionOnHold", + i18n("Received connection from %1, on hold (waiting for confirmation)", + name)); + + TubesConnectionDialog *dialog = new TubesConnectionDialog(0); + dialog->setContactName(name); + dialog->setAllowRemoteControl(KrfbConfig::allowDesktopControl()); + + connect(dialog, SIGNAL(okClicked()), SLOT(dialogAccepted())); + connect(dialog, SIGNAL(cancelClicked()), SLOT(reject())); + + dialog->show(); +} + +void PendingTubesRfbClient::dialogAccepted() +{ + TubesConnectionDialog *dialog = qobject_cast(sender()); + Q_ASSERT(dialog); + + TubesRfbClient *client = new TubesRfbClient(m_rfbClient, m_contact, parent()); + client->setControlEnabled(dialog->allowRemoteControl()); + accept(client); +} + +#include "tubesrfbclient.moc" diff --git a/krfb/krfb/tubesrfbclient.h b/krfb/krfb/tubesrfbclient.h new file mode 100644 index 00000000..0050cb4c --- /dev/null +++ b/krfb/krfb/tubesrfbclient.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2010 Collabora Ltd. + @author George Kiagiadakis + + 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 Lesser General Public License + along with this program. If not, see . +*/ +#ifndef TUBESRFBCLIENT_H +#define TUBESRFBCLIENT_H + +#include "rfbclient.h" +#include + +class TubesRfbClient : public RfbClient +{ +public: + TubesRfbClient(rfbClientPtr client, + const Tp::ContactPtr &contact, QObject *parent=0) + : RfbClient(client, parent), m_contact(contact) + {} + + virtual QString name() const; + +private: + Tp::ContactPtr m_contact; +}; + +//********* + +class PendingTubesRfbClient : public PendingRfbClient +{ + Q_OBJECT +public: + PendingTubesRfbClient(rfbClientPtr client, QObject* parent = 0); + + void setContact(const Tp::ContactPtr & contact); + +protected Q_SLOTS: + virtual void processNewClient(); + +private Q_SLOTS: + void showConfirmationDialog(); + void dialogAccepted(); + +private: + Tp::ContactPtr m_contact; + bool m_processNewClientCalled; +}; + +#endif // TUBESRFBCLIENT_H diff --git a/krfb/krfb/tubesrfbserver.cpp b/krfb/krfb/tubesrfbserver.cpp new file mode 100644 index 00000000..d99ae49b --- /dev/null +++ b/krfb/krfb/tubesrfbserver.cpp @@ -0,0 +1,262 @@ +/* + Copyright (C) 2009-2011 Collabora Ltd. + @author George Goldberg + @author George Kiagiadakis + + 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 Lesser General Public License + along with this program. If not, see . +*/ +#include "tubesrfbserver.h" +#include "tubesrfbclient.h" +#include "sockethelpers.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef KRFB_WITH_KDE_TELEPATHY +#include +#include +#include +#include +#include +#endif + +struct TubesRfbServer::Private +{ + Tp::StreamTubeServerPtr stubeServer; + QHash contactsPerPort; + QHash clientsPerPort; +}; + +//static +TubesRfbServer *TubesRfbServer::instance; + +//static +void TubesRfbServer::init() +{ + instance = new TubesRfbServer; + //RfbServerManager takes care of deletion + + instance->startAndCheck(); +} + +TubesRfbServer::TubesRfbServer(QObject *parent) + : RfbServer(parent), d(new Private) +{ + kDebug() << "starting"; + + Tp::enableDebug(true); + Tp::enableWarnings(true); + Tp::registerTypes(); + + Tp::AccountFactoryPtr accountFactory = Tp::AccountFactory::create( + QDBusConnection::sessionBus(), + Tp::Features() << Tp::Account::FeatureCore + << Tp::Account::FeatureAvatar + << Tp::Account::FeatureCapabilities + << Tp::Account::FeatureProtocolInfo + << Tp::Account::FeatureProfile); + + Tp::ConnectionFactoryPtr connectionFactory = Tp::ConnectionFactory::create( + QDBusConnection::sessionBus(), + Tp::Features() << Tp::Connection::FeatureCore + << Tp::Connection::FeatureSelfContact); + + Tp::ChannelFactoryPtr channelFactory = Tp::ChannelFactory::create( + QDBusConnection::sessionBus()); + +#ifdef KRFB_WITH_KDE_TELEPATHY + Tp::ContactFactoryPtr contactFactory = KTp::ContactFactory::create( + Tp::Features() << Tp::Contact::FeatureAlias + <stubeServer = Tp::StreamTubeServer::create( + m_accountManager, + QStringList() << QLatin1String("rfb"), + QStringList(), + QLatin1String("krfb_rfb_handler"), + true); + + connect(m_accountManager->becomeReady(), + SIGNAL(finished(Tp::PendingOperation*)), + this, + SLOT(onAccountManagerReady())); + + m_contactsListModel = new KTp::ContactsListModel(this); +#else + Tp::ContactFactoryPtr contactFactory = Tp::ContactFactory::create( + Tp::Contact::FeatureAlias); + + d->stubeServer = Tp::StreamTubeServer::create( + QStringList() << QLatin1String("rfb"), + QStringList(), + QLatin1String("krfb_rfb_handler"), + true, + accountFactory, + connectionFactory, + channelFactory, + contactFactory); +#endif //KRFB_WITH_KDE_TELEPATHY + + connect(d->stubeServer.data(), + SIGNAL(tubeRequested(Tp::AccountPtr,Tp::OutgoingStreamTubeChannelPtr, + QDateTime,Tp::ChannelRequestHints)), + SLOT(onTubeRequested())); + connect(d->stubeServer.data(), + SIGNAL(tubeClosed(Tp::AccountPtr,Tp::OutgoingStreamTubeChannelPtr,QString,QString)), + SLOT(onTubeClosed())); + + connect(d->stubeServer.data(), + SIGNAL(newTcpConnection(QHostAddress,quint16,Tp::AccountPtr, + Tp::ContactPtr,Tp::OutgoingStreamTubeChannelPtr)), + SLOT(onNewTcpConnection(QHostAddress,quint16,Tp::AccountPtr, + Tp::ContactPtr,Tp::OutgoingStreamTubeChannelPtr))); + connect(d->stubeServer.data(), + SIGNAL(tcpConnectionClosed(QHostAddress,quint16,Tp::AccountPtr,Tp::ContactPtr, + QString,QString,Tp::OutgoingStreamTubeChannelPtr)), + SLOT(onTcpConnectionClosed(QHostAddress,quint16,Tp::AccountPtr,Tp::ContactPtr, + QString,QString,Tp::OutgoingStreamTubeChannelPtr))); + + // Pick a random port in the private range (49152–65535) + setListeningPort((KRandom::random() % 16383) + 49152); + // Listen only on the loopback network interface + setListeningAddress("127.0.0.1"); + setPasswordRequired(false); +} + +TubesRfbServer::~TubesRfbServer() +{ + kDebug(); + stop(); + delete d; +} + +#ifdef KRFB_WITH_KDE_TELEPATHY +KTp::ContactsListModel *TubesRfbServer::contactsListModel() +{ + return m_contactsListModel; +} +#endif + +void TubesRfbServer::startAndCheck() +{ + if (!start()) { + //try a few times with different ports + bool ok = false; + for (int i=0; !ok && i<5; i++) { + setListeningPort((KRandom::random() % 16383) + 49152); + ok = start(); + } + + if (!ok) { + kError() << "Failed to start tubes rfb server"; + return; + } + } + + //TODO listeningAddress() should be a QHostAddress + d->stubeServer->exportTcpSocket(QHostAddress(QString::fromAscii(listeningAddress())), + listeningPort()); +} + +void TubesRfbServer::onTubeRequested() +{ + kDebug() << "Got a tube"; +} + +void TubesRfbServer::onTubeClosed() +{ + kDebug() << "tube closed"; +} + +void TubesRfbServer::onNewTcpConnection(const QHostAddress & sourceAddress, + quint16 sourcePort, + const Tp::AccountPtr & account, + const Tp::ContactPtr & contact, + const Tp::OutgoingStreamTubeChannelPtr & tube) +{ + Q_UNUSED(account); + Q_UNUSED(tube); + + kDebug() << "CM signaled tube connection from" << sourceAddress << ":" << sourcePort; + + d->contactsPerPort[sourcePort] = contact; + if (d->clientsPerPort.contains(sourcePort)) { + kDebug() << "client already exists"; + d->clientsPerPort[sourcePort]->setContact(contact); + } +} + +void TubesRfbServer::onTcpConnectionClosed(const QHostAddress& sourceAddress, + quint16 sourcePort, + const Tp::AccountPtr& account, + const Tp::ContactPtr& contact, + const QString& error, + const QString& message, + const Tp::OutgoingStreamTubeChannelPtr& tube) +{ + Q_UNUSED(account); + Q_UNUSED(contact); + Q_UNUSED(tube); + + kDebug() << "Connection from" << sourceAddress << ":" << sourcePort << "closed." + << error << message; + + d->clientsPerPort.remove(sourcePort); + d->contactsPerPort.remove(sourcePort); +} + +PendingRfbClient* TubesRfbServer::newClient(rfbClientPtr client) +{ + PendingTubesRfbClient *c = new PendingTubesRfbClient(client, this); + quint16 port = peerPort(client->sock); + + kDebug() << "new tube client on port" << port; + + d->clientsPerPort[port] = c; + if (d->contactsPerPort.contains(port)) { + kDebug() << "already have a contact"; + c->setContact(d->contactsPerPort[port]); + } + + return c; +} + +#ifdef KRFB_WITH_KDE_TELEPATHY +void TubesRfbServer::onAccountManagerReady() +{ + m_contactsListModel->setAccountManager(m_accountManager); +} +#endif + +#include "tubesrfbserver.moc" diff --git a/krfb/krfb/tubesrfbserver.h b/krfb/krfb/tubesrfbserver.h new file mode 100644 index 00000000..5e57d73d --- /dev/null +++ b/krfb/krfb/tubesrfbserver.h @@ -0,0 +1,86 @@ +/* + Copyright (C) 2009-2011 Collabora Ltd. + @author George Goldberg + @author George Kiagiadakis + + 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 Lesser General Public License + along with this program. If not, see . +*/ +#ifndef TUBESRFBSERVER_H +#define TUBESRFBSERVER_H + +#include "rfbserver.h" +#include +#include + +#ifdef KRFB_WITH_KDE_TELEPATHY +namespace KTp { + class ContactsListModel; +} +#endif + +class TubesRfbServer : public RfbServer +{ + Q_OBJECT +public: + static TubesRfbServer *instance; + static void init(); + + virtual ~TubesRfbServer(); +#ifdef KRFB_WITH_KDE_TELEPATHY + KTp::ContactsListModel *contactsListModel(); +#endif + +protected: + TubesRfbServer(QObject *parent = 0); + + virtual PendingRfbClient* newClient(rfbClientPtr client); + +private Q_SLOTS: + void startAndCheck(); + + void onTubeRequested(); + void onTubeClosed(); + + void onNewTcpConnection( + const QHostAddress &sourceAddress, + quint16 sourcePort, + const Tp::AccountPtr &account, + const Tp::ContactPtr &contact, + const Tp::OutgoingStreamTubeChannelPtr &tube); + + void onTcpConnectionClosed( + const QHostAddress &sourceAddress, + quint16 sourcePort, + const Tp::AccountPtr &account, + const Tp::ContactPtr &contact, + const QString &error, + const QString &message, + const Tp::OutgoingStreamTubeChannelPtr &tube); + +#ifdef KRFB_WITH_KDE_TELEPATHY + void onAccountManagerReady(); +#endif + +private: + struct Private; + Private *const d; + +#ifdef KRFB_WITH_KDE_TELEPATHY + KTp::ContactsListModel *m_contactsListModel; + Tp::AccountManagerPtr m_accountManager; +#endif + +}; + +#endif // TUBESRFBSERVER_H diff --git a/krfb/krfb/ui/configsecurity.ui b/krfb/krfb/ui/configsecurity.ui new file mode 100644 index 00000000..93d59f37 --- /dev/null +++ b/krfb/krfb/ui/configsecurity.ui @@ -0,0 +1,41 @@ + + + Security + + + + 0 + 0 + 507 + 201 + + + + + + + Allow remote connections to control your desktop + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/krfb/krfb/ui/configtcp.ui b/krfb/krfb/ui/configtcp.ui new file mode 100644 index 00000000..a47538fc --- /dev/null +++ b/krfb/krfb/ui/configtcp.ui @@ -0,0 +1,94 @@ + + TCP + + + + 0 + 0 + 400 + 169 + + + + + 9 + + + 6 + + + + + Announce the service on the local network + + + true + + + + + + + Use default port + + + true + + + + + + + 0 + + + 6 + + + + + Listening port: + + + kcfg_port + + + + + + + false + + + 65535 + + + + + + + + + kcfg_useDefaultPort + kcfg_port + + + + + kcfg_useDefaultPort + toggled(bool) + kcfg_port + setDisabled(bool) + + + 120 + 53 + + + 277 + 122 + + + + + diff --git a/krfb/krfb/ui/connectionwidget.ui b/krfb/krfb/ui/connectionwidget.ui new file mode 100644 index 00000000..76bb2bba --- /dev/null +++ b/krfb/krfb/ui/connectionwidget.ui @@ -0,0 +1,149 @@ + + ConnectionWidget + + + + 0 + 0 + 500 + 212 + + + + + + + + 0 + 0 + + + + + 128 + 128 + + + + + + + + + + + 0 + 0 + + + + + 13 + 75 + true + + + + Attention + + + false + + + 0 + + + + + + + + 0 + 0 + + + + -1 + + + 5 + + + Somebody is requesting a connection to your computer. Granting this will allow the remote user to watch your desktop. + + + Qt::AutoText + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + 0 + + + 0 + + + + + + + + + + 75 + true + + + + Remote system: + + + false + + + + + + + + 75 + true + + + + 123.234.123.234 + + + false + + + + + + + + + + 0 + 0 + + + + If you turn this option on, the remote user can enter keystrokes and use your mouse pointer. This gives them full control over your computer, so be careful. When the option is disabled the remote user can only watch your screen. + + + Allow remote user to &control keyboard and mouse + + + + + + + + + + diff --git a/krfb/krfb/ui/invitewidget.ui b/krfb/krfb/ui/invitewidget.ui new file mode 100644 index 00000000..0aa70165 --- /dev/null +++ b/krfb/krfb/ui/invitewidget.ui @@ -0,0 +1,171 @@ + + InviteWidget + + + + 0 + 0 + 603 + 364 + + + + + + + + 0 + 0 + + + + + 128 + 128 + + + + + + + + + + + 75 + true + + + + Welcome to KDE Desktop Sharing + + + false + + + + + + + KDE Desktop Sharing allows you to invite somebody at a remote location to watch and possibly control your desktop. <a href="whatsthis">More about invitations...</a> + + + Qt::RichText + + + true + + + Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::NoTextInteraction + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 215 + 101 + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 90 + 26 + + + + + + + + + + + + + Create a new invitation and display the connection data. Use this option if you want to invite somebody personally, for example, to give the connection data over the phone. + + + Create &Personal Invitation... + + + + + + + This button will start your email application with a pre-configured text that explains to the recipient how to connect to your computer. + + + Invite via &Email... + + + + + + + &Manage Invitations (%1)... + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 90 + 26 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 24 + + + + + + + + + + + diff --git a/krfb/krfb/ui/mainwidget.ui b/krfb/krfb/ui/mainwidget.ui new file mode 100644 index 00000000..2925e783 --- /dev/null +++ b/krfb/krfb/ui/mainwidget.ui @@ -0,0 +1,537 @@ + + + MainWidget + + + + 0 + 0 + 600 + 340 + + + + + 0 + 0 + + + + + 600 + 340 + + + + + 16777215 + 16777215 + + + + + + + + 128 + 128 + + + + + 128 + 128 + + + + + + + + + + + QLayout::SetMaximumSize + + + + + + 0 + 0 + + + + + 400 + 20 + + + + + 16777215 + 40 + + + + + 75 + true + + + + KDE Desktop Sharing + + + KDE Desktop Sharing + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 400 + 40 + + + + + 16777215 + 80 + + + + KDE Desktop Sharing + + + KDE Desktop Sharing allows you to grant permission to someone at a remote location for viewing and possibly controlling your desktop. + + + true + + + + + + + + 0 + 0 + + + + + 400 + 20 + + + + + 16777215 + 40 + + + + Starts/Stops Remote Desktop Sharing + + + &Enable Desktop Sharing + + + + + + + false + + + + 0 + 0 + + + + + 0 + 100 + + + + Connection Details + + + + + + QLayout::SetMaximumSize + + + QFormLayout::ExpandingFieldsGrow + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + 0 + 0 + + + + &Address + + + addressAboutButton + + + + + + + QLayout::SetMaximumSize + + + + + + 0 + 0 + + + + More about this address + + + About + + + + + + + + + + + + + 0 + 0 + + + + Address required by remote users to connect to your desktop. Click about button on the right for more info. + + + 127.0.0.1 : 5900 + + + Qt::AlignCenter + + + + + + + + + + + QLayout::SetMaximumSize + + + QFormLayout::ExpandingFieldsGrow + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + 0 + 0 + + + + &Password + + + passwordEditButton + + + + + + + QLayout::SetMaximumSize + + + + + + 0 + 0 + + + + Edit/Save Desktop Sharing Password + + + Edit + + + + + + + + + + + + + 0 + 0 + + + + Password required by remote users to connect to your desktop. Click the edit button on the right to change password. + + + TemporaryPassword + + + Qt::AlignCenter + + + + + + + + + + + + + + false + + + + 0 + 0 + + + + Unattended Access allows a remote user with the password to gain control to your desktop without your explicit confirmation. + + + Unattended Access + + + + + + 0 + + + 10 + + + 0 + + + 10 + + + + + + 0 + 0 + + + + + 16777215 + 80 + + + + Unattended Access allows a remote user with the password to gain control to your desktop without your explicit confirmation. Click "About" button on right to know more. + + + Unattended Access allows a remote user with the password to gain control to your desktop without your explicit confirmation. + + + true + + + + + + + + 0 + 0 + + + + Know more about Unattended Access + + + About + + + + + + + + + + + + + + 0 + + + 10 + + + 0 + + + 10 + + + + + + 0 + 0 + + + + + 16777215 + 80 + + + + Starts/Stops unattended access to your desktop. Click on button on right to change password, and "About" button to know more. + + + Enable &Unattended Access + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 320 + 80 + + + + Change password for Unattended Access + + + &Change Unattended Password + + + + + + + + + + + + + + QLayout::SetMinimumSize + + + + + + + + KPushButton + QPushButton +
kpushbutton.h
+
+
+ + enableSharingCheckBox + addressAboutButton + passwordEditButton + enableUnattendedCheckBox + unattendedPasswordButton + + + + + enableSharingCheckBox + toggled(bool) + detailsGroupBox + setEnabled(bool) + + + 382 + 87 + + + 245 + 140 + + + + + enableSharingCheckBox + toggled(bool) + unattendedGroupBox + setEnabled(bool) + + + 320 + 76 + + + 325 + 214 + + + + +
diff --git a/krfb/krfb/ui/tubesconnectionwidget.ui b/krfb/krfb/ui/tubesconnectionwidget.ui new file mode 100644 index 00000000..480e3db2 --- /dev/null +++ b/krfb/krfb/ui/tubesconnectionwidget.ui @@ -0,0 +1,114 @@ + + + TubesConnectionWidget + + + + 0 + 0 + 500 + 162 + + + + + + + + 0 + 0 + + + + + 128 + 128 + + + + + + + + + + + 0 + 0 + + + + + 13 + 75 + true + + + + Confirmation + + + false + + + 0 + + + + + + + + 0 + 0 + + + + -1 + + + 5 + + + + + + Qt::AutoText + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + 0 + + + 0 + + + + + + + + 0 + 0 + + + + If you turn this option on, the remote user can enter keystrokes and use your mouse pointer. This gives them full control over your computer, so be careful. When the option is disabled the remote user can only watch your screen. + + + Allow remote user to &control keyboard and mouse + + + + + + + + + +