ukui-control-center/0000775000175000017500000000000013265607471013424 5ustar fengfengukui-control-center/configure.ac0000664000175000017500000001346213253611037015706 0ustar fengfengAC_INIT([ukui-control-center], [1.0.2], [penghuan@kylinos.cn]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([shell]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([1.9 no-dist-gzip dist-xz tar-ustar]) AM_MAINTAINER_MODE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes]])) AC_PROG_CC AM_PROG_CC_C_O AC_STDC_HEADERS AM_PROG_LIBTOOL # Use the Yelp documentation framework YELP_HELP_INIT AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal) # Internationalization support IT_PROG_INTLTOOL([0.37.1]) GETTEXT_PACKAGE=ukui-control-center AC_SUBST(GETTEXT_PACKAGE) AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext package]) AH_TEMPLATE([GETTEXT_PACKAGE]) AH_TEMPLATE([HAVE_CATGETS]) AH_TEMPLATE([HAVE_GETTEXT]) AH_TEMPLATE([HAVE_LC_MESSAGES]) AM_GLIB_GNU_GETTEXT GLIB_DEFINE_LOCALEDIR(UKUILOCALEDIR) dnl --------------------------------------------------------------------------- dnl - Make paths available for source files dnl --------------------------------------------------------------------------- AC_SUBST(SYSCONFDIR, $sysconfdir) AC_SUBST(DATADIR, $datadir) AC_SUBST(BINDIR, $bindir) AC_SUBST(SBINDIR, $sbindir) dnl ============================================== dnl Special GSettings section dnl ============================================== GLIB_GSETTINGS dnl ---------------------------------------------------------------------------- dnl - Library dependencies dnl ---------------------------------------------------------------------------- pkg-config=2.13.0 GIO_REQUIRED=2.25.0 GTK_REQUIRED=3.0.0 GDK_REQUIRED=3.0.0 GNOME_KEYRING_REQUIRED=3.0.0 DBUS_REQUIRED=1.0 DBUS_GLIB_REQUIRED=0.70 LIBNOTIFY_REQUIRED=0.7.0 CAIRO_REQUIRED=1.0.0 LIBPANEL_REQUIRED=1.5.0 XRANDR_REQUIRED=1.2.0 CANBERRA_REQUIRED=0.10 UPOWER_REQUIRED=0.9.1 PKG_CHECK_MODULES(GTK, [gtk+-3.0 >= 3.0.0]) #PKG_CHECK_MODULES(GTK_PIXBUF, [gdk-pixbuf-3.0]) dnl ---------------------------------------------------------------------------- dnl GTK library version dnl ---------------------------------------------------------------------------- AC_MSG_CHECKING([which gtk+ version to compile against]) AC_ARG_WITH([gtk], [AS_HELP_STRING([--with-gtk=2.0|3.0],[which gtk+ version to compile against (default: 2.0)])], [case "$with_gtk" in 2.0|3.0) ;; *) AC_MSG_ERROR([invalid gtk version specified]) ;; esac], [with_gtk=3.0]) AC_MSG_RESULT([-----------------------------------------------------]) AC_MSG_RESULT([$with_gtk]) AC_MSG_RESULT([-----------------------------------------------------]) case "$with_gtk" in 2.0) GTK_API_VERSION=2.0 GTK_REQUIRED=2.17.7 CANBERRA_GTK=libcanberra-gtk ;; 3.0) GTK_API_VERSION=3.0 GTK_REQUIRED=3.0.0 CANBERRA_GTK=libcanberra-gtk3 ;; esac PACKAGE_CFLAGS="-g -Wall $GTK_CFLAGS" PACKAGE_LIBS="-g $GTK_LIBS" AC_SUBST([PACKAGE_CFLAGS]) AC_SUBST([PACKAGE_LIBS]) AC_SUBST([PACKAGE_LDFLAGS]) PKG_CHECK_MODULES(CANBERRA, libcanberra-gtk3) PKG_CHECK_MODULES(PULSE, libpulse libpulse-mainloop-glib) #ukui-settings-daemon PKG_CHECK_MODULES(UKUI_SD, [ukui-settings-daemon]) #upower PKG_CHECK_MODULES(UPOWER, [upower-glib >= 0.9.1]) #upower PKG_CHECK_MODULES(OOBS, [liboobs-1 >= 2.91.1]) #mate-desktop PKG_CHECK_MODULES(MATE_DESKTOP, [mate-desktop-2.0]) PKG_CHECK_MODULES(MATE_KBD, [libmatekbd]) PKG_CHECK_MODULES(MATE_KBD_UI, [libmatekbdui]) #xft PKG_CHECK_MODULES(XFT, [xft]) #libxml PKG_CHECK_MODULES(LIBXML,[libxml-2.0]) PKG_CHECK_MODULES(DCONF, [dconf]) dnl --------------------------------------------------------------------------- dnl - Check library dependencies dnl --------------------------------------------------------------------------- PKG_CHECK_MODULES(GLIB, glib-2.0 >= $GLIB_REQUIRED gobject-2.0 gio-2.0 >= $GIO_REQUIRED gio-unix-2.0) PKG_CHECK_MODULES(CANBERRA, $CANBERRA_GTK >= $CANBERRA_REQUIRED) PKG_CHECK_MODULES(DBUS,[ dbus-glib-1 >= $DBUS_GLIB_REQUIRED dbus-1 >= $DBUS_REQUIRED gthread-2.0]) PKG_CHECK_MODULES(XI, xi) PKG_CHECK_MODULES(UKUI, [ gtk+-$GTK_API_VERSION >= $GTK_REQUIRED cairo >= $CAIRO_REQUIRED]) PKG_CHECK_MODULES(GDK, [ gdk-$GTK_API_VERSION >= $GDK_REQUIRED gdk-x11-$GTK_API_VERSION >= $GDK_REQUIRED]) PKG_CHECK_MODULES(X11, [ xrandr >= $XRANDR_REQUIRED xrender x11 xext xproto]) PKG_CHECK_MODULES(X11, x11 xrender) PKG_CHECK_EXISTS( [xrandr >= 1.3], [AC_DEFINE(HAVE_XRANDR_13, 1, [xrandr 1.3 available])]) PKG_CHECK_MODULES(LIBNOTIFY, libnotify >= $LIBNOTIFY_REQUIRED) dnl ======================================= dnl Panels dnl ======================================= PANELS_DIR="${libdir}/ukui-control-center/panels" AC_SUBST(PANELS_DIR) PANEL_CFLAGS="-I\$(top_srcdir)/ -DG_LOG_DOMAIN=\"\\\"ukui-control-center\\\"\"" AC_SUBST(PANEL_CFLAGS) #PANEL_LDFLAGS="-export_dynamic -avoid-version -module -no-undefined -export-symbols-regex '^g_io_module_(load|unload)'" #AC_SUBST(PANEL_LDFLAGS) AC_OUTPUT([ Makefile po/Makefile.in data/Makefile man/Makefile data/color/Makefile shell/Makefile panels/Makefile panels/time-data/Makefile panels/appearance/Makefile panels/user-accounts/Makefile panels/default-app/Makefile panels/keyboard/Makefile panels/mouse/Makefile panels/network-proxy/Makefile panels/session-properties/Makefile panels/display/Makefile panels/power/Makefile panels/volume-control/Makefile panels/volume-control/icons/Makefile panels/volume-control/icons/16x16/Makefile panels/volume-control/icons/16x16/status/Makefile panels/volume-control/icons/22x22/Makefile panels/volume-control/icons/22x22/status/Makefile panels/volume-control/icons/24x24/Makefile panels/volume-control/icons/24x24/status/Makefile panels/volume-control/icons/32x32/Makefile panels/volume-control/icons/32x32/status/Makefile panels/volume-control/icons/scalable/Makefile panels/volume-control/icons/scalable/devices/Makefile panels/volume-control/icons/scalable/status/Makefile ]) ukui-control-center/COPYING0000664000175000017500000004324013057175444014461 0ustar fengfeng 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 Lesser 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) This program is free software; you can redistribute 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) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 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 Lesser General Public License instead of this License. ukui-control-center/autogen.sh0000775000175000017500000000144313057411001015404 0ustar fengfeng#!/bin/sh # Run this to generate all the initial makefiles, etc. srcdir=`dirname $0` test -z "$srcdir" && srcdir=. if [ "$1"x = "clean"x ]; then rm -rf config.* aclocal.m4 compile configure Makefile.in install-sh missing autom4te.cache config.h.in ltmain.sh depcomp m4 config.h.in~ INSTALL Makefile stamp-h1 exit 0 fi PKG_NAME="ukui-control-center" (test -f $srcdir/configure.ac \ && test -f $srcdir/autogen.sh \ && test -d $srcdir/shell) || { echo -n "**Error**: Directory "\`$srcdir\'" does not look like the" echo " top-level $PKG_NAME directory" exit 1 } DIE=0 rm -f .using-gnome-libs-package if ! which mate-autogen ; then echo "You need to install the mate-common module and make" echo "sure the mate-autogen script is in your \$PATH." exit 1 fi . mate-autogen ukui-control-center/Makefile.am0000664000175000017500000000124613253611050015444 0ustar fengfengSUBDIRS = data panels shell po man DIST_SUBDIRS = data panels shell po man @INTLTOOL_XML_NOMERGE_RULE@ gsettingsschema_in_files = \ org.ukui.control-center.keybinding.gschema.xml.in gsettings_SCHEMAS = $(gsettingsschema_in_files:.xml.in=.xml) @GSETTINGS_RULES@ CLEANFILES = \ $(gsettings_SCHEMAS) \ *.gschema.valid EXTRA_DIST = \ autogen.sh \ $(gsettingsschema_in_files) clean-local : rm -rf config.guess config.sub config.* aclocal.m4 libtool compile configure Makefile.in install-sh missing autom4te.cache config.h.in ltmain.sh depcomp m4 config.h.in~ INSTALL Makefile stamp-h1 po/Makefile.in.in po/Makefile po/Makefile.in po/POTFILES man/Makefile.in man/Makefile ukui-control-center/po/0000775000175000017500000000000013263647163014042 5ustar fengfengukui-control-center/po/POTFILES.in0000664000175000017500000000330713245450076015615 0ustar fengfeng[encoding: UTF-8] # List of source files containing translatable strings. # Please keep this file sorted alphabetically. panels/display/ukui-display-properties-install-systemwide.c panels/display/org.ukuicc.randr.policy.in panels/display/xrandr-capplet.c panels/power/kpm-common.c panels/power/kpm-upower.c panels/power/kpm-prefs-core.c panels/keyboard/eggcellrendererkeys.c panels/keyboard/ukui-keybinding-properties.c panels/volume-control/gvc-balance-bar.c panels/volume-control/gvc-channel-bar.c panels/volume-control/gvc-combo-box.c panels/volume-control/gvc-mixer-control.c panels/volume-control/gvc-mixer-dialog.c panels/volume-control/gvc-sound-theme-chooser.c panels/volume-control/gvc-speaker-test.c panels/volume-control/sound-theme-file-utils.c panels/appearance/appearance-desktop.c panels/appearance/appearance-theme.c panels/appearance/font_render.ui panels/appearance/ukui-wp-item.c panels/keyboard/ukui-keyboard-properties-layout-chooser.ui panels/keyboard/shortcut_dialog.ui panels/network-proxy/network.ui panels/session-properties/gsm-app-dialog.c panels/session-properties/gsm-properties-dialog.c panels/session-properties/main-table.ui panels/session-properties/program_properties.ui panels/time-data/spy-time.c panels/user-accounts/change-face.ui panels/user-accounts/change-name.ui panels/user-accounts/change-pwd.ui panels/user-accounts/change-type.ui panels/user-accounts/delete-user.ui panels/user-accounts/run-passwd.c panels/user-accounts/user-accounts.c panels/user-accounts/user-create.ui panels/user-accounts/check-passwd.c shell/ukui-control-center.c shell/mainwindow.c shell/shell.ui panels/power/copy-theme-dialog.c panels/power/ukui-fullscreen-preview.ui panels/power/ukui-screensaver-preferences.c ukui-control-center/po/LINGUAS0000664000175000017500000000007513245450076015064 0ustar fengfeng# please keep this list sorted alphabetically # ko tr zh_CN ukui-control-center/po/ko.po0000664000175000017500000016250513253611051015006 0ustar fengfeng# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Canonical Ltd. # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: ukui-control-center\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-05-24 16:35+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Ko Jae Min \n" "Language-Team: Korean \n" "Language: ko\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0\n" #: panels/appearance/appearance-desktop.c:561 msgid "Add Wallpaper" msgstr "배경화면 추가" #: panels/appearance/appearance-desktop.c:594 msgid "Image" msgstr "이미지" #: panels/appearance/appearance-desktop.c:598 msgid "ALL File" msgstr "모든 파일" #: panels/appearance/appearance-theme.c:46 msgid "Please choose a color that you like as the theme colors." msgstr "원하시는 색상을 선택해주세요" #: panels/appearance/appearance-theme.c:62 msgid "" "Set up disable. Please wait at least 5 seconds that system subject will " "restart" msgstr "설정이 취소되었습니다. 5초뒤에 시스템을 재시작합니다" #: panels/appearance/font_render.ui.h:1 msgid "Font Rendering Details" msgstr "글꼴 렌더링" #: panels/appearance/font_render.ui.h:2 msgid "R_esolution:" msgstr "해상도(_E):" #: panels/appearance/font_render.ui.h:3 msgid "dots per inch" msgstr "도트 퍼 인치(DPI)" #: panels/appearance/font_render.ui.h:4 msgid "Smoothing" msgstr "부드럽게" #: panels/appearance/font_render.ui.h:5 msgid "_None" msgstr "안 함(_N)" #: panels/appearance/font_render.ui.h:6 msgid "Gra_yscale" msgstr "그레이스케일(_Y)" #: panels/appearance/font_render.ui.h:7 msgid "Sub_pixel (LCDs)" msgstr "서브픽셀(_P) (LCDs)" #: panels/appearance/font_render.ui.h:9 msgid "_Slight" msgstr "가늘게" #: panels/appearance/font_render.ui.h:10 msgid "N_one" msgstr "안 함(_O)" #: panels/appearance/font_render.ui.h:11 msgid "_Medium" msgstr "중간(_M)" #: panels/appearance/font_render.ui.h:12 msgid "_Full" msgstr "최대(_F)" #: panels/appearance/font_render.ui.h:13 msgid "Subpixel Order" msgstr "서브픽셀 방법" #: panels/appearance/font_render.ui.h:15 msgid "_RGB" msgstr "" #: panels/appearance/font_render.ui.h:17 msgid "_BGR" msgstr "" #: panels/appearance/font_render.ui.h:19 msgid "_VRGB" msgstr "" #: panels/appearance/font_render.ui.h:21 msgid "VB_GR" msgstr "" #: panels/appearance/ukui-wp-info.c:47 msgid "No Desktop Background" msgstr "배경화면이 없습니다" #: panels/appearance/ukui-wp-item.c:315 panels/appearance/ukui-wp-item.c:317 msgid "pixel" msgid_plural "pixels" msgstr[0] "픽셀" msgstr[1] "픽셀" #: panels/appearance/ukui-wp-item.c:327 #, c-format msgid "" "%s\n" "%s, %s\n" "File Path: %s\n" "Artist: %s" msgstr "" "%s\n" "%s, %s\n" "파일경로:%s\n" "제작자:%s" #: panels/appearance/ukui-wp-item.c:344 #, c-format msgid "" "%s\n" "%s\n" "File Path: %s\n" "Artist: %s" msgstr "" "%s\n" "%s\n" "파일경로:%s\n" "제작자:%s" #: panels/display/ukui-display-properties-install-systemwide.c:45 #, c-format msgid "" "Usage: %s SOURCE_FILE DEST_NAME\n" "\n" "This program installs a RANDR profile for multi-monitor setups into\n" "a systemwide location. The resulting profile will get used when\n" "the RANDR plug-in gets run in ukui-settings-daemon.\n" "\n" "SOURCE_FILE - a full pathname, typically /home/username/.config/monitors." "xml\n" "\n" "DEST_NAME - relative name for the installed file. This will get put in\n" " the systemwide directory for RANDR configurations,\n" " so the result will typically be %s/DEST_NAME\n" msgstr "" "사용: %s SOURCE_FILE DEST_NAME\n" "\n" "이 프로그램은 RANDR의 프로파일을 설치해서 시스템 전체의 \n" "멀티모니터를 설정합니다.RANDR 플러그인이 ukui-settings-daemon에 돌아가면\n" "프로파일이 만들어집니다.\n" "\n" "SOURCE_FILE - 절대경로, 보통 /home/username/.config/monitors.xml\n" "\n" "DEST_NAME - 상대경로일때 이용합니다.\n" " 시스템 전체의 RANDR 설정 디렉토리에 만들어집니다.\n" " 이 경로에 만들어질 것입니다.%s/DEST_NAME\n" #: panels/display/ukui-display-properties-install-systemwide.c:152 msgid "This program can only be used by the root user" msgstr "이 프로그램은 root 관리자만이 사용할 수 있습니다" #: panels/display/ukui-display-properties-install-systemwide.c:169 msgid "The source filename must be absolute" msgstr "소스 파일명은 절대경로여야합니다" #: panels/display/ukui-display-properties-install-systemwide.c:180 #, c-format msgid "Could not open %s: %s\n" msgstr "%s 파일을 열 수 없습니다: %s\n" #: panels/display/ukui-display-properties-install-systemwide.c:189 #, c-format msgid "Could not get information for %s: %s\n" msgstr "%s의 정보를 알 수 없습니다: %s\n" #: panels/display/ukui-display-properties-install-systemwide.c:196 #, c-format msgid "%s must be a regular file\n" msgstr "" #: panels/display/ukui-display-properties-install-systemwide.c:205 msgid "This program must only be run through pkexec(1)" msgstr "pkexec(1)을 통해사만 실행 가능합니다" #: panels/display/ukui-display-properties-install-systemwide.c:210 msgid "PKEXEC_UID must be set to an integer value" msgstr "PKEXEC_UID 는 정수로 설정해주세요" #: panels/display/ukui-display-properties-install-systemwide.c:216 #, c-format msgid "%s must be owned by you\n" msgstr "%s는 사용자의 소유여야 합니다\n" #: panels/display/ukui-display-properties-install-systemwide.c:224 #, c-format msgid "%s must not have any directory components\n" msgstr "%s은 모든 디렉토리 구성을 가지고 있지 않습니다\n" #: panels/display/ukui-display-properties-install-systemwide.c:232 #, c-format msgid "%s must be a directory\n" msgstr "%s는 디렉토리여야 합니다\n" #: panels/display/ukui-display-properties-install-systemwide.c:243 #, c-format msgid "Could not open %s/%s: %s\n" msgstr "다음을 열 수 없습니다 %s/%s: %s\n" #: panels/display/ukui-display-properties-install-systemwide.c:263 #, c-format msgid "Could not rename %s to %s: %s\n" msgstr "%s을 %s으로 이름을 바꿀 수 없습니다: %s\n" #: panels/display/xrandr-capplet.c:315 panels/display/xrandr-capplet.c:354 #: shell/shell.ui.h:1 msgid "Normal" msgstr "보통" #: panels/display/xrandr-capplet.c:316 #: panels/volume-control/gvc-balance-bar.c:112 shell/shell.ui.h:2 msgid "Left" msgstr "왼쪽" #: panels/display/xrandr-capplet.c:317 #: panels/volume-control/gvc-balance-bar.c:113 shell/shell.ui.h:3 msgid "Right" msgstr "오른쪽" #: panels/display/xrandr-capplet.c:318 shell/shell.ui.h:4 msgid "Upside-down" msgstr "위아래" #: panels/display/xrandr-capplet.c:360 #, c-format msgid "%d Hz" msgstr "" #: panels/display/xrandr-capplet.c:497 panels/display/xrandr-capplet.c:1744 msgid "Mirror Screens" msgstr "복제" #: panels/display/xrandr-capplet.c:499 #, c-format msgid "Monitor: %s" msgstr "모니터: %s" #. TRANSLATORS: a monitor is a device to measure voltage and current #: panels/display/xrandr-capplet.c:515 panels/power/kpm-upower.c:573 #: shell/mainwindow.c:509 shell/shell.ui.h:27 msgid "Monitor" msgid_plural "Monitors" msgstr[0] "모니터" #: panels/display/xrandr-capplet.c:632 #, c-format msgid "%d x %d" msgstr "" #: panels/display/xrandr-capplet.c:1600 msgid "" "Select a monitor to change its properties; drag it to rearrange its " "placement." msgstr "모니터의 설정을 위해 선택하시고 잡아끌어서 위치를 잡아주세요 " #: panels/display/xrandr-capplet.c:2204 msgid "Could not save the monitor configuration" msgstr "모니터의 설정을 저장할 수 없습니다" #: panels/display/xrandr-capplet.c:2226 msgid "Could not get session bus while applying display configuration" msgstr "화면 설정을 적용하는 동안에는 세션정보를 확인 할 수 없습니다" #: panels/display/xrandr-capplet.c:2245 msgid "Could not detect displays" msgstr "디스플레이가 잡히지 않습니다" #: panels/display/xrandr-capplet.c:2477 msgid "The monitor configuration has been saved" msgstr "모니터 설정이 저장되었습니다" #: panels/display/xrandr-capplet.c:2479 msgid "This configuration will be used the next time someone logs in." msgstr "이 설정은 다음에 로그인할 때 적용됩니다" #: panels/display/xrandr-capplet.c:2488 msgid "Could not set the default configuration for monitors" msgstr "모니터의 기본 설정을 적용할 수 없습니다" #: panels/display/xrandr-capplet.c:2557 #, fuzzy msgid "Could not get screen information" msgstr "%s의 정보를 알 수 없습니다: %s\n" #: panels/keyboard/ukui-keybinding-properties.c:1070 #: panels/keyboard/ukui-keybinding-properties.c:1693 msgid "Custom Shortcuts" msgstr "개인 설정 단축키" #: panels/keyboard/ukui-keybinding-properties.c:1379 #, c-format msgid "" "The shortcut \"%s\" is already used for\n" "\"%s\",please reset!!!" msgstr "" "단축키 “%s”은 이미 사용되고 있습니다.\n" "“%s”,다시 설정해주세요" #: panels/keyboard/ukui-keybinding-properties.c:1523 msgid "Add Shortcuts" msgstr "단축키 추가" #: panels/keyboard/ukui-keybinding-properties.c:1915 msgid "Selection Program" msgstr "프로그램 선택" #: panels/keyboard/ukui-keybinding-properties.c:1956 msgid "Function description" msgstr "기능 설명" #: panels/keyboard/ukui-keybinding-properties.c:1974 msgid "Hotkey" msgstr "단축키" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:1 msgid "Select the keyboard layout" msgstr "키보드 레이아웃 선택" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:2 msgid "_Variants:" msgstr "종류(_V):" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:3 msgid "_Country:" msgstr "국가(_C):" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:4 msgid "By _country" msgstr "국가에 따라(_C)" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:5 msgid "_Language:" msgstr "언어(_L):" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:6 msgid "By _language" msgstr "언어에 따라(_L):" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:7 msgid "Preview:" msgstr "미리보기" #: panels/keyboard/shortcut_dialog.ui.h:1 msgid "Custom Shortcut" msgstr "개인설정 단축키" #: panels/keyboard/shortcut_dialog.ui.h:2 #: panels/session-properties/main-table.ui.h:4 msgid "Name:" msgstr "이름:" #: panels/keyboard/shortcut_dialog.ui.h:3 msgid "Command" msgstr "명령:" #: panels/keyboard/shortcut_dialog.ui.h:4 msgid "Scan" msgstr "스캔" #: panels/network-proxy/network.ui.h:1 msgid "Network Proxy Details" msgstr "네트워크 프록시" #: panels/network-proxy/network.ui.h:2 msgid "User authentication" msgstr "사용자 인증" #: panels/network-proxy/network.ui.h:3 msgid "Username:" msgstr "사용자 이름:" #: panels/network-proxy/network.ui.h:4 msgid "Password:" msgstr "암호:" #: panels/power/kpm-common.c:52 msgid "Unknown time" msgstr "알 수 없는 시간" #: panels/power/kpm-common.c:57 #, c-format msgid "%i minutes" msgid_plural "%i minutes" msgstr[0] "%i 분" #: panels/power/kpm-common.c:68 #, c-format msgid "%i hours" msgid_plural "%i hours" msgstr[0] "%i 시" #: panels/power/kpm-common.c:74 #, c-format msgid "%i %s %i %s" msgstr "" #: panels/power/kpm-common.c:75 shell/shell.ui.h:58 msgid "hour" msgid_plural "hours" msgstr[0] "시" #: panels/power/kpm-common.c:76 msgid "minute" msgid_plural "minutes" msgstr[0] "분" #: panels/power/kpm-common.h:41 msgid "Power Manager" msgstr "전원 관리자" #: panels/power/kpm-common.h:42 msgid "Power Manager for the UKUI desktop" msgstr "UKUI 데스크탑을 위한 전원관리자" #: panels/power/kpm-prefs-core.c:187 panels/power/kpm-prefs-core.c:189 #: panels/power/kpm-prefs-core.c:805 msgid "Never" msgstr "안 함" #: panels/power/kpm-prefs-core.c:269 panels/power/kpm-prefs-core.c:272 msgid "Shutdown" msgstr "전원끄기" #: panels/power/kpm-prefs-core.c:281 panels/power/kpm-prefs-core.c:284 msgid "Hang" msgstr "절전" #: panels/power/kpm-prefs-core.c:289 panels/power/kpm-prefs-core.c:292 msgid "Sleep" msgstr "잠자기" #: panels/power/kpm-prefs-core.c:297 panels/power/kpm-prefs-core.c:300 msgid "Blank screen" msgstr "빈 화면" #: panels/power/kpm-prefs-core.c:305 panels/power/kpm-prefs-core.c:308 msgid "Ask" msgstr "묻기" #: panels/power/kpm-prefs-core.c:313 panels/power/kpm-prefs-core.c:316 msgid "Do not perform operations" msgstr "" #: panels/power/kpm-prefs-core.c:747 #, fuzzy, c-format msgid "%d hour" msgid_plural "%d hours" msgstr[0] "%d 시간" msgstr[1] "%d 시간" #: panels/power/kpm-prefs-core.c:750 #, c-format msgid "%d minute" msgid_plural "%d minutes" msgstr[0] "%d 분" msgstr[1] "%d 분" #: panels/power/kpm-prefs-core.c:753 #, c-format msgid "%d second" msgid_plural "%d seconds" msgstr[0] "%d 초" msgstr[1] "%d 초" #: panels/power/kpm-prefs-core.c:761 #, c-format msgid "%s %s %s" msgstr "" #: panels/power/kpm-prefs-core.c:766 panels/power/kpm-prefs-core.c:779 #, c-format msgid "%s %s" msgstr "" #: panels/power/kpm-prefs-core.c:771 panels/power/kpm-prefs-core.c:784 #: panels/power/kpm-prefs-core.c:790 #, c-format msgid "%s" msgstr "" #. TRANSLATORS: a phone is charging #. TRANSLATORS: device is charging, but we only have a percentage #: panels/power/kpm-upower.c:259 panels/power/kpm-upower.c:333 #, c-format msgid "%s charging (%.1f%%)" msgstr "%s 충전됨 (%.1f%%)" #. TRANSLATORS: The laptop battery is fully charged, and we know a time #: panels/power/kpm-upower.c:275 #, c-format msgid "" "Battery is fully charged.\n" "Provides %s laptop runtime" msgstr "" "배터리 충전 완료.\n" "%s 동안 구동될 수 있습니다" #. TRANSLATORS: the device is fully charged #: panels/power/kpm-upower.c:282 #, c-format msgid "%s is fully charged" msgstr "%s 완전히 충전 됨" #. TRANSLATORS: the device is discharging, and we have a time remaining #: panels/power/kpm-upower.c:292 #, c-format msgid "%s %s remaining (%.1f%%)" msgstr "%s %s 남았음 (%.1f%%)" #. TRANSLATORS: the device is discharging, but we only have a percentage #: panels/power/kpm-upower.c:299 #, c-format msgid "%s discharging (%.1f%%)" msgstr "%s 방전중 (%.1f%%)" #. TRANSLATORS: the device is charging, and we have a time to full and empty #: panels/power/kpm-upower.c:315 #, c-format msgid "" "%s %s until charged (%.1f%%)\n" "Provides %s battery runtime" msgstr "" "%s %s동안 충전 됨 (%.1f%%)\n" "%s 동안 배터리 구동됨" #. TRANSLATORS: device is charging, and we have a time to full and a percentage #: panels/power/kpm-upower.c:326 #, c-format msgid "%s %s until charged (%.1f%%)" msgstr "%s %s 동안 충전 됨(%.1f%%)" #. TRANSLATORS: this is only shown for laptops with multiple batteries #: panels/power/kpm-upower.c:341 #, c-format msgid "%s waiting to discharge (%.1f%%)" msgstr "%s 방전을 기다리는 중(%.1f%%)" #. TRANSLATORS: this is only shown for laptops with multiple batteries #: panels/power/kpm-upower.c:349 #, c-format msgid "%s waiting to charge (%.1f%%)" msgstr "%s 충전을 기다리는 중(%.1f%%)" #. TRANSLATORS: the type of data, e.g. Laptop battery #: panels/power/kpm-upower.c:410 msgid "Product:" msgstr "제품명:" #. TRANSLATORS: device is missing #. TRANSLATORS: device is charged #. TRANSLATORS: device is charging #. TRANSLATORS: device is discharging #: panels/power/kpm-upower.c:415 panels/power/kpm-upower.c:420 #: panels/power/kpm-upower.c:425 panels/power/kpm-upower.c:430 msgid "Status:" msgstr "현재 상태:" #: panels/power/kpm-upower.c:415 msgid "Missing" msgstr "못 찾음" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:420 panels/power/kpm-upower.c:730 msgid "Charged" msgstr "충전됨" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:425 panels/power/kpm-upower.c:718 msgid "Charging" msgstr "충전중" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:430 panels/power/kpm-upower.c:722 msgid "Discharging" msgstr "방전중" #. TRANSLATORS: percentage #: panels/power/kpm-upower.c:436 msgid "Percentage charge:" msgstr "충전 퍼센트:" #. TRANSLATORS: manufacturer #: panels/power/kpm-upower.c:441 msgid "Vendor:" msgstr "제조사:" #. TRANSLATORS: how the battery is made, e.g. Lithium Ion #: panels/power/kpm-upower.c:447 msgid "Technology:" msgstr "배터리방식:" #. TRANSLATORS: serial number of the battery #: panels/power/kpm-upower.c:452 msgid "Serial number:" msgstr "제품고유번호:" #. TRANSLATORS: model number of the battery #: panels/power/kpm-upower.c:457 msgid "Model:" msgstr "모델:" #. TRANSLATORS: time to fully charged #: panels/power/kpm-upower.c:463 msgid "Charge time:" msgstr "충전시간:" #. TRANSLATORS: time to empty #: panels/power/kpm-upower.c:470 msgid "Discharge time:" msgstr "방전시간:" #. TRANSLATORS: Excellent, Good, Fair and Poor are all related to battery Capacity #: panels/power/kpm-upower.c:479 msgid "Excellent" msgstr "매우좋음" #: panels/power/kpm-upower.c:483 msgid "Good" msgstr "좋음" #: panels/power/kpm-upower.c:487 msgid "Fair" msgstr "보통" #: panels/power/kpm-upower.c:491 msgid "Poor" msgstr "불량" #: panels/power/kpm-upower.c:495 msgid "Capacity:" msgstr "용량:" #: panels/power/kpm-upower.c:503 panels/power/kpm-upower.c:533 msgid "Current charge:" msgstr "현재 충전:" #: panels/power/kpm-upower.c:510 msgid "Last full charge:" msgstr "마지막 충전:" #: panels/power/kpm-upower.c:517 panels/power/kpm-upower.c:539 msgid "Design charge:" msgstr "" #: panels/power/kpm-upower.c:523 msgid "Charge rate:" msgstr "충전율:" #. TRANSLATORS: system power cord #: panels/power/kpm-upower.c:561 msgid "AC adapter" msgid_plural "AC adapters" msgstr[0] "교류 어댑터" #. TRANSLATORS: laptop primary battery #: panels/power/kpm-upower.c:565 msgid "Laptop battery" msgid_plural "Laptop batteries" msgstr[0] "랩탑 배터리" #. TRANSLATORS: battery-backed AC power source #: panels/power/kpm-upower.c:569 msgid "UPS" msgid_plural "UPSs" msgstr[0] "UPS" #. TRANSLATORS: wireless mice with internal batteries #: panels/power/kpm-upower.c:577 shell/mainwindow.c:450 shell/shell.ui.h:22 msgid "Mouse" msgid_plural "Mice" msgstr[0] "마우스" #. TRANSLATORS: wireless keyboard with internal battery #: panels/power/kpm-upower.c:581 shell/mainwindow.c:439 shell/shell.ui.h:21 msgid "Keyboard" msgid_plural "Keyboards" msgstr[0] "키보드" #. TRANSLATORS: portable device #: panels/power/kpm-upower.c:585 msgid "PDA" msgid_plural "PDAs" msgstr[0] "" msgstr[1] "" #. TRANSLATORS: cell phone (mobile...) #: panels/power/kpm-upower.c:589 msgid "Cell phone" msgid_plural "Cell phones" msgstr[0] "휴대전화" #. TRANSLATORS: media player, mp3 etc #: panels/power/kpm-upower.c:594 msgid "Media player" msgid_plural "Media players" msgstr[0] "미디어 재생기" #. TRANSLATORS: tablet device #: panels/power/kpm-upower.c:598 msgid "Tablet" msgid_plural "Tablets" msgstr[0] "태블릿" #. TRANSLATORS: tablet device #: panels/power/kpm-upower.c:602 msgid "Computer" msgid_plural "Computers" msgstr[0] "컴퓨터" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:673 msgid "Lithium Ion" msgstr "리튬 이온" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:677 msgid "Lithium Polymer" msgstr "리튬 폴리머" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:681 msgid "Lithium Iron Phosphate" msgstr "인산 철 리튬 " #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:685 msgid "Lead acid" msgstr "납축" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:689 msgid "Nickel Cadmium" msgstr "니켈-카드뮴" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:693 msgid "Nickel metal hydride" msgstr "니켈 메탈 하이드라이드" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:697 msgid "Unknown technology" msgstr "알 수 없음" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:726 msgid "Empty" msgstr "비었음" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:734 msgid "Waiting to charge" msgstr "충전 기다리는 중" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:738 msgid "Waiting to discharge" msgstr "방전 기다리는 중" #: panels/session-properties/gsm-app-dialog.c:145 msgid "Desktop file(*.desktop)" msgstr "아이콘 파일(*.desktop)" #: panels/session-properties/gsm-app-dialog.c:152 msgid "Select command" msgstr "명령 선택" #: panels/session-properties/gsm-app-dialog.c:257 msgid "Add programs" msgstr "프로그램 추가" #: panels/session-properties/gsm-app-dialog.c:261 msgid "Boot program property details" msgstr "시작 프로그램 속성" #: panels/session-properties/gsm-app-dialog.c:526 msgid "The startup command cannot be empty" msgstr "시작 명령은 빈 공간으로 둘 수 없습니다" #: panels/session-properties/gsm-app-dialog.c:532 msgid "The startup command is not valid" msgstr "올바른 시작 명령이 아닙니다" #: panels/session-properties/gsm-properties-dialog.c:427 #, c-format msgid "%d/%d/%d/ %d:%d:%d" msgstr "%d년%d월%d일 %d시%d분%d초" #: panels/session-properties/gsm-properties-dialog.c:508 msgid "property" msgstr "속성" #: panels/session-properties/gsm-properties-dialog.c:535 #, c-format msgid "%dByte" msgstr "%d바이트" #: panels/session-properties/main-table.ui.h:1 msgid "scan…" msgstr "스캔…" #: panels/session-properties/main-table.ui.h:2 msgid "Annotation:" msgstr "" #: panels/session-properties/main-table.ui.h:3 msgid "command:" msgstr "명령:" #: panels/session-properties/program_properties.ui.h:1 msgid "program name" msgstr "이름" #: panels/session-properties/program_properties.ui.h:2 msgid "File Type:" msgstr "유형:" #: panels/session-properties/program_properties.ui.h:3 msgid "File Description:" msgstr "설명:" #: panels/session-properties/program_properties.ui.h:4 msgid "Application" msgstr "应用程序" #: panels/session-properties/program_properties.ui.h:5 msgid "Program Location:" msgstr "위치:" #: panels/session-properties/program_properties.ui.h:6 msgid "Program Size:" msgstr "크기:" #: panels/session-properties/program_properties.ui.h:7 msgid "Access Time:" msgstr "접근했던 시간:" #: panels/session-properties/program_properties.ui.h:8 msgid "modification time:" msgstr "시간 수정:" #: panels/user-accounts/change-face.ui.h:1 msgid "Changge Face" msgstr "사진 바꾸기" #: panels/user-accounts/change-face.ui.h:2 #: panels/user-accounts/change-name.ui.h:2 #: panels/user-accounts/change-pwd.ui.h:2 #: panels/user-accounts/change-type.ui.h:2 #: panels/user-accounts/delete-user.ui.h:2 #: panels/user-accounts/user-accounts.c:1835 #: panels/user-accounts/user-create.ui.h:2 msgid "Cancel" msgstr "취소" #: panels/user-accounts/change-face.ui.h:3 #: panels/user-accounts/change-name.ui.h:3 #: panels/user-accounts/change-pwd.ui.h:3 #: panels/user-accounts/change-type.ui.h:3 #: panels/user-accounts/user-accounts.c:1836 msgid "Ok" msgstr "확인" #: panels/user-accounts/change-face.ui.h:4 #: panels/user-accounts/change-name.ui.h:4 #: panels/user-accounts/change-pwd.ui.h:4 #: panels/user-accounts/change-type.ui.h:5 #: panels/user-accounts/delete-user.ui.h:5 msgid "label" msgstr "" #: panels/user-accounts/change-face.ui.h:5 #: panels/user-accounts/user-accounts.c:1832 msgid "Browse more pictures" msgstr "더 많은 사진 찾기" #: panels/user-accounts/change-name.ui.h:1 msgid "Change Name" msgstr "바꾼 이" #: panels/user-accounts/change-pwd.ui.h:1 msgid "Change Password" msgstr "암호 바꾸기" #: panels/user-accounts/change-type.ui.h:1 msgid "Change Usertype" msgstr "사용자 유형 바꾸기" #: panels/user-accounts/change-type.ui.h:4 msgid "automatic logon" msgstr "자동 로그온" #: panels/user-accounts/change-type.ui.h:6 msgid "" "Please make sure that the computer has at least one user is the administrator" msgstr "컴퓨터마다 최소한 한 명의 관리자가 필요합니다" #: panels/user-accounts/change-type.ui.h:7 #: panels/user-accounts/user-create.ui.h:5 msgid "Standard User" msgstr "보통 사용자" #: panels/user-accounts/change-type.ui.h:8 msgid "" "Standard users can use most software, but you can not install software and \n" "change settings that affect all users." msgstr "" "보통 사용자는 대부분의 프로그램을 사용할 수 있습니다.\n" "하지만 프로그램을 설치하거나 시스템 전반적인 설정을 할 수 없습니다." #: panels/user-accounts/change-type.ui.h:10 #: panels/user-accounts/user-accounts.c:643 #: panels/user-accounts/user-accounts.c:884 #: panels/user-accounts/user-accounts.c:1024 #: panels/user-accounts/user-accounts.c:1086 #: panels/user-accounts/user-accounts.c:1087 #: panels/user-accounts/user-accounts.c:1157 #: panels/user-accounts/user-accounts.c:1369 #: panels/user-accounts/user-accounts.c:1465 #: panels/user-accounts/user-create.ui.h:8 msgid "Administrators" msgstr "관리자" #: panels/user-accounts/change-type.ui.h:11 #: panels/user-accounts/user-create.ui.h:9 msgid "" "Administrator can make any changes needed on the system, including \n" "installing and upgrading software." msgstr "" "관리자는 프로그램 설치를 포함한 시스템 전반적인 모든 것을 바꿀 수 있습니다." #: panels/user-accounts/delete-user.ui.h:1 msgid "Delete User" msgstr "기본 사용자" #: panels/user-accounts/delete-user.ui.h:3 msgid "Keep File" msgstr "파일 그대로 두기" #: panels/user-accounts/delete-user.ui.h:4 msgid "Delete File" msgstr "파일 삭제" #: panels/user-accounts/run-passwd.c:221 msgid "Authentication failure!" msgstr "인증 실패!" #: panels/user-accounts/run-passwd.c:298 msgid "New password length is too short!" msgstr "새로운 암호가 너무 짧습니다!" #: panels/user-accounts/run-passwd.c:304 msgid "The new password is too simple!" msgstr "새로운 암호가 너무 간단합니다!" #: panels/user-accounts/run-passwd.c:310 msgid "The new password is too similar to the old one!" msgstr "새로운 암호가 기존의 것과 너무 비슷합니다!" #: panels/user-accounts/run-passwd.c:313 msgid "The new password must contain numbers or special characters!" msgstr "암호는 숫자나 특수문자만 가능합니다!" #: panels/user-accounts/run-passwd.c:317 msgid "The new password is the same as the old one!" msgstr "새로운 암호가 기존의 것과 똑같습니다!" #: panels/user-accounts/run-passwd.c:320 msgid "The new password has been used recently!" msgstr "이미 쓰인적이 있는 암호입니다!" #: panels/user-accounts/run-passwd.c:324 msgid "Your password has been changed after you verify!" msgstr "암호가 바뀌었습니다!" #: panels/user-accounts/user-accounts.c:166 msgid "User name cannot be empty!" msgstr "이름은 비울 수 없습니다!" #: panels/user-accounts/user-accounts.c:183 msgid "Password length needs to more than 5 digits!" msgstr "암호는 5글자 이상으로 해주세요!" #: panels/user-accounts/user-accounts.c:202 msgid "enter the password twice inconsistencies!" msgstr "2次输入密码不一致!" #: panels/user-accounts/user-accounts.c:220 #: panels/user-accounts/user-accounts.c:725 msgid "The first character cannot be underlined!" msgstr "첫글자는 언더라인(_)이 될 수 없습니다!" #: panels/user-accounts/user-accounts.c:226 #: panels/user-accounts/user-accounts.c:731 msgid "User name can not contain capital letters!" msgstr "사용자 이름은 대문자를 쓸 수 없습니다!" #: panels/user-accounts/user-accounts.c:234 #: panels/user-accounts/user-accounts.c:739 msgid "The user name can only be composed of letters, numbers and underline!" msgstr "사용자 이름에는 문자와 숫자 언더라인(_)만이 가능합니다!" #: panels/user-accounts/user-accounts.c:241 msgid "The first character cannot be numeric!" msgstr "첫번째 글자는 숫자가 될 수 없습니다!" #: panels/user-accounts/user-accounts.c:255 #: panels/user-accounts/user-accounts.c:321 #: panels/user-accounts/user-accounts.c:2264 msgid "Please enter the username" msgstr "사용자 이름을 입력해주세요" #: panels/user-accounts/user-accounts.c:256 msgid "Please enter the password " msgstr "암호를 입력해주세요" #: panels/user-accounts/user-accounts.c:267 msgid "The user name is already in use, please use a different one." msgstr "사용중인 이름입니다. 다른 이름을 입력해주세요!" #: panels/user-accounts/user-accounts.c:290 msgid "" "The user name corresponds to the group already exists,please use a different " "user name" msgstr "이름이 이미 그룹에서 쓰이고 있습니다. 다른 이름을 입력해주세요" #: panels/user-accounts/user-accounts.c:306 msgid "username length should not long than 32!" msgstr "사용자 이름은 32글자 이상이 될 수 없습니다!" #: panels/user-accounts/user-accounts.c:321 #: panels/user-accounts/user-accounts.c:897 msgid "Please enter the new username" msgstr "새로운 이름을 입력해주세요" #: panels/user-accounts/user-accounts.c:323 #: panels/user-accounts/user-accounts.c:2271 msgid "Please enter the password" msgstr "암호를 입력해주세요" #: panels/user-accounts/user-accounts.c:323 #: panels/user-accounts/user-accounts.c:589 #: panels/user-accounts/user-accounts.c:680 msgid "Please enter new password" msgstr "암호를 입력해주세요" #: panels/user-accounts/user-accounts.c:324 #: panels/user-accounts/user-accounts.c:351 #: panels/user-accounts/user-accounts.c:575 #: panels/user-accounts/user-accounts.c:666 msgid "Please enter the current password" msgstr "현재 암호를 입력해주세요" #: panels/user-accounts/user-accounts.c:324 #: panels/user-accounts/user-accounts.c:351 #: panels/user-accounts/user-accounts.c:359 msgid "Please enter the new password" msgstr "새로운 암호를 입력해주세요" #: panels/user-accounts/user-accounts.c:324 #: panels/user-accounts/user-accounts.c:352 #: panels/user-accounts/user-accounts.c:359 #: panels/user-accounts/user-accounts.c:599 #: panels/user-accounts/user-accounts.c:689 #: panels/user-accounts/user-accounts.c:2276 msgid "Please confirm the new password" msgstr "암호를 다시 입력해주세요" #: panels/user-accounts/user-accounts.c:401 msgid "Please choose another password." msgstr "다른 암호를 사용해주세요." #: panels/user-accounts/user-accounts.c:415 msgid "Please reenter the current password." msgstr "현재 암호를 다시 입력해주세요" #: panels/user-accounts/user-accounts.c:422 msgid "Password can not be modified." msgstr "암호를 수정할 수 없었습니다" #: panels/user-accounts/user-accounts.c:463 msgid "Password length is too short!" msgstr "암호가 너무 짧습니다!" #: panels/user-accounts/user-accounts.c:464 msgid "" "Password length needs to more than 5 digits, and composed of letters, \n" " numbers or special characters." msgstr "암호는 5글자 이상의 알파벳 문자나 숫자, 특수문자로 이루어져야 합니다." #: panels/user-accounts/user-accounts.c:466 msgid "Password error" msgstr "암호 오류" #: panels/user-accounts/user-accounts.c:467 msgid "Please make sure you enter the password two times." msgstr "암호를 두번 입력해 주세요" #: panels/user-accounts/user-accounts.c:548 msgid "Password input error, please re-enter!" msgstr "암호 입력 오류 다시 입력해주세요!" #: panels/user-accounts/user-accounts.c:645 #: panels/user-accounts/user-accounts.c:886 #: panels/user-accounts/user-accounts.c:1026 #: panels/user-accounts/user-accounts.c:1091 #: panels/user-accounts/user-accounts.c:1092 #: panels/user-accounts/user-accounts.c:1162 #: panels/user-accounts/user-accounts.c:1371 #: panels/user-accounts/user-accounts.c:1467 msgid "Standard user" msgstr "일반 사용자" #: panels/user-accounts/user-accounts.c:650 #: panels/user-accounts/user-accounts.c:890 #: panels/user-accounts/user-accounts.c:1030 #: panels/user-accounts/user-accounts.c:1167 #: panels/user-accounts/user-accounts.c:1402 #: panels/user-accounts/user-accounts.c:1472 msgid "Logged(Current User)" msgstr "로그인 됨(현재 사용자)" #: panels/user-accounts/user-accounts.c:655 #: panels/user-accounts/user-accounts.c:892 #: panels/user-accounts/user-accounts.c:1032 #: panels/user-accounts/user-accounts.c:1169 #: panels/user-accounts/user-accounts.c:1406 #: panels/user-accounts/user-accounts.c:1476 msgid "Logged(Other Users)" msgstr "로그인 됨(다른 사용자)" #: panels/user-accounts/user-accounts.c:659 #: panels/user-accounts/user-accounts.c:894 #: panels/user-accounts/user-accounts.c:1034 #: panels/user-accounts/user-accounts.c:1171 #: panels/user-accounts/user-accounts.c:1410 #: panels/user-accounts/user-accounts.c:1480 msgid "Un-login(Other Users)" msgstr "로그인 안 함(다른 유저들)" #: panels/user-accounts/user-accounts.c:746 msgid "User name cannot start with number!" msgstr "이름은 숫자로 시작 될 수 없습니다!" #: panels/user-accounts/user-accounts.c:758 msgid "The user name has been used, please replace with another one!" msgstr "이미 쓰이고 있는 이름입니다. 다른 이름을 입력해주세요!" #: panels/user-accounts/user-accounts.c:789 #: panels/user-accounts/user-accounts.c:826 msgid "Modify username failed!" msgstr "이름 수정 실패!" #: panels/user-accounts/user-accounts.c:834 msgid "the user has logged in, please log out and modify!" msgstr "로그인 중입니다. 로그아웃하신 뒤 수정해주세요!" #: panels/user-accounts/user-accounts.c:1281 msgid "The user can not be deleted!" msgstr "사용자가 삭제되었습니다!" #: panels/user-accounts/user-accounts.c:1288 msgid "" "The user has logged in, please perform the delete operation after logging " "out!" msgstr "로그인 중인 사용자입니다. 로그 아웃후에 삭제를 진행하세요!" #: panels/user-accounts/user-accounts.c:1312 #, c-format msgid "" "do you confirm to delete all the files of " "%s?" msgstr "" "%s의 파일을 모두 삭제하시겠습니까?" #: panels/user-accounts/user-accounts.c:1316 #, c-format msgid "" "if you want to delete the %s user, belonging to the user's desktop, " "documents, favorites, music, pictures and video folder will be deleted!" msgstr "" "사용자 %s 삭제하시면 그 사용자의 바탕화면, 문서, 즐겨찾기, 사진, 동영상 폴더" "가\n" "모두 삭제됩니다!" #: panels/user-accounts/user-accounts.c:1374 msgid "Rename" msgstr "이름 바꾸기" #: panels/user-accounts/user-accounts.c:1380 msgid "Change PWD" msgstr "암호 바꾸기" #: panels/user-accounts/user-accounts.c:1385 msgid "Change Face" msgstr "사진 바꾸기" #: panels/user-accounts/user-accounts.c:1390 msgid "Change Type" msgstr "유형 바꾸기" #: panels/user-accounts/user-accounts.c:1395 msgid "Delete" msgstr "삭제" #: panels/user-accounts/user-accounts.c:1500 msgid "My Account" msgstr "내 계정" #: panels/user-accounts/user-accounts.c:1505 #: panels/user-accounts/user-accounts.c:2148 msgid "Other accounts" msgstr "다른 계정" #: panels/user-accounts/user-accounts.c:1981 msgid "Browse more pictures..." msgstr "더 많은 사진 찾기..." #: panels/user-accounts/user-create.ui.h:1 msgid "Create Account" msgstr "계정 만들기" #: panels/user-accounts/user-create.ui.h:3 msgid "Automatic Logon" msgstr "자동 로그온" #: panels/user-accounts/user-create.ui.h:4 msgid "select picture" msgstr "사진 선택" #: panels/user-accounts/user-create.ui.h:6 msgid "" "Standard users can use most software, but you can not install software\n" "and change settings that affect all users." msgstr "" "보통 사용자는 대부분의 프로그램을 사용할 수 있습니다.\n" "하지만 프로그램을 설치하거나 시스템 전반적인 설정을 할 수 없습니다." #: panels/volume-control/gvc-balance-bar.c:116 msgid "Rear" msgstr "뒤" #: panels/volume-control/gvc-balance-bar.c:117 msgid "Front" msgstr "앞" #: panels/volume-control/gvc-balance-bar.c:120 msgid "Minimum" msgstr "최소" #: panels/volume-control/gvc-balance-bar.c:121 msgid "Maximum" msgstr "최대" #: panels/volume-control/gvc-balance-bar.c:299 msgid "_Balance(_B):" msgstr "균형(_B):" #: panels/volume-control/gvc-balance-bar.c:302 msgid "_Fade(_F):" msgstr "서서히(_F):" #: panels/volume-control/gvc-balance-bar.c:305 msgid "_Subwoofer(_S):" msgstr "서브우퍼(_S):" #: panels/volume-control/gvc-channel-bar.c:608 msgid "Unamplified" msgstr "증폭하지 않음" #: panels/volume-control/gvc-channel-bar.c:870 msgid "Mute" msgstr "조용히" #: panels/volume-control/gvc-combo-box.c:169 msgid "_Profile(_P):" msgstr "프로필(_P):" #: panels/volume-control/gvc-mixer-control.c:1004 msgid "Disabled" msgstr "사용 안 함" #: panels/volume-control/gvc-mixer-control.c:1011 #, c-format msgid "%u Output" msgid_plural "%u Outputs" msgstr[0] "%u 출력" #: panels/volume-control/gvc-mixer-control.c:1021 #, c-format msgid "%u Input" msgid_plural "%u Inputs" msgstr[0] "%u 입력" #: panels/volume-control/gvc-mixer-dialog.c:313 msgid "Co_nnector" msgstr "커넥터(_N)" #: panels/volume-control/gvc-mixer-dialog.c:521 msgid "Peak detect" msgstr "최대 확인" #: panels/volume-control/gvc-mixer-dialog.c:608 msgid "Co_nnector:" msgstr "커넥터(_N):" #: panels/volume-control/gvc-mixer-dialog.c:1501 msgid "Device" msgstr "장치" #: panels/volume-control/gvc-mixer-dialog.c:1549 #, c-format msgid "Speaker Testing for %s" msgstr "%s 스피커 시험" #: panels/volume-control/gvc-mixer-dialog.c:1608 msgid "_Profiles:" msgstr "프로파일(_P):" #: panels/volume-control/gvc-mixer-dialog.c:1609 msgid "Test Speakers" msgstr "스피커 시험" #: panels/volume-control/gvc-mixer-dialog.c:1708 #: panels/volume-control/gvc-sound-theme-chooser.c:887 msgid "Name" msgstr "이름" #: panels/volume-control/gvc-mixer-dialog.c:1787 msgid "Sound Output Volume" msgstr "출력 음량(_O):" #: panels/volume-control/gvc-mixer-dialog.c:1818 msgid "Sound Effects" msgstr "효과음" #: panels/volume-control/gvc-mixer-dialog.c:1825 msgid "_Alert volume: " msgstr "알림음 음량(_A): " #: panels/volume-control/gvc-mixer-dialog.c:1838 msgid "Hardware" msgstr "장치" #: panels/volume-control/gvc-mixer-dialog.c:1843 msgid "C_hoose a device to configure:" msgstr "설정할 장치를 선택해주세요(_H):" #: panels/volume-control/gvc-mixer-dialog.c:1870 #: panels/volume-control/gvc-mixer-dialog.c:1999 msgid "Settings for the selected device:" msgstr "다음과 같은 장치 설정함:" #: panels/volume-control/gvc-mixer-dialog.c:1881 msgid "Input" msgstr "입력" #: panels/volume-control/gvc-mixer-dialog.c:1888 msgid "_Input volume: " msgstr "녹음 음량(_I): " #: panels/volume-control/gvc-mixer-dialog.c:1911 msgid "Input level:" msgstr "입력 수준:" #: panels/volume-control/gvc-mixer-dialog.c:1937 msgid "C_hoose a device for sound input:" msgstr "녹음 장치를 선택해 주세요(_H):" #: panels/volume-control/gvc-mixer-dialog.c:1967 msgid "Output" msgstr "출력" #: panels/volume-control/gvc-mixer-dialog.c:1972 msgid "C_hoose a device for sound output:" msgstr "출력 장치를 선택해주세요(_H):" #: panels/volume-control/gvc-mixer-dialog.c:2017 msgid "Applications" msgstr "프로그램" #: panels/volume-control/gvc-mixer-dialog.c:2021 msgid "No application is currently playing or recording audio." msgstr "현재 소리를 재생하거나 녹음하는 프로그램이 없습니다." #: panels/volume-control/gvc-mixer-dialog.c:2146 #: panels/volume-control/gvc-sound-theme-chooser.c:752 #: panels/volume-control/gvc-sound-theme-chooser.c:764 #: panels/volume-control/gvc-sound-theme-chooser.c:776 msgid "Sound Preferences" msgstr "소리 설정" #: panels/volume-control/gvc-sound-theme-chooser.c:223 #: panels/volume-control/gvc-sound-theme-chooser.c:863 msgid "Default" msgstr "기본" #: panels/volume-control/gvc-sound-theme-chooser.c:335 msgid "No sounds" msgstr "소리 없음" #: panels/volume-control/gvc-sound-theme-chooser.c:457 msgid "Built-in" msgstr "내장" #: panels/volume-control/gvc-sound-theme-chooser.c:642 #: panels/volume-control/sound-theme-file-utils.c:291 msgid "Custom" msgstr "개인 설정" #: panels/volume-control/gvc-sound-theme-chooser.c:755 #: panels/volume-control/gvc-sound-theme-chooser.c:766 #: panels/volume-control/gvc-sound-theme-chooser.c:778 msgid "Testing event sound" msgstr "소리 테스트" #: panels/volume-control/gvc-sound-theme-chooser.c:864 msgid "From theme" msgstr "테마로 부터" #: panels/volume-control/gvc-sound-theme-chooser.c:894 msgid "Type" msgstr "유형" #: panels/volume-control/gvc-sound-theme-chooser.c:1088 msgid "Sound _theme:" msgstr "소리 테마:" #: panels/volume-control/gvc-sound-theme-chooser.c:1101 msgid "C_hoose an alert sound:" msgstr "알림음을 선택해주세요(_H):" #: panels/volume-control/gvc-sound-theme-chooser.c:1135 msgid "Enable _window and button sounds" msgstr "창 활성화 및 버튼 소리(_W)" #: panels/volume-control/gvc-speaker-test.c:219 msgid "Stop" msgstr "정지" #: panels/volume-control/gvc-speaker-test.c:219 #: panels/volume-control/gvc-speaker-test.c:331 msgid "Test" msgstr "시험" #: panels/volume-control/gvc-speaker-test.c:227 msgid "Subwoofer" msgstr "서브우퍼" #: shell/mainwindow.c:111 msgid "-Kylin Control Center" msgstr "" #: shell/mainwindow.c:218 shell/shell.ui.h:11 msgid "Control Center" msgstr "제어 센터" #: shell/mainwindow.c:381 msgid "Time and Dates" msgstr "시간과 날짜" #: shell/mainwindow.c:384 msgid " Change the time and date of this computer " msgstr " 컴퓨터의 날짜와 시간을 바꿉니다. " #: shell/mainwindow.c:392 shell/shell.ui.h:13 msgid "User Account" msgstr "사용자 계정" #: shell/mainwindow.c:395 msgid "" " Change the computer user account \n" " settings and password" msgstr "" " 컴퓨터의 사용자 계정과\n" "암호를 바꿉니다." #: shell/mainwindow.c:403 shell/shell.ui.h:14 msgid "Personalization" msgstr "개인화" #: shell/mainwindow.c:406 msgid "" " Change the computer desktop background \n" " and related theme" msgstr "" " 바탕화면 배경을 바꾸고 \n" "테마를 설정합니다." #: shell/mainwindow.c:414 msgid "Default Application" msgstr "기본 프로그램" #: shell/mainwindow.c:417 msgid " Change the default application on this computer " msgstr " 컴퓨터의 기본 프로그램을 바꿉니다 " #: shell/mainwindow.c:431 msgid " Change the network on this computer " msgstr " 네트워크를 설정합니다" #: shell/mainwindow.c:442 msgid " Change the keyboard settings on this computer " msgstr " 키보드의 설정을 바꿉니다 " #: shell/mainwindow.c:453 msgid " Change the mouse settings on this computer " msgstr " 마우스의 설정을 바꿉니다 " #: shell/mainwindow.c:467 msgid " Configure the connection to the computer printer " msgstr " 프린터를 설정하고 연결합니다 " #: shell/mainwindow.c:475 shell/shell.ui.h:24 msgid "Sound" msgstr "소리" #: shell/mainwindow.c:478 msgid " Change the sound settings on this computer " msgstr " 컴퓨터의 소리를 설정합니다 " #: shell/mainwindow.c:487 msgid "Network Agent" msgstr "네트워크 관리" #: shell/mainwindow.c:490 msgid " Change the network agent on this computer " msgstr " 네트워크 관련된 설정을 합니다 " #: shell/mainwindow.c:498 shell/shell.ui.h:17 msgid "Autostart" msgstr "시작프로그램" #: shell/mainwindow.c:501 msgid " Change the autostart program on this computer " msgstr " 컴퓨터를 켤때 자동으로 시작되는 프로그램을 설정합니다" #: shell/mainwindow.c:511 msgid " Change the Monitor settings on this computer " msgstr " 모니터와 디스플레이에 관하여 설정합니다" #: shell/mainwindow.c:522 msgid "Power Management" msgstr "전원 관리자" #: shell/mainwindow.c:525 msgid " Change the power management settings on this computer " msgstr " 컴퓨터의 전원과 관련된 설정을 합니다 " #: shell/mainwindow.c:533 msgid "System Check" msgstr "시스템 체크" #: shell/mainwindow.c:536 msgid "check the system detection information on this computer " msgstr "이 컴퓨터의 시스템 정보를 체크합니다" #: shell/shell.ui.h:5 msgid "Tile" msgstr "바둑판형" #: shell/shell.ui.h:6 msgid "Zoom" msgstr "확대/축소" #: shell/shell.ui.h:7 msgid "Center" msgstr "가운데" #: shell/shell.ui.h:8 msgid "Scale" msgstr "늘이기" #: shell/shell.ui.h:9 msgid "Stretch" msgstr "꽉차게" #: shell/shell.ui.h:10 msgid "Span" msgstr "걸쳐서(스팬)" #: shell/shell.ui.h:12 msgid "Time Dates" msgstr "날짜/시간" #: shell/shell.ui.h:15 msgid "" "Default \n" "Application" msgstr "기본 프로그램" #: shell/shell.ui.h:18 msgid "System Configuration" msgstr "시스템 설정" #: shell/shell.ui.h:19 msgid "" "Network \n" "Connections" msgstr "네트워크 연결" #: shell/shell.ui.h:23 msgid "Printer" msgstr "프린터" #: shell/shell.ui.h:25 msgid "" "Network \n" "Agent" msgstr "네트워크 관리" #: shell/shell.ui.h:28 msgid "" "Power \n" "Management" msgstr "전원관리자" #: shell/shell.ui.h:30 msgid "Hardware Configure" msgstr "장치설정" #: shell/shell.ui.h:31 msgid "Home" msgstr "홈" #: shell/shell.ui.h:32 msgid "Time Dates_" msgstr "시간/날짜" #: shell/shell.ui.h:33 msgid "User Account_" msgstr "사용자계정" #: shell/shell.ui.h:34 msgid "Personalization_" msgstr "개인화" #: shell/shell.ui.h:35 msgid "Default APP" msgstr "기본프로그램" #: shell/shell.ui.h:36 msgid "Autostart_" msgstr "시작프로그램" #: shell/shell.ui.h:37 msgid "Keyboard_" msgstr "키보드" #: shell/shell.ui.h:38 msgid "Mouse_" msgstr "마우스" #: shell/shell.ui.h:39 msgid "Sound_" msgstr "소리" #: shell/shell.ui.h:40 msgid "Network Agent_" msgstr "네트워크 관리" #: shell/shell.ui.h:41 msgid "Monitor_" msgstr "모니터" #: shell/shell.ui.h:42 msgid "Power Manage" msgstr "전원관리자" #: shell/shell.ui.h:43 msgid "Tzone:" msgstr "시간대:" #: shell/shell.ui.h:44 msgid "date:" msgstr "날짜:" #: shell/shell.ui.h:45 msgid "time:" msgstr "시간:" #: shell/shell.ui.h:46 msgid " Jan" msgstr " 1월" #: shell/shell.ui.h:47 msgid " Feb" msgstr " 2월" #: shell/shell.ui.h:48 msgid " Mar" msgstr " 3월" #: shell/shell.ui.h:49 msgid " Apr" msgstr " 4월" #: shell/shell.ui.h:50 msgid " May" msgstr " 5월" #: shell/shell.ui.h:51 msgid " Jun" msgstr " 6월" #: shell/shell.ui.h:52 msgid " Jul" msgstr " 7월" #: shell/shell.ui.h:53 msgid " Aug" msgstr " 8월" #: shell/shell.ui.h:54 msgid " Sep" msgstr " 9월" #: shell/shell.ui.h:55 msgid " Oct" msgstr " 10월" #: shell/shell.ui.h:56 msgid " Nov" msgstr " 11월" #: shell/shell.ui.h:57 msgid " Dec" msgstr " 12월" #: shell/shell.ui.h:59 msgid "min" msgstr "분" #: shell/shell.ui.h:60 msgid "sec" msgstr "초" #: shell/shell.ui.h:61 msgid "With the network time synchronization" msgstr "네트워크 시간과 동기화" #: shell/shell.ui.h:62 msgid "Create a new account" msgstr "새로운 계정 만들기" #: shell/shell.ui.h:63 msgid "Add" msgstr "추가" #: shell/shell.ui.h:64 msgid "delete" msgstr "삭제" #: shell/shell.ui.h:65 msgid "Style:" msgstr "스타일:" #: shell/shell.ui.h:66 msgid "wallpaper" msgstr "배경화면" #: shell/shell.ui.h:67 msgid "Select the one you love color as the theme color" msgstr "원하시는 색상을 고르세요" #: shell/shell.ui.h:68 msgid "Theme color" msgstr "테마색상" #: shell/shell.ui.h:69 msgid "Font choice:" msgstr "글꼴 선택:" #: shell/shell.ui.h:70 msgid "Font size :" msgstr "글꼴 크기:" #: shell/shell.ui.h:72 #, no-c-format msgid "small(S) --100%(default)" msgstr "작은글씨(S) --100%(기본)" #: shell/shell.ui.h:74 #, no-c-format msgid "medium(M)--125%" msgstr "중간(M)--125%" #: shell/shell.ui.h:76 #, no-c-format msgid "large (L) --150%" msgstr "큰 글씨 (L) --150%" #: shell/shell.ui.h:77 msgid "Please select the clearest sample text" msgstr "가장 깔끔하게 보이는 글자를 선택하세요" #: shell/shell.ui.h:78 msgid "Restore Defaults" msgstr "기본값" #: shell/shell.ui.h:79 msgid "Font" msgstr "글꼴" #: shell/shell.ui.h:80 msgid "Internet" msgstr "인터넷" #: shell/shell.ui.h:81 msgid " Web Browser:" msgstr " 웹브라우저:" #: shell/shell.ui.h:82 msgid " Mail Reader:" msgstr " 메일 클라이언트:" #: shell/shell.ui.h:83 msgid "Multimedia" msgstr "멀티미디어" #: shell/shell.ui.h:84 msgid " Image Viewer:" msgstr " 그림보기:" #: shell/shell.ui.h:85 msgid " Audio Player:" msgstr " 음악 재생:" #: shell/shell.ui.h:86 msgid " Video Player:" msgstr " 동영상 재생:" #: shell/shell.ui.h:87 msgid "System" msgstr "시스템" #: shell/shell.ui.h:88 msgid " Text Editor:" msgstr " 텍스트 편집기:" #: shell/shell.ui.h:89 msgid " File Manager:" msgstr " 파일 관리자:" #: shell/shell.ui.h:90 msgid "Network Connections" msgstr "네트워크 연결" #: shell/shell.ui.h:91 msgid "Repeat Keys" msgstr "반복 키" #: shell/shell.ui.h:92 msgid "Key presses _repeat when key is held down" msgstr "키를 누르고 있으면 키가 반복적으로 눌리게 하기(R)" #: shell/shell.ui.h:93 msgid "_Delay:" msgstr "지연(D):" #: shell/shell.ui.h:94 msgid "_Speed:" msgstr "속도(S):" #: shell/shell.ui.h:95 msgid "Short" msgstr "짧게" #: shell/shell.ui.h:96 msgid "Slow" msgstr "느리게" #: shell/shell.ui.h:97 msgid "Repeat keys speed" msgstr "반복 키 속도" #: shell/shell.ui.h:98 msgid "Long" msgstr "길게" #: shell/shell.ui.h:99 msgid "Fast" msgstr "빠르게" #: shell/shell.ui.h:100 msgid "To test the repetition rate of the input character:" msgstr "문자 입력 속도를 확인해보세요:" #: shell/shell.ui.h:101 msgid "Cursor Blinking" msgstr "커서 깜빡임" #: shell/shell.ui.h:102 msgid "Cursor _blinks in text fields" msgstr "문자 입력 필드에서 커서 깜빡임(B)" #: shell/shell.ui.h:103 msgid "S_peed:" msgstr "속도(P):" #: shell/shell.ui.h:104 msgid "Cursor blinks speed" msgstr "깜빡임 속도" #: shell/shell.ui.h:105 msgid "General" msgstr "보통" #: shell/shell.ui.h:106 msgid "" "Please add the language you will use to the list. And the first one in the " "list is the most\n" "commonly used language." msgstr "" "언어 리스트에서 사용할 언어를 추가해주세요. \n" "가장 처음에 온 언어가 일반적으로 가장 많이 쓰이는 \n" "언어가 됩니다." #: shell/shell.ui.h:108 msgid "_Show..." msgstr "보여주기" #: shell/shell.ui.h:109 msgid "List of keyboard layouts selected for usage" msgstr "선택된 키보드 레이아웃 리스트" #: shell/shell.ui.h:110 msgid "_Separate layout for each window" msgstr "각 창마다 다른 레이아웃 적용(S)" #: shell/shell.ui.h:111 msgid "New windows u_se active window's layout" msgstr "새 창에도 활성화된 창의 레이아웃 적용(S)" #: shell/shell.ui.h:112 msgid "Reset to De_faults" msgstr "기본값으로 되돌리기(_F)" #: shell/shell.ui.h:113 msgid "Layouts" msgstr "레이아웃" #: shell/shell.ui.h:114 msgid "" "\"To edit a shortcut key, click on the corresponding row and type a new key " "\"\n" "\"combination, or press backspace to clear.\"" msgstr "" "\"단축키를 설정하려면 각 열을 클릭하신 뒤에 새로운 키조합을 눌러주세요.\"\n" "\".BackSpace를 누르시면 삭제됩니다.\"" #: shell/shell.ui.h:116 msgid "Shortcut" msgstr "단축키" #: shell/shell.ui.h:117 msgid "_Right-handed" msgstr "오른손 잡이" #: shell/shell.ui.h:118 msgid "_Left-handed" msgstr "왼손잡이" #: shell/shell.ui.h:119 msgid "Sh_ow position of pointer when the Control key is pressed" msgstr "Control키가 눌렸을 때 포인터 보이기" #: shell/shell.ui.h:120 msgid "_Sensitivity:" msgstr "민감도:" #: shell/shell.ui.h:121 msgid "Low" msgstr "낮게" #: shell/shell.ui.h:122 msgid "High" msgstr "높게" #: shell/shell.ui.h:123 msgid "Double-click the right bulb to test your settings" msgstr "오른쪽에 있는 전구에 더블클릭을 시험보실 수 있습니다" #: shell/shell.ui.h:124 msgid "Timeout" msgstr "시간제한" #: shell/shell.ui.h:125 msgid "Pointer moving speed" msgstr "포인터 속도" #: shell/shell.ui.h:126 msgid "Locate Pointer" msgstr "포인터 위치" #: shell/shell.ui.h:127 msgid "Mouse Keys" msgstr "마우스 버튼" #: shell/shell.ui.h:128 msgid "Double-Click Speed" msgstr "더블클릭 속도" #: shell/shell.ui.h:129 msgid "Disable _touchpad while typing" msgstr "키보드 키를 누를 때 터치패드 사용 안 함(T)" #: shell/shell.ui.h:130 msgid "Enable _mouse clicks with touchpad" msgstr "터치패드와 함께 마우스 클릭 사용(M)" #: shell/shell.ui.h:131 msgid "Scrolling" msgstr "스크롤" #: shell/shell.ui.h:132 msgid "_Disabled" msgstr "사용 안 함(_D)" #: shell/shell.ui.h:133 msgid "_Edge scrolling" msgstr "가장자리 스크롤(_E)" #: shell/shell.ui.h:134 msgid "Two-_finger scrolling" msgstr "두 손가락 스크롤(_F)" #: shell/shell.ui.h:135 msgid "Enable h_orizontal scrolling" msgstr "가로 스크롤 허용(O)" #: shell/shell.ui.h:136 msgid "Touchpad" msgstr "터치패드" #: shell/shell.ui.h:137 msgid "Di_rect internet connection" msgstr "직접 인터넷 연결(_R)" #: shell/shell.ui.h:138 msgid "_Manual proxy configuration" msgstr "수동 프록시 설정(_M)" #: shell/shell.ui.h:139 msgid "H_TTP proxy:" msgstr "HTTP 프록시:(_T)" #: shell/shell.ui.h:140 msgid "_Secure HTTP proxy:" msgstr "보안 HTTP 프록시(_S):" #: shell/shell.ui.h:141 msgid "_FTP proxy:" msgstr "_FTP 프록시:" #: shell/shell.ui.h:142 msgid "S_ocks host:" msgstr "S_ocks 호스트:" #: shell/shell.ui.h:143 msgid "Port:" msgstr "포트:" #: shell/shell.ui.h:144 msgid "_Details" msgstr "자세히(_D)" #: shell/shell.ui.h:145 msgid "_Automatic proxy configuration" msgstr "자동 프록시 설정(_A)" #: shell/shell.ui.h:146 msgid "Autoconfiguration _URL:" msgstr "자동설정 URL:(_U)" #: shell/shell.ui.h:147 msgid "Proxy Configuration" msgstr "프록시 설정" #: shell/shell.ui.h:148 msgid "Ignore Host List" msgstr "프록시 설정 무시 호스트" #: shell/shell.ui.h:149 msgid "Ignored Hosts" msgstr "무시된 호스트" #: shell/shell.ui.h:150 msgid "Additional startup _programs:" msgstr "시작 프로그램 추가(_P)" #: shell/shell.ui.h:151 msgid "Startup Programs" msgstr "시작 프로그램" #: shell/shell.ui.h:152 msgid "Change display appearance" msgstr "겉 모습 바꾸기" #: shell/shell.ui.h:153 msgid "Monitor:" msgstr "모니터:" #: shell/shell.ui.h:154 msgid "Resolution:" msgstr "해상도:" #: shell/shell.ui.h:155 msgid "Direction:" msgstr "연결:" #: shell/shell.ui.h:156 msgid "Save" msgstr "저장" #: shell/shell.ui.h:157 msgid "Make Default" msgstr "기본값으로" #: shell/shell.ui.h:158 msgid "Same image in all monitors" msgstr "모든 모니터에 같은 이미지로" #: shell/shell.ui.h:159 msgid "Set as primary" msgstr "제 1모니터로" #: shell/shell.ui.h:160 msgid "Open Monitor" msgstr "모니터 열기" #: shell/shell.ui.h:161 msgid "Close Monitor" msgstr "모니터 닫기" #: shell/shell.ui.h:162 msgid "Actions" msgstr "" #: shell/shell.ui.h:163 msgid "Put computer to _sleep when inactive:" msgstr "비활성화 되면 컴퓨터 잠자기(S):" #: shell/shell.ui.h:164 msgid "When laptop lid is cl_osed:" msgstr "랩톱의 뚜껑이 닫기면(O):" #: shell/shell.ui.h:165 msgid "Sp_in down hard disks when possible" msgstr "가능하면 하드디스크 끄기(I)" #: shell/shell.ui.h:166 msgid "Display" msgstr "화면" #: shell/shell.ui.h:167 msgid "Put _display to sleep when inactive:" msgstr "비활성화시 화면 끄기(D):" #: shell/shell.ui.h:168 msgid "Set display _brightness to:" msgstr "밝기 조정(B):" #: shell/shell.ui.h:169 msgid "Di_m display when idle" msgstr "아무 작업 없을 때 화면(M)" #: shell/shell.ui.h:170 msgid "On AC Power" msgstr "교류 어댑터" #: shell/shell.ui.h:171 msgid "When battery po_wer is critically low:" msgstr "배터리가 얼마 안 남았을 때(W):" #: shell/shell.ui.h:172 msgid "_Reduce backlight brightness" msgstr "밝기 줄이기(R)" #: shell/shell.ui.h:173 msgid "On Battery Power" msgstr "배터리 전원일 때" #: shell/shell.ui.h:174 msgid "When the power _button is pressed:" msgstr "전원 버튼이 눌렸을 때(B):" #: shell/shell.ui.h:175 msgid "When the _suspend button is pressed:" msgstr "절전 버튼이 눌렸을 때(S):" #: shell/shell.ui.h:176 msgid "Notification Area" msgstr "알림 영역" #: shell/shell.ui.h:177 msgid "_Never display an icon" msgstr "아이콘 보이지 않기(N)" #: shell/shell.ui.h:178 msgid "_Only display an icon when battery power is low" msgstr "배터리 전원이 낮을 때만 아이콘 보이기(O)" #: shell/shell.ui.h:179 msgid "Only display an icon when charging or _discharging" msgstr "충전, 방전일 때만 아이콘 보이기(D)" #: shell/shell.ui.h:180 msgid "Only display an icon when a battery is p_resent" msgstr "배터리가 있을 때만 아이콘 보이기 (R)" #: shell/shell.ui.h:181 msgid "_Always display an icon" msgstr "항상 아이콘 보이기(A)" #: shell/shell.ui.h:182 msgid "Screensaver" msgstr "화면 보호기" #: shell/shell.ui.h:183 msgid "Regard the computer as _idle after:" msgstr "다음 시간동안 아무 작업 없을 때" #: shell/shell.ui.h:184 msgid "_Activate screensaver when computer is idle" msgstr "아무작업 없으면 화면보호기 띄우기(A)" #: shell/shell.ui.h:185 msgid "_Lock screen when screensaver is active" msgstr "화면 보호기 있을 때 잠그기(L)" #: shell/ukui-control-center.c:59 msgid "window1" msgstr "" #: shell/ukui-control-center.c:60 msgid "ukuicc" msgstr "" ukui-control-center/po/tr.po0000664000175000017500000016777113253611051015034 0ustar fengfeng# Turkish translations for ukui-control-center package # ukui-control-center paketi için Türkçe çeviriler. # Copyright (C) 2017 Canonical Ltd. # This file is distributed under the same license as the ukui-control-center package. # Cihan Alkan , 2017. # msgid "" msgstr "" "Project-Id-Version: ukui-control-center\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-09-04 11:42+0800\n" "PO-Revision-Date: 2017-11-28 22:17+0300\n" "Last-Translator: Cihan Alkan \n" "Language-Team: Turkish\n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: panels/appearance/appearance-desktop.c:561 msgid "Add Wallpaper" msgstr "Arkaplan Ekle" #: panels/appearance/appearance-desktop.c:594 msgid "Image" msgstr "Resim" #: panels/appearance/appearance-desktop.c:598 msgid "ALL File" msgstr "Tüm Dosyalar" #: panels/appearance/appearance-theme.c:46 msgid "Please choose a color that you like as the theme colors." msgstr "Lütfen tema renkleri gibi bir renk seçin." #: panels/appearance/appearance-theme.c:62 msgid "" "Set up disable. Please wait at least 5 seconds that system subject will " "restart" msgstr "" "Devre dışı bırak'ı ayarla. Lütfen sistem konusunun yeniden başlatılması için " "en az 5 saniye bekleyin" #: panels/appearance/font_render.ui.h:1 msgid "Font Rendering Details" msgstr "Yazı Tipi İşleme Ayrıntıları" #: panels/appearance/font_render.ui.h:2 msgid "R_esolution:" msgstr "Çözünürlük" #: panels/appearance/font_render.ui.h:3 msgid "dots per inch" msgstr "inç başına nokta sayısı" #: panels/appearance/font_render.ui.h:4 msgid "Smoothing" msgstr "Yumuşatma" #: panels/appearance/font_render.ui.h:5 msgid "_None" msgstr "_Yok" #: panels/appearance/font_render.ui.h:6 msgid "Gra_yscale" msgstr "Gri tonlama" #: panels/appearance/font_render.ui.h:7 msgid "Sub_pixel (LCDs)" msgstr "" #: panels/appearance/font_render.ui.h:9 msgid "_Slight" msgstr "_Hafif" #: panels/appearance/font_render.ui.h:10 msgid "N_one" msgstr "Yok" #: panels/appearance/font_render.ui.h:11 msgid "_Medium" msgstr "_Orta" #: panels/appearance/font_render.ui.h:12 msgid "_Full" msgstr "Tam" #: panels/appearance/font_render.ui.h:13 msgid "Subpixel Order" msgstr "Altpiksel Sırası" #: panels/appearance/font_render.ui.h:15 msgid "_RGB" msgstr "" #: panels/appearance/font_render.ui.h:17 msgid "_BGR" msgstr "" #: panels/appearance/font_render.ui.h:19 msgid "_VRGB" msgstr "" #: panels/appearance/font_render.ui.h:21 msgid "VB_GR" msgstr "" #: panels/appearance/ukui-wp-info.c:47 msgid "No Desktop Background" msgstr "Arkaplan Resmi Yok" #: panels/appearance/ukui-wp-item.c:315 panels/appearance/ukui-wp-item.c:317 msgid "pixel" msgid_plural "pixels" msgstr[0] "piksel" msgstr[1] "piksel" #: panels/appearance/ukui-wp-item.c:327 #, c-format msgid "" "%s\n" "%s, %s\n" "File Path: %s\n" "Artist: %s" msgstr "" "%s\n" "%s\n" "Dosya Yolu: %s\n" "Artist: %s" #: panels/appearance/ukui-wp-item.c:344 #, c-format msgid "" "%s\n" "%s\n" "File Path: %s\n" "Artist: %s" msgstr "" "%s\n" "%s\n" "Dosya Yolu: %s\n" "Artist: %s" #: panels/display/ukui-display-properties-install-systemwide.c:45 #, c-format msgid "" "Usage: %s SOURCE_FILE DEST_NAME\n" "\n" "This program installs a RANDR profile for multi-monitor setups into\n" "a systemwide location. The resulting profile will get used when\n" "the RANDR plug-in gets run in ukui-settings-daemon.\n" "\n" "SOURCE_FILE - a full pathname, typically /home/username/.config/monitors." "xml\n" "\n" "DEST_NAME - relative name for the installed file. This will get put in\n" " the systemwide directory for RANDR configurations,\n" " so the result will typically be %s/DEST_NAME\n" msgstr "" "Kullanımı: %s SOURCE_FILE DEST_NAME\n" "\n" "Bu program, çoklu monitör kurulumları için sistem genelinde bir konuma \n" "bir RANDR profili yüklemektedir. Ortaya çıkan profil, RANDR eklentisi\n" "ukui-settings-daemon'da çalışmaya başladığında kullanılacaktır.\n" "\n" "SOURCE_FILE - a full pathname, typically /home/username/.config/monitors." "xml\n" "\n" "DEST_NAME - relative name for the installed file. This will get put in\n" " the systemwide directory for RANDR configurations,\n" " so the result will typically be %s/DEST_NAME\n" #: panels/display/ukui-display-properties-install-systemwide.c:152 msgid "This program can only be used by the root user" msgstr "Program yalnızca root kullanıcısı tarafından kullanılabilir" #: panels/display/ukui-display-properties-install-systemwide.c:169 msgid "The source filename must be absolute" msgstr "Kaynak dosya adı mutlaka olmalıdır" #: panels/display/ukui-display-properties-install-systemwide.c:180 #, c-format msgid "Could not open %s: %s\n" msgstr "%s açılamadı: %s\n" #: panels/display/ukui-display-properties-install-systemwide.c:189 #, c-format msgid "Could not get information for %s: %s\n" msgstr "%s için bilgi alamadı: %s \n" #: panels/display/ukui-display-properties-install-systemwide.c:196 #, c-format msgid "%s must be a regular file\n" msgstr "%s düzenli bir dosya olmalı\n" #: panels/display/ukui-display-properties-install-systemwide.c:205 msgid "This program must only be run through pkexec(1)" msgstr "Bu program yalnızca pkexec(1) üzerinden çalıştırılmalıdır." #: panels/display/ukui-display-properties-install-systemwide.c:210 msgid "PKEXEC_UID must be set to an integer value" msgstr "PKEXEC_UID bir tamsayı değerine ayarlanmalıdır" #: panels/display/ukui-display-properties-install-systemwide.c:216 #, c-format msgid "%s must be owned by you\n" msgstr "%s sana ait olmalı\n" #: panels/display/ukui-display-properties-install-systemwide.c:224 #, c-format msgid "%s must not have any directory components\n" msgstr "" #: panels/display/ukui-display-properties-install-systemwide.c:232 #, c-format msgid "%s must be a directory\n" msgstr "%s herhangi bir dizin bileşeni olmamalıdır\n" #: panels/display/ukui-display-properties-install-systemwide.c:243 #, c-format msgid "Could not open %s/%s: %s\n" msgstr "%s/%s açılamadı: %s\n" #: panels/display/ukui-display-properties-install-systemwide.c:263 #, c-format msgid "Could not rename %s to %s: %s\n" msgstr "%s dosyasını %s olarak yeniden adlandıramadı: %s\n" #: panels/display/xrandr-capplet.c:315 panels/display/xrandr-capplet.c:354 #: shell/shell.ui.h:1 msgid "Normal" msgstr "Normal" #: panels/display/xrandr-capplet.c:316 #: panels/volume-control/gvc-balance-bar.c:112 shell/shell.ui.h:2 msgid "Left" msgstr "Sol" #: panels/display/xrandr-capplet.c:317 #: panels/volume-control/gvc-balance-bar.c:113 shell/shell.ui.h:3 msgid "Right" msgstr "Sağ" #: panels/display/xrandr-capplet.c:318 shell/shell.ui.h:4 msgid "Upside-down" msgstr "Başaşağı" #: panels/display/xrandr-capplet.c:360 #, c-format msgid "%d Hz" msgstr "%d Hz" #: panels/display/xrandr-capplet.c:497 panels/display/xrandr-capplet.c:1744 msgid "Mirror Screens" msgstr "Ayna Ekranlar" #: panels/display/xrandr-capplet.c:499 #, c-format msgid "Monitor: %s" msgstr "Ekran: %s" #. TRANSLATORS: a monitor is a device to measure voltage and current #: panels/display/xrandr-capplet.c:515 panels/power/kpm-upower.c:573 #: shell/mainwindow.c:511 shell/shell.ui.h:27 msgid "Monitor" msgid_plural "Monitors" msgstr[0] "Ekran" msgstr[1] "Ekran" #: panels/display/xrandr-capplet.c:632 #, c-format msgid "%d x %d" msgstr "%d x %d" #: panels/display/xrandr-capplet.c:1600 msgid "" "Select a monitor to change its properties; drag it to rearrange its " "placement." msgstr "Özelliklerini değiştirmek için bir monitör seçmelidir; " "yerleşimini yeniden düzenlemek için sürükleyin." #: panels/display/xrandr-capplet.c:2204 msgid "Could not save the monitor configuration" msgstr "Ekran yapılandırması kaydedilemedi" #: panels/display/xrandr-capplet.c:2226 msgid "Could not get session bus while applying display configuration" msgstr "Ekran yapılandırmasını uygularken oturum veriyolu alınamadı" #: panels/display/xrandr-capplet.c:2245 msgid "Could not detect displays" msgstr "Görüntü algılanamadı" #: panels/display/xrandr-capplet.c:2477 msgid "The monitor configuration has been saved" msgstr "Monitör yapılandırması kaydedildi" #: panels/display/xrandr-capplet.c:2479 msgid "This configuration will be used the next time someone logs in." msgstr "Bu yapılandırma bir dahaki kullanıcı oturum açtığında kullanılacaktır." #: panels/display/xrandr-capplet.c:2488 msgid "Could not set the default configuration for monitors" msgstr "Monitörler için varsayılan yapılandırma ayarlanamadı." #: panels/display/xrandr-capplet.c:2557 msgid "Could not get screen information" msgstr "Ekran bilgisi alınamadı" #: panels/keyboard/ukui-keybinding-properties.c:1070 #: panels/keyboard/ukui-keybinding-properties.c:1693 msgid "Custom Shortcuts" msgstr "Kısayolları Özelleştir" #: panels/keyboard/ukui-keybinding-properties.c:1379 #, c-format msgid "" "The shortcut \"%s\" is already used for\n" "\"%s\",please reset!!!" msgstr "" "\"%s\" kısayolu zaten kullanılıyor\n" "\"%s\" lütfen sıfırlayın !!!" #: panels/keyboard/ukui-keybinding-properties.c:1523 msgid "Add Shortcuts" msgstr "Kısayol Ekle" #: panels/keyboard/ukui-keybinding-properties.c:1915 msgid "Selection Program" msgstr "Program Seçimi" #: panels/keyboard/ukui-keybinding-properties.c:1956 msgid "Function description" msgstr "Fonksiyon açıklaması" #: panels/keyboard/ukui-keybinding-properties.c:1974 msgid "Hotkey" msgstr "Kısayol" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:1 msgid "Select the keyboard layout" msgstr "Klavye düzenini seçin" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:2 msgid "_Variants:" msgstr "_Hafif:" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:3 msgid "_Country:" msgstr "Ülke:" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:4 msgid "By _country" msgstr "Ülkeye göre" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:5 msgid "_Language:" msgstr "Dil" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:6 msgid "By _language" msgstr "Dile göre" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:7 msgid "Preview:" msgstr "Önizleme" #: panels/keyboard/shortcut_dialog.ui.h:1 msgid "Custom Shortcut" msgstr "Kısayolları Özelleştir" #: panels/keyboard/shortcut_dialog.ui.h:2 #: panels/session-properties/main-table.ui.h:1 msgid "Name:" msgstr "İsim" #: panels/keyboard/shortcut_dialog.ui.h:3 msgid "Command" msgstr "Komut" #: panels/keyboard/shortcut_dialog.ui.h:4 msgid "Scan" msgstr "Tara" #: panels/network-proxy/network.ui.h:1 msgid "Network Proxy Details" msgstr "Ağ Proxy Ayrıntıları" #: panels/network-proxy/network.ui.h:2 msgid "User authentication" msgstr "Kullanıcı doğrulama" #: panels/network-proxy/network.ui.h:3 msgid "Username:" msgstr "Kullanıcı Adı:" #: panels/network-proxy/network.ui.h:4 msgid "Password:" msgstr "Parola:" #: panels/power/copy-theme-dialog.c:215 msgid "Copying files" msgstr "Dosyalar kopyalanıyor" #: panels/power/copy-theme-dialog.c:234 msgid "From:" msgstr "-den:" #: panels/power/copy-theme-dialog.c:238 msgid "To:" msgstr "e:" #: panels/power/copy-theme-dialog.c:259 msgid "Copying themes" msgstr "Temalar kopyalanıyor" #: panels/power/copy-theme-dialog.c:302 msgid "Invalid screensaver theme" msgstr "Geçersiz ekran koruyucu teması" #: panels/power/copy-theme-dialog.c:305 #, c-format msgid "%s does not appear to be a valid screensaver theme." msgstr "%s geçerli bir ekran koruyucu teması olarak görünmüyor." #: panels/power/copy-theme-dialog.c:485 #, c-format msgid "Copying file: %u of %u" msgstr "Dosya kopyalanıyor: %u / %u" #: panels/power/kpm-common.c:52 msgid "Unknown time" msgstr "Bilinmeyen zaman" #: panels/power/kpm-common.c:57 #, c-format msgid "%i minutes" msgid_plural "%i minutes" msgstr[0] "%i dakika" msgstr[1] "%i dakika" #: panels/power/kpm-common.c:68 #, c-format msgid "%i hours" msgid_plural "%i hours" msgstr[0] "%i saat" msgstr[1] "%i saat" #: panels/power/kpm-common.c:74 #, c-format msgid "%i %s %i %s" msgstr "" #: panels/power/kpm-common.c:75 shell/shell.ui.h:62 msgid "hour" msgid_plural "hours" msgstr[0] "saat" msgstr[1] "saat" #: panels/power/kpm-common.c:76 msgid "minute" msgid_plural "minutes" msgstr[0] "dakika" msgstr[1] "dakika" #: panels/power/kpm-common.h:41 msgid "Power Manager" msgstr "Güç Yönetimi" #: panels/power/kpm-common.h:42 msgid "Power Manager for the UKUI desktop" msgstr "UKUI masaüstü için güç yönetimi" #: panels/power/kpm-prefs-core.c:168 panels/power/kpm-prefs-core.c:170 msgid "Never" msgstr "Asla" #: panels/power/kpm-prefs-core.c:248 panels/power/kpm-prefs-core.c:253 #: panels/power/kpm-prefs-core.c:256 msgid "Shutdown" msgstr "Kapat" #: panels/power/kpm-prefs-core.c:260 panels/power/kpm-prefs-core.c:269 #: panels/power/kpm-prefs-core.c:272 msgid "Hang" msgstr "" #: panels/power/kpm-prefs-core.c:264 panels/power/kpm-prefs-core.c:277 #: panels/power/kpm-prefs-core.c:280 msgid "Sleep" msgstr "Uyut" #: panels/power/kpm-prefs-core.c:285 panels/power/kpm-prefs-core.c:288 #: panels/power/ukui-screensaver-preferences.c:462 #: panels/power/ukui-screensaver-preferences.c:614 #: panels/power/ukui-screensaver-preferences.c:853 msgid "Blank screen" msgstr "Siyah Ekran" #: panels/power/kpm-prefs-core.c:293 panels/power/kpm-prefs-core.c:296 msgid "Ask" msgstr "Sor" #: panels/power/kpm-prefs-core.c:301 panels/power/kpm-prefs-core.c:304 msgid "Do not perform operations" msgstr "Işlemleri gerçekleştirmeyin" #. TRANSLATORS: a phone is charging #. TRANSLATORS: device is charging, but we only have a percentage #: panels/power/kpm-upower.c:259 panels/power/kpm-upower.c:333 #, c-format msgid "%s charging (%.1f%%)" msgstr "%s şarj oluyor (%.1f%%)" #. TRANSLATORS: The laptop battery is fully charged, and we know a time #: panels/power/kpm-upower.c:275 #, c-format msgid "" "Battery is fully charged.\n" "Provides %s laptop runtime" msgstr "" "Pil tamamen dolu.\n" "%s laptop çalışma zamanı sağlar " #. TRANSLATORS: the device is fully charged #: panels/power/kpm-upower.c:282 #, c-format msgid "%s is fully charged" msgstr "%s tam dolu" #. TRANSLATORS: the device is discharging, and we have a time remaining #: panels/power/kpm-upower.c:292 #, c-format msgid "%s %s remaining (%.1f%%)" msgstr "%s %s kalan (%.1f%%)" #. TRANSLATORS: the device is discharging, but we only have a percentage #: panels/power/kpm-upower.c:299 #, c-format msgid "%s discharging (%.1f%%)" msgstr "%s boşalıyor (%.1f%%)" #. TRANSLATORS: the device is charging, and we have a time to full and empty #: panels/power/kpm-upower.c:315 #, c-format msgid "" "%s %s until charged (%.1f%%)\n" "Provides %s battery runtime" msgstr "" "%s %s şarj olana kadar (%.1f%%)\n" "%s batarya çalışma zamanı sağlar" #. TRANSLATORS: device is charging, and we have a time to full and a percentage #: panels/power/kpm-upower.c:326 #, c-format msgid "%s %s until charged (%.1f%%)" msgstr "%s %s şarj olana kadar(%.1f%%)" #. TRANSLATORS: this is only shown for laptops with multiple batteries #: panels/power/kpm-upower.c:341 #, c-format msgid "%s waiting to discharge (%.1f%%)" msgstr "%s deşarjı bekliyor (%.1f%%)" #. TRANSLATORS: this is only shown for laptops with multiple batteries #: panels/power/kpm-upower.c:349 #, c-format msgid "%s waiting to charge (%.1f%%)" msgstr "%s şarjı bekliyor (%.1f%%)" #. TRANSLATORS: the type of data, e.g. Laptop battery #: panels/power/kpm-upower.c:410 msgid "Product:" msgstr "Ürün:" #. TRANSLATORS: device is missing #. TRANSLATORS: device is charged #. TRANSLATORS: device is charging #. TRANSLATORS: device is discharging #: panels/power/kpm-upower.c:415 panels/power/kpm-upower.c:420 #: panels/power/kpm-upower.c:425 panels/power/kpm-upower.c:430 msgid "Status:" msgstr "Durum:" #: panels/power/kpm-upower.c:415 msgid "Missing" msgstr "Kayıp" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:420 panels/power/kpm-upower.c:730 msgid "Charged" msgstr "Şarjlı" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:425 panels/power/kpm-upower.c:718 msgid "Charging" msgstr "Şarj Oluyor" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:430 panels/power/kpm-upower.c:722 msgid "Discharging" msgstr "Boşalıyor" #. TRANSLATORS: percentage #: panels/power/kpm-upower.c:436 msgid "Percentage charge:" msgstr "Yüzde şarj:" #. TRANSLATORS: manufacturer #: panels/power/kpm-upower.c:441 msgid "Vendor:" msgstr "Üretici:" #. TRANSLATORS: how the battery is made, e.g. Lithium Ion #: panels/power/kpm-upower.c:447 msgid "Technology:" msgstr "Teknoloji" #. TRANSLATORS: serial number of the battery #: panels/power/kpm-upower.c:452 msgid "Serial number:" msgstr "Seri Numarası" #. TRANSLATORS: model number of the battery #: panels/power/kpm-upower.c:457 msgid "Model:" msgstr "Model" #. TRANSLATORS: time to fully charged #: panels/power/kpm-upower.c:463 msgid "Charge time:" msgstr "Şarj Süresi" #. TRANSLATORS: time to empty #: panels/power/kpm-upower.c:470 msgid "Discharge time:" msgstr "Deşarj Süresi" #. TRANSLATORS: Excellent, Good, Fair and Poor are all related to battery Capacity #: panels/power/kpm-upower.c:479 msgid "Excellent" msgstr "Mükemmel" #: panels/power/kpm-upower.c:483 msgid "Good" msgstr "İyi" #: panels/power/kpm-upower.c:487 msgid "Fair" msgstr "Normal" #: panels/power/kpm-upower.c:491 msgid "Poor" msgstr "Kötü" #: panels/power/kpm-upower.c:495 msgid "Capacity:" msgstr "Kapasite" #: panels/power/kpm-upower.c:503 panels/power/kpm-upower.c:533 msgid "Current charge:" msgstr "Şarj Durumu" #: panels/power/kpm-upower.c:510 msgid "Last full charge:" msgstr "Son tam şarj:" #: panels/power/kpm-upower.c:517 panels/power/kpm-upower.c:539 msgid "Design charge:" msgstr "Şarj Tasarımı" #: panels/power/kpm-upower.c:523 msgid "Charge rate:" msgstr "Şarj Oranı" #. TRANSLATORS: system power cord #: panels/power/kpm-upower.c:561 msgid "AC adapter" msgid_plural "AC adapters" msgstr[0] "AC Adaptörü" msgstr[1] "AC Adaptörü" #. TRANSLATORS: laptop primary battery #: panels/power/kpm-upower.c:565 msgid "Laptop battery" msgid_plural "Laptop batteries" msgstr[0] "Laptop Pili" msgstr[1] "Laptop Pili" #. TRANSLATORS: battery-backed AC power source #: panels/power/kpm-upower.c:569 msgid "UPS" msgid_plural "UPSs" msgstr[0] "UPS" msgstr[1] "UPS" #. TRANSLATORS: wireless mice with internal batteries #: panels/power/kpm-upower.c:577 shell/mainwindow.c:451 shell/shell.ui.h:22 msgid "Mouse" msgid_plural "Mice" msgstr[0] "Fare ve Dokunmatik Panel" msgstr[1] "Fare ve Dokunmatik Panel" #. TRANSLATORS: wireless keyboard with internal battery #: panels/power/kpm-upower.c:581 shell/mainwindow.c:440 shell/shell.ui.h:21 msgid "Keyboard" msgid_plural "Keyboards" msgstr[0] "Klavye" msgstr[1] "Klavye" #. TRANSLATORS: portable device #: panels/power/kpm-upower.c:585 msgid "PDA" msgid_plural "PDAs" msgstr[0] "PDA" msgstr[1] "PDA" #. TRANSLATORS: cell phone (mobile...) #: panels/power/kpm-upower.c:589 msgid "Cell phone" msgid_plural "Cell phones" msgstr[0] "Mobil Telefon" msgstr[1] "Mobil Telefon" #. TRANSLATORS: media player, mp3 etc #: panels/power/kpm-upower.c:594 msgid "Media player" msgid_plural "Media players" msgstr[0] "Medya Player" msgstr[1] "Medya Player" #. TRANSLATORS: tablet device #: panels/power/kpm-upower.c:598 msgid "Tablet" msgid_plural "Tablets" msgstr[0] "Tablet" msgstr[1] "Tablet" #. TRANSLATORS: tablet device #: panels/power/kpm-upower.c:602 msgid "Computer" msgid_plural "Computers" msgstr[0] "Bilgisayar" msgstr[1] "Bilgisayar" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:673 msgid "Lithium Ion" msgstr "Lityum İyon" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:677 msgid "Lithium Polymer" msgstr "Lityum Polimer" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:681 msgid "Lithium Iron Phosphate" msgstr "Lityum Demir Fosfat" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:685 msgid "Lead acid" msgstr "Kurşun Asit" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:689 msgid "Nickel Cadmium" msgstr "Nikel Kadmiyum" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:693 msgid "Nickel metal hydride" msgstr "Nikel Metal Hidrit" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:697 msgid "Unknown technology" msgstr "Bilinmeyen Teknoloji" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:726 msgid "Empty" msgstr "Boş" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:734 msgid "Waiting to charge" msgstr "Şarj için bekliyor" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:738 msgid "Waiting to discharge" msgstr "Deşarj için bekliyor" #: panels/power/ukui-fullscreen-preview.ui.h:1 msgid "Screensaver Preview" msgstr "Ekrankoruyucu Önizleme" #: panels/power/ukui-fullscreen-preview.ui.h:2 msgid "Screensaver preview" msgstr "Ekrankoruyucu önizleme" #: panels/power/ukui-screensaver-preferences.c:463 #: panels/power/ukui-screensaver-preferences.c:609 #: panels/power/ukui-screensaver-preferences.c:851 msgid "Random" msgstr "Rasgele" #: panels/power/ukui-screensaver-preferences.c:659 #: panels/power/ukui-screensaver-preferences.c:1618 #, c-format msgid "%d min" msgstr "%d dk" #: panels/power/ukui-screensaver-preferences.c:661 #: panels/power/ukui-screensaver-preferences.c:1620 #, c-format msgid "%d hour %d min" msgstr "%d saat %d dk" #: panels/power/ukui-screensaver-preferences.c:1676 msgid "Could not load the main interface" msgstr "Ana arayüz yüklenemedi" #: panels/power/ukui-screensaver-preferences.c:1678 msgid "Please make sure that the screensaver is properly installed" msgstr "Lütfen ekran koruyucunun düzgün bir şekilde yüklendiğinden emin olun" #: panels/session-properties/gsm-app-dialog.c:145 msgid "Desktop file(*.desktop)" msgstr "Desktop Dosyası(*.desktop)" #: panels/session-properties/gsm-app-dialog.c:152 msgid "Select command" msgstr "Komut seç" #: panels/session-properties/gsm-app-dialog.c:257 msgid "Add programs" msgstr "Program Ekle" #: panels/session-properties/gsm-app-dialog.c:261 msgid "Boot program property details" msgstr "Başlangıç programı özellik ayrıntıları" #: panels/session-properties/gsm-app-dialog.c:526 msgid "The startup command cannot be empty" msgstr "Başlangıç komutu boş olamaz" #: panels/session-properties/gsm-app-dialog.c:532 msgid "The startup command is not valid" msgstr "Başlangıç komutu geçerli değil" #: panels/session-properties/gsm-properties-dialog.c:117 msgid "enabled" msgstr "Aktif edildi" #: panels/session-properties/gsm-properties-dialog.c:119 msgid "disabled" msgstr "Pasif edildi" #: panels/session-properties/gsm-properties-dialog.c:445 #, c-format msgid "%d/%d/%d/ %d:%d:%d" msgstr "%d/%d/%d/ %d:%d:%d" #: panels/session-properties/gsm-properties-dialog.c:526 msgid "property" msgstr "özellik" #: panels/session-properties/gsm-properties-dialog.c:553 #, c-format msgid "%dByte" msgstr "%d Bayt" #: panels/session-properties/main-table.ui.h:2 msgid "Command:" msgstr "Komut" #: panels/session-properties/main-table.ui.h:3 msgid "Annotation:" msgstr "Not" #: panels/session-properties/main-table.ui.h:4 msgid "scan…" msgstr "tara..." #: panels/session-properties/program_properties.ui.h:1 msgid "program name" msgstr "program adı" #: panels/session-properties/program_properties.ui.h:2 msgid "File Type:" msgstr "Dosya Türü" #: panels/session-properties/program_properties.ui.h:3 msgid "File Description:" msgstr "Dosya Açıklaması:" #: panels/session-properties/program_properties.ui.h:4 msgid "Application" msgstr "Uygulama" #: panels/session-properties/program_properties.ui.h:5 msgid "Program Location:" msgstr "Program Yeri:" #: panels/session-properties/program_properties.ui.h:6 msgid "Program Size:" msgstr "Program Boyutu:" #: panels/session-properties/program_properties.ui.h:7 msgid "Access Time:" msgstr "Erişim Zamanı:" #: panels/session-properties/program_properties.ui.h:8 msgid "modification time:" msgstr "Değiştirilme Zamanı:" #: panels/user-accounts/change-face.ui.h:1 msgid "Changge Face" msgstr "Kullanıcı Simgesi Değiştir" #: panels/user-accounts/change-face.ui.h:2 #: panels/user-accounts/change-name.ui.h:2 #: panels/user-accounts/change-pwd.ui.h:2 #: panels/user-accounts/change-type.ui.h:2 #: panels/user-accounts/delete-user.ui.h:2 #: panels/user-accounts/user-accounts.c:2023 #: panels/user-accounts/user-create.ui.h:2 msgid "Cancel" msgstr "İptal" #: panels/user-accounts/change-face.ui.h:3 #: panels/user-accounts/change-name.ui.h:3 #: panels/user-accounts/change-pwd.ui.h:3 #: panels/user-accounts/change-type.ui.h:3 #: panels/user-accounts/user-accounts.c:2024 msgid "Ok" msgstr "Tamam" #: panels/user-accounts/change-face.ui.h:4 #: panels/user-accounts/change-name.ui.h:4 #: panels/user-accounts/change-pwd.ui.h:4 #: panels/user-accounts/change-type.ui.h:5 #: panels/user-accounts/delete-user.ui.h:5 shell/shell.ui.h:190 msgid "label" msgstr "etiket" #: panels/user-accounts/change-face.ui.h:5 #: panels/user-accounts/user-accounts.c:2020 msgid "Browse more pictures" msgstr "Daha fazla resim araştır" #: panels/user-accounts/change-name.ui.h:1 msgid "Change Name" msgstr "İsmi Değiştir" #: panels/user-accounts/change-pwd.ui.h:1 msgid "Change Password" msgstr "Parolayı Değiştir" #: panels/user-accounts/change-type.ui.h:1 msgid "Change Usertype" msgstr "Kullanıcı Türünü Değiştir" #: panels/user-accounts/change-type.ui.h:4 msgid "automatic login" msgstr "Otomatik Giriş" #: panels/user-accounts/change-type.ui.h:6 msgid "" "Please make sure that the computer has at least one user is the administrator" msgstr "" "Lütfen bilgisayarın en az bir kullanıcısının yönetici olduğundan emin olun." #: panels/user-accounts/change-type.ui.h:7 #: panels/user-accounts/user-create.ui.h:5 msgid "Standard User" msgstr "Normal Kullanıcı" #: panels/user-accounts/change-type.ui.h:8 msgid "" "Standard users can use most software, but you can not install software and \n" "change settings that affect all users." msgstr "" "Normal kullanıcılar çoğu yazılımı kullanabilir ancak yazılımı yükleyemez.\n" "Ayrıca tüm kullanıcıları etkileyen ayarları değiştiremez." #: panels/user-accounts/change-type.ui.h:10 #: panels/user-accounts/user-accounts.c:663 #: panels/user-accounts/user-accounts.c:909 #: panels/user-accounts/user-accounts.c:1090 #: panels/user-accounts/user-accounts.c:1199 #: panels/user-accounts/user-accounts.c:1200 #: panels/user-accounts/user-accounts.c:1314 #: panels/user-accounts/user-accounts.c:1535 #: panels/user-accounts/user-accounts.c:1646 #: panels/user-accounts/user-create.ui.h:8 msgid "Administrators" msgstr "Yönetici" #: panels/user-accounts/change-type.ui.h:11 #: panels/user-accounts/user-create.ui.h:9 msgid "" "Administrator can make any changes needed on the system, including \n" "installing and upgrading software." msgstr "" "Yönetici, yazılım yüklemek ve güncellemek de dahil olmak üzere sistem " "üzerinde gerekli değişiklikleri yapabilir." #: panels/user-accounts/delete-user.ui.h:1 msgid "Delete User" msgstr "Kullanıcı Sil" #: panels/user-accounts/delete-user.ui.h:3 msgid "Keep File" msgstr "Dosyayı Tut" #: panels/user-accounts/delete-user.ui.h:4 msgid "Delete File" msgstr "Dosyayı Sil" #: panels/user-accounts/run-passwd.c:221 msgid "Authentication failure!" msgstr "Kimlik doğrulama hatası!" #: panels/user-accounts/run-passwd.c:298 msgid "New password length is too short!" msgstr "Yeni parola uzunluğu çok kısa!" #: panels/user-accounts/run-passwd.c:304 msgid "The new password is too simple!" msgstr "Yeni parola çok basit!" #: panels/user-accounts/run-passwd.c:310 msgid "The new password is too similar to the old one!" msgstr "Yeni parola eskisiyle çok benzer!" #: panels/user-accounts/run-passwd.c:313 msgid "The new password must contain numbers or special characters!" msgstr "Yeni parolanın sayıları veya özel karakterleri içermesi gerekir!" #: panels/user-accounts/run-passwd.c:317 msgid "The new password is the same as the old one!" msgstr "Yeni parola eski parola ile aynı!" #: panels/user-accounts/run-passwd.c:320 msgid "The new password has been used recently!" msgstr "Yeni parola önceden kullanıldı!" #: panels/user-accounts/run-passwd.c:324 msgid "Your password has been changed after you verify!" msgstr "Doğrulamanızdan sonra parolanız değiştirildi!" #: panels/user-accounts/user-accounts.c:171 msgid "User name cannot be empty!" msgstr "Kullanıcı adı boş olamaz!" #: panels/user-accounts/user-accounts.c:187 msgid "Password length needs to more than 5 digits!" msgstr "Parola uzunluğu 5 haneden fazla olmalıdır!" #: panels/user-accounts/user-accounts.c:194 #: panels/user-accounts/user-accounts.c:382 msgid "Password length needs to less than 64 digits!" msgstr "Şifre uzunluğu 64 haneden daha az olmalı!" #: panels/user-accounts/user-accounts.c:200 #: panels/user-accounts/user-accounts.c:331 #: panels/user-accounts/user-accounts.c:365 #: panels/user-accounts/user-accounts.c:375 #: panels/user-accounts/user-accounts.c:389 #: panels/user-accounts/user-accounts.c:619 #: panels/user-accounts/user-accounts.c:704 #: panels/user-accounts/user-accounts.c:2476 msgid "Please confirm the new password" msgstr "Lütfen yeni parolayı onaylayın" #: panels/user-accounts/user-accounts.c:202 #: panels/user-accounts/user-accounts.c:219 #: panels/user-accounts/user-accounts.c:392 msgid "enter the password twice inconsistencies!" msgstr "İki kez tutarsızlık şifresini girin!" #: panels/user-accounts/user-accounts.c:234 #: panels/user-accounts/user-accounts.c:738 msgid "The first character cannot be underlined!" msgstr "İlk karakterlerin altı çizilemez!" #: panels/user-accounts/user-accounts.c:240 #: panels/user-accounts/user-accounts.c:744 msgid "User name can not contain capital letters!" msgstr "Kullanıcı adı büyük harf içermemelidir!" #: panels/user-accounts/user-accounts.c:248 #: panels/user-accounts/user-accounts.c:752 msgid "The user name can only be composed of letters, numbers and underline!" msgstr "Kullanıcı adı yalnızca harfler, rakamlar ve alt çizgiden oluşabilir!" #: panels/user-accounts/user-accounts.c:255 msgid "The first character cannot be numeric!" msgstr "İlk karakter sayısal olamaz!" #: panels/user-accounts/user-accounts.c:271 #: panels/user-accounts/user-accounts.c:328 #: panels/user-accounts/user-accounts.c:2468 msgid "Please enter the username" msgstr "Lütfen kullanıcı adını giriniz" #: panels/user-accounts/user-accounts.c:272 msgid "Please enter the password " msgstr "Lütfen parolayı giriniz" #: panels/user-accounts/user-accounts.c:283 msgid "The user name is already in use, please use a different one." msgstr "Kullanıcı adı zaten kullanılıyor, lütfen farklı bir tane kullanınız." #: panels/user-accounts/user-accounts.c:303 msgid "" "The user name corresponds to the group already exists,please use a different " "user name" msgstr "" "Kullanıcı adı, zaten var olan gruba karşılık geliyor, lütfen farklı bir " "kullanıcı adı kullanın" #: panels/user-accounts/user-accounts.c:316 msgid "username length should not long than 32!" msgstr "Kullanıcı adı 32 karakterden fazla olmamalıdır!" #: panels/user-accounts/user-accounts.c:328 #: panels/user-accounts/user-accounts.c:924 msgid "Please enter the new username" msgstr "ütfen yeni kullanıcı adını giriniz" #: panels/user-accounts/user-accounts.c:330 #: panels/user-accounts/user-accounts.c:2472 msgid "Please enter the password" msgstr "Lütfen parolayı giriniz" #: panels/user-accounts/user-accounts.c:330 #: panels/user-accounts/user-accounts.c:611 #: panels/user-accounts/user-accounts.c:698 msgid "Please enter new password" msgstr "Lütfen yeni parolayı girin" #: panels/user-accounts/user-accounts.c:331 #: panels/user-accounts/user-accounts.c:363 #: panels/user-accounts/user-accounts.c:601 #: panels/user-accounts/user-accounts.c:687 msgid "Please enter the current password" msgstr "Lütfen geçerli parolayı giriniz" #: panels/user-accounts/user-accounts.c:331 #: panels/user-accounts/user-accounts.c:364 #: panels/user-accounts/user-accounts.c:374 #: panels/user-accounts/user-accounts.c:388 msgid "Please enter the new password" msgstr "Lütfen yeni parolayı giriniz" #: panels/user-accounts/user-accounts.c:433 msgid "Please choose another password." msgstr "Lütfen başka bir parola seçin." #: panels/user-accounts/user-accounts.c:447 msgid "Please reenter the current password." msgstr "Lütfen geçerli parolayı tekrar giriniz." #: panels/user-accounts/user-accounts.c:454 msgid "Password can not be modified." msgstr "Şifre değiştirilemez." #: panels/user-accounts/user-accounts.c:494 msgid "Password length is too short!" msgstr "Şifre uzunluğu çok kısa!" #: panels/user-accounts/user-accounts.c:495 msgid "" "Password length needs to more than 5 digits, and composed of letters, \n" " numbers or special characters." msgstr "" "Şifre uzunluğu 5 basamağı aşmamalı ve harf, rakam veya" "özel karakterlerden oluşmalıdır." #: panels/user-accounts/user-accounts.c:497 msgid "Password length is too long!" msgstr "Şifre uzunluğu çok uzun!" #: panels/user-accounts/user-accounts.c:498 msgid "" "Password length needs to less than 64 digits, and composed of letters, \n" " numbers or special characters." msgstr "Şifre uzunluğu 64 haneden az olmalı ve harfler, sayılar veya özel karakterlerden oluşmalıdır." #: panels/user-accounts/user-accounts.c:500 msgid "Password error" msgstr "Parola hatası" #: panels/user-accounts/user-accounts.c:501 msgid "Please make sure you enter the password two times." msgstr "Lütfen şifreyi iki kez girdiğinizden emin olun." #: panels/user-accounts/user-accounts.c:577 msgid "Password input error, please re-enter!" msgstr "Parola girişi hatası, lütfen tekrar girin!" #: panels/user-accounts/user-accounts.c:665 #: panels/user-accounts/user-accounts.c:911 #: panels/user-accounts/user-accounts.c:1092 #: panels/user-accounts/user-accounts.c:1204 #: panels/user-accounts/user-accounts.c:1205 #: panels/user-accounts/user-accounts.c:1319 #: panels/user-accounts/user-accounts.c:1537 #: panels/user-accounts/user-accounts.c:1648 msgid "Standard user" msgstr "Normal kullanıcı" #: panels/user-accounts/user-accounts.c:671 #: panels/user-accounts/user-accounts.c:917 #: panels/user-accounts/user-accounts.c:1097 #: panels/user-accounts/user-accounts.c:1333 #: panels/user-accounts/user-accounts.c:1568 #: panels/user-accounts/user-accounts.c:1653 msgid "Logged(Current User)" msgstr "Kayıtlı (Geçerli Kullanıcı)" #: panels/user-accounts/user-accounts.c:676 #: panels/user-accounts/user-accounts.c:919 #: panels/user-accounts/user-accounts.c:1099 #: panels/user-accounts/user-accounts.c:1335 #: panels/user-accounts/user-accounts.c:1572 #: panels/user-accounts/user-accounts.c:1657 msgid "Logged(Other Users)" msgstr "Kayıtlı (Diğer Kullanıcı)" #: panels/user-accounts/user-accounts.c:680 #: panels/user-accounts/user-accounts.c:921 #: panels/user-accounts/user-accounts.c:1101 #: panels/user-accounts/user-accounts.c:1337 #: panels/user-accounts/user-accounts.c:1576 #: panels/user-accounts/user-accounts.c:1661 msgid "Un-login(Other Users)" msgstr "Giriş Yapmamış (Diğer Kullanıcılar)" #: panels/user-accounts/user-accounts.c:759 msgid "User name cannot start with number!" msgstr "Kullanıcı adı sayı ile başlayamaz!" #: panels/user-accounts/user-accounts.c:765 msgid "Username length need to less than 32!" msgstr "Kullanıcı adı uzunluğu 32'den az olmalı!" #: panels/user-accounts/user-accounts.c:777 msgid "The user name has been used, please replace with another one!" msgstr "Kullanıcı adı kullanılıyor, lütfen başka bir isimle değiştirin!" #: panels/user-accounts/user-accounts.c:808 #: panels/user-accounts/user-accounts.c:845 msgid "Modify username failed!" msgstr "Kullanıcı adını değiştirme başarısız oldu!" #: panels/user-accounts/user-accounts.c:853 msgid "the user has logged in, please log out and modify!" msgstr "Kullanıcı giriş yapmış, lütfen çıkış yapın ve sonra değişiklik yapın!" #: panels/user-accounts/user-accounts.c:1033 msgid "auto login" msgstr "Oto Giriş" #: panels/user-accounts/user-accounts.c:1036 msgid "_Cancel" msgstr "_İptal" #: panels/user-accounts/user-accounts.c:1038 msgid "_OK" msgstr "_Tamam" #: panels/user-accounts/user-accounts.c:1041 msgid "" "Already have other users set to automatically log in,\n" " click OK will overwrite the existing settings!" msgstr "" "Zaten diğer kullanıcılar otomatik olarak oturum açmak için ayarlanmış," " Tamam'ı tıklattığınızda mevcut ayarların üzerine yazılır!" #: panels/user-accounts/user-accounts.c:1448 msgid "The user can not be deleted!" msgstr "Kullanıcı silinemez!" #: panels/user-accounts/user-accounts.c:1456 msgid "" "The user has logged in, please perform the delete operation after logging " "out!" msgstr "Kullanıcı giriş yaptı, lütfen çıkış yaptıktan sonra silme işlemini gerçekleştir!" #: panels/user-accounts/user-accounts.c:1481 #, c-format msgid "" "do you confirm to delete all the files of " "%s?" msgstr " %s dosyaların tümünü silmeyi onaylıyor mu sunuz?" #: panels/user-accounts/user-accounts.c:1487 #, c-format msgid "" "if you want to delete the %s user, belonging to the user's \n" "desktop, documents, favorites, music, pictures and video \n" "folder will be deleted!" msgstr "Kullanıcının masaüstüne ait olan %s kullanıcısını silmek isterseniz, belgeler, sık kullanılanlar, müzik, resim ve video klasörü silinir!" #: panels/user-accounts/user-accounts.c:1540 msgid "Rename" msgstr "Yeniden Adlandır" #: panels/user-accounts/user-accounts.c:1546 msgid "Change PWD" msgstr "Şifre Değiştir" #: panels/user-accounts/user-accounts.c:1551 msgid "Change Face" msgstr "Kullanıcı Simgesi Değiştir" #: panels/user-accounts/user-accounts.c:1556 msgid "Change Type" msgstr "Tür Değiştir" #: panels/user-accounts/user-accounts.c:1561 msgid "Delete" msgstr "Sil" #: panels/user-accounts/user-accounts.c:2165 msgid "Browse more pictures..." msgstr "Daha fazla resim" #: panels/user-accounts/user-create.ui.h:1 msgid "Create Account" msgstr "Hesap Oluştur" #: panels/user-accounts/user-create.ui.h:3 msgid "Automatic Logon" msgstr "Otomatik Giriş" #: panels/user-accounts/user-create.ui.h:4 msgid "select picture" msgstr "Resim Seçin" #: panels/user-accounts/user-create.ui.h:6 msgid "" "Standard users can use most software, but you can not install software\n" "and change settings that affect all users." msgstr "" "Standart kullanıcılar çoğu yazılımı kullanabilir ancak yazılımı yükleyemez.\n" "Ayrıca tüm kullanıcıları etkileyen ayarları değiştiremezsiniz." #: panels/volume-control/gvc-balance-bar.c:116 msgid "Rear" msgstr "Arka" #: panels/volume-control/gvc-balance-bar.c:117 msgid "Front" msgstr "Ön" #: panels/volume-control/gvc-balance-bar.c:120 msgid "Minimum" msgstr "En az" #: panels/volume-control/gvc-balance-bar.c:121 msgid "Maximum" msgstr "En fazla" #: panels/volume-control/gvc-balance-bar.c:299 msgid "_Balance(_B):" msgstr "_Balans" #: panels/volume-control/gvc-balance-bar.c:302 msgid "_Fade(_F):" msgstr "_Soldurma" #: panels/volume-control/gvc-balance-bar.c:305 msgid "_Subwoofer(_S):" msgstr "" #: panels/volume-control/gvc-channel-bar.c:608 msgid "Unamplified" msgstr "Yükseltilmemiş" #: panels/volume-control/gvc-channel-bar.c:870 msgid "Mute" msgstr "Sessiz" #: panels/volume-control/gvc-combo-box.c:169 msgid "_Profile(_P):" msgstr "_Profil" #: panels/volume-control/gvc-mixer-control.c:1004 msgid "Disabled" msgstr "Kapalı" #: panels/volume-control/gvc-mixer-control.c:1011 #, c-format msgid "%u Output" msgid_plural "%u Outputs" msgstr[0] "%u Çıkış" msgstr[1] "%u Çıkış" #: panels/volume-control/gvc-mixer-control.c:1021 #, c-format msgid "%u Input" msgid_plural "%u Inputs" msgstr[0] "%u Giriş" msgstr[1] "%u Giriş" #: panels/volume-control/gvc-mixer-dialog.c:314 msgid "Co_nnector" msgstr "Bağlantı" #: panels/volume-control/gvc-mixer-dialog.c:522 msgid "Peak detect" msgstr "Tepe algılama" #: panels/volume-control/gvc-mixer-dialog.c:609 msgid "Co_nnector:" msgstr "Bağlayıcı" #: panels/volume-control/gvc-mixer-dialog.c:1502 msgid "Device" msgstr "Aygıt" #: panels/volume-control/gvc-mixer-dialog.c:1550 #, c-format msgid "Speaker Testing for %s" msgstr "%s için Hoparlör Testi" #: panels/volume-control/gvc-mixer-dialog.c:1610 msgid "_Profiles:" msgstr "_Profil:" #: panels/volume-control/gvc-mixer-dialog.c:1611 msgid "Test Speakers" msgstr "Sesi Kontrol Et" #: panels/volume-control/gvc-mixer-dialog.c:1710 #: panels/volume-control/gvc-sound-theme-chooser.c:890 msgid "Name" msgstr "İsim" #: panels/volume-control/gvc-mixer-dialog.c:1837 msgid "Sound Output Volume" msgstr "Ses Çıkış Hacmi" #: panels/volume-control/gvc-mixer-dialog.c:1868 msgid "Applications" msgstr "Uygulamalar" #: panels/volume-control/gvc-mixer-dialog.c:1874 msgid "No application is currently playing or recording audio." msgstr "Şu anda herhangi bir uygulama çalınmıyor veya ses kaydı yapılmıyor." #: panels/volume-control/gvc-mixer-dialog.c:1882 msgid "Sound Effects" msgstr "Ses Efektleri" #: panels/volume-control/gvc-mixer-dialog.c:1890 msgid "_Alert volume: " msgstr "_Uyarı sesi:" #: panels/volume-control/gvc-mixer-dialog.c:1911 msgid "Input" msgstr "Giriş" #: panels/volume-control/gvc-mixer-dialog.c:1919 msgid "_Input volume: " msgstr "_Giriş Sesi:" #: panels/volume-control/gvc-mixer-dialog.c:1942 msgid "Input level:" msgstr "_Giriş Seviyesi:" #: panels/volume-control/gvc-mixer-dialog.c:1971 msgid "C_hoose a device for sound input:" msgstr "Ses girişi için bir cihaz seçin:" #: panels/volume-control/gvc-mixer-dialog.c:2001 msgid "Output" msgstr "Çıkış" #: panels/volume-control/gvc-mixer-dialog.c:2007 msgid "C_hoose a device for sound output:" msgstr "Ses çıkışı için bir cihaz seçin:" #: panels/volume-control/gvc-mixer-dialog.c:2034 #: panels/volume-control/gvc-mixer-dialog.c:2078 msgid "Settings for the selected device:" msgstr "Seçilen cihazın ayarları:" #: panels/volume-control/gvc-mixer-dialog.c:2045 msgid "Hardware" msgstr "Donanım" #: panels/volume-control/gvc-mixer-dialog.c:2051 msgid "C_hoose a device to configure:" msgstr "Yapılandırılacak bir cihaz seçin:" #: panels/volume-control/gvc-mixer-dialog.c:2212 #: panels/volume-control/gvc-sound-theme-chooser.c:755 #: panels/volume-control/gvc-sound-theme-chooser.c:767 #: panels/volume-control/gvc-sound-theme-chooser.c:779 msgid "Sound Preferences" msgstr "Ses Tercihleri" #: panels/volume-control/gvc-sound-theme-chooser.c:226 #: panels/volume-control/gvc-sound-theme-chooser.c:866 msgid "Default" msgstr "Varsayılan" #: panels/volume-control/gvc-sound-theme-chooser.c:338 msgid "No sounds" msgstr "Ses Yok" #: panels/volume-control/gvc-sound-theme-chooser.c:460 msgid "Built-in" msgstr "Built-in" #: panels/volume-control/gvc-sound-theme-chooser.c:645 #: panels/volume-control/sound-theme-file-utils.c:291 msgid "Custom" msgstr "Özel" #: panels/volume-control/gvc-sound-theme-chooser.c:758 #: panels/volume-control/gvc-sound-theme-chooser.c:769 #: panels/volume-control/gvc-sound-theme-chooser.c:781 msgid "Testing event sound" msgstr "Etkinlik sesini test et" #: panels/volume-control/gvc-sound-theme-chooser.c:867 msgid "From theme" msgstr "Temadan al" #: panels/volume-control/gvc-sound-theme-chooser.c:897 msgid "Type" msgstr "Tür" #: panels/volume-control/gvc-sound-theme-chooser.c:1091 msgid "Sound _theme:" msgstr "Ses Teması" #: panels/volume-control/gvc-sound-theme-chooser.c:1104 msgid "C_hoose an alert sound:" msgstr "Bir uyarı sesi seçin" #: panels/volume-control/gvc-sound-theme-chooser.c:1138 msgid "Enable _window and button sounds" msgstr "Pencere ve düğme seslerini etkinleştir" #: panels/volume-control/gvc-speaker-test.c:219 msgid "Stop" msgstr "Dur" #: panels/volume-control/gvc-speaker-test.c:219 #: panels/volume-control/gvc-speaker-test.c:331 msgid "Test" msgstr "Test" #: panels/volume-control/gvc-speaker-test.c:227 msgid "Subwoofer" msgstr "" #: shell/mainwindow.c:112 msgid "-Kylin Control Center" msgstr "-Ukui Denetim Merkezi" #: shell/mainwindow.c:218 shell/shell.ui.h:11 msgid "Control Center" msgstr "Denetim Merkezi" #: shell/mainwindow.c:381 msgid "Time and Dates" msgstr "Tarih ve Zaman" #: shell/mainwindow.c:384 msgid " Change the time and date of this computer " msgstr "Bu bilgisayarın saat ve tarihini değiştir" #: shell/mainwindow.c:392 shell/shell.ui.h:13 msgid "User Account" msgstr "Kullanıcı Hesabı" #: shell/mainwindow.c:395 msgid "" " Change the computer user account \n" " settings and password" msgstr "" " Bilgisayar kullanıcı hesabı ayarlarını\n" "ve parolasını değiştir." #: shell/mainwindow.c:403 shell/shell.ui.h:14 msgid "Personalization" msgstr "Kişiselleştirme" #: shell/mainwindow.c:406 msgid "" " Change the computer desktop background \n" " and related theme" msgstr "" " Bilgisayarın masaüstü arka planını \n" "ve ilgili temayı değiştirin." #: shell/mainwindow.c:414 msgid "Default Application" msgstr "Geçerli Uygulamalar" #: shell/mainwindow.c:417 msgid " Change the default application on this computer " msgstr "u bilgisayardaki varsayılan uygulamayı değiştir" #: shell/mainwindow.c:432 msgid " Change the network on this computer " msgstr "Bu bilgisayardaki ağı değiştir" #: shell/mainwindow.c:443 msgid " Change the keyboard settings on this computer " msgstr "Bu bilgisayardaki klavye ayarlarını değiştir " #: shell/mainwindow.c:454 msgid " Change the mouse settings on this computer " msgstr "Bu bilgisayardaki fare ayarlarını değiştir" #: shell/mainwindow.c:468 msgid " Configure the connection to the computer printer " msgstr "Bilgisayara olan yazıcıyla bağlantıyı yapılandırın" #: shell/mainwindow.c:477 shell/shell.ui.h:24 msgid "Sound" msgstr "Ses" #: shell/mainwindow.c:480 msgid " Change the sound settings on this computer " msgstr "Bu bilgisayardaki ses ayarlarını değiştir" #: shell/mainwindow.c:489 msgid "Network Agent" msgstr "Ağ Aracı" #: shell/mainwindow.c:492 msgid " Change the network agent on this computer " msgstr "Bu bilgisayardaki ağı aracını değiştir" #: shell/mainwindow.c:500 shell/shell.ui.h:17 msgid "Autostart" msgstr "Otomatik Başlat" #: shell/mainwindow.c:503 msgid " Change the autostart program on this computer " msgstr "Bu bilgisayarda otomatik başlayan programları değiştirin" #: shell/mainwindow.c:513 msgid " Change the Monitor settings on this computer " msgstr "Bu bilgisayardaki Monitör ayarlarını değiştir" #: shell/mainwindow.c:524 msgid "Power Management" msgstr "Güç Yönetimi" #: shell/mainwindow.c:527 msgid " Change the power management settings on this computer " msgstr "Bu bilgisayardaki güç yönetimi ayarlarını değiştir" #: shell/mainwindow.c:535 msgid "System Check" msgstr "Sistemi Kontrol Et" #: shell/mainwindow.c:539 msgid "check the system detection information on this computer " msgstr "Bu bilgisayarda sistem algılama bilgilerini kontrol et" #: shell/shell.ui.h:5 msgid "Tile" msgstr "Döşeli" #: shell/shell.ui.h:6 msgid "Zoom" msgstr "Yakınlaştır" #: shell/shell.ui.h:7 msgid "Center" msgstr "Ortalanmış" #: shell/shell.ui.h:8 msgid "Scale" msgstr "Ölçekli" #: shell/shell.ui.h:9 msgid "Stretch" msgstr "Uzatılmış" #: shell/shell.ui.h:10 msgid "Span" msgstr "Yayılmış" #: shell/shell.ui.h:12 msgid "Time Dates" msgstr "Tarih ve Zaman" #: shell/shell.ui.h:15 msgid "" "Default \n" "Application" msgstr "" "Varsayılan \n" "Uygulamalar" #: shell/shell.ui.h:18 msgid "System Configuration" msgstr "Sistem Ayarları" #: shell/shell.ui.h:19 msgid "" "Network \n" "Connections" msgstr "Ağ Bağlantıları" #: shell/shell.ui.h:23 msgid "Printer" msgstr "Yazıcı" #: shell/shell.ui.h:25 msgid "" "Network \n" "Agent" msgstr "Ağ Ayarları" #: shell/shell.ui.h:28 msgid "" "Power \n" "Management" msgstr "Güç Yönetimi" #: shell/shell.ui.h:30 msgid "Hardware Configure" msgstr "Donanım Ayarları" #: shell/shell.ui.h:31 msgid "Home" msgstr "Giriş" #: shell/shell.ui.h:32 msgid "Personalization_" msgstr "Görünüm" #: shell/shell.ui.h:33 msgid "Autostart_" msgstr "Otomatik Başlat" #: shell/shell.ui.h:34 msgid "Default APP" msgstr "" "Tercih Edilen \n" "Uygulamalar" #: shell/shell.ui.h:35 msgid "Time Dates_" msgstr "Tarih ve Saat" #: shell/shell.ui.h:36 msgid "User Account_" msgstr "Kullanıcı Hesapları" #: shell/shell.ui.h:38 msgid "Network Connection_" msgstr "Ağ Bağlantıları" #: shell/shell.ui.h:39 msgid "Keyboard_" msgstr "Klavye" #: shell/shell.ui.h:40 msgid "Mouse_" msgstr "" "Fare ve \n" "Dokunmatik Panel" #: shell/shell.ui.h:42 msgid "Printer_" msgstr "Yazıcı" #: shell/shell.ui.h:43 msgid "Sound_" msgstr "Ses" #: shell/shell.ui.h:44 msgid "Network Agent_" msgstr "Ağ Ayarları" #: shell/shell.ui.h:45 msgid "Monitor_" msgstr "Ekran" #: shell/shell.ui.h:46 msgid "Power Manage" msgstr "Güç Yönetimi" #: shell/shell.ui.h:47 msgid "Tzone:" msgstr "Tzone" #: shell/shell.ui.h:48 msgid "date:" msgstr "Tarih" #: shell/shell.ui.h:49 msgid "time:" msgstr "Saat" #: shell/shell.ui.h:50 msgid " Jan" msgstr " Oca" #: shell/shell.ui.h:51 msgid " Feb" msgstr " Şub" #: shell/shell.ui.h:52 msgid " Mar" msgstr " Mar" #: shell/shell.ui.h:53 msgid " Apr" msgstr " Nis" #: shell/shell.ui.h:54 msgid " May" msgstr " May" #: shell/shell.ui.h:55 msgid " Jun" msgstr " Haz" #: shell/shell.ui.h:56 msgid " Jul" msgstr " Tem" #: shell/shell.ui.h:57 msgid " Aug" msgstr " Ağu" #: shell/shell.ui.h:58 msgid " Sep" msgstr " Eyl" #: shell/shell.ui.h:59 msgid " Oct" msgstr " Eki" #: shell/shell.ui.h:60 msgid " Nov" msgstr " Kas" #: shell/shell.ui.h:61 msgid " Dec" msgstr " Ara" #: shell/shell.ui.h:63 msgid "min" msgstr "dk" #: shell/shell.ui.h:64 msgid "sec" msgstr "sn" #: shell/shell.ui.h:65 msgid "With the network time synchronization" msgstr "Zaman bilgisini ağ üzerinden al" #: shell/shell.ui.h:66 msgid "because the ntp is installed,please use ntpdate." msgstr "ntp kurulduğundan, lütfen ntpdate'i kullanın." #: shell/shell.ui.h:67 msgid "Current Account" msgstr "Geçerli Hesap" #: shell/shell.ui.h:68 msgid "Other Accounts" msgstr "Diğer Hesaplar" #: shell/shell.ui.h:69 msgid "Create a new account" msgstr "Yeni Hesap Oluştur" #: shell/shell.ui.h:70 msgid "Add" msgstr "Ekle" #: shell/shell.ui.h:71 msgid "delete" msgstr "Sil" #: shell/shell.ui.h:72 msgid "Style:" msgstr "Stil" #: shell/shell.ui.h:73 msgid "wallpaper" msgstr "Arkaplan" #: shell/shell.ui.h:74 msgid "Select the one you love color as the theme color" msgstr "Tema rengi olarak sevdiğiniz birini seçin" #: shell/shell.ui.h:75 msgid "Theme color" msgstr "Tema Rengi" #: shell/shell.ui.h:76 msgid "Font choice:" msgstr "Font Seçiniz:" #: shell/shell.ui.h:77 msgid "Font size :" msgstr "Font Boyutu:" #: shell/shell.ui.h:79 #, no-c-format msgid "small(S) --100%(default)" msgstr "Küçük --100%(varsayılan)" #: shell/shell.ui.h:81 #, no-c-format msgid "medium(M)--125%" msgstr "Orta --125%" #: shell/shell.ui.h:83 #, no-c-format msgid "large (L) --150%" msgstr "Büyük --150%" #: shell/shell.ui.h:84 msgid "Please select the clearest sample text" msgstr "Lütfen en net örnek metni seçin" #: shell/shell.ui.h:85 msgid "Restore Defaults" msgstr "Varsayılanları Geri Yükle" #: shell/shell.ui.h:86 msgid "Font" msgstr "Font" #: shell/shell.ui.h:87 msgid "Internet" msgstr "İnternet" #: shell/shell.ui.h:88 msgid " Web Browser:" msgstr " Web Tarayıcı:" #: shell/shell.ui.h:89 msgid " Mail Reader:" msgstr " E-Posta Okuyucu:" #: shell/shell.ui.h:90 msgid "Multimedia" msgstr "Multimedya" #: shell/shell.ui.h:91 msgid " Image Viewer:" msgstr " Resim Görüntüleyici:" #: shell/shell.ui.h:92 msgid " Audio Player:" msgstr " Ses Oynatıcı:" #: shell/shell.ui.h:93 msgid " Video Player:" msgstr " Video Oynatıcı:" #: shell/shell.ui.h:94 msgid "System" msgstr "Sistem" #: shell/shell.ui.h:95 msgid " Text Editor:" msgstr " Metin Düzenleyici:" #: shell/shell.ui.h:96 msgid " File Manager:" msgstr " Dosya Yöneticisi:" #: shell/shell.ui.h:97 msgid "Network Connections" msgstr "Ağ Bağlantıları" #: shell/shell.ui.h:98 msgid "Repeat Keys" msgstr "Tuşları Tekrarla" #: shell/shell.ui.h:99 msgid "Key presses _repeat when key is held down" msgstr "Tuşa basılı tutulduğunda tuşa tekrar basın" #: shell/shell.ui.h:100 msgid "_Delay:" msgstr "_Gecikme" #: shell/shell.ui.h:101 msgid "_Speed:" msgstr "_Hız" #: shell/shell.ui.h:102 msgid "Short" msgstr "Kısa" #: shell/shell.ui.h:103 msgid "Slow" msgstr "Yavaş" #: shell/shell.ui.h:104 msgid "Repeat keys speed" msgstr "Tuşları tekrarlama hızı" #: shell/shell.ui.h:105 msgid "Long" msgstr "Uzun" #: shell/shell.ui.h:106 msgid "Fast" msgstr "Hızlı" #: shell/shell.ui.h:107 msgid "To test the repetition rate of the input character:" msgstr "Girilen karakterin yineleme oranını test etmek için" #: shell/shell.ui.h:108 msgid "Cursor Blinking" msgstr "İmleç Yanıp Sönmesi" #: shell/shell.ui.h:109 msgid "Cursor _blinks in text fields" msgstr "İmleç metin alanlarında yanıp söner" #: shell/shell.ui.h:110 msgid "S_peed:" msgstr "Hız:" #: shell/shell.ui.h:111 msgid "Cursor blinks speed" msgstr "İmleç Yanma Hızı" #: shell/shell.ui.h:112 msgid "General" msgstr "Genel" #: shell/shell.ui.h:113 msgid "" "Please add the language you will use to the list. And the first one in the " "list is the most\n" "commonly used language." msgstr "" "Lütfen kullanacağınız dili listeye ekleyin. \n" "Listedeki ilk dil en sık kullanılan dildir." #: shell/shell.ui.h:115 msgid "_Show..." msgstr "_Göster..." #: shell/shell.ui.h:116 msgid "List of keyboard layouts selected for usage" msgstr "Kullanım için seçilen klavye düzenleri listesi" #: shell/shell.ui.h:117 msgid "_Separate layout for each window" msgstr "Her pencere için ayrı düzen" #: shell/shell.ui.h:118 msgid "New windows u_se active window's layout" msgstr "Yeni pencere kullanıcıları aktif pencere düzeni" #: shell/shell.ui.h:119 msgid "Reset to De_faults" msgstr "Varsayılanlara Dön" #: shell/shell.ui.h:120 msgid "Layouts" msgstr "Düzenler" #: shell/shell.ui.h:121 msgid "" "\"To edit a shortcut key, click on the corresponding row and type a new key " "\"\n" "\"combination, or press backspace to clear.\"" msgstr "" "\"Bir kısayol tuşunu düzenlemek için, ilgili satırı tıklayın ve yeni bir tuş kombinasyonu yazın\"\n" "\".veya temizlemek için geri tuşuna basın.\"" #: shell/shell.ui.h:123 msgid "Shortcut" msgstr "Kısayol" #: shell/shell.ui.h:124 msgid "_Right-handed" msgstr "Sağ eli kullan" #: shell/shell.ui.h:125 msgid "_Left-handed" msgstr "Sol eli kullan" #: shell/shell.ui.h:126 msgid "Sh_ow position of pointer when the Control key is pressed" msgstr "Kontrol tuşu basılı olduğunda işaretçiyi konumunu göster" #: shell/shell.ui.h:127 msgid "_Sensitivity:" msgstr "_Duyarlılık" #: shell/shell.ui.h:128 msgid "Low" msgstr "Düşük" #: shell/shell.ui.h:129 msgid "High" msgstr "Yüksek" #: shell/shell.ui.h:130 msgid "Double-click the right bulb to test your settings" msgstr "Ayarlarınızı test etmek için sağdaki resmi çift tıklayın" #: shell/shell.ui.h:131 msgid "Timeout" msgstr "Zaman Aşımı" #: shell/shell.ui.h:132 msgid "Pointer moving speed" msgstr "İşaretçi Hareket Hızı" #: shell/shell.ui.h:133 msgid "Locate Pointer" msgstr "İşaretçiyi Bulun" #: shell/shell.ui.h:134 msgid "Mouse Keys" msgstr "Fare Tuşları" #: shell/shell.ui.h:135 msgid "Double-Click Speed" msgstr "Çift Tıklama Hızı" #: shell/shell.ui.h:136 msgid "Disable _touchpad while typing" msgstr "Yazarken dokunmatik paneli devre dışı bırak" #: shell/shell.ui.h:137 msgid "Enable _mouse clicks with touchpad" msgstr "Dokunmatik panelde fare tıklamalarını etkinleştir" #: shell/shell.ui.h:138 msgid "Scrolling" msgstr "Kaydırma" #: shell/shell.ui.h:139 msgid "_Disabled" msgstr "_Kapalı" #: shell/shell.ui.h:140 msgid "Vertical _edge scrolling" msgstr "Dikey kenar kaydırma" #: shell/shell.ui.h:141 msgid "_Horizontal edge scrolling" msgstr "Yatay kenar kaydırma" #: shell/shell.ui.h:142 msgid "_Vertical two-finger scrolling" msgstr "Dikey iki parmak kaydırma" #: shell/shell.ui.h:143 msgid "Horizontal two-_finger scrolling" msgstr "Yatay iki parmak kaydırma" #: shell/shell.ui.h:144 msgid "Enabled touchpad" msgstr "Dokunmatik Panel Etkin" #: shell/shell.ui.h:145 msgid "Touchpad" msgstr "Dokunmatik Panel" #: shell/shell.ui.h:146 msgid "Di_rect internet connection" msgstr "Doğrudan internet bağlantısı" #: shell/shell.ui.h:147 msgid "_Manual proxy configuration" msgstr "El ile proxy yapılandırması" #: shell/shell.ui.h:148 msgid "H_TTP proxy:" msgstr "H_TTP proxy:" #: shell/shell.ui.h:149 msgid "_Secure HTTP proxy:" msgstr "Güvenli HTTP proxy:" #: shell/shell.ui.h:150 msgid "_FTP proxy:" msgstr "_FTP proxy:" #: shell/shell.ui.h:151 msgid "S_ocks host:" msgstr "S_ocks host:" #: shell/shell.ui.h:152 msgid "Port:" msgstr "Port:" #: shell/shell.ui.h:153 msgid "_Details" msgstr "_Ayrıntılar" #: shell/shell.ui.h:154 msgid "_Automatic proxy configuration" msgstr "Otomatik proxy yapılandırması" #: shell/shell.ui.h:155 msgid "Autoconfiguration _URL:" msgstr "Otomatik Yapılandırma URL'si" #: shell/shell.ui.h:156 msgid "Proxy Configuration" msgstr "Proxy Yapılandırması" #: shell/shell.ui.h:157 msgid "Ignore Host List" msgstr "Host Listesini Yoksay" #: shell/shell.ui.h:158 msgid "Ignored Hosts" msgstr "Yoksayılan Hostlar" #: shell/shell.ui.h:159 msgid "Additional startup _programs:" msgstr "Ekli başlangıç programları:" #: shell/shell.ui.h:160 msgid "name" msgstr "İsim" #: shell/shell.ui.h:161 msgid "status" msgstr "Durum" #: shell/shell.ui.h:162 msgid "Startup Programs" msgstr "Başlangıç Programları" #: shell/shell.ui.h:163 msgid "Change display appearance" msgstr "Ekran görünümünü değiştir" #: shell/shell.ui.h:164 msgid "Monitor:" msgstr "Ekran" #: shell/shell.ui.h:165 msgid "Resolution:" msgstr "Çözünürlük" #: shell/shell.ui.h:166 msgid "Direction:" msgstr "Yön:" #: shell/shell.ui.h:167 msgid "Save" msgstr "Kaydet" #: shell/shell.ui.h:168 msgid "Same image in all monitors" msgstr "Tüm ekranlarda aynı resim" #: shell/shell.ui.h:169 msgid "Set as primary" msgstr "Birincil olarak ayarla" #: shell/shell.ui.h:170 msgid "Open Monitor" msgstr "Ekranı Aç" #: shell/shell.ui.h:171 msgid "Close Monitor" msgstr "Ekranı Kapat" #: shell/shell.ui.h:172 msgid "Computer status" msgstr "Bilgisayar Durumu" #: shell/shell.ui.h:173 msgid "AC Power" msgstr "AC Gücü" #: shell/shell.ui.h:174 msgid "Battery Power" msgstr "Pil Gücü" #: shell/shell.ui.h:175 msgid "Put _computer to sleep when inactive:" msgstr "Bilgisayarı uyku moduna al:" #: shell/shell.ui.h:176 msgid "Put _monitor to sleep when inactive:" msgstr "Eekranı uyku moduna al:" #: shell/shell.ui.h:177 msgid "When laptop lid is cl_osed:" msgstr "Dizüstü bilgisayar kapağı kapalı olduğunda:" #: shell/shell.ui.h:178 msgid "Actions" msgstr "Haraket" #: shell/shell.ui.h:179 msgid "When the power _button is pressed:" msgstr "Güç düğmesine basıldığında:" #: shell/shell.ui.h:180 msgid "When the sus_pend button is pressed:" msgstr "Askıya al düğmesine basıldığında:" #: shell/shell.ui.h:181 msgid "Icon display" msgstr "Simge Göster" #: shell/shell.ui.h:182 msgid "Only display an icon when a battery is p_resent" msgstr "Yalnızca bir pil varsa simge gösterin" #: shell/shell.ui.h:183 msgid "_Always display an icon" msgstr "_Her zaman bir simge gösterin" #: shell/shell.ui.h:184 msgid "Power Configure" msgstr "Güç Ayarları" #: shell/shell.ui.h:185 msgid "Regard the computer as _idle after:" msgstr "Bilgisayarı sonra boşta tutun:" #: shell/shell.ui.h:186 msgid "_Activate screensaver when computer is idle" msgstr "_Bilgisayar boştayken ekran koruyucuyu etkinleştirin" #: shell/shell.ui.h:187 msgid "_Lock screen when screensaver is active" msgstr "_Ekran koruyucu aktifken ekranı kilitle" #: shell/shell.ui.h:188 msgid "preview" msgstr "Önizleme" #: shell/shell.ui.h:189 msgid "Screensavers:" msgstr "Ekrankoruyucu" #: shell/shell.ui.h:191 msgid "Screensaver" msgstr "Ekran Koruyucu" #: shell/ukui-control-center.c:59 msgid "window1" msgstr "window1" #: shell/ukui-control-center.c:60 msgid "ukuicc" msgstr "ukuicc" ukui-control-center/po/README0000664000175000017500000000013713057175444014722 0ustar fengfeng更新翻译源文件pot: 修改.c\.h\.cpp\.ui中需翻译字符串后需要执行update-po, ukui-control-center/po/POTFILES.skip0000664000175000017500000000000013057175444016144 0ustar fengfengukui-control-center/po/zh_CN.po0000664000175000017500000017364413253611051015404 0ustar fengfeng# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Canonical Ltd. # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: ukui-control-center\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-03-08 15:55+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0\n" #: panels/appearance/appearance-desktop.c:561 msgid "Add Wallpaper" msgstr "添加壁纸" #: panels/appearance/appearance-desktop.c:594 msgid "Image" msgstr "图像" #: panels/appearance/appearance-desktop.c:598 msgid "ALL File" msgstr "所有文件" #: panels/appearance/appearance-theme.c:46 msgid "Please choose a color that you like as the theme colors." msgstr "选择一个您喜欢的颜色作为主题颜色" #: panels/appearance/appearance-theme.c:62 msgid "" "Set up disable. Please wait at least 5 seconds that system subject will " "restart" msgstr "设置无效!请等待至少5秒,以便系统主题重新启动" #: panels/appearance/font_render.ui.h:1 msgid "Font Rendering Details" msgstr "字体渲染详情" #: panels/appearance/font_render.ui.h:2 msgid "R_esolution:" msgstr "分辨率(_E):" #: panels/appearance/font_render.ui.h:3 msgid "dots per inch" msgstr "每英寸点数" #: panels/appearance/font_render.ui.h:4 msgid "Smoothing" msgstr "平滑" #: panels/appearance/font_render.ui.h:5 msgid "_None" msgstr "无(_N)" #: panels/appearance/font_render.ui.h:6 msgid "Gra_yscale" msgstr "灰度(_Y)" #: panels/appearance/font_render.ui.h:7 msgid "Sub_pixel (LCDs)" msgstr "次像素(_P) (LCDs)" #: panels/appearance/font_render.ui.h:9 msgid "_Slight" msgstr "微调" #: panels/appearance/font_render.ui.h:10 msgid "N_one" msgstr "无(_O)" #: panels/appearance/font_render.ui.h:11 msgid "_Medium" msgstr "中等(_M)" #: panels/appearance/font_render.ui.h:12 msgid "_Full" msgstr "完全(_F)" #: panels/appearance/font_render.ui.h:13 msgid "Subpixel Order" msgstr "次像素顺序" #: panels/appearance/font_render.ui.h:15 msgid "_RGB" msgstr "" #: panels/appearance/font_render.ui.h:17 msgid "_BGR" msgstr "" #: panels/appearance/font_render.ui.h:19 msgid "_VRGB" msgstr "" #: panels/appearance/font_render.ui.h:21 msgid "VB_GR" msgstr "" #: panels/appearance/ukui-wp-info.c:47 msgid "No Desktop Background" msgstr "无桌面背景" #: panels/appearance/ukui-wp-item.c:315 panels/appearance/ukui-wp-item.c:317 msgid "pixel" msgid_plural "pixels" msgstr[0] "像素" msgstr[1] "像素" #: panels/appearance/ukui-wp-item.c:327 #, c-format msgid "" "%s\n" "%s, %s\n" "File Path: %s\n" "Artist: %s" msgstr "" "%s\n" "%s, %s\n" "文件夹:%s\n" "作者:%s" #: panels/appearance/ukui-wp-item.c:344 #, c-format msgid "" "%s\n" "%s\n" "File Path: %s\n" "Artist: %s" msgstr "" "%s\n" "%s\n" "文件夹:%s\n" "作者:%s" #: panels/display/ukui-display-properties-install-systemwide.c:45 #, c-format msgid "" "Usage: %s SOURCE_FILE DEST_NAME\n" "\n" "This program installs a RANDR profile for multi-monitor setups into\n" "a systemwide location. The resulting profile will get used when\n" "the RANDR plug-in gets run in ukui-settings-daemon.\n" "\n" "SOURCE_FILE - a full pathname, typically /home/username/.config/monitors." "xml\n" "\n" "DEST_NAME - relative name for the installed file. This will get put in\n" " the systemwide directory for RANDR configurations,\n" " so the result will typically be %s/DEST_NAME\n" msgstr "" "用法: %s SOURCE_FILE DEST_NAME\n" "\n" "此程序向整个系统安装多显示器设置的 RANDR 配置文件。\n" "生成的配置文件将在 RANDR 插件在 ukui-settings-daemon \n" "中运行时被使用。\n" "\n" "SOURCE_FILE - 完整路径名称,通常为 /home/username/.config/monitors.xml\n" "\n" "DEST_NAME - 安装后文件的相对名称。\n" " 将被置于用于 RANDR 配置的系统目录,\n" " 所以生成文件通常为 %s/DEST_NAME\n" #: panels/display/ukui-display-properties-install-systemwide.c:152 msgid "This program can only be used by the root user" msgstr "此程序只能由 root 用户使用" #: panels/display/ukui-display-properties-install-systemwide.c:169 msgid "The source filename must be absolute" msgstr "源文件名必须为绝对路径" #: panels/display/ukui-display-properties-install-systemwide.c:180 #, c-format msgid "Could not open %s: %s\n" msgstr "无法打开 %s: %s\n" #: panels/display/ukui-display-properties-install-systemwide.c:189 #, c-format msgid "Could not get information for %s: %s\n" msgstr "无法获取 %s 的信息: %s\n" #: panels/display/ukui-display-properties-install-systemwide.c:196 #, c-format msgid "%s must be a regular file\n" msgstr "%s 必须为常规文件\n" #: panels/display/ukui-display-properties-install-systemwide.c:205 msgid "This program must only be run through pkexec(1)" msgstr "此程序仅能通过 pkexec(1) 运行" #: panels/display/ukui-display-properties-install-systemwide.c:210 msgid "PKEXEC_UID must be set to an integer value" msgstr "PKEXEC_UID 必须设为整数值" #: panels/display/ukui-display-properties-install-systemwide.c:216 #, c-format msgid "%s must be owned by you\n" msgstr "%s 必须归您所有\n" #: panels/display/ukui-display-properties-install-systemwide.c:224 #, c-format msgid "%s must not have any directory components\n" msgstr "%s 不应有任何目录部分\n" #: panels/display/ukui-display-properties-install-systemwide.c:232 #, c-format msgid "%s must be a directory\n" msgstr "%s 必须为目录\n" #: panels/display/ukui-display-properties-install-systemwide.c:243 #, c-format msgid "Could not open %s/%s: %s\n" msgstr "无法打开 %s/%s: %s\n" #: panels/display/ukui-display-properties-install-systemwide.c:263 #, c-format msgid "Could not rename %s to %s: %s\n" msgstr "无法将 %s 重命名为 %s: %s\n" #: panels/display/xrandr-capplet.c:315 panels/display/xrandr-capplet.c:354 #: shell/shell.ui.h:1 msgid "Normal" msgstr "普通" #: panels/display/xrandr-capplet.c:316 #: panels/volume-control/gvc-balance-bar.c:112 shell/shell.ui.h:2 msgid "Left" msgstr "左" #: panels/display/xrandr-capplet.c:317 #: panels/volume-control/gvc-balance-bar.c:113 shell/shell.ui.h:3 msgid "Right" msgstr "右" #: panels/display/xrandr-capplet.c:318 shell/shell.ui.h:4 msgid "Upside-down" msgstr "上下颠倒" #: panels/display/xrandr-capplet.c:360 #, c-format msgid "%d Hz" msgstr "" #: panels/display/xrandr-capplet.c:497 panels/display/xrandr-capplet.c:1744 msgid "Mirror Screens" msgstr " 镜像屏幕" #: panels/display/xrandr-capplet.c:499 #, c-format msgid "Monitor: %s" msgstr "显示器:" #. TRANSLATORS: a monitor is a device to measure voltage and current #: panels/display/xrandr-capplet.c:515 panels/power/kpm-upower.c:573 #: shell/mainwindow.c:270 shell/shell.ui.h:25 msgid "Monitor" msgid_plural "Monitors" msgstr[0] "显示器" #: panels/display/xrandr-capplet.c:632 #, c-format msgid "%d x %d" msgstr "" #: panels/display/xrandr-capplet.c:1600 msgid "" "Select a monitor to change its properties; drag it to rearrange its " "placement." msgstr "选择一个显示来更改它的属性;拖动它来排列位置。" #: panels/display/xrandr-capplet.c:2204 msgid "Could not save the monitor configuration" msgstr "无法保存显示器配置" #: panels/display/xrandr-capplet.c:2226 msgid "Could not get session bus while applying display configuration" msgstr "应用显示配置时无法获得会话总线" #: panels/display/xrandr-capplet.c:2245 msgid "Could not detect displays" msgstr "" #: panels/display/xrandr-capplet.c:2477 msgid "The monitor configuration has been saved" msgstr "显示器配置已保存" #: panels/display/xrandr-capplet.c:2479 msgid "This configuration will be used the next time someone logs in." msgstr "这个设置将在下次登入时使用" #: panels/display/xrandr-capplet.c:2488 msgid "Could not set the default configuration for monitors" msgstr "无法为显示器设置默认配置" #: panels/display/xrandr-capplet.c:2557 msgid "Could not get screen information" msgstr "不能获取屏幕信息" #: panels/keyboard/shortcut_dialog.ui.h:1 msgid "Custom Shortcut" msgstr "自定义快捷键" #: panels/keyboard/shortcut_dialog.ui.h:2 #: panels/session-properties/main-table.ui.h:1 msgid "Name:" msgstr "程序名称:" #: panels/keyboard/shortcut_dialog.ui.h:3 msgid "Command" msgstr "执行命令:" #: panels/keyboard/shortcut_dialog.ui.h:4 msgid "Scan" msgstr "浏览" #: panels/keyboard/ukui-keybinding-properties.c:1074 #: panels/keyboard/ukui-keybinding-properties.c:1697 msgid "Custom Shortcuts" msgstr "自定义快捷键" #: panels/keyboard/ukui-keybinding-properties.c:1350 #, c-format msgid "" "The shortcut \"%s\" cannot be used because it will become impossible to type " "using this key.\n" "Please try with a key such as Control, Alt or Shift at the same time." msgstr "" "快捷键 \"%s\" 不能被使用,因为很有可能使用该键进行输入\n" "请同时使用Ctrl,Alt或者Shift等键。" #: panels/keyboard/ukui-keybinding-properties.c:1383 #, c-format msgid "" "The shortcut \"%s\" is already used for\n" "\"%s\",please reset!!!" msgstr "" "快捷键“%s”已经用于\n" "“%s”,请重新设置" #: panels/keyboard/ukui-keybinding-properties.c:1527 msgid "Add Shortcuts" msgstr "添加快捷方式" #: panels/keyboard/ukui-keybinding-properties.c:1919 msgid "Selection Program" msgstr "选择快捷打开的程序" #: panels/keyboard/ukui-keybinding-properties.c:1963 msgid "Function description" msgstr "功能说明" #: panels/keyboard/ukui-keybinding-properties.c:1984 msgid "Hotkey" msgstr "热键" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:1 msgid "Select the keyboard layout" msgstr "选择键盘布局" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:2 msgid "_Variants:" msgstr "变体(_V):" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:3 msgid "_Country:" msgstr "国家/地区(_C):" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:4 msgid "By _country" msgstr "按国家/地区(_C)" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:5 msgid "_Language:" msgstr "语言(_L):" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:6 msgid "By _language" msgstr "按语言(_L):" #: panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h:7 msgid "Preview:" msgstr "预览" #: panels/network-proxy/network.ui.h:1 msgid "Network Proxy Details" msgstr "网络代理详情" #: panels/network-proxy/network.ui.h:2 msgid "User authentication" msgstr "用户认证" #: panels/network-proxy/network.ui.h:3 msgid "Username:" msgstr "用户名:" #: panels/network-proxy/network.ui.h:4 msgid "Password:" msgstr "密 码:" #: panels/power/copy-theme-dialog.c:215 msgid "Copying files" msgstr "" #: panels/power/copy-theme-dialog.c:234 msgid "From:" msgstr "" #: panels/power/copy-theme-dialog.c:238 msgid "To:" msgstr "" #: panels/power/copy-theme-dialog.c:259 msgid "Copying themes" msgstr "" #: panels/power/copy-theme-dialog.c:302 msgid "Invalid screensaver theme" msgstr "" #: panels/power/copy-theme-dialog.c:305 #, c-format msgid "%s does not appear to be a valid screensaver theme." msgstr "" #: panels/power/copy-theme-dialog.c:485 #, c-format msgid "Copying file: %u of %u" msgstr "" #: panels/power/kpm-common.c:52 msgid "Unknown time" msgstr "未知时间" #: panels/power/kpm-common.c:57 #, c-format msgid "%i minutes" msgid_plural "%i minutes" msgstr[0] "%i 分钟" #: panels/power/kpm-common.c:68 #, c-format msgid "%i hours" msgid_plural "%i hours" msgstr[0] "%i 小时" #: panels/power/kpm-common.c:74 #, c-format msgid "%i %s %i %s" msgstr "" #: panels/power/kpm-common.c:75 shell/shell.ui.h:60 msgid "hour" msgid_plural "hours" msgstr[0] "时" #: panels/power/kpm-common.c:76 msgid "minute" msgid_plural "minutes" msgstr[0] "分" #: panels/power/kpm-common.h:41 msgid "Power Manager" msgstr "电源管理" #: panels/power/kpm-common.h:42 msgid "Power Manager for the UKUI desktop" msgstr "UKUI桌面环境的电源管理" #: panels/power/kpm-prefs-core.c:168 panels/power/kpm-prefs-core.c:170 msgid "Never" msgstr "从不" #: panels/power/kpm-prefs-core.c:248 panels/power/kpm-prefs-core.c:253 #: panels/power/kpm-prefs-core.c:256 msgid "Shutdown" msgstr "关机" #: panels/power/kpm-prefs-core.c:260 panels/power/kpm-prefs-core.c:269 #: panels/power/kpm-prefs-core.c:272 msgid "Hang" msgstr "挂起" #: panels/power/kpm-prefs-core.c:264 panels/power/kpm-prefs-core.c:277 #: panels/power/kpm-prefs-core.c:280 msgid "Sleep" msgstr "休眠" #: panels/power/kpm-prefs-core.c:285 panels/power/kpm-prefs-core.c:288 #: panels/power/ukui-screensaver-preferences.c:474 #: panels/power/ukui-screensaver-preferences.c:580 #: panels/power/ukui-screensaver-preferences.c:763 msgid "Blank screen" msgstr "黑屏" #: panels/power/kpm-prefs-core.c:293 panels/power/kpm-prefs-core.c:296 msgid "Ask" msgstr "询问" #: panels/power/kpm-prefs-core.c:301 panels/power/kpm-prefs-core.c:304 msgid "Do not perform operations" msgstr "不执行操作" #. TRANSLATORS: a phone is charging #. TRANSLATORS: device is charging, but we only have a percentage #: panels/power/kpm-upower.c:259 panels/power/kpm-upower.c:333 #, c-format msgid "%s charging (%.1f%%)" msgstr "%s 充电中 (%.1f%%)" #. TRANSLATORS: The laptop battery is fully charged, and we know a time #: panels/power/kpm-upower.c:275 #, c-format msgid "" "Battery is fully charged.\n" "Provides %s laptop runtime" msgstr "" "电池已充满.\n" "可提供 %s 笔记本运行时间" #. TRANSLATORS: the device is fully charged #: panels/power/kpm-upower.c:282 #, c-format msgid "%s is fully charged" msgstr "%s 已充满" #. TRANSLATORS: the device is discharging, and we have a time remaining #: panels/power/kpm-upower.c:292 #, c-format msgid "%s %s remaining (%.1f%%)" msgstr "剩余%s %s (%.1f%%)" #. TRANSLATORS: the device is discharging, but we only have a percentage #: panels/power/kpm-upower.c:299 #, c-format msgid "%s discharging (%.1f%%)" msgstr "%s 放电中 (%.1f%%)" #. TRANSLATORS: the device is charging, and we have a time to full and empty #: panels/power/kpm-upower.c:315 #, c-format msgid "" "%s %s until charged (%.1f%%)\n" "Provides %s battery runtime" msgstr "" "还需%s %s才能充满 (%.1f%%)\n" "可提供 %s 电池运行时间" #. TRANSLATORS: device is charging, and we have a time to full and a percentage #: panels/power/kpm-upower.c:326 #, c-format msgid "%s %s until charged (%.1f%%)" msgstr "离充满还有 %s %s (%.1f%%)" #. TRANSLATORS: this is only shown for laptops with multiple batteries #: panels/power/kpm-upower.c:341 #, c-format msgid "%s waiting to discharge (%.1f%%)" msgstr "%s 正在等待充电(%.1f%%)" #. TRANSLATORS: this is only shown for laptops with multiple batteries #: panels/power/kpm-upower.c:349 #, c-format msgid "%s waiting to charge (%.1f%%)" msgstr "%s 正在等待充电(%.1f%%)" #. TRANSLATORS: the type of data, e.g. Laptop battery #: panels/power/kpm-upower.c:410 msgid "Product:" msgstr "产品:" #. TRANSLATORS: device is missing #. TRANSLATORS: device is charged #. TRANSLATORS: device is charging #. TRANSLATORS: device is discharging #: panels/power/kpm-upower.c:415 panels/power/kpm-upower.c:420 #: panels/power/kpm-upower.c:425 panels/power/kpm-upower.c:430 msgid "Status:" msgstr "状态:" #: panels/power/kpm-upower.c:415 msgid "Missing" msgstr "缺少" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:420 panels/power/kpm-upower.c:730 msgid "Charged" msgstr "已充满" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:425 panels/power/kpm-upower.c:718 msgid "Charging" msgstr "正充电" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:430 panels/power/kpm-upower.c:722 msgid "Discharging" msgstr "正放电" #. TRANSLATORS: percentage #: panels/power/kpm-upower.c:436 msgid "Percentage charge:" msgstr "充电百分比:" #. TRANSLATORS: manufacturer #: panels/power/kpm-upower.c:441 msgid "Vendor:" msgstr "厂家:" #. TRANSLATORS: how the battery is made, e.g. Lithium Ion #: panels/power/kpm-upower.c:447 msgid "Technology:" msgstr "技术:" #. TRANSLATORS: serial number of the battery #: panels/power/kpm-upower.c:452 msgid "Serial number:" msgstr "序列号:" #. TRANSLATORS: model number of the battery #: panels/power/kpm-upower.c:457 msgid "Model:" msgstr "型号:" #. TRANSLATORS: time to fully charged #: panels/power/kpm-upower.c:463 msgid "Charge time:" msgstr "充电时间:" #. TRANSLATORS: time to empty #: panels/power/kpm-upower.c:470 msgid "Discharge time:" msgstr "放电时间:" #. TRANSLATORS: Excellent, Good, Fair and Poor are all related to battery Capacity #: panels/power/kpm-upower.c:479 msgid "Excellent" msgstr "非常好" #: panels/power/kpm-upower.c:483 msgid "Good" msgstr "较好" #: panels/power/kpm-upower.c:487 msgid "Fair" msgstr "尚可" #: panels/power/kpm-upower.c:491 msgid "Poor" msgstr "不好" #: panels/power/kpm-upower.c:495 msgid "Capacity:" msgstr "容量:" #: panels/power/kpm-upower.c:503 panels/power/kpm-upower.c:533 msgid "Current charge:" msgstr "当前充电:" #: panels/power/kpm-upower.c:510 msgid "Last full charge:" msgstr "上次充电:" #: panels/power/kpm-upower.c:517 panels/power/kpm-upower.c:539 msgid "Design charge:" msgstr "设计充电:" #: panels/power/kpm-upower.c:523 msgid "Charge rate:" msgstr "充电率:" #. TRANSLATORS: system power cord #: panels/power/kpm-upower.c:561 msgid "AC adapter" msgid_plural "AC adapters" msgstr[0] "交流电源适配器" #. TRANSLATORS: laptop primary battery #: panels/power/kpm-upower.c:565 msgid "Laptop battery" msgid_plural "Laptop batteries" msgstr[0] "笔记本电池" #. TRANSLATORS: battery-backed AC power source #: panels/power/kpm-upower.c:569 msgid "UPS" msgid_plural "UPSs" msgstr[0] "UPS" #. TRANSLATORS: wireless mice with internal batteries #: panels/power/kpm-upower.c:577 shell/mainwindow.c:212 shell/shell.ui.h:24 msgid "Mouse" msgid_plural "Mice" msgstr[0] "鼠标" #. TRANSLATORS: wireless keyboard with internal battery #: panels/power/kpm-upower.c:581 shell/mainwindow.c:201 shell/shell.ui.h:22 msgid "Keyboard" msgid_plural "Keyboards" msgstr[0] "键盘" #. TRANSLATORS: portable device #: panels/power/kpm-upower.c:585 msgid "PDA" msgid_plural "PDAs" msgstr[0] "" msgstr[1] "" #. TRANSLATORS: cell phone (mobile...) #: panels/power/kpm-upower.c:589 msgid "Cell phone" msgid_plural "Cell phones" msgstr[0] "手机" #. TRANSLATORS: media player, mp3 etc #: panels/power/kpm-upower.c:594 msgid "Media player" msgid_plural "Media players" msgstr[0] "媒体播放器" #. TRANSLATORS: tablet device #: panels/power/kpm-upower.c:598 msgid "Tablet" msgid_plural "Tablets" msgstr[0] "触摸板" #. TRANSLATORS: tablet device #: panels/power/kpm-upower.c:602 msgid "Computer" msgid_plural "Computers" msgstr[0] "计算机" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:673 msgid "Lithium Ion" msgstr "锂离子" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:677 msgid "Lithium Polymer" msgstr "锂聚合物" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:681 msgid "Lithium Iron Phosphate" msgstr "磷酸铁锂" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:685 msgid "Lead acid" msgstr "铅酸" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:689 msgid "Nickel Cadmium" msgstr "镍氢" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:693 msgid "Nickel metal hydride" msgstr "镍氢" #. TRANSLATORS: battery technology #: panels/power/kpm-upower.c:697 msgid "Unknown technology" msgstr "未知技术" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:726 msgid "Empty" msgstr "空" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:734 msgid "Waiting to charge" msgstr "待充电" #. TRANSLATORS: battery state #: panels/power/kpm-upower.c:738 msgid "Waiting to discharge" msgstr "待放电" #: panels/power/ukui-fullscreen-preview.ui.h:1 msgid "Screensaver Preview" msgstr "屏保预览" #: panels/power/ukui-fullscreen-preview.ui.h:2 msgid "Screensaver preview" msgstr "屏保预览" #: panels/power/ukui-screensaver-preferences.c:475 #: panels/power/ukui-screensaver-preferences.c:575 #: panels/power/ukui-screensaver-preferences.c:761 msgid "Random" msgstr "随机" #: panels/power/ukui-screensaver-preferences.c:637 #: panels/power/ukui-screensaver-preferences.c:1461 #, c-format msgid "%d min" msgstr "%d 分钟" #: panels/power/ukui-screensaver-preferences.c:639 #: panels/power/ukui-screensaver-preferences.c:1463 #, c-format msgid "%d hour %d min" msgstr "%d 小时 %d 分" #: panels/power/ukui-screensaver-preferences.c:1519 msgid "Could not load the main interface" msgstr "无法加载主界面" #: panels/power/ukui-screensaver-preferences.c:1521 msgid "Please make sure that the screensaver is properly installed" msgstr "请确保屏保被正确的安装" #: panels/session-properties/gsm-app-dialog.c:145 msgid "Desktop file(*.desktop)" msgstr "桌面文件(*.desktop)" #: panels/session-properties/gsm-app-dialog.c:152 msgid "Select command" msgstr "选择命令" #: panels/session-properties/gsm-app-dialog.c:257 msgid "Add programs" msgstr "添加开机启动程序" #: panels/session-properties/gsm-app-dialog.c:261 msgid "Boot program property details" msgstr "启动程序属性详情" #: panels/session-properties/gsm-app-dialog.c:526 msgid "The startup command cannot be empty" msgstr "启动命令不能为空" #: panels/session-properties/gsm-app-dialog.c:532 msgid "The startup command is not valid" msgstr "无效的启动命令" #: panels/session-properties/gsm-properties-dialog.c:117 msgid "enabled" msgstr "已启动" #: panels/session-properties/gsm-properties-dialog.c:119 msgid "disabled" msgstr "已禁用" #: panels/session-properties/gsm-properties-dialog.c:445 #, c-format msgid "%d/%d/%d/ %d:%d:%d" msgstr "%d年%d月%d日%d时%d分%d秒" #: panels/session-properties/gsm-properties-dialog.c:526 msgid "property" msgstr "属性" #: panels/session-properties/gsm-properties-dialog.c:553 #, c-format msgid "%dByte" msgstr "%d字节" #: panels/session-properties/main-table.ui.h:2 msgid "Command:" msgstr "程序路径:" #: panels/session-properties/main-table.ui.h:3 msgid "Annotation:" msgstr "程序注释:" #: panels/session-properties/main-table.ui.h:4 msgid "scan…" msgstr "浏览…" #: panels/session-properties/program_properties.ui.h:1 msgid "program name" msgstr "名称" #: panels/session-properties/program_properties.ui.h:2 msgid "File Type:" msgstr "类型:" #: panels/session-properties/program_properties.ui.h:3 msgid "File Description:" msgstr "描述:" #: panels/session-properties/program_properties.ui.h:4 msgid "Application" msgstr "应用程序" #: panels/session-properties/program_properties.ui.h:5 msgid "Program Location:" msgstr "位置:" #: panels/session-properties/program_properties.ui.h:6 msgid "Program Size:" msgstr "大小:" #: panels/session-properties/program_properties.ui.h:7 msgid "Access Time:" msgstr "访问:" #: panels/session-properties/program_properties.ui.h:8 msgid "modification time:" msgstr "修改:" #: panels/user-accounts/change-face.ui.h:1 msgid "Changge Face" msgstr "更改头像" #: panels/user-accounts/change-face.ui.h:2 #: panels/user-accounts/change-name.ui.h:2 #: panels/user-accounts/change-pwd.ui.h:2 #: panels/user-accounts/change-type.ui.h:2 #: panels/user-accounts/delete-user.ui.h:2 #: panels/user-accounts/user-accounts.c:2039 #: panels/user-accounts/user-create.ui.h:2 msgid "Cancel" msgstr "取消" #: panels/user-accounts/change-face.ui.h:3 #: panels/user-accounts/change-name.ui.h:3 #: panels/user-accounts/change-pwd.ui.h:3 #: panels/user-accounts/change-type.ui.h:3 #: panels/user-accounts/user-accounts.c:2040 msgid "Ok" msgstr "确定" #: panels/user-accounts/change-face.ui.h:4 #: panels/user-accounts/change-name.ui.h:4 #: panels/user-accounts/change-pwd.ui.h:4 #: panels/user-accounts/change-type.ui.h:5 #: panels/user-accounts/delete-user.ui.h:5 shell/shell.ui.h:191 msgid "label" msgstr "" #: panels/user-accounts/change-face.ui.h:5 #: panels/user-accounts/user-accounts.c:2036 msgid "Browse more pictures" msgstr "浏览更多图片" #: panels/user-accounts/change-name.ui.h:1 msgid "Change Name" msgstr "更改用户名" #: panels/user-accounts/change-pwd.ui.h:1 msgid "Change Password" msgstr "更改密码" #: panels/user-accounts/change-type.ui.h:1 msgid "Change Usertype" msgstr "更改用户类型" #: panels/user-accounts/change-type.ui.h:4 msgid "automatic login" msgstr "自动登录" #: panels/user-accounts/change-type.ui.h:6 msgid "" "Please make sure that the computer has at least one user is the administrator" msgstr "请确保该计算机上至少有一个用户为管理员用户" #: panels/user-accounts/change-type.ui.h:7 #: panels/user-accounts/user-create.ui.h:5 msgid "Standard User" msgstr "标准用户" #: panels/user-accounts/change-type.ui.h:8 msgid "" "Standard users can use most software, but you can not install software and \n" "change settings that affect all users." msgstr "标准用户可以使用大多数软件,但不能安装软件和更改影响所有用户的设置。" #: panels/user-accounts/change-type.ui.h:10 #: panels/user-accounts/user-accounts.c:668 #: panels/user-accounts/user-accounts.c:925 #: panels/user-accounts/user-accounts.c:1109 #: panels/user-accounts/user-accounts.c:1218 #: panels/user-accounts/user-accounts.c:1219 #: panels/user-accounts/user-accounts.c:1333 #: panels/user-accounts/user-accounts.c:1559 #: panels/user-accounts/user-accounts.c:1669 #: panels/user-accounts/user-create.ui.h:8 msgid "Administrators" msgstr "管理员" #: panels/user-accounts/change-type.ui.h:11 #: panels/user-accounts/user-create.ui.h:9 msgid "" "Administrator can make any changes needed on the system, including \n" "installing and upgrading software." msgstr "管理员在系统上可以做任何需要的修改,包括安装和升级软件。      " #: panels/user-accounts/check-passwd.c:583 msgid "is the same as the old one" msgstr "新密码和旧密码一样!" #: panels/user-accounts/check-passwd.c:589 #: panels/user-accounts/check-passwd.c:593 #: panels/user-accounts/check-passwd.c:603 msgid "memory allocation error" msgstr "内存分配错误!" #: panels/user-accounts/check-passwd.c:608 msgid "is a palindrome" msgstr "回文密码!" #: panels/user-accounts/check-passwd.c:611 msgid "case changes only" msgstr "" #: panels/user-accounts/check-passwd.c:614 msgid "is too similar to the old one" msgstr "新密码和旧密码太相似!" #: panels/user-accounts/check-passwd.c:617 msgid "is too simple" msgstr "密码太过简单!" #: panels/user-accounts/check-passwd.c:620 msgid "is rotated" msgstr "循环密码!" #: panels/user-accounts/check-passwd.c:623 msgid "not enough character classes" msgstr "包含的字符种类不够!" #: panels/user-accounts/check-passwd.c:626 msgid "contains too many same characters consecutively" msgstr "包含太多相同的字符!" #: panels/user-accounts/check-passwd.c:629 msgid "contains too long of a monotonic character sequence" msgstr "包含太多的单调字符序列!" #: panels/user-accounts/check-passwd.c:632 msgid "contains the user name in some form" msgstr "包含用户名!" #: panels/user-accounts/delete-user.ui.h:1 msgid "Delete User" msgstr "删除用户" #: panels/user-accounts/delete-user.ui.h:3 msgid "Keep File" msgstr "保留文件" #: panels/user-accounts/delete-user.ui.h:4 msgid "Delete File" msgstr "删除文件" #: panels/user-accounts/run-passwd.c:221 msgid "Authentication failure!" msgstr "认证失败!" #: panels/user-accounts/run-passwd.c:298 msgid "New password length is too short!" msgstr "新密码长度太短!" #: panels/user-accounts/run-passwd.c:304 msgid "The new password is too simple!" msgstr "新密码太简单!" #: panels/user-accounts/run-passwd.c:310 msgid "The new password is too similar to the old one!" msgstr "新密码和旧密码太相似!" #: panels/user-accounts/run-passwd.c:313 msgid "The new password must contain numbers or special characters!" msgstr "新密码必须包含数字或特殊字符!" #: panels/user-accounts/run-passwd.c:317 msgid "The new password is the same as the old one!" msgstr "新密码和旧密码一样!" #: panels/user-accounts/run-passwd.c:320 msgid "The new password has been used recently!" msgstr "新密码最近已被使用过!" #: panels/user-accounts/run-passwd.c:324 msgid "Your password has been changed after you verify!" msgstr "在您验证过后您的密码已经被更改!" #: panels/user-accounts/user-accounts.c:168 msgid "User name cannot be empty!" msgstr "用户名不能为空!" #: panels/user-accounts/user-accounts.c:194 msgid "Password length needs to more than 5 digits!" msgstr "密码长度需要5位以上!" #: panels/user-accounts/user-accounts.c:201 #: panels/user-accounts/user-accounts.c:394 msgid "Password length needs to less than 64 digits!" msgstr "密码长度需要小于64位!" #: panels/user-accounts/user-accounts.c:213 #: panels/user-accounts/user-accounts.c:340 #: panels/user-accounts/user-accounts.c:378 #: panels/user-accounts/user-accounts.c:386 #: panels/user-accounts/user-accounts.c:401 #: panels/user-accounts/user-accounts.c:623 #: panels/user-accounts/user-accounts.c:719 #: panels/user-accounts/user-accounts.c:2544 msgid "Please confirm the new password" msgstr "请确认新密码" #: panels/user-accounts/user-accounts.c:215 #: panels/user-accounts/user-accounts.c:233 #: panels/user-accounts/user-accounts.c:404 msgid "enter the password twice inconsistencies!" msgstr "两次输入密码不一致!" #: panels/user-accounts/user-accounts.c:248 #: panels/user-accounts/user-accounts.c:754 msgid "The first character cannot be underlined!" msgstr "首字符不能为下划线!" #: panels/user-accounts/user-accounts.c:254 #: panels/user-accounts/user-accounts.c:760 msgid "User name can not contain capital letters!" msgstr "用户名不能包含大写字母!" #: panels/user-accounts/user-accounts.c:262 #: panels/user-accounts/user-accounts.c:768 msgid "The user name can only be composed of letters, numbers and underline!" msgstr "用户名只能由字母、数字以及下划线组成!" #: panels/user-accounts/user-accounts.c:269 msgid "The first character cannot be numeric!" msgstr "首字符不能为数字!" #: panels/user-accounts/user-accounts.c:280 #: panels/user-accounts/user-accounts.c:337 #: panels/user-accounts/user-accounts.c:2532 msgid "Please enter the username" msgstr "请输入用户名" #: panels/user-accounts/user-accounts.c:281 msgid "Please enter the password " msgstr "请输入密码" #: panels/user-accounts/user-accounts.c:293 msgid "The user name is already in use, please use a different one." msgstr "该用户名已被使用,请换用其他用户名!" #: panels/user-accounts/user-accounts.c:313 msgid "" "The user name corresponds to the group already exists,please use a different " "user name" msgstr "该用户名对应的组已存在,请换用其他用户名" #: panels/user-accounts/user-accounts.c:325 msgid "username length need to less than 32!" msgstr "用户名长度不能超过32位!" #: panels/user-accounts/user-accounts.c:337 #: panels/user-accounts/user-accounts.c:940 msgid "Please enter the new username" msgstr "请输入新用户名" #: panels/user-accounts/user-accounts.c:339 #: panels/user-accounts/user-accounts.c:2539 msgid "Please enter the password" msgstr "请输入密码" #: panels/user-accounts/user-accounts.c:339 #: panels/user-accounts/user-accounts.c:614 #: panels/user-accounts/user-accounts.c:710 msgid "Please enter new password" msgstr "请输入新密码" #: panels/user-accounts/user-accounts.c:340 #: panels/user-accounts/user-accounts.c:376 #: panels/user-accounts/user-accounts.c:592 #: panels/user-accounts/user-accounts.c:696 msgid "Please enter the current password" msgstr "请输入当前密码" #: panels/user-accounts/user-accounts.c:340 #: panels/user-accounts/user-accounts.c:377 #: panels/user-accounts/user-accounts.c:385 #: panels/user-accounts/user-accounts.c:400 msgid "Please enter the new password" msgstr "请输入新密码" #: panels/user-accounts/user-accounts.c:443 msgid "Please choose another password." msgstr "请选择其它的密码." #: panels/user-accounts/user-accounts.c:457 msgid "Please reenter the current password." msgstr "请重新输入当前密码." #: panels/user-accounts/user-accounts.c:464 msgid "Password can not be modified." msgstr "密码无法被修改." #: panels/user-accounts/user-accounts.c:557 msgid "Password input error, please re-enter!" msgstr "当前密码输入错误,请重新输入!" #: panels/user-accounts/user-accounts.c:670 #: panels/user-accounts/user-accounts.c:927 #: panels/user-accounts/user-accounts.c:1111 #: panels/user-accounts/user-accounts.c:1223 #: panels/user-accounts/user-accounts.c:1224 #: panels/user-accounts/user-accounts.c:1338 #: panels/user-accounts/user-accounts.c:1561 #: panels/user-accounts/user-accounts.c:1671 msgid "Standard user" msgstr "标准用户" #: panels/user-accounts/user-accounts.c:676 #: panels/user-accounts/user-accounts.c:933 #: panels/user-accounts/user-accounts.c:1116 #: panels/user-accounts/user-accounts.c:1352 #: panels/user-accounts/user-accounts.c:1593 #: panels/user-accounts/user-accounts.c:1679 msgid "Logged(Current User)" msgstr "已登录(当前用户)" #: panels/user-accounts/user-accounts.c:681 #: panels/user-accounts/user-accounts.c:935 #: panels/user-accounts/user-accounts.c:1118 #: panels/user-accounts/user-accounts.c:1354 #: panels/user-accounts/user-accounts.c:1597 #: panels/user-accounts/user-accounts.c:1683 msgid "Logged(Other Users)" msgstr "已登录(其他用户)" #: panels/user-accounts/user-accounts.c:685 #: panels/user-accounts/user-accounts.c:937 #: panels/user-accounts/user-accounts.c:1120 #: panels/user-accounts/user-accounts.c:1356 #: panels/user-accounts/user-accounts.c:1601 #: panels/user-accounts/user-accounts.c:1687 msgid "Un-login(Other Users)" msgstr "未登录(其他用户)" #: panels/user-accounts/user-accounts.c:775 msgid "User name cannot start with number!" msgstr "用户名不能以数字开头!" #: panels/user-accounts/user-accounts.c:781 msgid "Username length need to less than 32!" msgstr "用户名长度不能超过32位!" #: panels/user-accounts/user-accounts.c:793 msgid "The user name has been used, please replace with another one!" msgstr "该用户名已经被使用,请换一个!" #: panels/user-accounts/user-accounts.c:824 #: panels/user-accounts/user-accounts.c:861 msgid "Modify username failed!" msgstr "修改用户名失败!" #: panels/user-accounts/user-accounts.c:869 msgid "the user has logged in, please log out and modify!" msgstr "该用户已登录,请注销该用户后再修改!" #: panels/user-accounts/user-accounts.c:1052 #: panels/user-accounts/user-accounts.c:2286 msgid "auto login" msgstr "自动登录" #: panels/user-accounts/user-accounts.c:1055 #: panels/user-accounts/user-accounts.c:2289 msgid "_Cancel" msgstr "取消" #: panels/user-accounts/user-accounts.c:1057 #: panels/user-accounts/user-accounts.c:2291 msgid "_OK" msgstr "确认" #: panels/user-accounts/user-accounts.c:1060 #: panels/user-accounts/user-accounts.c:2294 msgid "" "\tAlready have other users set to automatically log in,\t\n" " \tclick OK will overwrite the existing settings!" msgstr "" "\t已经有其他用户设置为自动登录了,\t\n" "\t点击确认将覆盖以前的设置!" #: panels/user-accounts/user-accounts.c:1467 msgid "The user can not be deleted!" msgstr "无法删除该用户!" #: panels/user-accounts/user-accounts.c:1475 msgid "" "The user has logged in, please perform the delete operation after logging " "out!" msgstr "该用户已登录,请注销该用户后再执行删除操作!" #: panels/user-accounts/user-accounts.c:1500 #, c-format msgid "" "do you confirm to delete all the files of " "%s?" msgstr "" "确认删除用户 %s 的所有文件吗?" #: panels/user-accounts/user-accounts.c:1506 #, c-format msgid "" "if you want to delete the %s user, belonging to the user's \n" "desktop, documents, favorites, music, pictures and video \n" "folder will be deleted!" msgstr "" "如果要删除 %s 用户,那么属于该用户的桌面、文档、收藏\n" "夹、音乐、图片和视频文件夹的内容将全部被删除!" #: panels/user-accounts/user-accounts.c:1563 #: panels/user-accounts/user-accounts.c:1673 msgid "Super user" msgstr "超级用户" #: panels/user-accounts/user-accounts.c:1565 msgid "Rename" msgstr "更改用户名" #: panels/user-accounts/user-accounts.c:1571 msgid "Change PWD" msgstr "更改密码" #: panels/user-accounts/user-accounts.c:1576 msgid "Change Face" msgstr "更改头像" #: panels/user-accounts/user-accounts.c:1581 msgid "Change Type" msgstr "更改用户类型" #: panels/user-accounts/user-accounts.c:1586 msgid "Delete" msgstr "删除用户" #: panels/user-accounts/user-accounts.c:2181 msgid "Browse more pictures..." msgstr "浏览更多图片..." #: panels/user-accounts/user-create.ui.h:1 msgid "Create Account" msgstr "创建账户" #: panels/user-accounts/user-create.ui.h:3 msgid "Automatic Logon" msgstr "自动登录" #: panels/user-accounts/user-create.ui.h:4 msgid "select picture" msgstr "选择图片" #: panels/user-accounts/user-create.ui.h:6 msgid "" "Standard users can use most software, but you can not install software\n" "and change settings that affect all users." msgstr "标准用户可以使用大多数软件,但不能安装软件和更改影响所有用户的设置。" #: panels/volume-control/gvc-balance-bar.c:116 msgid "Rear" msgstr "后置声道" #: panels/volume-control/gvc-balance-bar.c:117 msgid "Front" msgstr "前置声道" #: panels/volume-control/gvc-balance-bar.c:120 msgid "Minimum" msgstr "最小值" #: panels/volume-control/gvc-balance-bar.c:121 msgid "Maximum" msgstr "最大值" #: panels/volume-control/gvc-balance-bar.c:299 msgid "_Balance(_B):" msgstr "平衡(_B):" #: panels/volume-control/gvc-balance-bar.c:302 msgid "_Fade(_F):" msgstr "淡出(_F):" #: panels/volume-control/gvc-balance-bar.c:305 msgid "_Subwoofer(_S):" msgstr "低音炮(_S):" #: panels/volume-control/gvc-channel-bar.c:608 msgid "Unamplified" msgstr "非放大" #: panels/volume-control/gvc-channel-bar.c:870 msgid "Mute" msgstr "静音" #: panels/volume-control/gvc-combo-box.c:169 msgid "_Profile(_P):" msgstr "配置文件(_P):" #: panels/volume-control/gvc-mixer-control.c:1004 msgid "Disabled" msgstr "禁用" #: panels/volume-control/gvc-mixer-control.c:1011 #, c-format msgid "%u Output" msgid_plural "%u Outputs" msgstr[0] "%u 输出" #: panels/volume-control/gvc-mixer-control.c:1021 #, c-format msgid "%u Input" msgid_plural "%u Inputs" msgstr[0] "%u 输入" #: panels/volume-control/gvc-mixer-dialog.c:314 msgid "Co_nnector" msgstr "连接器(_N)" #: panels/volume-control/gvc-mixer-dialog.c:522 msgid "Peak detect" msgstr "峰值检测" #: panels/volume-control/gvc-mixer-dialog.c:609 msgid "Co_nnector:" msgstr "连接器(_N):" #: panels/volume-control/gvc-mixer-dialog.c:1502 msgid "Device" msgstr "设备" #: panels/volume-control/gvc-mixer-dialog.c:1550 #, c-format msgid "Speaker Testing for %s" msgstr "%s测试" #: panels/volume-control/gvc-mixer-dialog.c:1610 msgid "_Profiles:" msgstr "配置(_P):" #: panels/volume-control/gvc-mixer-dialog.c:1611 msgid "Test Speakers" msgstr "测试听筒" #: panels/volume-control/gvc-mixer-dialog.c:1710 #: panels/volume-control/gvc-sound-theme-chooser.c:892 msgid "Name" msgstr "名称" #: panels/volume-control/gvc-mixer-dialog.c:1837 msgid "Sound Output Volume" msgstr "输出音量(_O):" #: panels/volume-control/gvc-mixer-dialog.c:1868 msgid "Applications" msgstr "应用程序" #: panels/volume-control/gvc-mixer-dialog.c:1874 msgid "No application is currently playing or recording audio." msgstr "目前没有应用程序在播放或录制音频" #: panels/volume-control/gvc-mixer-dialog.c:1882 msgid "Sound Effects" msgstr "声音效果" #: panels/volume-control/gvc-mixer-dialog.c:1890 msgid "_Alert volume: " msgstr "报警音量(_A): " #: panels/volume-control/gvc-mixer-dialog.c:1911 msgid "Input" msgstr "输入" #: panels/volume-control/gvc-mixer-dialog.c:1919 msgid "_Input volume: " msgstr "输入音量(_I): " #: panels/volume-control/gvc-mixer-dialog.c:1942 msgid "Input level:" msgstr "输入等级:" #: panels/volume-control/gvc-mixer-dialog.c:1971 msgid "C_hoose a device for sound input:" msgstr "选择声音输入设备(_H):" #: panels/volume-control/gvc-mixer-dialog.c:2001 msgid "Output" msgstr "输出" #: panels/volume-control/gvc-mixer-dialog.c:2007 msgid "C_hoose a device for sound output:" msgstr "选择声音输出设备(_H):" #: panels/volume-control/gvc-mixer-dialog.c:2034 #: panels/volume-control/gvc-mixer-dialog.c:2078 msgid "Settings for the selected device:" msgstr "所选设备的设置:" #: panels/volume-control/gvc-mixer-dialog.c:2045 msgid "Hardware" msgstr "硬件" #: panels/volume-control/gvc-mixer-dialog.c:2051 msgid "C_hoose a device to configure:" msgstr "选择要配置的设备(_H):" #: panels/volume-control/gvc-mixer-dialog.c:2212 #: panels/volume-control/gvc-sound-theme-chooser.c:757 #: panels/volume-control/gvc-sound-theme-chooser.c:769 #: panels/volume-control/gvc-sound-theme-chooser.c:781 msgid "Sound Preferences" msgstr "声音首选项" #: panels/volume-control/gvc-sound-theme-chooser.c:226 #: panels/volume-control/gvc-sound-theme-chooser.c:868 msgid "Default" msgstr "默认" #: panels/volume-control/gvc-sound-theme-chooser.c:338 msgid "No sounds" msgstr "无声音" #: panels/volume-control/gvc-sound-theme-chooser.c:460 msgid "Built-in" msgstr "内置" #: panels/volume-control/gvc-sound-theme-chooser.c:647 #: panels/volume-control/sound-theme-file-utils.c:291 msgid "Custom" msgstr "自定义" #: panels/volume-control/gvc-sound-theme-chooser.c:760 #: panels/volume-control/gvc-sound-theme-chooser.c:771 #: panels/volume-control/gvc-sound-theme-chooser.c:783 msgid "Testing event sound" msgstr "测试事件声音" #: panels/volume-control/gvc-sound-theme-chooser.c:869 msgid "From theme" msgstr "来自主题" #: panels/volume-control/gvc-sound-theme-chooser.c:899 msgid "Type" msgstr "类型" #: panels/volume-control/gvc-sound-theme-chooser.c:1093 msgid "Sound _theme:" msgstr "声音主题:" #: panels/volume-control/gvc-sound-theme-chooser.c:1106 msgid "C_hoose an alert sound:" msgstr "选择报警声音(_H):" #: panels/volume-control/gvc-sound-theme-chooser.c:1140 msgid "Enable _window and button sounds" msgstr "启用窗体与按钮声音(_W)" #: panels/volume-control/gvc-speaker-test.c:219 msgid "Stop" msgstr "停止" #: panels/volume-control/gvc-speaker-test.c:219 #: panels/volume-control/gvc-speaker-test.c:331 msgid "Test" msgstr "测试" #: panels/volume-control/gvc-speaker-test.c:227 msgid "Subwoofer" msgstr "低音炮" #: shell/mainwindow.c:94 shell/shell.ui.h:11 msgid "Control Center" msgstr "控制面板" #: shell/mainwindow.c:142 msgid "Time and Dates" msgstr "时间和日期" #: shell/mainwindow.c:145 msgid " Change the time and date of this computer " msgstr " 更改此计算机的时间和日期 " #: shell/mainwindow.c:153 shell/shell.ui.h:17 msgid "User Account" msgstr "用户账户" #: shell/mainwindow.c:156 msgid "" " Change the computer user account \n" " settings and password" msgstr "" " 更改此计算机的用户账户\n" "设置和密码" #: shell/mainwindow.c:164 shell/shell.ui.h:12 msgid "Personalization" msgstr "个性化" #: shell/mainwindow.c:167 msgid "" " Change the computer desktop background \n" " and related theme" msgstr "" " 更改此计算机的桌面背景 \n" "和主题相关" #: shell/mainwindow.c:175 msgid "Default Application" msgstr "默认应用程序" #: shell/mainwindow.c:178 msgid " Change the default application on this computer " msgstr " 更改此计算机的默认应用程序 " #: shell/mainwindow.c:193 msgid " Change the network on this computer " msgstr " 更改此计算机的网络连接" #: shell/mainwindow.c:204 msgid " Change the keyboard settings on this computer " msgstr " 更改此计算机的键盘设置 " #: shell/mainwindow.c:215 msgid " Change the mouse settings on this computer " msgstr " 更改此计算机的鼠标设置 " #: shell/mainwindow.c:228 msgid " Configure the connection to the computer printer " msgstr " 配置连接到此计算机的打印机 " #: shell/mainwindow.c:237 shell/shell.ui.h:23 msgid "Sound" msgstr "声音" #: shell/mainwindow.c:240 msgid " Change the sound settings on this computer " msgstr " 更改此计算机的声音设置 " #: shell/mainwindow.c:248 msgid "Network Agent" msgstr "网络代理" #: shell/mainwindow.c:251 msgid " Change the network agent on this computer " msgstr " 更改此计算机的网络代理 " #: shell/mainwindow.c:259 shell/shell.ui.h:13 msgid "Autostart" msgstr "开机启动" #: shell/mainwindow.c:262 msgid " Change the autostart program on this computer " msgstr " 更改此计算机的开机启动程序" #: shell/mainwindow.c:272 msgid " Change the Monitor settings on this computer " msgstr " 更改此计算机的显示器配置" #: shell/mainwindow.c:283 msgid "Power Management" msgstr "电源管理" #: shell/mainwindow.c:286 msgid " Change the power management settings on this computer " msgstr " 更改此计算机的电源管理选项 " #: shell/shell.ui.h:5 msgid "Tile" msgstr "平铺" #: shell/shell.ui.h:6 msgid "Zoom" msgstr "缩放" #: shell/shell.ui.h:7 msgid "Center" msgstr "居中" #: shell/shell.ui.h:8 msgid "Scale" msgstr "比例放大" #: shell/shell.ui.h:9 msgid "Stretch" msgstr "伸展" #: shell/shell.ui.h:10 msgid "Span" msgstr "适合宽度" #: shell/shell.ui.h:14 msgid "" "Default \n" "Application" msgstr "默认应用" #: shell/shell.ui.h:16 msgid "Time Dates" msgstr "时间和日期" #: shell/shell.ui.h:18 msgid "System Configuration" msgstr "系统配置" #: shell/shell.ui.h:19 msgid "Printer" msgstr "打印机" #: shell/shell.ui.h:20 msgid "" "Power \n" "Management" msgstr "电源管理" #: shell/shell.ui.h:26 msgid "" "Network \n" "Agent" msgstr "网络代理" #: shell/shell.ui.h:28 msgid "" "Network \n" "Connections" msgstr "网络连接" #: shell/shell.ui.h:30 msgid "Hardware Configure" msgstr "硬件配置" #: shell/shell.ui.h:31 msgid "Home" msgstr "控制面板主页" #: shell/shell.ui.h:32 msgid "_Personalization" msgstr "个性化" #: shell/shell.ui.h:33 msgid "_Autostart" msgstr "开机启动" #: shell/shell.ui.h:34 msgid "_Default APP" msgstr " 默认应用 " #: shell/shell.ui.h:35 msgid "_Time Dates" msgstr "时间和日期" #: shell/shell.ui.h:36 msgid "_User Account" msgstr "用户账户" #: shell/shell.ui.h:37 msgid "Network _Connection" msgstr "网络连接" #: shell/shell.ui.h:38 msgid "_Keyboard" msgstr "键盘" #: shell/shell.ui.h:39 msgid "M_ouse" msgstr "鼠标" #: shell/shell.ui.h:40 msgid "P_rinter" msgstr "打印机" #: shell/shell.ui.h:41 msgid "_Sound" msgstr "声音" #: shell/shell.ui.h:42 msgid "_Network Agent" msgstr "网络代理" #: shell/shell.ui.h:43 msgid "_Monitor" msgstr "显示器" #: shell/shell.ui.h:44 msgid "Po_wer Manage" msgstr " 电源管理 " #: shell/shell.ui.h:45 msgid "Tzone:" msgstr "时区:" #: shell/shell.ui.h:46 msgid "date:" msgstr "日期:" #: shell/shell.ui.h:47 msgid "time:" msgstr "时间:" #: shell/shell.ui.h:48 msgid "Jan" msgstr "一月" #: shell/shell.ui.h:49 msgid "Feb" msgstr "二月" #: shell/shell.ui.h:50 msgid "Mar" msgstr "三月" #: shell/shell.ui.h:51 msgid "Apr" msgstr "四月" #: shell/shell.ui.h:52 msgid "May" msgstr "五月" #: shell/shell.ui.h:53 msgid "Jun" msgstr "六月" #: shell/shell.ui.h:54 msgid "Jul" msgstr "七月" #: shell/shell.ui.h:55 msgid "Aug" msgstr "八月" #: shell/shell.ui.h:56 msgid "Sep" msgstr "九月" #: shell/shell.ui.h:57 msgid "Oct" msgstr "十月" #: shell/shell.ui.h:58 msgid "Nov" msgstr "十一月" #: shell/shell.ui.h:59 msgid "Dec" msgstr "十二月" #: shell/shell.ui.h:61 msgid "min" msgstr "分" #: shell/shell.ui.h:62 msgid "sec" msgstr "秒" #: shell/shell.ui.h:63 msgid "With the network time synchronization" msgstr "与网络时间同步" #: shell/shell.ui.h:64 msgid "because the ntp is installed,please use ntpdate." msgstr "由于安装了ntp,请使用ntpdate进行网络时间同步" #: shell/shell.ui.h:65 msgid "format:" msgstr "制式:" #: shell/shell.ui.h:66 msgid "12-hours" msgstr "12小时制" #: shell/shell.ui.h:67 msgid "24-hours" msgstr "24小时制" #: shell/shell.ui.h:68 msgid "Current Account" msgstr "当前账户" #: shell/shell.ui.h:69 msgid "Other Accounts" msgstr "其他账户" #: shell/shell.ui.h:70 msgid "Create a new account" msgstr "创建一个新账户" #: shell/shell.ui.h:71 msgid "Add" msgstr "添加壁纸" #: shell/shell.ui.h:72 msgid "delete" msgstr "删除壁纸" #: shell/shell.ui.h:73 msgid "Style:" msgstr "图片放置方式:" #: shell/shell.ui.h:74 msgid "wallpaper" msgstr "桌面背景" #: shell/shell.ui.h:75 msgid "Select the one you love color as the theme color" msgstr "选择一个你喜欢的颜色作为主题颜色" #: shell/shell.ui.h:76 msgid "Theme color" msgstr "主题颜色" #: shell/shell.ui.h:77 msgid "Font choice:" msgstr "字体选择:" #: shell/shell.ui.h:78 msgid "Font size :" msgstr "字体大小:" #: shell/shell.ui.h:80 #, no-c-format msgid "small(S) --100%(default)" msgstr "较小(S) --100%(默认)" #: shell/shell.ui.h:82 #, no-c-format msgid "medium(M)--125%" msgstr "中等(M)--125%" #: shell/shell.ui.h:84 #, no-c-format msgid "large (L) --150%" msgstr "较大 (L) --150%" #: shell/shell.ui.h:85 msgid "Please select the clearest sample text" msgstr "选择您看起来最清晰的文本示例" #: shell/shell.ui.h:86 msgid "Restore Defaults" msgstr "恢复默认设置" #: shell/shell.ui.h:87 msgid "Font" msgstr "字体" #: shell/shell.ui.h:88 msgid "Internet" msgstr "互联网" #: shell/shell.ui.h:89 msgid "Web Browser:" msgstr "网络浏览器:" #: shell/shell.ui.h:90 msgid "Mail Reader:" msgstr "邮件阅读器:" #: shell/shell.ui.h:91 msgid "Multimedia" msgstr "多媒体" #: shell/shell.ui.h:92 msgid "Image Viewer:" msgstr "图像查看器:" #: shell/shell.ui.h:93 msgid "Audio Player:" msgstr "音频播放器:" #: shell/shell.ui.h:94 msgid "Video Player:" msgstr "视频播放器:" #: shell/shell.ui.h:95 msgid "System" msgstr "系统" #: shell/shell.ui.h:96 msgid "Text Editor:" msgstr "文本编辑器:" #: shell/shell.ui.h:97 msgid "File Manager:" msgstr "文件管理器:" #: shell/shell.ui.h:98 msgid "Network Connections" msgstr "网络连接" #: shell/shell.ui.h:99 msgid "Repeat Keys" msgstr "按键重复" #: shell/shell.ui.h:100 msgid "Key presses _repeat when key is held down" msgstr "按住某一键时重复该键(R)" #: shell/shell.ui.h:101 msgid "_Delay:" msgstr "延时(D):" #: shell/shell.ui.h:102 msgid "_Speed:" msgstr "速度(S):" #: shell/shell.ui.h:103 msgid "Short" msgstr "短" #: shell/shell.ui.h:104 msgid "Slow" msgstr "慢" #: shell/shell.ui.h:105 msgid "Repeat keys speed" msgstr "按键重复速度" #: shell/shell.ui.h:106 msgid "Long" msgstr "长" #: shell/shell.ui.h:107 msgid "Fast" msgstr "快" #: shell/shell.ui.h:108 msgid "To test the repetition rate of the input character:" msgstr "输入字符来测试重复速度:" #: shell/shell.ui.h:109 msgid "Cursor Blinking" msgstr "光标闪烁" #: shell/shell.ui.h:110 msgid "Cursor _blinks in text fields" msgstr "文本域中的光标会闪烁(B)" #: shell/shell.ui.h:111 msgid "S_peed:" msgstr "速度(P):" #: shell/shell.ui.h:112 msgid "Cursor blinks speed" msgstr "光标闪烁速度" #: shell/shell.ui.h:113 msgid "General" msgstr "通用设置" #: shell/shell.ui.h:114 msgid "" "Please add the language you will use to the list. And the first one in the " "list is the most\n" "commonly used language." msgstr "将要使用的语言添加到此列表中,位于列表第一位的语言为您最常用的语言。" #: shell/shell.ui.h:116 msgid "_Show..." msgstr "显示" #: shell/shell.ui.h:117 msgid "List of keyboard layouts selected for usage" msgstr "选用的键盘布局列表" #: shell/shell.ui.h:118 msgid "_Separate layout for each window" msgstr "每个窗口独立布局(S)" #: shell/shell.ui.h:119 msgid "New windows u_se active window's layout" msgstr "新窗口使用活动窗口的布局(S)" #: shell/shell.ui.h:120 msgid "Reset to De_faults" msgstr "恢复默认配置(_F)" #: shell/shell.ui.h:121 msgid "Layouts" msgstr "布局" #: shell/shell.ui.h:122 msgid "" "\"To edit a shortcut key, click on the corresponding row and type a new key " "\"\n" "\"combination, or press backspace to clear.\"" msgstr "要编辑快捷键,请单击相应的行,然后输入新按键组合,或按退格键清除。" #: shell/shell.ui.h:124 msgid "Shortcut" msgstr "快捷键" #: shell/shell.ui.h:125 msgid "_Right-handed" msgstr "惯用右手" #: shell/shell.ui.h:126 msgid "_Left-handed" msgstr "惯用左手" #: shell/shell.ui.h:127 msgid "Sh_ow position of pointer when the Control key is pressed" msgstr "按住Ctrl键时显示指针位置" #: shell/shell.ui.h:128 msgid "S_ensitivity:" msgstr "灵敏度(E):" #: shell/shell.ui.h:129 msgid "Low" msgstr "低" #: shell/shell.ui.h:130 msgid "High" msgstr "高" #: shell/shell.ui.h:131 msgid "Double-click the right bulb to test your settings" msgstr "双击右侧的灯泡以便测试您的设置" #: shell/shell.ui.h:132 msgid "_Timeout:" msgstr "超时(T):" #: shell/shell.ui.h:133 msgid "Pointer moving speed" msgstr "指针移动速度" #: shell/shell.ui.h:134 msgid "Locate Pointer" msgstr "定位指针" #: shell/shell.ui.h:135 msgid "Mouse Keys" msgstr "鼠标键" #: shell/shell.ui.h:136 msgid "Double-Click Speed" msgstr "双击速度" #: shell/shell.ui.h:137 msgid "Disable _touchpad while typing" msgstr "打字时禁用触摸板(T)" #: shell/shell.ui.h:138 msgid "Enable _mouse clicks with touchpad" msgstr "启用触摸板的鼠标点击(M)" #: shell/shell.ui.h:139 msgid "Scrolling" msgstr "滚动" #: shell/shell.ui.h:140 msgid "_Disabled" msgstr "禁用(_D)" #: shell/shell.ui.h:141 msgid "Vertical _edge scrolling" msgstr "垂直边界滚动(_E)" #: shell/shell.ui.h:142 msgid "_Horizontal edge scrolling" msgstr "水平边界滚动(H)" #: shell/shell.ui.h:143 msgid "_Vertical two-finger scrolling" msgstr "垂直双指滚动(_V)" #: shell/shell.ui.h:144 msgid "Horizontal two-_finger scrolling" msgstr "水平双指滚动(_F)" #: shell/shell.ui.h:145 msgid "Enabled touchpad" msgstr "启用触摸板" #: shell/shell.ui.h:146 msgid "Touchpad" msgstr "触摸板" #: shell/shell.ui.h:147 msgid "Di_rect internet connection" msgstr "直接连接到互联网(_R)" #: shell/shell.ui.h:148 msgid "_Manual proxy configuration" msgstr "手动配置代理(_M)" #: shell/shell.ui.h:149 msgid "H_TTP proxy:" msgstr "H_TTP 代理:" #: shell/shell.ui.h:150 msgid "_Secure HTTP proxy:" msgstr "安全 HTTP 代理(_S):" #: shell/shell.ui.h:151 msgid "_FTP proxy:" msgstr "_FTP 代理:" #: shell/shell.ui.h:152 msgid "S_ocks host:" msgstr "S_ocks 主机:" #: shell/shell.ui.h:153 msgid "Port:" msgstr "端口:" #: shell/shell.ui.h:154 msgid "_Details" msgstr "细节(_D)" #: shell/shell.ui.h:155 msgid "_Automatic proxy configuration" msgstr "自动配置代理(_A)" #: shell/shell.ui.h:156 msgid "Autoconfiguration _URL:" msgstr "自动配置 _URL:" #: shell/shell.ui.h:157 msgid "Proxy Configuration" msgstr "代理服务器配置" #: shell/shell.ui.h:158 msgid "Ignore Host List" msgstr "忽略主机列表" #: shell/shell.ui.h:159 msgid "Ignored Hosts" msgstr "忽略的主机" #: shell/shell.ui.h:160 msgid "Additional startup _programs:" msgstr "额外的启动程序" #: shell/shell.ui.h:161 msgid "name" msgstr "名称" #: shell/shell.ui.h:162 msgid "status" msgstr "状态" #: shell/shell.ui.h:163 msgid "Startup Programs" msgstr "启动程序" #: shell/shell.ui.h:164 msgid "Change display appearance" msgstr "更改显示器外观" #: shell/shell.ui.h:165 msgid "Monitor:" msgstr "显示器:" #: shell/shell.ui.h:166 msgid "Resolution:" msgstr "分辨率:" #: shell/shell.ui.h:167 msgid "Direction:" msgstr "方向:" #: shell/shell.ui.h:168 msgid "Save" msgstr "保存更改" #: shell/shell.ui.h:169 msgid "Same image in all monitors" msgstr "所有显示器显示主屏幕图像" #: shell/shell.ui.h:170 msgid "Set as primary" msgstr "设为主屏" #: shell/shell.ui.h:171 msgid "Open Monitor" msgstr "打开显示器" #: shell/shell.ui.h:172 msgid "Close Monitor" msgstr "关闭显示器" #: shell/shell.ui.h:173 msgid "Computer status" msgstr "更改计算机状态" #: shell/shell.ui.h:174 msgid "AC Power" msgstr "电源供电" #: shell/shell.ui.h:175 msgid "Battery Power" msgstr "电池供电" #: shell/shell.ui.h:176 msgid "Put _computer to sleep when inactive:" msgstr "空闲此时间后将计算机转入睡眠(C):" #: shell/shell.ui.h:177 msgid "Put _monitor to sleep when inactive:" msgstr "空闲此时间后将显示器转入睡眠(M):" #: shell/shell.ui.h:178 msgid "When laptop lid is cl_osed:" msgstr "关闭笔记本电脑上盖时(O):" #: shell/shell.ui.h:179 msgid "Actions" msgstr "操作" #: shell/shell.ui.h:180 msgid "When the power _button is pressed:" msgstr "按下了电源按钮时(B):" #: shell/shell.ui.h:181 msgid "When the sus_pend button is pressed:" msgstr "按下了挂起按钮时(S):" #: shell/shell.ui.h:182 msgid "Icon display" msgstr "图标显示设置" #: shell/shell.ui.h:183 msgid "Only display an icon when a battery is p_resent" msgstr "仅当使用电池时显示图标(R)" #: shell/shell.ui.h:184 msgid "_Always display an icon" msgstr "总是显示图标(A)" #: shell/shell.ui.h:185 msgid "Power Configure" msgstr "电源设置" #: shell/shell.ui.h:186 msgid "Regard the computer as _idle after:" msgstr "于此时间后视计算机空闲(I):" #: shell/shell.ui.h:187 msgid "_Activate screensaver when computer is idle" msgstr "计算机空闲时激活屏幕保护程序(A)" #: shell/shell.ui.h:188 msgid "_Lock screen when screensaver is active" msgstr "屏幕保护程序激活时锁定屏幕(L)" #: shell/shell.ui.h:189 msgid "preview" msgstr "预览" #: shell/shell.ui.h:190 msgid "Screensavers:" msgstr "屏幕保护程序:" #: shell/shell.ui.h:192 msgid "Set display brightness to:" msgstr "设定显示器亮度为(B):" #: shell/shell.ui.h:193 msgid "Screensaver" msgstr "屏幕保护" #: shell/ukui-control-center.c:45 msgid "Show help options" msgstr "显示帮助选项" #: shell/ukui-control-center.c:46 msgid "Go to Time and Date settings page" msgstr "跳转到时间设置页面" #: shell/ukui-control-center.c:47 msgid "Go to Personalization settings page " msgstr "跳转到个性化设置页面" #: shell/ukui-control-center.c:48 msgid "Go to Power Management page" msgstr "跳转到电源管理页面" #: shell/ukui-control-center.c:49 msgid "Go to Sound settings page" msgstr "跳转到声音设置页面" #: shell/ukui-control-center.c:50 msgid "Go to User Account page" msgstr "跳转到用户设置页面" #: shell/ukui-control-center.c:51 msgid "Go to Keyboard settings page" msgstr "跳转到键盘设置界面" #: shell/ukui-control-center.c:52 msgid "Go to Display settings page" msgstr "跳转到显示设置界面" #: shell/ukui-control-center.c:134 msgid "- Page jump" msgstr "- 页面跳转" #: shell/ukui-control-center.c:143 #, c-format msgid "" "%s\n" "Run '%s --help' to see a full list of available command line options.\n" msgstr "" #: shell/ukui-control-center.c:198 msgid "window1" msgstr "" #~ msgid "-Kylin Control Center" #~ msgstr "-麒麟控制面板" #~ msgid "System Check" #~ msgstr "系统检测" #~ msgid "check the system detection information on this computer " #~ msgstr "查看此系统的检测信息" #~ msgid "Personalization_" #~ msgstr " 个性化 " #~ msgid "Autostart_" #~ msgstr " 开机启动 " #~ msgid "Time Dates_" #~ msgstr " 时间和日期" #~ msgid "User Account_" #~ msgstr " 用户账户 " #~ msgid "Keyboard_" #~ msgstr " 键盘 " #~ msgid "Mouse_" #~ msgstr " 鼠标 " #~ msgid "Printer_" #~ msgstr "打印机" #~ msgid "Sound_" #~ msgstr " 声音 " #~ msgid "Network Agent_" #~ msgstr " 网络代理 " #~ msgid "Monitor_" #~ msgstr " 显示器 " #~ msgid "username length should not long than 32!" #~ msgstr "用户名长度不能超过32" #~ msgid "Password length is too short!" #~ msgstr "密码长度太短!" #~ msgid "" #~ "Password length needs to more than 5 digits, and composed of letters, \n" #~ " numbers or special characters." #~ msgstr "密码必须长度必须大于5的字母、数字或特殊字符组成." #~ msgid "Password length is too long!" #~ msgstr "密码长度太长!" #~ msgid "" #~ "Password length needs to less than 64 digits, and composed of letters, \n" #~ " numbers or special characters." #~ msgstr "密码长度必须是小于64位的字母、数字或特殊字符组成." #~ msgid "Password error" #~ msgstr "密码错误" #~ msgid "Please make sure you enter the password two times." #~ msgstr "请确认您两次输入的密码一致." #~ msgid " Dec" #~ msgstr " 十二月" #~ msgid " Sep" #~ msgstr " 九月" #~ msgid "command:" #~ msgstr "命令:" #~ msgid "%d hour" #~ msgid_plural "%d hours" #~ msgstr[0] "%i 小时" #~ msgid "%d minute" #~ msgid_plural "%d minutes" #~ msgstr[0] "%i 分钟" #~ msgid "%d second" #~ msgid_plural "%d seconds" #~ msgstr[0] "%d 秒" #~ msgstr[1] "%d 秒" #~ msgid "Make Default" #~ msgstr "设为默认" #~ msgid "Sp_in down hard disks when possible" #~ msgstr "如果可能,减速硬盘(I)" #~ msgid "Put _display to sleep when inactive:" #~ msgstr "空闲此时间后将显示器转入睡眠(D):" #~ msgid "Di_m display when idle" #~ msgstr "空闲时变暗显示器(M)" #~ msgid "When battery po_wer is critically low:" #~ msgstr "电池电量将用尽时(W):" #~ msgid "_Reduce backlight brightness" #~ msgstr "减小背光亮度(R)" #~ msgid "Notification Area" #~ msgstr "通知区域" #~ msgid "_Never display an icon" #~ msgstr "从不显示图标(N)" #~ msgid "_Only display an icon when battery power is low" #~ msgstr "仅当电池电量即将用尽时显示图标(O)" #~ msgid "Only display an icon when charging or _discharging" #~ msgstr "仅在充电或放电时显示图标(D)" #~ msgid "My Account" #~ msgstr "我的账户" ukui-control-center/po/update-po0000775000175000017500000000515413245450076015666 0ustar fengfeng#!/bin/sh set -e intltool-extract --type=gettext/glade ../shell/shell.ui intltool-extract --type=gettext/glade ../panels/appearance/font_render.ui intltool-extract --type=gettext/glade ../panels/keyboard/ukui-keyboard-properties-layout-chooser.ui intltool-extract --type=gettext/glade ../panels/keyboard/shortcut_dialog.ui intltool-extract --type=gettext/glade ../panels/session-properties/main-table.ui intltool-extract --type=gettext/glade ../panels/session-properties/program_properties.ui #intltool-extract --type=gettext/glade ../panels/ukui-system-info/export_diagnose_info.ui intltool-extract --type=gettext/glade ../panels/network-proxy/network.ui intltool-extract --type=gettext/glade ../panels/user-accounts/change-face.ui intltool-extract --type=gettext/glade ../panels/user-accounts/change-pwd.ui intltool-extract --type=gettext/glade ../panels/user-accounts/delete-user.ui intltool-extract --type=gettext/glade ../panels/user-accounts/change-name.ui intltool-extract --type=gettext/glade ../panels/user-accounts/change-type.ui intltool-extract --type=gettext/glade ../panels/user-accounts/user-create.ui intltool-extract --type=gettext/glade ../panels/power/ukui-fullscreen-preview.ui cd $(dirname $0) PO_DIR=$PWD PROGNAME=$(basename $0) # Create a list of files to scan GETTEXT_FILES=$(mktemp --tmpdir uitk-unity.lst.XXXXX) trap 'rm -f "$GETTEXT_FILES"' EXIT cd .. find \( -name '*.h' -o -name '*.cpp' -o -name '*.c' -o -name '*.ui.h' \) \ -a ! \( -path './debian/*' -o -path './builddir/*' -o -path './build/*' -o -path './.bzr/*' \) | sort \ > $GETTEXT_FILES # Generate pot from our list xgettext \ --output $PO_DIR/ukui-control-center.pot \ --files-from $GETTEXT_FILES \ --qt --c++ \ --language=C \ --keyword=_ \ --keyword=gettext \ --keyword=ngettext \ --keyword=N_ \ --from-code=utf-8 \ --add-comments=TRANSLATORS \ --package-name="ukui-control-center" \ --copyright-holder="Canonical Ltd." echo "$PROGNAME: $PO_DIR/auto-generated.pot updated" sleep 1 rm shell/shell.ui.h rm panels/appearance/font_render.ui.h rm panels/keyboard/ukui-keyboard-properties-layout-chooser.ui.h rm panels/keyboard/shortcut_dialog.ui.h rm panels/session-properties/main-table.ui.h rm panels/session-properties/program_properties.ui.h #rm panels/ukui-system-info/export_diagnose_info.ui.h rm panels/network-proxy/network.ui.h rm panels/user-accounts/change-face.ui.h rm panels/user-accounts/change-pwd.ui.h rm panels/user-accounts/delete-user.ui.h rm panels/user-accounts/change-name.ui.h rm panels/user-accounts/change-type.ui.h rm panels/user-accounts/user-create.ui.h rm panels/power/ukui-fullscreen-preview.ui.h ukui-control-center/README0000664000175000017500000000254413055210571014275 0ustar fengfengUKUI Control Center ==================== About - The control center is UKUI's main interface for configuration of various aspects of your desktop. Installation - See the file 'INSTALL' How to report bugs - Bugs should be reported to the UKUI bug tracking system under github: https://github.com/ukui/ukui-control-center/issues In the report please include the following information - Operating system and version For Linux, version of the C and glib libraries How to reproduce the bug if possible If the bug was a crash, include the exact text that was printed out A stacktrace where possible [see below] How to get a stack trace - If the crash is reproducible, it is possible to get a stack trace and attach it to the bug report. The following steps are used to obtain a stack trace - Run the program in gdb [the GNU debugger] or any other debugger ie. gdb ukui-keyboard-properties Start the program ie. (gdb) run Reproduce the crash and the program will exit to the gdb prompt Get the back trace ie. (gdb) bt full Once you have the backtrace, copy and paste this either into the 'Comments' field or attach a file with it included. Patches - Patches should be submitted to github as pull requests: https://github.com/ukui/ukui-control-center/pulls https://help.github.com/articles/fork-a-repo https://help.github.com/articles/using-pull-requests ukui-control-center/shell/0000775000175000017500000000000013263647163014533 5ustar fengfengukui-control-center/shell/mainwindow.h0000664000175000017500000000532713256625660017067 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __MAINWINDOW_H #define __MAINWINDOW_H #include #include #include #include #include #include #include gboolean dispalyIsOk; GtkBuilder *builder; GtkWindow *window; GtkApplication * app; typedef struct _ButtonData ButtonData; struct _ButtonData { GtkViewport *vp; guint page; gchar *title; }; ButtonData data_time; ButtonData data_count; ButtonData data_theme; ButtonData data_app; ButtonData data_network; ButtonData data_key; ButtonData data_mouse; ButtonData data_printer; ButtonData data_sound; ButtonData data_net; ButtonData data_start; ButtonData data_display; ButtonData data_power; ButtonData data_system; GtkNotebook *notebook1; GtkNotebook *notebook2; GtkButton *bt_startpage; GtkButton *button1; GtkButton *button2; GtkButton *button3; GtkButton *button4; GtkButton *button5; GtkButton *button6; GtkButton *button7; GtkButton *button8; GtkButton *button9; GtkButton *button10; GtkButton *button11; GtkButton *button12; GtkButton *button13; GtkButton *button14; GtkViewport *vp_time; GtkButton *bt_time; GtkViewport *vp_count; GtkButton *bt_count; GtkViewport *vp_theme; GtkButton *bt_theme; GtkViewport *vp_app; GtkButton *bt_app; GtkViewport *vp_network; GtkButton *bt_network; GtkViewport *vp_key; GtkButton *bt_key; GtkViewport *vp_mouse; GtkButton *bt_mouse; GtkViewport *vp_printer; GtkButton *bt_printer; GtkViewport *vp_sound; GtkButton *bt_sound; GtkViewport *vp_net; GtkButton *bt_net; GtkViewport *vp_start; GtkButton *bt_start; GtkViewport *vp_display; GtkButton *bt_display; GtkViewport *vp_power; GtkButton *bt_power; GtkViewport *vp_system; GtkButton *bt_system; gboolean on_all_quit(); void ukui_init(int *argc, char **argv[]); void hide_viewport(); void init_signals(); void set_sidebar_sensitive(); void app_set_theme(const gchar *theme_path); #endif /* __MAINWINDOW_H */ ukui-control-center/shell/mainwindow.c0000664000175000017500000003707113256625660017063 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "mainwindow.h" #include "spy-time.h" //#include "../panels/users/users-account.h" #include "default-app.h" #include "ukui-keyboard-properties.h" #include "appearance-main.h" #include "mouse-setting.h" #include "network-proxy.h" #include "gsp-main.h" #include "xrandr-capplet.h" #include void app_set_theme(const gchar *theme_path) { static GtkCssProvider *provider = NULL; GFile *file; GdkScreen *screen; screen = gdk_screen_get_default(); if(theme_path!=NULL) { file = g_file_new_for_path(theme_path); if(file!=NULL) { if(provider==NULL) provider = gtk_css_provider_new(); gtk_css_provider_load_from_file(provider, file, NULL); gtk_style_context_add_provider_for_screen(screen, GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_USER); gtk_style_context_reset_widgets(screen); } } else { if(provider!=NULL) { gtk_style_context_remove_provider_for_screen(screen, GTK_STYLE_PROVIDER(provider)); g_object_unref(provider); provider = NULL; } gtk_style_context_reset_widgets(screen); } } gboolean on_all_quit(GtkWidget *widget, GdkEvent *event, gpointer user_data) { GtkBuilder * builder = user_data; time_data_destory(); // users_data_destory(); default_app_destory(); destory_keyboard_app(builder); destory_appearance_app(); destory_mouse_app(); destory_network_app(); // destory_ukui_system_info_app(); // bug::g_object_unref: assertion 'G_IS_OBJECT(object)' failed if (builder){ g_object_unref(builder); } g_application_quit(G_APPLICATION(app)); g_object_unref(app); // destory all panels and shell return TRUE; } //在页面跳转时,将侧边栏对应的viewport设置为insensitive,其余设置为sensitive void set_sidebar_sensitive() { gtk_widget_set_sensitive(GTK_WIDGET(vp_theme), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(vp_start), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(vp_app), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(vp_count), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(vp_net), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(vp_power), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(vp_display), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(vp_key), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(vp_mouse), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(vp_sound), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(vp_time), TRUE); } //各个页面之间的切换 void show_next_page(GtkWidget *widget, gpointer userdata) { ButtonData *data = (ButtonData *)userdata; set_sidebar_sensitive (); gtk_widget_set_sensitive(GTK_WIDGET(data->vp), FALSE); gtk_notebook_set_current_page(notebook1, (gint)1); gtk_notebook_set_current_page(notebook2, data->page); gtk_window_set_title(window, data->title); } //从主窗口跳转到对应页面 void switch_page(GtkWidget *widget, gpointer userdata) { ButtonData *data = (ButtonData *)userdata; set_sidebar_sensitive (); gtk_widget_set_sensitive(GTK_WIDGET(data->vp), FALSE); gtk_widget_show(GTK_WIDGET(data->vp)); gtk_notebook_set_current_page(notebook2, data->page); gtk_window_set_title(window, data->title); } void show_mainpage(GtkWidget *widget, gpointer userdata) { gtk_notebook_set_current_page(notebook1, (gint)0); gtk_window_set_title(window, _("Control Center")); } static void direct_call_program(GtkWidget * widget, gchar * program_name){ // in fact, we don't want to use function system(), because this function is dangerous, // always we can use it in shell but not in code, function popen() is safeer.but when we use popen in gtk program // the screen may not always refresh gchar * proname; int systemback; proname= g_strdup_printf("%s &",program_name); systemback = system(proname); if (systemback <0) { g_warning("Call program %s has occurred error\n", program_name); return; } else if (systemback ==0) { g_warning("Call program %s successfully, but no pid return\n", program_name); } else if (systemback == 127) { g_warning("Call program %s has occurred error\n", program_name); } else { g_warning("Successful\n"); } } static void set_button_image(GtkButton * button, gchar * icon_name) { GtkWidget * image; const gchar filename[80]; g_sprintf(filename,"%s/%s.png","/usr/share/ukui-control-center/icons",icon_name); //if (!g_file_test(filename, G_FILE_TEST_EXIST)) image = gtk_image_new_from_file(filename); gtk_button_set_image(GTK_BUTTON(button), image); } void init_signals() { notebook1 = (GtkNotebook *)GTK_WIDGET(gtk_builder_get_object(builder, "notebook1")); notebook2 = (GtkNotebook *)GTK_WIDGET(gtk_builder_get_object(builder, "notebook2")); vp_time = (GtkViewport *)GTK_WIDGET(gtk_builder_get_object(builder, "vp_time")); bt_time = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "bt_time")); data_time.vp = vp_time; data_time.page = 0; data_time.title = _("Time and Dates"); g_signal_connect(G_OBJECT(bt_time), "clicked", G_CALLBACK(switch_page), (gpointer)&data_time); button1 = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "button1")); gtk_widget_set_tooltip_text(GTK_WIDGET(button1), _(" Change the time and date of this computer ")); set_button_image(button1, "日期和时间"); g_signal_connect(G_OBJECT(button1), "clicked", G_CALLBACK(show_next_page), (gpointer)&data_time); vp_count = (GtkViewport *)GTK_WIDGET(gtk_builder_get_object(builder, "vp_count")); bt_count = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "bt_count")); data_count.vp = vp_count; data_count.page = 1; data_count.title = _("User Account"); g_signal_connect(G_OBJECT(bt_count), "clicked", G_CALLBACK(switch_page), (gpointer)&data_count); button2 = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "button2")); gtk_widget_set_tooltip_text(GTK_WIDGET(button2), _(" Change the computer user account \n settings and password")); set_button_image(button2, "用户账号"); g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(show_next_page), (gpointer)&data_count); vp_theme = (GtkViewport *)GTK_WIDGET(gtk_builder_get_object(builder, "vp_theme")); bt_theme = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "bt_theme")); data_theme.vp = vp_theme; data_theme.page = 2; data_theme.title = _("Personalization"); g_signal_connect(G_OBJECT(bt_theme), "clicked", G_CALLBACK(switch_page), (gpointer)&data_theme); button3 = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "button3")); gtk_widget_set_tooltip_text(GTK_WIDGET(button3), _(" Change the computer desktop background \n and related theme")); set_button_image(button3, "个性化"); g_signal_connect(G_OBJECT(button3), "clicked", G_CALLBACK(show_next_page), (gpointer)&data_theme); vp_app = (GtkViewport *)GTK_WIDGET(gtk_builder_get_object(builder, "vp_app")); bt_app = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "bt_app")); data_app.vp = vp_app; data_app.page = 3; data_app.title = _("Default Application"); g_signal_connect(G_OBJECT(bt_app), "clicked", G_CALLBACK(switch_page), (gpointer)&data_app); button4 = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "button4")); gtk_widget_set_tooltip_text(GTK_WIDGET(button4), _(" Change the default application on this computer ")); set_button_image(button4, "默认应用程序"); g_signal_connect(G_OBJECT(button4), "clicked", G_CALLBACK(show_next_page), (gpointer)&data_app); vp_network = (GtkViewport *)GTK_WIDGET(gtk_builder_get_object(builder, "vp_network")); //隐藏网络连接的选项按钮 bt_network = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "bt_connection")); //gtk_widget_hide(GTK_WIDGET(vp_network)); gtk_widget_hide(GTK_WIDGET(bt_network)); /*data_network.vp = vp_network; data_network.page = 4; data_network.title =_( "网络连接"); g_signal_connect(G_OBJECT(bt_network), "clicked", G_CALLBACK(switch_page), (gpointer)&data_network);*/ button5 = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "button5")); //g_signal_connect(G_OBJECT(button5), "clicked", G_CALLBACK(show_next_page), (gpointer)&data_network); gtk_widget_set_tooltip_text(GTK_WIDGET(button5), _(" Change the network on this computer ")); set_button_image(button5, "网络连接"); g_signal_connect(G_OBJECT(button5),"clicked", G_CALLBACK(direct_call_program),"nm-connection-editor"); vp_key = (GtkViewport *)GTK_WIDGET(gtk_builder_get_object(builder, "vp_key")); bt_key = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "bt_key")); data_key.vp = vp_key; data_key.page = 5; data_key.title = _("Keyboard"); g_signal_connect(G_OBJECT(bt_key), "clicked", G_CALLBACK(switch_page), (gpointer)&data_key); button6 = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "button6")); gtk_widget_set_tooltip_text(GTK_WIDGET(button6), _(" Change the keyboard settings on this computer ")); set_button_image(button6, "键盘"); g_signal_connect(G_OBJECT(button6), "clicked", G_CALLBACK(show_next_page), (gpointer)&data_key); vp_mouse = (GtkViewport *)GTK_WIDGET(gtk_builder_get_object(builder, "vp_mouse")); bt_mouse = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "bt_mouse")); data_mouse.vp = vp_mouse; data_mouse.page = 6; data_mouse.title =_("Mouse"); g_signal_connect(G_OBJECT(bt_mouse), "clicked", G_CALLBACK(switch_page), (gpointer)&data_mouse); button7 = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "button7")); gtk_widget_set_tooltip_text(GTK_WIDGET(button7), _(" Change the mouse settings on this computer ")); set_button_image(button7, "鼠标"); g_signal_connect(G_OBJECT(button7), "clicked", G_CALLBACK(show_next_page), (gpointer)&data_mouse); vp_printer = (GtkViewport *)GTK_WIDGET(gtk_builder_get_object(builder, "vp_printer")); bt_printer = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "bt_printer")); gtk_widget_hide(GTK_WIDGET(vp_printer)); gtk_widget_hide(GTK_WIDGET(bt_printer)); data_printer.vp = vp_printer; data_printer.page = 7; data_printer.title = "打印机"; button8 = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "button8")); set_button_image(button8, "打印机"); gtk_widget_set_tooltip_text(GTK_WIDGET(button8), _(" Configure the connection to the computer printer ")); // g_signal_connect(G_OBJECT(button8), "clicked", G_CALLBACK(direct_call_program),"system-config-printer"); // g_signal_connect(G_OBJECT(button8), "clicked", G_CALLBACK(show_next_page), (gpointer)&data_printer); g_signal_connect(G_OBJECT(button8), "clicked", G_CALLBACK(direct_call_program),"system-config-printer"); vp_sound = (GtkViewport *)GTK_WIDGET(gtk_builder_get_object(builder, "vp_sound")); bt_sound = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "bt_sound")); data_sound.vp = vp_sound; data_sound.page = 8; data_sound.title = _("Sound"); g_signal_connect(G_OBJECT(bt_sound), "clicked", G_CALLBACK(switch_page), (gpointer)&data_sound); button9 = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "button9")); gtk_widget_set_tooltip_text(GTK_WIDGET(button9), _(" Change the sound settings on this computer ")); set_button_image(button9, "声音"); g_signal_connect(G_OBJECT(button9), "clicked", G_CALLBACK(show_next_page), (gpointer)&data_sound); vp_net = (GtkViewport *)GTK_WIDGET(gtk_builder_get_object(builder, "vp_net")); bt_net = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "bt_net")); data_net.vp = vp_net; data_net.page = 9; data_net.title = _("Network Agent"); g_signal_connect(G_OBJECT(bt_net), "clicked", G_CALLBACK(switch_page), (gpointer)&data_net); button10 = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "button10")); gtk_widget_set_tooltip_text(GTK_WIDGET(button10), _(" Change the network agent on this computer ")); set_button_image(button10, "网络代理"); g_signal_connect(G_OBJECT(button10), "clicked", G_CALLBACK(show_next_page), (gpointer)&data_net); vp_start = (GtkViewport *)GTK_WIDGET(gtk_builder_get_object(builder, "vp_start")); bt_start = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "bt_start")); data_start.vp = vp_start; data_start.page = 10; data_start.title = _("Autostart"); g_signal_connect(G_OBJECT(bt_start), "clicked", G_CALLBACK(switch_page), (gpointer)&data_start); button11 = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "button11")); gtk_widget_set_tooltip_text(GTK_WIDGET(button11), _(" Change the autostart program on this computer ")); set_button_image(button11, "开机启动"); g_signal_connect(G_OBJECT(button11), "clicked", G_CALLBACK(show_next_page), (gpointer)&data_start); vp_display = (GtkViewport *)GTK_WIDGET(gtk_builder_get_object(builder, "vp_display")); bt_display = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "bt_display")); data_display.vp = vp_display; data_display.page = 11; data_display.title = _("Monitor"); button12 = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "button12")); gtk_widget_set_tooltip_text(GTK_WIDGET(button12), _(" Change the Monitor settings on this computer ")); set_button_image(button12, "显示器"); if(dispalyIsOk) { g_signal_connect(G_OBJECT(button12), "clicked", G_CALLBACK(show_next_page), (gpointer)&data_display); g_signal_connect(G_OBJECT(bt_display), "clicked", G_CALLBACK(switch_page), (gpointer)&data_display); } vp_power = (GtkViewport *)GTK_WIDGET(gtk_builder_get_object(builder, "vp_power")); bt_power = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "bt_power")); data_power.vp = vp_power; data_power.page = 12; data_power.title = _("Power Management"); g_signal_connect(G_OBJECT(bt_power), "clicked", G_CALLBACK(switch_page), (gpointer)&data_power); button13 = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "button13")); gtk_widget_set_tooltip_text(GTK_WIDGET(button13), _(" Change the power management settings on this computer ")); set_button_image(button13, "电源管理"); g_signal_connect(G_OBJECT(button13), "clicked", G_CALLBACK(show_next_page), (gpointer)&data_power); bt_startpage = (GtkButton *)GTK_WIDGET(gtk_builder_get_object(builder, "bt_startpage")); g_signal_connect(G_OBJECT(bt_startpage), "clicked", G_CALLBACK(show_mainpage), NULL); } ukui-control-center/shell/ukui-control-center.desktop0000775000175000017500000000053313253611037022031 0ustar fengfeng[Desktop Entry] Name=Control Center Name[zh_CN]=控制面板 Name[zh_HK]=控制面板 Name[zh_TW]=控制面板 Comment=麒麟控制面板 Icon=applications-system Exec=ukui-control-center Terminal=false Type=Application StartupNotify=true NoDisplay=true Categories=GTK;Settings; Keywords=UKUI;control;center;configuration;tool;destop;preferences; ukui-control-center/shell/Makefile.am0000664000175000017500000000317213256625660016572 0ustar fengfengAM_CPPFLAGS = \ -DUIDIR="\"$(uidir)\"" \ -I$(top_builddir)/panels/time-data \ -I$(top_builddir)/panels/user-accounts \ -I$(top_builddir)/panels/appearance \ -I$(top_builddir)/panels/default-app \ -I$(top_builddir)/panels/keyboard \ -I$(top_builddir)/panels/mouse \ -I$(top_builddir)/panels/network-proxy \ -I$(top_builddir)/panels/session-properties \ -I$(top_builddir)/panels/display \ -I$(top_builddir)/panels/power \ -I$(top_builddir)/panels/volume-control \ @PACKAGE_CFLAGS@ bin_PROGRAMS = ukui-control-center ukui_control_center_SOURCES = \ ukui-control-center.c \ mainwindow.c \ mainwindow.h ukui_control_center_LDADD = \ @PACKAGE_LIBS@ \ $(top_builddir)/panels/time-data/libtime.la \ $(top_builddir)/panels/user-accounts/libuser-accounts.la \ $(top_builddir)/panels/appearance/libappearance.la \ $(top_builddir)/panels/default-app/libdefaultapp.la \ $(top_builddir)/panels/keyboard/libkeyboard.la \ $(top_builddir)/panels/mouse/libmouseapp.la \ $(top_builddir)/panels/network-proxy/libnetworkproxy.la \ $(top_builddir)/panels/session-properties/libsessionproperties.la \ $(top_builddir)/panels/display/libdisplayapp.la \ $(top_builddir)/panels/power/libpower.la \ $(top_builddir)/panels/volume-control/libvolume.la \ -lm ukui_control_center_LDFLAGS = -export-dynamic @PACKAGE_LDFLAGS@ uidir = $(pkgdatadir)/ui ui_DATA = shell.ui \ ukcc.css desktopdir=$(datadir)/applications desktop_DATA=ukui-control-center.desktop EXTRA_DIST = \ $(ui_DATA) clean-local : rm -f *~ Makefile.in Makefile ukui-control-center/shell/shell.ui0000644000175000017500000161351713263623274016212 0ustar fengfeng 100 1 10 1 120 10 1 10 100 1 10 10 2000 300 10 10 1 100000 1 1 10 1 100000 1 1 10 65535 1 10 65535 1 10 65535 1 10 65535 1 10 500 0.5 10 10 900 0.5 10 10 3000 1800 10 10 100 2000 500 10 10 100 2500 1000 200 200 10 110 30 10 10 Normal Left Right Upside-down 100 1000 400 100 100 1 10 6 1 1 1 10 1 1 1 23 1 10 59 1 10 59 1 10 Tile Zoom Center Scale Stretch Span 990 650 True True True True True True Control Center False center applications-system True True True True True True True False True False vertical 200 True True True 165 True False vertical 150 True False 108 True False 30 start Personalization 100 108 True True False True none top False False 0 Autostart 100 108 True True False True none top False False 1 Default Application 100 108 True True False True none top False False 2 Time Dates 100 108 True True False True none top True True 3 User Account 100 108 True True False True none top False False 4 30 10 False True 0 940 35 True False 130 True False System Configuration 8 8 False True 0 True False 17 17 True True 1 True True 0 360 True True True True False vertical 150 True False 108 True False 30 True start Printer 100 108 True True False True none top False False 0 Power Management 100 108 True True False True none top False False 1 Keyboard 100 108 True True False True none top False False 2 Sound 100 108 True True False True none top False False 3 Mouse 100 108 True True False True none top False False 4 Monitor 100 108 True True False True none top False False 5 30 10 True True 0 180 True False 108 True False 30 True start Network Agent 100 108 True True False True none top False False 0 Network Connections 100 108 True True False True none top True True 1 30 10 True True 1 940 35 True False 130 True False Hardware Configure 8 False True 0 True False 17 17 True True 1 True True 1 True False 4 viewport11 200 True False none 200 True False vertical 35 True True False True True 5 none True False True False 16 go-previous False False 0 True False start 29 Home 11 True True 1 False False 0 True True True 5 True False 6 vertical True False none 40 True True False True baseline none True True False start 50 _Personalization True True True 0 True False none 40 True True False True none True True False start 50 _Autostart True True True 1 True False none 40 True True False True none True True False start 47 _Default APP True True True 2 True False none 40 True True False True none True True False start 50 _Time Dates True True True 3 True False none 40 True True False True none True True False start 50 _User Account True True True 4 True False 40 System Configuration False False 13 1 True True True 5 True False 5 vertical True False none 40 True True False True True none True True False start 50 Network _Connection True True True end 0 True False none 40 True True False True none True True False start 50 _Keyboard True True True 1 True False none 40 True True False True none True True False start 50 M_ouse True True True 2 True False none 40 True True False True True none True True False start 50 P_rinter True True True 3 True False none 40 True True False True none True True False start 50 _Sound True True True 4 True False none 40 True True False True none True True False start 50 _Network Agent True True True 5 True False none 40 True True False True none True True False start 50 _Monitor True True True 6 True False none 40 True True False True none True True False start 47 Po_wer Manage True True True 7 True False 40 Hardware Configure False True 13 2 False True 0 538 True True left False False True True 700 570 True False none True False 50 30 True False none True False Tzone: 5 65 50 30 True False none True False date: start 0 0 5 205 50 30 True False none True False time: 5 160 430 280 True False etched-in True False vertical 5 50 True False start 30 37 True True True True False gtk-go-back-ltr 98 10 30 37 True True True True False gtk-go-forward-ltr 287 10 75 37 True False end 132 10 75 37 True False baseline baseline immediate Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec 210 10 False True 0 True True 2015 6 14 False 8 8 True True 1 80 220 400 30 True False 80 65 40 30 True True False False time_and_date_hours True True True 80 160 40 30 True True False False time_and_date_minutes True True True 223 160 40 30 True True 2 False False time_and_date_seconds True True True 366 160 30 30 True False hour 194 162 30 30 True False min 336 162 30 30 True False sec 478 162 With the network time synchronization 280 30 True True False True 80 22 280 30 True False because the ntp is installed,please use ntpdate. 80 50 30 True False none True False format: 5 115 12-hours 100 30 True True False True True 80 115 24-hours 100 30 True True False True True radiobutton12 220 115 20 25 True False 720 500 True True never in True False none True False vertical 5 31 True False 100 True False Current Account False True 0 580 True False 5 15 15 False False 1 False False 0 90 True False vertical False False 1 31 True False True 100 True False Other Accounts False True 0 580 True False 5 15 15 False False 1 False False 2 other_users True False vertical 5 True True 3 20 25 160 35 True False none 113 33 True True False True none True False True False 16 add True True 0 True False Create a new account True True 1 22 543 1 True False 720 570 True True True False 200 33 True False none True False 10 True Add True True True True True 0 delete True True True True True 1 490 430 680 380 True False True True True True 0 browse 3 3 10 20 230 33 True False none True False True True False Style: True True 0 True False wp_style_liststore 0 True True 1 6 430 100 30 True False wallpaper False True False 555 180 True False vertical True False Select the one you love color as the theme color False False 0 True False 169 True True True 0 0 True True True 1 0 True True True 2 0 True True True 3 0 True True True 4 0 True True True 5 0 True True True 6 0 169 True True True 7 0 False True 1 15 25 1 100 30 True False Theme color 1 False True False vertical 16 200 True False vertical True False 230 30 True False none True False True False Font choice: False False 0 True False True True 1 10 25 True True 0 30 True False 250 80 True False none True False True False Font size : False False 0 True False vertical 3 small(S) --100%(default) True True False True True True True 0 medium(M)--125% True True False True True small_radio_button True True 1 large (L) --150% True True False True True small_radio_button True True 2 True True 1 10 True True 1 False False 0 True False vertical 10 True False Please select the clearest sample text False False 0 True False font_grid 205 True False 10 10 True True True False none True True True none True False True False 0 0 True False none True True True none True False True False 2 0 True False none True True True none True False True False 1 0 True False none True True True none True False True False 0 1 False False 1 False True 1 True False start Restore Defaults True True True False False 0 False False end 2 2 100 30 True False Font 2 False 20 25 2 True False 700 570 True False none True False default_app_scroll_window 700 505 True True never 480 True False none 480 True False vertical 12 40 True False 5 40 True False Internet False True 0 True False 10 20 20 True True 1 True False 0 True False 105 True False end Web Browser: False False 0 350 35 True False False True 1 False True 1 True False 105 True False end Mail Reader: False True 0 350 35 True False False True 1 False True 2 40 True False 5 40 True False Multimedia False True 0 True False 10 20 20 True True 1 True False 3 True False 105 True False start Image Viewer: False True 0 350 35 True False False True 1 False True 4 True False 105 True False end Audio Player: False True 0 350 35 True False False True 1 False True 5 True False 105 True False end Video Player: False True 0 350 35 True False False True 1 False True 6 40 True False 5 40 True False System False True 0 True False 10 20 20 True True 1 True False 7 True False 105 True False end Text Editor: False True 0 350 35 True False False True 1 False True 8 True False 105 True False end File Manager: False True 0 350 35 True False False True 1 False True 9 5 20 25 3 True False 661 536 True False Network Connections True True True 4 True False 720 570 True True True False 12 vertical 18 True False vertical 10 21 True False 10 True False Repeat Keys False True 0 True False 10 10 True True 1 False False 0 True False True False False False 0 True False vertical 15 Key presses _repeat when key is held down True True False start True True False False 0 True False 6 True False vertical 20 True False _Delay: True center True True 0 True False _Speed: True center True True 1 False False 0 True False vertical 18 True False Short True True 0 True False Slow True True 1 False False 1 True False vertical 20 240 28 True True keyboard_delay_ad False -1 False True True 0 240 28 True True keyboard_peace_ad False Repeat keys speed True True 1 False True 2 True False vertical 18 True False Long True True 0 True False Fast True True 1 False False 3 False True 1 True True 1 True True 5 1 153 33 True False start To test the repetition rate of the input character: True True 10 2 True False 0 0.40000000596046448 122 33 True True False False True True 3 False True 0 True False vertical 20 21 True False 10 True False Cursor Blinking False False 0 True False 10 10 True True 1 False False 0 True False True False False False 0 True False vertical 20 Cursor _blinks in text fields True True False start True True False False 0 True False 12 True False S_peed: True center False False 0 True False 6 True False Fast False False 0 240 28 True True keyboard_light_s_ad False Cursor blinks speed True True 1 True False Slow False False 2 False True 1 True True 1 True True 1 True True 1 False False 30 1 100 30 True False General center False True False 12 vertical 12 True False vertical 6 True False start Please add the language you will use to the list. And the first one in the list is the most commonly used language. False False 0 350 True False 6 True gtk-add True True True True True True 0 gtk-remove True True True True True True 1 gtk-go-up True True True True True True 2 gtk-go-down True True True True True True 3 _Show... True True True True True True 4 False False 1 True True in True True List of keyboard layouts selected for usage False True True 2 _Separate layout for each window True True False start True True False False 3 New windows u_se active window's layout True True False start True True False False 4 True True 0 True False 6 end Reset to De_faults True True True True False False end 0 False False 1 1 100 30 True False Layouts 1 False True False vertical 2 True False end gtk-add True True True False True False False 0 gtk-remove True False True True False True False False 1 False True end 0 True False 5 vertical 12 True False 5 vertical 6 True False 6 12 True False start "To edit a shortcut key, click on the corresponding row and type a new key " "combination, or press backspace to clear." fill True True 0 False True 0 True True never never in shortcut_treeview True True False True True True 1 True True 0 True True 1 2 100 30 True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK Shortcut 2 False 20 25 5 True False 720 570 True True True False 318 60 True False none True False vertical _Right-handed True True False True True True True True 0 _Left-handed True True False True True True right_hand True True 1 30 40 Sh_ow position of pointer when the Control key is pressed 543 28 True True False True True 30 160 370 33 True False none True False 28 True False _Speed: True True True 0 28 True False Slow True True 1 240 28 True True mouse_move_s_ad False right True True 2 1 28 True False Fast True True 3 30 255 370 33 True False none True False 28 True False S_ensitivity: True True True 0 28 True False Low True True 1 240 28 True True mouse_sens_ad False right True True 2 1 28 True False High True True 3 30 295 208 33 True False Double-click the right bulb to test your settings 30 395 374 33 True False none True False 28 True False _Timeout: True False True 0 1 28 True False Short True True 1 240 28 True True mouse_douclick_ad False right True True 2 1 28 True False Long True True 3 30 434 100 100 True False False 65 65 True False gtk-missing-image 67 445 398 650 33 True False 10 33 True False Pointer moving speed False True 0 True False 16 16 True True 1 17 220 650 33 True False 10 33 True False Locate Pointer False True 0 True False 16 16 True True 1 17 120 650 33 True False 10 33 True False Mouse Keys False True 0 True False 16 16 True True 1 17 6 650 33 True False 10 33 True False Double-Click Speed False True 0 True False 16 16 True True 1 17 365 100 30 True False General False True False 33 True False General 17 42 Disable _touchpad while typing 543 28 True True False True True 30 90 Enable _mouse clicks with touchpad 543 28 True True False True True 30 123 33 True False Scrolling 17 156 420 140 True False none True False vertical _Disabled True True False True True True True True 0 Vertical _edge scrolling True True False True True True scroll_disabled_radio True True 1 _Horizontal edge scrolling True True False True True True scroll_disabled_radio True True 2 _Vertical two-finger scrolling True True False True True True scroll_disabled_radio True True 3 Horizontal two-_finger scrolling True True False True True True scroll_disabled_radio True True 4 30 199 Enabled touchpad 400 30 True True False True 30 15 1 100 30 True False Touchpad 1 False 20 25 6 True False 661 536 True False Printer True True True 7 True False 720 570 True False none 20 25 8 True False 720 570 True False 1 none True True True False 8 vertical 18 True True False True True True True False <b>Di_rect internet connection</b> True True False False 10 0 True False vertical 18 True False vertical 6 True True False True True none_radiobutton True False <b>_Manual proxy configuration</b> True True False False 0 True False False True False False False 0 True False 12 20 True False H_TTP proxy: True 0 0 True False _Secure HTTP proxy: True 0 1 True False _FTP proxy: True 0 2 True False S_ocks host: True 0 3 True True False False 1 0 True True False False 1 1 True True False False 1 2 True True False False 1 3 True False Port: 2 0 True False Port: 2 1 True False Port: 2 2 True False Port: 2 3 True True False False adjustment16 1 3 0 True True False False adjustment17 1 3 1 True True False False adjustment18 1 3 2 True True False False adjustment19 1 3 3 _Details True True False True 5 0 True True 1 True True 10 2 True True 0 True False vertical 6 True True False True True none_radiobutton True False <b>_Automatic proxy configuration</b> True True False False 0 True False True False False False 0 True False False 12 True False Autoconfiguration _URL: True False False 0 450 True True False False False False 1 True True 1 True True 10 1 False False 1 False True 1 100 30 True False Proxy Configuration False True False 8 vertical 6 True False 600 Ignore Host List False False 10 0 True False True False 10 17 520 True True True 0 False False 0 0 gtk-add True True False True 1 0 True False 0 0 0 True False gtk-remove True True False True True True 0 1 1 350 True True False 0 1 False False 1 True True 1 1 100 30 True False Ignored Hosts 1 False 20 25 9 True False 700 570 True True False False True False 6 vertical 15 True False Additional startup _programs: True False True 0 True False vertical 15 25 True False 6 start gtk-add 80 True True True True False False 0 gtk-remove True False True True True False False 1 gtk-properties 28 True False True True True False False 430 2 True False False 0 True False out True False vertical hbox_title 35 True False True False name 0.05000000074505806 True True 0 True False status 0.10000000149011612 True True 1 False True 0 True True 1 never True True True True 1 True True 1 True True 1 True False Startup Programs False 20 25 10 True False 720 570 True False none True False display_alignment 500 200 True False 15 45 200 30 True False Change display appearance 15 8 70 30 True False Monitor: 15 300 70 30 True False Resolution: 15 340 70 30 True False Direction: 15 380 200 30 True False 105 300 200 30 True False 105 340 200 30 True False 105 380 Save 100 30 True True True 15 510 Same image in all monitors 200 30 True True False True 15 420 Set as primary 180 30 True True True 15 460 240 30 True False 100 30 True False bottom Open Monitor 120 30 True True False True radiobutton_display_off True True 0 Close Monitor 120 30 True True False True radiobutton_display_on True True 1 15 260 20 25 11 True False 720 570 True True True True False 670 33 True False True False Computer status False True 0 570 True False 10 16 16 False True 1 17 15 100 35 True True False True False gtk-missing-image True True 0 True False AC Power True True 1 285 40 100 35 True False True False gtk-missing-image True True 0 True False Battery Power True True 1 465 40 256 120 True False vertical 10 35 True False Put _computer to sleep when inactive: True False False 0 35 True False Put _monitor to sleep when inactive: True False False 1 35 True False When laptop lid is cl_osed: True False False 2 29 80 150 120 True False vertical 10 35 True False False False 0 35 True False False False 1 35 True False False False 2 260 80 150 120 True False vertical 10 35 True False False False 0 35 True False False False 1 35 True False False False 2 445 80 700 145 True False 670 33 True False True False Actions False True 0 620 True False 10 16 16 False True 1 17 272 85 True False vertical 10 True False When the power _button is pressed: True True True 0 True False True When the sus_pend button is pressed: True True True 1 29 40 150 85 True False vertical 10 True False True True 0 True False True True True 1 260 40 220 700 141 True False 670 33 True False True False Icon display False True 0 570 True False 10 16 16 False True 1 17 Only display an icon when a battery is p_resent 400 33 True True False True True True 29 40 _Always display an icon 400 33 True True False True True radiobutton_notification_present 29 75 365 100 30 True False Power Configure False True False 220 30 True False Regard the computer as _idle after: True 25 355 350 39 True True True adjustment-screensaver 0 0 False 240 350 _Activate screensaver when computer is idle 500 30 True True False True True 25 445 _Lock screen when screensaver is active 500 30 True True False True True 25 480 250 35 True False 120 285 preview 80 35 True True True 380 285 100 35 True False Screensavers: 25 285 90 30 True False label 600 355 335 215 True False 300 200 True False GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK | GDK_VISIBILITY_NOTIFY_MASK 170 35 100 30 True False 215 30 True False start Set display brightness to: False True 0 350 30 True True adjustment1 0 False right False True 1 90 30 True False start label False True 2 25 392 1 100 30 True False Screensaver 1 False 20 25 13 True True 1 1 False ukui-control-center/shell/ukui-control-center.c0000664000175000017500000002064113256625660020613 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "mainwindow.h" #include "spy-time.h" #include "user-accounts.h" #include "default-app.h" #include "ukui-keyboard-properties.h" #include "appearance-main.h" #include "mouse-setting.h" #include "network-proxy.h" #include "gsp-main.h" #include "xrandr-capplet.h" #include "kpm-prefs-core.h" #include "dialog-main.h" #include #include static gboolean switch_to_timeanddata_page = FALSE; static gboolean switch_to_appearance_page = FALSE; static gboolean switch_to_sound_page = FALSE; static gboolean switch_to_power_page = FALSE; static gboolean switch_to_user_page = FALSE; static gboolean switch_to_keyboard_page = FALSE; static gboolean switch_to_display_page = FALSE; static gboolean show_help = FALSE; const GOptionEntry cap_options[] = { {"help", 'h', 0, G_OPTION_ARG_NONE, &show_help, N_("Show help options"), NULL}, {"time", 't', 0, G_OPTION_ARG_NONE, &switch_to_timeanddata_page, N_("Go to Time and Date settings page"), NULL}, {"appearance", 'a', 0, G_OPTION_ARG_NONE, &switch_to_appearance_page, N_("Go to Personalization settings page "), NULL}, {"power", 'p', 0, G_OPTION_ARG_NONE, &switch_to_power_page, N_("Go to Power Management page"), NULL}, {"sound", 's', 0, G_OPTION_ARG_NONE, &switch_to_sound_page, N_("Go to Sound settings page"), NULL}, {"user", 'u', 0, G_OPTION_ARG_NONE, &switch_to_user_page, N_("Go to User Account page"), NULL}, {"keyboard", 'k', 0, G_OPTION_ARG_NONE, &switch_to_keyboard_page, N_("Go to Keyboard settings page"), NULL}, {"display", 'd', 0, G_OPTION_ARG_NONE, &switch_to_display_page, N_("Go to Display settings page"), NULL}, {NULL} }; //带参数命令行(第一个窗口或者后续打开的窗口)的页面跳转 void switch_options_page() { //每次重置为FALSE是为了防止打开第二个窗口时会出现多个TRUE gtk_notebook_set_current_page(notebook1, 1); set_sidebar_sensitive(); if(switch_to_appearance_page){ gtk_notebook_set_current_page(notebook2, 2); gtk_window_set_title(GTK_WINDOW(window), data_theme.title); gtk_widget_set_sensitive(GTK_WIDGET(vp_app), FALSE); switch_to_appearance_page = FALSE; }else if(switch_to_timeanddata_page){ gtk_notebook_set_current_page(notebook2, 0); gtk_window_set_title(GTK_WINDOW(window), data_time.title); gtk_widget_set_sensitive(GTK_WIDGET(vp_time), FALSE); switch_to_timeanddata_page = FALSE; }else if(switch_to_display_page){ gtk_notebook_set_current_page(notebook2, 11); gtk_window_set_title(GTK_WINDOW(window), data_display.title); gtk_widget_set_sensitive(GTK_WIDGET(vp_display), FALSE); switch_to_display_page = FALSE; }else if(switch_to_keyboard_page){ gtk_notebook_set_current_page(notebook2, 5); gtk_window_set_title(GTK_WINDOW(window), data_key.title); gtk_widget_set_sensitive(GTK_WIDGET(vp_key), FALSE); switch_to_keyboard_page = FALSE; }else if(switch_to_power_page){ gtk_notebook_set_current_page(notebook2, 12); gtk_window_set_title(GTK_WINDOW(window), data_power.title); gtk_widget_set_sensitive(GTK_WIDGET(vp_power), FALSE); switch_to_power_page = FALSE; }else if(switch_to_sound_page){ gtk_notebook_set_current_page(notebook2, 8); gtk_window_set_title(GTK_WINDOW(window), data_sound.title); gtk_widget_set_sensitive(GTK_WIDGET(vp_sound), FALSE); switch_to_sound_page = FALSE; }else if(switch_to_user_page){ gtk_notebook_set_current_page(notebook2, 1); gtk_window_set_title(GTK_WINDOW(window), data_count.title); gtk_widget_set_sensitive(GTK_WIDGET(vp_count), FALSE); switch_to_user_page = FALSE; }else{ //无参数时回到主界面 gtk_notebook_set_current_page(notebook1, 0); } } //初始化窗口的部件 void init_mainwindow() { add_time_and_data_app(builder); init_user_accounts(); add_appearance_app(builder); add_default_app(builder); add_keyboard_app(builder); add_mouse_app(builder); add_network_app(builder); add_gsp_app(builder); if(0==add_display_app(builder)) dispalyIsOk = FALSE; else dispalyIsOk = TRUE; add_volume_control_app(builder); init_power(); } //每次命令行启动时都会激活这个回调 static int command_line (GApplication *application, GApplicationCommandLine *cmdline) { int argc; char **argv; GOptionContext *context; GError *error = NULL; argv = g_application_command_line_get_arguments (cmdline, &argc); context = g_option_context_new(_("- Page jump")); g_option_context_add_main_entries(context, cap_options, "ukui-control-center"); g_option_context_set_translation_domain(context, "ukui-control-center"); g_option_context_add_group(context, gtk_get_option_group(TRUE)); //禁用默认的命令行help,手动添加了一个help选项,防止打开多个控制面板时前一个会退出 g_option_context_set_help_enabled(context, FALSE); if (context){ if (!g_option_context_parse(context, &argc, &argv, &error)){ g_warning(_("%s\nRun '%s --help' to see a full list of available command line options.\n"), error->message, argv[0]); g_error_free(error); g_option_context_free(context); return 1; } } //执行help选项时,显示命令行帮助 if(show_help){ gchar *help; GOptionGroup *group = NULL; //不显示默认的GTK+选项 help = g_option_context_get_help(context, TRUE, group); g_print("%s", help); g_free(help); g_option_context_free(context); return 0; } GList *list; //打开第二个窗口时进行判断,若存在窗口,激活当前的窗口 list = gtk_application_get_windows(GTK_APPLICATION(application)); if(list){ gtk_widget_grab_focus(GTK_WIDGET(window)); gtk_window_present(GTK_WINDOW(window)); }else{ init_mainwindow(); gtk_window_set_application(window, app); gtk_widget_show_all(GTK_WIDGET(window));//如果放到init_aignals后面会导致开始菜单弹出面板时开始菜单不隐藏 init_signals(); g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(on_all_quit), builder); } switch_options_page(); g_strfreev (argv); return 0; } int main(int argc, char * argv[]) { setlocale(LC_ALL,""); bindtextdomain ("ukui-control-center", "/usr/share/locale"); //告诉gettext最终的生成的翻译文件mo的位置 bind_textdomain_codeset("ukui-control-center","UTF-8"); //指定域消息条目(mo)中消息的字符编码 textdomain("ukui-control-center"); //设定翻译环境,即指定使用gettext的翻译。 gtk_init(&argc, &argv); GError *err = NULL; //加载css app_set_theme(UIDIR "/ukcc.css"); builder = gtk_builder_new(); gtk_builder_add_from_file(builder, UIDIR "/shell.ui", &err); if (err){ g_warning ("Could not load user interface file: %s", err->message); g_error_free (err); } window = GTK_WINDOW(gtk_builder_get_object(builder, _("window1"))); gtk_widget_set_name(GTK_WIDGET(window), "ukuicc"); app = gtk_application_new ("org.gtk.ukcc", G_APPLICATION_HANDLES_COMMAND_LINE); g_application_register(G_APPLICATION(app), NULL, NULL); g_signal_connect (app, "command-line", G_CALLBACK(command_line), NULL); int status = g_application_run(G_APPLICATION(app), argc, argv); return status; } ukui-control-center/shell/ukcc.css0000644000175000017500000000156113263623274016170 0ustar fengfeng#delete_user_action_area button { color: red; background-color: red; } #user_action_hbox button { color: blue; } #hbox_title label { background-color: #f0f0f0; } #shortcut_treeview header button { background-color: #f0f0f0; } dialog entry { color: #999999; } dialog entry:focus { color: #000000; } #viewport11 { background-color: #f0f0f0; /* viewport>button that is selected will be disabled in UKCC */ } #viewport11 button { color: blue; } #viewport11 viewport:disabled button:disabled { background-image: image(#c3dffe); } #viewport11 viewport:disabled button:disabled label:disabled { color: black; font-weight: bold; } #default_app_scroll_window { border-width: 0px; } #shortcut_treeview.view header button, iconview#shortcut_treeview header button { min-height: 35px; } #font_grid button:disabled { background-image: image(#c3dffe); } ukui-control-center/AUTHORS0000664000175000017500000000041113057175506014466 0ustar fengfengMATE: Perberos Steve Zesch Stefano Karapetsas GNOME: Jonathan Blandford UKUI wuxiaoyi penghuan zhangshuhao ukui-control-center/COPYING.LGPL0000644000175000017500000006364213064220646015215 0ustar fengfeng GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 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. [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 Street, 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! ukui-control-center/org.ukui.control-center.keybinding.gschema.xml.in0000664000175000017500000000137213253611037024774 0ustar fengfeng '' Keybinding Keybinding associated with a custom shortcut. '' Command Command associated with a custom keybinding. '' Name Description associated with a custom keybinding. ukui-control-center/panels/0000775000175000017500000000000013263647163014706 5ustar fengfengukui-control-center/panels/mouse/0000775000175000017500000000000013263647163016036 5ustar fengfengukui-control-center/panels/mouse/double-click-maybe.png0000664000175000017500000001112513057175444022173 0ustar fengfengPNG  IHDR@@% tEXtSoftwareAdobe ImageReadyqe<!iTXtXML:com.adobe.xmp eIDATxZ pWzchf4ct4`)βd+qZRNkԆTl6fckl\d& d.IBg$==+o&kUե~[PCy(.[[[ ~%DV2ނa4ax)t:{6 wOLL| l7i:v*<Ny]~[n hپ!~5e략q==u\ vl2 yQjEM`binI8,x;(KhUP@ @IIɺ͏ :v$d:DDZ <;19?s';P(*+++7_ ,0._|`4k oπ+VZz4k85/yqUTVLv2gM) HHg3m4d`SXLe -FO ŰR3 Y.0c,4)r>pk_CM3o ӁLwwC..-Q,6>}Kv! eғHTRHV{4 8s?,ЩS|?cG#d Ӱ*lE)-Vy_=]O$Ο{322rOEQQVO!4\ʀ|l^TfzѲeΧnۀ+(L-׉Zl6 .mj O"J7=60_#&.zM9ZTbJ3I:YJ5 \\R5>,͘@kH\q*L\Ԇo0sě>[@8O9(P+u\n}Fmvڅ],r5-RI 2CN83n^iET/T 2tc3̓yRAg1l2EkżŚ@dD(e >R(gYv mG|4+I˞DaX?9}6~Q˔c.A+a0C-*W891,x5/qx+d$'‡rl$=}Mbf1H?P? [ߙeIq$}9dӠngS/p nl@$)3i}AwGO4X^e~ÝeDW#';'24+n_qxxޯ0R))2ү2{jq ؐX,Q co=]Bf9Jʼn_vt 1GK%z"믽 nnWmLV8888==ih˚<\*$S삟i`Pni("NRq,$ŋA"'0%69 ϻT3%hT'=h||Lۿ:N$w@"NWկD V ͻ$sDp$G "&z#D2s`۝kl81/e^HԤ*’#/\t>{{0paj/,'!1P<ؤw%\RlK, ieꃐ/+R.E`,?⢇= MhO[ n=ηz[ĵ˱HOD6+Jf0^[R(At|h2H0NAǕ8N#,GHܦpY2dz-4(i.&F19 |x%ʴZ ĄWKFNtRjU qNͦԨL$\/InLrypRJ2H2tÌR'}9ʸdn2aWBP PQSB ҈+Gżj3Ζd%`p:{s~ʻɢ/0,4O+]Ak~ Ax!ҙLlb7P R漁ysv596|064Qu:Й0'_ bI_fcY|7Ro͉mdi3p8>gZXdr z X RB%B!%9o\_]hdBG "03~r>Ÿ^6=9\ T[(]R31F Kᘹ `*G#z!/S;q9xon=)-^$pY) {37= +@/2 [NGDɌ8VY+8Ep6WgC_S|xl&i,*V BN2`}NX,BNsYB5сP.T{넾9!M4N$2{tvoommO e8 :EroEbKfd:6`jj#z4A0je4P_x<0 8_Y+1y&[8kO|RH? X;0A OVkt20^vM -Nϓ2GOT;PH[Z+ݟdP^č_ < azu[xoݎڱʚ,?sK[ rpb0Ǚ̽w!@8Z֜$ 98*\QU߬Zue S7nذa$ǒ\P(K:8qQRS~RШbP+Ro xpaMSfXoq…ŞO}6ipnWRDžzc'OP@@-bPvm4ULSٰV5vU˵]̾r+ZX\9Qgg4wYCC" ]"(8o8_ lv6_1 G0TH0rtttsK箇k(\eEHRNA%Xf$X~,3:y@gj,ZLNgyT|q_v\i@L_s}Jb;]s@e3UbEiP~%P% ^ {Ӷfݜ>:jrKv?juuu+Cy( #include #include #include #include #include #include #include #include #define WID(s) (GTK_WIDGET(gtk_builder_get_object(mousedata.builder, s))) #define MOUSE_SCHEMA "org.mate.peripherals-mouse" #define DOUBLE_CLICK_KEY "double-click" #define TOUCHPAD_SCHEMA "org.ukui.peripherals-touchpad" #define MOUSE_DBLCLCK_OFF "mouse-dblclck-off" #define MOUSE_DBLCLCK_MAYBE "mouse-dblclck-maybe" #define MOUSE_DBLCLCK_ON "mouse-dblclck-on" #define MOUSE_DBLCLCK_ICON_SIZE 67 #define STOCK_ICON_PATH "/usr/share/ukui-control-center/pixmaps/" typedef struct _MouseData MouseData; typedef struct { char * stock_id; char * name; }StockIcon; typedef struct { GtkWidget * image; gint * timeout_id; }Time_out_data; static StockIcon items[] = { {MOUSE_DBLCLCK_MAYBE, "double-click-maybe.png"}, {MOUSE_DBLCLCK_OFF, "double-click-off.png"}, {MOUSE_DBLCLCK_ON, "double-click-on.png"} }; struct _MouseData { // gtk object GtkBuilder * builder; GtkWidget * right_hand; GtkWidget * left_hand; GtkWidget * location_pointer_position; GtkWidget * movtion_speed; GtkWidget * senstive_speed; GtkWidget * double_click_speed; GtkWidget * test_image; //synaptics GtkWidget * prefs_widget; GtkWidget * disable_typing_toggle; GtkWidget * tap_to_click_toggle; GtkWidget * horiz_scroll_toggle; GtkWidget * touchpad_enabled; GtkWidget * scroll_disabled_radio; GtkWidget * vertical_scroll_edge_radio; GtkWidget * horiz_scroll_edge_radio; GtkWidget * vertical_twofinger_scroll_radio; GtkWidget * horiz_twofinger_scroll_radio; }; MouseData mousedata; enum { DOUBLE_CLICK_TEST_OFF, DOUBLE_CLICK_TEST_MAYBE, DOUBLE_CLICK_TEST_ON }; static gint double_click_state = DOUBLE_CLICK_TEST_OFF; static GtkIconSize stock_icon_size =0; static GSettings * mouse_settings=NULL; static GSettings * touchpad_settings=NULL; static void synaptics_check_capabilities () { //have xinput int numdevices, i; XDeviceInfo *devicelist; Atom realtype, prop; int realformat; unsigned long nitems, bytes_after; unsigned char *data; prop = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Synaptics Capabilities", True); if (!prop) return; devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), &numdevices); for (i = 0; i < numdevices; i++) { if (devicelist[i].use != IsXExtensionPointer) continue; gdk_error_trap_push (); XDevice *device = XOpenDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), devicelist[i].id); if (gdk_error_trap_pop ()) continue; gdk_error_trap_push (); if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, prop, 0, 2, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data) == Success) && (realtype != None)) { /* Property data is booleans for has_left, has_middle, * has_right, has_double, has_triple */ if (!data[0]) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (WID ("tap_to_click_toggle")), TRUE); gtk_widget_set_sensitive (WID ("tap_to_click_toggle"), FALSE); } if (!data[3]) gtk_widget_set_sensitive (WID ("scroll_twofinger_radio"), FALSE); XFree (data); } gdk_error_trap_pop (); XCloseDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device); } XFreeDeviceList (devicelist); } gboolean supports_xinput_devices (void) { gint op_code, event, error; return XQueryExtension (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "XInputExtension", &op_code, &event, &error); } static gboolean device_has_property (XDevice *device, const char *property_name) { Atom realtype, prop; int realformat; unsigned long nitems, bytes_after; unsigned char *data; prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), property_name, True); if (!prop) return FALSE; gdk_error_trap_push (); if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device, prop, 0, 1, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data) == Success) && (realtype != None)) { gdk_error_trap_pop_ignored (); XFree (data); return TRUE; } gdk_error_trap_pop_ignored (); return FALSE; } XDevice* device_is_touchpad (XDeviceInfo *deviceinfo) { XDevice *device; if (deviceinfo->type != XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XI_TOUCHPAD, True)) return NULL; gdk_error_trap_push (); device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), deviceinfo->id); if (gdk_error_trap_pop () || (device == NULL)) return NULL; if (device_has_property (device, "libinput Tapping Enabled") || device_has_property (device, "Synaptics Off")) { return device; } XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device); return NULL; } static gboolean find_synaptics() { XDeviceInfo *device_info; gint n_devices; guint i; gboolean retval; if (supports_xinput_devices () == FALSE) return TRUE; retval = FALSE; device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices); if (device_info == NULL) return FALSE; for (i = 0; i < n_devices; i++) { XDevice *device; device = device_is_touchpad (&device_info[i]); if (device != NULL) { retval = TRUE; break; } } if (device_info != NULL) XFreeDeviceList (device_info); return retval; } GtkIconSize mouse_capplet_dblclck_icon_get_size(void) { return stock_icon_size; } static void register_stock_icons(GtkIconFactory * factory) { gint i; GtkIconSource * source; source = gtk_icon_source_new(); for (i=0; iimage))); gtk_image_set_from_stock(GTK_IMAGE(data->image), MOUSE_DBLCLCK_OFF, mouse_capplet_dblclck_icon_get_size()); *data->timeout_id = 0; return FALSE; } static gboolean event_box_button_press(GtkWidget * widget, GdkEventButton *event, gpointer user_data) { GtkWidget * image; gint double_click_time; static Time_out_data data; static gint test_maybe_timeout_id=0; static gint test_on_timeout_id=0; static gint double_click_timestamp=0; if (event->type != GDK_BUTTON_PRESS) { return FALSE; } double_click_time = g_settings_get_int(mouse_settings, DOUBLE_CLICK_KEY); image = g_object_get_data(G_OBJECT(widget), "image"); if (test_maybe_timeout_id != 0) { g_source_remove(test_maybe_timeout_id); } if (test_on_timeout_id !=0) { g_source_remove(test_on_timeout_id); } switch (double_click_state) { case DOUBLE_CLICK_TEST_OFF: double_click_state = DOUBLE_CLICK_TEST_MAYBE; data.image = image; data.timeout_id =&test_maybe_timeout_id; test_maybe_timeout_id = g_timeout_add(double_click_time, (GSourceFunc)reset_click_state_to_off,&data); break; case DOUBLE_CLICK_TEST_MAYBE: if (event->time -double_click_timestamp time; switch(double_click_state) { case DOUBLE_CLICK_TEST_OFF: gtk_image_set_from_stock(GTK_IMAGE(image), MOUSE_DBLCLCK_OFF, mouse_capplet_dblclck_icon_get_size()); break; case DOUBLE_CLICK_TEST_MAYBE: gtk_image_set_from_stock(GTK_IMAGE(image), MOUSE_DBLCLCK_MAYBE, mouse_capplet_dblclck_icon_get_size()); break; case DOUBLE_CLICK_TEST_ON: gtk_image_set_from_stock(GTK_IMAGE(image), MOUSE_DBLCLCK_ON, mouse_capplet_dblclck_icon_get_size()); break; } return TRUE; } static gboolean active_settings_daemon() { DBusGConnection *connection = NULL; DBusGProxy * proxy = NULL; GError * error =NULL; connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error); if (connection ==NULL) { g_warning("connect error:%s\n",error->message); g_error_free(error); return FALSE; } proxy = dbus_g_proxy_new_for_name(connection, "org.ukui.SettingsDaemon", "/org/ukui/SettingsDaemon", "org.ukui.SettingsDaemon"); if (proxy ==NULL) { g_warning("get proxy error\n"); return FALSE; } if (!org_ukui_SettingsDaemon_awake(proxy, &error)) { g_warning("SettingsDaemon awake error\n"); g_error_free(error); return FALSE; } return TRUE; } static void radio_button_toggle(GtkWidget * widget) { gboolean left_handed; left_handed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); g_settings_set_boolean(mouse_settings, "left-handed",left_handed); } static void radio_button_release(GtkWidget * widget, GdkEventButton * event, gpointer user_data) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE); } static void setup_dialog() { GtkRadioButton *radio; radio = GTK_RADIO_BUTTON(mousedata.left_hand); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), g_settings_get_boolean(mouse_settings, "left-handed")); g_signal_connect(mousedata.left_hand, "button_release_event", G_CALLBACK(radio_button_release), NULL); g_signal_connect(mousedata.right_hand, "button_release_event", G_CALLBACK(radio_button_release), NULL); g_signal_connect(mousedata.left_hand, "toggled", G_CALLBACK(radio_button_toggle),NULL); g_settings_bind(mouse_settings, "locate-pointer", mousedata.location_pointer_position, "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind(mouse_settings, "motion-acceleration", gtk_range_get_adjustment(GTK_RANGE(mousedata.movtion_speed)), "value" , G_SETTINGS_BIND_DEFAULT); g_settings_bind(mouse_settings, "motion-threshold", gtk_range_get_adjustment(GTK_RANGE(mousedata.senstive_speed)), "value", G_SETTINGS_BIND_DEFAULT); g_settings_bind(mouse_settings, DOUBLE_CLICK_KEY, gtk_range_get_adjustment(GTK_RANGE(mousedata.double_click_speed)), "value", G_SETTINGS_BIND_DEFAULT); gtk_image_set_from_stock(GTK_IMAGE(mousedata.test_image), MOUSE_DBLCLCK_OFF, mouse_capplet_dblclck_icon_get_size() ); g_object_set_data(G_OBJECT(WID("double_click_eventbox")), "image", mousedata.test_image); g_signal_connect(WID("double_click_eventbox"), "button_press_event",G_CALLBACK(event_box_button_press), NULL ); //judge if we need to show prefs_widget(1)---find_synaptics() if (find_synaptics() == FALSE) { gtk_notebook_remove_page(GTK_NOTEBOOK(mousedata.prefs_widget), 1); } else { g_settings_bind (touchpad_settings, "touchpad-enabled", mousedata.touchpad_enabled, "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (touchpad_settings, "disable-while-typing", mousedata.disable_typing_toggle, "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (touchpad_settings, "tap-to-click", mousedata.tap_to_click_toggle, "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (touchpad_settings, "vertical-edge-scrolling", mousedata.vertical_scroll_edge_radio, "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (touchpad_settings, "horizontal-edge-scrolling", mousedata.horiz_scroll_edge_radio, "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (touchpad_settings, "vertical-two-finger-scrolling", mousedata.vertical_twofinger_scroll_radio, "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (touchpad_settings, "horizontal-two-finger-scrolling", mousedata.horiz_twofinger_scroll_radio, "active", G_SETTINGS_BIND_DEFAULT); } } static void init_setting() { GtkSizeGroup * size_group; size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); gtk_size_group_add_widget(size_group, WID("movtion_label")); gtk_size_group_add_widget(size_group, WID("senstive_label")); gtk_size_group_add_widget(size_group, WID("double_click_label")); size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); gtk_size_group_add_widget(size_group, WID("movtion_slow")); gtk_size_group_add_widget(size_group, WID("senstive_low")); gtk_size_group_add_widget(size_group, WID("double_click_slow")); size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); gtk_size_group_add_widget(size_group, WID("movtion_fast")); gtk_size_group_add_widget(size_group, WID("senstive_high")); gtk_size_group_add_widget(size_group, WID("double_click_fast")); int accel_numerator, accel_denominator, threshold; //目的是当底下两个值为-1时,从底层获取到默认的具体值 double mouse_acceleration; //当前系统指针加速值,-1为系统默认 int mouse_threshold; //当前系统指针灵敏度,-1为系统默认 XGetPointerControl(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), &accel_numerator, &accel_denominator, &threshold); mouse_acceleration = g_settings_get_double(mouse_settings, "motion-acceleration"); mouse_threshold = g_settings_get_int(mouse_settings, "motion-threshold"); if(mouse_acceleration == -1.0) g_settings_set_double(mouse_settings, "motion-acceleration", (double)(accel_numerator/accel_denominator)); if(mouse_threshold == -1) g_settings_set_int(mouse_settings, "motion-threshold", threshold); } static void create_dialog(GtkBuilder * builder) { mousedata.builder = builder; mousedata.right_hand = WID("right_hand"); mousedata.left_hand = WID("left_hand"); mousedata.location_pointer_position = WID("locate_pointer_position"); mousedata.movtion_speed = WID("movtion_speed"); mousedata.senstive_speed = WID("senstive_speed"); mousedata.double_click_speed = WID("double_click_speed"); mousedata.test_image = WID("test_image"); mousedata.prefs_widget = WID("prefs_widget"); mousedata.disable_typing_toggle = WID("disable_typing_toggle"); mousedata.horiz_scroll_toggle = WID("horiz_scroll_toggle"); mousedata.tap_to_click_toggle = WID("tap_to_click_toggle"); mousedata.touchpad_enabled = WID("touchpad_enabled"); mousedata.scroll_disabled_radio = WID("scroll_disabled_radio"); mousedata.vertical_scroll_edge_radio = WID("vertical_scroll_edge_radio"); mousedata.horiz_scroll_edge_radio = WID("horiz_scroll_edge_radio"); mousedata.vertical_twofinger_scroll_radio = WID("vertical_twofinger_scroll_radio"); mousedata.horiz_twofinger_scroll_radio = WID("horiz_twofinger_scroll_radio"); } void add_mouse_app(GtkBuilder * builder) { g_debug("add_mouse_app"); active_settings_daemon(); mouse_settings = g_settings_new(MOUSE_SCHEMA); touchpad_settings = g_settings_new(TOUCHPAD_SCHEMA); create_dialog(builder); init_setting(); init_stock_icon(); setup_dialog(); } void destory_mouse_app() { g_object_unref(mouse_settings); g_object_unref(touchpad_settings); } ukui-control-center/panels/mouse/double-click-on.png0000664000175000017500000001611013057175444021511 0ustar fengfengPNG  IHDR@@% tEXtSoftwareAdobe ImageReadyqe<!iTXtXML:com.adobe.xmp R-6IDATxڜZ Wy{fvCҮNZٖ-|H( r8 NRH AbdZ]i/\wJVᅬh7hO!sof,0m ѻͩ_qpu轳oJIz+7Ar& :7E]GF%SuLw(!72: ,2zoE#yq$0X<Ȥ:-[LڬiDa [u S|OXs,j3n ؍'uNy0b 0o9mu&[à A69p?^]Tnώ%hޣiCLhv$>p`C=.V㚦 uΆakܔ[ 6nn_>*MBi̡Cl{gy:d|Ko3;zOg_(9`WhIw:;fz=剉KuypQ޺%酿|}]~{|] -.OjD>T6$Iy 6д{EQ]" o5v?˟=sldrMr3@_c=X/< 0>/lC_|M$" l2C>}WjojstPK$XHgA`?C&"~6+Iaxwm+."gC_<迹D aΩ*%E^ %,~[%q;U!ޣ9 xoپ2pα7S!Nɗ_DCD6 k.0 DO.l u *YGO ާq% U)>w-RAC VG2<8Heuf6O6k?f 4 =5/W?y2 ö"s?1Nh qa醭&0xVPL4`Ta=1!&ƋXc :̎&r-l9=3TMX8PwПxgwXvR.A:@j_iRĠ@mDK}hE^h1֢k*茦h 2L&;!hQ{; b1]tN嫗sFdYh}_Vy5ct*غŋC5sAAtɩI8ngO ީލ$E\h\26JfO+2ϳf 4.Hg.i$!5q񕼜! 7xK@(ܗ@/WRs 0ܺGwx ?~wD O6TR=fy&M `m+JuZ-C^` 4X@DAyMlH:q3`(-";v{՗& 2 {rmC`4 gܜH0o2:K9N6i*f՜|XoBbAm(3k% ۂE t @my(w{{۶m#vZh/g-Ғrq7ZXVɠXTlPQs1a^ 3E\^C xK@B:Մ;ظI<pw>@4q )zr_G$` %>gBhmm;rDq%O4[F PT E-gzK-Q=HWG6A-@cZ$@L %"@.(-QiڮU.CvRG!K &N;cl$sU x$FBF2tVZ( c$~0|. x'FbB\{#s f=%oI>1| hZc> ڜgIJ-7(+RVև[ώV>sp\<'OX,|=K]wm#`|6b"Ph>U"i)joj&mfpXu:ɊIQH|ވ 3ܛA2]jSlIeR,xM$424XC75\,w+бs.oɥ|&Ar]+y6-SlD 482oeƩP|%صYb^8Mj2Sm&Pe#`2e$%{kG/ߞwK+ \U(s@ u ٰL5"VL%ִPS%~G7aDD:,:RmYDr)zi [::e)屈 i/reQ>d@Xסnt3 KJ2čWg1ȁhːKCaj8Fܑř_֨ ȶrٴ@=V|TJ>bRY]dJOj(_y~+8]ۭ ĉGiޣjIql|v:0.._)8,Olk8pN8r!|i*1t(Ԩ4ǢV])V@JY7+E,d\oK{L:[^:wS/\岿cP^Ap^dx=& @\$ ȐI-6%aTld c"GV`:o ǝœj!$@hINg&*Բb>Ў hGϧӶm@.lh xuMDw$mR'7T͎S.p;Ujj,분$Nkiwh?)8RdI;Z<;[ymه+9Qv3Uf,}yG_[muOP[̅WFnT\-Z0--` n"8$(-?¤ B3ڮ8#G%bR4*YIqC7A/M9hbӅWtYH#oRWl>>Ե0za- .ۢkji&*5Kl`Φ`ZoȮm"p, $0Gy8֪n|ىEyrE,',q:#p#ƪýsX7{F{5ڌvrGRNؤQ4Ks3u6ຒͱ-߼TPswR/iygèg:)A ;4w&]P%Yo6+ r^n2rY55q ERyTƍ C tF4D -i e( { ap`6o"QO7 -Md^_B)]0A,o` h’bHUgd} B- gEAgK`A!+|i}qgRļUfGOk;%۷47;*h*3֜pkn&ntMm[ t@Ux Aqc˫jZegR.va*9Ks?+ 𞡩|w?`J?Â:844ZEn :_{p|ww&W sbCYhoHg F)6R J,)6bT8%k>xI\.m :Y2g;|qB Mp'slģ?a']Zty;o/Za9P.IvIԲB\80bD૚[:I̴!hH|V-wb ^\vܳ6z)c aԡub@'РK`prA4>4Hu]~UW~6;>h>$b"RӉ5%'`Uyd(kW*R22ԙZvAbBvuoZFMU!N>?^Rtd$A0!$ʸ>um1m:$a(WIi`M&^tkf6wm@G[T5`vUFZ[2|JW/5ZWƥ)E^Fk8:Yi<{ŊTT>-N4L~teD&nPs.\:61 RzAO͇ _k ~vǮz,qSbI!\ s\l!'}mpУ$=!,̹S %AKT>4Ȳn Jxɯ@Zl ބG֎njTm#,lWԪ%z㟬(0-H3Sbw`je]Lb5 7(Hiǿ#n|;"2oqtQpvD)oou0AD$MF+۵(}h 2wCM8l/\K9cJ{;feH('(?o~'e rIENDB`ukui-control-center/panels/mouse/mouse-setting.h0000664000175000017500000000013213057175444021005 0ustar fengfeng#include void add_mouse_app(GtkBuilder * builder); void destory_mouse_app(); ukui-control-center/panels/mouse/double-click-off.png0000664000175000017500000000776113057175444021663 0ustar fengfengPNG  IHDR@@% tEXtSoftwareAdobe ImageReadyqe<!iTXtXML:com.adobe.xmp ">j fIDATxZIs[וy!3)V9T\T9T&U#sz,zfrK5X""A yzhE"%Y yr]u.G@Ex(0Wg{UQo1% ޯSϠy`k_-Lj};@6v6q[T I$gڨ]$LV~^dO99>-ť4c/$i%F"aRpw;Q̯KƧ;u"ft)qq ^nU ,]0ǁ)iE~A< PR~?~-eюdl( bv-JaWg-qR,$y(HYͥ)jmǥ*R'DWm Q\%EbX U4u? p_ ^ /~2<H@h^(:uΎ&beYc>(VDžz-i f˩c DI@IhA 1ѵD@$&XY!ZYLXLQG>E_Ҝ:d )0@柛&|G Xjl3&54^|XL( koIX="tR|ytq3)885̎tW$|<"˭"Hxk _Mk4g= aZ8K,eôc!$fksV]DnT.$b+T::+S ۾I#?Xkrp- ҒVWJ⠼y0Tpn|dt,Xg~t $rYfbo1&%$+W8 BM4 o?m"#ۉſ,{6^_B(J<`\@dϋ \dot_v M̼S$>=,ZDЛŎ+[4-Bh||K.gtwHG'撯@jk9&\N${/г\JJlhV"M;GӍG{[R H%~r;XǻZ&J릣0$` w+ґߟNW@| ğn-&+00~.}nn.ynlUgdT^״ҵ#e=y :99YXnxcn_`.B ӷIL|&,a_ (a QT9@'#%#R2Xf6c=[:̣ X*JYu! W 1#f}T/'O/7-..*W>/ N62"W/ 5kWIqg2NRuNjY"=˱\,Y>7e*:2V(jq1 ؋hAhGWs t\UIua1LCu{Yq||<`a"r{"]*Hx! fwdw4{L|l "\+*uC(8?(EA(؁tDqH6^o=aTz@rBnOLoO?LP[3M 69i{?GM ̼:ZSs]XA} csOpZ<;8FA$i(rꨂOb5 XJWc}#ydoI&Y+v0K]K$ɓ#,2J:n/ AU;_t.J&)㸃P<[]}MF1/8e Q1Zn=0'6J\qfNNN"$Hw⽭-Qa}ШQ}t'1_uG9D&|-\۔ ~l|YzҡYzM;|tn|=j4]r4LMUO+(Wnn8@,s~xիe2v)5b7_plɥBkYrT c"r!B vuGӴ_pU.*>zhYE gzv~fcSw+ 9p*j>'D9%wM ^!8]X5y,/o" "*r]u.ׯ-M.ݳ1IENDB`ukui-control-center/panels/power/0000775000175000017500000000000013263647163016042 5ustar fengfengukui-control-center/panels/power/kpm-upower.c0000664000175000017500000005020713057175444020317 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #include "config.h" #include #include #include "egg-debug.h" #include "egg-precision.h" #include "kpm-upower.h" #include "kpm-common.h" #define GPM_UP_TIME_PRECISION 5*60 #define GPM_UP_TEXT_MIN_TIME 120 /** * gpm_upower_get_device_icon_index: * @percent: The charge of the device * * The index value depends on the percentage charge: * 00-10 = 000 * 10-30 = 020 * 30-50 = 040 * 50-70 = 060 * 70-90 = 080 * 90-100 = 100 * * Return value: The character string for the filename suffix. **/ static const gchar * gpm_upower_get_device_icon_index (UpDevice *device) { gdouble percentage; /* get device properties */ g_object_get (device, "percentage", &percentage, NULL); if (percentage < 10) return "000"; else if (percentage < 30) return "020"; else if (percentage < 50) return "040"; else if (percentage < 70) return "060"; else if (percentage < 90) return "080"; return "100"; } /** * gpm_upower_get_device_icon: * * Need to free the return value * **/ gchar * gpm_upower_get_device_icon (UpDevice *device) { gchar *filename = NULL; const gchar *prefix = NULL; const gchar *index_str; UpDeviceKind kind; UpDeviceState state; gboolean is_present; gdouble percentage; g_return_val_if_fail (device != NULL, NULL); /* get device properties */ g_object_get (device, "kind", &kind, "state", &state, "percentage", &percentage, "is-present", &is_present, NULL); /* get correct icon prefix */ prefix = up_device_kind_to_string (kind); /* get the icon from some simple rules */ if (kind == UP_DEVICE_KIND_LINE_POWER) { filename = g_strdup ("gpm-ac-adapter"); } else if (kind == UP_DEVICE_KIND_MONITOR) { filename = g_strdup ("gpm-monitor"); } else if (kind == UP_DEVICE_KIND_UPS) { if (!is_present) { /* battery missing */ filename = g_strdup_printf ("gpm-%s-missing", prefix); } else if (state == UP_DEVICE_STATE_FULLY_CHARGED) { filename = g_strdup_printf ("gpm-%s-100", prefix); } else if (state == UP_DEVICE_STATE_CHARGING) { index_str = gpm_upower_get_device_icon_index (device); filename = g_strdup_printf ("gpm-%s-%s-charging", prefix, index_str); } else if (state == UP_DEVICE_STATE_DISCHARGING) { index_str = gpm_upower_get_device_icon_index (device); filename = g_strdup_printf ("gpm-%s-%s", prefix, index_str); } } else if (kind == UP_DEVICE_KIND_BATTERY) { if (!is_present) { /* battery missing */ filename = g_strdup_printf ("gpm-%s-missing", prefix); } else if (state == UP_DEVICE_STATE_EMPTY) { filename = g_strdup_printf ("gpm-%s-empty", prefix); } else if (state == UP_DEVICE_STATE_FULLY_CHARGED) { filename = g_strdup_printf ("gpm-%s-charged", prefix); } else if (state == UP_DEVICE_STATE_CHARGING) { index_str = gpm_upower_get_device_icon_index (device); filename = g_strdup_printf ("gpm-%s-%s-charging", prefix, index_str); } else if (state == UP_DEVICE_STATE_DISCHARGING) { index_str = gpm_upower_get_device_icon_index (device); filename = g_strdup_printf ("gpm-%s-%s", prefix, index_str); } else if (state == UP_DEVICE_STATE_PENDING_CHARGE) { index_str = gpm_upower_get_device_icon_index (device); /* FIXME: do new grey icons */ filename = g_strdup_printf ("gpm-%s-%s-charging", prefix, index_str); } else if (state == UP_DEVICE_STATE_PENDING_DISCHARGE) { index_str = gpm_upower_get_device_icon_index (device); filename = g_strdup_printf ("gpm-%s-%s", prefix, index_str); } else { filename = g_strdup ("gpm-battery-missing"); } } else if (kind == UP_DEVICE_KIND_MOUSE || kind == UP_DEVICE_KIND_KEYBOARD || kind == UP_DEVICE_KIND_PHONE) { if (!is_present) { /* battery missing */ filename = g_strdup_printf ("gpm-%s-000", prefix); } else if (state == UP_DEVICE_STATE_FULLY_CHARGED) { filename = g_strdup_printf ("gpm-%s-100", prefix); } else if (state == UP_DEVICE_STATE_DISCHARGING) { index_str = gpm_upower_get_device_icon_index (device); filename = g_strdup_printf ("gpm-%s-%s", prefix, index_str); } } /* nothing matched */ if (filename == NULL) { egg_warning ("nothing matched, falling back to default icon"); filename = g_strdup ("dialog-warning"); } egg_debug ("got filename: %s", filename); return filename; } /** * gpm_upower_get_device_summary: **/ gchar * gpm_upower_get_device_summary (UpDevice *device) { const gchar *kind_desc = NULL; gchar *description = NULL; guint time_to_full_round; guint time_to_empty_round; gchar *time_to_full_str; gchar *time_to_empty_str; UpDeviceKind kind; UpDeviceState state; gdouble percentage; gboolean is_present; gint64 time_to_full; gint64 time_to_empty; /* get device properties */ g_object_get (device, "kind", &kind, "state", &state, "percentage", &percentage, "is-present", &is_present, "time-to-full", &time_to_full, "time-to-empty", &time_to_empty, NULL); if (!is_present) return NULL; kind_desc = gpm_device_kind_to_localised_text (kind, 1); /* don't display all the extra stuff for keyboards and mice */ if (kind == UP_DEVICE_KIND_MOUSE || kind == UP_DEVICE_KIND_KEYBOARD || kind == UP_DEVICE_KIND_PDA) return g_strdup_printf ("%s (%.1f%%)", kind_desc, percentage); /* we care if we are on AC */ if (kind == UP_DEVICE_KIND_PHONE) { if (state == UP_DEVICE_STATE_CHARGING || !state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: a phone is charging */ return g_strdup_printf (_("%s charging (%.1f%%)"), kind_desc, percentage); } return g_strdup_printf ("%s (%.1f%%)", kind_desc, percentage); } /* precalculate so we don't get Unknown time remaining */ time_to_full_round = egg_precision_round_down (time_to_full, GPM_UP_TIME_PRECISION); time_to_empty_round = egg_precision_round_down (time_to_empty, GPM_UP_TIME_PRECISION); /* we always display "Laptop battery 16 minutes remaining" as we need to clarify what device we are refering to */ if (state == UP_DEVICE_STATE_FULLY_CHARGED) { if (kind == UP_DEVICE_KIND_BATTERY && time_to_empty_round > GPM_UP_TEXT_MIN_TIME) { time_to_empty_str = kpm_get_timestring (time_to_empty_round); /* TRANSLATORS: The laptop battery is fully charged, and we know a time */ description = g_strdup_printf (_("Battery is fully charged.\nProvides %s laptop runtime"), time_to_empty_str); g_free (time_to_empty_str); } else { /* TRANSLATORS: the device is fully charged */ description = g_strdup_printf (_("%s is fully charged"), kind_desc); } } else if (state == UP_DEVICE_STATE_DISCHARGING) { if (time_to_empty_round > GPM_UP_TEXT_MIN_TIME) { time_to_empty_str = kpm_get_timestring (time_to_empty_round); /* TRANSLATORS: the device is discharging, and we have a time remaining */ description = g_strdup_printf (_("%s %s remaining (%.1f%%)"), kind_desc, time_to_empty_str, percentage); g_free (time_to_empty_str); } else { /* TRANSLATORS: the device is discharging, but we only have a percentage */ description = g_strdup_printf (_("%s discharging (%.1f%%)"), kind_desc, percentage); } } else if (state == UP_DEVICE_STATE_CHARGING) { if (time_to_full_round > GPM_UP_TEXT_MIN_TIME && time_to_empty_round > GPM_UP_TEXT_MIN_TIME) { /* display both discharge and charge time */ time_to_full_str = kpm_get_timestring (time_to_full_round); time_to_empty_str = kpm_get_timestring (time_to_empty_round); /* TRANSLATORS: the device is charging, and we have a time to full and empty */ description = g_strdup_printf (_("%s %s until charged (%.1f%%)\nProvides %s battery runtime"), kind_desc, time_to_full_str, percentage, time_to_empty_str); g_free (time_to_full_str); g_free (time_to_empty_str); } else if (time_to_full_round > GPM_UP_TEXT_MIN_TIME) { /* display only charge time */ time_to_full_str = kpm_get_timestring (time_to_full_round); /* TRANSLATORS: device is charging, and we have a time to full and a percentage */ description = g_strdup_printf (_("%s %s until charged (%.1f%%)"), kind_desc, time_to_full_str, percentage); g_free (time_to_full_str); } else { /* TRANSLATORS: device is charging, but we only have a percentage */ description = g_strdup_printf (_("%s charging (%.1f%%)"), kind_desc, percentage); } } else if (state == UP_DEVICE_STATE_PENDING_DISCHARGE) { /* TRANSLATORS: this is only shown for laptops with multiple batteries */ description = g_strdup_printf (_("%s waiting to discharge (%.1f%%)"), kind_desc, percentage); } else if (state == UP_DEVICE_STATE_PENDING_CHARGE) { /* TRANSLATORS: this is only shown for laptops with multiple batteries */ description = g_strdup_printf (_("%s waiting to charge (%.1f%%)"), kind_desc, percentage); } else { egg_warning ("in an undefined state we are not charging or " "discharging and the batteries are also not charged"); description = g_strdup_printf ("%s (%.1f%%)", kind_desc, percentage); } return description; } /** * gpm_upower_get_device_description: **/ gchar * gpm_upower_get_device_description (UpDevice *device) { GString *details; const gchar *text; gchar *time_str; UpDeviceKind kind; UpDeviceState state; UpDeviceTechnology technology; gdouble percentage; gdouble capacity; gdouble energy; gdouble energy_full; gdouble energy_full_design; gdouble energy_rate; gboolean is_present; gint64 time_to_full; gint64 time_to_empty; gchar *vendor = NULL; gchar *serial = NULL; gchar *model = NULL; g_return_val_if_fail (device != NULL, NULL); /* get device properties */ g_object_get (device, "kind", &kind, "state", &state, "percentage", &percentage, "is-present", &is_present, "time-to-full", &time_to_full, "time-to-empty", &time_to_empty, "technology", &technology, "capacity", &capacity, "energy", &energy, "energy-full", &energy_full, "energy-full-design", &energy_full_design, "energy-rate", &energy_rate, "vendor", &vendor, "serial", &serial, "model", &model, NULL); details = g_string_new (""); text = gpm_device_kind_to_localised_text (kind, 1); /* TRANSLATORS: the type of data, e.g. Laptop battery */ g_string_append_printf (details, "%s %s\n", _("Product:"), text); if (!is_present) { /* TRANSLATORS: device is missing */ g_string_append_printf (details, "%s %s\n", _("Status:"), _("Missing")); } else if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: device is charged */ g_string_append_printf (details, "%s %s\n", _("Status:"), _("Charged")); } else if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: device is charging */ g_string_append_printf (details, "%s %s\n", _("Status:"), _("Charging")); } else if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: device is discharging */ g_string_append_printf (details, "%s %s\n", _("Status:"), _("Discharging")); } if (percentage >= 0) { /* TRANSLATORS: percentage */ g_string_append_printf (details, "%s %.1f%%\n", _("Percentage charge:"), percentage); } if (vendor) { /* TRANSLATORS: manufacturer */ g_string_append_printf (details, "%s %s\n", _("Vendor:"), vendor); } if (technology != UP_DEVICE_TECHNOLOGY_UNKNOWN) { text = gpm_device_technology_to_localised_string (technology); /* TRANSLATORS: how the battery is made, e.g. Lithium Ion */ g_string_append_printf (details, "%s %s\n", _("Technology:"), text); } if (serial) { /* TRANSLATORS: serial number of the battery */ g_string_append_printf (details, "%s %s\n", _("Serial number:"), serial); } if (model) { /* TRANSLATORS: model number of the battery */ g_string_append_printf (details, "%s %s\n", _("Model:"), model); } if (time_to_full > 0) { time_str = kpm_get_timestring (time_to_full); /* TRANSLATORS: time to fully charged */ g_string_append_printf (details, "%s %s\n", _("Charge time:"), time_str); g_free (time_str); } if (time_to_empty > 0) { time_str = kpm_get_timestring (time_to_empty); /* TRANSLATORS: time to empty */ g_string_append_printf (details, "%s %s\n", _("Discharge time:"), time_str); g_free (time_str); } if (capacity > 0) { const gchar *condition; if (capacity > 99) { /* TRANSLATORS: Excellent, Good, Fair and Poor are all related to battery Capacity */ condition = _("Excellent"); } else if (capacity > 90) { condition = _("Good"); } else if (capacity > 70) { condition = _("Fair"); } else { condition = _("Poor"); } /* TRANSLATORS: %.1f is a percentage and %s the condition (Excellent, Good, ...) */ g_string_append_printf (details, "%s %.1f%% (%s)\n", _("Capacity:"), capacity, condition); } if (kind == UP_DEVICE_KIND_BATTERY) { if (energy > 0) { /* TRANSLATORS: current charge */ g_string_append_printf (details, "%s %.1f Wh\n", _("Current charge:"), energy); } if (energy_full > 0 && energy_full_design != energy_full) { /* TRANSLATORS: last full is the charge the battery was seen to charge to */ g_string_append_printf (details, "%s %.1f Wh\n", _("Last full charge:"), energy_full); } if (energy_full_design > 0) { /* Translators: */ /* TRANSLATORS: Design charge is the amount of charge the battery is designed to have when brand new */ g_string_append_printf (details, "%s %.1f Wh\n", _("Design charge:"), energy_full_design); } if (energy_rate > 0) { /* TRANSLATORS: the charge or discharge rate */ g_string_append_printf (details, "%s %.1f W\n", _("Charge rate:"), energy_rate); } } if (kind == UP_DEVICE_KIND_MOUSE || kind == UP_DEVICE_KIND_KEYBOARD) { if (energy > 0) { /* TRANSLATORS: the current charge for CSR devices */ g_string_append_printf (details, "%s %.0f/7\n", _("Current charge:"), energy); } if (energy_full_design > 0) { /* TRANSLATORS: the design charge for CSR devices */ g_string_append_printf (details, "%s %.0f/7\n", _("Design charge:"), energy_full_design); } } /* remove the last \n */ g_string_truncate (details, details->len-1); g_free (vendor); g_free (serial); g_free (model); return g_string_free (details, FALSE); } /** * gpm_device_kind_to_localised_text: **/ const gchar * gpm_device_kind_to_localised_text (UpDeviceKind kind, guint number) { const gchar *text = NULL; switch (kind) { case UP_DEVICE_KIND_LINE_POWER: /* TRANSLATORS: system power cord */ text = ngettext ("AC adapter", "AC adapters", number); break; case UP_DEVICE_KIND_BATTERY: /* TRANSLATORS: laptop primary battery */ text = ngettext ("Laptop battery", "Laptop batteries", number); break; case UP_DEVICE_KIND_UPS: /* TRANSLATORS: battery-backed AC power source */ text = ngettext ("UPS", "UPSs", number); break; case UP_DEVICE_KIND_MONITOR: /* TRANSLATORS: a monitor is a device to measure voltage and current */ text = ngettext ("Monitor", "Monitors", number); break; case UP_DEVICE_KIND_MOUSE: /* TRANSLATORS: wireless mice with internal batteries */ text = ngettext ("Mouse", "Mice", number); break; case UP_DEVICE_KIND_KEYBOARD: /* TRANSLATORS: wireless keyboard with internal battery */ text = ngettext ("Keyboard", "Keyboards", number); break; case UP_DEVICE_KIND_PDA: /* TRANSLATORS: portable device */ text = ngettext ("PDA", "PDAs", number); break; case UP_DEVICE_KIND_PHONE: /* TRANSLATORS: cell phone (mobile...) */ text = ngettext ("Cell phone", "Cell phones", number); break; #if UP_CHECK_VERSION(0,9,5) case UP_DEVICE_KIND_MEDIA_PLAYER: /* TRANSLATORS: media player, mp3 etc */ text = ngettext ("Media player", "Media players", number); break; case UP_DEVICE_KIND_TABLET: /* TRANSLATORS: tablet device */ text = ngettext ("Tablet", "Tablets", number); break; case UP_DEVICE_KIND_COMPUTER: /* TRANSLATORS: tablet device */ text = ngettext ("Computer", "Computers", number); break; #endif default: egg_warning ("enum unrecognised: %i", kind); text = up_device_kind_to_string (kind); } return text; } /** * gpm_device_kind_to_icon: **/ const gchar * gpm_device_kind_to_icon (UpDeviceKind kind) { const gchar *icon = NULL; switch (kind) { case UP_DEVICE_KIND_LINE_POWER: icon = "gpm-ac-adapter"; break; case UP_DEVICE_KIND_BATTERY: icon = "battery"; break; case UP_DEVICE_KIND_UPS: icon = "network-wired"; break; case UP_DEVICE_KIND_MONITOR: icon = "application-certificate"; break; case UP_DEVICE_KIND_MOUSE: icon = "input-mouse"; break; case UP_DEVICE_KIND_KEYBOARD: icon = "input-keyboard"; break; case UP_DEVICE_KIND_PDA: icon = "pda"; break; case UP_DEVICE_KIND_PHONE: icon = "phone"; break; #if UP_CHECK_VERSION(0,9,5) case UP_DEVICE_KIND_MEDIA_PLAYER: icon = "multimedia-player"; break; case UP_DEVICE_KIND_TABLET: icon = "input-tablet"; break; case UP_DEVICE_KIND_COMPUTER: icon = "computer-apple-ipad"; break; #endif default: egg_warning ("enum unrecognised: %i", kind); icon = "gtk-help"; } return icon; } /** * gpm_device_technology_to_localised_string: **/ const gchar * gpm_device_technology_to_localised_string (UpDeviceTechnology technology_enum) { const gchar *technology = NULL; switch (technology_enum) { case UP_DEVICE_TECHNOLOGY_LITHIUM_ION: /* TRANSLATORS: battery technology */ technology = _("Lithium Ion"); break; case UP_DEVICE_TECHNOLOGY_LITHIUM_POLYMER: /* TRANSLATORS: battery technology */ technology = _("Lithium Polymer"); break; case UP_DEVICE_TECHNOLOGY_LITHIUM_IRON_PHOSPHATE: /* TRANSLATORS: battery technology */ technology = _("Lithium Iron Phosphate"); break; case UP_DEVICE_TECHNOLOGY_LEAD_ACID: /* TRANSLATORS: battery technology */ technology = _("Lead acid"); break; case UP_DEVICE_TECHNOLOGY_NICKEL_CADMIUM: /* TRANSLATORS: battery technology */ technology = _("Nickel Cadmium"); break; case UP_DEVICE_TECHNOLOGY_NICKEL_METAL_HYDRIDE: /* TRANSLATORS: battery technology */ technology = _("Nickel metal hydride"); break; case UP_DEVICE_TECHNOLOGY_UNKNOWN: /* TRANSLATORS: battery technology */ technology = _("Unknown technology"); break; default: g_assert_not_reached (); break; } return technology; } /** * gpm_device_state_to_localised_string: **/ const gchar * gpm_device_state_to_localised_string (UpDeviceState state) { const gchar *state_string = NULL; switch (state) { case UP_DEVICE_STATE_CHARGING: /* TRANSLATORS: battery state */ state_string = _("Charging"); break; case UP_DEVICE_STATE_DISCHARGING: /* TRANSLATORS: battery state */ state_string = _("Discharging"); break; case UP_DEVICE_STATE_EMPTY: /* TRANSLATORS: battery state */ state_string = _("Empty"); break; case UP_DEVICE_STATE_FULLY_CHARGED: /* TRANSLATORS: battery state */ state_string = _("Charged"); break; case UP_DEVICE_STATE_PENDING_CHARGE: /* TRANSLATORS: battery state */ state_string = _("Waiting to charge"); break; case UP_DEVICE_STATE_PENDING_DISCHARGE: /* TRANSLATORS: battery state */ state_string = _("Waiting to discharge"); break; default: g_assert_not_reached (); break; } return state_string; } ukui-control-center/panels/power/egg-string.h0000664000175000017500000000304313057175444020260 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #ifndef __EGG_STRING_H #define __EGG_STRING_H #include G_BEGIN_DECLS guint egg_strlen (const gchar *text, guint len) G_GNUC_WARN_UNUSED_RESULT; gboolean egg_strzero (const gchar *text) G_GNUC_WARN_UNUSED_RESULT; gboolean egg_strvequal (gchar **id1, gchar **id2) G_GNUC_WARN_UNUSED_RESULT; gboolean egg_strtoint (const gchar *text, gint *value); gboolean egg_strtouint (const gchar *text, guint *value); gchar *egg_strreplace (const gchar *text, const gchar *find, const gchar *replace); G_END_DECLS #endif /* __EGG_STRING_H */ ukui-control-center/panels/power/gs-theme-manager.h0000664000175000017500000000511213245450076021326 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2006 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * * Authors: William Jon McCann * */ #ifndef __GS_THEME_MANAGER_H #define __GS_THEME_MANAGER_H #include G_BEGIN_DECLS #define GS_TYPE_THEME_MANAGER (gs_theme_manager_get_type ()) #define GS_THEME_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GS_TYPE_THEME_MANAGER, GSThemeManager)) #define GS_THEME_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GS_TYPE_THEME_MANAGER, GSThemeManagerClass)) #define GS_IS_THEME_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GS_TYPE_THEME_MANAGER)) #define GS_IS_THEME_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GS_TYPE_THEME_MANAGER)) #define GS_THEME_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GS_TYPE_THEME_MANAGER, GSThemeManagerClass)) typedef struct GSThemeManagerPrivate GSThemeManagerPrivate; typedef struct { GObject parent; GSThemeManagerPrivate *priv; } GSThemeManager; typedef struct { GObjectClass parent_class; } GSThemeManagerClass; typedef struct _GSThemeInfo GSThemeInfo; GType gs_theme_manager_get_type (void); GSThemeManager *gs_theme_manager_new (void); GSList *gs_theme_manager_get_info_list (GSThemeManager *manager); GSThemeInfo *gs_theme_manager_lookup_theme_info (GSThemeManager *manager, const char *theme); GSThemeInfo *gs_theme_info_ref (GSThemeInfo *info); void gs_theme_info_unref (GSThemeInfo *info); const char *gs_theme_info_get_id (GSThemeInfo *info); const char *gs_theme_info_get_name (GSThemeInfo *info); const char *gs_theme_info_get_exec (GSThemeInfo *info); G_END_DECLS #endif /* __GS_THEME_MANAGER_H */ ukui-control-center/panels/power/egg-dbus-proxy.c0000664000175000017500000001766413057175444021077 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2006-2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #include "config.h" #include #include #include #include #include "egg-debug.h" #include "egg-dbus-monitor.h" #include "egg-dbus-proxy.h" static void egg_dbus_proxy_finalize (GObject *object); #define EGG_DBUS_PROXY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_TYPE_DBUS_PROXY, EggDbusProxyPrivate)) /* this is a managed proxy, i.e. a proxy that handles messagebus and DBUS service restarts. */ struct EggDbusProxyPrivate { gchar *service; gchar *interface; gchar *path; DBusGProxy *proxy; EggDbusMonitor *monitor; gboolean assigned; DBusGConnection *connection; gulong monitor_callback_id; }; enum { PROXY_STATUS, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (EggDbusProxy, egg_dbus_proxy, G_TYPE_OBJECT) /** * egg_dbus_proxy_connect: * @proxy: This class instance * Return value: success **/ static gboolean egg_dbus_proxy_connect (EggDbusProxy *proxy) { GError *error = NULL; g_return_val_if_fail (EGG_IS_DBUS_PROXY (proxy), FALSE); /* are already connected? */ if (proxy->priv->proxy != NULL) { egg_debug ("already connected to %s", proxy->priv->service); return FALSE; } proxy->priv->proxy = dbus_g_proxy_new_for_name_owner (proxy->priv->connection, proxy->priv->service, proxy->priv->path, proxy->priv->interface, &error); /* check for any possible error */ if (error) { egg_warning ("DBUS error: %s", error->message); g_error_free (error); proxy->priv->proxy = NULL; } /* shouldn't be, but make sure proxy valid */ if (proxy->priv->proxy == NULL) { egg_debug ("proxy is NULL, maybe the daemon responsible " "for %s is not running?", proxy->priv->service); return FALSE; } g_signal_emit (proxy, signals [PROXY_STATUS], 0, TRUE); return TRUE; } /** * egg_dbus_proxy_disconnect: * @proxy: This class instance * Return value: success **/ static gboolean egg_dbus_proxy_disconnect (EggDbusProxy *proxy) { g_return_val_if_fail (EGG_IS_DBUS_PROXY (proxy), FALSE); /* are already disconnected? */ if (proxy->priv->proxy == NULL) { if (proxy->priv->service) egg_debug ("already disconnected from %s", proxy->priv->service); else egg_debug ("already disconnected."); return FALSE; } g_signal_emit (proxy, signals [PROXY_STATUS], 0, FALSE); g_object_unref (proxy->priv->proxy); proxy->priv->proxy = NULL; return TRUE; } /** * dbus_monitor_connection_cb: * @proxy: The dbus raw proxy * @status: The status of the service, where TRUE is connected * @screensaver: This class instance **/ static void dbus_monitor_connection_cb (EggDbusMonitor *monitor, gboolean status, EggDbusProxy *proxy) { g_return_if_fail (EGG_IS_DBUS_PROXY (proxy)); if (proxy->priv->assigned == FALSE) return; if (status) egg_dbus_proxy_connect (proxy); else egg_dbus_proxy_disconnect (proxy); } /** * egg_dbus_proxy_assign: * @proxy: This class instance * @connections: The bus connection * @service: The DBUS service name * @interface: The DBUS interface * @path: The DBUS path * Return value: The DBUS proxy, or NULL if we haven't connected yet. **/ DBusGProxy * egg_dbus_proxy_assign (EggDbusProxy *proxy, DBusGConnection *connection, const gchar *service, const gchar *path, const gchar *interface) { g_return_val_if_fail (EGG_IS_DBUS_PROXY (proxy), NULL); g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (service != NULL, NULL); g_return_val_if_fail (interface != NULL, NULL); g_return_val_if_fail (path != NULL, NULL); if (proxy->priv->assigned) { egg_warning ("already assigned proxy!"); return NULL; } proxy->priv->service = g_strdup (service); proxy->priv->interface = g_strdup (interface); proxy->priv->path = g_strdup (path); proxy->priv->connection = connection; proxy->priv->assigned = TRUE; /* We have to save the connection and remove the signal id later as instances of this object are likely to be registering with a singleton object many times */ egg_dbus_monitor_assign (proxy->priv->monitor, connection, service); /* try to connect and return proxy (or NULL if invalid) */ egg_dbus_proxy_connect (proxy); return proxy->priv->proxy; } /** * egg_dbus_proxy_get_proxy: * @proxy: This class instance * Return value: The DBUS proxy, or NULL if we are not connected **/ DBusGProxy * egg_dbus_proxy_get_proxy (EggDbusProxy *proxy) { g_return_val_if_fail (EGG_IS_DBUS_PROXY (proxy), NULL); if (proxy->priv->assigned == FALSE) return NULL; return proxy->priv->proxy; } /** * egg_dbus_proxy_is_connected: * @proxy: This class instance * Return value: if we are connected to a valid proxy **/ gboolean egg_dbus_proxy_is_connected (EggDbusProxy *proxy) { g_return_val_if_fail (EGG_IS_DBUS_PROXY (proxy), FALSE); if (proxy->priv->assigned == FALSE) return FALSE; if (proxy->priv->proxy == NULL) return FALSE; return TRUE; } /** * egg_dbus_proxy_class_init: * @proxy: This class instance **/ static void egg_dbus_proxy_class_init (EggDbusProxyClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = egg_dbus_proxy_finalize; g_type_class_add_private (klass, sizeof (EggDbusProxyPrivate)); signals [PROXY_STATUS] = g_signal_new ("proxy-status", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggDbusProxyClass, proxy_status), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); } /** * egg_dbus_proxy_init: * @egg_dbus_proxy: This class instance **/ static void egg_dbus_proxy_init (EggDbusProxy *proxy) { proxy->priv = EGG_DBUS_PROXY_GET_PRIVATE (proxy); proxy->priv->connection = NULL; proxy->priv->proxy = NULL; proxy->priv->service = NULL; proxy->priv->interface = NULL; proxy->priv->path = NULL; proxy->priv->assigned = FALSE; proxy->priv->monitor = egg_dbus_monitor_new (); proxy->priv->monitor_callback_id = g_signal_connect (proxy->priv->monitor, "connection-changed", G_CALLBACK (dbus_monitor_connection_cb), proxy); proxy->priv->monitor_callback_id = 0; } /** * egg_dbus_proxy_finalize: * @object: This class instance **/ static void egg_dbus_proxy_finalize (GObject *object) { EggDbusProxy *proxy; g_return_if_fail (object != NULL); g_return_if_fail (EGG_IS_DBUS_PROXY (object)); proxy = EGG_DBUS_PROXY (object); proxy->priv = EGG_DBUS_PROXY_GET_PRIVATE (proxy); if (proxy->priv->monitor_callback_id != 0) g_signal_handler_disconnect (proxy->priv->monitor, proxy->priv->monitor_callback_id); egg_dbus_proxy_disconnect (proxy); if (proxy->priv->proxy != NULL) g_object_unref (proxy->priv->proxy); g_object_unref (proxy->priv->monitor); g_free (proxy->priv->service); g_free (proxy->priv->interface); g_free (proxy->priv->path); G_OBJECT_CLASS (egg_dbus_proxy_parent_class)->finalize (object); } /** * egg_dbus_proxy_new: * Return value: new class instance. **/ EggDbusProxy * egg_dbus_proxy_new (void) { EggDbusProxy *proxy; proxy = g_object_new (EGG_TYPE_DBUS_PROXY, NULL); return EGG_DBUS_PROXY (proxy); } ukui-control-center/panels/power/kpm-brightness.h0000664000175000017500000000470213057175444021152 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #ifndef __KPM_BRIGHTNESS_H #define __KPM_BRIGHTNESS_H #include G_BEGIN_DECLS #define KPM_TYPE_BRIGHTNESS (kpm_brightness_get_type ()) #define KPM_BRIGHTNESS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), KPM_TYPE_BRIGHTNESS, KpmBrightness)) #define KPM_BRIGHTNESS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), KPM_TYPE_BRIGHTNESS, KpmBrightnessClass)) #define KPM_IS_BRIGHTNESS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), KPM_TYPE_BRIGHTNESS)) #define KPM_IS_BRIGHTNESS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), KPM_TYPE_BRIGHTNESS)) #define KPM_BRIGHTNESS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), KPM_TYPE_BRIGHTNESS, KpmBrightnessClass)) #define KPM_BRIGHTNESS_DIM_INTERVAL 5 /* ms */ typedef struct KpmBrightnessPrivate KpmBrightnessPrivate; typedef struct { GObject parent; KpmBrightnessPrivate *priv; } KpmBrightness; typedef struct { GObjectClass parent_class; void (* brightness_changed) (KpmBrightness *brightness, guint percentage); } KpmBrightnessClass; GType kpm_brightness_get_type (void); KpmBrightness *kpm_brightness_new (void); gboolean kpm_brightness_has_hw (KpmBrightness *brightness); gboolean kpm_brightness_up (KpmBrightness *brightness, gboolean *hw_changed); gboolean kpm_brightness_down (KpmBrightness *brightness, gboolean *hw_changed); gboolean kpm_brightness_get (KpmBrightness *brightness, guint *percentage); gboolean kpm_brightness_set (KpmBrightness *brightness, guint percentage, gboolean *hw_changed); G_END_DECLS #endif /* __KPM_BRIGHTNESS_H */ ukui-control-center/panels/power/kpm-brightness.c0000664000175000017500000007014513253611037021140 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008-2010 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #include "../../shell/mainwindow.h" #include "egg-discrete.h" #include "egg-debug.h" #include "egg-string.h" #include "kpm-brightness.h" #include "kpm-common.h" #include "kpm-marshal.h" #define KPM_BRIGHTNESS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), KPM_TYPE_BRIGHTNESS, KpmBrightnessPrivate)) #define KPM_SOLE_SETTER_USE_CACHE TRUE /* this may be insanity */ struct KpmBrightnessPrivate { gboolean has_changed_events; gboolean cache_trusted; guint cache_percentage; guint last_set_hw; Atom backlight; Display *dpy; GdkWindow *root_window; guint shared_value; gboolean has_extension; #ifdef HAVE_XRANDR_13 gboolean has_randr13; #endif gboolean hw_changed; /* A cache of XRRScreenResources is used as XRRGetScreenResources is expensive */ GPtrArray *resources; gint extension_levels; gint extension_current; }; enum { BRIGHTNESS_CHANGED, LAST_SIGNAL }; typedef enum { ACTION_BACKLIGHT_GET, ACTION_BACKLIGHT_SET, ACTION_BACKLIGHT_INC, ACTION_BACKLIGHT_DEC } KpmXRandROp; G_DEFINE_TYPE (KpmBrightness, kpm_brightness, G_TYPE_OBJECT) static guint signals [LAST_SIGNAL] = { 0 }; static gpointer kpm_brightness_object = NULL; /** * kpm_brightness_helper_get_value: **/ static gint kpm_brightness_helper_get_value (const gchar *argument) { gboolean ret; GError *error = NULL; gchar *stdout_data = NULL; gint exit_status = 0; gint value = -1; gchar *command = NULL; /* get the data */ command = g_strdup_printf (SBINDIR "/ukui-power-backlight-helper --%s", argument); ret = g_spawn_command_line_sync (command, &stdout_data, NULL, &exit_status, &error); if (!ret) { egg_error ("failed to get value: %s", error->message); g_error_free (error); goto out; } egg_debug ("executing %s retval: %i", command, exit_status); /* parse for a number */ ret = egg_strtoint (stdout_data, &value); if (!ret) goto out; out: g_free (command); g_free (stdout_data); return value; } /** * kpm_brightness_helper_set_value: **/ static gboolean kpm_brightness_helper_set_value (const gchar *argument, gint value) { gboolean ret; GError *error = NULL; gint exit_status = 0; gchar *command = NULL; /* get the data */ command = g_strdup_printf ("pkexec " SBINDIR "/ukui-power-backlight-helper --%s %i", argument, value); ret = g_spawn_command_line_sync (command, NULL, NULL, &exit_status, &error); if (!ret) { egg_error ("failed to get value: %s", error->message); g_error_free (error); goto out; } egg_debug ("executing %s retval: %i", command, exit_status); out: g_free (command); return ret; } /** * kpm_brightness_get_step: * @levels: The number of levels supported * Return value: the amount of hardware steps to do on each increment or decrement **/ static guint kpm_brightness_get_step (guint levels) { /* macbook pro has a bazzillion brightness levels, do in 5% steps */ if (levels > 20) return levels / 20; return 1; } /** * kpm_brightness_output_get_internal: **/ static gboolean kpm_brightness_output_get_internal (KpmBrightness *brightness, RROutput output, guint *cur) { unsigned long nitems; unsigned long bytes_after; guint *prop; Atom actual_type; int actual_format; gboolean ret = FALSE; g_return_val_if_fail (KPM_IS_BRIGHTNESS (brightness), FALSE); if (brightness->priv->backlight == None) return FALSE; if (XRRGetOutputProperty (brightness->priv->dpy, output, brightness->priv->backlight, 0, 4, False, False, None, &actual_type, &actual_format, &nitems, &bytes_after, ((unsigned char **)&prop)) != Success) { egg_debug ("failed to get property"); return FALSE; } if (actual_type == XA_INTEGER && nitems == 1 && actual_format == 32) { memcpy (cur, prop, sizeof (guint)); ret = TRUE; } XFree (prop); return ret; } /** * kpm_brightness_output_set_internal: **/ static gboolean kpm_brightness_output_set_internal (KpmBrightness *brightness, RROutput output, guint value) { gboolean ret = TRUE; g_return_val_if_fail (KPM_IS_BRIGHTNESS (brightness), FALSE); /* don't abort on error */ gdk_error_trap_push (); XRRChangeOutputProperty (brightness->priv->dpy, output, brightness->priv->backlight, XA_INTEGER, 32, PropModeReplace, (unsigned char *) &value, 1); XFlush (brightness->priv->dpy); gdk_flush (); if (gdk_error_trap_pop ()) { egg_warning ("failed to XRRChangeOutputProperty for brightness %i", value); ret = FALSE; } /* we changed the hardware */ if (ret) brightness->priv->hw_changed = TRUE; return ret; } /** * kpm_brightness_setup_display: **/ static gboolean kpm_brightness_setup_display (KpmBrightness *brightness) { gint major, minor; g_return_val_if_fail (KPM_IS_BRIGHTNESS (brightness), FALSE); /* get the display */ brightness->priv->dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default()); if (!brightness->priv->dpy) { egg_error ("Cannot open display"); return FALSE; } /* is XRandR new enough? */ if (!XRRQueryVersion (brightness->priv->dpy, &major, &minor)) { egg_debug ("RandR extension missing"); return FALSE; } if (major < 1 || (major == 1 && minor < 2)) { egg_debug ("RandR version %d.%d too old", major, minor); return FALSE; } /* can we support BACKLIGHT */ brightness->priv->backlight = XInternAtom (brightness->priv->dpy, "BACKLIGHT", True); if (brightness->priv->backlight == None) { egg_debug ("No outputs have backlight property"); return FALSE; } return TRUE; } #ifdef HAVE_XRANDR_13 /** * kpm_brightness_setup_version: Check whether xserver really supports xrandr-1.3 features. **/ static gboolean kpm_brightness_setup_version (KpmBrightness *brightness) { gint major, minor; g_return_val_if_fail (KPM_IS_BRIGHTNESS (brightness), FALSE); /* get the display */ brightness->priv->dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default()); if (!brightness->priv->dpy) { egg_error ("Cannot open display"); return FALSE; } if (!XRRQueryVersion (brightness->priv->dpy, &major, &minor)) { return FALSE; } if (major == 1 && minor < 3) { egg_debug ("RandR version %d.%d does not support XRRGetScreenResourcesCurrent", major, minor); return FALSE; } return TRUE; } #endif /** * kpm_brightness_output_get_limits: **/ static gboolean kpm_brightness_output_get_limits (KpmBrightness *brightness, RROutput output, guint *min, guint *max) { XRRPropertyInfo *info; gboolean ret = TRUE; g_return_val_if_fail (KPM_IS_BRIGHTNESS (brightness), FALSE); info = XRRQueryOutputProperty (brightness->priv->dpy, output, brightness->priv->backlight); if (info == NULL) { egg_debug ("could not get output property"); return FALSE; } if (!info->range || info->num_values != 2) { egg_debug ("was not range"); ret = FALSE; goto out; } *min = info->values[0]; *max = info->values[1]; out: XFree (info); return ret; } /** * kpm_brightness_output_get_percentage: **/ static gboolean kpm_brightness_output_get_percentage (KpmBrightness *brightness, RROutput output) { guint cur; gboolean ret; guint min, max; guint percentage; g_return_val_if_fail (KPM_IS_BRIGHTNESS (brightness), FALSE); ret = kpm_brightness_output_get_internal (brightness, output, &cur); if (!ret) return FALSE; ret = kpm_brightness_output_get_limits (brightness, output, &min, &max); if (!ret || min == max) return FALSE; egg_debug ("hard value=%i, min=%i, max=%i", cur, min, max); percentage = egg_discrete_to_percent (cur, (max-min)+1); egg_debug ("percentage %i", percentage); brightness->priv->shared_value = percentage; return TRUE; } /** * kpm_brightness_output_down: **/ static gboolean kpm_brightness_output_down (KpmBrightness *brightness, RROutput output) { guint cur; guint step; gboolean ret; guint min, max; g_return_val_if_fail (KPM_IS_BRIGHTNESS (brightness), FALSE); ret = kpm_brightness_output_get_internal (brightness, output, &cur); if (!ret) return FALSE; ret = kpm_brightness_output_get_limits (brightness, output, &min, &max); if (!ret || min == max) return FALSE; egg_debug ("hard value=%i, min=%i, max=%i", cur, min, max); if (cur == min) { egg_debug ("already min"); return TRUE; } step = kpm_brightness_get_step ((max-min)+1); if (cur < step) { egg_debug ("truncating to %i", min); cur = min; } else { cur -= step; } ret = kpm_brightness_output_set_internal (brightness, output, cur); return ret; } /** * kpm_brightness_output_up: **/ static gboolean kpm_brightness_output_up (KpmBrightness *brightness, RROutput output) { guint cur; gboolean ret; guint min, max; g_return_val_if_fail (KPM_IS_BRIGHTNESS (brightness), FALSE); ret = kpm_brightness_output_get_internal (brightness, output, &cur); if (!ret) return FALSE; ret = kpm_brightness_output_get_limits (brightness, output, &min, &max); if (!ret || min == max) return FALSE; egg_debug ("hard value=%i, min=%i, max=%i", cur, min, max); if (cur == max) { egg_debug ("already max"); return TRUE; } cur += kpm_brightness_get_step ((max-min)+1); if (cur > max) { egg_debug ("truncating to %i", max); cur = max; } ret = kpm_brightness_output_set_internal (brightness, output, cur); return ret; } /** * kpm_brightness_output_set: **/ static gboolean kpm_brightness_output_set (KpmBrightness *brightness, RROutput output) { guint cur; gboolean ret; guint min, max; gint i; gint shared_value_abs; guint step; g_return_val_if_fail (KPM_IS_BRIGHTNESS (brightness), FALSE); ret = kpm_brightness_output_get_internal (brightness, output, &cur); if (!ret) return FALSE; ret = kpm_brightness_output_get_limits (brightness, output, &min, &max); if (!ret || min == max) return FALSE; shared_value_abs = egg_discrete_from_percent (brightness->priv->shared_value, (max-min)+1); egg_debug ("percent=%i, absolute=%i", brightness->priv->shared_value, shared_value_abs); egg_debug ("hard value=%i, min=%i, max=%i", cur, min, max); if (shared_value_abs > (gint) max) shared_value_abs = max; if (shared_value_abs < (gint) min) shared_value_abs = min; if ((gint) cur == shared_value_abs) { egg_debug ("already set %i", cur); return TRUE; } /* step the correct way */ if ((gint) cur < shared_value_abs) { /* some adaptors have a large number of steps */ step = kpm_brightness_get_step (shared_value_abs - cur); egg_debug ("using step of %i", step); /* going up */ for (i=cur; i<=shared_value_abs; i+=step) { ret = kpm_brightness_output_set_internal (brightness, output, i); if (!ret) break; if ((gint) cur != shared_value_abs) g_usleep (1000 * KPM_BRIGHTNESS_DIM_INTERVAL); } } else { /* some adaptors have a large number of steps */ step = kpm_brightness_get_step (cur - shared_value_abs); egg_debug ("using step of %i", step); /* going down */ for (i=cur; i>=shared_value_abs; i-=step) { ret = kpm_brightness_output_set_internal (brightness, output, i); if (!ret) break; if ((gint) cur != shared_value_abs) g_usleep (1000 * KPM_BRIGHTNESS_DIM_INTERVAL); } } return TRUE; } /** * kpm_brightness_foreach_resource: **/ static gboolean kpm_brightness_foreach_resource (KpmBrightness *brightness, KpmXRandROp op, XRRScreenResources *resources) { gint i; gboolean ret; gboolean success_any = FALSE; RROutput output; g_return_val_if_fail (KPM_IS_BRIGHTNESS (brightness), FALSE); /* do for each output */ for (i=0; inoutput; i++) { output = resources->outputs[i]; egg_debug ("resource %i of %i", i+1, resources->noutput); if (op==ACTION_BACKLIGHT_GET) { ret = kpm_brightness_output_get_percentage (brightness, output); } else if (op==ACTION_BACKLIGHT_INC) { ret = kpm_brightness_output_up (brightness, output); } else if (op==ACTION_BACKLIGHT_DEC) { ret = kpm_brightness_output_down (brightness, output); } else if (op==ACTION_BACKLIGHT_SET) { ret = kpm_brightness_output_set (brightness, output); } else { ret = FALSE; egg_warning ("op not known"); } if (ret) { success_any = TRUE; } } return success_any; } /** * kpm_brightness_foreach_screen: **/ static gboolean kpm_brightness_foreach_screen (KpmBrightness *brightness, KpmXRandROp op) { guint i; guint length; XRRScreenResources *resource; gboolean ret; gboolean success_any = FALSE; g_return_val_if_fail (KPM_IS_BRIGHTNESS (brightness), FALSE); /* Return immediately if we can't use XRandR */ if (!brightness->priv->has_extension) return FALSE; /* do for each screen */ length = brightness->priv->resources->len; for (i=0; ipriv->resources, i); egg_debug ("using resource %p", resource); ret = kpm_brightness_foreach_resource (brightness, op, resource); if (ret) success_any = TRUE; } XSync (brightness->priv->dpy, False); return success_any; } /** * kpm_brightness_trust_cache: * @brightness: This brightness class instance * Return value: if we can trust the cache **/ static gboolean kpm_brightness_trust_cache (KpmBrightness *brightness) { g_return_val_if_fail (KPM_IS_BRIGHTNESS (brightness), FALSE); /* only return the cached value if the cache is trusted and we have change events */ if (brightness->priv->cache_trusted && brightness->priv->has_changed_events) { egg_debug ("using cache for value %u (okay)", brightness->priv->cache_percentage); return TRUE; } /* can we trust that if we set a value 5 minutes ago, will it still be valid now? * if we have multiple things setting policy on the workstation, e.g. fast user switching * or kpowersave, then this will be invalid -- this logic may be insane */ if (KPM_SOLE_SETTER_USE_CACHE && brightness->priv->cache_trusted) { egg_warning ("using cache for value %u (probably okay)", brightness->priv->cache_percentage); return TRUE; } return FALSE; } /** * kpm_brightness_set: * @brightness: This brightness class instance * @percentage: The percentage brightness * @hw_changed: If the hardware was changed, i.e. the brightness changed * Return value: %TRUE if success, %FALSE if there was an error **/ gboolean kpm_brightness_set (KpmBrightness *brightness, guint percentage, gboolean *hw_changed) { gboolean ret = FALSE; gboolean trust_cache; g_return_val_if_fail (KPM_IS_BRIGHTNESS (brightness), FALSE); /* can we check the new value with the cache? */ trust_cache = kpm_brightness_trust_cache (brightness); if (trust_cache && percentage == brightness->priv->cache_percentage) { egg_debug ("not setting the same value %i", percentage); return TRUE; } /* set the value we want */ brightness->priv->shared_value = percentage; /* reset to not-changed */ brightness->priv->hw_changed = FALSE; ret = kpm_brightness_foreach_screen (brightness, ACTION_BACKLIGHT_SET); /* legacy fallback */ if (!ret) { if (brightness->priv->extension_levels < 0) brightness->priv->extension_levels = kpm_brightness_helper_get_value ("get-max-brightness"); brightness->priv->extension_current = egg_discrete_from_percent (percentage, brightness->priv->extension_levels+1); ret = kpm_brightness_helper_set_value ("set-brightness", brightness->priv->extension_current); } /* did the hardware have to be modified? */ if (ret && hw_changed != NULL) *hw_changed = brightness->priv->hw_changed; /* we did something to the hardware, so untrusted */ if (ret) brightness->priv->cache_trusted = FALSE; return ret; } /** * kpm_brightness_get: * @brightness: This brightness class instance * Return value: The percentage brightness, or -1 for no hardware or error * * Gets the current (or at least what this class thinks is current) percentage * brightness. This is quick as no HAL inquiry is done. **/ gboolean kpm_brightness_get (KpmBrightness *brightness, guint *percentage) { gboolean ret = FALSE; gboolean trust_cache; guint percentage_local; g_return_val_if_fail (KPM_IS_BRIGHTNESS (brightness), FALSE); g_return_val_if_fail (percentage != NULL, FALSE); /* can we use the cache? */ trust_cache = kpm_brightness_trust_cache (brightness); if (trust_cache) { *percentage = brightness->priv->cache_percentage; return TRUE; } /* get the brightness from hardware -- slow */ ret = kpm_brightness_foreach_screen (brightness, ACTION_BACKLIGHT_GET); percentage_local = brightness->priv->shared_value; /* legacy fallback */ if (!ret) { if (brightness->priv->extension_levels < 0) brightness->priv->extension_levels = kpm_brightness_helper_get_value ("get-max-brightness"); brightness->priv->extension_current = kpm_brightness_helper_get_value ("get-brightness"); percentage_local = egg_discrete_to_percent (brightness->priv->extension_current, brightness->priv->extension_levels+1); ret = TRUE; } /* valid? */ if (percentage_local > 100) { egg_warning ("percentage value of %i will be truncated", percentage_local); percentage_local = 100; } /* a new value is always trusted if the method and checks succeed */ if (ret) { brightness->priv->cache_percentage = percentage_local; brightness->priv->cache_trusted = TRUE; *percentage = percentage_local; } else { brightness->priv->cache_trusted = FALSE; } return ret; } /** * kpm_brightness_up: * @brightness: This brightness class instance * @hw_changed: If the hardware was changed, i.e. the brightness changed * Return value: %TRUE if success, %FALSE if there was an error * * If possible, put the brightness of the LCD up one unit. **/ gboolean kpm_brightness_up (KpmBrightness *brightness, gboolean *hw_changed) { gboolean ret = FALSE; guint step; g_return_val_if_fail (KPM_IS_BRIGHTNESS (brightness), FALSE); /* reset to not-changed */ brightness->priv->hw_changed = FALSE; ret = kpm_brightness_foreach_screen (brightness, ACTION_BACKLIGHT_INC); /* did the hardware have to be modified? */ if (ret && hw_changed != NULL) *hw_changed = brightness->priv->hw_changed; /* we did something to the hardware, so untrusted */ if (ret) brightness->priv->cache_trusted = FALSE; /* legacy fallback */ if (!ret) { if (brightness->priv->extension_levels < 0) brightness->priv->extension_levels = kpm_brightness_helper_get_value ("get-max-brightness"); brightness->priv->extension_current = kpm_brightness_helper_get_value ("get-brightness"); /* increase by the step, limiting to the maximum possible levels */ if (brightness->priv->extension_current < brightness->priv->extension_levels) { step = kpm_brightness_get_step (brightness->priv->extension_levels); brightness->priv->extension_current += step; if (brightness->priv->extension_current > brightness->priv->extension_levels) brightness->priv->extension_current = brightness->priv->extension_levels; ret = kpm_brightness_helper_set_value ("set-brightness", brightness->priv->extension_current); } if (hw_changed != NULL) *hw_changed = ret; brightness->priv->cache_trusted = FALSE; goto out; } out: return ret; } /** * kpm_brightness_down: * @brightness: This brightness class instance * @hw_changed: If the hardware was changed, i.e. the brightness changed * Return value: %TRUE if success, %FALSE if there was an error * * If possible, put the brightness of the LCD down one unit. **/ gboolean kpm_brightness_down (KpmBrightness *brightness, gboolean *hw_changed) { gboolean ret = FALSE; guint step; g_return_val_if_fail (KPM_IS_BRIGHTNESS (brightness), FALSE); /* reset to not-changed */ brightness->priv->hw_changed = FALSE; ret = kpm_brightness_foreach_screen (brightness, ACTION_BACKLIGHT_DEC); /* did the hardware have to be modified? */ if (ret && hw_changed != NULL) *hw_changed = brightness->priv->hw_changed; /* we did something to the hardware, so untrusted */ if (ret) brightness->priv->cache_trusted = FALSE; /* legacy fallback */ if (!ret) { if (brightness->priv->extension_levels < 0) brightness->priv->extension_levels = kpm_brightness_helper_get_value ("get-max-brightness"); brightness->priv->extension_current = kpm_brightness_helper_get_value ("get-brightness"); /* decrease by the step, limiting to zero */ if (brightness->priv->extension_current > 0) { step = kpm_brightness_get_step (brightness->priv->extension_levels); brightness->priv->extension_current -= step; if (brightness->priv->extension_current < 0) brightness->priv->extension_current = 0; ret = kpm_brightness_helper_set_value ("set-brightness", brightness->priv->extension_current); } if (hw_changed != NULL) *hw_changed = ret; brightness->priv->cache_trusted = FALSE; goto out; } out: return ret; } /** * kpm_brightness_may_have_changed: **/ static void kpm_brightness_may_have_changed (KpmBrightness *brightness) { gboolean ret; guint percentage; ret = kpm_brightness_get (brightness, &percentage); if (!ret) { egg_warning ("failed to get output"); return; } egg_debug ("emitting brightness-changed (%i)", percentage); g_signal_emit (brightness, signals [BRIGHTNESS_CHANGED], 0, percentage); } /** * kpm_brightness_filter_xevents: **/ static GdkFilterReturn kpm_brightness_filter_xevents (GdkXEvent *xevent, GdkEvent *event, gpointer data) { KpmBrightness *brightness = KPM_BRIGHTNESS (data); if (event->type == GDK_NOTHING) return GDK_FILTER_CONTINUE; kpm_brightness_may_have_changed (brightness); return GDK_FILTER_CONTINUE; } static void kpm_brightness_update_cache (KpmBrightness *brightness); /** * kpm_brightness_monitors_changed: **/ static void kpm_brightness_monitors_changed (GdkScreen *screen, KpmBrightness *brightness) { g_return_if_fail (KPM_IS_BRIGHTNESS (brightness)); kpm_brightness_update_cache (brightness); } /** * kpm_brightness_update_cache: **/ static void kpm_brightness_update_cache (KpmBrightness *brightness) { guint length; gint screen; Window root; GdkScreen *gscreen; GdkDisplay *display; XRRScreenResources *resource; g_return_if_fail (KPM_IS_BRIGHTNESS (brightness)); /* invalidate and remove all the previous entries */ length = brightness->priv->resources->len; if (length > 0) g_ptr_array_set_size (brightness->priv->resources, 0); /* do for each screen */ display = gdk_display_get_default (); length = ScreenCount (brightness->priv->dpy); for (screen = 0; screen < (gint) length; screen++) { egg_debug ("screen %i of %i", screen+1, length); gscreen = gdk_display_get_screen (display, screen); /* if we have not setup the changed on the monitor, set it here */ if (g_object_get_data (G_OBJECT (gscreen), "gpk-set-monitors-changed") == NULL) { egg_debug ("watching ::monitors_changed on %p", gscreen); g_object_set_data (G_OBJECT (gscreen), "gpk-set-monitors-changed", (gpointer) "true"); //g_signal_connect (G_OBJECT (gscreen), "monitors_changed", // G_CALLBACK (kpm_brightness_monitors_changed), brightness); } root = RootWindow (brightness->priv->dpy, screen); /* XRRGetScreenResourcesCurrent is less expensive than XRRGetScreenResources, however it is available only in RandR 1.3 or higher and of course xserver needs to support it. */ if(dispalyIsOk) { #ifdef HAVE_XRANDR_13 if (brightness->priv->has_randr13) resource = XRRGetScreenResourcesCurrent (brightness->priv->dpy, root); else #endif resource = XRRGetScreenResources (brightness->priv->dpy, root); } if (resource != NULL) { egg_debug ("adding resource %p", resource); g_ptr_array_add (brightness->priv->resources, resource); } } } /** * kpm_brightness_has_hw: **/ gboolean kpm_brightness_has_hw (KpmBrightness *brightness) { g_return_val_if_fail (KPM_IS_BRIGHTNESS (brightness), FALSE); /* use XRandR first */ if (brightness->priv->has_extension) return TRUE; /* fallback to legacy access */ if (brightness->priv->extension_levels < 0) brightness->priv->extension_levels = kpm_brightness_helper_get_value ("get-max-brightness"); if (brightness->priv->extension_levels > 0) return TRUE; return FALSE; } /** * kpm_brightness_finalize: **/ static void kpm_brightness_finalize (GObject *object) { KpmBrightness *brightness; g_return_if_fail (object != NULL); g_return_if_fail (KPM_IS_BRIGHTNESS (object)); brightness = KPM_BRIGHTNESS (object); g_ptr_array_unref (brightness->priv->resources); gdk_window_remove_filter (brightness->priv->root_window, kpm_brightness_filter_xevents, brightness); G_OBJECT_CLASS (kpm_brightness_parent_class)->finalize (object); } /** * kpm_brightness_class_init: **/ static void kpm_brightness_class_init (KpmBrightnessClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = kpm_brightness_finalize; signals [BRIGHTNESS_CHANGED] = g_signal_new ("brightness-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (KpmBrightnessClass, brightness_changed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); g_type_class_add_private (klass, sizeof (KpmBrightnessPrivate)); } /** * kpm_brightness_init: * @brightness: This brightness class instance **/ static void kpm_brightness_init (KpmBrightness *brightness) { GdkScreen *screen; GdkDisplay *display; int event_base; int ignore; brightness->priv = KPM_BRIGHTNESS_GET_PRIVATE (brightness); brightness->priv->cache_trusted = FALSE; brightness->priv->has_changed_events = FALSE; brightness->priv->cache_percentage = 0; brightness->priv->hw_changed = FALSE; brightness->priv->extension_levels = -1; brightness->priv->resources = g_ptr_array_new_with_free_func ((GDestroyNotify) XRRFreeScreenResources); /* can we do this */ brightness->priv->has_extension = kpm_brightness_setup_display (brightness); #ifdef HAVE_XRANDR_13 brightness->priv->has_randr13 = kpm_brightness_setup_version (brightness); #endif if (brightness->priv->has_extension == FALSE) egg_debug ("no XRANDR extension"); screen = gdk_screen_get_default (); brightness->priv->root_window = gdk_screen_get_root_window (screen); display = gdk_display_get_default (); /* as we a filtering by a window, we have to add an event type */ if (!XRRQueryExtension (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), &event_base, &ignore)) { egg_warning ("can't get event_base for XRR"); } gdk_x11_register_standard_event_type (display, event_base, RRNotify + 1); gdk_window_add_filter (brightness->priv->root_window, kpm_brightness_filter_xevents, brightness); /* don't abort on error */ gdk_error_trap_push (); XRRSelectInput (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), GDK_WINDOW_XID (brightness->priv->root_window), RRScreenChangeNotifyMask | RROutputPropertyNotifyMask); /* <--- the only one we need, but see rh:345551 */ gdk_flush (); if (gdk_error_trap_pop ()) egg_warning ("failed to select XRRSelectInput"); /* create cache of XRRScreenResources as XRRGetScreenResources() is slow */ kpm_brightness_update_cache (brightness); } /** * kpm_brightness_new: * Return value: A new brightness class instance. * Can return NULL if no suitable hardware is found. **/ KpmBrightness * kpm_brightness_new (void) { if (kpm_brightness_object != NULL) { g_object_ref (kpm_brightness_object); } else { kpm_brightness_object = g_object_new (KPM_TYPE_BRIGHTNESS, NULL); g_object_add_weak_pointer (kpm_brightness_object, &kpm_brightness_object); } return KPM_BRIGHTNESS (kpm_brightness_object); } ukui-control-center/panels/power/kpm-prefs-core.h0000664000175000017500000000242113245450076021037 0ustar fengfeng#ifndef __KPMPREFSCORE_H #define __KPMPREFSCORE_H #include G_BEGIN_DECLS #define KPM_TYPE_PREFS (kpm_prefs_get_type ()) #define KPM_PREFS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), KPM_TYPE_PREFS, KpmPrefs)) #define KPM_PREFS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), KPM_TYPE_PREFS, KpmPrefsClass)) #define KPM_IS_PREFS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), KPM_TYPE_PREFS)) #define KPM_IS_PREFS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), KPM_TYPE_PREFS)) #define KPM_PREFS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), KPM_TYPE_PREFS, KpmPrefsClass)) typedef struct KpmPrefsPrivate KpmPrefsPrivate; typedef struct { GObject parent; KpmPrefsPrivate *priv; } KpmPrefs; typedef struct { GObjectClass parent_class; void (* action_help) (KpmPrefs *prefs); void (* action_close) (KpmPrefs *prefs); } KpmPrefsClass; GType kpm_prefs_get_type (void); KpmPrefs *kpm_prefs_new (void); void kpm_prefs_activate_window (KpmPrefs *prefs); void init_power(); G_END_DECLS #endif /* __KPMPREFS_H */ ukui-control-center/panels/power/egg-debug.c0000664000175000017500000001507613057175444020044 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ /** * SECTION:egg-debug * @short_description: Debugging functions * * This file contains functions that can be used for debugging. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "egg-debug.h" #define CONSOLE_RESET 0 #define CONSOLE_BLACK 30 #define CONSOLE_RED 31 #define CONSOLE_GREEN 32 #define CONSOLE_YELLOW 33 #define CONSOLE_BLUE 34 #define CONSOLE_MAGENTA 35 #define CONSOLE_CYAN 36 #define CONSOLE_WHITE 37 static gint fd = -1; /** * pk_set_console_mode: **/ static void pk_set_console_mode (guint console_code) { gchar command[13]; /* don't put extra commands into logs */ if (!egg_debug_is_console ()) return; /* Command is the control command to the terminal */ g_snprintf (command, 13, "%c[%dm", 0x1B, console_code); printf ("%s", command); } /** * egg_debug_backtrace: **/ void egg_debug_backtrace (void) { void *call_stack[512]; int call_stack_size; char **symbols; int i = 1; call_stack_size = backtrace (call_stack, G_N_ELEMENTS (call_stack)); symbols = backtrace_symbols (call_stack, call_stack_size); if (symbols != NULL) { pk_set_console_mode (CONSOLE_RED); g_print ("Traceback:\n"); while (i < call_stack_size) { g_print ("\t%s\n", symbols[i]); i++; } pk_set_console_mode (CONSOLE_RESET); free (symbols); } } /** * pk_log_line: **/ static void pk_log_line (const gchar *buffer) { ssize_t count; /* open a file */ if (fd == -1) { /* ITS4: ignore, /var/log/foo is owned by root, and this is just debug text */ fd = open (EGG_LOG_FILE, O_WRONLY|O_APPEND|O_CREAT, 0777); if (fd == -1) g_error ("could not open log: '%s'", EGG_LOG_FILE); } /* ITS4: ignore, debug text always NULL terminated */ count = write (fd, buffer, strlen (buffer)); if (count == -1) g_warning ("could not write %s", buffer); /* newline */ count = write (fd, "\n", 1); if (count == -1) g_warning ("could not write newline"); } /** * pk_print_line: **/ static void pk_print_line (const gchar *func, const gchar *file, const int line, const gchar *buffer, guint color) { gchar *str_time; gchar *header; time_t the_time; GThread *thread; time (&the_time); str_time = g_new0 (gchar, 255); strftime (str_time, 254, "%H:%M:%S", localtime (&the_time)); thread = g_thread_self (); /* generate header text */ header = g_strdup_printf ("TI:%s\tTH:%p\tFI:%s\tFN:%s,%d", str_time, thread, file, func, line); g_free (str_time); /* always in light green */ pk_set_console_mode (CONSOLE_GREEN); printf ("%s\n", header); /* different colors according to the severity */ pk_set_console_mode (color); printf (" - %s\n", buffer); pk_set_console_mode (CONSOLE_RESET); /* log to a file */ if (egg_debug_is_logging ()) { pk_log_line (header); pk_log_line (buffer); } /* flush this output, as we need to debug */ fflush (stdout); g_free (header); } /** * egg_debug_real: **/ void egg_debug_real (const gchar *func, const gchar *file, const int line, const gchar *format, ...) { va_list args; gchar *buffer = NULL; if (!egg_debug_enabled ()) return; va_start (args, format); g_vasprintf (&buffer, format, args); va_end (args); pk_print_line (func, file, line, buffer, CONSOLE_BLUE); g_free(buffer); } /** * egg_warning_real: **/ void egg_warning_real (const gchar *func, const gchar *file, const int line, const gchar *format, ...) { va_list args; gchar *buffer = NULL; if (!egg_debug_enabled ()) return; va_start (args, format); g_vasprintf (&buffer, format, args); va_end (args); /* do extra stuff for a warning */ if (!egg_debug_is_console ()) printf ("*** WARNING ***\n"); pk_print_line (func, file, line, buffer, CONSOLE_RED); g_free(buffer); } /** * egg_error_real: **/ void egg_error_real (const gchar *func, const gchar *file, const int line, const gchar *format, ...) { va_list args; gchar *buffer = NULL; va_start (args, format); g_vasprintf (&buffer, format, args); va_end (args); /* do extra stuff for a warning */ if (!egg_debug_is_console ()) printf ("*** ERROR ***\n"); pk_print_line (func, file, line, buffer, CONSOLE_RED); g_free(buffer); /* we want to fix this! */ egg_debug_backtrace (); exit (1); } /** * egg_debug_enabled: * * Returns: TRUE if we have debugging enabled **/ gboolean egg_debug_enabled (void) { const gchar *env; env = g_getenv (EGG_VERBOSE); return (g_strcmp0 (env, "1") == 0); } /** * egg_debug_is_logging: * * Returns: TRUE if we have logging enabled **/ gboolean egg_debug_is_logging (void) { const gchar *env; env = g_getenv (EGG_LOGGING); return (g_strcmp0 (env, "1") == 0); } /** * egg_debug_is_console: * * Returns: TRUE if we have debugging enabled **/ gboolean egg_debug_is_console (void) { const gchar *env; env = g_getenv (EGG_CONSOLE); return (g_strcmp0 (env, "1") == 0); } /** * egg_debug_set_logging: **/ void egg_debug_set_logging (gboolean enabled) { if (enabled) g_setenv (EGG_LOGGING, "1", TRUE); else g_setenv (EGG_LOGGING, "0", TRUE); if (egg_debug_is_logging ()) egg_debug ("logging to %s", EGG_LOG_FILE); } /** * egg_debug_init: * @debug: If we should print out verbose logging **/ void egg_debug_init (gboolean debug) { /* check if we are on console */ if (isatty (fileno (stdout)) == 1) g_setenv (EGG_CONSOLE, "1", FALSE); else g_setenv (EGG_CONSOLE, "0", FALSE); if (debug) g_setenv (EGG_VERBOSE, "1", FALSE); else g_setenv (EGG_VERBOSE, "0", FALSE); egg_debug ("Verbose debugging %i (on console %i)%s", egg_debug_enabled (), egg_debug_is_console (), EGG_VERBOSE); } ukui-control-center/panels/power/egg-array-float.h0000664000175000017500000000401613057175444021174 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #ifndef __EGG_ARRAY_FLOAT_H #define __EGG_ARRAY_FLOAT_H #include G_BEGIN_DECLS /* at the moment just use a GArray as it's quick */ typedef GArray EggArrayFloat; EggArrayFloat *egg_array_float_new (guint length); void egg_array_float_free (EggArrayFloat *array); gfloat egg_array_float_sum (EggArrayFloat *array); EggArrayFloat *egg_array_float_compute_gaussian (guint length, gfloat sigma); gfloat egg_array_float_compute_integral (EggArrayFloat *array, guint x1, guint x2); gfloat egg_array_float_get_average (EggArrayFloat *array); gboolean egg_array_float_print (EggArrayFloat *array); EggArrayFloat *egg_array_float_convolve (EggArrayFloat *data, EggArrayFloat *kernel); gfloat egg_array_float_get (EggArrayFloat *array, guint i); void egg_array_float_set (EggArrayFloat *array, guint i, gfloat value); EggArrayFloat *egg_array_float_remove_outliers (EggArrayFloat *data, guint length, gfloat sigma); #ifdef EGG_TEST void egg_array_float_test (gpointer data); #endif G_END_DECLS #endif /* __EGG_ARRAY_FLOAT_H */ ukui-control-center/panels/power/egg-idletime.h0000664000175000017500000000447613057175444020561 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #ifndef __EGG_IDLETIME_H #define __EGG_IDLETIME_H #include G_BEGIN_DECLS #define EGG_IDLETIME_TYPE (egg_idletime_get_type ()) #define EGG_IDLETIME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EGG_IDLETIME_TYPE, EggIdletime)) #define EGG_IDLETIME_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EGG_IDLETIME_TYPE, EggIdletimeClass)) #define EGG_IS_IDLETIME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EGG_IDLETIME_TYPE)) #define EGG_IS_IDLETIME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EGG_IDLETIME_TYPE)) #define EGG_IDLETIME_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EGG_IDLETIME_TYPE, EggIdletimeClass)) typedef struct EggIdletimePrivate EggIdletimePrivate; typedef struct { GObject parent; EggIdletimePrivate *priv; } EggIdletime; typedef struct { GObjectClass parent_class; void (* alarm_expired) (EggIdletime *idletime, guint timer_id); void (* reset) (EggIdletime *idletime); } EggIdletimeClass; GType egg_idletime_get_type (void); EggIdletime *egg_idletime_new (void); void egg_idletime_alarm_reset_all (EggIdletime *idletime); gboolean egg_idletime_alarm_set (EggIdletime *idletime, guint alarm_id, guint timeout); gboolean egg_idletime_alarm_remove (EggIdletime *idletime, guint alarm_id); gint64 egg_idletime_get_time (EggIdletime *idletime); #ifdef EGG_TEST void egg_idletime_test (gpointer data); #endif G_END_DECLS #endif /* __EGG_IDLETIME_H */ ukui-control-center/panels/power/Makefile.am0000664000175000017500000001066713245450076020103 0ustar fengfengcappletname = power saverdir = $(libexecdir)/ukui-screensaver #libexecdir = /usr/lib AM_CPPFLAGS = \ -DUIDIR=\""$(uidir)"\" \ @PACKAGE_CFLAGS@ \ -DUKUIMENU_I_KNOW_THIS_IS_UNSTABLE \ -fPIC \ $(PANEL_CFLAGS) \ ${DBUS_CFLAGS} \ $(UPOWER_CFLAGS) \ $(UNIQUE_CFLAGS) \ -DSBINDIR=\"$(sbindir)\" \ -DUKUILOCALEDIR=\""$(datadir)/locale"\" \ -DEGG_LOG_FILE=\""/tmp/kpm.log"\" \ -DEGG_VERBOSE="\"GPM_VERBOSE\"" \ -DEGG_LOGGING="\"GPM_LOGGING\"" \ -DEGG_CONSOLE="\"GPM_CONSOLE\"" \ -DSAVERDIR=\""$(saverdir)"\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ $(NULL) ccpanelsdir = $(PANELS_DIR) ccpanels_LTLIBRARIES = libpower.la libpower_la_SOURCES = \ egg-color.c \ egg-color.h \ egg-debug.h \ egg-debug.c \ egg-precision.h \ egg-precision.c \ egg-array-float.c \ egg-array-float.h \ egg-idletime.h \ egg-idletime.c \ egg-dbus-proxy.h \ egg-dbus-proxy.c \ egg-dbus-monitor.h \ egg-dbus-monitor.c \ egg-discrete.h \ egg-discrete.c \ egg-string.h \ egg-string.c \ egg-console-kit.h \ egg-console-kit.c \ kpm-common.h \ kpm-common.c \ kpm-brightness.h \ kpm-brightness.c \ kpm-marshal.h \ kpm-marshal.c \ kpm-upower.c \ kpm-upower.h \ kpm-prefs-core.c \ kpm-prefs-core.h \ ukui-screensaver-preferences.c \ subprocs.c \ subprocs.h \ gs-job.c \ gs-job.h \ gs-theme-manager.c \ gs-theme-manager.h \ gs-prefs.c \ gs-prefs.h \ copy-theme-dialog.c \ copy-theme-dialog.h \ $(NULL) libpower_la_LIBADD = \ @PACKAGE_LIBS@ \ $(DBUS_LIBS) \ $(UNIQUE_LIBS) \ $(UPOWER_LIBS) \ -lukui-menu \ $(NULL) libpower_la_LDFLAGS = -export-dynamic @PACKAGE_LDFLAGS@ uidir = $(pkgdatadir)/ui ui_DATA = ukui-fullscreen-preview.ui @INTLTOOL_XML_NOMERGE_RULE@ #gsettings_schemas_in_files = org.ukui.power-manager.gschema.xml.in #gsettings_SCHEMAS = $(gsettings_schemas_in_files:.gschema.xml.in=.gschema.xml) @GSETTINGS_RULES@ CLEANFILES = \ $(gsettings_SCHEMAS_in) \ $(gsettings_SCHEMAS) \ *.gschema.valid BUILT_SOURCES = \ org.ukui.PowerManager.h \ org.ukui.PowerManager.Backlight.h \ kpm-marshal.c \ kpm-marshal.h \ $(NULL) kpm-marshal.c: kpm-marshal.list echo "#include \"kpm-marshal.h\"" > $@ && \ @GLIB_GENMARSHAL@ $< --prefix=kpm_marshal --body >> $@ kpm-marshal.h: kpm-marshal.list @GLIB_GENMARSHAL@ $< --prefix=kpm_marshal --header > $@ org.ukui.PowerManager.h: org.ukui.PowerManager.xml libtool --mode=execute dbus-binding-tool \ --prefix=kpm_manager \ --mode=glib-server \ --output=org.ukui.PowerManager.h \ $(srcdir)/org.ukui.PowerManager.xml org.ukui.PowerManager.Backlight.h: org.ukui.PowerManager.Backlight.xml libtool --mode=execute dbus-binding-tool \ --prefix=kpm_backlight \ --mode=glib-server \ --output=org.ukui.PowerManager.Backlight.h \ $(srcdir)/org.ukui.PowerManager.Backlight.xml clean-local : rm -f *~ Makefile.in Makefile rm -f kpm-marshal.c kpm-marshal.h org.ukui.PowerManager.h org.ukui.PowerManager.Backlight.h ukui-control-center/panels/power/egg-color.c0000664000175000017500000001115513057175444020066 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #include #include "egg-color.h" /** * egg_color_from_rgb: * @red: The red value * @green: The green value * @blue: The blue value **/ guint32 egg_color_from_rgb (guint8 red, guint8 green, guint8 blue) { guint32 color = 0; color += (guint32) red * 0x10000; color += (guint32) green * 0x100; color += (guint32) blue; return color; } /** * egg_color_to_rgb: * @red: The red value * @green: The green value * @blue: The blue value **/ void egg_color_to_rgb (guint32 color, guint8 *red, guint8 *green, guint8 *blue) { *red = (color & 0xff0000) / 0x10000; *green = (color & 0x00ff00) / 0x100; *blue = color & 0x0000ff; } /*************************************************************************** *** MAKE CHECK TESTS *** ***************************************************************************/ #ifdef EGG_TEST #include "egg-test.h" void egg_color_test (gpointer data) { guint8 r, g, b; guint32 color; EggTest *test = (EggTest *) data; if (egg_test_start (test, "EggColor") == FALSE) { return; } /************************************************************/ egg_test_title (test, "get red"); egg_color_to_rgb (0xff0000, &r, &g, &b); if (r == 255 && g == 0 && b == 0) { egg_test_success (test, "got red"); } else { egg_test_failed (test, "could not get red (%i, %i, %i)", r, g, b); } /************************************************************/ egg_test_title (test, "get green"); egg_color_to_rgb (0x00ff00, &r, &g, &b); if (r == 0 && g == 255 && b == 0) { egg_test_success (test, "got green"); } else { egg_test_failed (test, "could not get green (%i, %i, %i)", r, g, b); } /************************************************************/ egg_test_title (test, "get blue"); egg_color_to_rgb (0x0000ff, &r, &g, &b); if (r == 0 && g == 0 && b == 255) { egg_test_success (test, "got blue"); } else { egg_test_failed (test, "could not get blue (%i, %i, %i)", r, g, b); } /************************************************************/ egg_test_title (test, "get black"); egg_color_to_rgb (0x000000, &r, &g, &b); if (r == 0 && g == 0 && b == 0) { egg_test_success (test, "got black"); } else { egg_test_failed (test, "could not get black (%i, %i, %i)", r, g, b); } /************************************************************/ egg_test_title (test, "get white"); egg_color_to_rgb (0xffffff, &r, &g, &b); if (r == 255 && g == 255 && b == 255) { egg_test_success (test, "got white"); } else { egg_test_failed (test, "could not get white (%i, %i, %i)", r, g, b); } /************************************************************/ egg_test_title (test, "set red"); color = egg_color_from_rgb (0xff, 0x00, 0x00); if (color == 0xff0000) { egg_test_success (test, "set red"); } else { egg_test_failed (test, "could not set red (%i)", color); } /************************************************************/ egg_test_title (test, "set green"); color = egg_color_from_rgb (0x00, 0xff, 0x00); if (color == 0x00ff00) { egg_test_success (test, "set green"); } else { egg_test_failed (test, "could not set green (%i)", color); } /************************************************************/ egg_test_title (test, "set blue"); color = egg_color_from_rgb (0x00, 0x00, 0xff); if (color == 0x0000ff) { egg_test_success (test, "set blue"); } else { egg_test_failed (test, "could not set blue (%i)", color); } /************************************************************/ egg_test_title (test, "set white"); color = egg_color_from_rgb (0xff, 0xff, 0xff); if (color == 0xffffff) { egg_test_success (test, "set white"); } else { egg_test_failed (test, "could not set white (%i)", color); } egg_test_end (test); } #endif ukui-control-center/panels/power/egg-precision.c0000664000175000017500000001256513057175444020751 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #include #include #include #include #include "egg-debug.h" #include "egg-precision.h" /** * egg_precision_round_up: * @value: The input value * @smallest: The smallest increment allowed * * 101, 10 110 * 95, 10 100 * 0, 10 0 * 112, 10 120 * 100, 10 100 **/ gint egg_precision_round_up (gfloat value, gint smallest) { gfloat division; if (fabs (value) < 0.01) return 0; if (smallest == 0) { egg_warning ("divisor zero"); return 0; } division = (gfloat) value / (gfloat) smallest; division = ceilf (division); division *= smallest; return (gint) division; } /** * egg_precision_round_down: * @value: The input value * @smallest: The smallest increment allowed * * 101, 10 100 * 95, 10 90 * 0, 10 0 * 112, 10 110 * 100, 10 100 **/ gint egg_precision_round_down (gfloat value, gint smallest) { gfloat division; if (fabs (value) < 0.01) return 0; if (smallest == 0) { egg_warning ("divisor zero"); return 0; } division = (gfloat) value / (gfloat) smallest; division = floorf (division); division *= smallest; return (gint) division; } /*************************************************************************** *** MAKE CHECK TESTS *** ***************************************************************************/ #ifdef EGG_TEST #include "egg-test.h" void egg_precision_test (gpointer data) { guint value; EggTest *test = (EggTest *) data; if (!egg_test_start (test, "EggPrecision")) return; /************************************************************/ egg_test_title (test, "limit precision down 0,10"); value = egg_precision_round_down (0, 10); if (value == 0) { egg_test_success (test, "got %i", value); } else { egg_test_failed (test, "precision incorrect (%i)", value); } /************************************************************/ egg_test_title (test, "limit precision down 4,10"); value = egg_precision_round_down (4, 10); if (value == 0) { egg_test_success (test, "got %i", value); } else { egg_test_failed (test, "precision incorrect (%i)", value); } /************************************************************/ egg_test_title (test, "limit precision down 11,10"); value = egg_precision_round_down (11, 10); if (value == 10) { egg_test_success (test, "got %i", value); } else { egg_test_failed (test, "precision incorrect (%i)", value); } /************************************************************/ egg_test_title (test, "limit precision down 201,2"); value = egg_precision_round_down (201, 2); if (value == 200) { egg_test_success (test, "got %i", value); } else { egg_test_failed (test, "precision incorrect (%i)", value); } /************************************************************/ egg_test_title (test, "limit precision down 100,10"); value = egg_precision_round_down (100, 10); if (value == 100) { egg_test_success (test, "got %i", value); } else { egg_test_failed (test, "precision incorrect (%i)", value); } /************************************************************/ egg_test_title (test, "limit precision up 0,10"); value = egg_precision_round_up (0, 10); if (value == 0) { egg_test_success (test, "got %i", value); } else { egg_test_failed (test, "precision incorrect (%i)", value); } /************************************************************/ egg_test_title (test, "limit precision up 4,10"); value = egg_precision_round_up (4, 10); if (value == 10) { egg_test_success (test, "got %i", value); } else { egg_test_failed (test, "precision incorrect (%i)", value); } /************************************************************/ egg_test_title (test, "limit precision up 11,10"); value = egg_precision_round_up (11, 10); if (value == 20) { egg_test_success (test, "got %i", value); } else { egg_test_failed (test, "precision incorrect (%i)", value); } /************************************************************/ egg_test_title (test, "limit precision up 201,2"); value = egg_precision_round_up (201, 2); if (value == 202) { egg_test_success (test, "got %i", value); } else { egg_test_failed (test, "precision incorrect (%i)", value); } /************************************************************/ egg_test_title (test, "limit precision up 100,10"); value = egg_precision_round_up (100, 10); if (value == 100) { egg_test_success (test, "got %i", value); } else { egg_test_failed (test, "precision incorrect (%i)", value); } egg_test_end (test); } #endif ukui-control-center/panels/power/egg-console-kit.c0000664000175000017500000002427213057175444021203 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2006-2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #include "config.h" #include #include #include #include #include #include #include "egg-debug.h" #include "egg-console-kit.h" static void egg_console_kit_finalize (GObject *object); #define EGG_CONSOLE_KIT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_TYPE_CONSOLE_KIT, EggConsoleKitPrivate)) #define CONSOLEKIT_NAME "org.freedesktop.ConsoleKit" #define CONSOLEKIT_PATH "/org/freedesktop/ConsoleKit" #define CONSOLEKIT_INTERFACE "org.freedesktop.ConsoleKit" #define CONSOLEKIT_MANAGER_PATH "/org/freedesktop/ConsoleKit/Manager" #define CONSOLEKIT_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager" #define CONSOLEKIT_SEAT_INTERFACE "org.freedesktop.ConsoleKit.Seat" #define CONSOLEKIT_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session" struct EggConsoleKitPrivate { DBusGConnection *connection; DBusGProxy *proxy_manager; DBusGProxy *proxy_session; gchar *session_id; }; enum { EGG_CONSOLE_KIT_ACTIVE_CHANGED, EGG_CONSOLE_KIT_LAST_SIGNAL }; static gpointer egg_console_kit_object = NULL; static guint signals [EGG_CONSOLE_KIT_LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (EggConsoleKit, egg_console_kit, G_TYPE_OBJECT) /** * egg_console_kit_restart: **/ gboolean egg_console_kit_restart (EggConsoleKit *console, GError **error) { gboolean ret; GError *error_local = NULL; g_return_val_if_fail (EGG_IS_CONSOLE_KIT (console), FALSE); g_return_val_if_fail (console->priv->proxy_manager != NULL, FALSE); ret = dbus_g_proxy_call (console->priv->proxy_manager, "Restart", &error_local, G_TYPE_INVALID, G_TYPE_INVALID); if (!ret) { egg_warning ("Couldn't restart: %s", error_local->message); if (error != NULL) *error = g_error_new (1, 0, "%s", error_local->message); g_error_free (error_local); } return ret; } /** * egg_console_kit_stop: **/ gboolean egg_console_kit_stop (EggConsoleKit *console, GError **error) { gboolean ret; GError *error_local = NULL; g_return_val_if_fail (EGG_IS_CONSOLE_KIT (console), FALSE); g_return_val_if_fail (console->priv->proxy_manager != NULL, FALSE); ret = dbus_g_proxy_call (console->priv->proxy_manager, "Stop", &error_local, G_TYPE_INVALID, G_TYPE_INVALID); if (!ret) { egg_warning ("Couldn't stop: %s", error_local->message); if (error != NULL) *error = g_error_new (1, 0, "%s", error_local->message); g_error_free (error_local); } return ret; } /** * egg_console_kit_can_stop: **/ gboolean egg_console_kit_can_stop (EggConsoleKit *console, gboolean *can_stop, GError **error) { gboolean ret; GError *error_local = NULL; g_return_val_if_fail (EGG_IS_CONSOLE_KIT (console), FALSE); g_return_val_if_fail (console->priv->proxy_manager != NULL, FALSE); ret = dbus_g_proxy_call (console->priv->proxy_manager, "CanStop", &error_local, G_TYPE_INVALID, G_TYPE_BOOLEAN, can_stop, G_TYPE_INVALID); if (!ret) { egg_warning ("Couldn't do CanStop: %s", error_local->message); if (error != NULL) *error = g_error_new (1, 0, "%s", error_local->message); g_error_free (error_local); /* CanStop was only added in new versions of ConsoleKit, * so assume true if this failed */ *can_stop = TRUE; } return ret; } /** * egg_console_kit_can_restart: **/ gboolean egg_console_kit_can_restart (EggConsoleKit *console, gboolean *can_restart, GError **error) { gboolean ret; GError *error_local = NULL; g_return_val_if_fail (EGG_IS_CONSOLE_KIT (console), FALSE); g_return_val_if_fail (console->priv->proxy_manager != NULL, FALSE); ret = dbus_g_proxy_call (console->priv->proxy_manager, "CanRestart", &error_local, G_TYPE_INVALID, G_TYPE_BOOLEAN, can_restart, G_TYPE_INVALID); if (!ret) { egg_warning ("Couldn't do CanRestart: %s", error_local->message); if (error != NULL) *error = g_error_new (1, 0, "%s", error_local->message); g_error_free (error_local); /* CanRestart was only added in new versions of ConsoleKit, * so assume true if this failed */ *can_restart = TRUE; } return ret; } /** * egg_console_kit_is_local: * * Return value: Returns whether the session is local **/ gboolean egg_console_kit_is_local (EggConsoleKit *console) { gboolean ret = FALSE; gboolean value = FALSE; GError *error = NULL; g_return_val_if_fail (EGG_IS_CONSOLE_KIT (console), FALSE); /* maybe console kit does not know about our session */ if (console->priv->proxy_session == NULL) { egg_warning ("no ConsoleKit session"); goto out; } /* is our session local */ ret = dbus_g_proxy_call (console->priv->proxy_session, "IsLocal", &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &value, G_TYPE_INVALID); if (!ret) { g_warning ("IsLocal failed: %s", error->message); g_error_free (error); goto out; } /* return value only if we successed */ ret = value; out: return ret; } /** * egg_console_kit_is_active: * * Return value: Returns whether the session is active on the Seat that it is attached to. **/ gboolean egg_console_kit_is_active (EggConsoleKit *console) { gboolean ret = FALSE; gboolean value = FALSE; GError *error = NULL; g_return_val_if_fail (EGG_IS_CONSOLE_KIT (console), FALSE); /* maybe console kit does not know about our session */ if (console->priv->proxy_session == NULL) { egg_warning ("no ConsoleKit session"); goto out; } /* is our session active */ ret = dbus_g_proxy_call (console->priv->proxy_session, "IsActive", &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &value, G_TYPE_INVALID); if (!ret) { g_warning ("IsActive failed: %s", error->message); g_error_free (error); goto out; } /* return value only if we successed */ ret = value; out: return ret; } /** * egg_console_kit_active_changed_cb: **/ static void egg_console_kit_active_changed_cb (DBusGProxy *proxy, gboolean active, EggConsoleKit *console) { egg_debug ("emitting active: %i", active); g_signal_emit (console, signals [EGG_CONSOLE_KIT_ACTIVE_CHANGED], 0, active); } /** * egg_console_kit_class_init: * @klass: The EggConsoleKitClass **/ static void egg_console_kit_class_init (EggConsoleKitClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = egg_console_kit_finalize; g_type_class_add_private (klass, sizeof (EggConsoleKitPrivate)); signals [EGG_CONSOLE_KIT_ACTIVE_CHANGED] = g_signal_new ("active-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggConsoleKitClass, active_changed), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); } /** * egg_console_kit_init: **/ static void egg_console_kit_init (EggConsoleKit *console) { gboolean ret; GError *error = NULL; guint32 pid; console->priv = EGG_CONSOLE_KIT_GET_PRIVATE (console); console->priv->proxy_manager = NULL; console->priv->session_id = NULL; /* connect to D-Bus */ console->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); if (console->priv->connection == NULL) { egg_warning ("Failed to connect to the D-Bus daemon: %s", error->message); g_error_free (error); goto out; } /* connect to ConsoleKit */ console->priv->proxy_manager = dbus_g_proxy_new_for_name (console->priv->connection, CONSOLEKIT_NAME, CONSOLEKIT_MANAGER_PATH, CONSOLEKIT_MANAGER_INTERFACE); if (console->priv->proxy_manager == NULL) { egg_warning ("cannot connect to ConsoleKit"); goto out; } /* get the session we are running in */ pid = getpid (); ret = dbus_g_proxy_call (console->priv->proxy_manager, "GetSessionForUnixProcess", &error, G_TYPE_UINT, pid, G_TYPE_INVALID, DBUS_TYPE_G_OBJECT_PATH, &console->priv->session_id, G_TYPE_INVALID); if (!ret) { egg_warning ("Failed to get session for pid %i: %s", pid, error->message); g_error_free (error); goto out; } egg_debug ("ConsoleKit session ID: %s", console->priv->session_id); /* connect to session */ console->priv->proxy_session = dbus_g_proxy_new_for_name (console->priv->connection, CONSOLEKIT_NAME, console->priv->session_id, CONSOLEKIT_SESSION_INTERFACE); if (console->priv->proxy_session == NULL) { egg_warning ("cannot connect to: %s", console->priv->session_id); goto out; } dbus_g_proxy_add_signal (console->priv->proxy_session, "ActiveChanged", G_TYPE_BOOLEAN, G_TYPE_INVALID); dbus_g_proxy_connect_signal (console->priv->proxy_session, "ActiveChanged", G_CALLBACK (egg_console_kit_active_changed_cb), console, NULL); out: return; } /** * egg_console_kit_finalize: * @object: The object to finalize **/ static void egg_console_kit_finalize (GObject *object) { EggConsoleKit *console; g_return_if_fail (EGG_IS_CONSOLE_KIT (object)); console = EGG_CONSOLE_KIT (object); g_return_if_fail (console->priv != NULL); if (console->priv->proxy_manager != NULL) g_object_unref (console->priv->proxy_manager); if (console->priv->proxy_session != NULL) g_object_unref (console->priv->proxy_session); g_free (console->priv->session_id); G_OBJECT_CLASS (egg_console_kit_parent_class)->finalize (object); } /** * egg_console_kit_new: * * Return value: a new EggConsoleKit object. **/ EggConsoleKit * egg_console_kit_new (void) { if (egg_console_kit_object != NULL) { g_object_ref (egg_console_kit_object); } else { egg_console_kit_object = g_object_new (EGG_TYPE_CONSOLE_KIT, NULL); g_object_add_weak_pointer (egg_console_kit_object, &egg_console_kit_object); } return EGG_CONSOLE_KIT (egg_console_kit_object); } ukui-control-center/panels/power/org.ukui.PowerManager.xml0000664000175000017500000000017213253611037022703 0ustar fengfeng ukui-control-center/panels/power/egg-discrete.h0000664000175000017500000000252113057175444020554 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #ifndef __EGG_DISCRETE_H #define __EGG_DISCRETE_H #include G_BEGIN_DECLS guint egg_discrete_from_percent (guint percentage, guint levels); guint egg_discrete_to_percent (guint discrete, guint levels); gfloat egg_discrete_to_fraction (guint discrete, guint levels); #ifdef EGG_TEST void egg_discrete_test (gpointer data); #endif G_END_DECLS #endif /* __EGG_DISCRETE_H */ ukui-control-center/panels/power/gs-prefs.h0000664000175000017500000000654013245450076017741 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2004-2006 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * * Authors: William Jon McCann * */ #ifndef __GS_PREFS_H #define __GS_PREFS_H #include G_BEGIN_DECLS #define GS_TYPE_PREFS (gs_prefs_get_type ()) #define GS_PREFS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GS_TYPE_PREFS, GSPrefs)) #define GS_PREFS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GS_TYPE_PREFS, GSPrefsClass)) #define GS_IS_PREFS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GS_TYPE_PREFS)) #define GS_IS_PREFS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GS_TYPE_PREFS)) #define GS_PREFS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GS_TYPE_PREFS, GSPrefsClass)) typedef enum { GS_MODE_BLANK_ONLY, GS_MODE_RANDOM, GS_MODE_SINGLE } GSSaverMode; typedef struct GSPrefsPrivate GSPrefsPrivate; typedef struct { GObject parent; GSPrefsPrivate *priv; guint idle_activation_enabled : 1; /* whether to activate when idle */ guint lock_enabled : 1; /* whether to lock when active */ guint logout_enabled : 1; /* Whether to offer the logout option */ guint lock_disabled : 1; /* Whether locking the system is disabled */ guint user_switch_disabled : 1; /* Whether user switching is disabled */ guint user_switch_enabled : 1; /* Whether to offer the user switch option */ guint keyboard_enabled : 1; /* Whether to try to embed a keyboard */ guint status_message_enabled : 1; /* show the status message in the lock */ guint power_timeout; /* how much idle time before power management */ guint timeout; /* how much idle time before activation */ guint lock_timeout; /* how long after activation locking starts */ guint logout_timeout; /* how long until the logout option appears */ guint cycle; /* how long each theme should run */ char *logout_command; /* command to use to logout */ char *keyboard_command; /* command to use to embed a keyboard */ GSList *themes; /* the screensaver themes to run */ GSSaverMode mode; /* theme selection mode */ } GSPrefs; typedef struct { GObjectClass parent_class; void (* changed) (GSPrefs *prefs); } GSPrefsClass; GType gs_prefs_get_type (void); GSPrefs * gs_prefs_new (void); void gs_prefs_load (GSPrefs *prefs); G_END_DECLS #endif /* __GS_PREFS_H */ ukui-control-center/panels/power/egg-dbus-proxy.h0000664000175000017500000000441713057175444021074 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2006-2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #ifndef __DBUSPROXY_H #define __DBUSPROXY_H #include #include G_BEGIN_DECLS #define EGG_TYPE_DBUS_PROXY (egg_dbus_proxy_get_type ()) #define EGG_DBUS_PROXY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EGG_TYPE_DBUS_PROXY, EggDbusProxy)) #define EGG_DBUS_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EGG_TYPE_DBUS_PROXY, EggDbusProxyClass)) #define EGG_IS_DBUS_PROXY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EGG_TYPE_DBUS_PROXY)) #define EGG_IS_DBUS_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EGG_TYPE_DBUS_PROXY)) #define EGG_DBUS_PROXY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EGG_TYPE_DBUS_PROXY, EggDbusProxyClass)) typedef struct EggDbusProxyPrivate EggDbusProxyPrivate; typedef struct { GObject parent; EggDbusProxyPrivate *priv; } EggDbusProxy; typedef struct { GObjectClass parent_class; void (* proxy_status) (EggDbusProxy *proxy, gboolean status); } EggDbusProxyClass; GType egg_dbus_proxy_get_type (void); EggDbusProxy *egg_dbus_proxy_new (void); DBusGProxy *egg_dbus_proxy_assign (EggDbusProxy *dbus_proxy, DBusGConnection *connection, const gchar *service, const gchar *path, const gchar *interface); DBusGProxy *egg_dbus_proxy_get_proxy (EggDbusProxy *egg_dbus_proxy); gboolean egg_dbus_proxy_is_connected (EggDbusProxy *egg_dbus_proxy); G_END_DECLS #endif /* __DBUSPROXY_H */ ukui-control-center/panels/power/egg-test.c0000664000175000017500000001522513057175444017731 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #include #include #include #include #include #include #include "egg-test.h" struct EggTest { guint total; guint succeeded; gboolean started; gboolean titled; gchar *type; GTimer *timer; GMainLoop *loop; guint hang_loop_id; gpointer user_data; }; /** * egg_test_init: **/ EggTest * egg_test_init () { EggTest *test; test = g_new (EggTest, 1); test->total = 0; test->succeeded = 0; test->type = NULL; test->started = FALSE; test->titled = FALSE; test->timer = g_timer_new (); test->loop = g_main_loop_new (NULL, FALSE); test->hang_loop_id = 0; return test; } /** * egg_test_loop_quit: **/ void egg_test_loop_quit (EggTest *test) { /* disable the loop watch */ if (test->hang_loop_id != 0) { g_source_remove (test->hang_loop_id); test->hang_loop_id = 0; } g_main_loop_quit (test->loop); } /** * egg_test_hang_check: **/ static gboolean egg_test_hang_check (gpointer data) { EggTest *test = (EggTest *) data; g_main_loop_quit (test->loop); return FALSE; } /** * egg_test_loop_wait: **/ void egg_test_loop_wait (EggTest *test, guint timeout) { test->hang_loop_id = g_timeout_add (timeout, egg_test_hang_check, test); g_main_loop_run (test->loop); } /** * egg_test_loop_check: **/ void egg_test_loop_check (EggTest *test) { guint elapsed = egg_test_elapsed (test); egg_test_title (test, "did we timeout out of the loop"); if (test->hang_loop_id == 0) { egg_test_success (test, "loop blocked for %ims", elapsed); } else { egg_test_failed (test, "hangcheck saved us after %ims", elapsed); } } /** * egg_test_set_user_data: **/ void egg_test_set_user_data (EggTest *test, gpointer user_data) { test->user_data = user_data; } /** * egg_test_get_user_data: **/ gpointer egg_test_get_user_data (EggTest *test) { return test->user_data; } /** * egg_test_finish: **/ gint egg_test_finish (EggTest *test) { gint retval; g_print ("test passes (%u/%u) : ", test->succeeded, test->total); if (test->succeeded == test->total) { g_print ("ALL OKAY\n"); retval = 0; } else { g_print ("%u FAILURE(S)\n", test->total - test->succeeded); retval = 1; } g_timer_destroy (test->timer); g_main_loop_unref (test->loop); g_free (test); return retval; } /** * egg_test_elapsed: * * Returns: time in ms **/ guint egg_test_elapsed (EggTest *test) { gdouble time_s; time_s = g_timer_elapsed (test->timer, NULL); return (guint) (time_s * 1000.0f); } /** * egg_test_start: **/ gboolean egg_test_start (EggTest *test, const gchar *name) { if (test->started) { g_print ("Not ended test! Cannot start!\n"); exit (1); } test->type = g_strdup (name); test->started = TRUE; return TRUE; } /** * egg_test_end: **/ void egg_test_end (EggTest *test) { if (test->started == FALSE) { g_print ("Not started test! Cannot finish!\n"); exit (1); } g_print ("OK\n"); /* disable hang check */ if (test->hang_loop_id != 0) { g_source_remove (test->hang_loop_id); test->hang_loop_id = 0; } test->started = FALSE; g_free (test->type); } /** * egg_test_title: **/ void egg_test_title (EggTest *test, const gchar *format, ...) { va_list args; gchar *va_args_buffer = NULL; /* already titled? */ if (test->titled) { g_print ("Already titled!\n"); exit (1); } /* reset the value egg_test_elapsed replies with */ g_timer_reset (test->timer); va_start (args, format); g_vasprintf (&va_args_buffer, format, args); va_end (args); g_print ("> check #%u\t%s: \t%s...", test->total+1, test->type, va_args_buffer); g_free (va_args_buffer); test->titled = TRUE; test->total++; } /** * egg_test_success: **/ void egg_test_success (EggTest *test, const gchar *format, ...) { va_list args; gchar *va_args_buffer = NULL; /* not titled? */ if (!test->titled) { g_print ("Not titled!\n"); exit (1); } if (format == NULL) { g_print ("...OK\n"); goto finish; } va_start (args, format); g_vasprintf (&va_args_buffer, format, args); va_end (args); g_print ("...OK [%s]\n", va_args_buffer); g_free (va_args_buffer); finish: test->titled = FALSE; test->succeeded++; } /** * egg_test_failed: **/ void egg_test_failed (EggTest *test, const gchar *format, ...) { va_list args; gchar *va_args_buffer = NULL; /* not titled? */ if (!test->titled) { g_print ("Not titled!\n"); exit (1); } if (format == NULL) { g_print ("FAILED\n"); goto failed; } va_start (args, format); g_vasprintf (&va_args_buffer, format, args); va_end (args); g_print ("FAILED [%s]\n", va_args_buffer); g_free (va_args_buffer); failed: exit (1); } /** * egg_test_assert: **/ void egg_test_assert (EggTest *test, gboolean value) { if (value) egg_test_success (test, NULL); else egg_test_failed (test, NULL); } /** * egg_test_title_assert: **/ void egg_test_title_assert (EggTest *test, const gchar *text, gboolean value) { egg_test_title (test, "%s", text); if (value) egg_test_success (test, NULL); else egg_test_failed (test, NULL); } /** * egg_test_get_data_file: **/ gchar * egg_test_get_data_file (const gchar *filename) { gboolean ret; gchar *full; /* check to see if we are being run in the build root */ full = g_build_filename ("..", "data", "tests", filename, NULL); ret = g_file_test (full, G_FILE_TEST_EXISTS); if (ret) return full; g_free (full); /* check to see if we are being run in the build root */ full = g_build_filename ("..", "..", "data", "tests", filename, NULL); ret = g_file_test (full, G_FILE_TEST_EXISTS); if (ret) return full; g_free (full); /* check to see if we are being run in make check */ full = g_build_filename ("..", "..", "..", "data", "tests", filename, NULL); ret = g_file_test (full, G_FILE_TEST_EXISTS); if (ret) return full; g_print ("[WARN] failed to find '%s'\n", full); g_free (full); return NULL; } ukui-control-center/panels/power/kpm-upower.h0000664000175000017500000000306013057175444020317 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #ifndef __KPM_UPOWER_H #define __KPM_UPOWER_H #include #include G_BEGIN_DECLS const gchar *gpm_device_kind_to_localised_text (UpDeviceKind kind, guint number); const gchar *gpm_device_kind_to_icon (UpDeviceKind kind); const gchar *gpm_device_technology_to_localised_string (UpDeviceTechnology technology_enum); const gchar *gpm_device_state_to_localised_string (UpDeviceState state); gchar *gpm_upower_get_device_icon (UpDevice *device); gchar *gpm_upower_get_device_summary (UpDevice *device); gchar *gpm_upower_get_device_description (UpDevice *device); G_END_DECLS #endif /* __KPM_UPOWER_H */ ukui-control-center/panels/power/kpm-prefs-core.c0000664000175000017500000011521513256625660021045 0ustar fengfeng#include #include #define UPOWER_ENABLE_DEPRECATED #include #include "kpm-prefs-core.h" #include "kpm-common.h" #include "egg-debug.h" #include "egg-console-kit.h" #include "kpm-brightness.h" #include "../../shell/mainwindow.h" static void kpm_prefs_finalize (GObject *object); #define KPM_PREFS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), KPM_TYPE_PREFS, KpmPrefsPrivate)) struct KpmPrefsPrivate { UpClient *client; GtkBuilder *builder; gboolean has_batteries; gboolean has_lcd; gboolean has_ups; gboolean has_button_lid; gboolean has_button_suspend; gboolean can_shutdown; gboolean can_suspend; gboolean can_hibernate; GSettings *settings; EggConsoleKit *console; }; G_DEFINE_TYPE (KpmPrefs, kpm_prefs, G_TYPE_OBJECT) /** * kpm_prefs_class_init: * @klass: This prefs class instance **/ static void kpm_prefs_class_init (KpmPrefsClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = kpm_prefs_finalize; g_type_class_add_private (klass, sizeof (KpmPrefsPrivate)); } /** * kpm_prefs_finalize: * @object: This prefs class instance **/ static void kpm_prefs_finalize (GObject *object) { KpmPrefs *prefs; g_return_if_fail (object != NULL); g_return_if_fail (KPM_IS_PREFS (object)); prefs = KPM_PREFS (object); prefs->priv = KPM_PREFS_GET_PRIVATE (prefs); g_object_unref (prefs->priv->settings); g_object_unref (prefs->priv->client); g_object_unref (prefs->priv->console); G_OBJECT_CLASS (kpm_prefs_parent_class)->finalize (object); } /** * kpm_prefs_format_percentage_cb: * @scale: The GtkScale object * @value: The value in %. **/ static gchar * kpm_prefs_format_percentage_cb (GtkScale *scale, gdouble value) { return g_strdup_printf ("%.0f%%", value); } /** * kpm_prefs_set_combo_simple_text: **/ static void kpm_prefs_set_combo_simple_text (GtkWidget *combo_box) { #if !GTK_CHECK_VERSION (2, 24, 0) GtkCellRenderer *cell; GtkListStore *store; store = gtk_list_store_new (1, G_TYPE_STRING); gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), GTK_TREE_MODEL (store)); g_object_unref (store); cell = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell, "text", 0, NULL); #else // nothing to do with GTK_COMBO_BOX_TEXT #endif } /** * kpm_prefs_action_time_changed_cb: **/ static void kpm_prefs_action_time_changed_cb (GtkWidget *widget, KpmPrefs *prefs) { guint value; const gint *values; const gchar *kpm_pref_key; guint active; values = (const gint *) g_object_get_data (G_OBJECT (widget), "values"); kpm_pref_key = (const gchar *) g_object_get_data (G_OBJECT (widget), "settings_key"); active = gtk_combo_box_get_active (GTK_COMBO_BOX (widget)); value = values[active]; egg_debug ("Changing %s to %i", kpm_pref_key, value); g_settings_set_int (prefs->priv->settings, kpm_pref_key, value); } /** * kpm_prefs_setup_time_combo: * @prefs: This prefs class instance * @widget_name: The GtkWidget name * @kpm_pref_key: The settings key for this preference setting. * @actions: The actions to associate in an array. **/ static void kpm_prefs_setup_time_combo (KpmPrefs *prefs, const gchar *widget_name, const gchar *kpm_pref_key, const gint *values) { guint value; gchar *text; guint i; gboolean is_writable; GtkWidget *widget; widget = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, widget_name)); kpm_prefs_set_combo_simple_text (widget); value = g_settings_get_int (prefs->priv->settings, kpm_pref_key); is_writable = g_settings_is_writable (prefs->priv->settings, kpm_pref_key); gtk_widget_set_sensitive (widget, is_writable); g_object_set_data (G_OBJECT (widget), "settings_key", (gpointer) kpm_pref_key); g_object_set_data (G_OBJECT (widget), "values", (gpointer) values); /* add each time */ for (i=0; values[i] != -1; i++) { /* get translation for number of seconds */ if (values[i] != 0) { text = kpm_get_timestring (values[i]); #if GTK_CHECK_VERSION (2, 24, 0) gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT (widget), text); #else gtk_combo_box_append_text (GTK_COMBO_BOX (widget), text); #endif g_free (text); } else { #if GTK_CHECK_VERSION (2, 24, 0) gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT (widget), _("Never")); #else gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("Never")); #endif } /* matches, so set default */ if (value == values[i]) gtk_combo_box_set_active (GTK_COMBO_BOX (widget), i); } /* connect after set */ g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (kpm_prefs_action_time_changed_cb), prefs); } /** * kpm_prefs_actions_destroy_cb: **/ static void kpm_prefs_actions_destroy_cb (KpmActionPolicy *array) { g_free (array); } /** * kpm_prefs_action_combo_changed_cb: **/ static void kpm_prefs_action_combo_changed_cb (GtkWidget *widget, KpmPrefs *prefs) { KpmActionPolicy policy; const KpmActionPolicy *actions; const gchar *kpm_pref_key; guint active; actions = (const KpmActionPolicy *) g_object_get_data (G_OBJECT (widget), "actions"); kpm_pref_key = (const gchar *) g_object_get_data (G_OBJECT (widget), "settings_key"); active = gtk_combo_box_get_active (GTK_COMBO_BOX (widget)); policy = actions[active]; g_settings_set_enum (prefs->priv->settings, kpm_pref_key, policy); } /** * kpm_prefs_setup_action_combo: * @prefs: This prefs class instance * @widget_name: The GtkWidget name * @kpm_pref_key: The settings key for this preference setting. * @actions: The actions to associate in an array. **/ static void kpm_prefs_setup_action_combo (KpmPrefs *prefs, const gchar *widget_name, const gchar *kpm_pref_key, const KpmActionPolicy *actions) { gint i; gboolean is_writable; GtkWidget *widget; KpmActionPolicy policy; KpmActionPolicy value; GPtrArray *array; KpmActionPolicy *actions_added; widget = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, widget_name)); kpm_prefs_set_combo_simple_text (widget); value = g_settings_get_enum (prefs->priv->settings, kpm_pref_key); is_writable = g_settings_is_writable (prefs->priv->settings, kpm_pref_key); //gtk_widget_set_sensitive (widget, is_writable); array = g_ptr_array_new (); g_object_set_data (G_OBJECT (widget), "settings_key", (gpointer) kpm_pref_key); g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (kpm_prefs_action_combo_changed_cb), prefs); for (i=0; actions[i] != -1; i++) { policy = actions[i]; if (policy == KPM_ACTION_POLICY_SHUTDOWN && !prefs->priv->can_shutdown) { //只是为了在交流电情况下显示出来 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT (widget), _("Shutdown")); g_ptr_array_add(array, GINT_TO_POINTER (policy)); egg_debug ("Cannot add option, as cannot shutdown."); } else if (policy == KPM_ACTION_POLICY_SHUTDOWN && prefs->priv->can_shutdown) { #if GTK_CHECK_VERSION (2, 24, 0) gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT (widget), _("Shutdown")); g_ptr_array_add(array, GINT_TO_POINTER (policy)); #else gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("Shutdown")); g_ptr_array_add (array, GINT_TO_POINTER (policy)); #endif } else if (policy == KPM_ACTION_POLICY_SUSPEND && !prefs->priv->can_suspend) { gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT (widget), _("Hang")); g_ptr_array_add (array, GINT_TO_POINTER (policy)); egg_debug ("Cannot add option, as cannot suspend."); } else if (policy == KPM_ACTION_POLICY_HIBERNATE && !prefs->priv->can_hibernate) { gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT (widget), _("Sleep")); g_ptr_array_add(array, GINT_TO_POINTER (policy)); egg_debug ("Cannot add option, as cannot hibernate."); } else if (policy == KPM_ACTION_POLICY_SUSPEND && prefs->priv->can_suspend) { #if GTK_CHECK_VERSION (2, 24, 0) gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT (widget), _("Hang")); g_ptr_array_add (array, GINT_TO_POINTER (policy)); #else gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("Hang")); g_ptr_array_add (array, GINT_TO_POINTER (policy)); #endif } else if (policy == KPM_ACTION_POLICY_HIBERNATE && prefs->priv->can_hibernate) { #if GTK_CHECK_VERSION (2, 24, 0) gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT (widget), _("Sleep")); g_ptr_array_add(array, GINT_TO_POINTER (policy)); #else gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("Sleep")); g_ptr_array_add (array, GINT_TO_POINTER (policy)); #endif } else if (policy == KPM_ACTION_POLICY_BLANK) { #if GTK_CHECK_VERSION (2, 24, 0) gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT (widget), _("Blank screen")); g_ptr_array_add (array, GINT_TO_POINTER (policy)); #else gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("Blank screen")); g_ptr_array_add (array, GINT_TO_POINTER (policy)); #endif } else if (policy == KPM_ACTION_POLICY_INTERACTIVE) { #if GTK_CHECK_VERSION (2, 24, 0) gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT (widget), _("Ask")); g_ptr_array_add(array, GINT_TO_POINTER (policy)); #else gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("Ask")); g_ptr_array_add (array, GINT_TO_POINTER (policy)); #endif } else if (policy == KPM_ACTION_POLICY_NOTHING) { #if GTK_CHECK_VERSION (2, 24, 0) gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT (widget), _("Do not perform operations")); g_ptr_array_add(array, GINT_TO_POINTER (policy)); #else gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("Do not perform operations")); g_ptr_array_add (array, GINT_TO_POINTER (policy)); #endif } else { egg_warning ("Unknown action read from settings: %i", policy); } } /* save as array _only_ the actions we could add */ actions_added = g_new0 (KpmActionPolicy, array->len+1); for (i=0; ilen; i++) actions_added[i] = GPOINTER_TO_INT (g_ptr_array_index (array, i)); actions_added[i] = -1; g_object_set_data_full (G_OBJECT (widget), "actions", (gpointer) actions_added, (GDestroyNotify) kpm_prefs_actions_destroy_cb); /* set what we have in the settings */ for (i=0; actions_added[i] != -1; i++) { policy = actions_added[i]; if (value == policy) gtk_combo_box_set_active (GTK_COMBO_BOX (widget), i); } g_ptr_array_unref (array); } static void init_picture(KpmPrefs *prefs) { GtkImage *ac_image = GTK_IMAGE(gtk_builder_get_object (prefs->priv->builder, "image1_ac")); gtk_image_set_from_file(ac_image, "/usr/share/ukui-control-center/icons/AC.png"); GtkImage *battery_image = GTK_IMAGE(gtk_builder_get_object (prefs->priv->builder, "image2_battery")); gtk_image_set_from_file(battery_image, "/usr/share/ukui-control-center/icons/battery.png"); } static void set_hide(KpmPrefs *prefs, gchar *widget_name){ GtkWidget *widget; widget = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, widget_name)); gtk_widget_hide(widget); } //如果是arm架构,隐藏掉有问题的选项 static void hide_arch(KpmPrefs *prefs) { FILE *stream; char buffer[20]; //arch命令获取体系架构 stream = popen("arch", "r"); if(!stream) return; fgets(buffer, sizeof(buffer), stream); //获取到的buffer会多一个换行符 char *arch = strtok(buffer,"\n"); if(!strcmp(arch, "aarch64")) { set_hide (prefs, "layout7_action"); set_hide (prefs, "label27_sleep"); set_hide (prefs, "label65_laptop"); set_hide (prefs, "combobox_ac_computer"); set_hide (prefs, "combobox_ac_lid"); set_hide (prefs, "combobox_battery_computer"); set_hide (prefs, "combobox_battery_lid"); GtkWidget *layout_power = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "layout5_power")); GtkWidget *layout_icon = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "layout9_icon")); gtk_layout_move(GTK_LAYOUT(layout_power), layout_icon, 0, 150); } pclose(stream); } static void prefs_setup_ac (KpmPrefs *prefs) { init_picture(prefs); hide_arch(prefs); GtkWidget *widget; const KpmActionPolicy button_lid_actions[] = {KPM_ACTION_POLICY_NOTHING, KPM_ACTION_POLICY_BLANK, KPM_ACTION_POLICY_SUSPEND, KPM_ACTION_POLICY_HIBERNATE, KPM_ACTION_POLICY_SHUTDOWN, -1}; static const gint computer_times[] = {10*60, 30*60, 1*60*60, 2*60*60, 0, /* never */ -1}; static const gint display_times[] = {1*60, 5*60, 10*60, 30*60, 1*60*60, 0, /* never */ -1}; kpm_prefs_setup_time_combo (prefs, "combobox_ac_computer", KPM_SETTINGS_SLEEP_COMPUTER_AC, computer_times); kpm_prefs_setup_time_combo (prefs, "combobox_ac_display", KPM_SETTINGS_SLEEP_DISPLAY_AC, display_times); kpm_prefs_setup_action_combo (prefs, "combobox_ac_lid", KPM_SETTINGS_BUTTON_LID_AC, button_lid_actions); //对电源界面的标签进行处理 GtkWidget *label27 = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "label27_sleep")); GtkWidget *label28 = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "label28_sleep")); GtkWidget *label65 = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "label65_laptop")); GtkWidget *label34 = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "label34_press")); GtkWidget *label37 = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "label37_suspend")); gtk_label_set_xalign(GTK_LABEL(label27), 0.0); gtk_label_set_xalign(GTK_LABEL(label28), 0.0); gtk_label_set_xalign(GTK_LABEL(label65), 0.0); gtk_label_set_xalign(GTK_LABEL(label34), 0.0); gtk_label_set_xalign(GTK_LABEL(label37), 0.0); /* setup brightness slider */ // widget = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "hscale_ac_brightness")); // g_settings_bind (prefs->priv->settings, KPM_SETTINGS_BRIGHTNESS_AC, // gtk_range_get_adjustment (GTK_RANGE (widget)), "value", // G_SETTINGS_BIND_DEFAULT); // g_signal_connect (G_OBJECT (widget), "format-value", // G_CALLBACK (kpm_prefs_format_percentage_cb), NULL); /* set up the checkboxes */ // widget = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "checkbutton_ac_display_dim")); // g_settings_bind (prefs->priv->settings, KPM_SETTINGS_IDLE_DIM_AC, // widget, "active", // G_SETTINGS_BIND_DEFAULT); // widget = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "checkbutton_ac_spindown")); // g_settings_bind (prefs->priv->settings, KPM_SETTINGS_SPINDOWN_ENABLE_AC, // widget, "active", // G_SETTINGS_BIND_DEFAULT); /* 不是笔记本 */ if (prefs->priv->has_button_lid == FALSE) { widget = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "combobox_ac_lid")); #if GTK_CHECK_VERSION (2, 24, 0) gtk_widget_hide(widget); #else gtk_widget_hide_all (widget); #endif } /* 关于显示器的设置选项暂时去掉 */ if (prefs->priv->has_lcd == FALSE) { /* widget = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "viewport_ac_brightness")); #if GTK_CHECK_VERSION (2, 24, 0) gtk_widget_hide(widget); #else gtk_widget_hide_all (widget); #endif widget = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "viewport_ac_dim")); #if GTK_CHECK_VERSION (2, 24, 0) gtk_widget_hide(widget); #else gtk_widget_hide_all (widget); #endif */ } } static void set_insensitive(KpmPrefs *prefs, gchar *widget_name){ GtkWidget *widget; widget = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, widget_name)); gtk_widget_set_sensitive(widget, FALSE); } static void prefs_setup_battery (KpmPrefs *prefs) { GtkWidget *widget; GtkNotebook *notebook; gint page; const KpmActionPolicy button_lid_actions[] = {KPM_ACTION_POLICY_NOTHING, KPM_ACTION_POLICY_BLANK, KPM_ACTION_POLICY_SUSPEND, KPM_ACTION_POLICY_HIBERNATE, KPM_ACTION_POLICY_SHUTDOWN, -1}; const KpmActionPolicy battery_critical_actions[] = {KPM_ACTION_POLICY_NOTHING, KPM_ACTION_POLICY_SUSPEND, KPM_ACTION_POLICY_HIBERNATE, KPM_ACTION_POLICY_SHUTDOWN, -1}; static const gint computer_times[] = {10*60, 30*60, 1*60*60, 2*60*60, 0, /* never */ -1}; static const gint display_times[] = {1*60, 5*60, 10*60, 30*60, 1*60*60, 0, /* never */ -1}; kpm_prefs_setup_time_combo (prefs, "combobox_battery_computer", KPM_SETTINGS_SLEEP_COMPUTER_BATT, computer_times); kpm_prefs_setup_time_combo (prefs, "combobox_battery_display", KPM_SETTINGS_SLEEP_DISPLAY_BATT, display_times); if (prefs->priv->has_batteries == FALSE) { //notebook = GTK_NOTEBOOK (gtk_builder_get_object (prefs->priv->builder, "notebook_power_manager")); //widget = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "vbox_battery")); //page = gtk_notebook_page_num (notebook, GTK_WIDGET (widget)); //gtk_notebook_remove_page (notebook, page); //return; set_insensitive(prefs, "combobox_battery_computer"); set_insensitive(prefs, "combobox_battery_display"); //set_insensitive(prefs, "combobox_ac_lid"); set_insensitive(prefs, "combobox_battery_lid"); } kpm_prefs_setup_action_combo (prefs, "combobox_battery_lid", KPM_SETTINGS_BUTTON_LID_BATT, button_lid_actions); /* kpm_prefs_setup_action_combo (prefs, "combobox_battery_critical", KPM_SETTINGS_ACTION_CRITICAL_BATT, battery_critical_actions); */ /* set up the checkboxes */ /* widget = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "checkbutton_battery_display_reduce")); g_settings_bind (prefs->priv->settings, KPM_SETTINGS_BACKLIGHT_BATTERY_REDUCE, widget, "active", G_SETTINGS_BIND_DEFAULT); widget = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "checkbutton_battery_display_dim")); g_settings_bind (prefs->priv->settings, KPM_SETTINGS_IDLE_DIM_BATT, widget, "active", G_SETTINGS_BIND_DEFAULT); widget = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "checkbutton_battery_spindown")); g_settings_bind (prefs->priv->settings, KPM_SETTINGS_SPINDOWN_ENABLE_BATT, widget, "active", G_SETTINGS_BIND_DEFAULT); */ //如果不是笔记本,隐藏有关笔记本盖子的相关选项,并调整布局 if (prefs->priv->has_button_lid == FALSE) { widget = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "combobox_battery_lid")); GtkWidget *label = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "label65_laptop")); GtkWidget *layout_action = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "layout7_action")); GtkWidget *layout_power = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "layout5_power")); gtk_layout_move(GTK_LAYOUT(layout_power), layout_action, 0, 195); #if GTK_CHECK_VERSION(2, 24, 0) gtk_widget_hide(widget); gtk_widget_hide(label); #else gtk_widget_hide_all (widget); gtk_widget_hide(label); #endif } if (prefs->priv->has_lcd == FALSE) { //widget = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "viewport_battery_dim")); #if GTK_CHECK_VERSION(2, 24, 0) // gtk_widget_hide(widget); #else // gtk_widget_hide_all (widget); #endif } } static void prefs_setup_general (KpmPrefs *prefs) { GtkWidget *widget; const KpmActionPolicy power_button_actions[] = {KPM_ACTION_POLICY_INTERACTIVE, KPM_ACTION_POLICY_SUSPEND, KPM_ACTION_POLICY_HIBERNATE, KPM_ACTION_POLICY_SHUTDOWN, -1}; const KpmActionPolicy suspend_button_actions[] = {KPM_ACTION_POLICY_NOTHING, KPM_ACTION_POLICY_SUSPEND, KPM_ACTION_POLICY_HIBERNATE, -1}; kpm_prefs_setup_action_combo (prefs, "combobox_general_power", KPM_SETTINGS_BUTTON_POWER, power_button_actions); kpm_prefs_setup_action_combo (prefs, "combobox_general_suspend", KPM_SETTINGS_BUTTON_SUSPEND, suspend_button_actions); /*如果没有挂起按钮则要隐藏挂起的选项*/ if (prefs->priv->has_button_suspend == FALSE) { widget = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "combobox_general_suspend")); GtkWidget *widget_label = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "label37_suspend")); #if GTK_CHECK_VERSION (2, 24, 0) gtk_widget_hide (widget); gtk_widget_hide (widget_label); #else gtk_widget_hide_all (widget); gtk_widget_hide_all (widget_label); #endif } } /** * kpm_prefs_icon_radio_cb: * @widget: The GtkWidget object **/ static void kpm_prefs_icon_radio_cb (GtkWidget *widget, KpmPrefs *prefs) { gint policy; policy = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "policy")); g_settings_set_enum (prefs->priv->settings, KPM_SETTINGS_ICON_POLICY, policy); } /** setup the notification page */ static void prefs_setup_notification (KpmPrefs *prefs) { gint icon_policy; GtkWidget *radiobutton_icon_always; GtkWidget *radiobutton_icon_present; // GtkWidget *radiobutton_icon_charge; // GtkWidget *radiobutton_icon_low; // GtkWidget *radiobutton_icon_never; gboolean is_writable; icon_policy = g_settings_get_enum (prefs->priv->settings, KPM_SETTINGS_ICON_POLICY); radiobutton_icon_always = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "radiobutton_notification_always")); radiobutton_icon_present = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, "radiobutton_notification_present")); // radiobutton_icon_charge = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, // "radiobutton_notification_charge")); // radiobutton_icon_low = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, // "radiobutton_notification_low")); // radiobutton_icon_never = GTK_WIDGET (gtk_builder_get_object (prefs->priv->builder, // "radiobutton_notification_never")); is_writable = g_settings_is_writable (prefs->priv->settings, KPM_SETTINGS_ICON_POLICY); gtk_widget_set_sensitive (radiobutton_icon_always, is_writable); gtk_widget_set_sensitive (radiobutton_icon_present, is_writable); //gtk_widget_set_sensitive (radiobutton_icon_charge, is_writable); //gtk_widget_set_sensitive (radiobutton_icon_low, is_writable); //gtk_widget_set_sensitive (radiobutton_icon_never, is_writable); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radiobutton_icon_always), icon_policy == KPM_ICON_POLICY_ALWAYS); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radiobutton_icon_present), icon_policy == KPM_ICON_POLICY_PRESENT); /* gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radiobutton_icon_charge), icon_policy == KPM_ICON_POLICY_CHARGE); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radiobutton_icon_low), icon_policy == KPM_ICON_POLICY_LOW); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radiobutton_icon_never), icon_policy == KPM_ICON_POLICY_NEVER); */ g_object_set_data (G_OBJECT (radiobutton_icon_always), "policy", GINT_TO_POINTER (KPM_ICON_POLICY_ALWAYS)); g_object_set_data (G_OBJECT (radiobutton_icon_present), "policy", GINT_TO_POINTER (KPM_ICON_POLICY_PRESENT)); /* g_object_set_data (G_OBJECT (radiobutton_icon_charge), "policy", GINT_TO_POINTER (KPM_ICON_POLICY_CHARGE)); g_object_set_data (G_OBJECT (radiobutton_icon_low), "policy", GINT_TO_POINTER (KPM_ICON_POLICY_LOW)); g_object_set_data (G_OBJECT (radiobutton_icon_never), "policy", GINT_TO_POINTER (KPM_ICON_POLICY_NEVER)); */ /* only connect the callbacks after we set the value, else the settings * keys gets written to (for a split second), and the icon flickers. */ g_signal_connect (radiobutton_icon_always, "clicked", G_CALLBACK (kpm_prefs_icon_radio_cb), prefs); g_signal_connect (radiobutton_icon_present, "clicked", G_CALLBACK (kpm_prefs_icon_radio_cb), prefs); /* g_signal_connect (radiobutton_icon_charge, "clicked", G_CALLBACK (kpm_prefs_icon_radio_cb), prefs); g_signal_connect (radiobutton_icon_low, "clicked", G_CALLBACK (kpm_prefs_icon_radio_cb), prefs); g_signal_connect (radiobutton_icon_never, "clicked", G_CALLBACK (kpm_prefs_icon_radio_cb), prefs); */ } static void kpm_prefs_init (KpmPrefs *prefs) { GError *error = NULL; GPtrArray *devices = NULL; UpDevice *device; UpDeviceKind kind; KpmBrightness *brightness; #if !UP_CHECK_VERSION(0, 99, 0) gboolean ret; #endif guint i; GDBusProxy *proxy; GVariant *res, *inner; gchar * r; prefs->priv = KPM_PREFS_GET_PRIVATE (prefs); prefs->priv->client = up_client_new (); prefs->priv->console = egg_console_kit_new (); prefs->priv->settings = g_settings_new (KPM_SETTINGS_SCHEMA); prefs->priv->can_shutdown = FALSE; prefs->priv->can_suspend = FALSE; prefs->priv->can_hibernate = FALSE; prefs->priv->builder = builder; if (LOGIND_RUNNING()) { /* get values from logind */ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", NULL, &error ); if (proxy == NULL) { egg_error("Error connecting to dbus - %s", error->message); g_error_free (error); return; } res = g_dbus_proxy_call_sync (proxy, "CanPowerOff", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error ); if (error == NULL && res != NULL) { g_variant_get(res,"(s)", &r); prefs->priv->can_shutdown = g_strcmp0(r,"yes")==0?TRUE:FALSE; g_variant_unref (res); } else if (error != NULL ) { egg_error ("Error in dbus - %s", error->message); g_error_free (error); } res = g_dbus_proxy_call_sync (proxy, "CanSuspend", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error ); if (error == NULL && res != NULL) { g_variant_get(res,"(s)", &r); prefs->priv->can_suspend = g_strcmp0(r,"yes")==0?TRUE:FALSE; g_variant_unref (res); } else if (error != NULL ) { egg_error ("Error in dbus - %s", error->message); g_error_free (error); } res = g_dbus_proxy_call_sync (proxy, "CanHibernate", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error ); if (error == NULL && res != NULL) { g_variant_get(res,"(s)", &r); prefs->priv->can_hibernate = g_strcmp0(r,"yes")==0?TRUE:FALSE; g_variant_unref (res); } else if (error != NULL ) { egg_error ("Error in dbus - %s", error->message); g_error_free (error); } g_object_unref(proxy); } else { /* are we allowed to shutdown? */ egg_console_kit_can_stop (prefs->priv->console, &prefs->priv->can_shutdown, NULL); #if !UP_CHECK_VERSION(0, 99, 0) /* get values from UpClient */ prefs->priv->can_suspend = up_client_get_can_suspend (prefs->priv->client); prefs->priv->can_hibernate = up_client_get_can_hibernate (prefs->priv->client); #endif } if (LOGIND_RUNNING()) { proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, "org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.DBus.Properties", NULL, &error ); if (proxy == NULL) { egg_error("Error connecting to dbus - %s", error->message); g_error_free (error); return; } res = g_dbus_proxy_call_sync (proxy, "Get", g_variant_new( "(ss)", "org.freedesktop.UPower", "LidIsPresent"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error ); if (error == NULL && res != NULL) { g_variant_get(res, "(v)", &inner ); prefs->priv->has_button_lid = g_variant_get_boolean(inner); g_variant_unref (inner); g_variant_unref (res); } else if (error != NULL ) { egg_error ("Error in dbus - %s", error->message); g_error_free (error); } g_object_unref(proxy); } else { #if UP_CHECK_VERSION(0,9,2) prefs->priv->has_button_lid = up_client_get_lid_is_present (prefs->priv->client); #else g_object_get (prefs->priv->client, "lid-is-present", &prefs->priv->has_button_lid, NULL); #endif } prefs->priv->has_button_suspend = TRUE; /* find if we have brightness hardware */ brightness = kpm_brightness_new (); prefs->priv->has_lcd = kpm_brightness_has_hw (brightness); g_object_unref (brightness); #if !UP_CHECK_VERSION(0, 99, 0) /* get device list */ ret = up_client_enumerate_devices_sync (prefs->priv->client, NULL, &error); if (!ret) { egg_warning ("failed to get device list: %s", error->message); g_error_free (error); } #endif devices = up_client_get_devices (prefs->priv->client); for (i=0; ilen; i++) { device = g_ptr_array_index (devices, i); g_object_get (device, "kind", &kind, NULL); if (kind == UP_DEVICE_KIND_BATTERY) prefs->priv->has_batteries = TRUE; if (kind == UP_DEVICE_KIND_UPS) prefs->priv->has_ups = TRUE; } g_ptr_array_unref (devices); prefs_setup_ac (prefs); //prefs_setup_screensaver(prefs); prefs_setup_battery (prefs); prefs_setup_general (prefs); prefs_setup_notification (prefs); } /** * kpm_prefs_new: * Return value: new KpmPrefs instance. **/ KpmPrefs * kpm_prefs_new (void) { KpmPrefs *prefs; prefs = g_object_new (KPM_TYPE_PREFS, NULL); return KPM_PREFS (prefs); } void init_power() { g_warning("power"); screensaver_init(builder); kpm_prefs_new(); } ukui-control-center/panels/power/kpm-marshal.list0000664000175000017500000000047113057175444021154 0ustar fengfengNONE:INT,BOXED NONE:STRING,STRING NONE:POINTER,STRING,STRING NONE:UINT,UINT,BOOL NONE:STRING,STRING,STRING NONE:STRING,BOOLEAN NONE:STRING,STRING,BOOLEAN NONE:STRING,STRING,BOOLEAN,BOOLEAN,BOOLEAN NONE:INT NONE:STRING NONE:INT,LONG,BOOLEAN,BOOLEAN NONE:BOOLEAN,BOOLEAN NONE:UINT NONE:UINT,UINT NONE:UINT,POINTER ukui-control-center/panels/power/org.ukui.PowerManager.Backlight.xml0000664000175000017500000000074013253611037024573 0ustar fengfeng ukui-control-center/panels/power/egg-test.h0000664000175000017500000000366313057175444017741 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #ifndef __EGG_TEST_H #define __EGG_TEST_H #include #include typedef struct EggTest EggTest; gboolean egg_test_start (EggTest *test, const gchar *name); void egg_test_end (EggTest *test); void egg_test_title (EggTest *test, const gchar *format, ...); void egg_test_title_assert (EggTest *test, const gchar *text, gboolean value); void egg_test_assert (EggTest *test, gboolean value); void egg_test_success (EggTest *test, const gchar *format, ...); void egg_test_failed (EggTest *test, const gchar *format, ...) G_GNUC_NORETURN; EggTest *egg_test_init (void); gint egg_test_finish (EggTest *test); guint egg_test_elapsed (EggTest *test); void egg_test_loop_quit (EggTest *test); void egg_test_loop_wait (EggTest *test, guint timeout); void egg_test_loop_check (EggTest *test); void egg_test_set_user_data (EggTest *test, gpointer user_data); gpointer egg_test_get_user_data (EggTest *test); gchar *egg_test_get_data_file (const gchar *filename); #endif /* __EGG_TEST_H */ ukui-control-center/panels/power/subprocs.h0000664000175000017500000000217213245450076020050 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * subprocs.c --- choosing, spawning, and killing screenhacks. * * xscreensaver, Copyright (c) 1991-2003 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation. No representations are made about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. */ #ifndef __GS_SUBPROCS_H #define __GS_SUBPROCS_H #include #include G_BEGIN_DECLS void unblock_sigchld (void); #ifdef HAVE_SIGACTION sigset_t #else /* !HAVE_SIGACTION */ int #endif /* !HAVE_SIGACTION */ block_sigchld (void); int signal_pid (int pid, int signal); void await_dying_children (int pid, gboolean debug); G_END_DECLS #endif /* __GS_SUBPROCS_H */ ukui-control-center/panels/power/egg-discrete.c0000664000175000017500000001121313057175444020545 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #include #include #include #include #include "egg-debug.h" #include "egg-discrete.h" /** * egg_discrete_from_percent: * @percentage: The percentage to convert * @levels: The number of discrete levels * * We have to be carefull when converting from %->discrete as precision is very * important if we want the highest value. * * Return value: The discrete value for this percentage. **/ guint egg_discrete_from_percent (guint percentage, guint levels) { /* check we are in range */ if (percentage > 100) return levels; if (levels == 0) { egg_warning ("levels is 0!"); return 0; } return (guint) ((((gfloat) percentage * (gfloat) (levels - 1)) / 100.0f) + 0.5f); } /** * egg_discrete_to_percent: * @hw: The discrete level * @levels: The number of discrete levels * * We have to be carefull when converting from discrete->%. * * Return value: The percentage for this discrete value. **/ guint egg_discrete_to_percent (guint discrete, guint levels) { /* check we are in range */ if (discrete > levels) return 100; if (levels == 0) { egg_warning ("levels is 0!"); return 0; } return (guint) (((gfloat) discrete * (100.0f / (gfloat) (levels - 1))) + 0.5f); } /** * egg_discrete_to_fraction: * @hw: The discrete level * @levels: The number of discrete levels * * We have to be careful when converting from discrete->fractions. * * Return value: The floating point fraction (0..1) for this discrete value. **/ gfloat egg_discrete_to_fraction (guint discrete, guint levels) { /* check we are in range */ if (discrete > levels) return 1.0; if (levels == 0) { egg_warning ("levels is 0!"); return 0.0; } return (guint) ((gfloat) discrete / ((gfloat) (levels - 1))); } /*************************************************************************** *** MAKE CHECK TESTS *** ***************************************************************************/ #ifdef EGG_TEST #include "egg-test.h" void egg_discrete_test (gpointer data) { guint value; gfloat fvalue; EggTest *test = (EggTest *) data; if (!egg_test_start (test, "EggDiscrete")) return; /************************************************************/ egg_test_title (test, "convert discrete 0/10 levels"); value = egg_discrete_to_percent (0, 10); if (value == 0) { egg_test_success (test, "got %i", value); } else { egg_test_failed (test, "conversion incorrect (%i)", value); } /************************************************************/ egg_test_title (test, "convert discrete 9/10 levels"); value = egg_discrete_to_percent (9, 10); if (value == 100) { egg_test_success (test, "got %i", value); } else { egg_test_failed (test, "conversion incorrect (%i)", value); } /************************************************************/ egg_test_title (test, "convert discrete 20/10 levels"); value = egg_discrete_to_percent (20, 10); if (value == 100) { egg_test_success (test, "got %i", value); } else { egg_test_failed (test, "conversion incorrect (%i)", value); } /************************************************************/ egg_test_title (test, "convert discrete 0/10 levels"); fvalue = egg_discrete_to_fraction (0, 10); if (fvalue > -0.01 && fvalue < 0.01) { egg_test_success (test, "got %f", fvalue); } else { egg_test_failed (test, "conversion incorrect (%f)", fvalue); } /************************************************************/ egg_test_title (test, "convert discrete 9/10 levels"); fvalue = egg_discrete_to_fraction (9, 10); if (fvalue > -1.01 && fvalue < 1.01) { egg_test_success (test, "got %f", fvalue); } else { egg_test_failed (test, "conversion incorrect (%f)", fvalue); } egg_test_end (test); } #endif ukui-control-center/panels/power/egg-idletime.c0000664000175000017500000004452713057175444020555 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2009 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include "egg-idletime.h" static void egg_idletime_finalize (GObject *object); #define EGG_IDLETIME_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_IDLETIME_TYPE, EggIdletimePrivate)) struct EggIdletimePrivate { gint sync_event; gboolean reset_set; XSyncCounter idle_counter; GPtrArray *array; Display *dpy; }; typedef struct { guint id; XSyncValue timeout; XSyncAlarm xalarm; EggIdletime *idletime; } EggIdletimeAlarm; enum { SIGNAL_ALARM_EXPIRED, SIGNAL_RESET, LAST_SIGNAL }; typedef enum { EGG_IDLETIME_ALARM_TYPE_POSITIVE, EGG_IDLETIME_ALARM_TYPE_NEGATIVE, EGG_IDLETIME_ALARM_TYPE_DISABLED } EggIdletimeAlarmType; static guint signals [LAST_SIGNAL] = { 0 }; static gpointer egg_idletime_object = NULL; G_DEFINE_TYPE (EggIdletime, egg_idletime, G_TYPE_OBJECT) /** * egg_idletime_xsyncvalue_to_int64: */ static gint64 egg_idletime_xsyncvalue_to_int64 (XSyncValue value) { return ((guint64) XSyncValueHigh32 (value)) << 32 | (guint64) XSyncValueLow32 (value); } /** * egg_idletime_get_time: */ gint64 egg_idletime_get_time (EggIdletime *idletime) { XSyncValue value; XSyncQueryCounter (idletime->priv->dpy, idletime->priv->idle_counter, &value); return egg_idletime_xsyncvalue_to_int64 (value); } /** * egg_idletime_xsync_alarm_set: */ static void egg_idletime_xsync_alarm_set (EggIdletime *idletime, EggIdletimeAlarm *alarm, EggIdletimeAlarmType alarm_type) { XSyncAlarmAttributes attr; XSyncValue delta; unsigned int flags; XSyncTestType test; /* just remove it */ if (alarm_type == EGG_IDLETIME_ALARM_TYPE_DISABLED) { if (alarm->xalarm) { XSyncDestroyAlarm (idletime->priv->dpy, alarm->xalarm); alarm->xalarm = None; } return; } /* which way do we do the test? */ if (alarm_type == EGG_IDLETIME_ALARM_TYPE_POSITIVE) test = XSyncPositiveTransition; else test = XSyncNegativeTransition; XSyncIntToValue (&delta, 0); attr.trigger.counter = idletime->priv->idle_counter; attr.trigger.value_type = XSyncAbsolute; attr.trigger.test_type = test; attr.trigger.wait_value = alarm->timeout; attr.delta = delta; flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType | XSyncCAValue | XSyncCADelta; if (alarm->xalarm) XSyncChangeAlarm (idletime->priv->dpy, alarm->xalarm, flags, &attr); else alarm->xalarm = XSyncCreateAlarm (idletime->priv->dpy, flags, &attr); } /** * egg_idletime_alarm_reset_all: */ void egg_idletime_alarm_reset_all (EggIdletime *idletime) { guint i; EggIdletimeAlarm *alarm; g_return_if_fail (EGG_IS_IDLETIME (idletime)); if (!idletime->priv->reset_set) return; /* reset all the alarms (except the reset alarm) to their timeouts */ for (i=1; ipriv->array->len; i++) { alarm = g_ptr_array_index (idletime->priv->array, i); egg_idletime_xsync_alarm_set (idletime, alarm, EGG_IDLETIME_ALARM_TYPE_POSITIVE); } /* set the reset alarm to be disabled */ alarm = g_ptr_array_index (idletime->priv->array, 0); egg_idletime_xsync_alarm_set (idletime, alarm, EGG_IDLETIME_ALARM_TYPE_DISABLED); /* emit signal so say we've reset all timers */ g_signal_emit (idletime, signals [SIGNAL_RESET], 0); /* we need to be reset again on the next event */ idletime->priv->reset_set = FALSE; } /** * egg_idletime_alarm_find_id: */ static EggIdletimeAlarm * egg_idletime_alarm_find_id (EggIdletime *idletime, guint id) { guint i; EggIdletimeAlarm *alarm; for (i=0; ipriv->array->len; i++) { alarm = g_ptr_array_index (idletime->priv->array, i); if (alarm->id == id) return alarm; } return NULL; } /** * egg_idletime_set_reset_alarm: */ static void egg_idletime_set_reset_alarm (EggIdletime *idletime, XSyncAlarmNotifyEvent *alarm_event) { EggIdletimeAlarm *alarm; int overflow; XSyncValue add; gint64 current, reset_threshold; alarm = egg_idletime_alarm_find_id (idletime, 0); if (!idletime->priv->reset_set) { /* don't match on the current value because * XSyncNegativeComparison means less or equal. */ XSyncIntToValue (&add, -1); XSyncValueAdd (&alarm->timeout, alarm_event->counter_value, add, &overflow); /* set the reset alarm to fire the next time * idletime->priv->idle_counter < the current counter value */ egg_idletime_xsync_alarm_set (idletime, alarm, EGG_IDLETIME_ALARM_TYPE_NEGATIVE); /* don't try to set this again if multiple timers are going off in sequence */ idletime->priv->reset_set = TRUE; current = egg_idletime_get_time (idletime); reset_threshold = egg_idletime_xsyncvalue_to_int64 (alarm->timeout); if (current < reset_threshold) { /* We've missed the alarm already */ egg_idletime_alarm_reset_all (idletime); } } } /** * egg_idletime_alarm_find_event: */ static EggIdletimeAlarm * egg_idletime_alarm_find_event (EggIdletime *idletime, XSyncAlarmNotifyEvent *alarm_event) { guint i; EggIdletimeAlarm *alarm; for (i=0; ipriv->array->len; i++) { alarm = g_ptr_array_index (idletime->priv->array, i); if (alarm_event->alarm == alarm->xalarm) return alarm; } return NULL; } /** * egg_idletime_event_filter_cb: */ static GdkFilterReturn egg_idletime_event_filter_cb (GdkXEvent *gdkxevent, GdkEvent *event, gpointer data) { EggIdletimeAlarm *alarm; XEvent *xevent = (XEvent *) gdkxevent; EggIdletime *idletime = (EggIdletime *) data; XSyncAlarmNotifyEvent *alarm_event; /* no point continuing */ if (xevent->type != idletime->priv->sync_event + XSyncAlarmNotify) return GDK_FILTER_CONTINUE; alarm_event = (XSyncAlarmNotifyEvent *) xevent; /* did we match one of our alarms? */ alarm = egg_idletime_alarm_find_event (idletime, alarm_event); if (alarm == NULL) return GDK_FILTER_CONTINUE; /* are we the reset alarm? */ if (alarm->id == 0) { egg_idletime_alarm_reset_all (idletime); goto out; } /* emit */ g_signal_emit (alarm->idletime, signals [SIGNAL_ALARM_EXPIRED], 0, alarm->id); /* we need the first alarm to go off to set the reset alarm */ egg_idletime_set_reset_alarm (idletime, alarm_event); out: /* don't propagate */ return GDK_FILTER_REMOVE; } /** * egg_idletime_alarm_new: */ static EggIdletimeAlarm * egg_idletime_alarm_new (EggIdletime *idletime, guint id) { EggIdletimeAlarm *alarm; /* create a new alarm */ alarm = g_new0 (EggIdletimeAlarm, 1); /* set the default values */ alarm->id = id; alarm->xalarm = None; alarm->idletime = g_object_ref (idletime); return alarm; } /** * egg_idletime_alarm_set: */ gboolean egg_idletime_alarm_set (EggIdletime *idletime, guint id, guint timeout) { EggIdletimeAlarm *alarm; g_return_val_if_fail (EGG_IS_IDLETIME (idletime), FALSE); g_return_val_if_fail (id != 0, FALSE); g_return_val_if_fail (timeout != 0, FALSE); /* see if we already created an alarm with this ID */ alarm = egg_idletime_alarm_find_id (idletime, id); if (alarm == NULL) { /* create a new alarm */ alarm = egg_idletime_alarm_new (idletime, id); /* add to array */ g_ptr_array_add (idletime->priv->array, alarm); } /* set the timeout */ XSyncIntToValue (&alarm->timeout, (gint)timeout); /* set, and start the timer */ egg_idletime_xsync_alarm_set (idletime, alarm, EGG_IDLETIME_ALARM_TYPE_POSITIVE); return TRUE; } /** * egg_idletime_alarm_free: */ static gboolean egg_idletime_alarm_free (EggIdletime *idletime, EggIdletimeAlarm *alarm) { g_return_val_if_fail (EGG_IS_IDLETIME (idletime), FALSE); g_return_val_if_fail (alarm != NULL, FALSE); if (alarm->xalarm) XSyncDestroyAlarm (idletime->priv->dpy, alarm->xalarm); g_object_unref (alarm->idletime); g_free (alarm); g_ptr_array_remove (idletime->priv->array, alarm); return TRUE; } /** * egg_idletime_alarm_free: */ gboolean egg_idletime_alarm_remove (EggIdletime *idletime, guint id) { EggIdletimeAlarm *alarm; g_return_val_if_fail (EGG_IS_IDLETIME (idletime), FALSE); alarm = egg_idletime_alarm_find_id (idletime, id); if (alarm == NULL) return FALSE; egg_idletime_alarm_free (idletime, alarm); return TRUE; } /** * egg_idletime_class_init: **/ static void egg_idletime_class_init (EggIdletimeClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = egg_idletime_finalize; g_type_class_add_private (klass, sizeof (EggIdletimePrivate)); signals [SIGNAL_ALARM_EXPIRED] = g_signal_new ("alarm-expired", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggIdletimeClass, alarm_expired), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [SIGNAL_RESET] = g_signal_new ("reset", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggIdletimeClass, reset), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } /** * egg_idletime_init: **/ static void egg_idletime_init (EggIdletime *idletime) { int sync_error; int ncounters; XSyncSystemCounter *counters; EggIdletimeAlarm *alarm; guint i; idletime->priv = EGG_IDLETIME_GET_PRIVATE (idletime); idletime->priv->array = g_ptr_array_new (); idletime->priv->reset_set = FALSE; idletime->priv->idle_counter = None; idletime->priv->sync_event = 0; idletime->priv->dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default()); /* get the sync event */ if (!XSyncQueryExtension (idletime->priv->dpy, &idletime->priv->sync_event, &sync_error)) { g_warning ("No Sync extension."); return; } /* gtk_init should do XSyncInitialize for us */ counters = XSyncListSystemCounters (idletime->priv->dpy, &ncounters); for (i=0; i < ncounters && !idletime->priv->idle_counter; i++) { if (strcmp(counters[i].name, "IDLETIME") == 0) idletime->priv->idle_counter = counters[i].counter; } XSyncFreeSystemCounterList (counters); /* arh. we don't have IDLETIME support */ if (!idletime->priv->idle_counter) { g_warning ("No idle counter."); return; } /* catch the timer alarm */ gdk_window_add_filter (NULL, egg_idletime_event_filter_cb, idletime); /* create a reset alarm */ alarm = egg_idletime_alarm_new (idletime, 0); g_ptr_array_add (idletime->priv->array, alarm); } /** * egg_idletime_finalize: **/ static void egg_idletime_finalize (GObject *object) { guint i; EggIdletime *idletime; EggIdletimeAlarm *alarm; g_return_if_fail (object != NULL); g_return_if_fail (EGG_IS_IDLETIME (object)); idletime = EGG_IDLETIME (object); idletime->priv = EGG_IDLETIME_GET_PRIVATE (idletime); /* free all counters, including reset counter */ for (i=0; ipriv->array->len; i++) { alarm = g_ptr_array_index (idletime->priv->array, i); egg_idletime_alarm_free (idletime, alarm); } g_ptr_array_free (idletime->priv->array, TRUE); G_OBJECT_CLASS (egg_idletime_parent_class)->finalize (object); } /** * egg_idletime_new: **/ EggIdletime * egg_idletime_new (void) { if (egg_idletime_object != NULL) { g_object_ref (egg_idletime_object); } else { egg_idletime_object = g_object_new (EGG_IDLETIME_TYPE, NULL); g_object_add_weak_pointer (egg_idletime_object, &egg_idletime_object); } return EGG_IDLETIME (egg_idletime_object); } /*************************************************************************** *** MAKE CHECK TESTS *** ***************************************************************************/ #ifdef EGG_TEST #include "egg-test.h" static void egg_test_egg_idletime_wait (guint time_ms) { GTimer *ltimer = g_timer_new (); gfloat goal = time_ms / (gfloat) 1000.0f; do { g_main_context_iteration (NULL, FALSE); } while (g_timer_elapsed (ltimer, NULL) < goal); g_timer_destroy (ltimer); } static guint last_alarm = 0; static guint event_time; GTimer *timer; static void gpm_alarm_expired_cb (EggIdletime *idletime, guint alarm, gpointer data) { last_alarm = alarm; event_time = g_timer_elapsed (timer, NULL) * (gfloat) 1000.0f; // g_print ("[evt %i in %ims]\n", alarm, event_time); } static void wait_until_alarm (void) { g_print ("*****************************\n"); g_print ("*** DO NOT MOVE THE MOUSE ***\n"); g_print ("*****************************\n"); while (last_alarm == 0) g_main_context_iteration (NULL, FALSE); } static void wait_until_reset (void) { if (last_alarm == 0) return; g_print ("*****************************\n"); g_print ("*** MOVE THE MOUSE ***\n"); g_print ("*****************************\n"); while (last_alarm != 0) g_main_context_iteration (NULL, FALSE); egg_test_egg_idletime_wait (1000); } void egg_idletime_test (gpointer data) { EggIdletime *idletime; gboolean ret; guint i; EggTest *test = (EggTest *) data; if (egg_test_start (test, "EggIdletime") == FALSE) return; timer = g_timer_new (); gdk_init (NULL, NULL); /* warn */ g_timer_start (timer); /************************************************************/ egg_test_title (test, "check to see if delay works as expected"); egg_test_egg_idletime_wait (2000); event_time = g_timer_elapsed (timer, NULL) * (gfloat) 1000.0f; if (event_time > 1800 && event_time < 2200) { egg_test_success (test, "time %i~=%i", 2000, event_time); } else { egg_test_failed (test, "time not the same! %i != %i", event_time, 2000); } /************************************************************/ egg_test_title (test, "make sure we get a non null device"); idletime = egg_idletime_new (); if (idletime != NULL) { egg_test_success (test, "got EggIdletime"); } else { egg_test_failed (test, "could not get EggIdletime"); } g_signal_connect (idletime, "alarm-expired", G_CALLBACK (gpm_alarm_expired_cb), NULL); /************************************************************/ egg_test_title (test, "check if we are alarm zero with no alarms"); if (last_alarm == 0) { egg_test_success (test, NULL); } else { egg_test_failed (test, "alarm %i set!", last_alarm); } /************************************************************/ egg_test_title (test, "check if we can set an reset alarm"); ret = egg_idletime_alarm_set (idletime, 0, 100); if (!ret) { egg_test_success (test, "ignored reset alarm"); } else { egg_test_failed (test, "did not ignore reset alarm"); } /************************************************************/ egg_test_title (test, "check if we can set an alarm timeout of zero"); ret = egg_idletime_alarm_set (idletime, 999, 0); if (!ret) { egg_test_success (test, "ignored invalid alarm"); } else { egg_test_failed (test, "did not ignore invalid alarm"); } /************************************************************/ g_timer_start (timer); egg_test_title (test, "check if we can set an alarm"); ret = egg_idletime_alarm_set (idletime, 101, 5000); if (ret) { egg_test_success (test, "set alarm okay"); } else { egg_test_failed (test, "could not set alarm"); } egg_idletime_alarm_set (idletime, 101, 5000); wait_until_alarm (); /* loop this two times */ for (i=0; i<2; i++) { /* just let it time out, and wait for human input */ wait_until_reset (); g_timer_start (timer); /************************************************************/ g_timer_start (timer); egg_test_title (test, "check if we can set an alarm"); ret = egg_idletime_alarm_set (idletime, 101, 5000); if (ret) { egg_test_success (test, "set alarm 5000ms okay"); } else { egg_test_failed (test, "could not set alarm 5000ms"); } /* wait for alarm to go off */ wait_until_alarm (); g_timer_start (timer); /************************************************************/ egg_test_title (test, "check if correct alarm has gone off"); if (last_alarm == 101) { egg_test_success (test, "correct alarm"); } else { egg_test_failed (test, "alarm %i set!", last_alarm); } /************************************************************/ egg_test_title (test, "check if alarm has gone off in correct time"); if (event_time > 3000 && event_time < 6000) { egg_test_success (test, "correct, timeout ideally %ims (we did after %ims)", 5000, event_time); } else { egg_test_failed (test, "alarm %i did not timeout correctly !", last_alarm); } } /* just let it time out, and wait for human input */ wait_until_reset (); g_timer_start (timer); /************************************************************/ g_timer_start (timer); egg_test_title (test, "check if we can set an existing alarm"); ret = egg_idletime_alarm_set (idletime, 101, 10000); if (ret) { egg_test_success (test, "set alarm 10000ms okay"); } else { egg_test_failed (test, "could not set alarm 10000ms"); } /* wait for alarm to go off */ wait_until_alarm (); g_timer_start (timer); /************************************************************/ egg_test_title (test, "check if alarm has gone off in the old time"); if (event_time > 5000) { egg_test_success (test, "last timeout value used"); } else { egg_test_failed (test, "incorrect timeout used %ims", event_time); } /************************************************************/ egg_test_title (test, "check if we can remove an invalid alarm"); ret = egg_idletime_alarm_remove (idletime, 202); if (!ret) { egg_test_success (test, "ignored invalid alarm"); } else { egg_test_failed (test, "removed invalid alarm"); } /************************************************************/ egg_test_title (test, "check if we can remove an valid alarm"); ret = egg_idletime_alarm_remove (idletime, 101); if (ret) { egg_test_success (test, "removed valid alarm"); } else { egg_test_failed (test, "failed to remove valid alarm"); } g_timer_destroy (timer); g_object_unref (idletime); egg_test_end (test); } #endif ukui-control-center/panels/power/gs-prefs.c0000664000175000017500000003560013245450076017733 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2004-2006 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * * Authors: William Jon McCann * */ #include "config.h" #include #include #include #include #include "gs-prefs.h" static void gs_prefs_class_init (GSPrefsClass *klass); static void gs_prefs_init (GSPrefs *prefs); static void gs_prefs_finalize (GObject *object); #define LOCKDOWN_SETTINGS_SCHEMA "org.mate.lockdown" #define KEY_LOCK_DISABLE "disable-lock-screen" #define KEY_USER_SWITCH_DISABLE "disable-user-switching" #define SESSION_SETTINGS_SCHEMA "org.ukui.session" #define KEY_IDLE_DELAY "idle-delay" #define GSETTINGS_SCHEMA "org.ukui.screensaver" #define KEY_IDLE_ACTIVATION_ENABLED "idle-activation-enabled" #define KEY_LOCK_ENABLED "lock-enabled" #define KEY_MODE "mode" #define KEY_POWER_DELAY "power-management-delay" #define KEY_LOCK_DELAY "lock-delay" #define KEY_CYCLE_DELAY "cycle-delay" #define KEY_THEMES "themes" #define KEY_USER_SWITCH_ENABLED "user-switch-enabled" #define KEY_LOGOUT_ENABLED "logout-enabled" #define KEY_LOGOUT_DELAY "logout-delay" #define KEY_LOGOUT_COMMAND "logout-command" #define KEY_KEYBOARD_ENABLED "embedded-keyboard-enabled" #define KEY_KEYBOARD_COMMAND "embedded-keyboard-command" #define KEY_STATUS_MESSAGE_ENABLED "status-message-enabled" #define GS_PREFS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_PREFS, GSPrefsPrivate)) struct GSPrefsPrivate { GSettings *settings; GSettings *lockdown_settings; GSettings *session_settings; }; enum { CHANGED, LAST_SIGNAL }; enum { PROP_0 }; static guint signals [LAST_SIGNAL] = { 0, }; G_DEFINE_TYPE (GSPrefs, gs_prefs, G_TYPE_OBJECT) static void gs_prefs_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gs_prefs_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gs_prefs_class_init (GSPrefsClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gs_prefs_finalize; object_class->get_property = gs_prefs_get_property; object_class->set_property = gs_prefs_set_property; signals [CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GSPrefsClass, changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); g_type_class_add_private (klass, sizeof (GSPrefsPrivate)); } static void _gs_prefs_set_timeout (GSPrefs *prefs, int value) { if (value < 1) value = 10; /* pick a reasonable large number for the upper bound */ if (value > 480) value = 480; prefs->timeout = value * 60000; } static void _gs_prefs_set_power_timeout (GSPrefs *prefs, int value) { if (value < 1) value = 60; /* pick a reasonable large number for the upper bound */ if (value > 480) value = 480; /* this value is in seconds - others are in minutes */ prefs->power_timeout = value * 1000; } static void _gs_prefs_set_lock_timeout (GSPrefs *prefs, int value) { if (value < 0) value = 0; /* pick a reasonable large number for the upper bound */ if (value > 480) value = 480; prefs->lock_timeout = value * 60000; } static void _gs_prefs_set_cycle_timeout (GSPrefs *prefs, int value) { if (value < 1) value = 1; /* pick a reasonable large number for the upper bound */ if (value > 480) value = 480; prefs->cycle = value * 60000; } static void _gs_prefs_set_mode (GSPrefs *prefs, gint mode) { prefs->mode = mode; } static void _gs_prefs_set_themes (GSPrefs *prefs, gchar **values) { guint i; if (prefs->themes) { g_slist_foreach (prefs->themes, (GFunc)g_free, NULL); g_slist_free (prefs->themes); } /* take ownership of the list */ prefs->themes = NULL; for (i=0; values[i] != NULL; i++) prefs->themes = g_slist_append (prefs->themes, g_strdup (values[i])); } static void _gs_prefs_set_idle_activation_enabled (GSPrefs *prefs, gboolean value) { prefs->idle_activation_enabled = value; } static void _gs_prefs_set_lock_enabled (GSPrefs *prefs, gboolean value) { prefs->lock_enabled = value; } static void _gs_prefs_set_lock_disabled (GSPrefs *prefs, gboolean value) { prefs->lock_disabled = value; } static void _gs_prefs_set_user_switch_disabled (GSPrefs *prefs, gboolean value) { prefs->user_switch_disabled = value; } static void _gs_prefs_set_keyboard_enabled (GSPrefs *prefs, gboolean value) { prefs->keyboard_enabled = value; } static void _gs_prefs_set_keyboard_command (GSPrefs *prefs, const char *value) { g_free (prefs->keyboard_command); prefs->keyboard_command = NULL; if (value) { /* FIXME: check command */ prefs->keyboard_command = g_strdup (value); } } static void _gs_prefs_set_status_message_enabled (GSPrefs *prefs, gboolean enabled) { prefs->status_message_enabled = enabled; } static void _gs_prefs_set_logout_enabled (GSPrefs *prefs, gboolean value) { prefs->logout_enabled = value; } static void _gs_prefs_set_logout_command (GSPrefs *prefs, const char *value) { g_free (prefs->logout_command); prefs->logout_command = NULL; if (value) { /* FIXME: check command */ prefs->logout_command = g_strdup (value); } } static void _gs_prefs_set_logout_timeout (GSPrefs *prefs, int value) { if (value < 0) value = 0; /* pick a reasonable large number for the upper bound */ if (value > 480) value = 480; prefs->logout_timeout = value * 60000; } static void _gs_prefs_set_user_switch_enabled (GSPrefs *prefs, gboolean value) { prefs->user_switch_enabled = value; } static void gs_prefs_load_from_settings (GSPrefs *prefs) { glong value; gboolean bvalue; char *string; gchar **strv; gint mode; bvalue = g_settings_get_boolean (prefs->priv->settings, KEY_IDLE_ACTIVATION_ENABLED); _gs_prefs_set_idle_activation_enabled (prefs, bvalue); bvalue = g_settings_get_boolean (prefs->priv->settings, KEY_LOCK_ENABLED); _gs_prefs_set_lock_enabled (prefs, bvalue); bvalue = g_settings_get_boolean (prefs->priv->lockdown_settings, KEY_LOCK_DISABLE); _gs_prefs_set_lock_disabled (prefs, bvalue); bvalue = g_settings_get_boolean (prefs->priv->lockdown_settings, KEY_USER_SWITCH_DISABLE); _gs_prefs_set_user_switch_disabled (prefs, bvalue); value = g_settings_get_int (prefs->priv->session_settings, KEY_IDLE_DELAY); _gs_prefs_set_timeout (prefs, value); value = g_settings_get_int (prefs->priv->settings, KEY_POWER_DELAY); _gs_prefs_set_power_timeout (prefs, value); value = g_settings_get_int (prefs->priv->settings, KEY_LOCK_DELAY); _gs_prefs_set_lock_timeout (prefs, value); value = g_settings_get_int (prefs->priv->settings, KEY_CYCLE_DELAY); _gs_prefs_set_cycle_timeout (prefs, value); mode = g_settings_get_enum (prefs->priv->settings, KEY_MODE); _gs_prefs_set_mode (prefs, mode); strv = g_settings_get_strv (prefs->priv->settings, KEY_THEMES); _gs_prefs_set_themes (prefs, strv); g_strfreev (strv); /* Embedded keyboard options */ bvalue = g_settings_get_boolean (prefs->priv->settings, KEY_KEYBOARD_ENABLED); _gs_prefs_set_keyboard_enabled (prefs, bvalue); string = g_settings_get_string (prefs->priv->settings, KEY_KEYBOARD_COMMAND); _gs_prefs_set_keyboard_command (prefs, string); g_free (string); bvalue = g_settings_get_boolean (prefs->priv->settings, KEY_STATUS_MESSAGE_ENABLED); _gs_prefs_set_status_message_enabled (prefs, bvalue); /* Logout options */ bvalue = g_settings_get_boolean (prefs->priv->settings, KEY_LOGOUT_ENABLED); _gs_prefs_set_logout_enabled (prefs, bvalue); string = g_settings_get_string (prefs->priv->settings, KEY_LOGOUT_COMMAND); _gs_prefs_set_logout_command (prefs, string); g_free (string); value = g_settings_get_int (prefs->priv->settings, KEY_LOGOUT_DELAY); _gs_prefs_set_logout_timeout (prefs, value); /* User switching options */ bvalue = g_settings_get_boolean (prefs->priv->settings, KEY_USER_SWITCH_ENABLED); _gs_prefs_set_user_switch_enabled (prefs, bvalue); } static void key_changed_cb (GSettings *settings, gchar *key, GSPrefs *prefs) { if (strcmp (key, KEY_MODE) == 0) { gint mode; mode = g_settings_get_enum (settings, key); _gs_prefs_set_mode (prefs, mode); } else if (strcmp (key, KEY_THEMES) == 0) { gchar **strv = NULL; strv = g_settings_get_strv (settings, key); _gs_prefs_set_themes (prefs, strv); g_strfreev (strv); } else if (strcmp (key, KEY_IDLE_DELAY) == 0) { int delay; delay = g_settings_get_int (settings, key); _gs_prefs_set_timeout (prefs, delay); } else if (strcmp (key, KEY_POWER_DELAY) == 0) { int delay; delay = g_settings_get_int (settings, key); _gs_prefs_set_power_timeout (prefs, delay); } else if (strcmp (key, KEY_LOCK_DELAY) == 0) { int delay; delay = g_settings_get_int (settings, key); _gs_prefs_set_lock_timeout (prefs, delay); } else if (strcmp (key, KEY_IDLE_ACTIVATION_ENABLED) == 0) { gboolean enabled; enabled = g_settings_get_boolean (settings, key); _gs_prefs_set_idle_activation_enabled (prefs, enabled); } else if (strcmp (key, KEY_LOCK_ENABLED) == 0) { gboolean enabled; enabled = g_settings_get_boolean (settings, key); _gs_prefs_set_lock_enabled (prefs, enabled); } else if (strcmp (key, KEY_LOCK_DISABLE) == 0) { gboolean disabled; disabled = g_settings_get_boolean (settings, key); _gs_prefs_set_lock_disabled (prefs, disabled); } else if (strcmp (key, KEY_USER_SWITCH_DISABLE) == 0) { gboolean disabled; disabled = g_settings_get_boolean (settings, key); _gs_prefs_set_user_switch_disabled (prefs, disabled); } else if (strcmp (key, KEY_CYCLE_DELAY) == 0) { int delay; delay = g_settings_get_int (settings, key); _gs_prefs_set_cycle_timeout (prefs, delay); } else if (strcmp (key, KEY_KEYBOARD_ENABLED) == 0) { gboolean enabled; enabled = g_settings_get_boolean (settings, key); _gs_prefs_set_keyboard_enabled (prefs, enabled); } else if (strcmp (key, KEY_KEYBOARD_COMMAND) == 0) { char *command; command = g_settings_get_string (settings, key); _gs_prefs_set_keyboard_command (prefs, command); g_free (command); } else if (strcmp (key, KEY_STATUS_MESSAGE_ENABLED) == 0) { gboolean enabled; enabled = g_settings_get_boolean (settings, key); _gs_prefs_set_status_message_enabled (prefs, enabled); } else if (strcmp (key, KEY_LOGOUT_ENABLED) == 0) { gboolean enabled; enabled = g_settings_get_boolean (settings, key); _gs_prefs_set_logout_enabled (prefs, enabled); } else if (strcmp (key, KEY_LOGOUT_DELAY) == 0) { int delay; delay = g_settings_get_int (settings, key); _gs_prefs_set_logout_timeout (prefs, delay); } else if (strcmp (key, KEY_LOGOUT_COMMAND) == 0) { char *command; command = g_settings_get_string (settings, key); _gs_prefs_set_logout_command (prefs, command); g_free (command); } else if (strcmp (key, KEY_USER_SWITCH_ENABLED) == 0) { gboolean enabled; enabled = g_settings_get_boolean (settings, key); _gs_prefs_set_user_switch_enabled (prefs, enabled); } else { //g_warning ("Config key not handled: %s", key); } g_signal_emit (prefs, signals [CHANGED], 0); } static void gs_prefs_init (GSPrefs *prefs) { prefs->priv = GS_PREFS_GET_PRIVATE (prefs); prefs->priv->settings = g_settings_new (GSETTINGS_SCHEMA); g_signal_connect (prefs->priv->settings, "changed", G_CALLBACK (key_changed_cb), prefs); prefs->priv->lockdown_settings = g_settings_new (LOCKDOWN_SETTINGS_SCHEMA); g_signal_connect (prefs->priv->lockdown_settings, "changed", G_CALLBACK (key_changed_cb), prefs); prefs->priv->session_settings = g_settings_new (SESSION_SETTINGS_SCHEMA); g_signal_connect (prefs->priv->session_settings, "changed::" KEY_IDLE_DELAY, G_CALLBACK (key_changed_cb), prefs); prefs->idle_activation_enabled = TRUE; prefs->lock_enabled = TRUE; prefs->lock_disabled = FALSE; prefs->logout_enabled = FALSE; prefs->user_switch_enabled = FALSE; prefs->timeout = 600000; prefs->power_timeout = 60000; prefs->lock_timeout = 0; prefs->logout_timeout = 14400000; prefs->cycle = 600000; prefs->mode = GS_MODE_SINGLE; gs_prefs_load_from_settings (prefs); } static void gs_prefs_finalize (GObject *object) { GSPrefs *prefs; g_return_if_fail (object != NULL); g_return_if_fail (GS_IS_PREFS (object)); prefs = GS_PREFS (object); g_return_if_fail (prefs->priv != NULL); if (prefs->priv->settings) { g_object_unref (prefs->priv->settings); prefs->priv->settings = NULL; } if (prefs->priv->lockdown_settings) { g_object_unref (prefs->priv->lockdown_settings); prefs->priv->lockdown_settings = NULL; } if (prefs->priv->session_settings) { g_object_unref (prefs->priv->session_settings); prefs->priv->session_settings = NULL; } if (prefs->themes) { g_slist_foreach (prefs->themes, (GFunc)g_free, NULL); g_slist_free (prefs->themes); } g_free (prefs->logout_command); g_free (prefs->keyboard_command); G_OBJECT_CLASS (gs_prefs_parent_class)->finalize (object); } GSPrefs * gs_prefs_new (void) { GObject *prefs; prefs = g_object_new (GS_TYPE_PREFS, NULL); return GS_PREFS (prefs); } ukui-control-center/panels/power/egg-string.c0000664000175000017500000003066013057175444020260 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ /** * SECTION:pk-common * @short_description: Common utility functions for PackageKit * * This file contains functions that may be useful. */ #include "config.h" #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #include #include "egg-debug.h" #include "egg-string.h" /** * egg_strtoint: * @text: The text the convert * @value: The return numeric return value * * Converts a string into a signed integer value in a safe way. * * Return value: %TRUE if the string was converted correctly **/ gboolean egg_strtoint (const gchar *text, gint *value) { gchar *endptr = NULL; gint64 value_raw; /* invalid */ if (text == NULL) return FALSE; /* parse */ value_raw = g_ascii_strtoll (text, &endptr, 10); /* parsing error */ if (endptr == text) return FALSE; /* out of range */ if (value_raw > G_MAXINT || value_raw < G_MININT) return FALSE; /* cast back down to value */ *value = (gint) value_raw; return TRUE; } /** * egg_strtouint: * @text: The text the convert * @value: The return numeric return value * * Converts a string into a unsigned integer value in a safe way. * * Return value: %TRUE if the string was converted correctly **/ gboolean egg_strtouint (const gchar *text, guint *value) { gchar *endptr = NULL; guint64 value_raw; /* invalid */ if (text == NULL) return FALSE; /* parse */ value_raw = g_ascii_strtoull (text, &endptr, 10); /* parsing error */ if (endptr == text) return FALSE; /* out of range */ if (value_raw > G_MAXINT) return FALSE; /* cast back down to value */ *value = (guint) value_raw; return TRUE; } /** * egg_strzero: * @text: The text to check * * This function is a much safer way of doing "if (strlen (text) == 0))" * as it does not rely on text being NULL terminated. It's also much * quicker as it only checks the first byte rather than scanning the whole * string just to verify it's not zero length. * * Return value: %TRUE if the string was converted correctly **/ gboolean egg_strzero (const gchar *text) { if (text == NULL) return TRUE; if (text[0] == '\0') return TRUE; return FALSE; } /** * egg_strlen: * @text: The text to check * @len: The maximum length of the string * * This function is a much safer way of doing strlen as it checks for NULL and * a stupidly long string. * * Return value: the length of the string, or len if the string is too long. **/ guint egg_strlen (const gchar *text, guint len) { guint i; /* common case */ if (text == NULL || text[0] == '\0') return 0; /* only count up to len */ for (i=1; i * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #ifndef __EGG_DEBUG_H #define __EGG_DEBUG_H #include #include G_BEGIN_DECLS #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /** * egg_debug: * * Non critical debugging */ #define egg_debug(...) egg_debug_real (__func__, __FILE__, __LINE__, __VA_ARGS__) /** * egg_warning: * * Important debugging */ #define egg_warning(...) egg_warning_real (__func__, __FILE__, __LINE__, __VA_ARGS__) /** * egg_error: * * Critical debugging, with exit */ #define egg_error(...) egg_error_real (__func__, __FILE__, __LINE__, __VA_ARGS__) #elif defined(__GNUC__) && __GNUC__ >= 3 #define egg_debug(...) egg_debug_real (__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) #define egg_warning(...) egg_warning_real (__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) #define egg_error(...) egg_error_real (__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) #else #define egg_debug(...) #define egg_warning(...) #define egg_error(...) #endif void egg_debug_init (gboolean debug); void egg_debug_set_logging (gboolean enabled); gboolean egg_debug_enabled (void); gboolean egg_debug_is_logging (void); gboolean egg_debug_is_console (void); void egg_debug_backtrace (void); void egg_debug_real (const gchar *func, const gchar *file, int line, const gchar *format, ...) __attribute__((format (printf,4,5))); void egg_warning_real (const gchar *func, const gchar *file, int line, const gchar *format, ...) __attribute__((format (printf,4,5))); void egg_error_real (const gchar *func, const gchar *file, int line, const gchar *format, ...) G_GNUC_NORETURN __attribute__((format (printf,4,5))); G_END_DECLS #endif /* __EGG_DEBUG_H */ ukui-control-center/panels/power/copy-theme-dialog.h0000664000175000017500000000354213245450076021521 0ustar fengfeng/* copy-theme-dialog.h * Copyright (C) 2008 John Millikin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301, USA. **/ #ifndef __COPY_THEME_DIALOG_H__ #define __COPY_THEME_DIALOG_H__ #include G_BEGIN_DECLS #define COPY_THEME_DIALOG_TYPE copy_theme_dialog_get_type () #define COPY_THEME_DIALOG(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, COPY_THEME_DIALOG_TYPE, CopyThemeDialog) #define COPY_THEME_DIALOG_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, COPY_THEME_DIALOG_TYPE, CopyThemeDialogClass) #define IS_COPY_THEME_DIALOG(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, COPY_THEME_DIALOG_TYPE) typedef struct _CopyThemeDialog CopyThemeDialog; typedef struct _CopyThemeDialogClass CopyThemeDialogClass; typedef struct _CopyThemeDialogPrivate CopyThemeDialogPrivate; struct _CopyThemeDialog { GtkDialog dialog; CopyThemeDialogPrivate *priv; }; struct _CopyThemeDialogClass { GtkDialogClass parent_class; void (*cancelled) (CopyThemeDialog *dialog); void (*complete) (CopyThemeDialog *dialog); }; GType copy_theme_dialog_get_type (void); GtkWidget *copy_theme_dialog_new (GList *files); void copy_theme_dialog_begin (CopyThemeDialog *dialog); G_END_DECLS #endif /* __COPY_THEME_DIALOG_H__ */ ukui-control-center/panels/power/subprocs.c0000664000175000017500000000720113245450076020041 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * subprocs.c --- choosing, spawning, and killing screenhacks. * * xscreensaver, Copyright (c) 1991-2003 Jamie Zawinski * Modified: Copyright (c) 2004 William Jon McCann * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation. No representations are made about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. */ #include "config.h" #include #include #include #include #ifndef ESRCH # include #endif #include /* sys/resource.h needs this for timeval */ # include /* for waitpid() and associated macros */ #ifdef VMS # include # include /* for close */ # include /* for getpid */ # define pid_t int # define fork vfork #endif /* VMS */ #include /* for the signal names */ #include #include "subprocs.h" #if !defined(SIGCHLD) && defined(SIGCLD) # define SIGCHLD SIGCLD #endif /* Semaphore to temporarily turn the SIGCHLD handler into a no-op. Don't alter this directly -- use block_sigchld() / unblock_sigchld(). */ static int block_sigchld_handler = 0; #ifdef HAVE_SIGACTION sigset_t #else /* !HAVE_SIGACTION */ int #endif /* !HAVE_SIGACTION */ block_sigchld (void) { #ifdef HAVE_SIGACTION sigset_t child_set; sigemptyset (&child_set); sigaddset (&child_set, SIGCHLD); sigaddset (&child_set, SIGPIPE); sigprocmask (SIG_BLOCK, &child_set, 0); #endif /* HAVE_SIGACTION */ block_sigchld_handler++; #ifdef HAVE_SIGACTION return child_set; #else /* !HAVE_SIGACTION */ return 0; #endif /* !HAVE_SIGACTION */ } void unblock_sigchld (void) { #ifdef HAVE_SIGACTION sigset_t child_set; sigemptyset (&child_set); sigaddset (&child_set, SIGCHLD); sigaddset (&child_set, SIGPIPE); sigprocmask (SIG_UNBLOCK, &child_set, 0); #endif /* HAVE_SIGACTION */ block_sigchld_handler--; } int signal_pid (int pid, int signal) { int status = -1; gboolean verbose = TRUE; if (block_sigchld_handler) /* This function should not be called from the signal handler. */ abort(); block_sigchld (); /* we control the horizontal... */ status = kill (pid, signal); if (verbose && status < 0) { if (errno == ESRCH) g_message ("Child process %lu was already dead.", (unsigned long) pid); else { char buf [1024]; snprintf (buf, sizeof (buf), "Couldn't kill child process %lu", (unsigned long) pid); perror (buf); } } unblock_sigchld (); if (block_sigchld_handler < 0) abort (); return status; } #ifndef VMS void await_dying_children (int pid, gboolean debug) { while (1) { int wait_status = 0; pid_t kid; errno = 0; kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED); if (debug) { if (kid < 0 && errno) g_message ("waitpid(%d) ==> %ld (%d)", pid, (long) kid, errno); else if (kid != 0) g_message ("waitpid(%d) ==> %ld", pid, (long) kid); } /* 0 means no more children to reap. -1 means error -- except "interrupted system call" isn't a "real" error, so if we get that, we should just try again. */ if (kid < 0 && errno != EINTR) break; } } #else /* VMS */ static void await_dying_children (saver_info *si) { return; } #endif /* VMS */ ukui-control-center/panels/power/egg-array-float.c0000664000175000017500000005615213057175444021177 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #include "config.h" #include #include #include #include #include #include #include "egg-debug.h" #include "egg-array-float.h" /** * egg_array_float_guassian_value: * * @x: input value * @sigma: sigma value * Return value: the gaussian, in floating point precision **/ static gfloat egg_array_float_guassian_value (gfloat x, gfloat sigma) { return (1.0 / (sqrtf(2.0*3.1415927) * sigma)) * (expf((-(powf(x,2.0)))/(2.0 * powf(sigma, 2.0)))); } /** * egg_array_float_new: * * @length: length of array * Return value: Allocate array * * Creates a new size array which is zeroed. Free with g_array_free(); **/ EggArrayFloat * egg_array_float_new (guint length) { guint i; EggArrayFloat *array; array = g_array_sized_new (TRUE, FALSE, sizeof(gfloat), length); array->len = length; /* clear to 0.0 */ for (i=0; i= array->len) g_error ("above index! (%i)", i); return g_array_index (array, gfloat, i); } /** * egg_array_float_set: * * @array: input array **/ void egg_array_float_set (EggArrayFloat *array, guint i, gfloat value) { g_array_index (array, gfloat, i) = value; } /** * egg_array_float_free: * * @array: input array * * Frees the array, deallocating data **/ void egg_array_float_free (EggArrayFloat *array) { if (array != NULL) g_array_free (array, TRUE); } /** * egg_array_float_get_average: * @array: This class instance * * Gets the average value. **/ gfloat egg_array_float_get_average (EggArrayFloat *array) { guint i; guint length; gfloat average = 0; length = array->len; for (i=0; i 0.01f) { egg_warning ("got wrong sum (%f), perhaps sigma too high for size?", value); egg_array_float_free (array); array = NULL; } return array; } /** * egg_array_float_sum: * * @array: input array * * Sum the elements of the array **/ gfloat egg_array_float_sum (EggArrayFloat *array) { guint length; guint i; gfloat total = 0; length = array->len; for (i=0; ilen; /* debug out */ for (i=0; ilen; length_kernel = kernel->len; result = egg_array_float_new (length_data); /* convolve */ for (i=0;i= length_data) idx = length_data - 1; value += g_array_index (data, gfloat, idx) * g_array_index (kernel, gfloat, j); } g_array_index (result, gfloat, i) = value; } return result; } /** * egg_array_float_compute_integral: * @array: This class instance * * Computes complete discrete integral of dataset. * Will only work with a step size of one. **/ gfloat egg_array_float_compute_integral (EggArrayFloat *array, guint x1, guint x2) { gfloat value; guint i; g_return_val_if_fail (x2 >= x1, 0.0); /* if the same point, then we have no area */ if (x1 == x2) return 0.0; value = 0.0; for (i=x1; i <= x2; i++) value += g_array_index (array, gfloat, i); return value; } /** * powfi: **/ static gfloat powfi (gfloat base, guint n) { guint i; gfloat retval = 1; for (i=1; i <= n; i++) retval *= base; return retval; } /** * egg_array_float_remove_outliers: * * @data: input array * @size: size to analyse * @sigma: sigma for standard deviation * Return value: Data with outliers removed * * Compares local sections of the data, removing outliers if they fall * ouside of sigma, and using the average of the other points in it's place. **/ EggArrayFloat * egg_array_float_remove_outliers (EggArrayFloat *data, guint length, gfloat sigma) { guint i; guint j; guint half_length; gfloat value; gfloat average; gfloat average_not_inc; gfloat average_square; gfloat biggest_difference; gfloat outlier_value; EggArrayFloat *result; g_return_val_if_fail (length % 2 == 1, NULL); result = egg_array_float_new (data->len); /* check for no data */ if (data->len == 0) goto out; half_length = (length - 1) / 2; /* copy start and end of array */ for (i=0; i < half_length; i++) g_array_index (result, gfloat, i) = g_array_index (data, gfloat, i); for (i=data->len-half_length; i < data->len; i++) g_array_index (result, gfloat, i) = g_array_index (data, gfloat, i); /* find the standard deviation of a block off data */ for (i=half_length; i < data->len-half_length; i++) { average = 0; average_square = 0; /* find the average and the squared average */ for (j=i-half_length; j biggest_difference) { biggest_difference = value; outlier_value = g_array_index (data, gfloat, j); } } average_not_inc = (average * length) - outlier_value; average_not_inc /= length - 1; g_array_index (result, gfloat, i) = average_not_inc; } } out: return result; } /*************************************************************************** *** MAKE CHECK TESTS *** ***************************************************************************/ #ifdef EGG_TEST #include "egg-test.h" void egg_array_float_test (gpointer data) { EggArrayFloat *array; EggArrayFloat *kernel; EggArrayFloat *result; gfloat value; gfloat sigma; guint size; EggTest *test = (EggTest *) data; if (egg_test_start (test, "EggArrayFloat") == FALSE) return; /************************************************************/ egg_test_title (test, "make sure we get a non null array"); array = egg_array_float_new (10); if (array != NULL) egg_test_success (test, "got EggArrayFloat"); else egg_test_failed (test, "could not get EggArrayFloat"); egg_array_float_print (array); egg_array_float_free (array); /************************************************************/ egg_test_title (test, "make sure we get the correct length array"); array = egg_array_float_new (10); if (array->len == 10) egg_test_success (test, "got correct size"); else egg_test_failed (test, "got wrong size"); /************************************************************/ egg_test_title (test, "make sure we get the correct array sum"); value = egg_array_float_sum (array); if (value == 0.0) egg_test_success (test, "got correct sum"); else egg_test_failed (test, "got wrong sum (%f)", value); /************************************************************/ egg_test_title (test, "remove outliers"); egg_array_float_set (array, 0, 30.0); egg_array_float_set (array, 1, 29.0); egg_array_float_set (array, 2, 31.0); egg_array_float_set (array, 3, 33.0); egg_array_float_set (array, 4, 100.0); egg_array_float_set (array, 5, 27.0); egg_array_float_set (array, 6, 30.0); egg_array_float_set (array, 7, 29.0); egg_array_float_set (array, 8, 31.0); egg_array_float_set (array, 9, 30.0); kernel = egg_array_float_remove_outliers (array, 3, 10.0); if (kernel != NULL && kernel->len == 10) egg_test_success (test, "got correct length outlier array"); else egg_test_failed (test, "got gaussian array length (%i)", array->len); egg_array_float_print (array); egg_array_float_print (kernel); /************************************************************/ egg_test_title (test, "make sure we removed the outliers"); value = egg_array_float_sum (kernel); if (fabs(value - 30*10) < 1) egg_test_success (test, "got sum (%f)", value); else egg_test_failed (test, "got wrong sum (%f)", value); egg_array_float_free (kernel); /************************************************************/ egg_test_title (test, "remove outliers step"); egg_array_float_set (array, 0, 0.0); egg_array_float_set (array, 1, 0.0); egg_array_float_set (array, 2, 0.0); egg_array_float_set (array, 3, 0.0); egg_array_float_set (array, 4, 0.0); egg_array_float_set (array, 5, 0.0); egg_array_float_set (array, 6, 0.0); egg_array_float_set (array, 7, 10.0); egg_array_float_set (array, 8, 20.0); egg_array_float_set (array, 9, 50.0); kernel = egg_array_float_remove_outliers (array, 3, 20.0); if (kernel != NULL && kernel->len == 10) egg_test_success (test, "got correct length outlier array"); else egg_test_failed (test, "got gaussian array length (%i)", array->len); egg_array_float_print (array); egg_array_float_print (kernel); /************************************************************/ egg_test_title (test, "make sure we removed the outliers"); value = egg_array_float_sum (kernel); if (fabs(value - 80) < 1) egg_test_success (test, "got sum (%f)", value); else egg_test_failed (test, "got wrong sum (%f)", value); egg_array_float_free (kernel); /************************************************************/ egg_test_title (test, "get gaussian 0.0, sigma 1.1"); value = egg_array_float_guassian_value (0.0, 1.1); if (fabs (value - 0.36267) < 0.0001) egg_test_success (test, "got correct gaussian"); else egg_test_failed (test, "got wrong gaussian (%f)", value); /************************************************************/ egg_test_title (test, "get gaussian 0.5, sigma 1.1"); value = egg_array_float_guassian_value (0.5, 1.1); if (fabs (value - 0.32708) < 0.0001) egg_test_success (test, "got correct gaussian"); else egg_test_failed (test, "got wrong gaussian (%f)", value); /************************************************************/ egg_test_title (test, "get gaussian 1.0, sigma 1.1"); value = egg_array_float_guassian_value (1.0, 1.1); if (fabs (value - 0.23991) < 0.0001) egg_test_success (test, "got correct gaussian"); else egg_test_failed (test, "got wrong gaussian (%f)", value); /************************************************************/ egg_test_title (test, "get gaussian 0.5, sigma 4.5"); value = egg_array_float_guassian_value (0.5, 4.5); if (fabs (value - 0.088108) < 0.0001) egg_test_success (test, "got correct gaussian"); else egg_test_failed (test, "got wrong gaussian (%f)", value); /************************************************************/ size = 5; sigma = 1.1; egg_test_title (test, "get inprecise gaussian array (%i), sigma %f", size, sigma); kernel = egg_array_float_compute_gaussian (size, sigma); if (kernel == NULL) egg_test_success (test, NULL); else { egg_test_failed (test, "got gaussian array length (%i)", array->len); egg_array_float_print (kernel); } /************************************************************/ size = 9; sigma = 1.1; egg_test_title (test, "get gaussian-9 array (%i), sigma %f", size, sigma); kernel = egg_array_float_compute_gaussian (size, sigma); if (kernel != NULL && kernel->len == size) egg_test_success (test, "got correct length gaussian array"); else egg_test_failed (test, "got gaussian array length (%i)", array->len); egg_array_float_print (kernel); /************************************************************/ egg_test_title (test, "make sure we get an accurate gaussian"); value = egg_array_float_sum (kernel); if (fabs(value - 1.0) < 0.01) egg_test_success (test, "got sum (%f)", value); else egg_test_failed (test, "got wrong sum (%f)", value); /************************************************************/ egg_test_title (test, "make sure we get get and set"); egg_array_float_set (array, 4, 100.0); value = egg_array_float_get (array, 4); if (value == 100.0) egg_test_success (test, "got value okay", value); else egg_test_failed (test, "got wrong value (%f)", value); egg_array_float_print (array); /************************************************************/ egg_test_title (test, "make sure we get the correct array sum (2)"); egg_array_float_set (array, 0, 20.0); egg_array_float_set (array, 1, 44.0); egg_array_float_set (array, 2, 45.0); egg_array_float_set (array, 3, 89.0); egg_array_float_set (array, 4, 100.0); egg_array_float_set (array, 5, 12.0); egg_array_float_set (array, 6, 76.0); egg_array_float_set (array, 7, 78.0); egg_array_float_set (array, 8, 1.20); egg_array_float_set (array, 9, 3.0); value = egg_array_float_sum (array); if (fabs (value - 468.2) < 0.0001f) egg_test_success (test, "got correct sum"); else egg_test_failed (test, "got wrong sum (%f)", value); /************************************************************/ egg_test_title (test, "test convolving with kernel #1"); egg_array_float_set (array, 0, 0.0); egg_array_float_set (array, 1, 0.0); egg_array_float_set (array, 2, 0.0); egg_array_float_set (array, 3, 0.0); egg_array_float_set (array, 4, 100.0); egg_array_float_set (array, 5, 0.0); egg_array_float_set (array, 6, 0.0); egg_array_float_set (array, 7, 0.0); egg_array_float_set (array, 8, 0.0); egg_array_float_set (array, 9, 0.0); result = egg_array_float_convolve (array, kernel); if (result->len == 10) egg_test_success (test, "got correct size convolve product"); else egg_test_failed (test, "got correct size convolve product (%f)", result->len); egg_array_float_print (result); /************************************************************/ egg_test_title (test, "make sure we get the correct array sum of convolve #1"); value = egg_array_float_sum (result); if (fabs(value - 100.0) < 5.0) egg_test_success (test, "got correct (enough) sum (%f)", value); else egg_test_failed (test, "got wrong sum (%f)", value); egg_array_float_free (result); /************************************************************/ egg_test_title (test, "test convolving with kernel #2"); egg_array_float_set (array, 0, 100.0); egg_array_float_set (array, 1, 0.0); egg_array_float_set (array, 2, 0.0); egg_array_float_set (array, 3, 0.0); egg_array_float_set (array, 4, 0.0); egg_array_float_set (array, 5, 0.0); egg_array_float_set (array, 6, 0.0); egg_array_float_set (array, 7, 0.0); egg_array_float_set (array, 8, 0.0); egg_array_float_set (array, 9, 0.0); result = egg_array_float_convolve (array, kernel); if (result->len == 10) egg_test_success (test, "got correct size convolve product"); else egg_test_failed (test, "got correct size convolve product (%f)", result->len); egg_array_float_print (array); egg_array_float_print (result); /************************************************************/ egg_test_title (test, "make sure we get the correct array sum of convolve #2"); value = egg_array_float_sum (result); if (fabs(value - 100.0) < 10.0) egg_test_success (test, "got correct (enough) sum (%f)", value); else egg_test_failed (test, "got wrong sum (%f)", value); egg_array_float_free (result); /************************************************************/ egg_test_title (test, "test convolving with kernel #3"); egg_array_float_set (array, 0, 0.0); egg_array_float_set (array, 1, 0.0); egg_array_float_set (array, 2, 0.0); egg_array_float_set (array, 3, 0.0); egg_array_float_set (array, 4, 0.0); egg_array_float_set (array, 5, 0.0); egg_array_float_set (array, 6, 0.0); egg_array_float_set (array, 7, 0.0); egg_array_float_set (array, 8, 0.0); egg_array_float_set (array, 9, 100.0); result = egg_array_float_convolve (array, kernel); if (result->len == 10) egg_test_success (test, "got correct size convolve product"); else egg_test_failed (test, "got correct size convolve product (%f)", result->len); egg_array_float_print (array); egg_array_float_print (result); /************************************************************/ egg_test_title (test, "make sure we get the correct array sum of convolve #3"); value = egg_array_float_sum (result); if (fabs(value - 100.0) < 10.0) egg_test_success (test, "got correct (enough) sum (%f)", value); else egg_test_failed (test, "got wrong sum (%f)", value); egg_array_float_free (result); /************************************************************/ egg_test_title (test, "test convolving with kernel #4"); egg_array_float_set (array, 0, 10.0); egg_array_float_set (array, 1, 10.0); egg_array_float_set (array, 2, 10.0); egg_array_float_set (array, 3, 10.0); egg_array_float_set (array, 4, 10.0); egg_array_float_set (array, 5, 10.0); egg_array_float_set (array, 6, 10.0); egg_array_float_set (array, 7, 10.0); egg_array_float_set (array, 8, 10.0); egg_array_float_set (array, 9, 10.0); result = egg_array_float_convolve (array, kernel); if (result->len == 10) egg_test_success (test, "got correct size convolve product"); else egg_test_failed (test, "got incorrect size convolve product (%f)", result->len); egg_array_float_print (array); egg_array_float_print (result); /************************************************************/ egg_test_title (test, "make sure we get the correct array sum of convolve #4"); value = egg_array_float_sum (result); if (fabs(value - 100.0) < 1.0) egg_test_success (test, "got correct (enough) sum (%f)", value); else egg_test_failed (test, "got wrong sum (%f)", value); /************************************************************/ egg_test_title (test, "test convolving with kernel #5"); egg_array_float_set (array, 0, 10.0); egg_array_float_set (array, 1, 10.0); egg_array_float_set (array, 2, 10.0); egg_array_float_set (array, 3, 10.0); egg_array_float_set (array, 4, 0.0); egg_array_float_set (array, 5, 10.0); egg_array_float_set (array, 6, 10.0); egg_array_float_set (array, 7, 10.0); egg_array_float_set (array, 8, 10.0); egg_array_float_set (array, 9, 10.0); result = egg_array_float_convolve (array, kernel); if (result->len == 10) egg_test_success (test, "got correct size convolve product"); else egg_test_failed (test, "got incorrect size convolve product (%f)", result->len); egg_array_float_print (array); egg_array_float_print (result); /************************************************************/ egg_test_title (test, "make sure we get the correct array sum of convolve #5"); value = egg_array_float_sum (result); if (fabs(value - 90.0) < 1.0) egg_test_success (test, "got correct (enough) sum (%f)", value); else egg_test_failed (test, "got wrong sum (%f)", value); /*************** INTEGRATION TEST ************************/ egg_test_title (test, "integration down"); egg_array_float_set (array, 0, 0.0); egg_array_float_set (array, 1, 1.0); egg_array_float_set (array, 2, 2.0); egg_array_float_set (array, 3, 3.0); egg_array_float_set (array, 4, 4.0); egg_array_float_set (array, 5, 5.0); egg_array_float_set (array, 6, 6.0); egg_array_float_set (array, 7, 7.0); egg_array_float_set (array, 8, 8.0); egg_array_float_set (array, 9, 9.0); size = egg_array_float_compute_integral (array, 0, 4); if (size == 0+1+2+3+4) egg_test_success (test, "intergrated okay"); else egg_test_failed (test, "did not intergrated okay (%i)", size); egg_test_title (test, "integration up"); size = egg_array_float_compute_integral (array, 5, 9); if (size == 5+6+7+8+9) egg_test_success (test, "intergrated okay"); else egg_test_failed (test, "did not intergrated okay (%i)", size); egg_test_title (test, "integration all"); size = egg_array_float_compute_integral (array, 0, 9); if (size == 0+1+2+3+4+5+6+7+8+9) egg_test_success (test, "intergrated okay"); else egg_test_failed (test, "did not intergrated okay (%i)", size); /*************** AVERAGE TEST ************************/ egg_test_title (test, "average"); egg_array_float_set (array, 0, 0.0); egg_array_float_set (array, 1, 1.0); egg_array_float_set (array, 2, 2.0); egg_array_float_set (array, 3, 3.0); egg_array_float_set (array, 4, 4.0); egg_array_float_set (array, 5, 5.0); egg_array_float_set (array, 6, 6.0); egg_array_float_set (array, 7, 7.0); egg_array_float_set (array, 8, 8.0); egg_array_float_set (array, 9, 9.0); value = egg_array_float_get_average (array); if (value == 4.5) egg_test_success (test, "averaged okay"); else egg_test_failed (test, "did not average okay (%i)", value); egg_array_float_free (result); egg_array_float_free (array); egg_array_float_free (kernel); egg_test_end (test); } #endif ukui-control-center/panels/power/copy-theme-dialog.c0000664000175000017500000003732413245450076021521 0ustar fengfeng/* copy-theme-dialog.c * Copyright (C) 2008 John Millikin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301, USA. **/ #include "config.h" #include #include #include #include #include #include #include #include #include "copy-theme-dialog.h" static void copy_theme_dialog_class_init (CopyThemeDialogClass *klass); static void copy_theme_dialog_init (CopyThemeDialog *dlg); static void add_file_to_dialog (gpointer data, gpointer user_data); static void single_copy_complete (GObject *source_object, GAsyncResult *res, gpointer user_data); static void copy_theme_dialog_copy_next (CopyThemeDialog *dialog); static void copy_theme_dialog_cancel (CopyThemeDialog *dialog); static void copy_theme_dialog_finalize (GObject *obj); static void copy_theme_dialog_update_num_files (CopyThemeDialog *dlg); static void copy_theme_dialog_response (GtkDialog *dialog, gint response_id); static void eel_gtk_label_make_bold (GtkLabel *label); static void create_titled_label (GtkTable *table, int row, GtkWidget **title_widget, GtkWidget **label_text_widget); static GObjectClass *parent_class = NULL; enum { CANCELLED = 0, COMPLETE, SIGNAL_COUNT }; struct _CopyThemeDialogPrivate { GtkWidget *progress; GtkWidget *status; GtkWidget *current; GtkWidget *from; GtkWidget *to; GFile *theme_dir; GSList *all_files, *file; GSList *all_basenames, *basename; guint index; guint total_files; GCancellable *cancellable; }; guint signals[SIGNAL_COUNT] = {0, 0}; GType copy_theme_dialog_get_type (void) { static GType copy_theme_dialog_type = 0; if (!copy_theme_dialog_type) { static GTypeInfo copy_theme_dialog_info = { sizeof (CopyThemeDialogClass), NULL, /* GBaseInitFunc */ NULL, /* GBaseFinalizeFunc */ (GClassInitFunc) copy_theme_dialog_class_init, NULL, /* GClassFinalizeFunc */ NULL, /* data */ sizeof (CopyThemeDialog), 0, /* n_preallocs */ (GInstanceInitFunc) copy_theme_dialog_init, NULL }; copy_theme_dialog_type = g_type_register_static (GTK_TYPE_DIALOG, "CopyThemeDialog", ©_theme_dialog_info, 0); } return copy_theme_dialog_type; } static void copy_theme_dialog_class_init (CopyThemeDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); g_type_class_add_private (klass, sizeof (CopyThemeDialogPrivate)); klass->cancelled = copy_theme_dialog_cancel; object_class->finalize = copy_theme_dialog_finalize; GTK_DIALOG_CLASS (klass)->response = copy_theme_dialog_response; signals[CANCELLED] = g_signal_new ("cancelled", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (CopyThemeDialogClass, cancelled), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[COMPLETE] = g_signal_new ("complete", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CopyThemeDialogClass, complete), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); parent_class = g_type_class_peek_parent (klass); } GtkWidget* copy_theme_dialog_new (GList *files) { GtkWidget *dialog; CopyThemeDialogPrivate *priv; dialog = GTK_WIDGET (g_object_new (COPY_THEME_DIALOG_TYPE, NULL)); priv = COPY_THEME_DIALOG (dialog)->priv; priv->index = 0; priv->total_files = 0; priv->all_files = NULL; priv->all_basenames = NULL; g_list_foreach (files, add_file_to_dialog, dialog); priv->file = priv->all_files; priv->basename = priv->all_basenames; return dialog; } static gboolean copy_finished (CopyThemeDialog *dialog) { return (g_cancellable_is_cancelled (dialog->priv->cancellable) || dialog->priv->file == NULL); } static void copy_theme_dialog_init (CopyThemeDialog *dlg) { GtkWidget *vbox; GtkWidget *hbox; GtkWidget *progress_vbox; GtkWidget *table; GtkWidget *label; GtkWidget *dialog_vbox; char *markup; gchar *theme_dir_path; dlg->priv = G_TYPE_INSTANCE_GET_PRIVATE (dlg, COPY_THEME_DIALOG_TYPE, CopyThemeDialogPrivate); /* Find and, if needed, create the directory for storing themes */ theme_dir_path = g_build_filename (g_get_user_data_dir (), "applications", "screensavers", NULL); dlg->priv->theme_dir = g_file_new_for_path (theme_dir_path); g_mkdir_with_parents (theme_dir_path, S_IRWXU); g_free (theme_dir_path); /* For cancelling async I/O operations */ dlg->priv->cancellable = g_cancellable_new (); /* GUI settings */ dialog_vbox = gtk_dialog_get_content_area (GTK_DIALOG (dlg)); gtk_container_set_border_width (GTK_CONTAINER (dialog_vbox), 4); gtk_box_set_spacing (GTK_BOX (dialog_vbox), 4); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_container_set_border_width (GTK_CONTAINER (vbox), 6); gtk_box_pack_start (GTK_BOX (dialog_vbox), vbox, TRUE, TRUE, 0); dlg->priv->status = gtk_label_new (""); markup = g_strdup_printf ("%s", _("Copying files")); gtk_label_set_markup (GTK_LABEL (dlg->priv->status), markup); g_free (markup); gtk_widget_set_halign (dlg->priv->status, GTK_ALIGN_START); gtk_widget_set_valign (dlg->priv->status, GTK_ALIGN_START); gtk_box_pack_start (GTK_BOX (vbox), dlg->priv->status, FALSE, FALSE, 0); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); table = gtk_table_new (2, 2, FALSE); gtk_table_set_row_spacings (GTK_TABLE (table), 4); gtk_table_set_col_spacings (GTK_TABLE (table), 4); create_titled_label (GTK_TABLE (table), 0, &label, &dlg->priv->from); gtk_label_set_text (GTK_LABEL (label), _("From:")); create_titled_label (GTK_TABLE (table), 1, &label, &dlg->priv->to); gtk_label_set_text (GTK_LABEL (label), _("To:")); gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (table), FALSE, FALSE, 0); progress_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_box_set_homogeneous (GTK_BOX (progress_vbox), TRUE); gtk_box_pack_start (GTK_BOX (vbox), progress_vbox, FALSE, FALSE, 0); dlg->priv->progress = gtk_progress_bar_new (); gtk_box_pack_start (GTK_BOX (progress_vbox), dlg->priv->progress, FALSE, FALSE, 0); dlg->priv->current = gtk_label_new (""); gtk_box_pack_start (GTK_BOX (progress_vbox), dlg->priv->current, FALSE, FALSE, 0); gtk_widget_set_halign (dlg->priv->current, GTK_ALIGN_START); gtk_dialog_add_button (GTK_DIALOG (dlg), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); gtk_window_set_title (GTK_WINDOW (dlg), _("Copying themes")); gtk_container_set_border_width (GTK_CONTAINER (dlg), 6); gtk_widget_show_all (dialog_vbox); } static void add_file_to_dialog (gpointer data, gpointer user_data) { CopyThemeDialogPrivate *priv; GFile *file; gchar *basename = NULL, *raw_basename; priv = COPY_THEME_DIALOG (user_data)->priv; file = G_FILE (data); raw_basename = g_file_get_basename (file); if (g_str_has_suffix (raw_basename, ".desktop")) { /* FIXME: validate key file? */ basename = g_strndup (raw_basename, /* 8 = strlen (".desktop") */ strlen (raw_basename) - 8); } g_free (raw_basename); if (basename) { g_object_ref (file); priv->all_files = g_slist_append (priv->all_files, file); priv->all_basenames = g_slist_append (priv->all_basenames, basename); priv->total_files++; } else { GtkWidget *dialog; gchar *uri; dialog = gtk_message_dialog_new (GTK_WINDOW (user_data), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Invalid screensaver theme")); uri = g_file_get_uri (file); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), _("%s does not appear to be a valid screensaver theme."), uri); g_free (uri); gtk_window_set_title (GTK_WINDOW (dialog), ""); gtk_window_set_icon_name (GTK_WINDOW (dialog), "preferences-desktop-screensaver"); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } } static void single_copy_complete (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; gboolean should_continue = FALSE; CopyThemeDialog *dialog = COPY_THEME_DIALOG (user_data); if (g_file_copy_finish (G_FILE (source_object), res, &error)) { should_continue = TRUE; } else { /* If the file already exists, generate a new random name * and try again. **/ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) { GFile *file, *destination; gchar *basename, *full_basename; g_error_free (error); file = G_FILE (dialog->priv->file->data); basename = (gchar *) (dialog->priv->basename->data); g_return_if_fail (file != NULL); g_return_if_fail (basename != NULL); full_basename = g_strdup_printf ("%s-%u.desktop", basename, g_random_int ()); destination = g_file_get_child (dialog->priv->theme_dir, full_basename); g_free (full_basename); g_file_copy_async (file, destination, G_FILE_COPY_NONE, G_PRIORITY_DEFAULT, dialog->priv->cancellable, NULL, NULL, single_copy_complete, dialog); } else { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { /* User has cancelled the theme copy */ g_signal_emit (G_OBJECT (dialog), signals[CANCELLED], 0, NULL); } else { /* Some other error occurred, ignore and * try to copy remaining files **/ should_continue = TRUE; } g_error_free (error); } } /* Update informational widgets and, if needed, signal * copy completion. **/ if (should_continue) { dialog->priv->index++; dialog->priv->file = dialog->priv->file->next; dialog->priv->basename = dialog->priv->basename->next; copy_theme_dialog_update_num_files (dialog); copy_theme_dialog_copy_next (dialog); } } /* Try to copy the theme file to the user's screensaver directory. * If a file with the given name already exists, the error will be * caught later and the copy re-attempted with a random value * appended to the filename. **/ static void copy_theme_dialog_copy_next (CopyThemeDialog *dialog) { GFile *file, *destination; gchar *basename, *full_basename; if (copy_finished (dialog)) { g_signal_emit (G_OBJECT (dialog), signals[COMPLETE], 0, NULL); return; } file = G_FILE (dialog->priv->file->data); basename = (gchar *) (dialog->priv->basename->data); g_return_if_fail (file != NULL); g_return_if_fail (basename != NULL); full_basename = g_strdup_printf ("%s.desktop", basename); destination = g_file_get_child (dialog->priv->theme_dir, full_basename); g_free (full_basename); g_file_copy_async (file, destination, G_FILE_COPY_NONE, G_PRIORITY_DEFAULT, dialog->priv->cancellable, NULL, NULL, single_copy_complete, dialog); } static gboolean timeout_display_dialog (gpointer data) { if (IS_COPY_THEME_DIALOG (data)) { CopyThemeDialog *dialog = COPY_THEME_DIALOG (data); if (!copy_finished (dialog)) { gtk_widget_show (GTK_WIDGET (dialog)); g_signal_connect (dialog, "response", G_CALLBACK (copy_theme_dialog_response), dialog); } } return FALSE; } void copy_theme_dialog_begin (CopyThemeDialog *dialog) { gtk_widget_hide (GTK_WIDGET (dialog)); /* If the copy operation takes more than half a second to * complete, display the dialog. **/ g_timeout_add (500, timeout_display_dialog, dialog); copy_theme_dialog_copy_next (dialog); } static void copy_theme_dialog_cancel (CopyThemeDialog *dialog) { g_cancellable_cancel (dialog->priv->cancellable); } static void copy_theme_dialog_finalize (GObject *obj) { CopyThemeDialog *dlg = COPY_THEME_DIALOG (obj); g_object_unref (dlg->priv->theme_dir); g_slist_foreach (dlg->priv->all_files, (GFunc) (g_object_unref), NULL); g_slist_free (dlg->priv->all_files); g_slist_foreach (dlg->priv->all_basenames, (GFunc) (g_free), NULL); g_slist_free (dlg->priv->all_basenames); g_object_unref (dlg->priv->cancellable); if (parent_class->finalize) parent_class->finalize (G_OBJECT (dlg)); } static void copy_theme_dialog_update_num_files (CopyThemeDialog *dlg) { gchar *str = g_strdup_printf (_("Copying file: %u of %u"), dlg->priv->index, dlg->priv->total_files); gtk_progress_bar_set_text (GTK_PROGRESS_BAR (dlg->priv->progress), str); g_free (str); } static void copy_theme_dialog_response (GtkDialog *dialog, gint response_id) { g_cancellable_cancel (COPY_THEME_DIALOG (dialog)->priv->cancellable); } /** * eel_gtk_label_make_bold. * * Switches the font of label to a bold equivalent. * @label: The label. **/ static void eel_gtk_label_make_bold (GtkLabel *label) { PangoFontDescription *font_desc; font_desc = pango_font_description_new (); pango_font_description_set_weight (font_desc, PANGO_WEIGHT_BOLD); /* This will only affect the weight of the font, the rest is * from the current state of the widget, which comes from the * theme or user prefs, since the font desc only has the * weight flag turned on. */ gtk_widget_override_font (GTK_WIDGET (label), font_desc); pango_font_description_free (font_desc); } /* from caja */ static void create_titled_label (GtkTable *table, int row, GtkWidget **title_widget, GtkWidget **label_text_widget) { *title_widget = gtk_label_new (""); eel_gtk_label_make_bold (GTK_LABEL (*title_widget)); gtk_widget_set_halign (*title_widget, GTK_ALIGN_END); gtk_widget_set_valign (*title_widget, GTK_ALIGN_START); gtk_table_attach (table, *title_widget, 0, 1, row, row + 1, GTK_FILL, 0, 0, 0); gtk_widget_show (*title_widget); *label_text_widget = gtk_label_new (""); gtk_label_set_ellipsize (GTK_LABEL (*label_text_widget), PANGO_ELLIPSIZE_END); gtk_table_attach (table, *label_text_widget, 1, 2, row, row + 1, GTK_FILL | GTK_EXPAND, 0, 0, 0); gtk_widget_show (*label_text_widget); gtk_widget_set_halign (*label_text_widget, GTK_ALIGN_START); gtk_widget_set_valign (*label_text_widget, GTK_ALIGN_START); } ukui-control-center/panels/power/egg-dbus-monitor.h0000664000175000017500000000463313057175444021402 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #ifndef __EGG_DBUS_MONITOR_H #define __EGG_DBUS_MONITOR_H #include #include G_BEGIN_DECLS #define EGG_TYPE_DBUS_MONITOR (egg_dbus_monitor_get_type ()) #define EGG_DBUS_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EGG_TYPE_DBUS_MONITOR, EggDbusMonitor)) #define EGG_DBUS_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EGG_TYPE_DBUS_MONITOR, EggDbusMonitorClass)) #define EGG_IS_DBUS_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EGG_TYPE_DBUS_MONITOR)) #define EGG_IS_DBUS_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EGG_TYPE_DBUS_MONITOR)) #define EGG_DBUS_MONITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EGG_TYPE_DBUS_MONITOR, EggDbusMonitorClass)) #define EGG_DBUS_MONITOR_ERROR (egg_dbus_monitor_error_quark ()) #define EGG_DBUS_MONITOR_TYPE_ERROR (egg_dbus_monitor_error_get_type ()) typedef struct EggDbusMonitorPrivate EggDbusMonitorPrivate; typedef struct { GObject parent; EggDbusMonitorPrivate *priv; } EggDbusMonitor; typedef struct { GObjectClass parent_class; void (* connection_changed) (EggDbusMonitor *watch, gboolean connected); void (* connection_replaced) (EggDbusMonitor *watch); } EggDbusMonitorClass; GType egg_dbus_monitor_get_type (void); EggDbusMonitor *egg_dbus_monitor_new (void); gboolean egg_dbus_monitor_assign (EggDbusMonitor *monitor, DBusGConnection *connection, const gchar *service); gboolean egg_dbus_monitor_is_connected (EggDbusMonitor *monitor); G_END_DECLS #endif /* __EGG_DBUS_MONITOR_H */ ukui-control-center/panels/power/ukui-screensaver-preferences.c0000664000175000017500000013721513256625660024011 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2004-2006 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA * 02110-1301, USA. * * Authors: William Jon McCann * Rodrigo Moya * */ #include "config.h" #define _GNU_SOURCE #include #include #include #include /* For uid_t, gid_t */ #include #include #include #include #if GTK_CHECK_VERSION (3, 0, 0) #define MATE_DESKTOP_USE_UNSTABLE_API #include #define gdk_spawn_command_line_on_screen mate_gdk_spawn_command_line_on_screen #endif #include "copy-theme-dialog.h" #include "gs-theme-manager.h" #include "gs-job.h" #include "gs-prefs.h" /* for GS_MODE enum */ #include "kpm-brightness.h" #define GTK_BUILDER_FILE "ukui-fullscreen-preview.ui" #define LOCKDOWN_SETTINGS_SCHEMA "org.mate.lockdown" #define KEY_LOCK_DISABLE "disable-lock-screen" #define SESSION_SETTINGS_SCHEMA "org.ukui.session" #define KEY_IDLE_DELAY "idle-delay" #define GSETTINGS_SCHEMA "org.ukui.screensaver" #define KEY_LOCK "lock-enabled" #define KEY_IDLE_ACTIVATION_ENABLED "idle-activation-enabled" #define KEY_MODE "mode" #define KEY_LOCK_DELAY "lock-delay" #define KEY_CYCLE_DELAY "cycle-delay" #define KEY_THEMES "themes" #define GPM_COMMAND "ukui-power-preferences" #define KPM_SETTINGS_BRIGHTNESS_AC "brightness-ac" #define KPM_SETTINGS_SCHEMA "org.ukui.power-manager" enum { NAME_COLUMN = 0, ID_COLUMN, N_COLUMNS }; /* Drag and drop info */ enum { TARGET_URI_LIST, TARGET_NS_URL }; static GtkTargetEntry drop_types [] = { { "text/uri-list", 0, TARGET_URI_LIST }, { "_NETSCAPE_URL", 0, TARGET_NS_URL } }; static GtkBuilder *builder = NULL; static GtkBuilder *builder_preview = NULL; //预览时显示的界面 static GSThemeManager *theme_manager = NULL; static GSJob *job = NULL; static GSettings *screensaver_settings = NULL; static GSettings *session_settings = NULL; static GSettings *lockdown_settings = NULL; static GSettings *brightness_settings = NULL; static gint32 config_get_activate_delay (gboolean *is_writable) { gint32 delay; if (is_writable) { *is_writable = g_settings_is_writable (session_settings, KEY_IDLE_DELAY); } delay = g_settings_get_int (session_settings, KEY_IDLE_DELAY); if (delay < 1) { delay = 1; } return delay; } static void config_set_activate_delay (gint32 timeout) { g_settings_set_int (session_settings, KEY_IDLE_DELAY, timeout); } static int config_get_mode (gboolean *is_writable) { int mode; if (is_writable) { *is_writable = g_settings_is_writable (screensaver_settings, KEY_MODE); } mode = g_settings_get_enum (screensaver_settings, KEY_MODE); return mode; } static void config_set_mode (int mode) { g_settings_set_enum (screensaver_settings, KEY_MODE, mode); } static char * config_get_theme (gboolean *is_writable) { char *name; int mode; screensaver_settings = g_settings_new (GSETTINGS_SCHEMA); if (is_writable) { gboolean can_write_theme; gboolean can_write_mode; can_write_theme = g_settings_is_writable (screensaver_settings, KEY_THEMES); can_write_mode = g_settings_is_writable (screensaver_settings, KEY_MODE); *is_writable = can_write_theme && can_write_mode; } mode = config_get_mode (NULL); name = NULL; if (mode == GS_MODE_BLANK_ONLY) { name = g_strdup ("__blank-only"); } else if (mode == GS_MODE_RANDOM) { name = g_strdup ("__random"); } else { gchar **strv; strv = g_settings_get_strv (screensaver_settings, KEY_THEMES); if (strv != NULL) { name = g_strdup (strv[0]); } else { /* TODO: handle error */ /* default to blank */ name = g_strdup ("__blank-only"); } g_strfreev (strv); } return name; } static gchar ** get_all_theme_ids (GSThemeManager *theme_manager) { gchar **ids = NULL; GSList *entries; GSList *l; guint idx = 0; char *info_id; entries = gs_theme_manager_get_info_list (theme_manager); ids = g_new0 (gchar *, g_slist_length (entries) + 1); for (l = entries; l; l = l->next) { GSThemeInfo *info = l->data; info_id = gs_theme_info_get_id (info); //屏蔽掉随机中ukui-screensaver中的屏保 if(!strcmp(info_id, "screensavers-gnomelogo-floaters") || !strcmp(info_id, "screensavers-footlogo-floaters") || !strcmp(info_id, "screensavers-popsquares") || !strcmp(info_id, "screensavers-personal-slideshow") || !strcmp(info_id, "screensavers-cosmos-slideshow") || !strcmp(info_id, "ukui-screensavers-cosmos-slideshow") || !strcmp(info_id, "ukui-screensavers-footlogo-floaters") || !strcmp(info_id, "ukui-screensavers-popsquares") || !strcmp(info_id, "ukui-screensavers-personal-slideshow") || !strcmp(info_id, "ukui-screensavers-gnomelogo-floaters")) continue; ids[idx++] = g_strdup (info_id); gs_theme_info_unref (info); } g_slist_free (entries); return ids; } static void config_set_theme (const char *theme_id) { gchar **strv = NULL; int mode; screensaver_settings = g_settings_new (GSETTINGS_SCHEMA); if (theme_id && strcmp (theme_id, "__blank-only") == 0) { mode = GS_MODE_BLANK_ONLY; //0 } else if (theme_id && strcmp (theme_id, "__random") == 0) { mode = GS_MODE_RANDOM; //1 /* set the themes key to contain all available screensavers */ strv = get_all_theme_ids (theme_manager); } else { mode = GS_MODE_SINGLE; //2 strv = g_strsplit (theme_id, "%%%", 1); } config_set_mode (mode); g_settings_set_strv (screensaver_settings, KEY_THEMES, (const gchar * const*) strv); g_strfreev (strv); } static gboolean config_get_enabled (gboolean *is_writable) { int enabled; if (is_writable) { *is_writable = g_settings_is_writable (screensaver_settings, KEY_LOCK); } enabled = g_settings_get_boolean (screensaver_settings, KEY_IDLE_ACTIVATION_ENABLED); return enabled; } static void config_set_enabled (gboolean enabled) { g_settings_set_boolean (screensaver_settings, KEY_IDLE_ACTIVATION_ENABLED, enabled); if(enabled) system("ukui-screensaver-command --exit; nohup ukui-screensaver > /dev/null 2>&1 &"); } static gboolean config_get_lock (gboolean *is_writable) { gboolean lock; if (is_writable) { *is_writable = g_settings_is_writable (screensaver_settings, KEY_LOCK); } lock = g_settings_get_boolean (screensaver_settings, KEY_LOCK); return lock; } static gboolean config_get_lock_disabled () { return g_settings_get_boolean (lockdown_settings, KEY_LOCK_DISABLE); } static void config_set_lock (gboolean lock) { g_settings_set_boolean (screensaver_settings, KEY_LOCK, lock); } static void preview_clear (GtkWidget *widget) { //realize用于实例化该widget gtk_widget_realize(widget); if(gtk_widget_get_window(widget) == NULL){ g_warning("----The GdkWindow is NULL.----"); return; } cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(widget)); cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); cairo_fill(cr); cairo_destroy(cr); gtk_widget_queue_draw (widget); } static void job_set_theme (GSJob *job, const char *theme) { GSThemeInfo *info; const char *command; command = NULL; info = gs_theme_manager_lookup_theme_info (theme_manager, theme); if (info != NULL) { command = gs_theme_info_get_exec (info); } gs_job_set_command (job, command); if (info != NULL) { gs_theme_info_unref (info); } } static void preview_set_theme (GtkWidget *widget, const char *theme, const char *name) { GtkWidget *label; char *markup; if (job != NULL) { gs_job_stop (job); } preview_clear (widget); //label是预览时的间隔空白,传进来name只是为了给预览时的窗口加上标题 label = GTK_WIDGET (gtk_builder_get_object (builder_preview, "fullscreen_preview_theme_label")); markup = g_markup_printf_escaped ("%s", name); gtk_label_set_markup (GTK_LABEL (label), markup); g_free (markup); if ((theme && strcmp (theme, "__blank-only") == 0)) { } else if (theme && strcmp (theme, "__random") == 0) { gchar **themes; themes = get_all_theme_ids (theme_manager); if (themes != NULL) { gint32 i; i = g_random_int_range (0, g_strv_length (themes)); job_set_theme (job, themes[i]); g_strfreev (themes); gs_job_start (job); } } else { job_set_theme (job, theme); gs_job_start (job); } } //帮助界面 static void help_display (void) { GError *error; error = NULL; gtk_show_uri (NULL, "help:ukui-user-guide/prefs-screensaver", GDK_CURRENT_TIME, &error); if (error != NULL) { GtkWidget *d; d = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", error->message); gtk_dialog_run (GTK_DIALOG (d)); gtk_widget_destroy (d); g_error_free (error); } } static GSList * get_theme_info_list (void) { return gs_theme_manager_get_info_list (theme_manager); } //加载屏保 static void //populate_model (GtkTreeStore *store) populate_model (GtkTreeModel *model) { GtkTreeIter iter; GSList *themes = NULL; GSList *l; GtkWidget *theme_combo_box = GTK_WIDGET(gtk_builder_get_object(builder, "savers_combox")); /* //黑屏 gtk_tree_store_append (store, &iter, NULL); gtk_tree_store_set (store, &iter, NAME_COLUMN, _("Blank screen"), ID_COLUMN, "__blank-only", -1); //随机 gtk_tree_store_append (store, &iter, NULL); gtk_tree_store_set (store, &iter, NAME_COLUMN, _("Random"), ID_COLUMN, "__random", -1); //分隔符 gtk_tree_store_append (store, &iter, NULL); gtk_tree_store_set (store, &iter, NAME_COLUMN, NULL, ID_COLUMN, "__separator", -1); */ //只是添加的name,并没有添加id gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(theme_combo_box), _("Blank screen")); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(theme_combo_box), _("Random")); //其他主题屏保 themes = get_theme_info_list (); if (themes == NULL) { return; } for (l = themes; l; l = l->next) { const char *name; const char *id; GSThemeInfo *info = l->data; if (info == NULL) { continue; } name = gs_theme_info_get_name (info); id = gs_theme_info_get_id (info); //屏蔽掉下拉框中的ukui-screensaver中的屏保 if (!strcmp(id, "screensavers-popsquares") || !strcmp(id, "screensavers-gnomelogo-floaters") || !strcmp(id, "screensavers-footlogo-floaters") || !strcmp(id, "screensavers-personal-slideshow") || !strcmp(id, "screensavers-cosmos-slideshow") || !strcmp(id, "ukui-screensavers-popsquares") || !strcmp(id, "ukui-screensavers-gnomelogo-floaters") || !strcmp(id, "ukui-screensavers-footlogo-floaters") || !strcmp(id, "ukui-screensavers-personal-slideshow") || !strcmp(id, "ukui-screensavers-cosmos-slideshow")) continue; gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(theme_combo_box), name); gs_theme_info_unref (info); } g_slist_free (themes); } static void tree_selection_previous (GtkTreeSelection *selection) { GtkTreeIter iter; GtkTreeModel *model; GtkTreePath *path; if (! gtk_tree_selection_get_selected (selection, &model, &iter)) { return; } path = gtk_tree_model_get_path (model, &iter); if (gtk_tree_path_prev (path)) { gtk_tree_selection_select_path (selection, path); } } static void tree_selection_next (GtkTreeSelection *selection) { GtkTreeIter iter; GtkTreeModel *model; GtkTreePath *path; if (! gtk_tree_selection_get_selected (selection, &model, &iter)) { return; } path = gtk_tree_model_get_path (model, &iter); gtk_tree_path_next (path); gtk_tree_selection_select_path (selection, path); } static void combo_box_changed_cb (GtkWidget *theme_combo_box) { GtkTreeModel *model; GtkTreeIter iter; char *theme; GtkWidget *preview = GTK_WIDGET (gtk_builder_get_object (builder, "preview_area")); gtk_widget_show_all(preview); if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(theme_combo_box), &iter)) { model = gtk_combo_box_get_model(GTK_COMBO_BOX(theme_combo_box)); gtk_tree_model_get(model, &iter, 0, &theme, -1); GList *themes = NULL; GList *l; themes = get_theme_info_list (); if (themes == NULL) { return; } //处理黑屏和随机的情况,因为只有theme(对应name) if(!strcmp(theme, _("Random"))){ char *random_id = "__random"; preview_set_theme (preview, random_id, theme); config_set_theme (random_id); } if(!strcmp(theme, _("Blank screen"))){ char *blank_id = "__blank-only"; preview_set_theme (preview, blank_id, theme); config_set_theme (blank_id); } //其他的屏保,通过theme(name)可以获得其id值 for (l = themes; l; l = l->next) { char *name; char *id; GSThemeInfo *info = l->data; if (info == NULL) { continue; } name = gs_theme_info_get_name (info); id = gs_theme_info_get_id (info); if(!strcmp(theme, name)) { //设置屏保 preview_set_theme (preview, id, name); config_set_theme (id); } gs_theme_info_unref (info); } //g_free(theme); g_slist_free (themes); } } //为了保持和锁屏的时间布局一致,这里用label来显示值的变化 static void brightness_value_changed(GtkRange *range, gpointer user_data) { gchar label_text[10]; int value = gtk_range_get_value(range); sprintf(label_text, "%d%%", value); GtkWidget *label_value = GTK_WIDGET (gtk_builder_get_object (builder, "label_value")); gtk_label_set_text(GTK_LABEL(label_value),label_text); } static void activate_delay_value_changed_cb (GtkRange *range, gpointer user_data) { gchar *label_text; int value = gtk_range_get_value (range); int time = value * 60; int min = (time % (60 * 60)) / 60; int hour = time / (60 * 60); if (!hour) label_text = g_strdup_printf (_("%d min"), min); else label_text = g_strdup_printf (_("%d hour %d min"), hour,min); GtkWidget *label = GTK_WIDGET (gtk_builder_get_object (builder, "scale_label")); gtk_label_set_text(GTK_LABEL(label),""); gtk_label_set_text(GTK_LABEL(label),label_text); config_set_activate_delay ((gint32)value); } static int compare_theme_names (char *name_a, char *name_b, char *id_a, char *id_b) { if (id_a == NULL) { return 1; } else if (id_b == NULL) { return -1; } if (strcmp (id_a, "__blank-only") == 0) { return -1; } else if (strcmp (id_b, "__blank-only") == 0) { return 1; } else if (strcmp (id_a, "__random") == 0) { return -1; } else if (strcmp (id_b, "__random") == 0) { return 1; } else if (strcmp (id_a, "__separator") == 0) { return -1; } else if (strcmp (id_b, "__separator") == 0) { return 1; } if (name_a == NULL) { return 1; } else if (name_b == NULL) { return -1; } return g_utf8_collate (name_a, name_b); } static int compare_theme (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) { char *name_a; char *name_b; char *id_a; char *id_b; int result; gtk_tree_model_get (model, a, NAME_COLUMN, &name_a, -1); gtk_tree_model_get (model, b, NAME_COLUMN, &name_b, -1); gtk_tree_model_get (model, a, ID_COLUMN, &id_a, -1); gtk_tree_model_get (model, b, ID_COLUMN, &id_b, -1); result = compare_theme_names (name_a, name_b, id_a, id_b); g_free (name_a); g_free (name_b); g_free (id_a); g_free (id_b); return result; } static void setup_combo_box (GtkWidget *theme_combo_box, GtkWidget *preview) { GtkTreeModel *model; model = gtk_combo_box_get_model(GTK_COMBO_BOX(theme_combo_box)); populate_model (GTK_TREE_MODEL(model)); //GtkWidget *theme_combo_box = GTK_WIDGET(gtk_builder_get_object(builder, "comboboxtext1")); g_signal_connect (G_OBJECT (theme_combo_box), "changed", G_CALLBACK (combo_box_changed_cb), NULL); } //初始化combo_box的值 static void setup_combo_box_selection (GtkWidget *combo_box) { char *theme; char *name; char *combo_box_text; GtkTreeModel *model; GtkTreeIter iter; gboolean is_writable; gboolean valid; //获取到当前所设置的屏保的id theme = config_get_theme (&is_writable); if (! is_writable) { gtk_widget_set_sensitive (combo_box, FALSE); } //先通过id获取到name if (!strcmp(theme, "__random")) name = _("Random"); if (!strcmp(theme, "__blank-only")) name = _("Blank screen"); GList *themes = NULL; GList *l; themes = get_theme_info_list (); if (themes == NULL) { return; } for (l = themes; l; l = l->next) { //const char *name; const char *id; GSThemeInfo *info = l->data; if (info == NULL) { continue; } //name = gs_theme_info_get_name (info); id = gs_theme_info_get_id (info); if(!strcmp(theme, id)) { name = gs_theme_info_get_name (info); break; } gs_theme_info_unref (info); } //再通过当前name和从combo_box中获得到的name进行比较 model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo_box)); valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); while (valid && name) { gtk_tree_model_get(model, &iter, 0, &combo_box_text, -1); if(!strcmp(name, combo_box_text)){ gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo_box), &iter); //preview_set_theme (preview, theme, name); valid = FALSE; } else valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); } g_free(theme); g_slist_free (themes); } //加载combo_box中的各种屏保 static void reload_themes (void) { GtkWidget *theme_combo_box; GtkTreeModel *model; theme_combo_box = GTK_WIDGET(gtk_builder_get_object(builder, "savers_combox")); model = gtk_combo_box_get_model(GTK_COMBO_BOX(theme_combo_box)); populate_model (GTK_TREE_MODEL(model)); gtk_combo_box_set_model(GTK_COMBO_BOX (theme_combo_box), GTK_TREE_MODEL (model)); } static void theme_copy_complete_cb (GtkWidget *dialog, gpointer user_data) { reload_themes (); gtk_widget_destroy (dialog); } static void theme_installer_run (GtkWidget *prefs_dialog, GList *files) { GtkWidget *copy_dialog; copy_dialog = copy_theme_dialog_new (files); g_list_foreach (files, (GFunc) (g_object_unref), NULL); g_list_free (files); gtk_window_set_transient_for (GTK_WINDOW (copy_dialog), GTK_WINDOW (prefs_dialog)); gtk_window_set_icon_name (GTK_WINDOW (copy_dialog), "preferences-desktop-screensaver"); g_signal_connect (copy_dialog, "complete", G_CALLBACK (theme_copy_complete_cb), NULL); copy_theme_dialog_begin (COPY_THEME_DIALOG (copy_dialog)); } /* Callback issued during drag movements */ static gboolean drag_motion_cb (GtkWidget *widget, GdkDragContext *context, int x, int y, guint time, gpointer data) { return FALSE; } /* Callback issued during drag leaves */ static void drag_leave_cb (GtkWidget *widget, GdkDragContext *context, guint time, gpointer data) { gtk_widget_queue_draw (widget); } /* GIO has no version of mate_vfs_uri_list_parse(), so copy from MateVFS * and re-work to create GFiles. **/ static GList * uri_list_parse (const gchar *uri_list) { const gchar *p, *q; gchar *retval; GFile *file; GList *result = NULL; g_return_val_if_fail (uri_list != NULL, NULL); p = uri_list; /* We don't actually try to validate the URI according to RFC * 2396, or even check for allowed characters - we just ignore * comments and trim whitespace off the ends. We also * allow LF delimination as well as the specified CRLF. */ while (p != NULL) { if (*p != '#') { while (g_ascii_isspace (*p)) p++; q = p; while ((*q != '\0') && (*q != '\n') && (*q != '\r')) q++; if (q > p) { q--; while (q > p && g_ascii_isspace (*q)) q--; retval = g_malloc (q - p + 2); strncpy (retval, p, q - p + 1); retval[q - p + 1] = '\0'; file = g_file_new_for_uri (retval); g_free (retval); if (file != NULL) result = g_list_prepend (result, file); } } p = strchr (p, '\n'); if (p != NULL) p++; } return g_list_reverse (result); } /* Callback issued on actual drops. Attempts to load the file dropped. */ static void drag_data_received_cb (GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *selection_data, guint info, guint time, gpointer data) { GList *files; if (!(info == TARGET_URI_LIST || info == TARGET_NS_URL)) return; files = uri_list_parse ((char *) gtk_selection_data_get_data (selection_data)); if (files != NULL) { GtkWidget *prefs_dialog; prefs_dialog = GTK_WIDGET (gtk_builder_get_object (builder, "prefs_dialog")); theme_installer_run (prefs_dialog, files); } } static void lock_checkbox_toggled (GtkToggleButton *button, gpointer user_data) { config_set_lock (gtk_toggle_button_get_active (button)); } static void enabled_checkbox_toggled (GtkToggleButton *button, gpointer user_data) { config_set_enabled (gtk_toggle_button_get_active (button)); } static void ui_disable_lock (gboolean disable) { GtkWidget *widget; widget = GTK_WIDGET (gtk_builder_get_object (builder, "screensaver_lock_checkbox")); gtk_widget_set_sensitive (widget, !disable); if (disable) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE); } } static void ui_set_lock (gboolean enabled) { GtkWidget *widget; gboolean active; gboolean lock_disabled; widget = GTK_WIDGET (gtk_builder_get_object (builder, "screensaver_lock_checkbox")); active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); if (active != enabled) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), enabled); } lock_disabled = config_get_lock_disabled (); ui_disable_lock (lock_disabled); } static void ui_set_enabled (gboolean enabled) { GtkWidget *widget; gboolean active; gboolean is_writable; gboolean lock_disabled; widget = GTK_WIDGET (gtk_builder_get_object (builder, "screensaver_enable_checkbox")); active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); if (active != enabled) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), enabled); } widget = GTK_WIDGET (gtk_builder_get_object (builder, "screensaver_lock_checkbox")); config_get_lock (&is_writable); if (is_writable) { gtk_widget_set_sensitive (widget, enabled); } lock_disabled = config_get_lock_disabled (); ui_disable_lock(lock_disabled); } static void ui_set_delay (int delay) { GtkWidget *widget; widget = GTK_WIDGET (gtk_builder_get_object (builder, "activate_delay_hscale")); gtk_range_set_value (GTK_RANGE (widget), delay); } static void key_changed_cb (GSettings *settings, const gchar *key, gpointer data) { if (strcmp (key, KEY_IDLE_ACTIVATION_ENABLED) == 0) { gboolean enabled; enabled = g_settings_get_boolean (settings, key); ui_set_enabled (enabled); } else if (strcmp (key, KEY_LOCK) == 0) { gboolean enabled; enabled = g_settings_get_boolean (settings, key); ui_set_lock (enabled); } else if (strcmp (key, KEY_LOCK_DISABLE) == 0) { gboolean disabled; disabled = g_settings_get_boolean (settings, key); ui_disable_lock (disabled); } else if (strcmp (key, KEY_THEMES) == 0) { GtkWidget *combo_box; combo_box = GTK_WIDGET (gtk_builder_get_object (builder, "savers_combox")); setup_combo_box_selection (combo_box); } else if (strcmp (key, KEY_IDLE_DELAY) == 0) { int delay; delay = g_settings_get_int (settings, key); ui_set_delay (delay); } else { /*g_warning ("Config key not handled: %s", key);*/ } } //预览下的向前操作的callback static void fullscreen_preview_previous_cb (GtkWidget *fullscreen_preview_window, gpointer user_data) { GtkWidget *combo_box; GtkTreeIter iter; GtkTreeModel *model; combo_box = GTK_WIDGET (gtk_builder_get_object (builder, "savers_combox")); gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo_box), &iter); model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo_box)); //这里因为gtk_tree_model_iter_previous这个api是3.0的,所以我也不知道怎么获取它的上一个迭代器。 if(gtk_tree_model_iter_previous(model, &iter)) gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo_box), &iter); else return; } //预览模式下向后操作的callback static void fullscreen_preview_next_cb (GtkWidget *fullscreen_preview_window, gpointer user_data) { GtkWidget *combo_box; GtkTreeIter iter; GtkTreeModel *model; combo_box = GTK_WIDGET (gtk_builder_get_object (builder, "savers_combox")); gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo_box), &iter); model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo_box)); if(gtk_tree_model_iter_next(model, &iter)) gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo_box), &iter); else return; } //预览模式下取消的callback static void fullscreen_preview_cancelled_cb (GtkWidget *button, gpointer user_data) { GtkWidget *fullscreen_preview_area; GtkWidget *fullscreen_preview_window; GtkWidget *preview_area; GtkWidget *dialog; preview_area = GTK_WIDGET (gtk_builder_get_object (builder, "preview_area")); gs_job_set_widget (job, preview_area); fullscreen_preview_area = GTK_WIDGET (gtk_builder_get_object (builder_preview, "fullscreen_preview_area")); preview_clear (fullscreen_preview_area); fullscreen_preview_window = GTK_WIDGET (gtk_builder_get_object (builder_preview, "fullscreen_preview_window")); gtk_widget_hide (fullscreen_preview_window); } //预览显示的回调 static void fullscreen_preview_start_cb (GtkWidget *widget, gpointer user_data) { GtkWidget *fullscreen_preview_area; GtkWidget *fullscreen_preview_window; fullscreen_preview_window = GTK_WIDGET (gtk_builder_get_object (builder_preview, "fullscreen_preview_window")); gtk_window_fullscreen (GTK_WINDOW (fullscreen_preview_window)); gtk_window_set_keep_above (GTK_WINDOW (fullscreen_preview_window), TRUE); gtk_widget_show (fullscreen_preview_window); gtk_widget_grab_focus (fullscreen_preview_window); fullscreen_preview_area = GTK_WIDGET (gtk_builder_get_object (builder_preview, "fullscreen_preview_area")); preview_clear (fullscreen_preview_area); gs_job_set_widget (job, fullscreen_preview_area); } static void constrain_list_size (GtkWidget *widget, GtkRequisition *requisition, GtkWidget *to_size) { GtkRequisition req; int max_height; /* constrain height to be the tree height up to a max */ max_height = (gdk_screen_get_height (gtk_widget_get_screen (widget))) / 4; gtk_widget_size_request (to_size, &req); requisition->height = MIN (req.height, max_height); } static gboolean check_is_root_user (void) { #ifndef G_OS_WIN32 uid_t ruid, euid, suid; /* Real, effective and saved user ID's */ gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */ #ifdef HAVE_GETRESUID if (getresuid (&ruid, &euid, &suid) != 0 || getresgid (&rgid, &egid, &sgid) != 0) #endif /* HAVE_GETRESUID */ { suid = ruid = getuid (); sgid = rgid = getgid (); euid = geteuid (); egid = getegid (); } if (ruid == 0) { return TRUE; } #endif return FALSE; } static void setup_for_root_user (void) { GtkWidget *lock_checkbox; GtkWidget *label; lock_checkbox = GTK_WIDGET (gtk_builder_get_object (builder, "screensaver_lock_checkbox")); label = GTK_WIDGET (gtk_builder_get_object (builder, "root_warning_label")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lock_checkbox), FALSE); gtk_widget_set_sensitive (lock_checkbox, FALSE); gtk_widget_show (label); } static GdkVisual * get_best_visual (void) { char *command; char *std_output; int exit_status; GError *error; unsigned long v; char c; GdkVisual *visual; gboolean res; visual = NULL; command = g_build_filename (LIBEXECDIR, "ukui-screensaver-gl-helper", NULL); error = NULL; res = g_spawn_command_line_sync (command, &std_output, NULL, &exit_status, &error); if (! res) { g_debug ("Could not run command '%s': %s", command, error->message); g_error_free (error); goto out; } if (1 == sscanf (std_output, "0x%lx %c", &v, &c)) { if (v != 0) { VisualID visual_id; visual_id = (VisualID) v; visual = gdk_x11_screen_lookup_visual (gdk_screen_get_default (), visual_id); g_debug ("Found best visual for GL: 0x%x", (unsigned int) visual_id); } } out: g_free (std_output); g_free (command); return visual; } //#if GTK_CHECK_VERSION (3, 0, 0) /* copied from gs-window-x11.c */ extern char **environ; static gchar ** spawn_make_environment_for_screen (GdkScreen *screen, gchar **envp) { gchar **retval = NULL; gchar *display_name; gint display_index = -1; gint i, env_len; g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); if (envp == NULL) envp = environ; for (env_len = 0; envp[env_len]; env_len++) if (strncmp (envp[env_len], "DISPLAY", strlen ("DISPLAY")) == 0) display_index = env_len; retval = g_new (char *, env_len + 1); retval[env_len] = NULL; display_name = gdk_screen_make_display_name (screen); for (i = 0; i < env_len; i++) if (i == display_index) retval[i] = g_strconcat ("DISPLAY=", display_name, NULL); else retval[i] = g_strdup (envp[i]); g_assert (i == env_len); g_free (display_name); return retval; } static gboolean spawn_command_line_on_screen_sync (GdkScreen *screen, const gchar *command_line, char **standard_output, char **standard_error, int *exit_status, GError **error) { char **argv = NULL; char **envp = NULL; gboolean retval; g_return_val_if_fail (command_line != NULL, FALSE); if (! g_shell_parse_argv (command_line, NULL, &argv, error)) { return FALSE; } envp = spawn_make_environment_for_screen (screen, NULL); retval = g_spawn_sync (NULL, argv, envp, G_SPAWN_SEARCH_PATH, NULL, NULL, standard_output, standard_error, exit_status, error); g_strfreev (argv); g_strfreev (envp); return retval; } static GdkVisual * get_best_visual_for_screen (GdkScreen *screen) { char *command; char *std_output; int exit_status; GError *error; unsigned long v; char c; GdkVisual *visual; gboolean res; visual = NULL; command = g_build_filename (LIBEXECDIR, "ukui-screensaver-gl-helper", NULL); error = NULL; std_output = NULL; res = spawn_command_line_on_screen_sync (screen, command, &std_output, NULL, &exit_status, &error); if (! res) { g_debug ("Could not run command '%s': %s", command, error->message); g_error_free (error); goto out; } if (1 == sscanf (std_output, "0x%lx %c", &v, &c)) { if (v != 0) { VisualID visual_id; visual_id = (VisualID) v; visual = gdk_x11_screen_lookup_visual (screen, visual_id); g_debug ("Found best GL visual for screen %d: 0x%x", gdk_screen_get_number (screen), (unsigned int) visual_id); } } out: g_free (std_output); g_free (command); return visual; } static void widget_set_best_visual (GtkWidget *widget) { GdkVisual *visual; g_return_if_fail (widget != NULL); visual = get_best_visual_for_screen (gtk_widget_get_screen (widget)); if (visual != NULL) { gtk_widget_set_visual (widget, visual); g_object_unref (visual); } } static gboolean setup_treeview_idle (gpointer data) { GtkWidget *preview; GtkWidget *theme_combo_box; preview = GTK_WIDGET (gtk_builder_get_object (builder, "preview_area")); //treeview = GTK_WIDGET (gtk_builder_get_object (builder, "savers_treeview")); theme_combo_box = GTK_WIDGET (gtk_builder_get_object (builder, "savers_combox")); setup_combo_box (theme_combo_box, preview); setup_combo_box_selection (theme_combo_box); //setup_treeview_selection (treeview); return FALSE; } static gboolean is_program_in_path (const char *program) { char *tmp = g_find_program_in_path (program); if (tmp != NULL) { g_free (tmp); return TRUE; } else { return FALSE; } } void init_scale(GtkWidget *scale_label,gdouble time) { gchar *label_text; int timeout = time; int hour = timeout/60; int min = timeout%60; if (!hour) label_text = g_strdup_printf (_("%d min"), min); else label_text = g_strdup_printf (_("%d hour %d min"), hour,min); gtk_label_set_text(GTK_LABEL(scale_label),label_text); } //void show_preview(GtkWidget *widget, gpointer user_data) //{ // g_warning("------------111111111-----------"); // GtkWidget *combo_box = GTK_WIDGET (gtk_builder_get_object (builder, "savers_combox")); // combo_box_changed_cb (combo_box); //} //magical function gboolean show_preview(GtkWidget *widget, cairo_t *cr, gpointer data) { GdkRGBA black = { 0.0, 0.0, 0.0, 1.0 }; gdk_cairo_set_source_rgba(cr, &black); cairo_paint(cr); return FALSE; } static void init_capplet (void) { GtkWidget *dialog; GtkWidget *preview; GtkWidget *combo_box; GtkWidget *list_scroller; GtkWidget *activate_delay_hscale; GtkWidget *activate_delay_hbox; GtkWidget *label; GtkWidget *enabled_checkbox; GtkWidget *lock_checkbox; GtkWidget *root_warning_label; GtkWidget *preview_button; GtkWidget *gpm_button; GtkWidget *fullscreen_preview_window; GtkWidget *fullscreen_preview_previous; GtkWidget *fullscreen_preview_next; GtkWidget *fullscreen_preview_area; GtkWidget *fullscreen_preview_close; char *gtk_builder_file; gdouble activate_delay; gboolean enabled; gboolean is_writable; GError *error=NULL; gint mode; GtkWidget *vp_screen; //gtk_builder_file = g_build_filename (GTKBUILDERDIR, GTK_BUILDER_FILE, NULL); builder_preview = gtk_builder_new(); if (!gtk_builder_add_from_file(builder_preview, UIDIR "/ukui-fullscreen-preview.ui", &error)) { g_warning("Couldn't load builder file: %s", error->message); g_error_free(error); } g_free (gtk_builder_file); if (builder == NULL) { dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not load the main interface")); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), _("Please make sure that the screensaver is properly installed")); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); exit (1); } preview = GTK_WIDGET (gtk_builder_get_object (builder, "preview_area")); activate_delay_hscale = GTK_WIDGET (gtk_builder_get_object (builder, "activate_delay_hscale")); enabled_checkbox = GTK_WIDGET (gtk_builder_get_object (builder, "screensaver_enable_checkbox")); lock_checkbox = GTK_WIDGET (gtk_builder_get_object (builder, "screensaver_lock_checkbox")); preview_button = GTK_WIDGET (gtk_builder_get_object (builder, "preview_button")); combo_box = GTK_WIDGET (gtk_builder_get_object (builder, "savers_combox")); GtkWidget *scale_label = GTK_WIDGET (gtk_builder_get_object (builder, "scale_label")); gtk_label_set_xalign(GTK_LABEL(scale_label), 0.0); //调节显示器亮度的相关设置 GtkWidget *label_ac_brightness = GTK_WIDGET (gtk_builder_get_object (builder, "label_ac_brightness")); gtk_label_set_xalign(GTK_LABEL(label_ac_brightness), 0.0); GtkWidget *label_value = GTK_WIDGET (gtk_builder_get_object (builder, "label_value")); gtk_label_set_xalign(GTK_LABEL(label_value), 0.17); GtkWidget *hscale_ac_brightness = GTK_WIDGET (gtk_builder_get_object (builder, "hscale_ac_brightness")); brightness_settings = g_settings_new (KPM_SETTINGS_SCHEMA); g_settings_bind (brightness_settings, KPM_SETTINGS_BRIGHTNESS_AC, gtk_range_get_adjustment (GTK_RANGE (hscale_ac_brightness)), "value", G_SETTINGS_BIND_DEFAULT); //初始化显示器亮度的设置,直接调用回调 brightness_value_changed(hscale_ac_brightness, NULL); g_signal_connect(hscale_ac_brightness, "value-changed", G_CALLBACK (brightness_value_changed), NULL); //检查硬件是否支持亮度设置 KpmBrightness *brightness = kpm_brightness_new (); gboolean has_lcd = kpm_brightness_has_hw (brightness); g_object_unref (brightness); //不支持时隐藏设置选项并调整布局 if(has_lcd == FALSE) { GtkWidget *widget = GTK_WIDGET (gtk_builder_get_object (builder, "brightness_hbox")); gtk_widget_hide(widget); widget = GTK_WIDGET (gtk_builder_get_object (builder, "layout10_screensaver")); gtk_layout_move(GTK_LAYOUT(widget), enabled_checkbox, 25, 415); gtk_layout_move(GTK_LAYOUT(widget), lock_checkbox, 25, 450); } fullscreen_preview_window = GTK_WIDGET (gtk_builder_get_object (builder_preview, "fullscreen_preview_window")); fullscreen_preview_area = GTK_WIDGET (gtk_builder_get_object (builder_preview, "fullscreen_preview_area")); fullscreen_preview_close = GTK_WIDGET (gtk_builder_get_object (builder_preview, "fullscreen_preview_close")); fullscreen_preview_previous = GTK_WIDGET (gtk_builder_get_object (builder_preview, "fullscreen_preview_previous_button")); fullscreen_preview_next = GTK_WIDGET (gtk_builder_get_object (builder_preview, "fullscreen_preview_next_button")); //因为没有向前的api,所以暂时先屏蔽掉向前和向后预览 gtk_widget_set_no_show_all (fullscreen_preview_previous, FALSE); gtk_widget_set_no_show_all (fullscreen_preview_next, FALSE); gtk_widget_hide(fullscreen_preview_previous); gtk_widget_hide(fullscreen_preview_next); g_signal_connect(preview, "draw", G_CALLBACK(show_preview), NULL); label = GTK_WIDGET (gtk_builder_get_object (builder, "activate_delay_label")); gtk_label_set_xalign(GTK_LABEL(label), 0.0); gtk_label_set_mnemonic_widget (GTK_LABEL (label), activate_delay_hscale); label = GTK_WIDGET (gtk_builder_get_object (builder, "label63_screen")); gtk_label_set_xalign(GTK_LABEL(label), 0.0); widget_set_best_visual (preview); if (! is_program_in_path (GPM_COMMAND)) { gtk_widget_set_no_show_all (gpm_button, TRUE); gtk_widget_hide (gpm_button); } screensaver_settings = g_settings_new (GSETTINGS_SCHEMA); g_signal_connect (screensaver_settings, "changed", G_CALLBACK (key_changed_cb), NULL); session_settings = g_settings_new (SESSION_SETTINGS_SCHEMA); g_signal_connect (session_settings, "changed::" KEY_IDLE_DELAY, G_CALLBACK (key_changed_cb), NULL); lockdown_settings = g_settings_new (LOCKDOWN_SETTINGS_SCHEMA); g_signal_connect (lockdown_settings, "changed::" KEY_LOCK_DISABLE, G_CALLBACK (key_changed_cb), NULL); activate_delay = config_get_activate_delay (&is_writable); ui_set_delay (activate_delay); if (! is_writable) { gtk_widget_set_sensitive (activate_delay_hbox, FALSE); } gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lock_checkbox), config_get_lock (&is_writable)); if (! is_writable) { gtk_widget_set_sensitive (lock_checkbox, FALSE); } g_signal_connect (lock_checkbox, "toggled", G_CALLBACK (lock_checkbox_toggled), NULL); enabled = config_get_enabled (&is_writable); init_scale(scale_label, activate_delay); ui_set_enabled (enabled); if (! is_writable) { gtk_widget_set_sensitive (enabled_checkbox, FALSE); } g_signal_connect (enabled_checkbox, "toggled", G_CALLBACK (enabled_checkbox_toggled), NULL); /* Update list of themes if using random screensaver */ mode = g_settings_get_enum (screensaver_settings, KEY_MODE); if (mode == GS_MODE_RANDOM) { gchar **list; list = get_all_theme_ids (theme_manager); g_settings_set_strv (screensaver_settings, KEY_THEMES, (const gchar * const*) list); g_strfreev (list); } preview_clear (preview); //设置job中的widget,用于显示屏保 gs_job_set_widget (job, preview); if (check_is_root_user ()) { setup_for_root_user (); } g_signal_connect (activate_delay_hscale, "value-changed", G_CALLBACK (activate_delay_value_changed_cb), NULL); g_signal_connect (preview_button, "clicked", G_CALLBACK (fullscreen_preview_start_cb), combo_box); g_signal_connect (fullscreen_preview_close, "clicked", G_CALLBACK (fullscreen_preview_cancelled_cb), NULL); g_signal_connect (fullscreen_preview_previous, "clicked", G_CALLBACK (fullscreen_preview_previous_cb), NULL); g_signal_connect (fullscreen_preview_next, "clicked", G_CALLBACK (fullscreen_preview_next_cb), NULL); g_idle_add ((GSourceFunc)setup_treeview_idle, NULL); } static void finalize_capplet (void) { //正确的做法是在回调里直接new一个,修改完之后再减引用计数,但这里设置的是一个 //全局的gsettings所以不能这样。 //g_object_unref (screensaver_settings); //g_object_unref (session_settings); //g_object_unref (lockdown_settings); } void screensaver_init(GtkBuilder *screensaver_builder) { g_warning("add screensaver"); builder = screensaver_builder; job = gs_job_new(); theme_manager = gs_theme_manager_new (); init_capplet(); GSPrefs *prefs = gs_prefs_new (); // finalize_capplet(); } ukui-control-center/panels/power/kpm-common.c0000664000175000017500000001103613253611037020252 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2005-2007 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #include "config.h" #include #include #include #include #include #include "egg-debug.h" #include "kpm-common.h" /** * kpm_get_timestring: * @time_secs: The time value to convert in seconds * @cookie: The cookie we are looking for * * Returns a localised timestring * * Return value: The time string, e.g. "2 hours 3 minutes" **/ gchar * kpm_get_timestring (guint time_secs) { char* timestring = NULL; gint hours; gint minutes; /* Add 0.5 to do rounding */ minutes = (int) ( ( time_secs / 60.0 ) + 0.5 ); if (minutes == 0) { timestring = g_strdup (_("Unknown time")); return timestring; } if (minutes < 60) { timestring = g_strdup_printf (ngettext("%i minutes", "%i minutes", minutes), minutes); return timestring; } hours = minutes / 60; minutes = minutes % 60; if (minutes == 0) timestring = g_strdup_printf (ngettext( "%i hours", "%i hours", hours), hours); else /* TRANSLATOR: "%i %s %i %s" are "%i hours %i minutes" * Swap order with "%2$s %2$i %1$s %1$i if needed */ timestring = g_strdup_printf (_("%i %s %i %s"), hours, ngettext("hour", "hours", hours), minutes, ngettext("minute", "minutes", minutes)); return timestring; } /** * gpm_discrete_from_percent: * @percentage: The percentage to convert * @levels: The number of discrete levels * * We have to be carefull when converting from %->discrete as precision is very * important if we want the highest value. * * Return value: The discrete value for this percentage. **/ guint gpm_discrete_from_percent (guint percentage, guint levels) { /* check we are in range */ if (percentage > 100) return levels; if (levels == 0) { g_warning ("levels is 0!"); return 0; } return (guint) ((((gfloat) percentage * (gfloat) (levels - 1)) / 100.0f) + 0.5f); } /** * gpm_discrete_to_percent: * @hw: The discrete level * @levels: The number of discrete levels * * We have to be carefull when converting from discrete->%. * * Return value: The percentage for this discrete value. **/ guint gpm_discrete_to_percent (guint discrete, guint levels) { /* check we are in range */ if (discrete > levels) return 100; if (levels == 0) { g_warning ("levels is 0!"); return 0; } return (guint) (((gfloat) discrete * (100.0f / (gfloat) (levels - 1))) + 0.5f); } /** * gpm_help_display: * @link_id: Subsection of ukui-power-manager help section **/ void gpm_help_display (const gchar *link_id) { GError *error = NULL; gchar *uri; if (link_id != NULL) uri = g_strconcat ("help:ukui-power-manager?", link_id, NULL); else uri = g_strdup ("help:ukui-power-manager"); gtk_show_uri (NULL, uri, GDK_CURRENT_TIME, &error); if (error != NULL) { GtkWidget *d; d = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", error->message); gtk_widget_set_name(GTK_WIDGET(d), "ukuicc"); gtk_dialog_run (GTK_DIALOG(d)); gtk_widget_destroy (d); g_error_free (error); } g_free (uri); } /*************************************************************************** *** MAKE CHECK TESTS *** ***************************************************************************/ #ifdef EGG_TEST #include "egg-test.h" void gpm_common_test (gpointer data) { EggTest *test = (EggTest *) data; if (egg_test_start (test, "GpmCommon") == FALSE) return; egg_test_end (test); } #endif ukui-control-center/panels/power/egg-console-kit.h0000664000175000017500000000516013057175444021203 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #ifndef __EGG_CONSOLE_KIT_H #define __EGG_CONSOLE_KIT_H #include G_BEGIN_DECLS #define EGG_TYPE_CONSOLE_KIT (egg_console_kit_get_type ()) #define EGG_CONSOLE_KIT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EGG_TYPE_CONSOLE_KIT, EggConsoleKit)) #define EGG_CONSOLE_KIT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EGG_TYPE_CONSOLE_KIT, EggConsoleKitClass)) #define EGG_IS_CONSOLE_KIT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EGG_TYPE_CONSOLE_KIT)) #define EGG_IS_CONSOLE_KIT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EGG_TYPE_CONSOLE_KIT)) #define EGG_CONSOLE_KIT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EGG_TYPE_CONSOLE_KIT, EggConsoleKitClass)) #define EGG_CONSOLE_KIT_ERROR (egg_console_kit_error_quark ()) #define EGG_CONSOLE_KIT_TYPE_ERROR (egg_console_kit_error_get_type ()) typedef struct EggConsoleKitPrivate EggConsoleKitPrivate; typedef struct { GObject parent; EggConsoleKitPrivate *priv; } EggConsoleKit; typedef struct { GObjectClass parent_class; void (* active_changed) (EggConsoleKit *console, gboolean active); } EggConsoleKitClass; GType egg_console_kit_get_type (void); EggConsoleKit *egg_console_kit_new (void); gboolean egg_console_kit_is_local (EggConsoleKit *console); gboolean egg_console_kit_is_active (EggConsoleKit *console); gboolean egg_console_kit_stop (EggConsoleKit *console, GError **error); gboolean egg_console_kit_restart (EggConsoleKit *console, GError **error); gboolean egg_console_kit_can_stop (EggConsoleKit *console, gboolean *can_stop, GError **error); gboolean egg_console_kit_can_restart (EggConsoleKit *console, gboolean *can_restart, GError **error); G_END_DECLS #endif /* __EGG_CONSOLE_KIT_H */ ukui-control-center/panels/power/egg-dbus-monitor.c0000664000175000017500000001620313057175444021371 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2006-2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #include "config.h" #include #include #include #include #include #include #include #include "egg-debug.h" #include "egg-dbus-monitor.h" static void egg_dbus_monitor_finalize (GObject *object); #define EGG_DBUS_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_TYPE_DBUS_MONITOR, EggDbusMonitorPrivate)) struct EggDbusMonitorPrivate { gchar *service; DBusGProxy *proxy; DBusGConnection *connection; const gchar *unique_name; }; enum { EGG_DBUS_MONITOR_CONNECTION_CHANGED, EGG_DBUS_MONITOR_CONNECTION_REPLACED, EGG_DBUS_MONITOR_LAST_SIGNAL }; static guint signals [EGG_DBUS_MONITOR_LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (EggDbusMonitor, egg_dbus_monitor, G_TYPE_OBJECT) /** * egg_dbus_monitor_name_owner_changed_cb: **/ static void egg_dbus_monitor_name_owner_changed_cb (DBusGProxy *proxy, const gchar *name, const gchar *prev, const gchar *new, EggDbusMonitor *monitor) { guint new_len; guint prev_len; g_return_if_fail (EGG_IS_DBUS_MONITOR (monitor)); if (monitor->priv->proxy == NULL) return; /* not us */ if (strcmp (name, monitor->priv->service) != 0) return; /* ITS4: ignore, not used for allocation */ new_len = strlen (new); /* ITS4: ignore, not used for allocation */ prev_len = strlen (prev); /* something --> nothing */ if (prev_len != 0 && new_len == 0) { g_signal_emit (monitor, signals [EGG_DBUS_MONITOR_CONNECTION_CHANGED], 0, FALSE); return; } /* nothing --> something */ if (prev_len == 0 && new_len != 0) { g_signal_emit (monitor, signals [EGG_DBUS_MONITOR_CONNECTION_CHANGED], 0, TRUE); return; } /* something --> something (we've replaced the old process) */ if (prev_len != 0 && new_len != 0) { /* only send this to the prev client */ if (strcmp (monitor->priv->unique_name, prev) == 0) g_signal_emit (monitor, signals [EGG_DBUS_MONITOR_CONNECTION_REPLACED], 0); return; } } /** * egg_dbus_monitor_assign: * @monitor: This class instance * @connection: The bus connection * @service: The EGG_DBUS_MONITOR service name * Return value: success * * Emits connection-changed(TRUE) if connection is alive - this means you * have to connect up the callback before this function is called. **/ gboolean egg_dbus_monitor_assign (EggDbusMonitor *monitor, DBusGConnection *connection, const gchar *service) { GError *error = NULL; gboolean connected; DBusConnection *conn; g_return_val_if_fail (EGG_IS_DBUS_MONITOR (monitor), FALSE); g_return_val_if_fail (service != NULL, FALSE); g_return_val_if_fail (connection != NULL, FALSE); if (monitor->priv->proxy != NULL) { egg_warning ("already assigned!"); return FALSE; } monitor->priv->service = g_strdup (service); monitor->priv->connection = connection; monitor->priv->proxy = dbus_g_proxy_new_for_name_owner (monitor->priv->connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, &error); if (error != NULL) { egg_warning ("Cannot connect to DBUS: %s", error->message); g_error_free (error); return FALSE; } dbus_g_proxy_add_signal (monitor->priv->proxy, "NameOwnerChanged", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); dbus_g_proxy_connect_signal (monitor->priv->proxy, "NameOwnerChanged", G_CALLBACK (egg_dbus_monitor_name_owner_changed_cb), monitor, NULL); /* coldplug */ connected = egg_dbus_monitor_is_connected (monitor); if (connected) g_signal_emit (monitor, signals [EGG_DBUS_MONITOR_CONNECTION_CHANGED], 0, TRUE); /* save this for the replaced check */ conn = dbus_g_connection_get_connection (monitor->priv->connection); monitor->priv->unique_name = dbus_bus_get_unique_name (conn); return TRUE; } /** * egg_dbus_monitor_is_connected: * @monitor: This class instance * Return value: if we are connected to a valid watch **/ gboolean egg_dbus_monitor_is_connected (EggDbusMonitor *monitor) { DBusError error; DBusConnection *conn; gboolean ret; g_return_val_if_fail (EGG_IS_DBUS_MONITOR (monitor), FALSE); /* get raw connection */ conn = dbus_g_connection_get_connection (monitor->priv->connection); dbus_error_init (&error); ret = dbus_bus_name_has_owner (conn, monitor->priv->service, &error); if (dbus_error_is_set (&error)) { egg_debug ("error: %s", error.message); dbus_error_free (&error); } return ret; } /** * egg_dbus_monitor_class_init: * @klass: The EggDbusMonitorClass **/ static void egg_dbus_monitor_class_init (EggDbusMonitorClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = egg_dbus_monitor_finalize; g_type_class_add_private (klass, sizeof (EggDbusMonitorPrivate)); signals [EGG_DBUS_MONITOR_CONNECTION_CHANGED] = g_signal_new ("connection-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggDbusMonitorClass, connection_changed), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); signals [EGG_DBUS_MONITOR_CONNECTION_REPLACED] = g_signal_new ("connection-replaced", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggDbusMonitorClass, connection_replaced), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } /** * egg_dbus_monitor_init: * @monitor: This class instance **/ static void egg_dbus_monitor_init (EggDbusMonitor *monitor) { monitor->priv = EGG_DBUS_MONITOR_GET_PRIVATE (monitor); monitor->priv->service = NULL; monitor->priv->connection = NULL; monitor->priv->proxy = NULL; } /** * egg_dbus_monitor_finalize: * @object: The object to finalize **/ static void egg_dbus_monitor_finalize (GObject *object) { EggDbusMonitor *monitor; g_return_if_fail (EGG_IS_DBUS_MONITOR (object)); monitor = EGG_DBUS_MONITOR (object); g_return_if_fail (monitor->priv != NULL); if (monitor->priv->proxy != NULL) g_object_unref (monitor->priv->proxy); G_OBJECT_CLASS (egg_dbus_monitor_parent_class)->finalize (object); } /** * egg_dbus_monitor_new: * * Return value: a new EggDbusMonitor object. **/ EggDbusMonitor * egg_dbus_monitor_new (void) { EggDbusMonitor *monitor; monitor = g_object_new (EGG_TYPE_DBUS_MONITOR, NULL); return EGG_DBUS_MONITOR (monitor); } ukui-control-center/panels/power/gs-job.c0000664000175000017500000002620213245450076017364 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2004-2006 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * * Authors: William Jon McCann * */ #include "config.h" #include #include #include #include #include #include #include #if defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS) #include #endif #include #include #include #include #include "gs-job.h" #include "subprocs.h" static void gs_job_class_init (GSJobClass *klass); static void gs_job_init (GSJob *job); static void gs_job_finalize (GObject *object); #define GS_JOB_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_JOB, GSJobPrivate)) typedef enum { GS_JOB_INVALID, GS_JOB_RUNNING, GS_JOB_STOPPED, GS_JOB_KILLED, GS_JOB_DEAD } GSJobStatus; struct GSJobPrivate { GtkWidget *widget; GSJobStatus status; gint pid; guint watch_id; char *command; }; G_DEFINE_TYPE (GSJob, gs_job, G_TYPE_OBJECT) static char * widget_get_id_string (GtkWidget *widget) { char *id = NULL; g_return_val_if_fail (widget != NULL, NULL); GdkWindow *win = gtk_widget_get_window (widget); if(win == NULL) id = g_strdup_printf ("0x%X", (guint32)gtk_widget_get_window (widget)); //(guint32)GDK_WINDOW_XID (gtk_widget_get_window (widget))); else id = g_strdup_printf ("0x%X", //GDK_WINDOW_XID(gtk_widget_get_window (widget))); (guint32)GDK_WINDOW_XID (gtk_widget_get_window (widget))); return id; } static void gs_job_class_init (GSJobClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gs_job_finalize; g_type_class_add_private (klass, sizeof (GSJobPrivate)); } static void gs_job_init (GSJob *job) { job->priv = GS_JOB_GET_PRIVATE (job); } /* adapted from gspawn.c */ static int wait_on_child (int pid) { int status; wait_again: if (waitpid (pid, &status, 0) < 0) { if (errno == EINTR) { goto wait_again; } else if (errno == ECHILD) { ; /* do nothing, child already reaped */ } else { g_debug ("waitpid () should not fail in 'GSJob'"); } } return status; } static void gs_job_died (GSJob *job) { if (job->priv->pid > 0) { int exit_status; g_debug ("Waiting on process %d", job->priv->pid); exit_status = wait_on_child (job->priv->pid); job->priv->status = GS_JOB_DEAD; if (WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) != 0)) { g_debug ("Wait on child process failed"); } else { /* exited normally */ } } g_spawn_close_pid (job->priv->pid); job->priv->pid = 0; g_debug ("Job died"); } static void gs_job_finalize (GObject *object) { GSJob *job; g_return_if_fail (object != NULL); g_return_if_fail (GS_IS_JOB (object)); job = GS_JOB (object); g_return_if_fail (job->priv != NULL); if (job->priv->pid > 0) { signal_pid (job->priv->pid, SIGTERM); gs_job_died (job); } g_free (job->priv->command); job->priv->command = NULL; G_OBJECT_CLASS (gs_job_parent_class)->finalize (object); } void gs_job_set_widget (GSJob *job, GtkWidget *widget) { g_return_if_fail (job != NULL); g_return_if_fail (GS_IS_JOB (job)); if (widget != job->priv->widget) { job->priv->widget = widget; /* restart job */ if (gs_job_is_running (job)) { gs_job_stop (job); gs_job_start (job); } } } gboolean gs_job_set_command (GSJob *job, const char *command) { g_return_val_if_fail (GS_IS_JOB (job), FALSE); g_debug ("Setting command for job: '%s'", command != NULL ? command : "NULL"); g_free (job->priv->command); job->priv->command = g_strdup (command); return TRUE; } GSJob * gs_job_new (void) { GObject *job; job = g_object_new (GS_TYPE_JOB, NULL); return GS_JOB (job); } GSJob * gs_job_new_for_widget (GtkWidget *widget) { GObject *job; job = g_object_new (GS_TYPE_JOB, NULL); gs_job_set_widget (GS_JOB (job), widget); return GS_JOB (job); } static void nice_process (int pid, int nice_level) { g_return_if_fail (pid > 0); if (nice_level == 0) { return; } #if defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS) g_debug ("Setting child process priority to: %d", nice_level); if (setpriority (PRIO_PROCESS, pid, nice_level) != 0) { g_debug ("setpriority(PRIO_PROCESS, %lu, %d) failed", (unsigned long) pid, nice_level); } #else g_debug ("don't know how to change process priority on this system."); #endif } static GPtrArray * get_env_vars (GtkWidget *widget) { GPtrArray *env; char *str; int i; static const char *allowed_env_vars [] = { "PATH", "SESSION_MANAGER", "XAUTHORITY", "XAUTHLOCALHOSTNAME", "LANG", "LANGUAGE", "DBUS_SESSION_BUS_ADDRESS" }; env = g_ptr_array_new (); str = gdk_screen_make_display_name (gtk_widget_get_screen (widget)); g_ptr_array_add (env, g_strdup_printf ("DISPLAY=%s", str)); g_free (str); g_ptr_array_add (env, g_strdup_printf ("HOME=%s", g_get_home_dir ())); for (i = 0; i < G_N_ELEMENTS (allowed_env_vars); i++) { const char *var; const char *val; var = allowed_env_vars [i]; val = g_getenv (var); if (val != NULL) { g_ptr_array_add (env, g_strdup_printf ("%s=%s", var, val)); } } str = widget_get_id_string (widget); g_ptr_array_add (env, g_strdup_printf ("XSCREENSAVER_WINDOW=%s", str)); g_free (str); g_ptr_array_add (env, NULL); return env; } static gboolean spawn_on_widget (GtkWidget *widget, const char *command, int *pid, GIOFunc watch_func, gpointer user_data, guint *watch_id) { char **argv; GPtrArray *env; gboolean result; GIOChannel *channel; GError *error = NULL; int standard_error; int child_pid; int id; int i; if (command == NULL) { return FALSE; } if (! g_shell_parse_argv (command, NULL, &argv, &error)) { g_debug ("Could not parse command: %s", error->message); g_error_free (error); return FALSE; } env = get_env_vars (widget); error = NULL; result = g_spawn_async_with_pipes (NULL, argv, (char **)env->pdata, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &child_pid, NULL, NULL, &standard_error, &error); for (i = 0; i < env->len; i++) { g_free (g_ptr_array_index (env, i)); } g_ptr_array_free (env, TRUE); if (! result) { g_debug ("Could not start command '%s': %s", command, error->message); g_error_free (error); g_strfreev (argv); return FALSE; } g_strfreev (argv); nice_process (child_pid, 10); if (pid != NULL) { *pid = child_pid; } else { g_spawn_close_pid (child_pid); } channel = g_io_channel_unix_new (standard_error); g_io_channel_set_close_on_unref (channel, TRUE); g_io_channel_set_flags (channel, g_io_channel_get_flags (channel) | G_IO_FLAG_NONBLOCK, NULL); id = g_io_add_watch (channel, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, watch_func, user_data); if (watch_id != NULL) { *watch_id = id; } g_io_channel_unref (channel); return result; } static gboolean command_watch (GIOChannel *source, GIOCondition condition, GSJob *job) { GIOStatus status; GError *error = NULL; gboolean done = FALSE; g_return_val_if_fail (job != NULL, FALSE); if (condition & G_IO_IN) { char *str; status = g_io_channel_read_line (source, &str, NULL, NULL, &error); if (status == G_IO_STATUS_NORMAL) { g_debug ("command output: %s", str); } else if (status == G_IO_STATUS_EOF) { done = TRUE; } else if (error != NULL) { g_debug ("command error: %s", error->message); g_error_free (error); } g_free (str); } else if (condition & G_IO_HUP) { done = TRUE; } if (done) { gs_job_died (job); job->priv->watch_id = 0; return FALSE; } return TRUE; } gboolean gs_job_is_running (GSJob *job) { gboolean running; g_return_val_if_fail (GS_IS_JOB (job), FALSE); running = (job->priv->pid > 0); return running; } gboolean gs_job_start (GSJob *job) { gboolean result; g_return_val_if_fail (job != NULL, FALSE); g_return_val_if_fail (GS_IS_JOB (job), FALSE); g_debug ("starting job"); if (job->priv->pid != 0) { g_debug ("Cannot restart active job."); return FALSE; } if (job->priv->widget == NULL) { g_debug ("Could not start job: screensaver window is not set."); return FALSE; } if (job->priv->command == NULL) { /* no warning here because a NULL command is interpreted as a no-op job */ g_debug ("No command set for job."); return FALSE; } result = spawn_on_widget (job->priv->widget, job->priv->command, &job->priv->pid, (GIOFunc)command_watch, job, &job->priv->watch_id); if (result) { job->priv->status = GS_JOB_RUNNING; } return result; } static void remove_command_watch (GSJob *job) { if (job->priv->watch_id != 0) { g_source_remove (job->priv->watch_id); job->priv->watch_id = 0; } } gboolean gs_job_stop (GSJob *job) { g_return_val_if_fail (job != NULL, FALSE); g_return_val_if_fail (GS_IS_JOB (job), FALSE); g_debug ("stopping job"); if (job->priv->pid == 0) { g_debug ("Could not stop job: pid not defined"); return FALSE; } if (job->priv->status == GS_JOB_STOPPED) { gs_job_suspend (job, FALSE); } remove_command_watch (job); signal_pid (job->priv->pid, SIGTERM); job->priv->status = GS_JOB_KILLED; gs_job_died (job); return TRUE; } gboolean gs_job_suspend (GSJob *job, gboolean suspend) { g_return_val_if_fail (job != NULL, FALSE); g_return_val_if_fail (GS_IS_JOB (job), FALSE); g_debug ("suspending job"); if (job->priv->pid == 0) { return FALSE; } signal_pid (job->priv->pid, (suspend ? SIGSTOP : SIGCONT)); job->priv->status = (suspend ? GS_JOB_STOPPED : GS_JOB_RUNNING); return TRUE; } ukui-control-center/panels/power/kpm-common.h0000664000175000017500000001600213253611037020255 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2005-2007 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #ifndef __GPMCOMMON_H #define __GPMCOMMON_H #include #include G_BEGIN_DECLS #define LOGIND_RUNNING() (access("/run/systemd/seats/", F_OK) >= 0) #define GPM_DBUS_SERVICE "org.ukui.PowerManager" #define GPM_DBUS_INTERFACE "org.ukui.PowerManager" #define GPM_DBUS_INTERFACE_BACKLIGHT "org.ukui.PowerManager.Backlight" #define GPM_DBUS_PATH "/org/ukui/PowerManager" #define GPM_DBUS_PATH_BACKLIGHT "/org/ukui/PowerManager/Backlight" #define GPM_DBUS_PATH_KBD_BACKLIGHT "/org/ukui/PowerManager/KbdBacklight" /* common descriptions of this program */ #define GPM_NAME _("Power Manager") #define GPM_DESCRIPTION _("Power Manager for the UKUI desktop") /* schema location */ #define KPM_SETTINGS_SCHEMA "org.ukui.power-manager" /* actions */ #define GPM_SETTINGS_ACTION_CRITICAL_UPS "action-critical-ups" #define KPM_SETTINGS_ACTION_CRITICAL_BATT "action-critical-battery" #define GPM_SETTINGS_ACTION_LOW_UPS "action-low-ups" #define GPM_SETTINGS_ACTION_SLEEP_TYPE_AC "action-sleep-type-ac" #define GPM_SETTINGS_ACTION_SLEEP_TYPE_BATT "action-sleep-type-battery" #define GPM_SETTINGS_SLEEP_WHEN_CLOSED "event-when-closed-battery" /* backlight stuff */ #define GPM_SETTINGS_BACKLIGHT_ENABLE "backlight-enable" #define KPM_SETTINGS_BACKLIGHT_BATTERY_REDUCE "backlight-battery-reduce" #define GPM_SETTINGS_DPMS_METHOD_AC "dpms-method-ac" #define GPM_SETTINGS_DPMS_METHOD_BATT "dpms-method-battery" #define GPM_SETTINGS_IDLE_BRIGHTNESS "idle-brightness" #define KPM_SETTINGS_IDLE_DIM_AC "idle-dim-ac" #define KPM_SETTINGS_IDLE_DIM_BATT "idle-dim-battery" #define GPM_SETTINGS_IDLE_DIM_TIME "idle-dim-time" #define KPM_SETTINGS_BRIGHTNESS_AC "brightness-ac" #define GPM_SETTINGS_BRIGHTNESS_DIM_BATT "brightness-dim-battery" /* keyboard backlight */ #define GPM_SETTINGS_KBD_BACKLIGHT_BATT_REDUCE "kbd-backlight-battery-reduce" #define GPM_SETTINGS_KBD_BRIGHTNESS_ON_AC "kbd-brightness-on-ac" #define GPM_SETTINGS_KBD_BRIGHTNESS_DIM_BY_ON_BATT "kbd-brightness-dim-by-on-battery" #define GPM_SETTINGS_KBD_BRIGHTNESS_DIM_BY_ON_IDLE "kbd-brightness-dim-by-on-idle" /* buttons */ #define KPM_SETTINGS_BUTTON_LID_AC "button-lid-ac" #define KPM_SETTINGS_BUTTON_LID_BATT "button-lid-battery" #define KPM_SETTINGS_BUTTON_SUSPEND "button-suspend" #define KPM_SETTINGS_BUTTON_HIBERNATE "button-hibernate" #define KPM_SETTINGS_BUTTON_POWER "button-power" /* general */ #define GPM_SETTINGS_USE_TIME_POLICY "use-time-for-policy" #define GPM_SETTINGS_NETWORKMANAGER_SLEEP "network-sleep" #define GPM_SETTINGS_IDLE_CHECK_CPU "check-type-cpu" /* lock */ #define GPM_SETTINGS_LOCK_USE_SCREENSAVER "lock-use-screensaver" #define GPM_SETTINGS_LOCK_ON_BLANK_SCREEN "lock-blank-screen" #define GPM_SETTINGS_LOCK_ON_SUSPEND "lock-suspend" #define GPM_SETTINGS_LOCK_ON_HIBERNATE "lock-hibernate" #define GPM_SETTINGS_LOCK_KEYRING_SUSPEND "lock-keyring-suspend" #define GPM_SETTINGS_LOCK_KEYRING_HIBERNATE "lock-keyring-hibernate" /* disks */ #define KPM_SETTINGS_SPINDOWN_ENABLE_AC "spindown-enable-ac" #define KPM_SETTINGS_SPINDOWN_ENABLE_BATT "spindown-enable-battery" #define GPM_SETTINGS_SPINDOWN_TIMEOUT_AC "spindown-timeout-ac" #define GPM_SETTINGS_SPINDOWN_TIMEOUT_BATT "spindown-timeout-battery" /* notify */ #define GPM_SETTINGS_NOTIFY_PERHAPS_RECALL "notify-perhaps-recall" #define GPM_SETTINGS_NOTIFY_LOW_CAPACITY "notify-low-capacity" #define GPM_SETTINGS_NOTIFY_DISCHARGING "notify-discharging" #define GPM_SETTINGS_NOTIFY_FULLY_CHARGED "notify-fully-charged" #define GPM_SETTINGS_NOTIFY_SLEEP_FAILED "notify-sleep-failed" #define GPM_SETTINGS_NOTIFY_SLEEP_FAILED_URI "notify-sleep-failed-uri" #define GPM_SETTINGS_NOTIFY_LOW_POWER "notify-low-power" /* thresholds */ #define GPM_SETTINGS_PERCENTAGE_LOW "percentage-low" #define GPM_SETTINGS_PERCENTAGE_CRITICAL "percentage-critical" #define GPM_SETTINGS_PERCENTAGE_ACTION "percentage-action" #define GPM_SETTINGS_TIME_LOW "time-low" #define GPM_SETTINGS_TIME_CRITICAL "time-critical" #define GPM_SETTINGS_TIME_ACTION "time-action" /* timeout */ #define KPM_SETTINGS_SLEEP_COMPUTER_AC "sleep-computer-ac" #define KPM_SETTINGS_SLEEP_COMPUTER_BATT "sleep-computer-battery" #define KPM_SETTINGS_SLEEP_COMPUTER_UPS "sleep-computer-ups" #define KPM_SETTINGS_SLEEP_DISPLAY_AC "sleep-display-ac" #define KPM_SETTINGS_SLEEP_DISPLAY_BATT "sleep-display-battery" #define KPM_SETTINGS_SLEEP_DISPLAY_UPS "sleep-display-ups" /* ui */ #define KPM_SETTINGS_ICON_POLICY "icon-policy" #define GPM_SETTINGS_ENABLE_SOUND "enable-sound" #define GPM_SETTINGS_SHOW_ACTIONS "show-actions" /* statistics */ #define GPM_SETTINGS_INFO_HISTORY_TIME "info-history-time" #define GPM_SETTINGS_INFO_HISTORY_TYPE "info-history-type" #define GPM_SETTINGS_INFO_HISTORY_GRAPH_SMOOTH "info-history-graph-smooth" #define GPM_SETTINGS_INFO_HISTORY_GRAPH_POINTS "info-history-graph-points" #define GPM_SETTINGS_INFO_STATS_TYPE "info-stats-type" #define GPM_SETTINGS_INFO_STATS_GRAPH_SMOOTH "info-stats-graph-smooth" #define GPM_SETTINGS_INFO_STATS_GRAPH_POINTS "info-stats-graph-points" #define GPM_SETTINGS_INFO_PAGE_NUMBER "info-page-number" #define GPM_SETTINGS_INFO_LAST_DEVICE "info-last-device" /* ukui-screensaver */ #define GS_SETTINGS_SCHEMA "org.ukui.screensaver" #define GS_SETTINGS_PREF_LOCK_ENABLED "lock-enabled" typedef enum { KPM_ICON_POLICY_ALWAYS, KPM_ICON_POLICY_PRESENT, KPM_ICON_POLICY_CHARGE, KPM_ICON_POLICY_LOW, KPM_ICON_POLICY_CRITICAL, KPM_ICON_POLICY_NEVER } KpmIconPolicy; typedef enum { KPM_ACTION_POLICY_BLANK, KPM_ACTION_POLICY_SUSPEND, KPM_ACTION_POLICY_SHUTDOWN, KPM_ACTION_POLICY_HIBERNATE, KPM_ACTION_POLICY_INTERACTIVE, KPM_ACTION_POLICY_NOTHING } KpmActionPolicy; gchar *kpm_get_timestring (guint time); guint gpm_discrete_from_percent (guint percentage, guint levels); guint gpm_discrete_to_percent (guint discrete, guint levels); void gpm_help_display (const gchar *link_id); #ifdef EGG_TEST void gpm_common_test (gpointer data); #endif G_END_DECLS #endif /* __GPMCOMMON_H */ ukui-control-center/panels/power/egg-precision.h0000664000175000017500000000237713057175444020756 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #ifndef __EGG_PRECISION_H #define __EGG_PRECISION_H #include G_BEGIN_DECLS gint egg_precision_round_up (gfloat value, gint smallest); gint egg_precision_round_down (gfloat value, gint smallest); #ifdef EGG_TEST void egg_precision_test (gpointer data); #endif G_END_DECLS #endif /* __EGG_PRECISION_H */ ukui-control-center/panels/power/gs-job.h0000664000175000017500000000445613245450076017400 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2004-2005 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * * Authors: William Jon McCann * */ #ifndef __GS_JOB_H #define __GS_JOB_H #include G_BEGIN_DECLS #define GS_TYPE_JOB (gs_job_get_type ()) #define GS_JOB(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GS_TYPE_JOB, GSJob)) #define GS_JOB_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GS_TYPE_JOB, GSJobClass)) #define GS_IS_JOB(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GS_TYPE_JOB)) #define GS_IS_JOB_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GS_TYPE_JOB)) #define GS_JOB_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GS_TYPE_JOB, GSJobClass)) typedef struct GSJobPrivate GSJobPrivate; typedef struct { GObject parent; GSJobPrivate *priv; } GSJob; typedef struct { GObjectClass parent_class; } GSJobClass; GType gs_job_get_type (void); GSJob *gs_job_new (void); GSJob *gs_job_new_for_widget (GtkWidget *widget); gboolean gs_job_is_running (GSJob *job); gboolean gs_job_start (GSJob *job); gboolean gs_job_stop (GSJob *job); gboolean gs_job_suspend (GSJob *job, gboolean suspend); void gs_job_set_widget (GSJob *job, GtkWidget *widget); gboolean gs_job_set_command (GSJob *job, const char *command); G_END_DECLS #endif /* __GS_JOB_H */ ukui-control-center/panels/power/gs-theme-manager.c0000664000175000017500000002262313245450076021327 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2006 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * * Authors: William Jon McCann * */ #include "config.h" #include #include #include #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #include #include #include "gs-theme-manager.h" static void gs_theme_manager_class_init (GSThemeManagerClass *klass); static void gs_theme_manager_init (GSThemeManager *theme_manager); static void gs_theme_manager_finalize (GObject *object); #define GS_THEME_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_THEME_MANAGER, GSThemeManagerPrivate)) struct _GSThemeInfo { char *name; char *exec; char *file_id; guint refcount; }; struct GSThemeManagerPrivate { UkuiMenuTree *menu_tree; }; G_DEFINE_TYPE (GSThemeManager, gs_theme_manager, G_TYPE_OBJECT) static gpointer theme_manager_object = NULL; static const char *known_engine_locations [] = { SAVERDIR, #ifdef XSCREENSAVER_HACK_DIR XSCREENSAVER_HACK_DIR, #endif LIBEXECDIR "/xscreensaver", "/usr/libexec/xscreensaver", "/usr/lib/xscreensaver", NULL }; /* Returns the full path to the queried command */ static char * find_command (const char *command) { int i; if (g_path_is_absolute (command)) { char *dirname; dirname = g_path_get_dirname (command); for (i = 0; known_engine_locations [i]; i++) { if (strcmp (dirname, known_engine_locations [i]) == 0) { if (g_file_test (command, G_FILE_TEST_IS_EXECUTABLE) && ! g_file_test (command, G_FILE_TEST_IS_DIR)) { g_free (dirname); return g_strdup (command); } } } g_free (dirname); } else { for (i = 0; known_engine_locations [i]; i++) { char *path; path = g_build_filename (known_engine_locations [i], command, NULL); if (g_file_test (path, G_FILE_TEST_IS_EXECUTABLE) && ! g_file_test (path, G_FILE_TEST_IS_DIR)) { return path; } g_free (path); } } return NULL; } static gboolean check_command (const char *command) { char *path; char **argv; g_return_val_if_fail (command != NULL, FALSE); g_shell_parse_argv (command, NULL, &argv, NULL); path = find_command (argv [0]); g_strfreev (argv); if (path != NULL) { g_free (path); return TRUE; } return FALSE; } static void add_known_engine_locations_to_path (void) { static gboolean already_added; int i; GString *str; /* We only want to add the items to the path once */ if (already_added) { return; } already_added = TRUE; /* TODO: set a default PATH ? */ str = g_string_new (g_getenv ("PATH")); for (i = 0; known_engine_locations [i]; i++) { /* TODO: check that permissions are safe */ if (g_file_test (known_engine_locations [i], G_FILE_TEST_IS_DIR)) { g_string_append_printf (str, ":%s", known_engine_locations [i]); } } g_setenv ("PATH", str->str, TRUE); g_string_free (str, TRUE); } GSThemeInfo * gs_theme_info_ref (GSThemeInfo *info) { g_return_val_if_fail (info != NULL, NULL); g_return_val_if_fail (info->refcount > 0, NULL); info->refcount++; return info; } void gs_theme_info_unref (GSThemeInfo *info) { g_return_if_fail (info != NULL); g_return_if_fail (info->refcount > 0); if (--info->refcount == 0) { g_free (info->name); g_free (info->exec); g_free (info->file_id); g_free (info); } } const char * gs_theme_info_get_id (GSThemeInfo *info) { g_return_val_if_fail (info != NULL, NULL); return info->file_id; } const char * gs_theme_info_get_name (GSThemeInfo *info) { g_return_val_if_fail (info != NULL, NULL); return info->name; } const char * gs_theme_info_get_exec (GSThemeInfo *info) { const char *exec; g_return_val_if_fail (info != NULL, NULL); if (check_command (info->exec)) { exec = info->exec; } else { exec = NULL; } return exec; } static GSThemeInfo * gs_theme_info_new_from_ukuimenu_tree_entry (UkuiMenuTreeEntry *entry) { GSThemeInfo *info; const char *str; char *pos; info = g_new0 (GSThemeInfo, 1); info->refcount = 1; info->name = g_strdup (ukuimenu_tree_entry_get_name (entry)); info->exec = g_strdup (ukuimenu_tree_entry_get_exec (entry)); /* remove the .desktop suffix */ str = ukuimenu_tree_entry_get_desktop_file_id (entry); pos = g_strrstr (str, ".desktop"); if (pos) { info->file_id = g_strndup (str, pos - str); } else { info->file_id = g_strdup (str); } return info; } static GSThemeInfo * find_info_for_id (UkuiMenuTree *tree, const char *id) { GSThemeInfo *info; UkuiMenuTreeDirectory *root; GSList *items; GSList *l; root = ukuimenu_tree_get_root_directory (tree); if (root == NULL) { return NULL; } items = ukuimenu_tree_directory_get_contents (root); info = NULL; for (l = items; l; l = l->next) { if (info == NULL && ukuimenu_tree_item_get_type (l->data) == UKUIMENU_TREE_ITEM_ENTRY) { UkuiMenuTreeEntry *entry = l->data; const char *file_id; file_id = ukuimenu_tree_entry_get_desktop_file_id (entry); if (file_id && id && strcmp (file_id, id) == 0) { info = gs_theme_info_new_from_ukuimenu_tree_entry (entry); } } ukuimenu_tree_item_unref (l->data); } g_slist_free (items); ukuimenu_tree_item_unref (root); return info; } GSThemeInfo * gs_theme_manager_lookup_theme_info (GSThemeManager *theme_manager, const char *name) { GSThemeInfo *info; char *id; g_return_val_if_fail (GS_IS_THEME_MANAGER (theme_manager), NULL); g_return_val_if_fail (name != NULL, NULL); id = g_strdup_printf ("%s.desktop", name); info = find_info_for_id (theme_manager->priv->menu_tree, id); g_free (id); return info; } static void theme_prepend_entry (GSList **parent_list, UkuiMenuTreeEntry *entry, const char *filename) { GSThemeInfo *info; info = gs_theme_info_new_from_ukuimenu_tree_entry (entry); *parent_list = g_slist_prepend (*parent_list, info); } static void make_theme_list (GSList **parent_list, UkuiMenuTreeDirectory *directory, const char *filename) { GSList *items; GSList *l; items = ukuimenu_tree_directory_get_contents (directory); for (l = items; l; l = l->next) { switch (ukuimenu_tree_item_get_type (l->data)) { case UKUIMENU_TREE_ITEM_ENTRY: theme_prepend_entry (parent_list, l->data, filename); break; case UKUIMENU_TREE_ITEM_ALIAS: case UKUIMENU_TREE_ITEM_DIRECTORY: default: break; } ukuimenu_tree_item_unref (l->data); } g_slist_free (items); *parent_list = g_slist_reverse (*parent_list); } GSList * gs_theme_manager_get_info_list (GSThemeManager *theme_manager) { GSList *l = NULL; UkuiMenuTreeDirectory *root; g_return_val_if_fail (GS_IS_THEME_MANAGER (theme_manager), NULL); root = ukuimenu_tree_get_root_directory (theme_manager->priv->menu_tree); if (root != NULL) { make_theme_list (&l, root, "ukui-screensavers.menu"); ukuimenu_tree_item_unref (root); } return l; } static void gs_theme_manager_class_init (GSThemeManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gs_theme_manager_finalize; g_type_class_add_private (klass, sizeof (GSThemeManagerPrivate)); } static UkuiMenuTree * get_themes_tree (void) { UkuiMenuTree *themes_tree = NULL; /* we only need to add the locations to the path once and since this is only run once we'll do it here */ add_known_engine_locations_to_path (); themes_tree = ukuimenu_tree_lookup ("ukui-screensavers.menu", UKUIMENU_TREE_FLAGS_NONE); return themes_tree; } static void gs_theme_manager_init (GSThemeManager *theme_manager) { theme_manager->priv = GS_THEME_MANAGER_GET_PRIVATE (theme_manager); theme_manager->priv->menu_tree = get_themes_tree (); } static void gs_theme_manager_finalize (GObject *object) { GSThemeManager *theme_manager; g_return_if_fail (object != NULL); g_return_if_fail (GS_IS_THEME_MANAGER (object)); theme_manager = GS_THEME_MANAGER (object); g_return_if_fail (theme_manager->priv != NULL); if (theme_manager->priv->menu_tree != NULL) { ukuimenu_tree_unref (theme_manager->priv->menu_tree); } G_OBJECT_CLASS (gs_theme_manager_parent_class)->finalize (object); } GSThemeManager * gs_theme_manager_new (void) { if (theme_manager_object) { g_object_ref (theme_manager_object); } else { theme_manager_object = g_object_new (GS_TYPE_THEME_MANAGER, NULL); g_object_add_weak_pointer (theme_manager_object, (gpointer *) &theme_manager_object); } return GS_THEME_MANAGER (theme_manager_object); } ukui-control-center/panels/power/ukui-fullscreen-preview.ui0000664000175000017500000001354113245450076023174 0ustar fengfeng True True Screensaver Preview True center True True True False True False vertical True False 30 True False gtk-dialog-warning False False 0 True False Screensaver preview fill True False True 1 True False True True 2 True True False True False gtk-go-back False False 3 True True False True False gtk-go-forward False False 4 gtk-leave-fullscreen True True False True False False 5 False False 0 True False True True 1 ukui-control-center/panels/power/egg-color.h0000664000175000017500000000355713057175444020102 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2008 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #ifndef __EGG_COLOR_H #define __EGG_COLOR_H #include G_BEGIN_DECLS #define EGG_COLOR_WHITE 0xffffff #define EGG_COLOR_BLACK 0x000000 #define EGG_COLOR_RED 0xff0000 #define EGG_COLOR_GREEN 0x00ff00 #define EGG_COLOR_BLUE 0x0000ff #define EGG_COLOR_CYAN 0x00ffff #define EGG_COLOR_MAGENTA 0xff00ff #define EGG_COLOR_YELLOW 0xffff00 #define EGG_COLOR_GREY 0xcccccc #define EGG_COLOR_DARK_RED 0x600000 #define EGG_COLOR_DARK_GREEN 0x006000 #define EGG_COLOR_DARK_BLUE 0x000060 #define EGG_COLOR_DARK_CYAN 0x006060 #define EGG_COLOR_DARK_MAGENTA 0x600060 #define EGG_COLOR_DARK_YELLOW 0x606000 #define EGG_COLOR_DARK_GREY 0x606060 guint32 egg_color_from_rgb (guint8 red, guint8 green, guint8 blue); void egg_color_to_rgb (guint32 color, guint8 *red, guint8 *green, guint8 *blue); #ifdef EGG_TEST void egg_color_test (gpointer data); #endif G_END_DECLS #endif /* __EGG_COLOR_H */ ukui-control-center/panels/session-properties/0000775000175000017500000000000013263647163020563 5ustar fengfengukui-control-center/panels/session-properties/gsp-app.h0000664000175000017500000001031113057175444022276 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 1999 Free Software Foundation, Inc. * Copyright (C) 2007, 2009 Vincent Untz. * Copyright (C) 2008 Lucas Rocha. * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef __GSP_APP_H #define __GSP_APP_H #include #include G_BEGIN_DECLS #define GSP_TYPE_APP (gsp_app_get_type ()) #define GSP_APP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSP_TYPE_APP, GspApp)) #define GSP_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSP_TYPE_APP, GspAppClass)) #define GSP_IS_APP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSP_TYPE_APP)) #define GSP_IS_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSP_TYPE_APP)) #define GSP_APP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSP_TYPE_APP, GspAppClass)) typedef struct _GspApp GspApp; typedef struct _GspAppClass GspAppClass; typedef struct _GspAppPrivate GspAppPrivate; struct _GspAppClass { GObjectClass parent_class; void (* changed) (GspApp *app); void (* removed) (GspApp *app); }; struct _GspApp { GObject parent_instance; GspAppPrivate *priv; }; GType gsp_app_get_type (void); int gsp_app_create (const char *name, const char *comment, const char *exec, const char *icon); void gsp_app_update (GspApp *app, const char *name, const char *comment, const char *exec); gboolean gsp_app_copy_desktop_file (const char *uri); void gsp_app_delete (GspApp *app); const char *gsp_app_get_basename (GspApp *app); const char *gsp_app_get_path (GspApp *app); gboolean gsp_app_get_hidden (GspApp *app); gboolean gsp_app_get_display (GspApp *app); gboolean gsp_app_get_enabled (GspApp *app); void gsp_app_set_enabled (GspApp *app, gboolean enabled); gboolean gsp_app_get_shown (GspApp *app); const char *gsp_app_get_name (GspApp *app); const char *gsp_app_get_exec (GspApp *app); const char *gsp_app_get_comment (GspApp *app); const char *gsp_app_get_description (GspApp *app); GIcon *gsp_app_get_icon (GspApp *app); const char *gsp_app_get_icon_char (GspApp *app); /* private interface for GspAppManager only */ GspApp *gsp_app_new (const char *path, unsigned int xdg_position); void gsp_app_reload_at (GspApp *app, const char *path, unsigned int xdg_position); unsigned int gsp_app_get_xdg_position (GspApp *app); unsigned int gsp_app_get_xdg_system_position (GspApp *app); void gsp_app_set_xdg_system_position (GspApp *app, unsigned int position); G_END_DECLS #endif /* __GSP_APP_H */ ukui-control-center/panels/session-properties/main-table.ui0000664000175000017500000001105413245450076023127 0ustar fengfeng 440 145 True False 83 35 True False Name: True session_properties_name_entry 15 15 83 35 True False Command: True session_properties_command_entry 15 60 83 35 True False Annotation: True label2 15 105 270 35 True True False False 98 15 270 35 True True False False 98 60 270 35 True True False False 98 105 scan… 60 35 True True True 380 60 ukui-control-center/panels/session-properties/Makefile.am0000664000175000017500000000160513057175444022620 0ustar fengfengcappletname=sessionproperties noinst_LTLIBRARIES=libsessionproperties.la AUTOMAKE_OPTIONS=foreign #INCLUDES= `pkg-config --cflags gtk+-2.0 gio-2.0 glib-2.0 dbus-glib-1` #LIBS=`pkg-config --libs gtk+-2.0 gio-2.0 glib-2.0 dbus-glib-1` AM_CPPFLAGS= \ -DUIDIR="\"$(uidir)\"" \ $(GTK_CFLAGS) \ $(GLIB_CFLAGS) \ $(DBUS_CFLAGS) \ $(NULL) libsessionproperties_la_LIBADD = \ $(GTK_LIBS) \ $(GLIB_LIBS) \ $(DBUS_LIBS) \ $(NULL) libsessionproperties_la_SOURCES =\ eggdesktopfile.c \ eggdesktopfile.h \ gsm-app-dialog.c \ gsm-app-dialog.h \ gsm-properties-dialog.c \ gsm-properties-dialog.h \ gsm-util.c \ gsm-util.h \ gsp-app.c \ gsp-app.h \ gsp-app-manager.c \ gsp-app-manager.h \ gsp-keyfile.c \ gsp-keyfile.h \ gsp-main.c \ gsp-main.h uidir= $(pkgdatadir)/ui ui_DATA= main-table.ui program_properties.ui -include $(top_srcdir)/git.mk clean-local : rm -f *~ Makefile.in Makefile ukui-control-center/panels/session-properties/program_properties.ui0000644000175000017500000003407013111751271025033 0ustar fengfeng 400 450 False 5 False dialog True True False vertical 2 True False end False True 0 True False vertical True False 100 True False gtk-missing-image False True 0 True False start True True program name False True 1 True True 0 True False False True 1 True False 100 True False start False False File Type: 0 0 100 True False False False File Description: 0 1 True False start True True Application 1 0 True False start True True True char 1 1 True True 2 True False False True 3 True False 100 True False Program Location: 0 0 100 True False Program Size: 0 1 True False start True True True char 1 0 True False start True True 1 1 True True 4 True False False True 5 True False 100 True False Access Time: 0 0 100 True False modification time: 0 1 True False start True True 1 0 True False start True True 1 1 True True 6 True True 1 ukui-control-center/panels/session-properties/gsm-properties-dialog.c0000664000175000017500000007420713253611051025140 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 1999 Free Software Foundation, Inc. * Copyright (C) 2007 Vincent Untz. * Copyright (C) 2008 Lucas Rocha. * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include #include #include "gsm-properties-dialog.h" #include "gsm-app-dialog.h" #include "gsm-util.h" #include "gsp-app.h" #include "gsp-app-manager.h" #include //#define GSM_PROPERTIES_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_PROPERTIES_DIALOG, GsmPropertiesDialogPrivate)) #define GTKBUILDER_FILE "session-properties.ui" #define CAPPLET_TREEVIEW_WIDGET_NAME "session_properties_treeview" #define CAPPLET_ADD_WIDGET_NAME "session_properties_add_button" #define CAPPLET_DELETE_WIDGET_NAME "session_properties_delete_button" #define CAPPLET_EDIT_WIDGET_NAME "session_properties_edit_button" #define CAPPLET_SAVE_WIDGET_NAME "session_properties_save_button" #define CAPPLET_REMEMBER_WIDGET_NAME "session_properties_remember_toggle" #define STARTUP_APP_ICON "system-run" #define SPC_SETTINGS_SCHEMA "org.ukui.session" #define SPC_SETTINGS_AUTOSAVE_KEY "auto-save-session" GtkBuilder * topbuilder = NULL; struct GsmPropertiesDialogPrivate { GtkBuilder *xml; GtkListStore *list_store; GtkTreeModel *tree_filter; GtkTreeView *treeview; GtkWidget *add_button; GtkWidget *delete_button; GtkWidget *edit_button; GSettings *settings; GspAppManager *manager; }; enum { STORE_COL_VISIBLE = 0, STORE_COL_ENABLED, STORE_COL_GICON, STORE_COL_DESCRIPTION, STORE_COL_APP, STORE_COL_SEARCH, STORE_COL_LABEL, STORE_COL_SPACE, NUMBER_OF_COLUMNS }; /*static void gsm_properties_dialog_class_init (GsmPropertiesDialogClass *klass); static void gsm_properties_dialog_init (GsmPropertiesDialog *properties_dialog); static void gsm_properties_dialog_finalize (GObject *object); G_DEFINE_TYPE (GsmPropertiesDialog, gsm_properties_dialog, GTK_TYPE_DIALOG) */ static GsmPropertiesDialog Dialog1; static GsmPropertiesDialogPrivate Dialog2; GsmPropertiesDialog *dialog1; GsmPropertiesDialogPrivate *dialog2; static gboolean find_by_app (GtkTreeModel *model, GtkTreeIter *iter, GspApp *app) { GspApp *iter_app = NULL; if (!gtk_tree_model_get_iter_first (model, iter)) { return FALSE; } do { gtk_tree_model_get (model, iter, STORE_COL_APP, &iter_app, -1); if (iter_app == app) { g_object_unref (iter_app); return TRUE; } } while (gtk_tree_model_iter_next (model, iter)); return FALSE; } const char * kylin_set_the_label(GspApp *app){ const char *label; gboolean enabled = gsp_app_get_enabled(app); if(enabled) label = _("enabled"); else label = _("disabled"); return label; } static void _fill_iter_from_app (GtkListStore *list_store, GtkTreeIter *iter, GspApp *app) { gboolean hidden; gboolean display; gboolean enabled; gboolean shown; GIcon *icon; const char *description; const char *app_name; const char *label; const char *space = " "; hidden = gsp_app_get_hidden (app); display = gsp_app_get_display (app); enabled = gsp_app_get_enabled (app); shown = gsp_app_get_shown (app); icon = gsp_app_get_icon (app); description = gsp_app_get_description (app); app_name = gsp_app_get_name (app); label = kylin_set_the_label(app); if (G_IS_THEMED_ICON (icon)) { GtkIconTheme *theme; const char * const *icon_names; theme = gtk_icon_theme_get_default (); icon_names = g_themed_icon_get_names (G_THEMED_ICON (icon)); if (icon_names[0] == NULL || !gtk_icon_theme_has_icon (theme, icon_names[0])) { g_object_unref (icon); icon = NULL; } } else if (G_IS_FILE_ICON (icon)) { GFile *iconfile; iconfile = g_file_icon_get_file (G_FILE_ICON (icon)); if (!g_file_query_exists (iconfile, NULL)) { g_object_unref (icon); icon = NULL; } } if (icon == NULL) { icon = g_themed_icon_new (STARTUP_APP_ICON); } gtk_list_store_set (list_store, iter, STORE_COL_VISIBLE, !hidden && shown && display, STORE_COL_ENABLED, enabled, STORE_COL_GICON, icon, STORE_COL_DESCRIPTION, description, STORE_COL_APP, app, STORE_COL_SEARCH, app_name, STORE_COL_LABEL, label, STORE_COL_SPACE, space, -1); g_object_unref (icon); } static void _app_changed (GsmPropertiesDialog *dialog, GspApp *app) { GtkTreeIter iter; if (!find_by_app (GTK_TREE_MODEL (dialog->priv->list_store), &iter, app)) { return; } _fill_iter_from_app (dialog->priv->list_store, &iter, app); } static void append_app (GsmPropertiesDialog *dialog, GspApp *app) { GtkTreeIter iter; gtk_list_store_append (dialog->priv->list_store, &iter); _fill_iter_from_app (dialog->priv->list_store, &iter, app); g_signal_connect_swapped (app, "changed", G_CALLBACK (_app_changed), dialog); } static void _app_added (GsmPropertiesDialog *dialog, GspApp *app, GspAppManager *manager) { append_app (dialog, app); } static void _app_removed (GsmPropertiesDialog *dialog, GspApp *app, GspAppManager *manager) { GtkTreeIter iter; if (!find_by_app (GTK_TREE_MODEL (dialog->priv->list_store), &iter, app)) { return; } g_signal_handlers_disconnect_by_func (app, _app_changed, dialog); gtk_list_store_remove (dialog->priv->list_store, &iter); } static void populate_model (GsmPropertiesDialog *dialog) { GSList *apps; GSList *l; apps = gsp_app_manager_get_apps (dialog->priv->manager); for (l = apps; l != NULL; l = l->next) { append_app (dialog, GSP_APP (l->data)); } g_slist_free (apps); } static void on_selection_changed (GtkTreeSelection *selection, GsmPropertiesDialog *dialog) { gboolean sel; sel = gtk_tree_selection_get_selected (selection, NULL, NULL); gtk_widget_set_sensitive (dialog->priv->edit_button, sel); gtk_widget_set_sensitive (dialog->priv->delete_button, sel); } static void on_startup_enabled_toggled (GtkCellRendererToggle *cell_renderer, char *path, GsmPropertiesDialog *dialog) { GtkTreeIter iter; GspApp *app; gboolean active; if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (dialog->priv->tree_filter), &iter, path)) { return; } app = NULL; gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->tree_filter), &iter, STORE_COL_APP, &app, -1); active = gtk_cell_renderer_toggle_get_active (cell_renderer); active = !active; if (app) { gsp_app_set_enabled (app, active); g_object_unref (app); } } static void on_drag_data_received (GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y, GtkSelectionData *data, guint info, guint time, GsmPropertiesDialog *dialog) { gboolean dnd_success; dnd_success = FALSE; if (data != NULL) { char **filenames; int i; filenames = gtk_selection_data_get_uris (data); for (i = 0; filenames[i] && filenames[i][0]; i++) { /* Return success if at least one file succeeded */ gboolean file_success; file_success = gsp_app_copy_desktop_file (filenames[i]); dnd_success = dnd_success || file_success; } g_strfreev (filenames); } gtk_drag_finish (drag_context, dnd_success, FALSE, time); g_signal_stop_emission_by_name (widget, "drag_data_received"); } static void on_drag_begin (GtkWidget *widget, GdkDragContext *context, GsmPropertiesDialog *dialog) { GtkTreePath *path; GtkTreeIter iter; GspApp *app; gtk_tree_view_get_cursor (GTK_TREE_VIEW (widget), &path, NULL); gtk_tree_model_get_iter (GTK_TREE_MODEL (dialog->priv->tree_filter), &iter, path); gtk_tree_path_free (path); gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->tree_filter), &iter, STORE_COL_APP, &app, -1); if (app) { g_object_set_data_full (G_OBJECT (context), "gsp-app", g_object_ref (app), g_object_unref); g_object_unref (app); } } static void on_drag_data_get (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time, GsmPropertiesDialog *dialog) { GspApp *app; app = g_object_get_data (G_OBJECT (context), "gsp-app"); if (app) { const char *uris[2]; char *uri; uri = g_filename_to_uri (gsp_app_get_path (app), NULL, NULL); uris[0] = uri; uris[1] = NULL; gtk_selection_data_set_uris (selection_data, (char **) uris); g_free (uri); } } static void on_add_app_clicked (GtkWidget *widget, GsmPropertiesDialog *dialog) { GtkWidget *add_dialog; char *name; char *exec; char *comment; char *icon; add_dialog = gsm_app_dialog_new (NULL, NULL, NULL); //gtk_window_set_transient_for (GTK_WINDOW (add_dialog), // GTK_WINDOW (dialog)); if (gsm_app_dialog_run (GSM_APP_DIALOG (add_dialog), &name, &exec, &comment, &icon)) { if(8 == gsp_app_create (name, comment, exec ,icon)) { GtkWidget *msgbox; msgbox = gtk_message_dialog_new (GTK_WINDOW (add_dialog), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s开机启动已经存在!", name); gtk_widget_set_name(GTK_WIDGET(msgbox), "ukuicc"); gtk_dialog_run (GTK_DIALOG (msgbox)); gtk_widget_destroy (msgbox); } g_free (name); g_free (exec); g_free (comment); g_free (icon); } } static void on_delete_app_clicked (GtkWidget *widget, GsmPropertiesDialog *dialog) { GtkTreeSelection *selection; GtkTreeIter iter; GspApp *app; selection = gtk_tree_view_get_selection (dialog->priv->treeview); if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) { return; } app = NULL; gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->tree_filter), &iter, STORE_COL_APP, &app, -1); if (app) { gsp_app_delete (app); // g_object_unref (app);arm64下会崩溃 } } static char * get_string_from_guint64(guint64 gu){ GDateTime * time; static gchar str[50]; gint year, month, day; time = g_date_time_new_from_unix_local(gu); g_date_time_get_ymd(time, &year, &month, &day); g_sprintf(str, _("%d/%d/%d/ %d:%d:%d"),year,month,day,g_date_time_get_hour(time),g_date_time_get_minute(time),g_date_time_get_second(time)); return str; } //example 1: Exec =/usr/bin/youker-assistant //example 2: Exec =ukui-search-tool //example 3: Exec =libreoffice --math //example 4: Exec =smplayer --add-to-playlist %U //and others example, like 1&3 1&4 ... //we need to consider $PATH, and return string like "Exec = /usr/bin/smplayer --add-to-playlist %U" //there must be 3 parts at least, name(/usr/bin/smplayer),argument(--add-to-playlist) and format(%U) static char * get_absolute_app_path(char * exec){ char * absolute_exec; char ** tmp_str; char * env; char ** tmp_env; int size; char file_path[50]; if (exec) { tmp_str = g_strsplit(exec, " ", -1); env = g_getenv("PATH"); tmp_env = g_strsplit(env, ":", -1); if (g_file_test(tmp_str[0],G_FILE_TEST_EXISTS)){ absolute_exec = tmp_str[0]; return absolute_exec; } for(;*tmp_env;tmp_env++){ g_sprintf(file_path, "%s/%s",*tmp_env,tmp_str[0]); if (g_file_test(file_path, G_FILE_TEST_EXISTS)){ absolute_exec = file_path; return absolute_exec; } } } } static void on_edit_app_clicked (GtkWidget *widget, GsmPropertiesDialog *dialog) { GtkTreeSelection *selection; GtkTreeIter iter; GspApp *app; GtkWidget * builder; GError * error= NULL; GtkWidget *edit_dialog; GtkDialog * pro_dialog; builder = gtk_builder_new(); if (gtk_builder_add_from_file(builder, UIDIR"/program_properties.ui", &error ) == 0){ g_warning("Could not load ui file occurred error:%s", error->message); return; } edit_dialog = GTK_WIDGET(gtk_builder_get_object(builder, "dialog")); selection = gtk_tree_view_get_selection (dialog->priv->treeview); if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) { return; } app = NULL; gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->tree_filter), &iter, STORE_COL_APP, &app, -1); if (app) { char *name; char *exec; char *comment; char *absolute_exec=NULL; GIcon *icon; char *title; gint res; GFile * exec_file; GError * err= NULL; GFileInfo * exec_info; name = gsp_app_get_name(app); exec = gsp_app_get_exec(app); absolute_exec = get_absolute_app_path(exec); comment = gsp_app_get_comment(app); icon = gsp_app_get_icon(app); title = g_strdup_printf("%s %s",name,_("property")); gtk_window_set_title(edit_dialog,title); //set label if (comment) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(builder, "pro_des")), comment); else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(builder, "pro_des")), gsp_app_get_description(app)); gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(builder, "pro_name")), name); gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(builder, "pro_exec")), exec); if (icon == NULL){ gtk_image_set_from_icon_name(GTK_IMAGE(gtk_builder_get_object(builder, "pro_icon")), STARTUP_APP_ICON, GTK_ICON_SIZE_BUTTON); } else gtk_image_set_from_gicon(GTK_IMAGE(gtk_builder_get_object(builder, "pro_icon")), icon,GTK_ICON_SIZE_BUTTON); exec_file = g_file_new_for_path(absolute_exec); exec_info = g_file_query_info(exec_file, G_FILE_ATTRIBUTE_STANDARD_SIZE"," G_FILE_ATTRIBUTE_TIME_MODIFIED"," G_FILE_ATTRIBUTE_TIME_ACCESS, G_FILE_QUERY_INFO_NONE, NULL, &err ); if (err != NULL){ g_warning("get exec info error:%s", err->message); } g_object_unref(exec_file); goffset off = g_file_info_get_size(exec_info); gchar str[20]; g_sprintf(str, _("%dByte"),(gint )off); gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(builder, "pro_size")), str); guint64 modified_time; guint64 accessed_time; char * modified_str = NULL; char * accessed_str = NULL; modified_time = g_file_info_get_attribute_uint64(exec_info, G_FILE_ATTRIBUTE_TIME_MODIFIED); modified_str = get_string_from_guint64(modified_time); gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(builder, "pro_cha_time")), modified_str); accessed_time = g_file_info_get_attribute_uint64(exec_info, G_FILE_ATTRIBUTE_TIME_ACCESS); accessed_str = get_string_from_guint64(accessed_time); gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(builder, "pro_cre_time")), accessed_str); gtk_dialog_add_button(GTK_DIALOG(edit_dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); res = gtk_dialog_run(edit_dialog); g_free(title); gtk_widget_destroy(edit_dialog); g_object_unref (app); g_object_unref(exec_info); } } static void on_row_activated (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, GsmPropertiesDialog *dialog) { on_edit_app_clicked (NULL, dialog); } static void on_save_session_clicked (GtkWidget *widget, GsmPropertiesDialog *dialog) { g_debug ("Session saving is not implemented yet!"); } static void setup_dialog (GsmPropertiesDialog *dialog) { GtkTreeView *treeview; GtkWidget *button; GtkTreeModel *tree_filter; GtkTreeViewColumn *column; GtkCellRenderer *renderer; GtkTreeSelection *selection; GtkTargetList *targetlist; dialog->priv->list_store = gtk_list_store_new (NUMBER_OF_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_ICON, G_TYPE_STRING, G_TYPE_OBJECT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); tree_filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (dialog->priv->list_store),NULL); g_object_unref (dialog->priv->list_store); dialog->priv->tree_filter = tree_filter; //根据这个属性的bool值判断是否过滤此行 gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (tree_filter),STORE_COL_VISIBLE); treeview = GTK_TREE_VIEW (gtk_builder_get_object (dialog->priv->xml,CAPPLET_TREEVIEW_WIDGET_NAME)); dialog->priv->treeview = treeview; gtk_tree_view_set_model (treeview, tree_filter); g_object_unref (tree_filter); gtk_tree_view_set_headers_visible (treeview, FALSE); g_signal_connect (treeview, "row-activated", G_CALLBACK (on_row_activated), dialog); selection = gtk_tree_view_get_selection (treeview); gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); g_signal_connect (selection, "changed", G_CALLBACK (on_selection_changed), dialog); /* ICON COLUMN */ renderer = gtk_cell_renderer_pixbuf_new (); gtk_cell_renderer_set_padding(renderer, 0, 5); column = gtk_tree_view_column_new_with_attributes ("Icon", renderer, "gicon", STORE_COL_GICON, "sensitive", STORE_COL_ENABLED, NULL); g_object_set (renderer, "stock-size", GSM_PROPERTIES_ICON_SIZE, NULL); gtk_tree_view_append_column (treeview, column); /* NAME COLUMN */ renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("Program", renderer, "markup", STORE_COL_DESCRIPTION, "sensitive", STORE_COL_ENABLED, NULL); // g_object_set (renderer, // "ellipsize", PANGO_ELLIPSIZE_END, // NULL); gtk_tree_view_append_column (treeview, column); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("Space", renderer, "markup", STORE_COL_SPACE, "sensitive", STORE_COL_ENABLED, NULL); gtk_tree_view_append_column (treeview, column); /* CHECKBOX COLUMN */ renderer = gtk_cell_renderer_toggle_new (); column = gtk_tree_view_column_new_with_attributes ("Enabled", renderer, "active", STORE_COL_ENABLED, NULL); gtk_tree_view_append_column (treeview, column); g_signal_connect (renderer, "toggled", G_CALLBACK (on_startup_enabled_toggled), dialog); /* LABEL COLUMN */ renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes("Lable", renderer, "markup",STORE_COL_LABEL, "sensitive", STORE_COL_ENABLED, NULL); gtk_tree_view_append_column (treeview, column); gtk_tree_view_column_set_sort_column_id (column, STORE_COL_DESCRIPTION); gtk_tree_view_set_search_column (treeview, STORE_COL_SEARCH); gtk_tree_view_set_rules_hint (treeview, TRUE); gtk_tree_view_enable_model_drag_source (treeview, GDK_BUTTON1_MASK|GDK_BUTTON2_MASK, NULL, 0, GDK_ACTION_COPY); gtk_drag_source_add_uri_targets (GTK_WIDGET (treeview)); gtk_drag_dest_set (GTK_WIDGET (treeview), GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY); gtk_drag_dest_add_uri_targets (GTK_WIDGET (treeview)); /* we don't want to accept drags coming from this widget */ targetlist = gtk_drag_dest_get_target_list (GTK_WIDGET (treeview)); if (targetlist != NULL) { GtkTargetEntry *targets; gint n_targets; gint i; targets = gtk_target_table_new_from_list (targetlist, &n_targets); for (i = 0; i < n_targets; i++) targets[i].flags = GTK_TARGET_OTHER_WIDGET; targetlist = gtk_target_list_new (targets, n_targets); gtk_drag_dest_set_target_list (GTK_WIDGET (treeview), targetlist); gtk_target_list_unref (targetlist); gtk_target_table_free (targets, n_targets); } g_signal_connect (treeview, "drag_begin", G_CALLBACK (on_drag_begin), dialog); g_signal_connect (treeview, "drag_data_get", G_CALLBACK (on_drag_data_get), dialog); g_signal_connect (treeview, "drag_data_received", G_CALLBACK (on_drag_data_received), dialog); gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (dialog->priv->list_store), STORE_COL_DESCRIPTION, GTK_SORT_ASCENDING); button = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml, CAPPLET_ADD_WIDGET_NAME)); dialog->priv->add_button = button; g_signal_connect (button, "clicked", G_CALLBACK (on_add_app_clicked), dialog); button = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml, CAPPLET_DELETE_WIDGET_NAME)); dialog->priv->delete_button = button; g_signal_connect (button, "clicked", G_CALLBACK (on_delete_app_clicked), dialog); button = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml, CAPPLET_EDIT_WIDGET_NAME)); dialog->priv->edit_button = button; g_signal_connect (button, "clicked", G_CALLBACK (on_edit_app_clicked), dialog); //dialog->priv->settings = g_settings_new(SPC_SETTINGS_SCHEMA); //button = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml, // CAPPLET_REMEMBER_WIDGET_NAME)); //g_settings_bind (dialog->priv->settings, SPC_SETTINGS_AUTOSAVE_KEY, // button, "active", G_SETTINGS_BIND_DEFAULT); //button = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml, // CAPPLET_SAVE_WIDGET_NAME)); //g_signal_connect (button, // "clicked", // G_CALLBACK (on_save_session_clicked), // dialog); dialog->priv->manager = gsp_app_manager_get (); gsp_app_manager_fill (dialog->priv->manager); g_signal_connect_swapped (dialog->priv->manager, "added", G_CALLBACK (_app_added), dialog); g_signal_connect_swapped (dialog->priv->manager, "removed", G_CALLBACK (_app_removed), dialog); populate_model (dialog); } void gsm_properties_dialog_new(GtkBuilder *builder) { topbuilder = builder; dialog1 = &Dialog1; dialog2 = &Dialog2; dialog1->priv = dialog2; dialog1->priv->xml = builder; setup_dialog(dialog1); } void gsm_properties_dialog_destroy(){ if (dialog1->priv->manager !=NULL){ g_object_unref(dialog1->priv->manager); dialog1->priv->manager = NULL; } g_object_unref(dialog1->priv->settings); } ukui-control-center/panels/session-properties/gsp-app-manager.c0000664000175000017500000005036513245450076023712 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 1999 Free Software Foundation, Inc. * Copyright (C) 2007, 2009 Vincent Untz. * Copyright (C) 2008 Lucas Rocha. * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include "gsm-util.h" #include "gsp-app.h" #include "gsp-app-manager.h" static GspAppManager *manager = NULL; typedef struct { char *dir; int index; GFileMonitor *monitor; } GspXdgDir; struct _GspAppManagerPrivate { GSList *apps; GSList *dirs; }; #define GSP_APP_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSP_TYPE_APP_MANAGER, GspAppManagerPrivate)) enum { ADDED, REMOVED, LAST_SIGNAL }; static guint gsp_app_manager_signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (GspAppManager, gsp_app_manager, G_TYPE_OBJECT) static void gsp_app_manager_dispose (GObject *object); static void gsp_app_manager_finalize (GObject *object); static void _gsp_app_manager_app_unref (GspApp *app, GspAppManager *manager); static void _gsp_app_manager_app_removed (GspAppManager *manager, GspApp *app); static GspXdgDir * _gsp_xdg_dir_new (const char *dir, int index) { GspXdgDir *xdgdir; xdgdir = g_slice_new (GspXdgDir); xdgdir->dir = g_strdup (dir); xdgdir->index = index; xdgdir->monitor = NULL; return xdgdir; } static void _gsp_xdg_dir_free (GspXdgDir *xdgdir) { if (xdgdir->dir) { g_free (xdgdir->dir); xdgdir->dir = NULL; } if (xdgdir->monitor) { g_file_monitor_cancel (xdgdir->monitor); g_object_unref (xdgdir->monitor); xdgdir->monitor = NULL; } g_slice_free (GspXdgDir, xdgdir); } static void gsp_app_manager_class_init (GspAppManagerClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); gobject_class->dispose = gsp_app_manager_dispose; gobject_class->finalize = gsp_app_manager_finalize; gsp_app_manager_signals[ADDED] = g_signal_new ("added", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GspAppManagerClass, added), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); gsp_app_manager_signals[REMOVED] = g_signal_new ("removed", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GspAppManagerClass, removed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); g_type_class_add_private (class, sizeof (GspAppManagerPrivate)); } static void gsp_app_manager_init (GspAppManager *manager) { manager->priv = GSP_APP_MANAGER_GET_PRIVATE (manager); memset (manager->priv, 0, sizeof (GspAppManagerPrivate)); } static void gsp_app_manager_dispose (GObject *object) { GspAppManager *manager; g_return_if_fail (object != NULL); g_return_if_fail (GSP_IS_APP_MANAGER (object)); manager = GSP_APP_MANAGER (object); /* we unref GspApp objects in dispose since they might need to * reference us during their dispose/finalize */ g_slist_foreach (manager->priv->apps, (GFunc) _gsp_app_manager_app_unref, manager); g_slist_free (manager->priv->apps); manager->priv->apps = NULL; G_OBJECT_CLASS (gsp_app_manager_parent_class)->dispose (object); } static void gsp_app_manager_finalize (GObject *object) { GspAppManager *manager; g_return_if_fail (object != NULL); g_return_if_fail (GSP_IS_APP_MANAGER (object)); manager = GSP_APP_MANAGER (object); g_slist_foreach (manager->priv->dirs, (GFunc) _gsp_xdg_dir_free, NULL); g_slist_free (manager->priv->dirs); manager->priv->dirs = NULL; G_OBJECT_CLASS (gsp_app_manager_parent_class)->finalize (object); manager = NULL; } static void _gsp_app_manager_emit_added (GspAppManager *manager, GspApp *app) { g_signal_emit (G_OBJECT (manager), gsp_app_manager_signals[ADDED], 0, app); } static void _gsp_app_manager_emit_removed (GspAppManager *manager, GspApp *app) { g_signal_emit (G_OBJECT (manager), gsp_app_manager_signals[REMOVED], 0, app); } /* * Directories */ static int gsp_app_manager_get_dir_index (GspAppManager *manager, const char *dir) { GSList *l; GspXdgDir *xdgdir; g_return_val_if_fail (GSP_IS_APP_MANAGER (manager), -1); g_return_val_if_fail (dir != NULL, -1); for (l = manager->priv->dirs; l != NULL; l = l->next) { xdgdir = l->data; if (strcmp (dir, xdgdir->dir) == 0) { return xdgdir->index; } } return -1; } const char * gsp_app_manager_get_dir (GspAppManager *manager, unsigned int index) { GSList *l; GspXdgDir *xdgdir; g_return_val_if_fail (GSP_IS_APP_MANAGER (manager), NULL); for (l = manager->priv->dirs; l != NULL; l = l->next) { xdgdir = l->data; if (index == xdgdir->index) { return xdgdir->dir; } } return NULL; } static int _gsp_app_manager_find_dir_with_basename (GspAppManager *manager, const char *basename, int minimum_index) { GSList *l; GspXdgDir *xdgdir; char *path; GKeyFile *keyfile; int result = -1; path = NULL; keyfile = g_key_file_new (); for (l = manager->priv->dirs; l != NULL; l = l->next) { xdgdir = l->data; if (xdgdir->index <= minimum_index) { continue; } g_free (path); path = g_build_filename (xdgdir->dir, basename, NULL); if (!g_file_test (path, G_FILE_TEST_EXISTS)) { continue; } if (!g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, NULL)) { continue; } /* the file exists and is readable */ if (result == -1) { result = xdgdir->index; } else { result = MIN (result, xdgdir->index); } } g_key_file_free (keyfile); g_free (path); return result; } static void _gsp_app_manager_handle_delete (GspAppManager *manager, GspApp *app, const char *basename, int index) { unsigned int position; unsigned int system_position; position = gsp_app_get_xdg_position (app); system_position = gsp_app_get_xdg_system_position (app); if (system_position < index) { /* it got deleted, but we don't even care about it */ return; } if (index < position) { /* it got deleted, but in a position earlier than the current * one. This happens when the user file was changed and became * identical to the system file; in this case, the user file is * simply removed. */ g_assert (index == 0); return; } if (position == index && (system_position == index || system_position == G_MAXUINT)) { /* the file used by the user was deleted, and there's no other * file in system directories. So it really got deleted. */ _gsp_app_manager_app_removed (manager, app); return; } if (system_position == index) { /* then we know that position != index; we just hae to tell * GspApp if there's still a system directory containing this * basename */ int new_system; new_system = _gsp_app_manager_find_dir_with_basename (manager, basename, index); if (new_system < 0) { gsp_app_set_xdg_system_position (app, G_MAXUINT); } else { gsp_app_set_xdg_system_position (app, new_system); } return; } if (position == index) { /* then we know that system_position != G_MAXUINT; we need to * tell GspApp to change position to system_position */ const char *dir; dir = gsp_app_manager_get_dir (manager, system_position); if (dir) { char *path; path = g_build_filename (dir, basename, NULL); gsp_app_reload_at (app, path, (unsigned int) system_position); g_free (path); } else { _gsp_app_manager_app_removed (manager, app); } return; } g_assert_not_reached (); } static gboolean gsp_app_manager_xdg_dir_monitor (GFileMonitor *monitor, GFile *child, GFile *other_file, GFileMonitorEvent flags, gpointer data) { GspAppManager *manager; GspApp *old_app; GspApp *app; GFile *parent; char *basename; char *dir; char *path; int index; manager = GSP_APP_MANAGER (data); basename = g_file_get_basename (child); if (!g_str_has_suffix (basename, ".desktop")) { /* not a desktop file, we can ignore */ g_free (basename); return TRUE; } old_app = gsp_app_manager_find_app_with_basename (manager, basename); parent = g_file_get_parent (child); dir = g_file_get_path (parent); g_object_unref (parent); index = gsp_app_manager_get_dir_index (manager, dir); if (index < 0) { /* not a directory we know; should never happen, though */ g_free (dir); return TRUE; } path = g_file_get_path (child); switch (flags) { case G_FILE_MONITOR_EVENT_CHANGED: case G_FILE_MONITOR_EVENT_CREATED: /* we just do as if it was a new file: GspApp is clever enough * to do the right thing */ app = gsp_app_new (path, (unsigned int) index); /* we didn't have this app before, so add it */ if (old_app == NULL && app != NULL) { gsp_app_manager_add (manager, app); g_object_unref (app); } /* else: it was just updated, GspApp took care of * sending the event */ break; case G_FILE_MONITOR_EVENT_DELETED: if (!old_app) { /* it got deleted, but we don't know about it, so * nothing to do */ break; } _gsp_app_manager_handle_delete (manager, old_app, basename, index); break; default: break; } g_free (path); g_free (dir); g_free (basename); return TRUE; } /* * Initialization */ static void _gsp_app_manager_fill_from_dir (GspAppManager *manager, GspXdgDir *xdgdir) { GFile *file; GDir *dir; const char *name; file = g_file_new_for_path (xdgdir->dir); xdgdir->monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); g_object_unref (file); if (xdgdir->monitor) { g_signal_connect (xdgdir->monitor, "changed", G_CALLBACK (gsp_app_manager_xdg_dir_monitor), manager); } dir = g_dir_open (xdgdir->dir, 0, NULL); if (!dir) { return; } while ((name = g_dir_read_name (dir))) { GspApp *app; char *desktop_file_path; if (!g_str_has_suffix (name, ".desktop")) { continue; } desktop_file_path = g_build_filename (xdgdir->dir, name, NULL); app = gsp_app_new (desktop_file_path, xdgdir->index); if (app != NULL) { gsp_app_manager_add (manager, app); g_object_unref (app); } g_free (desktop_file_path); } g_dir_close (dir); } void gsp_app_manager_fill (GspAppManager *manager) { char **autostart_dirs; int i; if (manager->priv->apps != NULL) return; autostart_dirs = gsm_util_get_autostart_dirs (); /* we always assume that the first directory is the user one */ g_assert (g_str_has_prefix (autostart_dirs[0], g_get_user_config_dir ())); for (i = 0; autostart_dirs[i] != NULL; i++) { GspXdgDir *xdgdir; if (gsp_app_manager_get_dir_index (manager, autostart_dirs[i]) >= 0) { continue; } xdgdir = _gsp_xdg_dir_new (autostart_dirs[i], i); manager->priv->dirs = g_slist_prepend (manager->priv->dirs, xdgdir); _gsp_app_manager_fill_from_dir (manager, xdgdir); } g_strfreev (autostart_dirs); } /* * App handling */ static void _gsp_app_manager_app_unref (GspApp *app, GspAppManager *manager) { g_signal_handlers_disconnect_by_func (app, _gsp_app_manager_app_removed, manager); g_object_unref (app); } static void _gsp_app_manager_app_removed (GspAppManager *manager, GspApp *app) { _gsp_app_manager_emit_removed (manager, app); manager->priv->apps = g_slist_remove (manager->priv->apps, app); _gsp_app_manager_app_unref (app, manager); } void gsp_app_manager_add (GspAppManager *manager, GspApp *app) { g_return_if_fail (GSP_IS_APP_MANAGER (manager)); g_return_if_fail (GSP_IS_APP (app)); manager->priv->apps = g_slist_prepend (manager->priv->apps, g_object_ref (app)); g_signal_connect_swapped (app, "removed", G_CALLBACK (_gsp_app_manager_app_removed), manager); _gsp_app_manager_emit_added (manager, app); } GspApp * gsp_app_manager_find_local_app_with_name_exec (GspAppManager *manager, const char *name ,const char *exec,const char* icon) { GSList *l; GspApp *app; g_return_val_if_fail (GSP_IS_APP_MANAGER (manager), NULL); g_return_val_if_fail (exec != NULL, NULL); for (l = manager->priv->apps; l != NULL; l = l->next) { app = GSP_APP (l->data); //防止有些应用的desktop文件不包含这些项而导致为空 if(!gsp_app_get_name(app) || !gsp_app_get_exec(app) || !gsp_app_get_path(app)) return NULL; if (!strcmp (name, gsp_app_get_name(app))&&!strcmp (exec, gsp_app_get_exec(app))) //&&!strcmp (icon, gsp_app_get_icon_char(app))) { if(strstr(gsp_app_get_path(app),"config/autostart/") && gsp_app_get_hidden(app) && !gsp_app_get_enabled(app)) { //g_warning("-----------表示是本地文件并且隐藏了--------------%s",gsp_app_get_path(app)); return NULL; } if(strstr(gsp_app_get_path(app),"config/autostart/") && !gsp_app_get_hidden(app)) { //g_warning("-----------表示是本地文件并且显示了--------------%s",gsp_app_get_path(app)); return app; } else if(!gsp_app_get_hidden(app) && gsp_app_get_display(app) && gsp_app_get_shown(app) && strstr(gsp_app_get_path(app),"/etc/xdg/autostart/")) { //g_warning("----------表示是系统目录文件并且会显示在控制面板---------------%s",gsp_app_get_path(app)); return app; } g_warning("------------3-------------%s",gsp_app_get_path(app)); } } //g_warning("--------------4-----------%s",gsp_app_get_path(app)); return NULL; } GspApp * gsp_app_manager_find_app_with_basename (GspAppManager *manager, const char *basename) { GSList *l; GspApp *app; g_return_val_if_fail (GSP_IS_APP_MANAGER (manager), NULL); g_return_val_if_fail (basename != NULL, NULL); for (l = manager->priv->apps; l != NULL; l = l->next) { app = GSP_APP (l->data); if (strcmp (basename, gsp_app_get_basename (app)) == 0) return app; } return NULL; } GspApp * gsp_app_manager_find_app_with_name (GspAppManager *manager, const char *name) { GSList *l; GspApp *app; g_return_val_if_fail (GSP_IS_APP_MANAGER (manager), NULL); g_return_val_if_fail (name != NULL, NULL); for (l = manager->priv->apps; l != NULL; l = l->next) { app = GSP_APP (l->data); if (strcmp (name, gsp_app_get_name (app)) == 0) return app; } return NULL; } /* * Singleton */ GspAppManager * gsp_app_manager_get (void) { if (manager == NULL) { manager = g_object_new (GSP_TYPE_APP_MANAGER, NULL); return manager; } else { return g_object_ref (manager); } } GSList * gsp_app_manager_get_apps (GspAppManager *manager) { g_return_val_if_fail (GSP_IS_APP_MANAGER (manager), NULL); return g_slist_copy (manager->priv->apps); } ukui-control-center/panels/session-properties/gsp-app.c0000664000175000017500000010344113253611037022267 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 1999 Free Software Foundation, Inc. * Copyright (C) 2007, 2009 Vincent Untz. * Copyright (C) 2008 Lucas Rocha. * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "gsm-app-dialog.h" #include "gsm-properties-dialog.h" #include "gsm-util.h" #include "gsp-app-manager.h" #include "gsp-keyfile.h" #include "gsp-app.h" //#define GSP_APP_SAVE_DELAY 2 #define GSP_APP_SAVE_DELAY 1 #define GSP_ASP_SAVE_MASK_HIDDEN 0x0001 #define GSP_ASP_SAVE_MASK_ENABLED 0x0002 #define GSP_ASP_SAVE_MASK_NAME 0x0004 #define GSP_ASP_SAVE_MASK_EXEC 0x0008 #define GSP_ASP_SAVE_MASK_COMMENT 0x0010 #define GSP_ASP_SAVE_MASK_NO_DISPLAY 0x0020 #define GSP_ASP_SAVE_MASK_ALL 0xffff struct _GspAppPrivate { char *basename; char *path; gboolean hidden; gboolean no_display; gboolean enabled; gboolean shown; char *name; char *exec; char *comment; char *icon; GIcon *gicon; char *description; /* position of the directory in the XDG environment variable */ unsigned int xdg_position; /* position of the first system directory in the XDG env var containing * this autostart app too (G_MAXUINT means none) */ unsigned int xdg_system_position; unsigned int save_timeout; /* mask of what has changed */ unsigned int save_mask; /* path that contains the original file that needs to be saved */ char *old_system_path; /* after writing to file, we skip the next file monitor event of type * CHANGED */ gboolean skip_next_monitor_event; }; #define GSP_APP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSP_TYPE_APP, GspAppPrivate)) enum { CHANGED, REMOVED, LAST_SIGNAL }; static guint gsp_app_signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (GspApp, gsp_app, G_TYPE_OBJECT) static void gsp_app_dispose (GObject *object); static void gsp_app_finalize (GObject *object); static gboolean _gsp_app_save (gpointer data); static gboolean _gsp_str_equal (const char *a, const char *b) { if (g_strcmp0 (a, b) == 0) { return TRUE; } if (a && !b && a[0] == '\0') { return TRUE; } if (b && !a && b[0] == '\0') { return TRUE; } return FALSE; } static void gsp_app_class_init (GspAppClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); gobject_class->dispose = gsp_app_dispose; gobject_class->finalize = gsp_app_finalize; gsp_app_signals[CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GspAppClass, changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); gsp_app_signals[REMOVED] = g_signal_new ("removed", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GspAppClass, removed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); g_type_class_add_private (class, sizeof (GspAppPrivate)); } static void gsp_app_init (GspApp *app) { app->priv = GSP_APP_GET_PRIVATE (app); memset (app->priv, 0, sizeof (GspAppPrivate)); app->priv->xdg_position = G_MAXUINT; app->priv->xdg_system_position = G_MAXUINT; } static void _gsp_app_free_reusable_data (GspApp *app) { if (app->priv->path) { g_free (app->priv->path); app->priv->path = NULL; } if (app->priv->name) { g_free (app->priv->name); app->priv->name = NULL; } if (app->priv->exec) { g_free (app->priv->exec); app->priv->exec = NULL; } if (app->priv->comment) { g_free (app->priv->comment); app->priv->comment = NULL; } if (app->priv->icon) { g_free (app->priv->icon); app->priv->icon = NULL; } if (app->priv->gicon) { g_object_unref (app->priv->gicon); app->priv->gicon = NULL; } if (app->priv->description) { g_free (app->priv->description); app->priv->description = NULL; } if (app->priv->old_system_path) { g_free (app->priv->old_system_path); app->priv->old_system_path = NULL; } } static void gsp_app_dispose (GObject *object) { GspApp *app; g_return_if_fail (object != NULL); g_return_if_fail (GSP_IS_APP (object)); app = GSP_APP (object); /* we save in dispose since we might need to reference GspAppManager */ if (app->priv->save_timeout) { g_source_remove (app->priv->save_timeout); app->priv->save_timeout = 0; /* save now */ _gsp_app_save (app); } G_OBJECT_CLASS (gsp_app_parent_class)->dispose (object); } static void gsp_app_finalize (GObject *object) { GspApp *app; g_return_if_fail (object != NULL); g_return_if_fail (GSP_IS_APP (object)); app = GSP_APP (object); if (app->priv->basename) { g_free (app->priv->basename); app->priv->basename = NULL; } _gsp_app_free_reusable_data (app); G_OBJECT_CLASS (gsp_app_parent_class)->finalize (object); } static void _gsp_app_emit_changed (GspApp *app) { g_signal_emit (G_OBJECT (app), gsp_app_signals[CHANGED], 0); } static void _gsp_app_emit_removed (GspApp *app) { g_signal_emit (G_OBJECT (app), gsp_app_signals[REMOVED], 0); } static void _gsp_app_update_description (GspApp *app) { const char *primary; const char *secondary; if (!gsm_util_text_is_blank (app->priv->name)) { primary = app->priv->name; } else if (!gsm_util_text_is_blank (app->priv->exec)) { primary = app->priv->exec; } else { primary = "No name"; } if (!gsm_util_text_is_blank (app->priv->comment)) { secondary = app->priv->comment; } else { secondary = "No description"; } g_free (app->priv->description); app->priv->description = g_markup_printf_escaped ("%s", primary); } /* * Saving */ static void _gsp_ensure_user_autostart_dir (void) { char *dir; dir = g_build_filename (g_get_user_config_dir (), "autostart", NULL); g_mkdir_with_parents (dir, S_IRWXU); g_free (dir); } static gboolean _gsp_app_user_equal_system (GspApp *app, char **system_path) { GspAppManager *manager; const char *system_dir; char *path; char *str; GKeyFile *keyfile; manager = gsp_app_manager_get (); system_dir = gsp_app_manager_get_dir (manager, app->priv->xdg_system_position); g_object_unref (manager); if (!system_dir) { return FALSE; } path = g_build_filename (system_dir, app->priv->basename, NULL); keyfile = g_key_file_new (); if (!g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, NULL)) { g_free (path); g_key_file_free (keyfile); return FALSE; } if (gsp_key_file_get_boolean (keyfile, G_KEY_FILE_DESKTOP_KEY_HIDDEN, FALSE) != app->priv->hidden || gsp_key_file_get_boolean (keyfile, GSP_KEY_FILE_DESKTOP_KEY_AUTOSTART_ENABLED, TRUE) != app->priv->enabled || gsp_key_file_get_shown (keyfile, //gsm_util_get_current_desktop ()) != app->priv->shown) { "UKUI") != app->priv->shown) { g_free (path); g_key_file_free (keyfile); return FALSE; } if (gsp_key_file_get_boolean (keyfile, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, FALSE) != app->priv->no_display) { g_free (path); g_key_file_free (keyfile); return FALSE; } str = gsp_key_file_get_locale_string (keyfile, G_KEY_FILE_DESKTOP_KEY_NAME); if (!_gsp_str_equal (str, app->priv->name)) { g_free (str); g_free (path); g_key_file_free (keyfile); return FALSE; } g_free (str); str = gsp_key_file_get_locale_string (keyfile, G_KEY_FILE_DESKTOP_KEY_COMMENT); if (!_gsp_str_equal (str, app->priv->comment)) { g_free (str); g_free (path); g_key_file_free (keyfile); return FALSE; } g_free (str); str = gsp_key_file_get_string (keyfile, G_KEY_FILE_DESKTOP_KEY_EXEC); if (!_gsp_str_equal (str, app->priv->exec)) { g_free (str); g_free (path); g_key_file_free (keyfile); return FALSE; } g_free (str); str = gsp_key_file_get_locale_string (keyfile, G_KEY_FILE_DESKTOP_KEY_ICON); if (!_gsp_str_equal (str, app->priv->icon)) { g_free (str); g_free (path); g_key_file_free (keyfile); return FALSE; } g_free (str); g_key_file_free (keyfile); *system_path = path; return TRUE; } static inline void _gsp_app_save_done_success (GspApp *app) { app->priv->save_mask = 0; if (app->priv->old_system_path) { g_free (app->priv->old_system_path); app->priv->old_system_path = NULL; } } static gboolean _gsp_app_save (gpointer data) { GspApp *app; char *use_path; GKeyFile *keyfile; GError *error; app = GSP_APP (data); /* first check if removing the data from the user dir and using the * data from the system dir is enough -- this helps us keep clean the * user config dir by removing unneeded files */ if (_gsp_app_user_equal_system (app, &use_path)) { if (g_file_test (app->priv->path, G_FILE_TEST_EXISTS)) { g_remove (app->priv->path); } g_free (app->priv->path); app->priv->path = use_path; app->priv->xdg_position = app->priv->xdg_system_position; _gsp_app_save_done_success (app); return FALSE; } if (app->priv->old_system_path) use_path = app->priv->old_system_path; else use_path = app->priv->path; keyfile = g_key_file_new (); error = NULL; g_key_file_load_from_file (keyfile, use_path, G_KEY_FILE_KEEP_COMMENTS|G_KEY_FILE_KEEP_TRANSLATIONS, &error); if (error) { g_error_free (error); gsp_key_file_populate (keyfile); } if (app->priv->save_mask & GSP_ASP_SAVE_MASK_HIDDEN) { gsp_key_file_set_boolean (keyfile, G_KEY_FILE_DESKTOP_KEY_HIDDEN, app->priv->hidden); } if (app->priv->save_mask & GSP_ASP_SAVE_MASK_NO_DISPLAY) { gsp_key_file_set_boolean (keyfile, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, app->priv->no_display); } if (app->priv->save_mask & GSP_ASP_SAVE_MASK_ENABLED) { gsp_key_file_set_boolean (keyfile, GSP_KEY_FILE_DESKTOP_KEY_AUTOSTART_ENABLED, app->priv->enabled); } if (app->priv->save_mask & GSP_ASP_SAVE_MASK_NAME) { gsp_key_file_set_locale_string (keyfile, G_KEY_FILE_DESKTOP_KEY_NAME, app->priv->name); gsp_key_file_ensure_C_key (keyfile, G_KEY_FILE_DESKTOP_KEY_NAME); } if (app->priv->save_mask & GSP_ASP_SAVE_MASK_COMMENT) { gsp_key_file_set_locale_string (keyfile, G_KEY_FILE_DESKTOP_KEY_COMMENT, app->priv->comment); gsp_key_file_ensure_C_key (keyfile, G_KEY_FILE_DESKTOP_KEY_COMMENT); } if (app->priv->save_mask & GSP_ASP_SAVE_MASK_EXEC) { gsp_key_file_set_string (keyfile, G_KEY_FILE_DESKTOP_KEY_EXEC, app->priv->exec); gsp_key_file_set_string (keyfile, G_KEY_FILE_DESKTOP_KEY_ICON, app->priv->icon); } _gsp_ensure_user_autostart_dir (); if (gsp_key_file_to_file (keyfile, app->priv->path, NULL)) { app->priv->skip_next_monitor_event = TRUE; _gsp_app_save_done_success (app); } else { g_warning ("Could not save %s file", app->priv->path); } g_key_file_free (keyfile); app->priv->save_timeout = 0; return FALSE; } static void _gsp_app_queue_save (GspApp *app) { if (app->priv->save_timeout) { g_source_remove (app->priv->save_timeout); app->priv->save_timeout = 0; } /* if the file was not in the user directory, then we'll create a copy * there */ if (app->priv->xdg_position != 0) { app->priv->xdg_position = 0; if (app->priv->old_system_path == NULL) { app->priv->old_system_path = app->priv->path; /* if old_system_path was not NULL, then it means we * tried to save and we failed; in that case, we want * to try again and use the old file as a basis again */ } app->priv->path = g_build_filename (g_get_user_config_dir (), "autostart", app->priv->basename, NULL); } app->priv->save_timeout = g_timeout_add_seconds (GSP_APP_SAVE_DELAY, _gsp_app_save, app); } /* * Accessors */ const char * gsp_app_get_basename (GspApp *app) { g_return_val_if_fail (GSP_IS_APP (app), NULL); return app->priv->basename; } const char * gsp_app_get_path (GspApp *app) { g_return_val_if_fail (GSP_IS_APP (app), NULL); return app->priv->path; } gboolean gsp_app_get_hidden (GspApp *app) { g_return_val_if_fail (GSP_IS_APP (app), FALSE); return app->priv->hidden; } gboolean gsp_app_get_display (GspApp *app) { g_return_val_if_fail (GSP_IS_APP (app), FALSE); return !app->priv->no_display; } gboolean gsp_app_get_enabled (GspApp *app) { g_return_val_if_fail (GSP_IS_APP (app), FALSE); return app->priv->enabled; } void gsp_app_set_enabled (GspApp *app, gboolean enabled) { g_return_if_fail (GSP_IS_APP (app)); if (enabled == app->priv->enabled) { return; } app->priv->enabled = enabled; app->priv->save_mask |= GSP_ASP_SAVE_MASK_ENABLED; _gsp_app_queue_save (app); _gsp_app_emit_changed (app); } gboolean gsp_app_get_shown (GspApp *app) { g_return_val_if_fail (GSP_IS_APP (app), FALSE); return app->priv->shown; } const char * gsp_app_get_name (GspApp *app) { g_return_val_if_fail (GSP_IS_APP (app), NULL); return app->priv->name; } const char * gsp_app_get_exec (GspApp *app) { g_return_val_if_fail (GSP_IS_APP (app), NULL); return app->priv->exec; } const char * gsp_app_get_comment (GspApp *app) { g_return_val_if_fail (GSP_IS_APP (app), NULL); return app->priv->comment; } GIcon * gsp_app_get_icon (GspApp *app) { g_return_val_if_fail (GSP_IS_APP (app), NULL); if (app->priv->gicon) { return g_object_ref (app->priv->gicon); } else { return NULL; } } const char * gsp_app_get_icon_char (GspApp *app) { g_return_val_if_fail (GSP_IS_APP (app), NULL); return app->priv->icon; } unsigned int gsp_app_get_xdg_position (GspApp *app) { g_return_val_if_fail (GSP_IS_APP (app), G_MAXUINT); return app->priv->xdg_position; } unsigned int gsp_app_get_xdg_system_position (GspApp *app) { g_return_val_if_fail (GSP_IS_APP (app), G_MAXUINT); return app->priv->xdg_system_position; } void gsp_app_set_xdg_system_position (GspApp *app, unsigned int position) { g_return_if_fail (GSP_IS_APP (app)); app->priv->xdg_system_position = position; } const char * gsp_app_get_description (GspApp *app) { g_return_val_if_fail (GSP_IS_APP (app), NULL); return app->priv->description; } /* * High-level edition */ void gsp_app_update (GspApp *app, const char *name, const char *comment, const char *exec) { gboolean changed; g_return_if_fail (GSP_IS_APP (app)); changed = FALSE; if (!_gsp_str_equal (name, app->priv->name)) { changed = TRUE; g_free (app->priv->name); app->priv->name = g_strdup (name); app->priv->save_mask |= GSP_ASP_SAVE_MASK_NAME; } if (!_gsp_str_equal (comment, app->priv->comment)) { changed = TRUE; g_free (app->priv->comment); app->priv->comment = g_strdup (comment); app->priv->save_mask |= GSP_ASP_SAVE_MASK_COMMENT; } if (changed) { _gsp_app_update_description (app); } if (!_gsp_str_equal (exec, app->priv->exec)) { changed = TRUE; g_free (app->priv->exec); app->priv->exec = g_strdup (exec); app->priv->save_mask |= GSP_ASP_SAVE_MASK_EXEC; } if (changed) { _gsp_app_queue_save (app); _gsp_app_emit_changed (app); } } void gsp_app_delete (GspApp *app) { g_return_if_fail (GSP_IS_APP (app)); if (app->priv->xdg_position == 0 && app->priv->xdg_system_position == G_MAXUINT) { /* exists in user directory only */ if (app->priv->save_timeout) { g_source_remove (app->priv->save_timeout); app->priv->save_timeout = 0; } if (g_file_test (app->priv->path, G_FILE_TEST_EXISTS)) { g_remove (app->priv->path); } /* for extra safety */ app->priv->enabled = FALSE; app->priv->hidden = TRUE; app->priv->save_mask |= GSP_ASP_SAVE_MASK_HIDDEN; app->priv->save_mask |= GSP_ASP_SAVE_MASK_ENABLED; _gsp_app_emit_removed (app); } else { /* also exists in system directory, so we have to keep a file * in the user directory */ app->priv->enabled = FALSE; app->priv->hidden = TRUE; app->priv->save_mask |= GSP_ASP_SAVE_MASK_HIDDEN; app->priv->save_mask |= GSP_ASP_SAVE_MASK_ENABLED; _gsp_app_queue_save (app); _gsp_app_emit_changed (app); } } /* * New autostart app */ void gsp_app_reload_at (GspApp *app, const char *path, unsigned int xdg_position) { g_return_if_fail (GSP_IS_APP (app)); app->priv->xdg_position = G_MAXUINT; gsp_app_new (path, xdg_position); } GspApp * gsp_app_new (const char *path, unsigned int xdg_position) { GspAppManager *manager; GspApp *app; GKeyFile *keyfile; char *basename; gboolean new; basename = g_path_get_basename (path); manager = gsp_app_manager_get (); app = gsp_app_manager_find_app_with_basename (manager, basename); g_object_unref (manager); new = (app == NULL); if (!new) { if (app->priv->xdg_position == xdg_position) { if (app->priv->skip_next_monitor_event) { app->priv->skip_next_monitor_event = FALSE; return NULL; } /* else: the file got changed but not by us, we'll * update our data from disk */ } if (app->priv->xdg_position < xdg_position || app->priv->save_timeout != 0) { /* we don't really care about this file, since we * already have something with a higher priority, or * we're going to write something in the user config * anyway. * Note: xdg_position >= 1 so it's a system dir */ app->priv->xdg_system_position = MIN (xdg_position, app->priv->xdg_system_position); return NULL; } } keyfile = g_key_file_new (); if (!g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, NULL)) { g_key_file_free (keyfile); g_free (basename); return NULL; } if (new) { app = g_object_new (GSP_TYPE_APP, NULL); app->priv->basename = basename; } else { g_free (basename); _gsp_app_free_reusable_data (app); } app->priv->path = g_strdup (path); app->priv->hidden = gsp_key_file_get_boolean (keyfile, G_KEY_FILE_DESKTOP_KEY_HIDDEN, FALSE); app->priv->no_display = gsp_key_file_get_boolean (keyfile, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, FALSE); app->priv->enabled = gsp_key_file_get_boolean (keyfile, GSP_KEY_FILE_DESKTOP_KEY_AUTOSTART_ENABLED, TRUE); app->priv->shown = gsp_key_file_get_shown (keyfile, //gsm_util_get_current_desktop ()); "UKUI"); app->priv->name = gsp_key_file_get_locale_string (keyfile, G_KEY_FILE_DESKTOP_KEY_NAME); //app->priv->exec = gsp_key_file_get_string (keyfile, // G_KEY_FILE_DESKTOP_KEY_EXEC); app->priv->exec = g_key_file_get_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL); if (strcmp(app->priv->exec, "/usr/bin/ukui-settings-daemon") == 0) return NULL; app->priv->comment = gsp_key_file_get_locale_string (keyfile, G_KEY_FILE_DESKTOP_KEY_COMMENT); if (gsm_util_text_is_blank (app->priv->name)) { g_free (app->priv->name); app->priv->name = g_strdup (app->priv->exec); } app->priv->icon = gsp_key_file_get_locale_string (keyfile, G_KEY_FILE_DESKTOP_KEY_ICON); if (app->priv->icon) { /* look at icon and see if it's a themed icon or not */ if (g_path_is_absolute (app->priv->icon)) { GFile *iconfile; iconfile = g_file_new_for_path (app->priv->icon); app->priv->gicon = g_file_icon_new (iconfile); g_object_unref (iconfile); } else { app->priv->gicon = g_themed_icon_new (app->priv->icon); } } else { app->priv->gicon = NULL; } g_key_file_free (keyfile); _gsp_app_update_description (app); if (xdg_position > 0) { g_assert (xdg_position <= app->priv->xdg_system_position); app->priv->xdg_system_position = xdg_position; } /* else we keep the old value (which is G_MAXUINT if it wasn't set) */ app->priv->xdg_position = xdg_position; g_assert (!new || app->priv->save_timeout == 0); app->priv->save_timeout = 0; app->priv->old_system_path = NULL; app->priv->skip_next_monitor_event = FALSE; if (!new) { _gsp_app_emit_changed (app); } return app; } static char * _gsp_find_free_basename (const char *suggested_basename) { GspAppManager *manager; char *base_path; char *filename; char *basename; int i; if (g_str_has_suffix (suggested_basename, ".desktop")) { char *basename_no_ext; basename_no_ext = g_strndup (suggested_basename, strlen (suggested_basename) - strlen (".desktop")); base_path = g_build_filename (g_get_user_config_dir (), "autostart", basename_no_ext, NULL); g_free (basename_no_ext); } else { base_path = g_build_filename (g_get_user_config_dir (), "autostart", suggested_basename, NULL); } filename = g_strdup_printf ("%s.desktop", base_path); basename = g_path_get_basename (filename); manager = gsp_app_manager_get (); i = 1; #define _GSP_FIND_MAX_TRY 10000 while (gsp_app_manager_find_app_with_basename (manager, basename) != NULL && g_file_test (filename, G_FILE_TEST_EXISTS) && i < _GSP_FIND_MAX_TRY) { g_free (filename); g_free (basename); filename = g_strdup_printf ("%s-%d.desktop", base_path, i); basename = g_path_get_basename (filename); i++; } g_object_unref (manager); g_free (base_path); g_free (filename); if (i == _GSP_FIND_MAX_TRY) { g_free (basename); return NULL; } return basename; } //return 8 重复创建 // // int gsp_app_create (const char *name, const char *comment, const char *exec, const char *icon) { GspAppManager *manager; GspApp *app; char *basename; char **argv; int argc; g_return_if_fail (!gsm_util_text_is_blank (exec)); if (!g_shell_parse_argv (exec, &argc, &argv, NULL)) { return 0; } basename = _gsp_find_free_basename (argv[0]); g_strfreev (argv); if (basename == NULL) { return 0 ; } app = g_object_new (GSP_TYPE_APP, NULL); app->priv->basename = basename; app->priv->path = g_build_filename (g_get_user_config_dir (), "autostart", app->priv->basename, NULL); manager = gsp_app_manager_get (); if(NULL != gsp_app_manager_find_local_app_with_name_exec(manager,name,exec,icon)) { return 8; } app->priv->hidden = FALSE; app->priv->no_display = FALSE; app->priv->enabled = TRUE; app->priv->shown = TRUE; if (!gsm_util_text_is_blank (name)) { app->priv->name = g_strdup (name); } else { app->priv->name = g_strdup (exec); } app->priv->exec = g_strdup (exec); app->priv->comment = g_strdup (comment); if(icon==NULL) { app->priv->icon = NULL; app->priv->gicon = NULL; } else{ app->priv->icon = g_strdup(icon); app->priv->gicon = g_icon_new_for_string (icon,NULL); } _gsp_app_update_description (app); /* by definition */ app->priv->xdg_position = 0; app->priv->xdg_system_position = G_MAXUINT; app->priv->save_timeout = 0; app->priv->save_mask |= GSP_ASP_SAVE_MASK_ALL; app->priv->old_system_path = NULL; app->priv->skip_next_monitor_event = FALSE; _gsp_app_queue_save (app); gsp_app_manager_add (manager, app); if(NULL!=app->priv->gicon) g_object_unref (app->priv->gicon); g_object_unref (app); g_object_unref (manager); return 0; } gboolean gsp_app_copy_desktop_file (const char *uri) { GspAppManager *manager; GspApp *app; GFile *src_file; char *src_basename; char *dst_basename; char *dst_path; GFile *dst_file; gboolean changed; g_return_val_if_fail (uri != NULL, FALSE); src_file = g_file_new_for_uri (uri); src_basename = g_file_get_basename (src_file); if (src_basename == NULL) { g_object_unref (src_file); return FALSE; } dst_basename = _gsp_find_free_basename (src_basename); g_free (src_basename); if (dst_basename == NULL) { g_object_unref (src_file); return FALSE; } dst_path = g_build_filename (g_get_user_config_dir (), "autostart", dst_basename, NULL); g_free (dst_basename); dst_file = g_file_new_for_path (dst_path); _gsp_ensure_user_autostart_dir (); if (!g_file_copy (src_file, dst_file, G_FILE_COPY_NONE, NULL, NULL, NULL, NULL)) { g_object_unref (src_file); g_object_unref (dst_file); g_free (dst_path); return FALSE; } g_object_unref (src_file); g_object_unref (dst_file); app = gsp_app_new (dst_path, 0); if (!app) { g_remove (dst_path); g_free (dst_path); return FALSE; } g_free (dst_path); changed = FALSE; if (app->priv->hidden) { changed = TRUE; app->priv->hidden = FALSE; app->priv->save_mask |= GSP_ASP_SAVE_MASK_HIDDEN; } if (app->priv->no_display) { changed = TRUE; app->priv->no_display = FALSE; app->priv->save_mask |= GSP_ASP_SAVE_MASK_NO_DISPLAY; } if (!app->priv->enabled) { changed = TRUE; app->priv->enabled = TRUE; app->priv->save_mask |= GSP_ASP_SAVE_MASK_ENABLED; } if (changed) { _gsp_app_queue_save (app); } manager = gsp_app_manager_get (); gsp_app_manager_add (manager, app); g_object_unref (app); g_object_unref (manager); return TRUE; } ukui-control-center/panels/session-properties/gsm-util.h0000664000175000017500000000354413057175444022502 0ustar fengfeng/* gsm-util.h * Copyright (C) 2008 Lucas Rocha. * * This program is free software; you can redistribute 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 * Lesser 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 St, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifndef __GSM_UTIL_H__ #define __GSM_UTIL_H__ #include #ifdef __cplusplus extern "C" { #endif char * gsm_util_find_desktop_file_for_app_name (const char *app_name, char **dirs); gchar *gsm_util_get_empty_tmp_session_dir (void); const char *gsm_util_get_saved_session_dir (void); gchar** gsm_util_get_app_dirs (void); gchar** gsm_util_get_autostart_dirs (void); gchar ** gsm_util_get_desktop_dirs (void); const char *gsm_util_get_current_desktop (void); gboolean gsm_util_text_is_blank (const char *str); void gsm_util_init_error (gboolean fatal, const char *format, ...); char * gsm_util_generate_startup_id (void); void gsm_util_setenv (const char *variable, const char *value); #ifdef __cplusplus } #endif #endif /* __GSM_UTIL_H__ */ ukui-control-center/panels/session-properties/gsp-main.c0000664000175000017500000000224713111000752022422 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "gsp-main.h" #include #include #include #include #include "gsm-properties-dialog.h" void add_gsp_app(GtkBuilder * builder) { g_debug("gsm properties dialog"); gsm_properties_dialog_new(builder); } void destroy_gsp_app(){ gsm_properties_dialog_destroy(); } ukui-control-center/panels/session-properties/eggdesktopfile.h0000664000175000017500000001600013057175444023724 0ustar fengfeng/* eggdesktopfile.h - Freedesktop.Org Desktop Files * Copyright (C) 2007 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING.LIB. If not, * write to the Free Software Foundation, Inc., 51 Franklin St - * Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __EGG_DESKTOP_FILE_H__ #define __EGG_DESKTOP_FILE_H__ #include #ifdef __cplusplus extern "C" { #endif typedef struct EggDesktopFile EggDesktopFile; typedef enum { EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED, EGG_DESKTOP_FILE_TYPE_APPLICATION, EGG_DESKTOP_FILE_TYPE_LINK, EGG_DESKTOP_FILE_TYPE_DIRECTORY } EggDesktopFileType; EggDesktopFile *egg_desktop_file_new (const char *desktop_file_path, GError **error); EggDesktopFile *egg_desktop_file_new_from_data_dirs (const char *desktop_file_path, GError **error); EggDesktopFile *egg_desktop_file_new_from_dirs (const char *desktop_file_path, const char **search_dirs, GError **error); EggDesktopFile *egg_desktop_file_new_from_key_file (GKeyFile *key_file, const char *source, GError **error); void egg_desktop_file_free (EggDesktopFile *desktop_file); const char *egg_desktop_file_get_source (EggDesktopFile *desktop_file); EggDesktopFileType egg_desktop_file_get_desktop_file_type (EggDesktopFile *desktop_file); const char *egg_desktop_file_get_name (EggDesktopFile *desktop_file); const char *egg_desktop_file_get_icon (EggDesktopFile *desktop_file); gboolean egg_desktop_file_can_launch (EggDesktopFile *desktop_file, const char *desktop_environment); gboolean egg_desktop_file_accepts_documents (EggDesktopFile *desktop_file); gboolean egg_desktop_file_accepts_multiple (EggDesktopFile *desktop_file); gboolean egg_desktop_file_accepts_uris (EggDesktopFile *desktop_file); char *egg_desktop_file_parse_exec (EggDesktopFile *desktop_file, GSList *documents, GError **error); gboolean egg_desktop_file_launch (EggDesktopFile *desktop_file, GSList *documents, GError **error, ...) G_GNUC_NULL_TERMINATED; typedef enum { EGG_DESKTOP_FILE_LAUNCH_CLEARENV = 1, EGG_DESKTOP_FILE_LAUNCH_PUTENV, EGG_DESKTOP_FILE_LAUNCH_SCREEN, EGG_DESKTOP_FILE_LAUNCH_WORKSPACE, EGG_DESKTOP_FILE_LAUNCH_DIRECTORY, EGG_DESKTOP_FILE_LAUNCH_TIME, EGG_DESKTOP_FILE_LAUNCH_FLAGS, EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC, EGG_DESKTOP_FILE_LAUNCH_RETURN_PID, EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE, EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE, EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE, EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID } EggDesktopFileLaunchOption; /* Standard Keys */ #define EGG_DESKTOP_FILE_GROUP "Desktop Entry" #define EGG_DESKTOP_FILE_KEY_TYPE "Type" #define EGG_DESKTOP_FILE_KEY_VERSION "Version" #define EGG_DESKTOP_FILE_KEY_NAME "Name" #define EGG_DESKTOP_FILE_KEY_GENERIC_NAME "GenericName" #define EGG_DESKTOP_FILE_KEY_NO_DISPLAY "NoDisplay" #define EGG_DESKTOP_FILE_KEY_COMMENT "Comment" #define EGG_DESKTOP_FILE_KEY_ICON "Icon" #define EGG_DESKTOP_FILE_KEY_HIDDEN "Hidden" #define EGG_DESKTOP_FILE_KEY_ONLY_SHOW_IN "OnlyShowIn" #define EGG_DESKTOP_FILE_KEY_NOT_SHOW_IN "NotShowIn" #define EGG_DESKTOP_FILE_KEY_TRY_EXEC "TryExec" #define EGG_DESKTOP_FILE_KEY_EXEC "Exec" #define EGG_DESKTOP_FILE_KEY_PATH "Path" #define EGG_DESKTOP_FILE_KEY_TERMINAL "Terminal" #define EGG_DESKTOP_FILE_KEY_MIME_TYPE "MimeType" #define EGG_DESKTOP_FILE_KEY_CATEGORIES "Categories" #define EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY "StartupNotify" #define EGG_DESKTOP_FILE_KEY_STARTUP_WM_CLASS "StartupWMClass" #define EGG_DESKTOP_FILE_KEY_URL "URL" /* Accessors */ gboolean egg_desktop_file_has_key (EggDesktopFile *desktop_file, const char *key, GError **error); char *egg_desktop_file_get_string (EggDesktopFile *desktop_file, const char *key, GError **error) G_GNUC_MALLOC; char *egg_desktop_file_get_locale_string (EggDesktopFile *desktop_file, const char *key, const char *locale, GError **error) G_GNUC_MALLOC; gboolean egg_desktop_file_get_boolean (EggDesktopFile *desktop_file, const char *key, GError **error); double egg_desktop_file_get_numeric (EggDesktopFile *desktop_file, const char *key, GError **error); int egg_desktop_file_get_integer (EggDesktopFile *desktop_file, const char *key, GError **error); char **egg_desktop_file_get_string_list (EggDesktopFile *desktop_file, const char *key, gsize *length, GError **error) G_GNUC_MALLOC; char **egg_desktop_file_get_locale_string_list (EggDesktopFile *desktop_file, const char *key, const char *locale, gsize *length, GError **error) G_GNUC_MALLOC; /* Errors */ #define EGG_DESKTOP_FILE_ERROR egg_desktop_file_error_quark() GQuark egg_desktop_file_error_quark (void); typedef enum { EGG_DESKTOP_FILE_ERROR_INVALID, EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION } EggDesktopFileError; /* Global application desktop file */ void egg_set_desktop_file (const char *desktop_file_path); void egg_set_desktop_file_without_defaults (const char *desktop_file_path); EggDesktopFile *egg_get_desktop_file (void); #ifdef __cplusplus } #endif #endif /* __EGG_DESKTOP_FILE_H__ */ ukui-control-center/panels/session-properties/gsp-app-manager.h0000664000175000017500000000466213057175444023722 0ustar fengfeng#ifndef __GSP_APP_MANAGER_H #define __GSP_APP_MANAGER_H #include #include #ifdef __cplusplus extern "C" { #endif #define GSP_TYPE_APP_MANAGER (gsp_app_manager_get_type ()) #define GSP_APP_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSP_TYPE_APP_MANAGER, GspAppManager)) #define GSP_APP_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSP_TYPE_APP_MANAGER, GspAppManagerClass)) #define GSP_IS_APP_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSP_TYPE_APP_MANAGER)) #define GSP_IS_APP_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSP_TYPE_APP_MANAGER)) #define GSP_APP_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSP_TYPE_APP_MANAGER, GspAppManagerClass)) typedef struct _GspAppManager GspAppManager; typedef struct _GspAppManagerClass GspAppManagerClass; typedef struct _GspAppManagerPrivate GspAppManagerPrivate; struct _GspAppManagerClass { GObjectClass parent_class; void (* added) (GspAppManager *manager, GspApp *app); void (* removed) (GspAppManager *manager, GspApp *app); }; struct _GspAppManager { GObject parent_instance; GspAppManagerPrivate *priv; }; GType gsp_app_manager_get_type (void); GspAppManager *gsp_app_manager_get (void); void gsp_app_manager_fill (GspAppManager *manager); GSList *gsp_app_manager_get_apps (GspAppManager *manager); GspApp *gsp_app_manager_find_app_with_basename (GspAppManager *manager, const char *basename); GspApp *gsp_app_manager_find_app_with_name (GspAppManager *manager, const char *name); GspApp *gsp_app_manager_find_local_app_with_name_exec(GspAppManager *manager, const char *name, const char *exec,const char *icon); const char *gsp_app_manager_get_dir (GspAppManager *manager, unsigned int index); void gsp_app_manager_add (GspAppManager *manager, GspApp *app); #ifdef __cplusplus } #endif #endif /* __GSP_APP_MANAGER_H */ ukui-control-center/panels/session-properties/gsm-properties-dialog.h0000664000175000017500000000256113057175444025154 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef __GSM_PROPERTIES_DIALOG_H #define __GSM_PROPERTIES_DIALOG_H #include #include typedef struct GsmPropertiesDialogPrivate GsmPropertiesDialogPrivate; typedef struct { GtkViewport parent; GsmPropertiesDialogPrivate *priv; } GsmPropertiesDialog; void gsm_properties_dialog_new (GtkBuilder * builder); void gsm_properties_dialog_destroy(); #define GSM_PROPERTIES_ICON_SIZE GTK_ICON_SIZE_LARGE_TOOLBAR #endif /* __GSM_PROPERTIES_DIALOG_H */ ukui-control-center/panels/session-properties/gsp-keyfile.c0000664000175000017500000001413013057175444023144 0ustar fengfeng/* * gsp-keyfile.c: GKeyFile extensions * * Copyright (C) 2008, 2009 Novell, Inc. * * Based on code from panel-keyfile.c (from gnome-panel) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Authors: * Vincent Untz */ #include #include #include "gsp-keyfile.h" void gsp_key_file_populate (GKeyFile *keyfile) { gsp_key_file_set_string (keyfile, G_KEY_FILE_DESKTOP_KEY_TYPE, "Application"); gsp_key_file_set_string (keyfile, G_KEY_FILE_DESKTOP_KEY_EXEC, "/bin/false"); } //FIXME: kill this when bug #309224 is fixed gboolean gsp_key_file_to_file (GKeyFile *keyfile, const gchar *path, GError **error) { GError *write_error; gchar *data; gsize length; gboolean res; g_return_val_if_fail (keyfile != NULL, FALSE); g_return_val_if_fail (path != NULL, FALSE); write_error = NULL; data = g_key_file_to_data (keyfile, &length, &write_error); if (write_error) { g_propagate_error (error, write_error); return FALSE; } res = g_file_set_contents (path, data, length, &write_error); g_free (data); if (write_error) { g_propagate_error (error, write_error); return FALSE; } return res; } gboolean gsp_key_file_get_boolean (GKeyFile *keyfile, const gchar *key, gboolean default_value) { GError *error; gboolean retval; error = NULL; retval = g_key_file_get_boolean (keyfile, G_KEY_FILE_DESKTOP_GROUP, key, &error); if (error != NULL) { retval = default_value; g_error_free (error); } return retval; } gboolean gsp_key_file_get_shown (GKeyFile *keyfile, const char *current_desktop) { char **only_show_in, **not_show_in; gboolean found; int i; if (!current_desktop) return TRUE; only_show_in = g_key_file_get_string_list (keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN, NULL, NULL); if (only_show_in) { found = FALSE; for (i = 0; only_show_in[i] != NULL; i++) { if (g_strcmp0 (current_desktop, only_show_in[i]) == 0) { found = TRUE; break; } } g_strfreev (only_show_in); if (!found) return FALSE; } not_show_in = g_key_file_get_string_list (keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN, NULL, NULL); if (not_show_in) { found = FALSE; for (i = 0; not_show_in[i] != NULL; i++) { if (g_strcmp0 (current_desktop, not_show_in[i]) == 0) { found = TRUE; break; } } g_strfreev (not_show_in); if (found) return FALSE; } return TRUE; } void gsp_key_file_set_locale_string (GKeyFile *keyfile, const gchar *key, const gchar *value) { const char *locale; const char * const *langs_pointer; int i; if (value == NULL) { value = ""; } locale = NULL; langs_pointer = g_get_language_names (); for (i = 0; langs_pointer[i] != NULL; i++) { /* find first without encoding */ if (strchr (langs_pointer[i], '.') == NULL) { locale = langs_pointer[i]; break; } } if (locale != NULL) { g_key_file_set_locale_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, key, locale, value); } else { g_key_file_set_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, key, value); } } void gsp_key_file_ensure_C_key (GKeyFile *keyfile, const char *key) { char *C_value; char *buffer; /* Make sure we set the "C" locale strings to the terms we set here. * This is so that if the user logs into another locale they get their * own description there rather then empty. It is not the C locale * however, but the user created this entry herself so it's OK */ C_value = gsp_key_file_get_string (keyfile, key); if (C_value == NULL || C_value [0] == '\0') { buffer = gsp_key_file_get_locale_string (keyfile, key); if (buffer) { gsp_key_file_set_string (keyfile, key, buffer); g_free (buffer); } } g_free (C_value); } ukui-control-center/panels/session-properties/gsm-util.c0000664000175000017500000003753713253611037022475 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * gsm-util.c * Copyright (C) 2008 Lucas Rocha. * * This program is free software; you can redistribute 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 * Lesser 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 St, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gsm-util.h" static gchar *_saved_session_dir = NULL; char * gsm_util_find_desktop_file_for_app_name (const char *name, char **autostart_dirs) { char *app_path; char **app_dirs; GKeyFile *key_file; char *desktop_file; int i; app_path = NULL; app_dirs = gsm_util_get_app_dirs (); key_file = g_key_file_new (); desktop_file = g_strdup_printf ("%s.desktop", name); g_debug ("GsmUtil: Looking for file '%s'", desktop_file); for (i = 0; app_dirs[i] != NULL; i++) { g_debug ("GsmUtil: Looking in '%s'", app_dirs[i]); } g_key_file_load_from_dirs (key_file, desktop_file, (const char **) app_dirs, &app_path, G_KEY_FILE_NONE, NULL); if (app_path != NULL) { g_debug ("GsmUtil: found in XDG app dirs: '%s'", app_path); } if (app_path == NULL && autostart_dirs != NULL) { g_key_file_load_from_dirs (key_file, desktop_file, (const char **) autostart_dirs, &app_path, G_KEY_FILE_NONE, NULL); if (app_path != NULL) { g_debug ("GsmUtil: found in autostart dirs: '%s'", app_path); } } /* look for ukui vender prefix */ if (app_path == NULL) { g_free (desktop_file); desktop_file = g_strdup_printf ("ukui-%s.desktop", name); g_key_file_load_from_dirs (key_file, desktop_file, (const char **) app_dirs, &app_path, G_KEY_FILE_NONE, NULL); if (app_path != NULL) { g_debug ("GsmUtil: found in XDG app dirs: '%s'", app_path); } } if (app_path == NULL && autostart_dirs != NULL) { g_key_file_load_from_dirs (key_file, desktop_file, (const char **) autostart_dirs, &app_path, G_KEY_FILE_NONE, NULL); if (app_path != NULL) { g_debug ("GsmUtil: found in autostart dirs: '%s'", app_path); } } g_free (desktop_file); g_key_file_free (key_file); g_strfreev (app_dirs); return app_path; } static gboolean ensure_dir_exists (const char *dir) { if (g_file_test (dir, G_FILE_TEST_IS_DIR)) return TRUE; if (g_mkdir_with_parents (dir, 0755) == 0) return TRUE; if (errno == EEXIST) return g_file_test (dir, G_FILE_TEST_IS_DIR); g_warning ("GsmSessionSave: Failed to create directory %s: %s", dir, strerror (errno)); return FALSE; } gchar * gsm_util_get_empty_tmp_session_dir (void) { char *tmp; gboolean exists; tmp = g_build_filename (g_get_user_config_dir (), "ukui-session", "saved-session.new", NULL); exists = ensure_dir_exists (tmp); if (G_UNLIKELY (!exists)) { g_warning ("GsmSessionSave: could not create directory for saved session: %s", tmp); g_free (tmp); return NULL; } else { /* make sure it's empty */ GDir *dir; const char *filename; dir = g_dir_open (tmp, 0, NULL); if (dir) { while ((filename = g_dir_read_name (dir))) { char *path = g_build_filename (tmp, filename, NULL); g_unlink (path); } g_dir_close (dir); } } return tmp; } const gchar * gsm_util_get_saved_session_dir (void) { if (_saved_session_dir == NULL) { gboolean exists; _saved_session_dir = g_build_filename (g_get_user_config_dir (), "ukui-session", "saved-session", NULL); exists = ensure_dir_exists (_saved_session_dir); if (G_UNLIKELY (!exists)) { static gboolean printed_warning = FALSE; if (!printed_warning) { g_warning ("GsmSessionSave: could not create directory for saved session: %s", _saved_session_dir); printed_warning = TRUE; } _saved_session_dir = NULL; return NULL; } } return _saved_session_dir; } char ** gsm_util_get_autostart_dirs () { GPtrArray *dirs; const char * const *system_config_dirs; const char * const *system_data_dirs; int i; dirs = g_ptr_array_new (); g_ptr_array_add (dirs,g_build_filename (g_get_user_config_dir (), "autostart", NULL)); /* system_data_dirs = g_get_system_data_dirs (); for (i = 0; system_data_dirs[i]; i++) { g_ptr_array_add (dirs, g_build_filename (system_data_dirs[i], "ukui", "autostart", NULL)); }*/ system_config_dirs = g_get_system_config_dirs (); for (i = 0; system_config_dirs[i]; i++) { g_ptr_array_add (dirs,g_build_filename (system_config_dirs[i], "autostart", NULL)); } g_ptr_array_add (dirs, NULL); return (char **) g_ptr_array_free (dirs, FALSE); } char ** gsm_util_get_app_dirs () { GPtrArray *dirs; const char * const *system_data_dirs; int i; dirs = g_ptr_array_new (); g_ptr_array_add (dirs, g_build_filename (g_get_user_data_dir (), "applications", NULL)); system_data_dirs = g_get_system_data_dirs (); for (i = 0; system_data_dirs[i]; i++) { g_ptr_array_add (dirs, g_build_filename (system_data_dirs[i], "applications", NULL)); } g_ptr_array_add (dirs, NULL); return (char **) g_ptr_array_free (dirs, FALSE); } char ** gsm_util_get_desktop_dirs () { char **apps; char **autostart; char **result; int size; int i; apps = gsm_util_get_app_dirs (); autostart = gsm_util_get_autostart_dirs (); size = 0; for (i = 0; apps[i] != NULL; i++) { size++; } for (i = 0; autostart[i] != NULL; i++) { size++; } size += 2; /* saved session + last NULL */ result = g_new (char *, size + 1); for (i = 0; apps[i] != NULL; i++) { result[i] = apps[i]; } g_free (apps); size = i; for (i = 0; autostart[i] != NULL; i++) { result[size + i] = autostart[i]; } g_free (autostart); size = size + i; result[size] = g_strdup (gsm_util_get_saved_session_dir ()); result[size + 1] = NULL; return result; } const char * gsm_util_get_current_desktop () { static char *current_desktop = NULL; if (!current_desktop) { const char *desktop; desktop = g_getenv ("XDG_CURRENT_DESKTOP"); if (!desktop || desktop[0] == '\0') current_desktop = g_strdup ("GNOME"); else current_desktop = g_strdup (desktop); } if (g_strcmp0 (current_desktop, "*") == 0) return NULL; return current_desktop; } gboolean gsm_util_text_is_blank (const char *str) { if (str == NULL) { return TRUE; } while (*str) { if (!isspace(*str)) { return FALSE; } str++; } return TRUE; } /** * gsm_util_init_error: * @fatal: whether or not the error is fatal to the login session * @format: printf-style error message format * @...: error message args * * Displays the error message to the user. If @fatal is %TRUE, gsm * will exit after displaying the message. * * This should be called for major errors that occur before the * session is up and running. (Notably, it positions the dialog box * itself, since no window manager will be running yet.) **/ void gsm_util_init_error (gboolean fatal, const char *format, ...) { GtkWidget *dialog; char *msg; va_list args; va_start (args, format); msg = g_strdup_vprintf (format, args); va_end (args); /* If option parsing failed, Gtk won't have been initialized... */ if (!gdk_display_get_default ()) { if (!gtk_init_check (NULL, NULL)) { /* Oh well, no X for you! */ g_printerr ("Unable to start login session (and unable to connect to the X server)"); g_printerr ("%s", msg); exit (1); } } dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", msg); g_free (msg); gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER); gtk_widget_set_name(GTK_WIDGET(dialog), "ukuicc"); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); if (fatal) { gtk_main_quit (); } } /** * gsm_util_generate_startup_id: * * Generates a new SM client ID. * * Return value: an SM client ID. **/ char * gsm_util_generate_startup_id (void) { static int sequence = -1; static guint rand1 = 0; static guint rand2 = 0; static pid_t pid = 0; struct timeval tv; /* The XSMP spec defines the ID as: * * Version: "1" * Address type and address: * "1" + an IPv4 address as 8 hex digits * "2" + a DECNET address as 12 hex digits * "6" + an IPv6 address as 32 hex digits * Time stamp: milliseconds since UNIX epoch as 13 decimal digits * Process-ID type and process-ID: * "1" + POSIX PID as 10 decimal digits * Sequence number as 4 decimal digits * * XSMP client IDs are supposed to be globally unique: if * SmsGenerateClientID() is unable to determine a network * address for the machine, it gives up and returns %NULL. * UKUI and KDE have traditionally used a fourth address * format in this case: * "0" + 16 random hex digits * * We don't even bother trying SmsGenerateClientID(), since the * user's IP address is probably "192.168.1.*" anyway, so a random * number is actually more likely to be globally unique. */ if (!rand1) { rand1 = g_random_int (); rand2 = g_random_int (); pid = getpid (); } sequence = (sequence + 1) % 10000; gettimeofday (&tv, NULL); return g_strdup_printf ("10%.04x%.04x%.10lu%.3u%.10lu%.4d", rand1, rand2, (unsigned long) tv.tv_sec, (unsigned) tv.tv_usec, (unsigned long) pid, sequence); } static gboolean gsm_util_update_activation_environment (const char *variable, const char *value, GError **error) { DBusGConnection *dbus_connection; DBusGProxy *bus_proxy; GHashTable *environment; gboolean environment_updated; environment_updated = FALSE; bus_proxy = NULL; environment = NULL; dbus_connection = dbus_g_bus_get (DBUS_BUS_SESSION, error); if (dbus_connection == NULL) { return FALSE; } bus_proxy = dbus_g_proxy_new_for_name_owner (dbus_connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, error); if (bus_proxy == NULL) { goto out; } environment = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (environment, (void *) variable, (void *) value); if (!dbus_g_proxy_call (bus_proxy, "UpdateActivationEnvironment", error, DBUS_TYPE_G_STRING_STRING_HASHTABLE, environment, G_TYPE_INVALID, G_TYPE_INVALID)) goto out; environment_updated = TRUE; out: if (bus_proxy != NULL) { g_object_unref (bus_proxy); } if (environment != NULL) { g_hash_table_destroy (environment); } return environment_updated; } void gsm_util_setenv (const char *variable, const char *value) { GError *bus_error; g_setenv (variable, value, TRUE); bus_error = NULL; /* If this fails it isn't fatal, it means some things like session * management and keyring won't work in activated clients. */ if (!gsm_util_update_activation_environment (variable, value, &bus_error)) { g_warning ("Could not make bus activated clients aware of %s=%s environment variable: %s", variable, value, bus_error->message); g_error_free (bus_error); } } ukui-control-center/panels/session-properties/gsm-app-dialog.c0000664000175000017500000005127713253611037023532 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "config.h" #include #include #include #include #include "gsm-util.h" #include #include "gsm-app-dialog.h" #define GTKBUILDER_FILE "session-properties.ui" #define CAPPLET_NAME_ENTRY_WIDGET_NAME "session_properties_name_entry" #define CAPPLET_COMMAND_ENTRY_WIDGET_NAME "session_properties_command_entry" #define CAPPLET_COMMENT_ENTRY_WIDGET_NAME "session_properties_comment_entry" #define CAPPLET_BROWSE_WIDGET_NAME "session_properties_browse_button" #define GSM_APP_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_APP_DIALOG, GsmAppDialogPrivate)) struct GsmAppDialogPrivate { GtkWidget *name_entry; GtkWidget *command_entry; GtkWidget *comment_entry; GtkWidget *browse_button; char *name; char *command; char *comment; char *icon; }; static void gsm_app_dialog_class_init (GsmAppDialogClass *klass); static void gsm_app_dialog_init (GsmAppDialog *app_dialog); static void gsm_app_dialog_finalize (GObject *object); enum { PROP_0, PROP_NAME, PROP_COMMAND, PROP_COMMENT }; G_DEFINE_TYPE (GsmAppDialog, gsm_app_dialog, GTK_TYPE_DIALOG) static char * make_exec_uri (const char *exec) { GString *str; const char *c; if (exec == NULL) { return g_strdup (""); } if (strchr (exec, ' ') == NULL) { return g_strdup (exec); } str = g_string_new_len (NULL, strlen (exec)); str = g_string_append_c (str, '"'); for (c = exec; *c != '\0'; c++) { /* FIXME: GKeyFile will add an additional backslach so we'll * end up with toto\\" instead of toto\" * We could use g_key_file_set_value(), but then we don't * benefit from the other escaping that glib is doing... */ if (*c == '"') { str = g_string_append (str, "\\\""); } else { str = g_string_append_c (str, *c); } } str = g_string_append_c (str, '"'); return g_string_free (str, FALSE); } static void get_desktop_file_info(GsmAppDialog *dialog, const char * filename){ GDesktopAppInfo * app_info; char * name; char * description; char * commandline; char * icon; //analysis desktop file,we use GDesktopAppInfo, and then translates to G_APP_INFO,because //GDesktopAppInfo get description is not locale string,g_app_info* use g_key_file* to get string in desktop //we can read the code in glib--gio app_info = g_desktop_app_info_new_from_filename(filename); name = g_app_info_get_name(G_APP_INFO(app_info)); description = g_app_info_get_description(G_APP_INFO(app_info)); commandline = g_app_info_get_commandline(G_APP_INFO(app_info)); icon = g_app_info_get_icon(app_info); if(icon) dialog->priv->icon = g_icon_to_string(icon); else dialog->priv->icon = NULL; gtk_entry_set_text(GTK_ENTRY(dialog->priv->name_entry), name); gtk_entry_set_text(GTK_ENTRY(dialog->priv->comment_entry), description); gtk_entry_set_text(GTK_ENTRY(dialog->priv->command_entry), commandline); g_object_unref(app_info); } static void on_browse_button_clicked (GtkWidget *widget, GsmAppDialog *dialog) { GtkWidget *chooser; int response; GtkFileFilter *filter; chooser = gtk_file_chooser_dialog_new ("", GTK_WINDOW (dialog), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); //gtk_window_set_transient_for (GTK_WINDOW (chooser), // GTK_WINDOW (dialog)); gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser),"/etc/xdg/autostart"); filter = gtk_file_filter_new(); gtk_file_filter_set_name(filter,_("Desktop file(*.desktop)")); gtk_file_filter_add_pattern(filter, "*.desktop"); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser),filter); gtk_window_set_destroy_with_parent (GTK_WINDOW (chooser), TRUE); gtk_widget_set_name(GTK_WIDGET(chooser), "ukuicc"); gtk_window_set_title (GTK_WINDOW (chooser), _("Select command")); gtk_widget_show (chooser); response = gtk_dialog_run (GTK_DIALOG (chooser)); if (response == GTK_RESPONSE_ACCEPT) { char *text; char *uri; text = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser)); get_desktop_file_info(dialog,text); uri = make_exec_uri (text); g_free (text); //gtk_entry_set_text (GTK_ENTRY (dialog->priv->command_entry), uri); g_free (uri); } gtk_widget_destroy (chooser); } static void on_entry_activate (GtkEntry *entry, GsmAppDialog *dialog) { gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); } static void setup_dialog (GsmAppDialog *dialog) { GtkWidget *content_area; GtkWidget *widget; GtkBuilder *xml; GError *error; xml = gtk_builder_new (); error = NULL; if (!gtk_builder_add_from_file (xml, UIDIR "/main-table.ui", &error)) { if (error) { g_warning ("Could not load capplet UI file: %s", error->message); g_error_free (error); } else { g_warning ("Could not load capplet UI file."); } if (gtk_builder_add_from_file(xml, "../panels/session-properties", NULL)==0){ g_warning("Can not load ui file in system"); } } gtk_window_set_skip_taskbar_hint(GTK_WINDOW(dialog), TRUE); content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); widget = GTK_WIDGET (gtk_builder_get_object (xml, "main-table")); gtk_container_add (GTK_CONTAINER (content_area), widget); gtk_container_set_border_width (GTK_CONTAINER (dialog), 0); gtk_window_set_icon_name (GTK_WINDOW (dialog), "ukui-session-properties"); g_object_set (dialog, "allow-shrink", FALSE, "allow-grow", FALSE, NULL); gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); dialog->priv->name_entry = GTK_WIDGET (gtk_builder_get_object (xml, CAPPLET_NAME_ENTRY_WIDGET_NAME)); g_signal_connect (dialog->priv->name_entry, "activate", G_CALLBACK (on_entry_activate), dialog); if (dialog->priv->name != NULL) { gtk_entry_set_text (GTK_ENTRY (dialog->priv->name_entry), dialog->priv->name); } dialog->priv->browse_button = GTK_WIDGET (gtk_builder_get_object (xml, CAPPLET_BROWSE_WIDGET_NAME)); g_signal_connect (dialog->priv->browse_button, "clicked", G_CALLBACK (on_browse_button_clicked), dialog); dialog->priv->command_entry = GTK_WIDGET (gtk_builder_get_object (xml, CAPPLET_COMMAND_ENTRY_WIDGET_NAME)); g_signal_connect (dialog->priv->command_entry, "activate", G_CALLBACK (on_entry_activate), dialog); if (dialog->priv->command != NULL) { gtk_entry_set_text (GTK_ENTRY (dialog->priv->command_entry), dialog->priv->command); } dialog->priv->comment_entry = GTK_WIDGET (gtk_builder_get_object (xml, CAPPLET_COMMENT_ENTRY_WIDGET_NAME)); g_signal_connect (dialog->priv->comment_entry, "activate", G_CALLBACK (on_entry_activate), dialog); if (dialog->priv->comment != NULL) { gtk_entry_set_text (GTK_ENTRY (dialog->priv->comment_entry), dialog->priv->comment); } if (dialog->priv->name == NULL && dialog->priv->command == NULL && dialog->priv->comment == NULL) { gtk_window_set_title (GTK_WINDOW (dialog), _("Add programs")); gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_ADD, GTK_RESPONSE_OK); } else { gtk_window_set_title (GTK_WINDOW (dialog), _("Boot program property details")); gtk_editable_set_editable(GTK_EDITABLE(dialog->priv->command_entry), FALSE); gtk_editable_set_editable(GTK_EDITABLE(dialog->priv->name_entry), FALSE); gtk_editable_set_editable(GTK_EDITABLE(dialog->priv->comment_entry), FALSE); gtk_widget_set_sensitive(dialog->priv->browse_button, FALSE); //gtk_dialog_add_button (GTK_DIALOG (dialog), // GTK_STOCK_SAVE, GTK_RESPONSE_OK); } if (xml != NULL) { g_object_unref (xml); } } static GObject * gsm_app_dialog_constructor (GType type, guint n_construct_app, GObjectConstructParam *construct_app) { GsmAppDialog *dialog; dialog = GSM_APP_DIALOG (G_OBJECT_CLASS (gsm_app_dialog_parent_class)->constructor (type, n_construct_app, construct_app)); setup_dialog (dialog); gtk_widget_show_all (GTK_WIDGET (dialog)); return G_OBJECT (dialog); } static void gsm_app_dialog_dispose (GObject *object) { GsmAppDialog *dialog; g_return_if_fail (object != NULL); g_return_if_fail (GSM_IS_APP_DIALOG (object)); dialog = GSM_APP_DIALOG (object); g_free (dialog->priv->name); dialog->priv->name = NULL; g_free (dialog->priv->command); dialog->priv->command = NULL; g_free (dialog->priv->comment); dialog->priv->comment = NULL; G_OBJECT_CLASS (gsm_app_dialog_parent_class)->dispose (object); } static void gsm_app_dialog_set_name (GsmAppDialog *dialog, const char *name) { g_return_if_fail (GSM_IS_APP_DIALOG (dialog)); g_free (dialog->priv->name); dialog->priv->name = g_strdup (name); g_object_notify (G_OBJECT (dialog), "name"); } static void gsm_app_dialog_set_command (GsmAppDialog *dialog, const char *name) { g_return_if_fail (GSM_IS_APP_DIALOG (dialog)); g_free (dialog->priv->command); dialog->priv->command = g_strdup (name); g_object_notify (G_OBJECT (dialog), "command"); } static void gsm_app_dialog_set_comment (GsmAppDialog *dialog, const char *name) { g_return_if_fail (GSM_IS_APP_DIALOG (dialog)); g_free (dialog->priv->comment); dialog->priv->comment = g_strdup (name); g_object_notify (G_OBJECT (dialog), "comment"); } const char * gsm_app_dialog_get_name (GsmAppDialog *dialog) { g_return_val_if_fail (GSM_IS_APP_DIALOG (dialog), NULL); return gtk_entry_get_text (GTK_ENTRY (dialog->priv->name_entry)); } const char * gsm_app_dialog_get_command (GsmAppDialog *dialog) { g_return_val_if_fail (GSM_IS_APP_DIALOG (dialog), NULL); return gtk_entry_get_text (GTK_ENTRY (dialog->priv->command_entry)); } const char * gsm_app_dialog_get_comment (GsmAppDialog *dialog) { g_return_val_if_fail (GSM_IS_APP_DIALOG (dialog), NULL); return gtk_entry_get_text (GTK_ENTRY (dialog->priv->comment_entry)); } static void gsm_app_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GsmAppDialog *dialog = GSM_APP_DIALOG (object); switch (prop_id) { case PROP_NAME: gsm_app_dialog_set_name (dialog, g_value_get_string (value)); break; case PROP_COMMAND: gsm_app_dialog_set_command (dialog, g_value_get_string (value)); break; case PROP_COMMENT: gsm_app_dialog_set_comment (dialog, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gsm_app_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GsmAppDialog *dialog = GSM_APP_DIALOG (object); switch (prop_id) { case PROP_NAME: g_value_set_string (value, dialog->priv->name); break; case PROP_COMMAND: g_value_set_string (value, dialog->priv->command); break; case PROP_COMMENT: g_value_set_string (value, dialog->priv->comment); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gsm_app_dialog_class_init (GsmAppDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = gsm_app_dialog_get_property; object_class->set_property = gsm_app_dialog_set_property; object_class->constructor = gsm_app_dialog_constructor; object_class->dispose = gsm_app_dialog_dispose; object_class->finalize = gsm_app_dialog_finalize; g_object_class_install_property (object_class, PROP_NAME, g_param_spec_string ("name", "name", "name", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_COMMAND, g_param_spec_string ("command", "command", "command", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_COMMENT, g_param_spec_string ("comment", "comment", "comment", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_type_class_add_private (klass, sizeof (GsmAppDialogPrivate)); } static void gsm_app_dialog_init (GsmAppDialog *dialog) { dialog->priv = GSM_APP_DIALOG_GET_PRIVATE (dialog); } static void gsm_app_dialog_finalize (GObject *object) { GsmAppDialog *dialog; g_return_if_fail (object != NULL); g_return_if_fail (GSM_IS_APP_DIALOG (object)); dialog = GSM_APP_DIALOG (object); g_return_if_fail (dialog->priv != NULL); G_OBJECT_CLASS (gsm_app_dialog_parent_class)->finalize (object); } GtkWidget * gsm_app_dialog_new (const char *name, const char *command, const char *comment) { GObject *object; object = g_object_new (GSM_TYPE_APP_DIALOG, "name", name, "command", command, "comment", comment, NULL); return GTK_WIDGET (object); } gboolean gsm_app_dialog_run (GsmAppDialog *dialog, char **name_p, char **command_p, char **comment_p, char **icon_p) { gboolean retval; retval = FALSE; gtk_widget_set_name(GTK_WIDGET(dialog), "ukuicc"); while (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { const char *name; const char *exec; const char *comment; const char *error_msg; GError *error; char **argv; int argc; name = gsm_app_dialog_get_name (GSM_APP_DIALOG (dialog)); exec = gsm_app_dialog_get_command (GSM_APP_DIALOG (dialog)); comment = gsm_app_dialog_get_comment (GSM_APP_DIALOG (dialog)); if(icon_p) { if(dialog->priv->icon!=NULL) *icon_p = g_strdup (dialog->priv->icon); else *icon_p = g_strdup ("system-run"); } error = NULL; error_msg = NULL; if (gsm_util_text_is_blank (exec)) { error_msg = _("The startup command cannot be empty"); } else { if (!g_shell_parse_argv (exec, &argc, &argv, &error)) { if (error != NULL) { error_msg = error->message; } else { error_msg = _("The startup command is not valid"); } } } if (error_msg != NULL) { GtkWidget *msgbox; msgbox = gtk_message_dialog_new (GTK_WINDOW (dialog), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", error_msg); if (error != NULL) { g_error_free (error); } gtk_widget_set_name(GTK_WIDGET(msgbox), "ukuicc"); gtk_dialog_run (GTK_DIALOG (msgbox)); gtk_widget_destroy (msgbox); continue; } if (gsm_util_text_is_blank (name)) { name = argv[0]; } if (name_p) { *name_p = g_strdup (name); } g_strfreev (argv); if (command_p) { *command_p = g_strdup (exec); } if (comment_p) { *comment_p = g_strdup (comment); } retval = TRUE; break; } gtk_widget_destroy (GTK_WIDGET (dialog)); return retval; } ukui-control-center/panels/session-properties/gsp-main.h0000664000175000017500000000167513057175444022457 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include void add_gsp_app(GtkBuilder * builder); void destroy_gsp_app(); ukui-control-center/panels/session-properties/gsp-keyfile.h0000664000175000017500000000500613253611037023142 0ustar fengfeng/* * gsp-keyfile.h: GKeyFile extensions * * Copyright (C) 2008, 2009 Novell, Inc. * * Based on code from panel-keyfile.h (from gnome-panel) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Authors: * Vincent Untz */ #ifndef GSP_KEYFILE_H #define GSP_KEYFILE_H #include "glib.h" G_BEGIN_DECLS #define GSP_KEY_FILE_DESKTOP_KEY_AUTOSTART_ENABLED "X-UKUI-Autostart-enabled" void gsp_key_file_populate (GKeyFile *keyfile); gboolean gsp_key_file_to_file (GKeyFile *keyfile, const gchar *path, GError **error); gboolean gsp_key_file_get_boolean (GKeyFile *keyfile, const gchar *key, gboolean default_value); gboolean gsp_key_file_get_shown (GKeyFile *keyfile, const char *current_desktop); #define gsp_key_file_get_string(key_file, key) \ g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, key, NULL) #define gsp_key_file_get_locale_string(key_file, key) \ g_key_file_get_locale_string(key_file, G_KEY_FILE_DESKTOP_GROUP, key, NULL, NULL) #define gsp_key_file_set_boolean(key_file, key, value) \ g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, key, value) #define gsp_key_file_set_string(key_file, key, value) \ g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP, key, value) void gsp_key_file_set_locale_string (GKeyFile *keyfile, const gchar *key, const gchar *value); void gsp_key_file_ensure_C_key (GKeyFile *keyfile, const char *key); G_END_DECLS #endif /* GSP_KEYFILE_H */ ukui-control-center/panels/session-properties/eggdesktopfile.c0000664000175000017500000012236713253611037023724 0ustar fengfeng/* eggdesktopfile.c - Freedesktop.Org Desktop Files * Copyright (C) 2007 Novell, Inc. * * Based on ukui-desktop-item.c * Copyright (C) 1999, 2000 Red Hat Inc. * Copyright (C) 2001 George Lebl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING.LIB. If not, * write to the Free Software Foundation, Inc., 51 Franklin St - * Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "eggdesktopfile.h" #include #include #include #include #include struct EggDesktopFile { GKeyFile* key_file; char* source; char* name; char* icon; EggDesktopFileType type; char document_code; }; /** * egg_desktop_file_new: * @desktop_file_path: path to a Freedesktop-style Desktop file * @error: error pointer * * Creates a new #EggDesktopFile for @desktop_file. * * Return value: the new #EggDesktopFile, or %NULL on error. **/ EggDesktopFile* egg_desktop_file_new(const char* desktop_file_path, GError** error) { GKeyFile* key_file; key_file = g_key_file_new(); if (!g_key_file_load_from_file(key_file, desktop_file_path, 0, error)) { g_key_file_free(key_file); return NULL; } return egg_desktop_file_new_from_key_file(key_file, desktop_file_path, error); } /** * egg_desktop_file_new_from_data_dirs: * @desktop_file_path: relative path to a Freedesktop-style Desktop file * @error: error pointer * * Looks for @desktop_file_path in the paths returned from * g_get_user_data_dir() and g_get_system_data_dirs(), and creates * a new #EggDesktopFile from it. * * Return value: the new #EggDesktopFile, or %NULL on error. **/ EggDesktopFile* egg_desktop_file_new_from_data_dirs(const char* desktop_file_path, GError** error) { EggDesktopFile* desktop_file; GKeyFile* key_file; char* full_path; key_file = g_key_file_new(); if (!g_key_file_load_from_data_dirs(key_file, desktop_file_path, &full_path, 0, error)) { g_key_file_free(key_file); return NULL; } desktop_file = egg_desktop_file_new_from_key_file(key_file, full_path, error); g_free(full_path); return desktop_file; } /** * egg_desktop_file_new_from_dirs: * @desktop_file_path: relative path to a Freedesktop-style Desktop file * @search_dirs: NULL-terminated array of directories to search * @error: error pointer * * Looks for @desktop_file_path in the paths returned from * g_get_user_data_dir() and g_get_system_data_dirs(), and creates * a new #EggDesktopFile from it. * * Return value: the new #EggDesktopFile, or %NULL on error. **/ EggDesktopFile* egg_desktop_file_new_from_dirs(const char* desktop_file_path, const char** search_dirs, GError** error) { EggDesktopFile* desktop_file; GKeyFile* key_file; char* full_path; key_file = g_key_file_new(); if (!g_key_file_load_from_dirs(key_file, desktop_file_path, search_dirs, &full_path, 0, error)) { g_key_file_free(key_file); return NULL; } desktop_file = egg_desktop_file_new_from_key_file(key_file, full_path, error); g_free(full_path); return desktop_file; } /** * egg_desktop_file_new_from_key_file: * @key_file: a #GKeyFile representing a desktop file * @source: the path or URI that @key_file was loaded from, or %NULL * @error: error pointer * * Creates a new #EggDesktopFile for @key_file. Assumes ownership of * @key_file (on success or failure); you should consider @key_file to * be freed after calling this function. * * Return value: the new #EggDesktopFile, or %NULL on error. **/ EggDesktopFile* egg_desktop_file_new_from_key_file(GKeyFile* key_file, const char* source, GError** error) { EggDesktopFile* desktop_file; char* version; char* type; if (!g_key_file_has_group(key_file, EGG_DESKTOP_FILE_GROUP)) { g_set_error(error, EGG_DESKTOP_FILE_ERROR, EGG_DESKTOP_FILE_ERROR_INVALID, "File is not a valid .desktop file"); g_key_file_free(key_file); return NULL; } version = g_key_file_get_value(key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_VERSION, NULL); if (version) { double version_num; char* end; version_num = g_ascii_strtod(version, &end); if (*end) { g_warning("Invalid Version string '%s' in %s", version, source ? source : "(unknown)"); } else if (version_num > 1.0) { g_set_error(error, EGG_DESKTOP_FILE_ERROR, EGG_DESKTOP_FILE_ERROR_INVALID, "Unrecognized desktop file Version '%s'", version); g_free(version); g_key_file_free(key_file); return NULL; } g_free (version); } desktop_file = g_new0(EggDesktopFile, 1); desktop_file->key_file = key_file; if (g_path_is_absolute(source)) { desktop_file->source = g_filename_to_uri(source, NULL, NULL); } else { desktop_file->source = g_strdup(source); } desktop_file->name = g_key_file_get_string(key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_NAME, error); if (!desktop_file->name) { egg_desktop_file_free(desktop_file); return NULL; } type = g_key_file_get_string(key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_TYPE, error); if (!type) { egg_desktop_file_free(desktop_file); return NULL; } if (!strcmp (type, "Application")) { char *exec, *p; desktop_file->type = EGG_DESKTOP_FILE_TYPE_APPLICATION; exec = g_key_file_get_string (key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_EXEC, error); if (!exec) { egg_desktop_file_free (desktop_file); g_free (type); return NULL; } /* See if it takes paths or URIs or neither */ for (p = exec; *p; p++) { if (*p == '%') { if (p[1] == '\0' || strchr ("FfUu", p[1])) { desktop_file->document_code = p[1]; break; } p++; } } g_free (exec); } else if (!strcmp (type, "Link")) { char *url; desktop_file->type = EGG_DESKTOP_FILE_TYPE_LINK; url = g_key_file_get_string (key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_URL, error); if (!url) { egg_desktop_file_free (desktop_file); g_free (type); return NULL; } g_free (url); } else if (!strcmp (type, "Directory")) desktop_file->type = EGG_DESKTOP_FILE_TYPE_DIRECTORY; else desktop_file->type = EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED; g_free (type); /* Check the Icon key */ desktop_file->icon = g_key_file_get_string (key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_ICON, NULL); if (desktop_file->icon && !g_path_is_absolute (desktop_file->icon)) { char *ext; /* Lots of .desktop files still get this wrong */ ext = strrchr (desktop_file->icon, '.'); if (ext && (!strcmp (ext, ".png") || !strcmp (ext, ".xpm") || !strcmp (ext, ".svg"))) { g_warning ("Desktop file '%s' has malformed Icon key '%s'" "(should not include extension)", source ? source : "(unknown)", desktop_file->icon); *ext = '\0'; } } return desktop_file; } /** * egg_desktop_file_free: * @desktop_file: an #EggDesktopFile * * Frees @desktop_file. **/ void egg_desktop_file_free (EggDesktopFile *desktop_file) { g_key_file_free (desktop_file->key_file); g_free (desktop_file->source); g_free (desktop_file->name); g_free (desktop_file->icon); g_free (desktop_file); } /** * egg_desktop_file_get_source: * @desktop_file: an #EggDesktopFile * * Gets the URI that @desktop_file was loaded from. * * Return value: @desktop_file's source URI **/ const char * egg_desktop_file_get_source (EggDesktopFile *desktop_file) { return desktop_file->source; } /** * egg_desktop_file_get_desktop_file_type: * @desktop_file: an #EggDesktopFile * * Gets the desktop file type of @desktop_file. * * Return value: @desktop_file's type **/ EggDesktopFileType egg_desktop_file_get_desktop_file_type (EggDesktopFile *desktop_file) { return desktop_file->type; } /** * egg_desktop_file_get_name: * @desktop_file: an #EggDesktopFile * * Gets the (localized) value of @desktop_file's "Name" key. * * Return value: the application/link name **/ const char * egg_desktop_file_get_name (EggDesktopFile *desktop_file) { return desktop_file->name; } /** * egg_desktop_file_get_icon: * @desktop_file: an #EggDesktopFile * * Gets the value of @desktop_file's "Icon" key. * * If the icon string is a full path (that is, if g_path_is_absolute() * returns %TRUE when called on it), it points to a file containing an * unthemed icon. If the icon string is not a full path, it is the * name of a themed icon, which can be looked up with %GtkIconTheme, * or passed directly to a theme-aware widget like %GtkImage or * %GtkCellRendererPixbuf. * * Return value: the icon path or name **/ const char * egg_desktop_file_get_icon (EggDesktopFile *desktop_file) { return desktop_file->icon; } gboolean egg_desktop_file_has_key (EggDesktopFile *desktop_file, const char *key, GError **error) { return g_key_file_has_key (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, key, error); } char * egg_desktop_file_get_string (EggDesktopFile *desktop_file, const char *key, GError **error) { return g_key_file_get_string (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, key, error); } char * egg_desktop_file_get_locale_string (EggDesktopFile *desktop_file, const char *key, const char *locale, GError **error) { return g_key_file_get_locale_string (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, key, locale, error); } gboolean egg_desktop_file_get_boolean (EggDesktopFile *desktop_file, const char *key, GError **error) { return g_key_file_get_boolean (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, key, error); } double egg_desktop_file_get_numeric (EggDesktopFile *desktop_file, const char *key, GError **error) { return g_key_file_get_double (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, key, error); } int egg_desktop_file_get_integer (EggDesktopFile *desktop_file, const char *key, GError **error) { return g_key_file_get_integer (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, key, error); } char ** egg_desktop_file_get_string_list (EggDesktopFile *desktop_file, const char *key, gsize *length, GError **error) { return g_key_file_get_string_list (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, key, length, error); } char ** egg_desktop_file_get_locale_string_list (EggDesktopFile *desktop_file, const char *key, const char *locale, gsize *length, GError **error) { return g_key_file_get_locale_string_list (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, key, locale, length, error); } /** * egg_desktop_file_can_launch: * @desktop_file: an #EggDesktopFile * @desktop_environment: the name of the running desktop environment, * or %NULL * * Tests if @desktop_file can/should be launched in the current * environment. If @desktop_environment is non-%NULL, @desktop_file's * "OnlyShowIn" and "NotShowIn" keys are checked to make sure that * this desktop_file is appropriate for the named environment. * * Furthermore, if @desktop_file has type * %EGG_DESKTOP_FILE_TYPE_APPLICATION, its "TryExec" key (if any) is * also checked, to make sure the binary it points to exists. * * egg_desktop_file_can_launch() does NOT check the value of the * "Hidden" key. * * Return value: %TRUE if @desktop_file can be launched **/ gboolean egg_desktop_file_can_launch (EggDesktopFile *desktop_file, const char *desktop_environment) { char *try_exec, *found_program; char **only_show_in, **not_show_in; gboolean found; int i; if (desktop_file->type != EGG_DESKTOP_FILE_TYPE_APPLICATION && desktop_file->type != EGG_DESKTOP_FILE_TYPE_LINK) return FALSE; if (desktop_environment) { only_show_in = g_key_file_get_string_list (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_ONLY_SHOW_IN, NULL, NULL); if (only_show_in) { for (i = 0, found = FALSE; only_show_in[i] && !found; i++) { if (!strcmp (only_show_in[i], desktop_environment)) found = TRUE; } g_strfreev (only_show_in); if (!found) return FALSE; } not_show_in = g_key_file_get_string_list (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_NOT_SHOW_IN, NULL, NULL); if (not_show_in) { for (i = 0, found = FALSE; not_show_in[i] && !found; i++) { if (!strcmp (not_show_in[i], desktop_environment)) found = TRUE; } g_strfreev (not_show_in); if (found) return FALSE; } } if (desktop_file->type == EGG_DESKTOP_FILE_TYPE_APPLICATION) { try_exec = g_key_file_get_string (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_TRY_EXEC, NULL); if (try_exec) { found_program = g_find_program_in_path (try_exec); g_free (try_exec); if (!found_program) return FALSE; g_free (found_program); } } return TRUE; } /** * egg_desktop_file_accepts_documents: * @desktop_file: an #EggDesktopFile * * Tests if @desktop_file represents an application that can accept * documents on the command line. * * Return value: %TRUE or %FALSE **/ gboolean egg_desktop_file_accepts_documents (EggDesktopFile *desktop_file) { return desktop_file->document_code != 0; } /** * egg_desktop_file_accepts_multiple: * @desktop_file: an #EggDesktopFile * * Tests if @desktop_file can accept multiple documents at once. * * If this returns %FALSE, you can still pass multiple documents to * egg_desktop_file_launch(), but that will result in multiple copies * of the application being launched. See egg_desktop_file_launch() * for more details. * * Return value: %TRUE or %FALSE **/ gboolean egg_desktop_file_accepts_multiple (EggDesktopFile *desktop_file) { return (desktop_file->document_code == 'F' || desktop_file->document_code == 'U'); } /** * egg_desktop_file_accepts_uris: * @desktop_file: an #EggDesktopFile * * Tests if @desktop_file can accept (non-"file:") URIs as documents to * open. * * Return value: %TRUE or %FALSE **/ gboolean egg_desktop_file_accepts_uris (EggDesktopFile *desktop_file) { return (desktop_file->document_code == 'U' || desktop_file->document_code == 'u'); } static void append_quoted_word (GString *str, const char *s, gboolean in_single_quotes, gboolean in_double_quotes) { const char *p; if (!in_single_quotes && !in_double_quotes) g_string_append_c (str, '\''); else if (!in_single_quotes && in_double_quotes) g_string_append (str, "\"'"); if (!strchr (s, '\'')) g_string_append (str, s); else { for (p = s; *p != '\0'; p++) { if (*p == '\'') g_string_append (str, "'\\''"); else g_string_append_c (str, *p); } } if (!in_single_quotes && !in_double_quotes) g_string_append_c (str, '\''); else if (!in_single_quotes && in_double_quotes) g_string_append (str, "'\""); } static void do_percent_subst (EggDesktopFile *desktop_file, char code, GString *str, GSList **documents, gboolean in_single_quotes, gboolean in_double_quotes) { GSList *d; char *doc; switch (code) { case '%': g_string_append_c (str, '%'); break; case 'F': case 'U': for (d = *documents; d; d = d->next) { doc = d->data; g_string_append (str, " "); append_quoted_word (str, doc, in_single_quotes, in_double_quotes); } *documents = NULL; break; case 'f': case 'u': if (*documents) { doc = (*documents)->data; g_string_append (str, " "); append_quoted_word (str, doc, in_single_quotes, in_double_quotes); *documents = (*documents)->next; } break; case 'i': if (desktop_file->icon) { g_string_append (str, "--icon "); append_quoted_word (str, desktop_file->icon, in_single_quotes, in_double_quotes); } break; case 'c': if (desktop_file->name) { append_quoted_word (str, desktop_file->name, in_single_quotes, in_double_quotes); } break; case 'k': if (desktop_file->source) { append_quoted_word (str, desktop_file->source, in_single_quotes, in_double_quotes); } break; case 'D': case 'N': case 'd': case 'n': case 'v': case 'm': /* Deprecated; skip */ break; default: g_warning ("Unrecognized %%-code '%%%c' in Exec", code); break; } } static char * parse_exec (EggDesktopFile *desktop_file, GSList **documents, GError **error) { char *exec, *p, *command; gboolean escape, single_quot, double_quot; GString *gs; exec = g_key_file_get_string (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_EXEC, error); if (!exec) return NULL; /* Build the command */ gs = g_string_new (NULL); escape = single_quot = double_quot = FALSE; for (p = exec; *p != '\0'; p++) { if (escape) { escape = FALSE; g_string_append_c (gs, *p); } else if (*p == '\\') { if (!single_quot) escape = TRUE; g_string_append_c (gs, *p); } else if (*p == '\'') { g_string_append_c (gs, *p); if (!single_quot && !double_quot) single_quot = TRUE; else if (single_quot) single_quot = FALSE; } else if (*p == '"') { g_string_append_c (gs, *p); if (!single_quot && !double_quot) double_quot = TRUE; else if (double_quot) double_quot = FALSE; } else if (*p == '%' && p[1]) { do_percent_subst (desktop_file, p[1], gs, documents, single_quot, double_quot); p++; } else g_string_append_c (gs, *p); } g_free (exec); command = g_string_free (gs, FALSE); /* Prepend "xdg-terminal " if needed (FIXME: use gvfs) */ if (g_key_file_has_key (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_TERMINAL, NULL)) { GError *terminal_error = NULL; gboolean use_terminal = g_key_file_get_boolean (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_TERMINAL, &terminal_error); if (terminal_error) { g_free (command); g_propagate_error (error, terminal_error); return NULL; } if (use_terminal) { gs = g_string_new ("xdg-terminal "); append_quoted_word (gs, command, FALSE, FALSE); g_free (command); command = g_string_free (gs, FALSE); } } return command; } static GSList * translate_document_list (EggDesktopFile *desktop_file, GSList *documents) { gboolean accepts_uris = egg_desktop_file_accepts_uris (desktop_file); GSList *ret, *d; for (d = documents, ret = NULL; d; d = d->next) { const char *document = d->data; gboolean is_uri = !g_path_is_absolute (document); char *translated; if (accepts_uris) { if (is_uri) translated = g_strdup (document); else translated = g_filename_to_uri (document, NULL, NULL); } else { if (is_uri) translated = g_filename_from_uri (document, NULL, NULL); else translated = g_strdup (document); } if (translated) ret = g_slist_prepend (ret, translated); } return g_slist_reverse (ret); } static void free_document_list (GSList *documents) { GSList *d; for (d = documents; d; d = d->next) g_free (d->data); g_slist_free (documents); } /** * egg_desktop_file_parse_exec: * @desktop_file: a #EggDesktopFile * @documents: a list of document paths or URIs * @error: error pointer * * Parses @desktop_file's Exec key, inserting @documents into it, and * returns the result. * * If @documents contains non-file: URIs and @desktop_file does not * accept URIs, those URIs will be ignored. Likewise, if @documents * contains more elements than @desktop_file accepts, the extra * documents will be ignored. * * Return value: the parsed Exec string **/ char * egg_desktop_file_parse_exec (EggDesktopFile *desktop_file, GSList *documents, GError **error) { GSList *translated, *docs; char *command; docs = translated = translate_document_list (desktop_file, documents); command = parse_exec (desktop_file, &docs, error); free_document_list (translated); return command; } static gboolean parse_link (EggDesktopFile *desktop_file, EggDesktopFile **app_desktop_file, GSList **documents, GError **error) { char *url; GKeyFile *key_file; url = g_key_file_get_string (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_URL, error); if (!url) return FALSE; *documents = g_slist_prepend (NULL, url); /* FIXME: use gvfs */ key_file = g_key_file_new (); g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_NAME, "xdg-open"); g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_TYPE, "Application"); g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_EXEC, "xdg-open %u"); *app_desktop_file = egg_desktop_file_new_from_key_file (key_file, NULL, NULL); return TRUE; } #if GTK_CHECK_VERSION (2, 12, 0) static char * start_startup_notification (GdkDisplay *display, EggDesktopFile *desktop_file, const char *argv0, int screen, int workspace, guint32 launch_time) { static int sequence = 0; char *startup_id; char *description, *wmclass; char *screen_str, *workspace_str; if (g_key_file_has_key (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY, NULL)) { if (!g_key_file_get_boolean (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY, NULL)) return NULL; wmclass = NULL; } else { wmclass = g_key_file_get_string (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_STARTUP_WM_CLASS, NULL); if (!wmclass) return NULL; } if (launch_time == (guint32)-1) launch_time = gdk_x11_display_get_user_time (display); startup_id = g_strdup_printf ("%s-%lu-%s-%s-%d_TIME%lu", g_get_prgname (), (unsigned long)getpid (), g_get_host_name (), argv0, sequence++, (unsigned long)launch_time); description = g_strdup_printf ("Starting %s", desktop_file->name); screen_str = g_strdup_printf ("%d", screen); workspace_str = workspace == -1 ? NULL : g_strdup_printf ("%d", workspace); gdk_x11_display_broadcast_startup_message (display, "new", "ID", startup_id, "NAME", desktop_file->name, "SCREEN", screen_str, "BIN", argv0, "ICON", desktop_file->icon, "DESKTOP", workspace_str, "DESCRIPTION", description, "WMCLASS", wmclass, NULL); g_free (description); g_free (wmclass); g_free (screen_str); g_free (workspace_str); return startup_id; } static void end_startup_notification (GdkDisplay *display, const char *startup_id) { gdk_x11_display_broadcast_startup_message (display, "remove", "ID", startup_id, NULL); } #define EGG_DESKTOP_FILE_SN_TIMEOUT_LENGTH (30 /* seconds */) typedef struct { GdkDisplay *display; char *startup_id; } StartupNotificationData; static gboolean startup_notification_timeout (gpointer data) { StartupNotificationData *sn_data = data; end_startup_notification (sn_data->display, sn_data->startup_id); g_object_unref (sn_data->display); g_free (sn_data->startup_id); g_free (sn_data); return FALSE; } static void set_startup_notification_timeout (GdkDisplay *display, const char *startup_id) { StartupNotificationData *sn_data; sn_data = g_new (StartupNotificationData, 1); sn_data->display = g_object_ref (display); sn_data->startup_id = g_strdup (startup_id); g_timeout_add_seconds (EGG_DESKTOP_FILE_SN_TIMEOUT_LENGTH, startup_notification_timeout, sn_data); } #endif /* GTK 2.12 */ static GPtrArray * array_putenv (GPtrArray *env, char *variable) { guint i, keylen; if (!env) { char **envp; env = g_ptr_array_new (); envp = g_listenv (); for (i = 0; envp[i]; i++) { const char *value; value = g_getenv (envp[i]); g_ptr_array_add (env, g_strdup_printf ("%s=%s", envp[i], value ? value : "")); } g_strfreev (envp); } keylen = strcspn (variable, "="); /* Remove old value of key */ for (i = 0; i < env->len; i++) { char *envvar = env->pdata[i]; if (!strncmp (envvar, variable, keylen) && envvar[keylen] == '=') { g_free (envvar); g_ptr_array_remove_index_fast (env, i); break; } } /* Add new value */ g_ptr_array_add (env, g_strdup (variable)); return env; } static gboolean egg_desktop_file_launchv (EggDesktopFile *desktop_file, GSList *documents, va_list args, GError **error) { EggDesktopFileLaunchOption option; GSList *translated_documents = NULL, *docs = NULL; char *command, **argv; int argc, i, screen_num; gboolean success, current_success; GdkDisplay *display; char *startup_id; GPtrArray *env = NULL; char **variables = NULL; GdkScreen *screen = NULL; int workspace = -1; const char *directory = NULL; guint32 launch_time = (guint32)-1; GSpawnFlags flags = G_SPAWN_SEARCH_PATH; GSpawnChildSetupFunc setup_func = NULL; gpointer setup_data = NULL; GPid *ret_pid = NULL; int *ret_stdin = NULL, *ret_stdout = NULL, *ret_stderr = NULL; char **ret_startup_id = NULL; if (documents && desktop_file->document_code == 0) { g_set_error (error, EGG_DESKTOP_FILE_ERROR, EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, "Application does not accept documents on command line"); return FALSE; } /* Read the options: technically it's incorrect for the caller to * NULL-terminate the list of options (rather than 0-terminating * it), but NULL-terminating lets us use G_GNUC_NULL_TERMINATED, * it's more consistent with other glib/gtk methods, and it will * work as long as sizeof (int) <= sizeof (NULL), and NULL is * represented as 0. (Which is true everywhere we care about.) */ while ((option = va_arg (args, EggDesktopFileLaunchOption))) { switch (option) { case EGG_DESKTOP_FILE_LAUNCH_CLEARENV: if (env) g_ptr_array_free (env, TRUE); env = g_ptr_array_new (); break; case EGG_DESKTOP_FILE_LAUNCH_PUTENV: variables = va_arg (args, char **); for (i = 0; variables[i]; i++) env = array_putenv (env, variables[i]); break; case EGG_DESKTOP_FILE_LAUNCH_SCREEN: screen = va_arg (args, GdkScreen *); break; case EGG_DESKTOP_FILE_LAUNCH_WORKSPACE: workspace = va_arg (args, int); break; case EGG_DESKTOP_FILE_LAUNCH_DIRECTORY: directory = va_arg (args, const char *); break; case EGG_DESKTOP_FILE_LAUNCH_TIME: launch_time = va_arg (args, guint32); break; case EGG_DESKTOP_FILE_LAUNCH_FLAGS: flags |= va_arg (args, GSpawnFlags); /* Make sure they didn't set any flags that don't make sense. */ flags &= ~G_SPAWN_FILE_AND_ARGV_ZERO; break; case EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC: setup_func = va_arg (args, GSpawnChildSetupFunc); setup_data = va_arg (args, gpointer); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_PID: ret_pid = va_arg (args, GPid *); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE: ret_stdin = va_arg (args, int *); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE: ret_stdout = va_arg (args, int *); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE: ret_stderr = va_arg (args, int *); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID: ret_startup_id = va_arg (args, char **); break; default: g_set_error (error, EGG_DESKTOP_FILE_ERROR, EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION, "Unrecognized launch option: %d", GPOINTER_TO_INT (option)); success = FALSE; goto out; } } if (screen) { char *display_name = gdk_screen_make_display_name (screen); char *display_env = g_strdup_printf ("DISPLAY=%s", display_name); env = array_putenv (env, display_env); g_free (display_name); g_free (display_env); display = gdk_screen_get_display (screen); } else { display = gdk_display_get_default (); screen = gdk_display_get_default_screen (display); } screen_num = gdk_screen_get_number (screen); translated_documents = translate_document_list (desktop_file, documents); docs = translated_documents; success = FALSE; do { command = parse_exec (desktop_file, &docs, error); if (!command) goto out; if (!g_shell_parse_argv (command, &argc, &argv, error)) { g_free (command); goto out; } g_free (command); #if GTK_CHECK_VERSION (2, 12, 0) startup_id = start_startup_notification (display, desktop_file, argv[0], screen_num, workspace, launch_time); if (startup_id) { char *startup_id_env = g_strdup_printf ("DESKTOP_STARTUP_ID=%s", startup_id); env = array_putenv (env, startup_id_env); g_free (startup_id_env); } #else startup_id = NULL; #endif /* GTK 2.12 */ if (env != NULL) g_ptr_array_add (env, NULL); current_success = g_spawn_async_with_pipes (directory, argv, env ? (char **)(env->pdata) : NULL, flags, setup_func, setup_data, ret_pid, ret_stdin, ret_stdout, ret_stderr, error); g_strfreev (argv); if (startup_id) { #if GTK_CHECK_VERSION (2, 12, 0) if (current_success) { set_startup_notification_timeout (display, startup_id); if (ret_startup_id) *ret_startup_id = startup_id; else g_free (startup_id); } else #endif /* GTK 2.12 */ g_free (startup_id); } else if (ret_startup_id) *ret_startup_id = NULL; if (current_success) { /* If we successfully launch any instances of the app, make * sure we return TRUE and don't set @error. */ success = TRUE; error = NULL; /* Also, only set the output params on the first one */ ret_pid = NULL; ret_stdin = ret_stdout = ret_stderr = NULL; ret_startup_id = NULL; } } while (docs && current_success); out: if (env) { g_ptr_array_foreach (env, (GFunc)g_free, NULL); g_ptr_array_free (env, TRUE); } free_document_list (translated_documents); return success; } /** * egg_desktop_file_launch: * @desktop_file: an #EggDesktopFile * @documents: a list of URIs or paths to documents to open * @error: error pointer * @...: additional options * * Launches @desktop_file with the given arguments. Additional options * can be specified as follows: * * %EGG_DESKTOP_FILE_LAUNCH_CLEARENV: (no arguments) * clears the environment in the child process * %EGG_DESKTOP_FILE_LAUNCH_PUTENV: (char **variables) * adds the NAME=VALUE strings in the given %NULL-terminated * array to the child process's environment * %EGG_DESKTOP_FILE_LAUNCH_SCREEN: (GdkScreen *screen) * causes the application to be launched on the given screen * %EGG_DESKTOP_FILE_LAUNCH_WORKSPACE: (int workspace) * causes the application to be launched on the given workspace * %EGG_DESKTOP_FILE_LAUNCH_DIRECTORY: (char *dir) * causes the application to be launched in the given directory * %EGG_DESKTOP_FILE_LAUNCH_TIME: (guint32 launch_time) * sets the "launch time" for the application. If the user * interacts with another window after @launch_time but before * the launched application creates its first window, the window * manager may choose to not give focus to the new application. * Passing 0 for @launch_time will explicitly request that the * application not receive focus. * %EGG_DESKTOP_FILE_LAUNCH_FLAGS (GSpawnFlags flags) * Sets additional #GSpawnFlags to use. See g_spawn_async() for * more details. * %EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC (GSpawnChildSetupFunc, gpointer) * Sets the child setup callback and the data to pass to it. * (See g_spawn_async() for more details.) * * %EGG_DESKTOP_FILE_LAUNCH_RETURN_PID (GPid **pid) * On a successful launch, sets *@pid to the PID of the launched * application. * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID (char **startup_id) * On a successful launch, sets *@startup_id to the Startup * Notification "startup id" of the launched application. * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE (int *fd) * On a successful launch, sets *@fd to the file descriptor of * a pipe connected to the application's stdin. * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE (int *fd) * On a successful launch, sets *@fd to the file descriptor of * a pipe connected to the application's stdout. * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE (int *fd) * On a successful launch, sets *@fd to the file descriptor of * a pipe connected to the application's stderr. * * The options should be terminated with a single %NULL. * * If @documents contains multiple documents, but * egg_desktop_file_accepts_multiple() returns %FALSE for * @desktop_file, then egg_desktop_file_launch() will actually launch * multiple instances of the application. In that case, the return * value (as well as any values passed via * %EGG_DESKTOP_FILE_LAUNCH_RETURN_PID, etc) will only reflect the * first instance of the application that was launched (but the * %EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC will be called for each * instance). * * Return value: %TRUE if the application was successfully launched. **/ gboolean egg_desktop_file_launch (EggDesktopFile *desktop_file, GSList *documents, GError **error, ...) { va_list args; gboolean success; EggDesktopFile *app_desktop_file; switch (desktop_file->type) { case EGG_DESKTOP_FILE_TYPE_APPLICATION: va_start (args, error); success = egg_desktop_file_launchv (desktop_file, documents, args, error); va_end (args); break; case EGG_DESKTOP_FILE_TYPE_LINK: if (documents) { g_set_error (error, EGG_DESKTOP_FILE_ERROR, EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, "Can't pass document URIs to a 'Type=Link' desktop entry"); return FALSE; } if (!parse_link (desktop_file, &app_desktop_file, &documents, error)) return FALSE; va_start (args, error); success = egg_desktop_file_launchv (app_desktop_file, documents, args, error); va_end (args); egg_desktop_file_free (app_desktop_file); free_document_list (documents); break; case EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED: case EGG_DESKTOP_FILE_TYPE_DIRECTORY: default: g_set_error (error, EGG_DESKTOP_FILE_ERROR, EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, "Not a launchable item"); success = FALSE; break; } return success; } GQuark egg_desktop_file_error_quark (void) { return g_quark_from_static_string ("egg-desktop_file-error-quark"); } G_LOCK_DEFINE_STATIC (egg_desktop_file); static EggDesktopFile *egg_desktop_file; static void egg_set_desktop_file_internal (const char *desktop_file_path, gboolean set_defaults) { GError *error = NULL; G_LOCK (egg_desktop_file); if (egg_desktop_file) egg_desktop_file_free (egg_desktop_file); egg_desktop_file = egg_desktop_file_new (desktop_file_path, &error); if (error) { g_warning ("Could not load desktop file '%s': %s", desktop_file_path, error->message); g_error_free (error); } if (set_defaults && egg_desktop_file != NULL) { /* Set localized application name and default window icon */ if (egg_desktop_file->name) g_set_application_name (egg_desktop_file->name); if (egg_desktop_file->icon) { if (g_path_is_absolute (egg_desktop_file->icon)) gtk_window_set_default_icon_from_file (egg_desktop_file->icon, NULL); else gtk_window_set_default_icon_name (egg_desktop_file->icon); } } G_UNLOCK (egg_desktop_file); } /** * egg_set_desktop_file: * @desktop_file_path: path to the application's desktop file * * Creates an #EggDesktopFile for the application from the data at * @desktop_file_path. This will also call g_set_application_name() * with the localized application name from the desktop file, and * gtk_window_set_default_icon_name() or * gtk_window_set_default_icon_from_file() with the application's * icon. Other code may use additional information from the desktop * file. * See egg_set_desktop_file_without_defaults() for a variant of this * function that does not set the application name and default window * icon. * * Note that for thread safety reasons, this function can only * be called once, and is mutually exclusive with calling * egg_set_desktop_file_without_defaults(). **/ void egg_set_desktop_file (const char *desktop_file_path) { egg_set_desktop_file_internal (desktop_file_path, TRUE); } /** * egg_set_desktop_file_without_defaults: * @desktop_file_path: path to the application's desktop file * * Creates an #EggDesktopFile for the application from the data at * @desktop_file_path. * See egg_set_desktop_file() for a variant of this function that * sets the application name and default window icon from the information * in the desktop file. * * Note that for thread safety reasons, this function can only * be called once, and is mutually exclusive with calling * egg_set_desktop_file(). **/ void egg_set_desktop_file_without_defaults (const char *desktop_file_path) { egg_set_desktop_file_internal (desktop_file_path, FALSE); } /** * egg_get_desktop_file: * * Gets the application's #EggDesktopFile, as set by * egg_set_desktop_file(). * * Return value: the #EggDesktopFile, or %NULL if it hasn't been set. **/ EggDesktopFile * egg_get_desktop_file (void) { EggDesktopFile *retval; G_LOCK (egg_desktop_file); retval = egg_desktop_file; G_UNLOCK (egg_desktop_file); return retval; } ukui-control-center/panels/session-properties/gsm-app-dialog.h0000664000175000017500000000366613057175444023547 0ustar fengfeng#ifndef __GSM_APP_DIALOG_H #define __GSM_APP_DIALOG_H #include #include #ifdef __cplusplus extern "C" { #endif #define GSM_TYPE_APP_DIALOG (gsm_app_dialog_get_type ()) #define GSM_APP_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSM_TYPE_APP_DIALOG, GsmAppDialog)) #define GSM_APP_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSM_TYPE_APP_DIALOG, GsmAppDialogClass)) #define GSM_IS_APP_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSM_TYPE_APP_DIALOG)) #define GSM_IS_APP_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSM_TYPE_APP_DIALOG)) #define GSM_APP_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSM_TYPE_APP_DIALOG, GsmAppDialogClass)) typedef struct GsmAppDialogPrivate GsmAppDialogPrivate; typedef struct { GtkDialog parent; GsmAppDialogPrivate *priv; } GsmAppDialog; typedef struct { GtkDialogClass parent_class; } GsmAppDialogClass; GType gsm_app_dialog_get_type (void); GtkWidget * gsm_app_dialog_new (const char *name, const char *command, const char *comment); gboolean gsm_app_dialog_run (GsmAppDialog *dialog, char **name_p, char **command_p, char **comment_p, char **icon_p); const char * gsm_app_dialog_get_name (GsmAppDialog *dialog); const char * gsm_app_dialog_get_command (GsmAppDialog *dialog); const char * gsm_app_dialog_get_comment (GsmAppDialog *dialog); #ifdef __cplusplus } #endif #endif /* __GSM_APP_DIALOG_H */ ukui-control-center/panels/appearance/0000775000175000017500000000000013263647163017005 5ustar fengfengukui-control-center/panels/appearance/appearance.h0000664000175000017500000001010313253611050021231 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef _APPEARANCE_H #define _APPEARANCE_H #include #include #include #define MATE_DESKTOP_USE_UNSTABLE_API #include #define WP_SCHEMA "org.mate.background" #define WP_FILE_KEY "picture-filename" #define WP_OPTIONS_KEY "picture-options" #define WP_SHADING_KEY "color-shading-type" #define WP_PCOLOR_KEY "primary-color" #define WP_SCOLOR_KEY "secondary-color" #define INTERFACE_SCHEMA "org.mate.interface" #define GTK_FONT_KEY "font-name" #define MONOSPACE_FONT_KEY "monospace-font-name" #define DOCUMENT_FONT_KEY "document-font-name" #define GTK_THEME_KEY "gtk-theme" #define ICON_THEME_KEY "icon-theme" #define COLOR_SCHEME_KEY "gtk-color-scheme" #define GTK_FONT_DEFAULT_VALUE "Sans 10" #define LOCKDOWN_SCHEMA "org.mate.lockdown" #define DISABLE_THEMES_SETTINGS_KEY "disable-theme-settings" #define PEONY_SCHEMA "org.ukui.peony.desktop" #define DESKTOP_FONT_KEY "font" #define MARCO_SCHEMA "org.gnome.desktop.wm.preferences" #define MARCO_THEME_KEY "theme" #define WINDOW_TITLE_FONT_KEY "titlebar-font" #define WINDOW_TITLE_USES_SYSTEM_KEY "titlebar-uses-system-font" #define NOTIFICATION_SCHEMA "org.mate.NotificationDaemon" #define NOTIFICATION_THEME_KEY "theme" #define MOUSE_SCHEMA "org.mate.peripherals-mouse" #define CURSOR_THEME_KEY "cursor-theme" #define CURSOR_SIZE_KEY "cursor-size" #define FONT_RENDER_SCHEMA "org.ukui.font-rendering" #define FONT_ANTIALIASING_KEY "antialiasing" #define FONT_HINTING_KEY "hinting" #define FONT_RGBA_ORDER_KEY "rgba-order" #define FONT_DPI_KEY "dpi" typedef struct { GSettings* settings; GSettings* wp_settings; GSettings* peony_settings; GSettings* interface_settings; GSettings* marco_settings; GSettings* mouse_settings; GSettings* font_settings; GtkBuilder* ui; MateDesktopThumbnailFactory* thumb_factory; gulong screen_size_handler; gulong screen_monitors_handler; /* desktop */ GHashTable* wp_hash; GtkIconView* wp_view; GtkTreeModel* wp_model; GtkWidget* wp_style_menu; GtkWidget* wp_rem_button; GtkFileChooser* wp_filesel; GtkWidget* wp_image; //GtkWidget * menu; //GtkTreePath * path; //current path GSList* wp_uris; gint frame; gint thumb_width; gint thumb_height; GtkWidget * dialog_vbox2; /* font */ GtkWidget* font_details; GSList* font_groups; gchar* revert_application_font; gchar* revert_documents_font; gchar* revert_desktop_font; gchar* revert_windowtitle_font; gchar* revert_monospace_font; /* style */ GdkPixbuf* gtk_theme_icon; GdkPixbuf* window_theme_icon; GdkPixbuf* icon_theme_icon; GtkWidget* style_message_area; GtkWidget* style_message_label; GtkWidget* style_install_button; } AppearanceData; #define appearance_capplet_get_widget(x, y) (GtkWidget*) gtk_builder_get_object(x->ui, y) #endif ukui-control-center/panels/appearance/appearance-desktop.h0000664000175000017500000000176213245450075022724 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "ukui-wp-xml.h" void desktop_init(AppearanceData * data, const gchar **wallpaper); void desktop_shutdown(AppearanceData * data); ukui-control-center/panels/appearance/ukui-wp-xml.h0000664000175000017500000000203613253611037021344 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef _UKUI_WP_XML_H_ #define _UKUI_WP_XML_H_ #include "ukui-wp-item.h" void ukui_wp_xml_load_list(AppearanceData* data); void ukui_wp_xml_save_list(AppearanceData* data); #endif ukui-control-center/panels/appearance/appearance-desktop.c0000664000175000017500000010110313253611037022701 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "appearance-desktop.h" #include enum { TARGET_URI_LIST, TARGET_BGIMAGE }; static const GtkTargetEntry drop_types[] = { {"text/uri-list", 0, TARGET_URI_LIST}, {"property/bgimage", 0, TARGET_BGIMAGE} }; static const GtkTargetEntry drag_types[] = { {"text/uri-list", GTK_TARGET_OTHER_WIDGET, TARGET_URI_LIST} }; static void wp_props_wp_selected (GtkTreeSelection *selection, AppearanceData *data); static void wp_update_preview(GtkFileChooser* chooser, AppearanceData* data); static void select_item(AppearanceData* data, UkuiWPItem* item, gboolean scroll) { GtkTreePath* path; g_return_if_fail(data != NULL); if (item == NULL) return; path = gtk_tree_row_reference_get_path(item->rowref); gtk_icon_view_select_path(data->wp_view, path); if (scroll) { gtk_icon_view_scroll_to_path(data->wp_view, path, FALSE, 0.5, 0.0); } gtk_tree_path_free(path); } static UkuiWPItem* get_selected_item(AppearanceData* data, GtkTreeIter* iter) { UkuiWPItem* item = NULL; GList* selected; selected = gtk_icon_view_get_selected_items (data->wp_view); if (selected != NULL) { GtkTreeIter sel_iter; gtk_tree_model_get_iter(data->wp_model, &sel_iter, selected->data); g_list_foreach(selected, (GFunc) gtk_tree_path_free, NULL); g_list_free(selected); if (iter) *iter = sel_iter; gtk_tree_model_get(data->wp_model, &sel_iter, 1, &item, -1); } return item; } static gboolean predicate (gpointer key, gpointer value, gpointer data) { MateBG *bg = data; UkuiWPItem *item = value; return item->bg == bg; } static void on_item_changed (MateBG *bg, AppearanceData *data) { GtkTreeModel *model; GtkTreeIter iter; GtkTreePath *path; UkuiWPItem *item; item = g_hash_table_find (data->wp_hash, predicate, bg); if (!item) return; model = gtk_tree_row_reference_get_model (item->rowref); path = gtk_tree_row_reference_get_path (item->rowref); if (gtk_tree_model_get_iter (model, &iter, path)) { GdkPixbuf *pixbuf; g_signal_handlers_block_by_func (bg, G_CALLBACK (on_item_changed), data); pixbuf = ukui_wp_item_get_thumbnail (item, data->thumb_factory, data->thumb_width, data->thumb_height); if (pixbuf) { gtk_list_store_set (GTK_LIST_STORE (data->wp_model), &iter, 0, pixbuf, -1); g_object_unref (pixbuf); } g_signal_handlers_unblock_by_func (bg, G_CALLBACK (on_item_changed), data); } } static void wp_props_load_wallpaper (gchar *key, UkuiWPItem *item, AppearanceData *data) { GtkTreeIter iter; GtkTreePath *path; GdkPixbuf *pixbuf; if (item->deleted == TRUE) return; gtk_list_store_append (GTK_LIST_STORE (data->wp_model), &iter); pixbuf = ukui_wp_item_get_thumbnail (item, data->thumb_factory, data->thumb_width, data->thumb_height); ukui_wp_item_update_description (item); gtk_list_store_set (GTK_LIST_STORE (data->wp_model), &iter, 0, pixbuf, 1, item, -1); if (pixbuf != NULL) g_object_unref (pixbuf); path = gtk_tree_model_get_path (data->wp_model, &iter); item->rowref = gtk_tree_row_reference_new (data->wp_model, path); g_signal_connect (item->bg, "changed", G_CALLBACK (on_item_changed), data); gtk_tree_path_free (path); } static UkuiWPItem * wp_add_image (AppearanceData *data, const gchar *filename) { UkuiWPItem *item; if (!filename) return NULL; item = g_hash_table_lookup (data->wp_hash, filename); if (item != NULL) { if (item->deleted) { item->deleted = FALSE; wp_props_load_wallpaper (item->filename, item, data); } } else { item = ukui_wp_item_new (filename, data->wp_hash, data->thumb_factory); if (item != NULL) { wp_props_load_wallpaper (item->filename, item, data); } } return item; } static void wp_add_images (AppearanceData *data, GSList *images) { GdkWindow *window; GtkWidget *w; GdkCursor *cursor; UkuiWPItem *item; w = appearance_capplet_get_widget (data, "appearance_window"); window = gtk_widget_get_window (w); data->dialog_vbox2 = appearance_capplet_get_widget(data, "dialog-vbox2"); item = NULL; cursor = gdk_cursor_new_for_display (gdk_display_get_default (), GDK_WATCH); gdk_window_set_cursor (window, cursor); #if GTK_CHECK_VERSION (3, 0, 0) g_object_unref (cursor); #else gdk_cursor_unref (cursor); #endif while (images != NULL) { gchar *uri = images->data; item = wp_add_image (data, uri); images = g_slist_remove (images, uri); g_free (uri); } gdk_window_set_cursor (window, NULL); if (item != NULL) { select_item (data, item, TRUE); } } static void wp_option_menu_set (AppearanceData *data, int value, gboolean shade_type) { if (!shade_type) { gtk_combo_box_set_active (GTK_COMBO_BOX (data->wp_style_menu), value); } } static void wp_set_sensitivities (AppearanceData *data) { UkuiWPItem *item; gchar *filename = NULL; item = get_selected_item (data, NULL); if (item != NULL) filename = item->filename; if (!g_settings_is_writable (data->wp_settings, WP_OPTIONS_KEY) || (filename && !strcmp (filename, "(none)"))) gtk_widget_set_sensitive (data->wp_style_menu, TRUE); else gtk_widget_set_sensitive (data->wp_style_menu, TRUE); if (!filename || !strcmp (filename, "(none)")) gtk_widget_set_sensitive (data->wp_rem_button, FALSE); else gtk_widget_set_sensitive (data->wp_rem_button, TRUE); } static void wp_scale_type_changed (GtkComboBox *combobox, AppearanceData *data) { UkuiWPItem *item; GtkTreeIter iter; GdkPixbuf *pixbuf; item = get_selected_item (data, &iter); if (item == NULL) return; item->options = gtk_combo_box_get_active (GTK_COMBO_BOX (data->wp_style_menu)); pixbuf = ukui_wp_item_get_thumbnail (item, data->thumb_factory, data->thumb_width, data->thumb_height); gtk_list_store_set (GTK_LIST_STORE (data->wp_model), &iter, 0, pixbuf, -1); if (pixbuf != NULL) g_object_unref (pixbuf); if (g_settings_is_writable (data->wp_settings, WP_OPTIONS_KEY)) { g_settings_delay (data->wp_settings); g_settings_set_enum (data->wp_settings, WP_OPTIONS_KEY, item->options); g_settings_apply (data->wp_settings); } } static void wp_remove_wallpaper (GtkWidget *widget, AppearanceData *data) { UkuiWPItem *item; GtkTreeIter iter; GtkTreePath *path; gboolean ifremove; item = get_selected_item (data, &iter); if (item) { item->deleted = TRUE; g_signal_handlers_block_by_func(data->wp_view, wp_props_wp_selected, data); ifremove = gtk_list_store_remove(GTK_LIST_STORE(data->wp_model), &iter); if (ifremove) { path = gtk_tree_model_get_path (data->wp_model, &iter); } else { path = gtk_tree_path_new_first (); } gtk_icon_view_select_path (data->wp_view, path); gtk_icon_view_set_cursor (data->wp_view, path, NULL, FALSE); gtk_tree_path_free (path); g_signal_handlers_unblock_by_func(data->wp_view, wp_props_wp_selected, data); wp_props_wp_selected(NULL,data); } } static void wp_uri_changed (const gchar *uri, AppearanceData *data) { UkuiWPItem *item, *selected; item = g_hash_table_lookup (data->wp_hash, uri); selected = get_selected_item (data, NULL); if (selected != NULL && strcmp (selected->filename, uri) != 0) { if (item == NULL) item = wp_add_image (data, uri); if (item) select_item (data, item, TRUE); } } static void wp_file_changed (GSettings *settings, gchar *key, AppearanceData *data) { gchar *uri; gchar *wpfile; uri = g_settings_get_string (settings, key); if (g_utf8_validate (uri, -1, NULL) && g_file_test (uri, G_FILE_TEST_EXISTS)) wpfile = g_strdup (uri); else wpfile = g_filename_from_utf8 (uri, -1, NULL, NULL, NULL); wp_uri_changed (wpfile, data); g_free (wpfile); g_free (uri); } static void wp_options_changed (GSettings *settings, gchar *key, AppearanceData *data) { UkuiWPItem *item; item = get_selected_item (data, NULL); if (item != NULL) { item->options = g_settings_get_enum (settings, key); wp_option_menu_set (data, item->options, FALSE); } } static void wp_shading_changed (GSettings *settings, gchar *key, AppearanceData *data) { UkuiWPItem *item; wp_set_sensitivities (data); item = get_selected_item (data, NULL); if (item != NULL) { item->shade_type = g_settings_get_enum (settings, key); wp_option_menu_set (data, item->shade_type, TRUE); } } static gboolean wp_props_wp_set (AppearanceData *data, UkuiWPItem *item) { gchar *pcolor, *scolor; g_settings_delay (data->wp_settings); if (!strcmp (item->filename, "(none)")) { g_settings_set_enum (data->wp_settings, WP_OPTIONS_KEY, 0); g_settings_set_string (data->wp_settings, WP_FILE_KEY, ""); } else { gchar *uri; if (g_utf8_validate (item->filename, -1, NULL)) uri = g_strdup (item->filename); else uri = g_filename_to_utf8 (item->filename, -1, NULL, NULL, NULL); if (uri == NULL) { g_warning ("Failed to convert filename to UTF-8: %s", item->filename); } else { g_settings_set_string (data->wp_settings, WP_FILE_KEY, uri); g_free (uri); } g_settings_set_enum (data->wp_settings, WP_OPTIONS_KEY, item->options); } g_settings_set_enum (data->wp_settings, WP_SHADING_KEY, item->shade_type); pcolor = gdk_color_to_string (item->pcolor); scolor = gdk_color_to_string (item->scolor); g_settings_set_string (data->wp_settings, WP_PCOLOR_KEY, pcolor); g_settings_set_string (data->wp_settings, WP_SCOLOR_KEY, scolor); //g_free (pcolor); //g_free (scolor); g_settings_apply (data->wp_settings); return FALSE; } static void setBackgroundInDbus(GObject *source_object, GAsyncResult *res, gpointer user_data) { GVariant *path; GError *error1 = NULL; path = g_dbus_connection_call_finish( G_DBUS_CONNECTION(source_object), res, &error1); g_object_unref (source_object); if(path) { GDBusConnection *user_bus; GError *error2 = NULL; gchar *user_path; g_variant_get(path, "(o)", &user_path); user_bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error2); if (!user_bus) { g_warning("Failed to get session bus: %s", error2->message); g_error_free(error2); return; } g_dbus_connection_call (user_bus, "org.freedesktop.Accounts", user_path, "org.freedesktop.Accounts.User", "SetBackgroundFile", g_variant_new( "(s)", (gchar *)user_data), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); g_variant_unref(path); } else { g_warning("%s", error1->message); g_error_free (error1); } } /*static void remove_background(GtkMenuItem *menuitem, AppearanceData *data){ g_warning("remove"); UkuiWPItem * item = NULL; GtkTreeModel * model; GtkTreeIter iter; model = gtk_icon_view_get_model(GTK_ICON_VIEW(data->wp_view)); if(gtk_tree_model_get_iter(model, &iter, data->path)){ gtk_tree_model_get(model, &iter, 1, &item, -1); } else{ return; } if(item){ item->deleted = TRUE; gtk_tree_path_free(data->path); } }*/ /*static gboolean right_click_cb(GtkWidget * widget, GdkEventButton *event, AppearanceData *data) { UkuiWPItem * item; gint x,y; gint cell_x,cell_y; GtkTreePath * path; GtkTreeModel * model; if(event->button != 3) return FALSE; x = (gint)event->x; y = (gint)event->y; model = gtk_icon_view_get_model(GTK_ICON_VIEW(widget)); path = gtk_icon_view_get_path_at_pos(GTK_ICON_VIEW(widget), x, y); if(!path) return FALSE; gtk_icon_view_select_path(data->wp_view, path); gtk_icon_view_set_cursor(data->wp_view, path, NULL, FALSE); data->path = path; gtk_menu_popup(GTK_MENU(data->menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time()); return TRUE; }*/ static void wp_props_wp_selected (GtkTreeSelection *selection, AppearanceData *data) { UkuiWPItem *item; item = get_selected_item (data, NULL); if (item != NULL) { wp_set_sensitivities (data); if (strcmp (item->filename, "(none)") != 0) wp_option_menu_set (data, item->options, FALSE); GDBusConnection *bus; GError *error = NULL; const gchar *name = g_get_real_name(); bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM,NULL, &error); if (!bus) { g_warning("Failed to get session bus: %s", error->message); g_error_free(error); } g_dbus_connection_call (bus, "org.freedesktop.Accounts", "/org/freedesktop/Accounts", "org.freedesktop.Accounts", "FindUserByName", g_variant_new("(s)", name), G_VARIANT_TYPE("(o)"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, (GAsyncReadyCallback)setBackgroundInDbus, item->filename); wp_option_menu_set (data, item->shade_type, TRUE); wp_props_wp_set (data, item); } else { gtk_widget_set_sensitive (data->wp_rem_button, FALSE); } } void wp_create_filechooser (AppearanceData *data) { const char *start_dir, *pictures = NULL; GtkFileFilter *filter; data->wp_filesel = GTK_FILE_CHOOSER (gtk_file_chooser_dialog_new (_("Add Wallpaper"), GTK_WINDOW (appearance_capplet_get_widget (data, "appearance_window")), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL)); gtk_dialog_set_default_response (GTK_DIALOG (data->wp_filesel), GTK_RESPONSE_OK); gtk_window_set_skip_taskbar_hint(GTK_WINDOW (data->wp_filesel), TRUE); gtk_file_chooser_set_select_multiple (data->wp_filesel, TRUE); gtk_file_chooser_set_use_preview_label (data->wp_filesel, FALSE); start_dir = g_get_home_dir (); if (g_file_test ("/usr/share/backgrounds", G_FILE_TEST_IS_DIR)) { gtk_file_chooser_add_shortcut_folder (data->wp_filesel, "/usr/share/backgrounds", NULL); start_dir = "/usr/share/backgrounds"; } pictures = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES); if (pictures != NULL && g_file_test (pictures, G_FILE_TEST_IS_DIR)) { gtk_file_chooser_add_shortcut_folder (data->wp_filesel, pictures, NULL); start_dir = pictures; } gtk_file_chooser_set_current_folder (data->wp_filesel, start_dir); filter = gtk_file_filter_new (); gtk_file_filter_add_pixbuf_formats (filter); gtk_file_filter_set_name (filter, _("Image")); gtk_file_chooser_add_filter (data->wp_filesel, filter); filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, _("ALL File")); gtk_file_filter_add_pattern (filter, "*"); gtk_file_chooser_add_filter (data->wp_filesel, filter); data->wp_image = gtk_image_new (); gtk_file_chooser_set_preview_widget (data->wp_filesel, data->wp_image); gtk_widget_set_size_request (data->wp_image, 128, -1); gtk_widget_show (data->wp_image); g_signal_connect (data->wp_filesel, "update-preview", (GCallback) wp_update_preview, data); } static void wp_file_open_dialog (GtkWidget *widget, AppearanceData *data) { GSList *files; if (!data->wp_filesel) wp_create_filechooser (data); gtk_widget_set_name(GTK_WIDGET(data->wp_filesel), "ukuicc"); switch (gtk_dialog_run (GTK_DIALOG (data->wp_filesel))) { case GTK_RESPONSE_OK: files = gtk_file_chooser_get_filenames (data->wp_filesel); wp_add_images (data, files); case GTK_RESPONSE_CANCEL: default: gtk_widget_hide (GTK_WIDGET (data->wp_filesel)); break; } } static void wp_drag_received (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time, AppearanceData *data) { if (info == TARGET_URI_LIST || info == TARGET_BGIMAGE) { GSList *realuris = NULL; gchar **uris; uris = g_uri_list_extract_uris ((gchar *) gtk_selection_data_get_data (selection_data)); if (uris != NULL) { GtkWidget *w; GdkWindow *window; GdkCursor *cursor; gchar **uri; w = appearance_capplet_get_widget (data, "appearance_window"); window = gtk_widget_get_window (w); cursor = gdk_cursor_new_for_display (gdk_display_get_default (), GDK_WATCH); gdk_window_set_cursor (window, cursor); gdk_cursor_unref (cursor); for (uri = uris; *uri; ++uri) { GFile *f; f = g_file_new_for_uri (*uri); realuris = g_slist_append (realuris, g_file_get_path (f)); g_object_unref (f); } wp_add_images (data, realuris); gdk_window_set_cursor (window, NULL); g_strfreev (uris); } } } static void wp_drag_get_data (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint type, guint time, AppearanceData *data) { if (type == TARGET_URI_LIST) { UkuiWPItem *item = get_selected_item (data, NULL); if (item != NULL) { char *uris[2]; uris[0] = g_filename_to_uri (item->filename, NULL, NULL); uris[1] = NULL; gtk_selection_data_set_uris (selection_data, uris); g_free (uris[0]); } } } static gboolean wp_view_tooltip_cb (GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, AppearanceData *data) { GtkTreeIter iter; UkuiWPItem *item; if (gtk_icon_view_get_tooltip_context (data->wp_view, &x, &y, keyboard_mode, NULL, NULL, &iter)) { gtk_tree_model_get (data->wp_model, &iter, 1, &item, -1); gtk_tooltip_set_markup (tooltip, item->description); return TRUE; } return FALSE; } static gint wp_list_sort (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, AppearanceData *data) { UkuiWPItem *itema, *itemb; gint retval; gtk_tree_model_get (model, a, 1, &itema, -1); gtk_tree_model_get (model, b, 1, &itemb, -1); if (!strcmp (itema->filename, "(none)")) { retval = -1; } else if (!strcmp (itemb->filename, "(none)")) { retval = 1; } else { retval = g_utf8_collate (itema->description, itemb->description); } return retval; } static void wp_update_preview (GtkFileChooser *chooser, AppearanceData *data) { gchar *uri; uri = gtk_file_chooser_get_preview_uri (chooser); if (uri) { GdkPixbuf *pixbuf = NULL; const gchar *mime_type = NULL; GFile *file; GFileInfo *file_info; file = g_file_new_for_uri (uri); file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL); g_object_unref (file); if (file_info != NULL) { mime_type = g_file_info_get_content_type (file_info); g_object_unref (file_info); } if (mime_type) { pixbuf = mate_desktop_thumbnail_factory_generate_thumbnail (data->thumb_factory, uri, mime_type); } if (pixbuf != NULL) { gtk_image_set_from_pixbuf (GTK_IMAGE (data->wp_image), pixbuf); g_object_unref (pixbuf); } else { gtk_image_set_from_stock (GTK_IMAGE (data->wp_image), NULL, GTK_ICON_SIZE_DIALOG); } } gtk_file_chooser_set_preview_widget_active (chooser, TRUE); } static gboolean reload_item (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, AppearanceData *data) { UkuiWPItem *item; GdkPixbuf *pixbuf; gtk_tree_model_get (model, iter, 1, &item, -1); pixbuf = ukui_wp_item_get_thumbnail (item, data->thumb_factory, data->thumb_width, data->thumb_height); if (pixbuf) { gtk_list_store_set (GTK_LIST_STORE (data->wp_model), iter, 0, pixbuf, -1); g_object_unref (pixbuf); } return FALSE; } static gdouble get_monitor_aspect_ratio_for_widget (GtkWidget *widget) { gdouble aspect; gint monitor; GdkRectangle rect; monitor = gdk_screen_get_monitor_at_window (gtk_widget_get_screen (widget), gtk_widget_get_window (widget)); gdk_screen_get_monitor_geometry (gtk_widget_get_screen (widget), monitor, &rect); if (rect.width ==0) return 0; aspect = rect.height / (gdouble)rect.width; return aspect; } #define LIST_IMAGE_SIZE 140 static void compute_thumbnail_sizes (AppearanceData *data) { gdouble aspect; aspect = get_monitor_aspect_ratio_for_widget (GTK_WIDGET (data->wp_view)); //g_warning("aspect=%ld,thumb_width=%d, thumb_height=%d",(gint)aspect,data->thumb_width, data->thumb_height); if (aspect > 1) { /* portrait */ data->thumb_width = LIST_IMAGE_SIZE / aspect; data->thumb_height = LIST_IMAGE_SIZE; } else if(aspect <1 && aspect >0) { data->thumb_width = LIST_IMAGE_SIZE; data->thumb_height = LIST_IMAGE_SIZE * aspect; } else { g_warning("aspect is 0"); } } static void reload_wallpapers (AppearanceData *data) { compute_thumbnail_sizes (data); gtk_tree_model_foreach (data->wp_model, (GtkTreeModelForeachFunc)reload_item, data); } static void load_wallpaper_and_show_now(gchar * key, UkuiWPItem *item, AppearanceData *data) { wp_props_load_wallpaper(key, item, data); gtk_widget_queue_draw(data->wp_view); while(g_main_context_pending(NULL)) g_main_context_iteration(NULL,FALSE); } static gboolean wp_load_stuffs (void *user_data) { AppearanceData *data; gchar *imagepath, *uri, *style; UkuiWPItem *item; data = (AppearanceData *) user_data; compute_thumbnail_sizes (data); ukui_wp_xml_load_list (data); g_hash_table_foreach (data->wp_hash, (GHFunc) load_wallpaper_and_show_now, data); style = g_settings_get_string (data->wp_settings, WP_OPTIONS_KEY); if (style == NULL) style = g_strdup ("none"); uri = g_settings_get_string (data->wp_settings, WP_FILE_KEY); if (uri && *uri == '\0') { g_free (uri); uri = NULL; } if (uri == NULL) uri = g_strdup ("(none)"); if (g_utf8_validate (uri, -1, NULL) && g_file_test (uri, G_FILE_TEST_EXISTS)) imagepath = g_strdup (uri); else imagepath = g_filename_from_utf8 (uri, -1, NULL, NULL, NULL); g_free (uri); item = g_hash_table_lookup (data->wp_hash, imagepath); if (item != NULL) { /* update with the current gsettings */ ukui_wp_item_update (item); if (strcmp (style, "none") != 0) { if (item->deleted == TRUE) { item->deleted = FALSE; wp_props_load_wallpaper (item->filename, item, data); } select_item (data, item, FALSE); } } else if (strcmp (style, "none") != 0) { item = wp_add_image (data, imagepath); if (item) select_item (data, item, FALSE); } item = g_hash_table_lookup (data->wp_hash, "(none)"); if (item == NULL) { item = ukui_wp_item_new ("(none)", data->wp_hash, data->thumb_factory); if (item != NULL) { wp_props_load_wallpaper (item->filename, item, data); } } else { if (item->deleted == TRUE) { item->deleted = FALSE; wp_props_load_wallpaper (item->filename, item, data); } if (!strcmp (style, "none")) { select_item (data, item, FALSE); wp_option_menu_set (data, MATE_BG_PLACEMENT_SCALED, FALSE); } } g_free (imagepath); g_free (style); if (data->wp_uris) { wp_add_images (data, data->wp_uris); data->wp_uris = NULL; } return FALSE; } static void wp_select_after_realize (GtkWidget *widget, AppearanceData *data) { UkuiWPItem *item; g_idle_add (wp_load_stuffs, data); item = get_selected_item (data, NULL); if (item == NULL) item = g_hash_table_lookup (data->wp_hash, "(none)"); select_item (data, item, TRUE); } static GdkPixbuf *buttons[3]; static void create_button_images (AppearanceData *data) { GtkWidget *widget = (GtkWidget*)data->wp_view; GtkStyle *style = gtk_widget_get_style (widget); GtkIconSet *icon_set; GdkPixbuf *pixbuf, *pb, *pb2; gint i, w, h; icon_set = gtk_style_lookup_icon_set (style, "gtk-media-play"); pb = gtk_icon_set_render_icon (icon_set, style, GTK_TEXT_DIR_RTL, GTK_STATE_NORMAL, GTK_ICON_SIZE_MENU, widget, NULL); pb2 = gtk_icon_set_render_icon (icon_set, style, GTK_TEXT_DIR_LTR, GTK_STATE_NORMAL, GTK_ICON_SIZE_MENU, widget, NULL); w = gdk_pixbuf_get_width (pb); h = gdk_pixbuf_get_height (pb); for (i = 0; i < 3; i++) { pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 2 * w, h); gdk_pixbuf_fill (pixbuf, 0); if (i > 0) gdk_pixbuf_composite (pb, pixbuf, 0, 0, w, h, 0, 0, 1, 1, GDK_INTERP_NEAREST, 255); if (i < 2) gdk_pixbuf_composite (pb2, pixbuf, w, 0, w, h, w, 0, 1, 1, GDK_INTERP_NEAREST, 255); buttons[i] = pixbuf; } g_object_unref (pb); g_object_unref (pb2); } static void next_frame (AppearanceData *data, GtkCellRenderer *cr, gint direction) { UkuiWPItem *item; GtkTreeIter iter; GdkPixbuf *pixbuf, *pb; gint frame; pixbuf = NULL; frame = data->frame + direction; item = get_selected_item (data, &iter); if (frame >= 0) pixbuf = ukui_wp_item_get_frame_thumbnail (item, data->thumb_factory, data->thumb_width, data->thumb_height, frame); if (pixbuf) { gtk_list_store_set (GTK_LIST_STORE (data->wp_model), &iter, 0, pixbuf, -1); g_object_unref (pixbuf); data->frame = frame; } pb = buttons[1]; if (direction < 0) { if (frame == 0) pb = buttons[0]; } else { pixbuf = ukui_wp_item_get_frame_thumbnail (item, data->thumb_factory, data->thumb_width, data->thumb_height, frame + 1); if (pixbuf) g_object_unref (pixbuf); else pb = buttons[2]; } g_object_set (cr, "pixbuf", pb, NULL); } static gboolean wp_button_press_cb (GtkWidget *widget, GdkEventButton *event, AppearanceData *data) { GtkCellRenderer *cell; GdkEventButton *button_event = (GdkEventButton *) event; if (event->type != GDK_BUTTON_PRESS) return FALSE; if (gtk_icon_view_get_item_at_pos (GTK_ICON_VIEW (widget), button_event->x, button_event->y, NULL, &cell)) { if (g_object_get_data (G_OBJECT (cell), "buttons")) { gint w, h; GtkCellRenderer *cell2 = NULL; gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h); if (gtk_icon_view_get_item_at_pos (GTK_ICON_VIEW (widget), button_event->x + w, button_event->y, NULL, &cell2) && cell == cell2) next_frame (data, cell, -1); else next_frame (data, cell, 1); return TRUE; } } return FALSE; } static void wp_selected_changed_cb (GtkIconView *view, AppearanceData *data) { GtkCellRenderer *cr; GList *cells, *l; data->frame = -1; cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (data->wp_view)); for (l = cells; l; l = l->next) { cr = l->data; if (g_object_get_data (G_OBJECT (cr), "buttons")) g_object_set (cr, "pixbuf", buttons[0], NULL); } g_list_free (cells); } static void buttons_cell_data_func (GtkCellLayout *layout, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) { AppearanceData *data = user_data; GtkTreePath *path; UkuiWPItem *item; gboolean visible; path = gtk_tree_model_get_path (model, iter); if (gtk_icon_view_path_is_selected (GTK_ICON_VIEW (layout), path)) { item = get_selected_item (data, NULL); visible = mate_bg_changes_with_time (item->bg); } else visible = FALSE; g_object_set (G_OBJECT (cell), "visible", visible, NULL); gtk_tree_path_free (path); } static void screen_monitors_changed (GdkScreen *screen, AppearanceData *data) { reload_wallpapers (data); } void desktop_init (AppearanceData *data, const gchar **uris) { GtkWidget *add_button; GtkCellRenderer *cr; GtkMenuItem * menuitem; data->wp_uris = NULL; if (uris != NULL) { while (*uris != NULL) { data->wp_uris = g_slist_append (data->wp_uris, g_strdup (*uris)); uris++; } } data->wp_hash = g_hash_table_new (g_str_hash, g_str_equal); g_signal_connect (data->wp_settings, "changed::" WP_FILE_KEY, G_CALLBACK (wp_file_changed), data); g_signal_connect (data->wp_settings, "changed::" WP_OPTIONS_KEY, G_CALLBACK (wp_options_changed), data); g_signal_connect (data->wp_settings, "changed::" WP_SHADING_KEY, G_CALLBACK (wp_shading_changed), data); data->wp_model = GTK_TREE_MODEL (gtk_list_store_new (2, GDK_TYPE_PIXBUF, G_TYPE_POINTER)); data->wp_view = GTK_ICON_VIEW (appearance_capplet_get_widget (data, "wp_view")); gtk_icon_view_set_model (data->wp_view, GTK_TREE_MODEL (data->wp_model)); g_signal_connect_after (data->wp_view, "realize", (GCallback) wp_select_after_realize, data); gtk_cell_layout_clear (GTK_CELL_LAYOUT (data->wp_view)); cr = gtk_cell_renderer_pixbuf_new (); g_object_set (cr, "xpad", 3, "ypad", 3, NULL); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (data->wp_view), cr, TRUE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (data->wp_view), cr, "pixbuf", 0, NULL); cr = gtk_cell_renderer_pixbuf_new (); create_button_images (data); g_object_set (cr, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, "pixbuf", buttons[0], NULL); g_object_set_data (G_OBJECT (cr), "buttons", GINT_TO_POINTER (TRUE)); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (data->wp_view), cr, FALSE); gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (data->wp_view), cr, buttons_cell_data_func, data, NULL); g_signal_connect (data->wp_view, "selection-changed", (GCallback) wp_selected_changed_cb, data); g_signal_connect (data->wp_view, "button-press-event", G_CALLBACK (wp_button_press_cb), data); data->frame = -1; //gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (data->wp_model), 1, // (GtkTreeIterCompareFunc) wp_list_sort, // data, NULL); //gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (data->wp_model), // 1, GTK_SORT_ASCENDING); gtk_drag_dest_set (GTK_WIDGET (data->wp_view), GTK_DEST_DEFAULT_ALL, drop_types, G_N_ELEMENTS (drop_types), GDK_ACTION_COPY | GDK_ACTION_MOVE); g_signal_connect (data->wp_view, "drag_data_received", (GCallback) wp_drag_received, data); gtk_drag_source_set (GTK_WIDGET (data->wp_view), GDK_BUTTON1_MASK, drag_types, G_N_ELEMENTS (drag_types), GDK_ACTION_COPY); g_signal_connect (data->wp_view, "drag-data-get", (GCallback) wp_drag_get_data, data); data->wp_style_menu = appearance_capplet_get_widget (data, "wp_style_menu"); g_signal_connect (data->wp_style_menu, "changed", (GCallback) wp_scale_type_changed, data); add_button = appearance_capplet_get_widget (data, "wp_add_button"); gtk_button_set_image (GTK_BUTTON (add_button), gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_BUTTON)); g_signal_connect (add_button, "clicked", (GCallback) wp_file_open_dialog, data); data->wp_rem_button = appearance_capplet_get_widget (data, "wp_rem_button"); gtk_button_set_image (GTK_BUTTON(data->wp_rem_button), gtk_image_new_from_stock ("gtk-remove", GTK_ICON_SIZE_BUTTON)); g_signal_connect (data->wp_rem_button, "clicked", (GCallback) wp_remove_wallpaper, data); data->screen_monitors_handler = g_signal_connect (gtk_widget_get_screen (GTK_WIDGET (data->wp_view)), "monitors-changed", G_CALLBACK (screen_monitors_changed), data); data->screen_size_handler = g_signal_connect (gtk_widget_get_screen (GTK_WIDGET (data->wp_view)), "size-changed", G_CALLBACK (screen_monitors_changed), data); g_signal_connect (data->wp_view, "selection-changed", (GCallback) wp_props_wp_selected, data); g_signal_connect (data->wp_view, "query-tooltip", (GCallback) wp_view_tooltip_cb, data); //g_signal_connect (data->wp_view, "button-press-event", // (GCallback) right_click_cb, data); gtk_widget_set_has_tooltip (GTK_WIDGET (data->wp_view), TRUE); //init menu /*data->menu = gtk_menu_new(); gtk_widget_set_size_request(data->menu, 100,40); menuitem = gtk_menu_item_new_with_label(_("Delete Wallpaper")); gtk_menu_shell_append(GTK_MENU_SHELL(data->menu), menuitem); g_signal_connect(GTK_MENU_ITEM(menuitem), "activate", G_CALLBACK(remove_background), data); gtk_widget_show(menuitem); */ wp_set_sensitivities (data); /* create the file selector later to save time on startup */ data->wp_filesel = NULL; } void desktop_shutdown (AppearanceData *data) { ukui_wp_xml_save_list (data); if (data->screen_monitors_handler > 0) { g_signal_handler_disconnect (gtk_widget_get_screen (GTK_WIDGET (data->wp_view)), data->screen_monitors_handler); data->screen_monitors_handler = 0; } if (data->screen_size_handler > 0) { g_signal_handler_disconnect (gtk_widget_get_screen (GTK_WIDGET (data->wp_view)), data->screen_size_handler); data->screen_size_handler = 0; } g_slist_foreach (data->wp_uris, (GFunc) g_free, NULL); g_slist_free (data->wp_uris); if (data->wp_filesel) { g_object_ref_sink (data->wp_filesel); g_object_unref (data->wp_filesel); } } ukui-control-center/panels/appearance/Makefile.am0000664000175000017500000000172213245450075021035 0ustar fengfengcappletname=appearance noinst_LTLIBRARIES=libappearance.la AUTOMAKE_OPTIONS = foreign AM_CPPFLAGS = \ -DUIDIR="\"$(uidir)\"" \ @PACKAGE_CFLAGS@ \ -fPIC \ -I$(srcdir)/../../shell/ \ $(GLIB_CFLAGS) \ $(XFT_CFLAGS) \ $(LIBXML_CFLAGS) \ $(MATE_DESKTOP_CFLAGS) \ $(X11_CFLAGS) \ $(NULL) libappearance_la_SOURCES= \ appearance-main.c \ appearance-main.h \ appearance-desktop.h \ appearance-desktop.c \ appearance-theme.c \ appearance-theme.h \ ukui-wp-item.c \ ukui-wp-item.h \ ukui-wp-xml.c \ ukui-wp-xml.h \ ukui-wp-info.c \ ukui-wp-info.h \ appearance.h \ appearance-font.c \ appearance-font.h \ $(NULL) libappearance_la_LIBADD = \ @PACKAGE_LIBS@ \ $(GLIB_LIBS) \ $(XFT_LIBS) \ $(LIBXML_LIBS) \ $(MATE_DESKTOP_LIBS) \ $(X11_LIBS) \ -lcrypt \ $(NULL) libappearance_la_LDFLAGS = -export-dynamic @PACKAGE_LDFLAGS@ uidir = $(pkgdatadir)/ui ui_DATA = font_render.ui -include $(top_srcdir)/git.mk clean-local : rm -f *~ Makefile.in Makefile ukui-control-center/panels/appearance/ukui-wp-info.h0000664000175000017500000000254513253611037021504 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef _UKUI_WP_INFO_H_ #define _UKUI_WP_INFO_H_ #include #include #include #include #define MATE_DESKTOP_USE_UNSTABLE_API #include typedef struct _UkuiWPInfo { char* uri; char* thumburi; char* name; char* mime_type; goffset size; time_t mtime; } UkuiWPInfo; UkuiWPInfo* ukui_wp_info_new(const char* uri, MateDesktopThumbnailFactory* thumbs); void ukui_wp_info_free(UkuiWPInfo* info); #endif ukui-control-center/panels/appearance/ukui-wp-info.c0000664000175000017500000000454613253611037021502 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "ukui-wp-info.h" #include UkuiWPInfo* ukui_wp_info_new(const char* uri, MateDesktopThumbnailFactory* thumbs) { UkuiWPInfo* wp; GFile* file = g_file_new_for_commandline_arg(uri); GFileInfo* info = g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_SIZE "," G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, NULL); g_object_unref(file); if (info == NULL || g_file_info_get_content_type (info) == NULL) { if (!strcmp (uri, "(none)")) { wp = g_new0(UkuiWPInfo, 1); wp->mime_type = g_strdup("image/x-no-data"); wp->uri = g_strdup(uri); wp->name = g_strdup(gettext("No Desktop Background")); wp->size = 0; } else { wp = NULL; } } else { wp = g_new0 (UkuiWPInfo, 1); wp->uri = g_strdup(uri); wp->name = g_strdup(g_file_info_get_name(info)); if (g_file_info_get_content_type(info) != NULL) { wp->mime_type = g_strdup(g_file_info_get_content_type(info)); } wp->size = g_file_info_get_size(info); wp->mtime = g_file_info_get_attribute_uint64(info, G_FILE_ATTRIBUTE_TIME_MODIFIED); wp->thumburi = mate_desktop_thumbnail_factory_lookup(thumbs, uri, wp->mtime); } if (info != NULL) { g_object_unref(info); } return wp; } void ukui_wp_info_free(UkuiWPInfo* info) { if (info == NULL) { return; } g_free(info->uri); g_free(info->thumburi); g_free(info->name); g_free(info->mime_type); } ukui-control-center/panels/appearance/appearance-font.h0000664000175000017500000000171713057175444022226 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "appearance.h" void font_init(AppearanceData* data); void font_shutdown(AppearanceData* data); ukui-control-center/panels/appearance/appearance-main.c0000664000175000017500000000560513253611050022161 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "appearance-main.h" #include #include "appearance-desktop.h" #include "appearance-font.h" #include #include "appearance-theme.h" AppearanceData *data; void init_appearance_data(GtkBuilder * builder) { GtkWidget * appearance_notebook; data=NULL; data = g_new(AppearanceData, 1); data->wp_settings = g_settings_new(WP_SCHEMA); data->peony_settings = g_settings_new(PEONY_SCHEMA); data->interface_settings = g_settings_new (INTERFACE_SCHEMA); data->marco_settings = g_settings_new (MARCO_SCHEMA); data->font_settings=g_settings_new(FONT_RENDER_SCHEMA); data->ui = builder; appearance_notebook = GTK_WIDGET(gtk_builder_get_object(builder, "appearance_notebook")); //Fixme: I remove page2 and page3 to wait designer give me pointe,remove theme page // gtk_notebook_remove_page(GTK_NOTEBOOK(appearance_notebook), 2); //notice that when you remove page1, page2 become page1,so remove screensaver page gtk_notebook_remove_page(GTK_NOTEBOOK(appearance_notebook), 1); //remove page4 //gtk_notebook_remove_page(GTK_NOTEBOOK(appearance_notebook), 1); //设置gsetting,保证scolor和pcolor为黑色 //由于gsetting比较耗时,暂时注释 //g_settings_set_string(data->wp_settings, WP_PCOLOR_KEY, "#000000000000"); //g_settings_set_string(data->wp_settings, WP_SCOLOR_KEY, "#000000000000"); data->thumb_factory = mate_desktop_thumbnail_factory_new (MATE_DESKTOP_THUMBNAIL_SIZE_NORMAL); } void add_appearance_app(GtkBuilder *builder) { g_debug("appearance"); gchar ** wallpaper_files = NULL; init_appearance_data(builder); if (!data) return; desktop_init(data, (const gchar **)wallpaper_files); theme_init(data); font_init(data); g_strfreev(wallpaper_files); } void destory_appearance_app() { font_shutdown(data); desktop_shutdown(data); g_object_unref (data->thumb_factory); g_object_unref (data->wp_settings); g_object_unref (data->peony_settings); g_object_unref (data->interface_settings); g_object_unref (data->marco_settings); g_object_unref (data->font_settings); g_free(data); } ukui-control-center/panels/appearance/appearance-theme.c0000664000175000017500000001336513057175444022357 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "appearance-theme.h" #include #define theme_gtk(x,y) GTK_WIDGET(gtk_builder_get_object(x.builder, y)) #define COLOR_DIR "/usr/share/ukui-control-center/color" typedef struct _ThemeData ThemeData; struct _ThemeData { GtkBuilder * builder; GtkWidget * color_button_gray; GtkWidget * color_button_blue; GtkWidget * color_button_yellow; GtkWidget * color_button_red; GtkWidget * color_button_green; GtkWidget * color_button_green_jun; GtkWidget * color_button_purple; GtkWidget * color_button_lightblue; GtkWidget * color_button_orange; GSettings * theme_setting; GSettings * theme_gtk_setting; GtkWidget * appearance_show_label; }; ThemeData themedata; static gboolean mute_lock; static gboolean reset_lock(gpointer user_data){ mute_lock = TRUE; gtk_label_set_text(GTK_LABEL(themedata.appearance_show_label), _("Please choose a color that you like as the theme colors.")); return FALSE; } static void set_theme_color(GtkWidget * widget, GdkEvent *event, gpointer user_data){ int systemback; if(mute_lock){ mute_lock = FALSE; g_settings_set_string(themedata.theme_setting,MARCO_THEME_KEY, user_data); g_settings_set_string(themedata.theme_gtk_setting,GTK_THEME_KEY, user_data); // systemback = system("/usr/bin/killall mate-panel"); systemback = system("/usr/bin/nohup /usr/bin/mate-panel --replace &"); g_timeout_add(5000, (GSourceFunc)reset_lock, NULL); return; } gtk_label_set_text(GTK_LABEL(themedata.appearance_show_label), _("Set up disable. Please wait at least 5 seconds that system subject will restart")); } static void component_init(){ themedata.color_button_blue = theme_gtk(themedata, "color_button_blue"); gtk_button_set_image(themedata.color_button_blue, gtk_image_new_from_file(COLOR_DIR"/ukui-blue.png")); g_signal_connect(themedata.color_button_blue, "button-release-event", G_CALLBACK(set_theme_color), "ukui-theme"); themedata.color_button_gray = theme_gtk(themedata, "color_button_gray"); gtk_button_set_image(themedata.color_button_gray, gtk_image_new_from_file(COLOR_DIR"/ukui-gray.png")); g_signal_connect(themedata.color_button_gray, "button-release-event", G_CALLBACK(set_theme_color), "ukui-theme-black"); themedata.color_button_yellow = theme_gtk(themedata, "color_button_yellow"); gtk_button_set_image(themedata.color_button_yellow, gtk_image_new_from_file(COLOR_DIR"/ukui-yellow.png")); g_signal_connect(themedata.color_button_yellow, "button-release-event", G_CALLBACK(set_theme_color), "ukui-theme-yellow"); themedata.color_button_red = theme_gtk(themedata, "color_button_red"); gtk_button_set_image(themedata.color_button_red, gtk_image_new_from_file(COLOR_DIR"/ukui-red.png")); g_signal_connect(themedata.color_button_red, "button-release-event", G_CALLBACK(set_theme_color), "ukui-theme-red"); themedata.color_button_green = theme_gtk(themedata, "color_button_green"); gtk_button_set_image(themedata.color_button_green, gtk_image_new_from_file(COLOR_DIR"/ukui-green.png")); g_signal_connect(themedata.color_button_green, "button-release-event", G_CALLBACK(set_theme_color), "ukui-theme-green"); themedata.color_button_green_jun = theme_gtk(themedata, "color_button_green_jun"); gtk_button_set_image(themedata.color_button_green_jun, gtk_image_new_from_file(COLOR_DIR"/ukui-green-jun.png")); g_signal_connect(themedata.color_button_green_jun, "button-release-event", G_CALLBACK(set_theme_color), "ukui-theme-jun"); themedata.color_button_purple = theme_gtk(themedata, "color_button_purple"); gtk_button_set_image(themedata.color_button_purple, gtk_image_new_from_file(COLOR_DIR"/ukui-purple.png")); g_signal_connect(themedata.color_button_purple, "button-release-event", G_CALLBACK(set_theme_color), "ukui-theme-purple"); /*themedata.color_button_lightblue = theme_gtk(themedata, "color_button_lightblue"); gtk_button_set_image(themedata.color_button_lightblue, gtk_image_new_from_file(COLOR_DIR"/ukui-light-blue.png")); g_signal_connect(themedata.color_button_lightblue, "button-release-event", G_CALLBACK(set_theme_color), "ukui-light-blue"); */ themedata.color_button_orange = theme_gtk(themedata, "color_button_orange"); gtk_button_set_image(themedata.color_button_orange, gtk_image_new_from_file(COLOR_DIR"/ukui-orange.png")); g_signal_connect(themedata.color_button_orange, "button-release-event", G_CALLBACK(set_theme_color), "ukui-theme-orange"); themedata.appearance_show_label = theme_gtk(themedata, "appearance_show_label"); } static void load_current_theme(){ gchar * current_theme; current_theme = g_settings_get_string(themedata.theme_setting, MARCO_THEME_KEY); } void theme_init(AppearanceData * data) { themedata.builder = data->ui; themedata.theme_setting = data->marco_settings; themedata.theme_gtk_setting = data->interface_settings; mute_lock = TRUE; component_init(); load_current_theme(); } ukui-control-center/panels/appearance/ukui-wp-item.h0000664000175000017500000000540013253611037021500 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #define MATE_DESKTOP_USE_UNSTABLE_API #include #include "appearance.h" #include "ukui-wp-info.h" #ifndef _UKUI_WP_ITEM_H_ #define _UKUI_WP_ITEM_H_ typedef struct _UkuiWPItem UkuiWPItem; struct _UkuiWPItem { MateBG *bg; gchar * name; gchar * filename; gchar * description; MateBGPlacement options; MateBGColorType shade_type; /* Where the Item is in the List */ GtkTreeRowReference * rowref; /* Real colors */ GdkColor * pcolor; GdkColor * scolor; UkuiWPInfo * fileinfo; /* Did the user remove us? */ gboolean deleted; /* Wallpaper author, if present */ gchar *artist; /* Width and Height of the original image */ gint width; gint height; }; UkuiWPItem * ukui_wp_item_new (const gchar *filename, GHashTable *wallpapers, MateDesktopThumbnailFactory *thumbnails); void ukui_wp_item_free (UkuiWPItem *item); GdkPixbuf * ukui_wp_item_get_thumbnail (UkuiWPItem *item, MateDesktopThumbnailFactory *thumbs, gint width, gint height); GdkPixbuf * ukui_wp_item_get_frame_thumbnail (UkuiWPItem *item, MateDesktopThumbnailFactory *thumbs, gint width, gint height, gint frame); void ukui_wp_item_update (UkuiWPItem *item); void ukui_wp_item_update_description (UkuiWPItem *item); void ukui_wp_item_ensure_mate_bg (UkuiWPItem *item); const gchar *wp_item_option_to_string (MateBGPlacement type); const gchar *wp_item_shading_to_string (MateBGColorType type); MateBGPlacement wp_item_string_to_option (const gchar *option); MateBGColorType wp_item_string_to_shading (const gchar *shade_type); #endif ukui-control-center/panels/appearance/ukui-wp-xml.c0000664000175000017500000003646313253611050021345 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include "ukui-wp-xml.h" #include #define WALLPAPER_DATADIR "/usr/share/ukui-background-properties" #define UBUNTUUKUI_BACKGROUND "bionic-ubuntukylin-wallpapers.xml" static gboolean ukui_wp_xml_get_bool(const xmlNode* parent, const char* prop_name) { gboolean ret_val = FALSE; if (parent != NULL && prop_name != NULL) { xmlChar* prop = xmlGetProp((xmlNode*) parent, (xmlChar*) prop_name); if (prop != NULL) { if (!g_ascii_strcasecmp((char*) prop, "true") || !g_ascii_strcasecmp((char*) prop, "1")) { ret_val = TRUE; } else { ret_val = FALSE; } g_free(prop); } } return ret_val; } static void ukui_wp_xml_set_bool(const xmlNode* parent, const xmlChar* prop_name, gboolean value) { if (parent != NULL && prop_name != NULL) { if (value) { xmlSetProp((xmlNode*) parent, prop_name, (xmlChar*) "true"); } else { xmlSetProp((xmlNode*) parent, prop_name, (xmlChar*) "false"); } } } static void ukui_wp_load_legacy(AppearanceData* data) { /* Legacy of GNOME2 * ~/.gnome2/wallpapers.list */ char* filename = g_build_filename(g_get_home_dir(), ".gnome2", "wallpapers.list", NULL); if (g_file_test(filename, G_FILE_TEST_EXISTS)) { FILE* fp; if ((fp = fopen(filename, "r")) != NULL) { char* foo = (char*) g_malloc(sizeof(char) * 4096); while (fgets(foo, 4096, fp)) { UkuiWPItem * item; if (foo[strlen(foo) - 1] == '\n') { foo[strlen(foo) - 1] = '\0'; } item = g_hash_table_lookup(data->wp_hash, foo); if (item != NULL) { continue; } if (!g_file_test(foo, G_FILE_TEST_EXISTS)) { continue; } item = ukui_wp_item_new(foo, data->wp_hash, data->thumb_factory); if (item != NULL && item->fileinfo == NULL) { ukui_wp_item_free(item); } } fclose(fp); g_free(foo); } } g_free(filename); } static void ukui_wp_xml_load_xml(AppearanceData* data, const char* filename) { xmlDoc* wplist; xmlNode* root; xmlNode* list; xmlNode* wpa; xmlChar* nodelang; const char* const* syslangs; GdkColor color1; GdkColor color2; gint i; wplist = xmlParseFile(filename); if (!wplist) { return; } syslangs = g_get_language_names(); root = xmlDocGetRootElement(wplist); for (list = root->children; list != NULL; list = list->next) { if (!strcmp((char*) list->name, "wallpaper")) { UkuiWPItem * wp; char *pcolor = NULL, *scolor = NULL; gboolean have_scale = FALSE, have_shade = FALSE, have_artist = FALSE; wp = g_new0(UkuiWPItem, 1); wp->deleted = ukui_wp_xml_get_bool(list, "deleted"); for (wpa = list->children; wpa != NULL; wpa = wpa->next) { if (wpa->type == XML_COMMENT_NODE) { continue; } else if (!strcmp ((char*) wpa->name, "filename")) { if (wpa->last != NULL && wpa->last->content != NULL) { const char* none = "(none)"; char* content = g_strstrip((char*) wpa->last->content); if (!strcmp (content, none)) { wp->filename = g_strdup (content); } else if (g_utf8_validate (content, -1, NULL) && g_file_test (content, G_FILE_TEST_EXISTS)) { wp->filename = g_strdup (content); } else { wp->filename = g_filename_from_utf8 (content, -1, NULL, NULL, NULL); } } else { break; } } else if (!strcmp ((char*) wpa->name, "name")) { if (wpa->last != NULL && wpa->last->content != NULL) { nodelang = xmlNodeGetLang (wpa->last); if (wp->name == NULL && nodelang == NULL) { wp->name = g_strdup (g_strstrip ((char *)wpa->last->content)); } else { for (i = 0; syslangs[i] != NULL; i++) { if (!strcmp (syslangs[i], (char *)nodelang)) { g_free (wp->name); wp->name = g_strdup (g_strstrip ((char*) wpa->last->content)); break; } } } xmlFree (nodelang); } else { break; } } else if (!strcmp ((char*) wpa->name, "options")) { if (wpa->last != NULL) { wp->options = wp_item_string_to_option(g_strstrip ((char *)wpa->last->content)); have_scale = TRUE; } } else if (!strcmp ((char*) wpa->name, "shade_type")) { if (wpa->last != NULL) { wp->shade_type = wp_item_string_to_shading(g_strstrip ((char *)wpa->last->content)); have_shade = TRUE; } } else if (!strcmp ((char*) wpa->name, "pcolor")) { if (wpa->last != NULL) { //pcolor = g_strdup(g_strstrip ((char *)wpa->last->content)); pcolor = "#000000000000"; } } else if (!strcmp ((char*) wpa->name, "scolor")) { if (wpa->last != NULL) { //scolor = g_strdup(g_strstrip ((char *)wpa->last->content)); scolor = "#000000000000"; } } else if (!strcmp ((char*) wpa->name, "artist")) { if (wpa->last != NULL) { wp->artist = g_strdup (g_strstrip ((char *)wpa->last->content)); have_artist = TRUE; } } else if (!strcmp ((char*) wpa->name, "text")) { /* Do nothing here, libxml2 is being weird */ } else { g_warning ("Unknown Tag: %s", wpa->name); } } /* Make sure we don't already have this one and that filename exists */ if (wp->filename == NULL || g_hash_table_lookup (data->wp_hash, wp->filename) != NULL) { ukui_wp_item_free (wp); //g_free (pcolor); //g_free (scolor); continue; } /* Verify the colors and alloc some GdkColors here */ if (!have_scale) { wp->options = g_settings_get_enum(data->wp_settings, WP_OPTIONS_KEY); } if (!have_shade) { wp->shade_type = g_settings_get_enum(data->wp_settings, WP_SHADING_KEY); } if (pcolor == NULL) { //pcolor = g_settings_get_string(data->wp_settings, WP_PCOLOR_KEY); pcolor = "#000000000000"; } if (scolor == NULL) { //scolor = g_settings_get_string (data->wp_settings, WP_SCOLOR_KEY); scolor = "#000000000000"; } if (!have_artist) { wp->artist = g_strdup ("(none)"); } gdk_color_parse(pcolor, &color1); gdk_color_parse(scolor, &color2); //g_free(pcolor); //g_free(scolor); wp->pcolor = gdk_color_copy(&color1); wp->scolor = gdk_color_copy(&color2); if ((wp->filename != NULL && g_file_test (wp->filename, G_FILE_TEST_EXISTS)) || !strcmp (wp->filename, "(none)")) { wp->fileinfo = ukui_wp_info_new(wp->filename, data->thumb_factory); if (wp->name == NULL || !strcmp(wp->filename, "(none)")) { g_free (wp->name); wp->name = g_strdup (wp->fileinfo->name); } ukui_wp_item_ensure_mate_bg (wp); ukui_wp_item_update_description (wp); g_hash_table_insert (data->wp_hash, wp->filename, wp); } else { ukui_wp_item_free(wp); wp = NULL; } } } xmlFreeDoc(wplist); } static void ukui_wp_file_changed(GFileMonitor* monitor, GFile* file, GFile* other_file, GFileMonitorEvent event_type, AppearanceData* data) { char* filename; switch (event_type) { case G_FILE_MONITOR_EVENT_CHANGED: case G_FILE_MONITOR_EVENT_CREATED: filename = g_file_get_path(file); ukui_wp_xml_load_xml(data, filename); g_free(filename); break; default: break; } } static void ukui_wp_xml_add_monitor(GFile* directory, AppearanceData* data) { GError* error = NULL; GFileMonitor* monitor = g_file_monitor_directory(directory, G_FILE_MONITOR_NONE, NULL, &error); if (error != NULL) { char* path = g_file_get_parse_name (directory); g_warning("Unable to monitor directory %s: %s", path, error->message); g_error_free(error); g_free(path); return; } g_signal_connect(monitor, "changed", G_CALLBACK(ukui_wp_file_changed), data); } static void ukui_wp_xml_load_from_dir(const char* path, AppearanceData* data) { GFile * directory; if (!g_file_test(path, G_FILE_TEST_IS_DIR)) { return; } directory = g_file_new_for_path(path); char* fullpath = g_build_filename(path, UBUNTUUKUI_BACKGROUND, NULL); ukui_wp_xml_load_xml(data, fullpath); g_free(fullpath); ukui_wp_xml_add_monitor(directory, data); } void ukui_wp_xml_load_list(AppearanceData* data) { char* wpdbfile; gint i; #if GLIB_CHECK_VERSION(2, 6, 0) wpdbfile = g_build_filename(g_get_user_config_dir(), "ukui", "backgrounds.xml", NULL); #else // glib version < 2.6.0 wpdbfile = g_build_filename(g_get_home_dir(), ".config", "ukui", "backgrounds.xml", NULL); #endif if (g_file_test(wpdbfile, G_FILE_TEST_EXISTS)) { ukui_wp_xml_load_xml(data, wpdbfile); g_free (wpdbfile); return; } g_free (wpdbfile); ukui_wp_xml_load_from_dir(WALLPAPER_DATADIR, data); ukui_wp_load_legacy(data); } static void ukui_wp_list_flatten(const char* key, UkuiWPItem* item, GSList** list) { if (key != NULL && item != NULL) { *list = g_slist_prepend(*list, item); } } void ukui_wp_xml_save_list(AppearanceData* data) { xmlDoc* wplist; xmlNode* root; xmlNode* wallpaper; //xmlNode* item; GSList* list = NULL; char* wpfile; g_hash_table_foreach(data->wp_hash, (GHFunc) ukui_wp_list_flatten, &list); g_hash_table_destroy(data->wp_hash); list = g_slist_reverse(list); #if GLIB_CHECK_VERSION(2, 6, 0) wpfile = g_build_filename(g_get_user_config_dir(), "ukui", "backgrounds.xml", NULL); #else // glib version < 2.6.0 wpfile = g_build_filename(g_get_home_dir(), ".config", "ukui", "backgrounds.xml", NULL); #endif xmlKeepBlanksDefault(0); wplist = xmlNewDoc((xmlChar*) "1.0"); xmlCreateIntSubset(wplist, (xmlChar*) "wallpapers", NULL, (xmlChar*) "ukui-wp-list.dtd"); root = xmlNewNode(NULL, (xmlChar*) "wallpapers"); xmlDocSetRootElement(wplist, root); while (list != NULL) { UkuiWPItem* wpitem = list->data; const char* none = "(none)"; char* filename; const char* scale; const char* shade; char* pcolor; char* scolor; if (!strcmp(wpitem->filename, none) || (g_utf8_validate(wpitem->filename, -1, NULL) && g_file_test(wpitem->filename, G_FILE_TEST_EXISTS))) { filename = g_strdup(wpitem->filename); } else { filename = g_filename_to_utf8(wpitem->filename, -1, NULL, NULL, NULL); } pcolor = gdk_color_to_string(wpitem->pcolor); scolor = gdk_color_to_string(wpitem->scolor); scale = wp_item_option_to_string(wpitem->options); shade = wp_item_shading_to_string(wpitem->shade_type); wallpaper = xmlNewChild(root, NULL, (xmlChar*) "wallpaper", NULL); ukui_wp_xml_set_bool(wallpaper, (xmlChar*) "deleted", wpitem->deleted); xmlNewTextChild(wallpaper, NULL, (xmlChar*) "name", (xmlChar*) wpitem->name); xmlNewTextChild(wallpaper, NULL, (xmlChar*) "filename", (xmlChar*) filename); xmlNewTextChild(wallpaper, NULL, (xmlChar*) "options", (xmlChar*) scale); xmlNewTextChild(wallpaper, NULL, (xmlChar*) "shade_type", (xmlChar*) shade); xmlNewTextChild(wallpaper, NULL, (xmlChar*) "pcolor", (xmlChar*) pcolor); xmlNewTextChild(wallpaper, NULL, (xmlChar*) "scolor", (xmlChar*) scolor); xmlNewTextChild(wallpaper, NULL, (xmlChar*) "artist", (xmlChar*) wpitem->artist); //g_free(pcolor); //g_free(scolor); g_free(filename); list = g_slist_delete_link(list, list); ukui_wp_item_free(wpitem); } /* Guardamos el archivo, solo si hay nodos en */ if (xmlChildElementCount(root) > 0) { xmlSaveFormatFile(wpfile, wplist, 1); } xmlFreeDoc(wplist); g_free(wpfile); } ukui-control-center/panels/appearance/appearance-main.h0000664000175000017500000000200713057175444022175 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef _APPEARANCE_MAIN_H #define _APPEARANCE_MAIN_H #include void add_appearance_app(GtkBuilder *builder); void destory_appearance_app(); #endif ukui-control-center/panels/appearance/font_render.ui0000644000175000017500000012230413111751271021635 0ustar fengfeng False 5 Font Rendering Details False dialog True False 2 True False end gtk-close True True True False True False False 1 True True end 0 True False 5 vertical 18 True False 0 0 True False 12 True False R_esolution: True dpi_spinner False False 0 True False 6 True True False False 1 True False 1 True False dots per inch False False 2 False False 1 False False 0 True False vertical True False Smoothing False False 0 True False 6 12 True False 6 12 True True False vertical 3 _None True True False True True True False False 0 True False True False True True 1 0 0 True False vertical 3 Gra_yscale True True False True True antialias_none_radio False False 0 True False True False True True 1 1 0 True False vertical 3 Sub_pixel (LCDs) True True False True True antialias_none_radio False False 0 True False True False True True 1 0 1 True True 1 True True 1 True False vertical True False _Slight True False False 0 True False 6 12 True False 6 12 True True False vertical 3 N_one True True False True True True False False 0 True False True False True True 1 0 0 True False vertical 3 _Slight True True False True True hint_none_radio False False 0 True False True False True True 1 1 0 True False vertical 3 _Medium True True False True True hint_none_radio False False 0 True False True False True True 1 0 1 True False vertical 3 _Full True True False True True hint_none_radio False False 0 True False True False True True 1 1 1 True True 1 True True 2 True False vertical True False Subpixel Order False False 0 True False 6 12 True False 6 12 True True False _RGB True True False True True True True True 0 True False gtk-missing-image False False 1 0 0 True False _BGR True True False True True subpixel_rgb_radio True True 0 True False gtk-missing-image False False 1 1 0 True False _VRGB True True False True True subpixel_rgb_radio True True 0 True False gtk-missing-image False False 1 0 1 True False VB_GR True True False True True subpixel_rgb_radio True True 0 True False gtk-missing-image False False 1 1 1 True True 1 True True 3 True True 1 button3 ukui-control-center/panels/appearance/ukui-wp-item.c0000664000175000017500000002220613253611037021476 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include "ukui-wp-item.h" const gchar *wp_item_option_to_string (MateBGPlacement type) { switch (type) { case MATE_BG_PLACEMENT_CENTERED: return "centered"; break; case MATE_BG_PLACEMENT_FILL_SCREEN: return "stretched"; break; case MATE_BG_PLACEMENT_SCALED: return "scaled"; break; case MATE_BG_PLACEMENT_ZOOMED: return "zoom"; break; case MATE_BG_PLACEMENT_TILED: return "wallpaper"; break; case MATE_BG_PLACEMENT_SPANNED: return "spanned"; break; } return ""; } const gchar *wp_item_shading_to_string (MateBGColorType type) { switch (type) { case MATE_BG_COLOR_SOLID: return "solid"; break; case MATE_BG_COLOR_H_GRADIENT: return "horizontal-gradient"; break; case MATE_BG_COLOR_V_GRADIENT: return "vertical-gradient"; break; } return ""; } MateBGPlacement wp_item_string_to_option (const gchar *option) { if (!g_strcmp0(option, "centered")) return MATE_BG_PLACEMENT_CENTERED; else if (!g_strcmp0(option, "stretched")) return MATE_BG_PLACEMENT_FILL_SCREEN; else if (!g_strcmp0(option, "scaled")) return MATE_BG_PLACEMENT_SCALED; else if (!g_strcmp0(option, "zoom")) return MATE_BG_PLACEMENT_ZOOMED; else if (!g_strcmp0(option, "wallpaper")) return MATE_BG_PLACEMENT_TILED; else if (!g_strcmp0(option, "spanned")) return MATE_BG_PLACEMENT_SPANNED; else return MATE_BG_PLACEMENT_SCALED; } MateBGColorType wp_item_string_to_shading (const gchar *shade_type) { if (!g_strcmp0(shade_type, "solid")) return MATE_BG_COLOR_SOLID; else if (!g_strcmp0(shade_type, "horizontal-gradient")) return MATE_BG_COLOR_H_GRADIENT; else if (!g_strcmp0(shade_type, "vertical-gradient")) return MATE_BG_COLOR_V_GRADIENT; else return MATE_BG_COLOR_SOLID; } static void set_bg_properties (UkuiWPItem *item) { if (item->filename) mate_bg_set_filename (item->bg, item->filename); mate_bg_set_color (item->bg, item->shade_type, item->pcolor, item->scolor); mate_bg_set_placement (item->bg, item->options); } void ukui_wp_item_ensure_mate_bg (UkuiWPItem *item) { if (!item->bg) { item->bg = mate_bg_new (); set_bg_properties (item); } } void ukui_wp_item_update (UkuiWPItem *item) { GSettings *settings; GdkColor color1 = { 0, 0, 0, 0 }, color2 = { 0, 0, 0, 0 }; gchar *s; settings = g_settings_new (WP_SCHEMA); item->options = g_settings_get_enum (settings, WP_OPTIONS_KEY); item->shade_type = g_settings_get_enum (settings, WP_SHADING_KEY); s = g_settings_get_string (settings, WP_PCOLOR_KEY); if (s != NULL) { gdk_color_parse (s, &color1); g_free (s); } s = g_settings_get_string (settings, WP_SCOLOR_KEY); if (s != NULL) { gdk_color_parse (s, &color2); g_free (s); } g_object_unref (settings); /*if (item->pcolor != NULL) gdk_color_free (item->pcolor); if (item->scolor != NULL) gdk_color_free (item->scolor); */ item->pcolor = gdk_color_copy (&color1); item->scolor = gdk_color_copy (&color2); } UkuiWPItem *ukui_wp_item_new (const gchar * filename, GHashTable * wallpapers, MateDesktopThumbnailFactory * thumbnails) { UkuiWPItem *item = g_new0 (UkuiWPItem, 1); item->filename = g_strdup (filename); item->fileinfo = ukui_wp_info_new (filename, thumbnails); if (item->fileinfo != NULL && item->fileinfo->mime_type != NULL && (g_str_has_prefix (item->fileinfo->mime_type, "image/") || strcmp (item->fileinfo->mime_type, "application/xml") == 0)) { if (g_utf8_validate (item->fileinfo->name, -1, NULL)) item->name = g_strdup (item->fileinfo->name); else item->name = g_filename_to_utf8 (item->fileinfo->name, -1, NULL, NULL, NULL); ukui_wp_item_update (item); ukui_wp_item_ensure_mate_bg (item); ukui_wp_item_update_description (item); g_hash_table_insert (wallpapers, item->filename, item); } else { ukui_wp_item_free (item); item = NULL; } return item; } void ukui_wp_item_free (UkuiWPItem * item) { if (item == NULL) { return; } g_free (item->name); g_free (item->filename); g_free (item->description); /*if (item->pcolor != NULL) gdk_color_free (item->pcolor); if (item->scolor != NULL) gdk_color_free (item->scolor); */ ukui_wp_info_free (item->fileinfo); if (item->bg) g_object_unref (item->bg); gtk_tree_row_reference_free (item->rowref); g_free (item); } static GdkPixbuf *add_slideshow_frame (GdkPixbuf *pixbuf) { GdkPixbuf *sheet, *sheet2; GdkPixbuf *tmp; gint w, h; w = gdk_pixbuf_get_width (pixbuf); h = gdk_pixbuf_get_height (pixbuf); sheet = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, w, h); gdk_pixbuf_fill (sheet, 0x00000000); sheet2 = gdk_pixbuf_new_subpixbuf (sheet, 1, 1, w - 2, h - 2); gdk_pixbuf_fill (sheet2, 0xffffffff); g_object_unref (sheet2); tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, w + 6, h + 6); gdk_pixbuf_fill (tmp, 0x00000000); gdk_pixbuf_composite (sheet, tmp, 6, 6, w, h, 6.0, 6.0, 1.0, 1.0, GDK_INTERP_NEAREST, 255); gdk_pixbuf_composite (sheet, tmp, 3, 3, w, h, 3.0, 3.0, 1.0, 1.0, GDK_INTERP_NEAREST, 255); gdk_pixbuf_composite (pixbuf, tmp, 0, 0, w, h, 0.0, 0.0, 1.0, 1.0, GDK_INTERP_NEAREST, 255); g_object_unref (sheet); return tmp; } GdkPixbuf * ukui_wp_item_get_frame_thumbnail (UkuiWPItem * item, MateDesktopThumbnailFactory * thumbs, int width, int height, gint frame) { GdkPixbuf *pixbuf = NULL; set_bg_properties (item); if (frame != -1) pixbuf = mate_bg_create_frame_thumbnail (item->bg, thumbs, gdk_screen_get_default (), width, height, frame); else pixbuf = mate_bg_create_thumbnail (item->bg, thumbs, gdk_screen_get_default(), width, height); if (pixbuf && mate_bg_changes_with_time (item->bg)) { GdkPixbuf *tmp; tmp = add_slideshow_frame (pixbuf); g_object_unref (pixbuf); pixbuf = tmp; } mate_bg_get_image_size (item->bg, thumbs, width, height, &item->width, &item->height); return pixbuf; } GdkPixbuf * ukui_wp_item_get_thumbnail (UkuiWPItem * item, MateDesktopThumbnailFactory * thumbs, gint width, gint height) { return ukui_wp_item_get_frame_thumbnail (item, thumbs, width, height, -1); } void ukui_wp_item_update_description (UkuiWPItem * item) { g_free (item->description); if (!strcmp (item->filename, "(none)")) { item->description = g_strdup (item->name); } else { const gchar *description; gchar *size; gchar *dirname = g_path_get_dirname (item->filename); gchar *artist; description = NULL; size = NULL; if (!item->artist || item->artist[0] == 0 || !g_strcmp0(item->artist, "(none)")) artist = g_strdup ("unknown"); else artist = g_strdup (item->artist); if (strcmp (item->fileinfo->mime_type, "application/xml") == 0) { if (mate_bg_changes_with_time (item->bg)) description = "Slide Show"; else if (item->width > 0 && item->height > 0) description = "Image"; } else description = g_content_type_get_description (item->fileinfo->mime_type); if (mate_bg_has_multiple_sizes (item->bg)) size = g_strdup ("multiple sizes"); else if (item->width > 0 && item->height > 0) { /* translators: x pixel(s) by y pixel(s) */ size = g_strdup_printf ("%d %s * %d %s", item->width, ngettext ("pixel", "pixels", item->width), item->height, ngettext ("pixel", "pixels", item->height)); } if (description && size) { /* translators: wallpaper name * mime type, size * Folder: /path/to/file * Artist: wallpaper author */ item->description = g_markup_printf_escaped (_("%s\n" "%s, %s\n" "File Path: %s\n" "Artist: %s"), item->name, description, size, dirname, artist); } else { /* translators: wallpaper name * Image missing * Folder: /path/to/file * Artist: wallpaper author */ item->description = g_markup_printf_escaped (_("%s\n" "%s\n" "File Path: %s\n" "Artist: %s"), item->name, "Image missing", dirname, artist); } g_free (size); g_free (dirname); g_free (artist); } } ukui-control-center/panels/appearance/appearance-font.c0000644000175000017500000005757013263623274022225 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "appearance-font.h" #include #include #include #include #include #include #include #include #define N 3 /* 设置字体,每套字体包括5个部件,应用程序字体、文档字体、等宽字体、桌面字体 和窗口标题字体。 字体设置为预设值,每套字体除大小不固定,其他字体类别固定。 目前有 ubuntu字体,分别为"ubuntu" "sans" "ubuntu mono" "' '" "ubuntu Bold" mate字体,分别为"ubuntu" "ubuntu" "ubuntu mono" "sans" "ubuntu Bold" ukui字体,分别为"ubuntu","ubuntu","ubuntu mono","ubuntu","ubuntu medium" */ typedef struct _FontSetting FontSetting; struct _FontSetting { GtkWidget * radiobutton; GtkWidget * font_select_combo; GtkBuilder * builder; GtkWidget * small_radio_button; GtkWidget * middle_radio_button; GtkWidget * large_radio_button; GtkWidget * monochrome_button; GtkWidget * monochrome_sample; GtkWidget * best_shapes_button; GtkWidget * best_shapes_sample; GtkWidget * best_contrast_button; GtkWidget * best_contrast_sample; GtkWidget * subpixel_button; GtkWidget * subpixel_sample; //current font info gint size; gchar * font_name; float middle; float small; float large; float level; //gsettings GSettings * g_interface; GSettings * g_marco; GSettings * g_peony; }; FontSetting fontsetting; gint default_font; gint default_document_font; gint default_monospace_font; gint default_peony_font; gint default_title_font; //for example, mate typedef struct _FontInfo FontInfo; struct _FontInfo{ char * font_type; //like ubuntu or mate char * font_name; // org.mate.interface font-name char * document_font_name; //org.mate.interface document-font-name char * monospace_font_name; //org.mate.interface monospace-font-name char * font; //org.mate.peony.desktop font char * titlebar_font; //org.mate.Marco.general }; //fill struct FontInfo fontinfo[N] = { {"Ubuntu", "Ubuntu", "Sans", "Ubuntu Mono", " ", "Ubuntu Bold"}, {"Mate", "Ubuntu", "Ubuntu", "Ubuntu Mono", "Sans", "Ubuntu Bold"}, {"Ukui", "Ubuntu", "Ubuntu", "Ubuntu Mono", "Ubuntu", "Ubuntu Medium"} }; typedef enum{ ANTIALIAS_NONE, ANTIALIAS_GRAYSCALE, ANTIALIAS_RGBA }Antialiasing; typedef enum{ HINT_NONE, HINT_SLIGHT, HINT_MEDIUM, HINT_FULL }Hinting; typedef enum{ RGBA_RGB, RGBA_BGR, RGBA_VRGB, RGBA_VBGR }RgbaOrder; typedef struct{ Antialiasing antialiasing; Hinting hinting; GtkButton * button; }FontPair; static GSList * font_pairs = NULL; static void font_select_changed(GtkComboBox *widget, gpointer user_data); /*static void setup_combotext_data(){ gint i; PangoFontFamily ** families; gint n_families; PangoFontMap * fontmap; fontmap = pango_cairo_font_map_get_default(); pango_font_map_list_families(fontmap, & families, & n_families); for (i =0; ifontsetting.middle){ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fontsetting.large_radio_button), TRUE); fontsetting.level = fontsetting.large; } treemodel = gtk_combo_box_get_model(GTK_COMBO_BOX(fontsetting.font_select_combo)); valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(treemodel),&iter); while (valid){ gtk_tree_model_get(treemodel, &iter,0, &name, -1); if (g_strcmp0(name, fontsetting.font_name) == 0){ g_signal_handlers_block_by_func(fontsetting.font_select_combo, font_select_changed, NULL); gtk_combo_box_set_active_iter(GTK_COMBO_BOX(fontsetting.font_select_combo), &iter); g_signal_handlers_unblock_by_func(fontsetting.font_select_combo, font_select_changed, NULL); valid = FALSE; } else { valid = gtk_tree_model_iter_next(treemodel, &iter); } } g_free(name); } static void get_default_setting(AppearanceData *data){ GVariant * value; char * font_value; gsize size; gint length; value = g_settings_get_default_value(data->interface_settings, DOCUMENT_FONT_KEY); size = g_variant_get_size (value); font_value = g_variant_get_string(value, &size); length = (gint)strlen(font_value); if (font_value[length -2] == ' '){ default_document_font = atoi(&font_value[length -1]); } else { default_document_font = atoi(&font_value[length -2]); } g_variant_unref(value); value = g_settings_get_default_value(data->interface_settings, GTK_FONT_KEY); size = g_variant_get_size(value); font_value = g_variant_get_string(value, &size); length = (gint)strlen(font_value); if (font_value[length -2] == ' ') default_font = atoi(&font_value[length -1]); else default_font = atoi(&font_value[length -2]); g_variant_unref(value); value = g_settings_get_default_value(data->interface_settings, MONOSPACE_FONT_KEY); size = g_variant_get_size(value); font_value = g_variant_get_string(value, &size); length = (gint)strlen(font_value); if (font_value[length -2] == ' ') default_monospace_font = atoi(&font_value[length -1]); else default_monospace_font = atoi(&font_value[length -2]); g_variant_unref(value); value = g_settings_get_default_value(data->peony_settings, DESKTOP_FONT_KEY); size = g_variant_get_size(value); font_value = g_variant_get_string(value, &size); length = (gint)strlen(font_value); if (font_value[length -2] == ' ') default_peony_font = atoi(&font_value[length -1]); else default_peony_font = atoi(&font_value[length -2]); g_variant_unref(value); value = g_settings_get_default_value(data->marco_settings, WINDOW_TITLE_FONT_KEY); size = g_variant_get_size(value); font_value = g_variant_get_string(value, &size); length = (gint)strlen(font_value); if (font_value[length -2] == ' ') default_title_font = atoi(&font_value[length -1]); else default_title_font = atoi(&font_value[length -2]); g_variant_unref(value); } static void sample_size_request(GtkWidget * darea, GtkRequisition * requisition){ // GdkPixbuf * pixbuf = g_object_get_data(G_OBJECT(darea), "sample-pixbuf"); // requisition->width = gdk_pixbuf_get_width(pixbuf) + 2; // requisition->height = gdk_pixbuf_get_height(pixbuf) + 2; } static void sample_expose(GtkWidget * darea, GdkEventExpose *expose){ // GtkAllocation allocation; // GdkPixbuf * pixbuf = g_object_get_data(G_OBJECT(darea), "sample-pixbuf"); // GdkWindow *window = gtk_widget_get_window(darea); // GtkStyle * style = gtk_widget_get_style(darea); // int width = gdk_pixbuf_get_width(pixbuf); // int height = gdk_pixbuf_get_height(pixbuf); // gtk_widget_get_allocation(darea, &allocation); // int x = (allocation.width - width) /2; // int y = (allocation.height- height) /2; // gdk_draw_rectangle(window, style->white_gc, TRUE, 0,0,allocation.width, allocation.height); // gdk_draw_rectangle(window, style->black_gc, FALSE,0,0,allocation.width -1, allocation.height -1); // gdk_draw_pixbuf(window, NULL, pixbuf, 0,0,x,y,width, height, GDK_RGB_DITHER_NORMAL,0,0); // gtk_widget_show(darea); } static XftFont *open_pattern(FcPattern *pattern, Antialiasing antialiasing, Hinting hinting){ FcPattern * res_pattern; FcResult result; XftFont * font; Display * xdisplay = gdk_x11_get_default_xdisplay(); int screen = gdk_x11_get_default_screen(); res_pattern = XftFontMatch(xdisplay, screen, pattern, &result); if (res_pattern == NULL){ return NULL; } FcPatternDel(res_pattern, FC_HINTING); FcPatternAddBool(res_pattern, FC_HINTING, hinting != HINT_NONE); FcPatternDel(res_pattern, FC_ANTIALIAS); FcPatternAddBool(res_pattern, FC_ANTIALIAS, antialiasing != ANTIALIAS_NONE); FcPatternDel(res_pattern, FC_RGBA); FcPatternAddInteger(res_pattern, FC_RGBA, antialiasing == ANTIALIAS_RGBA? FC_RGBA_RGB : FC_RGBA_NONE); FcPatternDel(res_pattern, FC_DPI); FcPatternAddInteger(res_pattern, FC_DPI, 96); font = XftFontOpenPattern(xdisplay, res_pattern); if (!font) FcPatternDestroy(res_pattern); return font; } static void sample_draw(GtkWidget* darea, cairo_t* cr) { cairo_surface_t* surface = g_object_get_data(G_OBJECT(darea), "sample-surface"); GtkAllocation allocation; int x, y, w, h; gtk_widget_get_allocation (darea, &allocation); x = allocation.width; y = allocation.height; w = cairo_image_surface_get_width (surface); h = cairo_image_surface_get_height (surface); cairo_set_line_width (cr, 1); cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); cairo_rectangle (cr, 0, 0, x, y); cairo_fill_preserve (cr); cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); cairo_stroke (cr); cairo_set_source_surface (cr, surface, (x - w) / 2, (y - h) / 2); cairo_paint(cr); } static void set_fontoptions(PangoContext *context, Antialiasing antialiasing, Hinting hinting) { cairo_font_options_t *opt; cairo_antialias_t aa; cairo_hint_style_t hs; switch (antialiasing) { case ANTIALIAS_NONE: aa = CAIRO_ANTIALIAS_NONE; break; case ANTIALIAS_GRAYSCALE: aa = CAIRO_ANTIALIAS_GRAY; break; case ANTIALIAS_RGBA: aa = CAIRO_ANTIALIAS_SUBPIXEL; break; default: aa = CAIRO_ANTIALIAS_DEFAULT; break; } switch (hinting) { case HINT_NONE: hs = CAIRO_HINT_STYLE_NONE; break; case HINT_SLIGHT: hs = CAIRO_HINT_STYLE_SLIGHT; break; case HINT_MEDIUM: hs = CAIRO_HINT_STYLE_MEDIUM; break; case HINT_FULL: hs = CAIRO_HINT_STYLE_FULL; break; default: hs = CAIRO_HINT_STYLE_DEFAULT; break; } opt = cairo_font_options_create (); cairo_font_options_set_antialias (opt, aa); cairo_font_options_set_hint_style (opt, hs); pango_cairo_context_set_font_options (context, opt); cairo_font_options_destroy (opt); } static void setup_font_sample(GtkWidget * darea, Antialiasing antialiasing, Hinting hinting){ const char * string1; char *lang = getenv("LANG"); if (!lang || strncmp(lang, "zh_CN", 5)) string1 = "Welcome to UKUI"; else string1 = "欢迎使用UKUI桌面环境"; PangoContext *context; PangoLayout *layout; PangoFontDescription *fd; PangoRectangle extents; cairo_surface_t *surface; cairo_t *cr; int width, height; context = gtk_widget_get_pango_context (darea); set_fontoptions (context, antialiasing, hinting); layout = pango_layout_new (context); fd = pango_font_description_from_string ("Serif"); pango_layout_set_font_description (layout, fd); pango_font_description_free (fd); pango_layout_set_markup (layout, string1, -1); pango_layout_get_extents (layout, NULL, &extents); width = PANGO_PIXELS(extents.width) + 4; height = PANGO_PIXELS(extents.height) + 2; surface = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); cr = cairo_create (surface); cairo_move_to (cr, 2, 1); pango_cairo_show_layout (cr, layout); g_object_unref (layout); cairo_destroy (cr); g_object_set_data_full(G_OBJECT(darea), "sample-surface", surface, (GDestroyNotify) cairo_surface_destroy); gtk_widget_set_size_request (GTK_WIDGET(darea), width + 2, height + 2); g_signal_connect(darea, "draw", G_CALLBACK(sample_draw), NULL); } //通过设置字体的的sensitive属性,结合css,实现给所选字体设置背景色 static void init_font_sensitive(){ gtk_widget_set_sensitive(fontsetting.monochrome_button, TRUE); gtk_widget_set_sensitive(fontsetting.best_contrast_button, TRUE); gtk_widget_set_sensitive(fontsetting.best_shapes_button, TRUE); gtk_widget_set_sensitive(fontsetting.subpixel_button, TRUE); } static void font_button_clicked(GtkButton *button, FontPair *pair){ init_font_sensitive(); gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE); GSettings * settings = g_settings_new(FONT_RENDER_SCHEMA); g_settings_set_enum(settings, FONT_ANTIALIASING_KEY, pair->antialiasing); g_settings_set_enum(settings, FONT_HINTING_KEY, pair->hinting); g_object_unref(settings); } static void setup_font_pair(GtkWidget * button, GtkWidget * darea, Antialiasing antialiasing, Hinting hinting){ FontPair *pair = g_new(FontPair, 1); pair->antialiasing = antialiasing; pair->hinting = hinting; pair->button = button; GSettings *settings = g_settings_new(FONT_RENDER_SCHEMA); int current_antialiasing = g_settings_get_enum(settings, FONT_ANTIALIASING_KEY); int current_hinting = g_settings_get_enum(settings, FONT_HINTING_KEY); if (current_antialiasing == antialiasing && current_hinting == hinting) gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE); g_object_unref(settings); setup_font_sample(darea, antialiasing, hinting); font_pairs = g_slist_prepend(font_pairs, pair); g_signal_connect(GTK_BUTTON(button), "clicked", G_CALLBACK(font_button_clicked), pair); } static void radio_button_clicked(GtkButton *button, GdkEvent *event,gpointer user_data){ gint new_level; gboolean current_state; current_state = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)); if (current_state) return; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE); //get the font size we need set new fontsetting.level = *(float *)user_data; set_gsetting(); } static void font_select_changed(GtkComboBox *widget, gpointer user_data){ gchar * current_font_name= NULL; //gchar current_new_font[30]; GtkTreeIter iter; GtkTreeModel * model; gtk_combo_box_get_active_iter(GTK_COMBO_BOX(fontsetting.font_select_combo),&iter); model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget)); gtk_tree_model_get(model, &iter, 0, ¤t_font_name, -1); if (current_font_name == NULL) return; fontsetting.font_name = current_font_name; set_gsetting(); } static gboolean reset_font_default(GtkWidget * widget, GdkEvent *event, gpointer user_data){ //reset font g_settings_reset(fontsetting.g_interface, DOCUMENT_FONT_KEY); g_settings_reset(fontsetting.g_interface, GTK_FONT_KEY); g_settings_reset(fontsetting.g_interface, MONOSPACE_FONT_KEY); g_settings_reset(fontsetting.g_marco,WINDOW_TITLE_FONT_KEY); g_settings_reset(fontsetting.g_peony, DESKTOP_FONT_KEY); init_font_info(); init_font_data(); //reset font render GSettings * settings = g_settings_new(FONT_RENDER_SCHEMA); g_settings_reset(settings,FONT_ANTIALIASING_KEY); g_settings_reset(settings,FONT_HINTING_KEY); init_font_sensitive(); g_object_unref(settings); } void font_init(AppearanceData * data){ GtkWidget * default_button; fontsetting.builder = data->ui; //init data fontsetting.small = 1.00; fontsetting.middle = 1.25; fontsetting.large = 1.50; fontsetting.g_interface = data->interface_settings; fontsetting.g_marco = data->marco_settings; fontsetting.g_peony = data->peony_settings; GtkWidget *label33 = GTK_WIDGET(gtk_builder_get_object(fontsetting.builder, "label33")); GtkWidget *label31 = GTK_WIDGET(gtk_builder_get_object(fontsetting.builder, "label31")); gtk_label_set_yalign(GTK_LABEL(label33), 0.0); gtk_label_set_xalign(GTK_LABEL(label31), 0.02); default_button = GTK_WIDGET(gtk_builder_get_object(fontsetting.builder, "default_button")); g_signal_connect(default_button, "button-press-event",G_CALLBACK(reset_font_default),NULL); fontsetting.font_select_combo = GTK_WIDGET(gtk_builder_get_object(fontsetting.builder, "font_select_comboboxtext")); g_signal_connect(GTK_COMBO_BOX(fontsetting.font_select_combo), "changed", G_CALLBACK(font_select_changed), NULL); fontsetting.small_radio_button = GTK_WIDGET(gtk_builder_get_object(fontsetting.builder, "small_radio_button")); g_signal_connect(GTK_BUTTON(fontsetting.small_radio_button), "button_release_event", G_CALLBACK(radio_button_clicked), &fontsetting.small); fontsetting.middle_radio_button = GTK_WIDGET(gtk_builder_get_object(fontsetting.builder, "middle_radio_button")); g_signal_connect(GTK_BUTTON(fontsetting.middle_radio_button), "button_release_event", G_CALLBACK(radio_button_clicked),&fontsetting.middle); fontsetting.large_radio_button =GTK_WIDGET(gtk_builder_get_object(fontsetting.builder, "large_radio_button")); g_signal_connect(GTK_BUTTON(fontsetting.large_radio_button), "button_release_event", G_CALLBACK(radio_button_clicked),&fontsetting.large); //sample fontsetting.monochrome_button = GTK_WIDGET(gtk_builder_get_object(fontsetting.builder, "monochrome_button")); fontsetting.monochrome_sample = GTK_WIDGET(gtk_builder_get_object(fontsetting.builder, "monochrome_sample")); fontsetting.best_contrast_button = GTK_WIDGET(gtk_builder_get_object(fontsetting.builder, "best_contrast_button")); fontsetting.best_contrast_sample = GTK_WIDGET(gtk_builder_get_object(fontsetting.builder, "best_contrast_sample")); fontsetting.best_shapes_button = GTK_WIDGET(gtk_builder_get_object(fontsetting.builder, "best_shapes_button")); fontsetting.best_shapes_sample = GTK_WIDGET(gtk_builder_get_object(fontsetting.builder, "best_shapes_sample")); fontsetting.subpixel_button = GTK_WIDGET(gtk_builder_get_object(fontsetting.builder, "subpixel_button")); fontsetting.subpixel_sample = GTK_WIDGET(gtk_builder_get_object(fontsetting.builder, "subpixel_sample")); //init sample setup_font_pair(fontsetting.monochrome_button, fontsetting.monochrome_sample, ANTIALIAS_NONE, HINT_FULL); setup_font_pair(fontsetting.best_contrast_button, fontsetting.best_contrast_sample, ANTIALIAS_GRAYSCALE, HINT_FULL); setup_font_pair(fontsetting.best_shapes_button, fontsetting.best_shapes_sample, ANTIALIAS_GRAYSCALE, HINT_MEDIUM); setup_font_pair(fontsetting.subpixel_button, fontsetting.subpixel_sample, ANTIALIAS_RGBA, HINT_FULL); //get default value from gsetting get_default_setting(data); //setup data into font_select_comboboxtext setup_combotext_data(); //get font information, include size and font name init_font_info(); //make font select combobox and font size show the level they should be setted init_font_data(); } void font_shutdown(AppearanceData *data){ } ukui-control-center/panels/appearance/appearance-theme.h0000664000175000017500000000165013057175444022356 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "appearance.h" void theme_init(AppearanceData * data); ukui-control-center/panels/Makefile.am0000664000175000017500000000026513057175444016744 0ustar fengfengSUBDIRS = time-data appearance user-accounts default-app keyboard mouse network-proxy session-properties display power volume-control clean-local : rm -f *~ Makefile.in Makefile ukui-control-center/panels/keyboard/0000775000175000017500000000000013263647163016506 5ustar fengfengukui-control-center/panels/keyboard/ukui-keyboard-properties-xkbpv.c0000664000175000017500000000731413253611037024742 0ustar fengfeng/* -*- mode: c; style: linux -*- */ /* ukui-keyboard-properties-xkbpv.c * Copyright (C) 2003-2007 Sergey V. Udaltsov * * Written by: Sergey V. Udaltsov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include #include "ukui-keyboard-properties-xkb.h" #ifdef HAVE_X11_EXTENSIONS_XKB_H #include "X11/XKBlib.h" /** * BAD STYLE: Taken from xklavier_private_xkb.h * Any ideas on architectural improvements are WELCOME */ extern gboolean xkl_xkb_config_native_prepare (XklEngine * engine, const XklConfigRec * data, XkbComponentNamesPtr component_names); extern void xkl_xkb_config_native_cleanup (XklEngine * engine, XkbComponentNamesPtr component_names); /* */ #endif static MatekbdKeyboardDrawingGroupLevel groupsLevels[] = { {0, 1}, {0, 3}, {0, 0}, {0, 2} }; static MatekbdKeyboardDrawingGroupLevel *pGroupsLevels[] = { groupsLevels, groupsLevels + 1, groupsLevels + 2, groupsLevels + 3 }; GtkWidget * xkb_layout_preview_create_widget (GtkBuilder * chooserDialog) { GtkWidget *kbdraw = matekbd_keyboard_drawing_new (); matekbd_keyboard_drawing_set_groups_levels (MATEKBD_KEYBOARD_DRAWING (kbdraw), pGroupsLevels); return kbdraw; } void xkb_layout_preview_update (GtkBuilder * chooser_dialog) { #ifdef HAVE_X11_EXTENSIONS_XKB_H GtkWidget *chooser = CWID ("xkb_layout_chooser"); GtkWidget *kbdraw = GTK_WIDGET (g_object_get_data (G_OBJECT (chooser), "kbdraw")); gchar *id = xkb_layout_chooser_get_selected_id (chooser_dialog); xkb_layout_preview_set_drawing_layout (kbdraw, id); g_free (id); #endif } void xkb_layout_preview_set_drawing_layout (GtkWidget * kbdraw, const gchar * id) { #ifdef HAVE_X11_EXTENSIONS_XKB_H if (kbdraw != NULL) { if (id != NULL) { XklConfigRec *data; char **p, *layout, *variant; XkbComponentNamesRec component_names; data = xkl_config_rec_new (); if (xkl_config_rec_get_from_server (data, engine)) { if ((p = data->layouts) != NULL) g_strfreev (data->layouts); if ((p = data->variants) != NULL) g_strfreev (data->variants); data->layouts = g_new0 (char *, 2); data->variants = g_new0 (char *, 2); if (matekbd_keyboard_config_split_items (id, &layout, &variant) && variant != NULL) { data->layouts[0] = (layout == NULL) ? NULL : g_strdup (layout); data->variants[0] = (variant == NULL) ? NULL : g_strdup (variant); } else { data->layouts[0] = (id == NULL) ? NULL : g_strdup (id); data->variants[0] = NULL; } if (xkl_xkb_config_native_prepare (engine, data, &component_names)) { matekbd_keyboard_drawing_set_keyboard (MATEKBD_KEYBOARD_DRAWING (kbdraw), &component_names); xkl_xkb_config_native_cleanup (engine, &component_names); } } g_object_unref (G_OBJECT (data)); } else matekbd_keyboard_drawing_set_keyboard (MATEKBD_KEYBOARD_DRAWING (kbdraw), NULL); } #endif } ukui-control-center/panels/keyboard/Makefile.am0000664000175000017500000000341113253611037020527 0ustar fengfengcappletname=keyboard noinst_LTLIBRARIES=libkeyboard.la AUTOMAKE_OPTIONS=foreign #INCLUDES= `pkg-config --cflags gtk+-2.0 gio-2.0 glib-2.0 ukui-settings-daemon libmatekbd gdk-2.0 libmatekbdui x11 dconf gobject-2.0` #LIBS= `pkg-config --libs gtk+-2.0 gio-2.0 glib-2.0 ukui-settings-daemon libmatekbd gdk-2.0 libmatekbdui x11 dconf gobject-2.0` AM_CPPFLAGS = \ -DUIDIR="\"$(uidir)\"" \ -DUKUI_KEYBINDINGS_DIR="\"$(pkgdatadir)/keybindings\"" \ $(GTK_CFLAGS) \ $(GLIB_CFLAGS) \ $(UKUI_SD_CFLAGS) \ $(MATE_KBD_CFLAGS) \ $(GDK_CFLAGS) \ $(MATE_KBD_UI_CFLAGS) \ $(X11_CFLAGS) \ $(DCONF_CFLAGS) \ $(NULL) libkeyboard_la_LIBADD = \ $(GTK_LIBS) \ $(GLIB_LIBS) \ $(UKUI_SD_LIBS) \ $(MATE_KBD_LIBS) \ $(GDK_LIBS) \ $(MATE_KBD_UI_LIBS) \ $(X11_LIBS) \ $(DCONF_LIBS) \ $(NULL) libkeyboard_la_SOURCES= \ ukui-keyboard-properties.c \ ukui-keyboard-properties.h \ ukui-keyboard-properties-a11y.c \ ukui-keyboard-properties-a11y.h \ ukui-keyboard-properties-xkb.c \ ukui-keyboard-properties-xkblt.c \ ukui-keyboard-properties-xkbltadd.c \ ukui-keyboard-properties-xkbmc.c \ ukui-keyboard-properties-xkbot.c \ ukui-keyboard-properties-xkbpv.c \ ukui-keyboard-properties-xkb.h \ eggaccelerators.c \ eggaccelerators.h \ eggcellrendererkeys.c \ eggcellrendererkeys.h \ ukui-keybinding-properties.c \ ukui-keybinding-properties.h \ wm-common.c \ wm-common.h \ dconf-util.c \ dconf-util.h uidir = $(pkgdatadir)/ui ui_DATA = ukui-keyboard-properties-layout-chooser.ui shortcut_dialog.ui @INTLTOOL_XML_NOMERGE_RULE@ xmldir = $(pkgdatadir)/keybindings xml_in_files = 01-desktop-key.xml.in xml_DATA = $(xml_in_files:.xml.in=.xml) EXTRA_DIST= $(xml_in_files) $(uidir) -include $(top_srcdir)/git.mk clean-local : rm -f *~ Makefile.in Makefile 00-multimedia-key.xml 01-desktop-key.xml ukui-control-center/panels/keyboard/ukui-keyboard-properties.h0000664000175000017500000000024613245450076023621 0ustar fengfeng#ifndef _KEYBOARD_PRO #define _KEYBOARD_PRO #include void add_keyboard_app(GtkBuilder * builder); void destory_keyboard_app(GtkBuilder * builder); #endif ukui-control-center/panels/keyboard/dconf-util.h0000664000175000017500000000263413057175444020727 0ustar fengfeng/* * dconf-util.h: helper API for dconf * * Copyright (C) 2012 Stefano Karapetsas * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Authors: * Stefano Karapetsas * Vincent Untz */ #ifndef __DCONF_UTIL_H__ #define __DCONF_UTIL_H__ #include G_BEGIN_DECLS gboolean dconf_util_write_sync (const gchar *key, GVariant *value, GError **error); gboolean dconf_util_recursive_reset (const gchar *dir, GError **error); gchar **dconf_util_list_subdirs (const gchar *dir, gboolean remove_trailing_slash); G_END_DECLS #endif /* __DCONF_UTIL_H__ */ ukui-control-center/panels/keyboard/ukui-keyboard-properties-a11y.h0000664000175000017500000000211113253611037024356 0ustar fengfeng/* -*- mode: c; style: linux -*- */ /* accessibility-keyboard.c * Copyright (C) 2002 Ximian, Inc. * * Written by: Jody 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, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 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 St, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifndef __UKUI_KEYBOARD_PROPERTY_A11Y_H #define __UKUI_KEYBOARD_PROPERTY_A11Y_H #include extern void setup_a11y_tabs (GtkBuilder * dialog); extern void finalize_a11y_tabs (void); #endif /* __UKUI_KEYBOARD_PROPERTY_A11Y_H */ ukui-control-center/panels/keyboard/ukui-keyboard-properties-xkbot.c0000664000175000017500000003664713253611037024752 0ustar fengfeng/* -*- mode: c; style: linux -*- */ /* ukui-keyboard-properties-xkbot.c * Copyright (C) 2003-2007 Sergey V. Udaltsov * * Written by: Sergey V. Udaltsov * John Spray * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include #include #include "ukui-keyboard-properties-xkb.h" static GtkBuilder *chooser_dialog = NULL; static const char *current1st_level_id = NULL; static GSList *option_checks_list = NULL; static GtkWidget *current_none_radio = NULL; static GtkWidget *current_expander = NULL; static gboolean current_multi_select = FALSE; static GSList *current_radio_group = NULL; #define OPTION_ID_PROP "optionID" #define SELCOUNTER_PROP "selectionCounter" #define EXPANDERS_PROP "expandersList" GSList * xkb_options_get_selected_list (void) { gchar **array; GSList *retval = NULL; gint i; array = g_settings_get_strv (xkb_kbd_settings, "options"); if (array != NULL) { for (i = 0; array[i]; i++) { retval = g_slist_append (retval, g_strdup (array[i])); } } g_strfreev (array); if (retval == NULL) { if (initial_config.options != NULL) { for (i = 0; initial_config.options[i] != NULL; i++) retval = g_slist_prepend (retval, g_strdup (initial_config.options[i])); } retval = g_slist_reverse (retval); } return retval; } /* Returns the selection counter of the expander (static current_expander) */ static int xkb_options_expander_selcounter_get (void) { return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (current_expander), SELCOUNTER_PROP)); } /* Increments the selection counter in the expander (static current_expander) using the value (can be 0)*/ static void xkb_options_expander_selcounter_add (int value) { g_object_set_data (G_OBJECT (current_expander), SELCOUNTER_PROP, GINT_TO_POINTER (xkb_options_expander_selcounter_get () + value)); } /* Resets the seletion counter in the expander (static current_expander) */ static void xkb_options_expander_selcounter_reset (void) { g_object_set_data (G_OBJECT (current_expander), SELCOUNTER_PROP, GINT_TO_POINTER (0)); } /* Formats the expander (static current_expander), based on the selection counter */ static void xkb_options_expander_highlight (void) { char *utf_group_name = g_object_get_data (G_OBJECT (current_expander), "utfGroupName"); int counter = xkb_options_expander_selcounter_get (); if (utf_group_name != NULL) { gchar *titlemarkup = g_strconcat (counter > 0 ? "" : "", utf_group_name, "", NULL); gtk_expander_set_label (GTK_EXPANDER (current_expander), titlemarkup); g_free (titlemarkup); } } /* Add optionname from the backend's selection list if it's not already in there. */ static void xkb_options_select (gchar * optionname) { gboolean already_selected = FALSE; GSList *options_list = xkb_options_get_selected_list (); GSList *option; for (option = options_list; option != NULL; option = option->next) if (!strcmp ((gchar *) option->data, optionname)) already_selected = TRUE; if (!already_selected) options_list = g_slist_append (options_list, g_strdup (optionname)); xkb_options_set_selected_list (options_list); clear_xkb_elements_list (options_list); } /* Remove all occurences of optionname from the backend's selection list */ static void xkb_options_deselect (gchar * optionname) { GSList *options_list = xkb_options_get_selected_list (); GSList *nodetmp; GSList *option = options_list; while (option != NULL) { gchar *id = (char *) option->data; if (!strcmp (id, optionname)) { nodetmp = option->next; g_free (id); options_list = g_slist_remove_link (options_list, option); g_slist_free_1 (option); option = nodetmp; } else option = option->next; } xkb_options_set_selected_list (options_list); clear_xkb_elements_list (options_list); } /* Return true if optionname describes a string already in the backend's list of selected options */ static gboolean xkb_options_is_selected (gchar * optionname) { gboolean retval = FALSE; GSList *options_list = xkb_options_get_selected_list (); GSList *option; for (option = options_list; option != NULL; option = option->next) { if (!strcmp ((gchar *) option->data, optionname)) retval = TRUE; } clear_xkb_elements_list (options_list); return retval; } /* Make sure selected options stay visible when navigating with the keyboard */ static gboolean option_focused_cb (GtkWidget * widget, GdkEventFocus * event, gpointer data) { GtkScrolledWindow *win = GTK_SCROLLED_WINDOW (data); GtkAllocation alloc; GtkAdjustment *adj; gtk_widget_get_allocation (widget, &alloc); adj = gtk_scrolled_window_get_vadjustment (win); gtk_adjustment_clamp_page (adj, alloc.y, alloc.y + alloc.height); return FALSE; } /* Update xkb backend to reflect the new UI state */ static void option_toggled_cb (GtkWidget * checkbutton, gpointer data) { gpointer optionID = g_object_get_data (G_OBJECT (checkbutton), OPTION_ID_PROP); if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton))) xkb_options_select (optionID); else xkb_options_deselect (optionID); } /* Add a check_button or radio_button to control a particular option This function makes particular use of the current... variables at the top of this file. */ static void xkb_options_add_option (XklConfigRegistry * config_registry, XklConfigItem * config_item, GtkBuilder * dialog) { GtkWidget *option_check; gchar *utf_option_name = xci_desc_to_utf8 (config_item); /* Copy this out because we'll load it into the widget with set_data */ gchar *full_option_name = g_strdup (matekbd_keyboard_config_merge_items (current1st_level_id, config_item->name)); gboolean initial_state; if (current_multi_select) option_check = gtk_check_button_new_with_label (utf_option_name); else { if (current_radio_group == NULL) { /* The first radio in a group is to be "Default", meaning none of the below options are to be included in the selected list. This is a HIG-compliant alternative to allowing no selection in the group. */ option_check = gtk_radio_button_new_with_label (current_radio_group, "Default"); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (option_check), TRUE); /* Make option name underscore - to enforce its first position in the list */ g_object_set_data_full (G_OBJECT (option_check), "utfOptionName", g_strdup (" "), g_free); option_checks_list = g_slist_append (option_checks_list, option_check); current_radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (option_check)); current_none_radio = option_check; g_signal_connect (option_check, "focus-in-event", G_CALLBACK (option_focused_cb), (gpointer)WID ("options_scroll")); } option_check = gtk_radio_button_new_with_label (current_radio_group, utf_option_name); current_radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (option_check)); g_object_set_data (G_OBJECT (option_check), "NoneRadio", current_none_radio); } initial_state = xkb_options_is_selected (full_option_name); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (option_check), initial_state); g_object_set_data_full (G_OBJECT (option_check), OPTION_ID_PROP, full_option_name, g_free); g_object_set_data_full (G_OBJECT (option_check), "utfOptionName", utf_option_name, g_free); g_signal_connect (option_check, "toggled", G_CALLBACK (option_toggled_cb), NULL); option_checks_list = g_slist_append (option_checks_list, option_check); g_signal_connect (option_check, "focus-in-event", G_CALLBACK (option_focused_cb), WID ("options_scroll")); xkb_options_expander_selcounter_add (initial_state); } static gint xkb_option_checks_compare (GtkWidget * chk1, GtkWidget * chk2) { const gchar *t1 = g_object_get_data (G_OBJECT (chk1), "utfOptionName"); const gchar *t2 = g_object_get_data (G_OBJECT (chk2), "utfOptionName"); return g_utf8_collate (t1, t2); } /* Add a group of options: create title and layout widgets and then add widgets for all the options in the group. */ static void xkb_options_add_group (XklConfigRegistry * config_registry, XklConfigItem * config_item, GtkBuilder * dialog) { GtkWidget *align, *vbox, *option_check; gboolean allow_multiple_selection = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (config_item), XCI_PROP_ALLOW_MULTIPLE_SELECTION)); GSList *expanders_list = g_object_get_data (G_OBJECT (dialog), EXPANDERS_PROP); gchar *utf_group_name = xci_desc_to_utf8 (config_item); gchar *titlemarkup = g_strconcat ("", utf_group_name, "", NULL); current_expander = gtk_expander_new (titlemarkup); gtk_expander_set_use_markup (GTK_EXPANDER (current_expander), TRUE); g_object_set_data_full (G_OBJECT (current_expander), "utfGroupName", utf_group_name, g_free); g_object_set_data_full (G_OBJECT (current_expander), "groupId", g_strdup (config_item->name), g_free); g_free (titlemarkup); align = gtk_alignment_new (0, 0, 1, 1); gtk_alignment_set_padding (GTK_ALIGNMENT (align), 6, 12, 12, 0); vbox = gtk_vbox_new (TRUE, 6); gtk_container_add (GTK_CONTAINER (align), vbox); gtk_container_add (GTK_CONTAINER (current_expander), align); current_multi_select = (gboolean) allow_multiple_selection; current_radio_group = NULL; current1st_level_id = config_item->name; option_checks_list = NULL; xkl_config_registry_foreach_option (config_registry, config_item->name, (ConfigItemProcessFunc) xkb_options_add_option, dialog); /* sort it */ option_checks_list = g_slist_sort (option_checks_list, (GCompareFunc) xkb_option_checks_compare); while (option_checks_list) { option_check = GTK_WIDGET (option_checks_list->data); gtk_box_pack_start (GTK_BOX (vbox), option_check, TRUE, TRUE, 0); option_checks_list = option_checks_list->next; } /* free it */ g_slist_free (option_checks_list); option_checks_list = NULL; xkb_options_expander_highlight (); expanders_list = g_slist_append (expanders_list, current_expander); g_object_set_data (G_OBJECT (dialog), EXPANDERS_PROP, expanders_list); g_signal_connect (current_expander, "focus-in-event", G_CALLBACK (option_focused_cb), WID ("options_scroll")); } static gint xkb_options_expanders_compare (GtkWidget * expander1, GtkWidget * expander2) { const gchar *t1 = g_object_get_data (G_OBJECT (expander1), "utfGroupName"); const gchar *t2 = g_object_get_data (G_OBJECT (expander2), "utfGroupName"); return g_utf8_collate (t1, t2); } /* Create widgets to represent the options made available by the backend */ void xkb_options_load_options (GtkBuilder * dialog) { GtkWidget *opts_vbox = WID ("options_vbox"); GSList *expanders_list; GtkWidget *expander; current1st_level_id = NULL; current_none_radio = NULL; current_multi_select = FALSE; current_radio_group = NULL; /* fill the list */ xkl_config_registry_foreach_option_group (config_registry, (ConfigItemProcessFunc) xkb_options_add_group, dialog); /* sort it */ expanders_list = g_object_get_data (G_OBJECT (dialog), EXPANDERS_PROP); expanders_list = g_slist_sort (expanders_list, (GCompareFunc) xkb_options_expanders_compare); g_object_set_data (G_OBJECT (dialog), EXPANDERS_PROP, expanders_list); while (expanders_list) { expander = GTK_WIDGET (expanders_list->data); gtk_box_pack_start (GTK_BOX (opts_vbox), expander, FALSE, FALSE, 0); expanders_list = expanders_list->next; } gtk_widget_show_all (opts_vbox); } static void chooser_response_cb (GtkDialog * dialog, gint response, gpointer data) { switch (response) { case GTK_RESPONSE_HELP: //capplet_help (GTK_WINDOW (dialog), // "prefs-keyboard-layoutoptions"); break; case GTK_RESPONSE_CLOSE:{ /* just cleanup */ GSList *expanders_list = g_object_get_data (G_OBJECT (dialog), EXPANDERS_PROP); g_object_set_data (G_OBJECT (dialog), EXPANDERS_PROP, NULL); g_slist_free (expanders_list); gtk_widget_destroy (GTK_WIDGET (dialog)); chooser_dialog = NULL; } break; } } /* Create popup dialog */ void xkb_options_popup_dialog (GtkBuilder * dialog) { GtkWidget *chooser; chooser_dialog = gtk_builder_new (); if (gtk_builder_add_from_file (chooser_dialog, UIDIR "/ukui-keyboard-properties-options-dialog.ui", NULL) ==0) { g_warning("error"); if (gtk_builder_add_from_file(chooser_dialog, "../panels/keyboard/ukui-keyboard-properties-options-dialog.ui",NULL) ==0) { g_warning("Can not find ui file"); return; } } chooser = CWID ("xkb_options_dialog"); gtk_window_set_transient_for (GTK_WINDOW (chooser), GTK_WINDOW (WID ("keyboard_dialog"))); xkb_options_load_options (chooser_dialog); g_signal_connect (chooser, "response", G_CALLBACK (chooser_response_cb), dialog); gtk_widget_set_name(GTK_WIDGET(chooser), "ukuicc"); gtk_dialog_run (GTK_DIALOG (chooser)); } /* Update selected option counters for a group-bound expander */ static void xkb_options_update_option_counters (XklConfigRegistry * config_registry, XklConfigItem * config_item) { gchar *full_option_name = g_strdup (matekbd_keyboard_config_merge_items (current1st_level_id, config_item->name)); gboolean current_state = xkb_options_is_selected (full_option_name); xkb_options_expander_selcounter_add (current_state); } /* Respond to a change in the xkb gsettings settings */ static void xkb_options_update (GSettings * settings, gchar * key, GtkBuilder * dialog) { /* Updating options is handled by gsettings notifies for each widget This is here to avoid calling it N_OPTIONS times for each gsettings change. */ enable_disable_restoring (dialog); if (chooser_dialog != NULL) { GSList *expanders_list = g_object_get_data (G_OBJECT (chooser_dialog), EXPANDERS_PROP); while (expanders_list) { current_expander = GTK_WIDGET (expanders_list->data); gchar *group_id = g_object_get_data (G_OBJECT (current_expander), "groupId"); current1st_level_id = group_id; xkb_options_expander_selcounter_reset (); xkl_config_registry_foreach_option(config_registry, group_id, (ConfigItemProcessFunc)xkb_options_update_option_counters, current_expander); xkb_options_expander_highlight (); expanders_list = expanders_list->next; } } } void xkb_options_register_gsettings_listener (GtkBuilder * dialog) { g_signal_connect (xkb_kbd_settings, "changed::options", G_CALLBACK (xkb_options_update), dialog); } ukui-control-center/panels/keyboard/ukui-keyboard-properties-xkbltadd.c0000664000175000017500000004146613253611037025413 0ustar fengfeng/* -*- mode: c; style: linux -*- */ /* ukui-keyboard-properties-xkbltadd.c * Copyright (C) 2003-2007 Sergey V. Udaltsov * * Written by: Sergey V. Udaltsov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include #include #include #include "ukui-keyboard-properties-xkb.h" enum { COMBO_BOX_MODEL_COL_SORT, COMBO_BOX_MODEL_COL_VISIBLE, COMBO_BOX_MODEL_COL_XKB_ID, COMBO_BOX_MODEL_COL_REAL_ID }; typedef void (*LayoutIterFunc) (XklConfigRegistry * config, ConfigItemProcessFunc func, gpointer data); typedef struct { GtkListStore *list_store; const gchar *lang_id; } AddVariantData; static void xkb_layout_chooser_available_layouts_fill (GtkBuilder * chooser_dialog, const gchar cblid[], const gchar cbvid[], LayoutIterFunc layout_iterator, ConfigItemProcessFunc layout_handler, GCallback combo_changed_notify); static void xkb_layout_chooser_available_language_variants_fill (GtkBuilder * chooser_dialog); static void xkb_layout_chooser_available_country_variants_fill (GtkBuilder * chooser_dialog); static void xkb_layout_chooser_add_variant_to_available_country_variants(XklConfigRegistry * config_registry, XklConfigItem * parent_config_item, XklConfigItem * config_item, AddVariantData * data) { gchar *utf_variant_name = config_item ? xkb_layout_description_utf8 (matekbd_keyboard_config_merge_items (parent_config_item->name, config_item->name)) : xci_desc_to_utf8 (parent_config_item); GtkTreeIter iter; const gchar *xkb_id = config_item ? matekbd_keyboard_config_merge_items (parent_config_item->name, config_item->name) : parent_config_item->name; if (config_item && g_object_get_data (G_OBJECT (config_item), XCI_PROP_EXTRA_ITEM)) { gchar *buf = g_strdup_printf ("%s", utf_variant_name); gtk_list_store_insert_with_values (data->list_store, &iter, -1, COMBO_BOX_MODEL_COL_SORT, utf_variant_name, COMBO_BOX_MODEL_COL_VISIBLE, buf, COMBO_BOX_MODEL_COL_XKB_ID, xkb_id, -1); g_free (buf); } else gtk_list_store_insert_with_values (data->list_store, &iter, -1, COMBO_BOX_MODEL_COL_SORT, utf_variant_name, COMBO_BOX_MODEL_COL_VISIBLE, utf_variant_name, COMBO_BOX_MODEL_COL_XKB_ID, xkb_id, -1); g_free (utf_variant_name); } static void xkb_layout_chooser_add_variant_to_available_language_variants(XklConfigRegistry * config_registry, XklConfigItem * parent_config_item, XklConfigItem * config_item, AddVariantData * data) { xkb_layout_chooser_add_variant_to_available_country_variants(config_registry, parent_config_item, config_item, data); } static void xkb_layout_chooser_add_language_to_available_languages (XklConfigRegistry * config_registry, XklConfigItem * config_item, GtkListStore * list_store) { gtk_list_store_insert_with_values (list_store, NULL, -1, COMBO_BOX_MODEL_COL_SORT, config_item->description, COMBO_BOX_MODEL_COL_VISIBLE, config_item->description, COMBO_BOX_MODEL_COL_REAL_ID, config_item->name, -1); } static void xkb_layout_chooser_add_country_to_available_countries (XklConfigRegistry * config_registry, XklConfigItem * config_item, GtkListStore * list_store) { gtk_list_store_insert_with_values (list_store, NULL, -1, COMBO_BOX_MODEL_COL_SORT, config_item->description, COMBO_BOX_MODEL_COL_VISIBLE, config_item->description, COMBO_BOX_MODEL_COL_REAL_ID, config_item->name, -1); } static void xkb_layout_chooser_enable_disable_buttons (GtkBuilder * chooser_dialog) { GtkWidget *cbv = CWID (gtk_notebook_get_current_page (GTK_NOTEBOOK (CWID ("choosers_nb"))) ? "xkb_language_variants_available" : "xkb_country_variants_available"); GtkTreeIter viter; gboolean enable_ok = gtk_combo_box_get_active_iter (GTK_COMBO_BOX (cbv), &viter); gtk_dialog_set_response_sensitive (GTK_DIALOG(CWID("xkb_layout_chooser")), GTK_RESPONSE_OK, enable_ok); gtk_widget_set_sensitive (CWID ("btnPrint"), enable_ok); } static void xkb_layout_chooser_available_variant_changed (GtkBuilder * chooser_dialog) { xkb_layout_preview_update (chooser_dialog); xkb_layout_chooser_enable_disable_buttons (chooser_dialog); } static void xkb_layout_chooser_available_language_changed (GtkBuilder * chooser_dialog) { xkb_layout_chooser_available_language_variants_fill (chooser_dialog); xkb_layout_chooser_available_variant_changed (chooser_dialog); } static void xkb_layout_chooser_available_country_changed (GtkBuilder * chooser_dialog) { xkb_layout_chooser_available_country_variants_fill (chooser_dialog); xkb_layout_chooser_available_variant_changed (chooser_dialog); } static void xkb_layout_chooser_page_changed (GtkWidget * notebook, GtkWidget * page, gint page_num, GtkBuilder * chooser_dialog) { xkb_layout_chooser_available_variant_changed (chooser_dialog); } static void xkb_layout_chooser_available_language_variants_fill (GtkBuilder * chooser_dialog) { GtkWidget *cbl = CWID ("xkb_languages_available"); GtkWidget *cbv = CWID ("xkb_language_variants_available"); GtkListStore *list_store; GtkTreeIter liter; list_store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (cbl), &liter)) { GtkTreeModel *lm = gtk_combo_box_get_model (GTK_COMBO_BOX (cbl)); gchar *lang_id; AddVariantData data = { list_store, 0 }; /* Now the variants of the selected layout */ gtk_tree_model_get (lm, &liter, COMBO_BOX_MODEL_COL_REAL_ID, &lang_id, -1); data.lang_id = lang_id; xkl_config_registry_foreach_language_variant (config_registry, lang_id, (TwoConfigItemsProcessFunc)xkb_layout_chooser_add_variant_to_available_language_variants, &data); g_free (lang_id); } /* Turn on sorting after filling the store, since that's faster */ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store), COMBO_BOX_MODEL_COL_SORT, GTK_SORT_ASCENDING); gtk_combo_box_set_model (GTK_COMBO_BOX (cbv), GTK_TREE_MODEL (list_store)); gtk_combo_box_set_active (GTK_COMBO_BOX (cbv), 0); } static void xkb_layout_chooser_available_country_variants_fill (GtkBuilder * chooser_dialog) { GtkWidget *cbl = CWID ("xkb_countries_available"); GtkWidget *cbv = CWID ("xkb_country_variants_available"); GtkListStore *list_store; GtkTreeIter liter; list_store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (cbl), &liter)) { GtkTreeModel *lm = gtk_combo_box_get_model (GTK_COMBO_BOX (cbl)); gchar *country_id; AddVariantData data = { list_store, 0 }; /* Now the variants of the selected layout */ gtk_tree_model_get (lm, &liter, COMBO_BOX_MODEL_COL_REAL_ID, &country_id, -1); xkl_config_registry_foreach_country_variant (config_registry, country_id, (TwoConfigItemsProcessFunc)xkb_layout_chooser_add_variant_to_available_country_variants, &data); g_free (country_id); } /* Turn on sorting after filling the store, since that's faster */ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store), COMBO_BOX_MODEL_COL_SORT, GTK_SORT_ASCENDING); gtk_combo_box_set_model (GTK_COMBO_BOX (cbv), GTK_TREE_MODEL (list_store)); gtk_combo_box_set_active (GTK_COMBO_BOX (cbv), 0); } static void xkb_layout_chooser_available_layouts_fill (GtkBuilder * chooser_dialog, const gchar cblid[], const gchar cbvid[], LayoutIterFunc layout_iterator, ConfigItemProcessFunc layout_handler, GCallback combo_changed_notify) { GtkWidget *cbl = CWID (cblid); GtkWidget *cbev = CWID (cbvid); GtkCellRenderer *renderer; GtkListStore *list_store; list_store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); gtk_combo_box_set_model (GTK_COMBO_BOX (cbl), GTK_TREE_MODEL (list_store)); renderer = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cbl), renderer, TRUE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (cbl), renderer, "markup", COMBO_BOX_MODEL_COL_VISIBLE, NULL); layout_iterator (config_registry, layout_handler, list_store); /* Turn on sorting after filling the model since that's faster */ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store), COMBO_BOX_MODEL_COL_SORT, GTK_SORT_ASCENDING); g_signal_connect_swapped (G_OBJECT (cbl), "changed", combo_changed_notify, chooser_dialog); /* Setup the variants combo */ renderer = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cbev), renderer, TRUE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (cbev), renderer, "markup", COMBO_BOX_MODEL_COL_VISIBLE, NULL); g_signal_connect_swapped (G_OBJECT (cbev), "changed", G_CALLBACK (xkb_layout_chooser_available_variant_changed), chooser_dialog); } GSList* xkb_layout_gslist_from_strv (gchar **array) { GSList *list = NULL; gint i; if (array != NULL) { for (i = 0; array[i]; i++) { list = g_slist_append (list, g_strdup (array[i])); } } return list; } gchar ** xkb_layout_strv_from_gslist (GSList *list) { GArray *array; GSList *l; array = g_array_new (TRUE, TRUE, sizeof (gchar *)); for (l = list; l; l = l->next) { array = g_array_append_val (array, l->data); } return (gchar **) array->data; } void xkl_layout_chooser_add_default_switcher_if_necessary (GSList * layouts_list) { GSList *options_list = xkb_options_get_selected_list (); gboolean was_appended; gchar **layouts_list_strv = xkb_layout_strv_from_gslist (layouts_list); gchar **options_list_strv = xkb_layout_strv_from_gslist (options_list); options_list_strv = matekbd_keyboard_config_add_default_switch_option_if_necessary (layouts_list_strv, options_list_strv, &was_appended); if (was_appended) { xkb_options_set_selected_list (options_list); } clear_xkb_elements_list (options_list); } static void xkb_layout_chooser_print (GtkBuilder * chooser_dialog) { GtkWidget *chooser = CWID ("xkb_layout_chooser"); GtkWidget *kbdraw = GTK_WIDGET (g_object_get_data (G_OBJECT (chooser), "kbdraw")); const char *id = xkb_layout_chooser_get_selected_id (chooser_dialog); char *descr = xkb_layout_description_utf8 (id); matekbd_keyboard_drawing_print (MATEKBD_KEYBOARD_DRAWING(kbdraw), GTK_WINDOW (CWID("xkb_layout_chooser")), descr); g_free (descr); } static void xkb_layout_chooser_response (GtkDialog * dialog, gint response, GtkBuilder * chooser_dialog) { GdkRectangle rect; if (response == GTK_RESPONSE_OK) { gchar *selected_id = (gchar *) xkb_layout_chooser_get_selected_id (chooser_dialog); if (selected_id != NULL) { GSList *layouts_list = xkb_layouts_get_selected_list (); selected_id = g_strdup (selected_id); layouts_list = g_slist_append (layouts_list, selected_id); xkb_layouts_set_selected_list (layouts_list); xkl_layout_chooser_add_default_switcher_if_necessary (layouts_list); clear_xkb_elements_list (layouts_list); } } else if (response == gtk_dialog_get_response_for_widget (dialog, CWID ("btnPrint"))) { xkb_layout_chooser_print (chooser_dialog); g_signal_stop_emission_by_name (dialog, "response"); return; } gtk_window_get_position (GTK_WINDOW (dialog), &rect.x, &rect.y); gtk_window_get_size (GTK_WINDOW (dialog), &rect.width, &rect.height); matekbd_preview_save_position (&rect); } void xkb_layout_choose (GtkBuilder * dialog) { GtkBuilder *chooser_dialog; chooser_dialog = gtk_builder_new (); if (gtk_builder_add_from_file (chooser_dialog, UIDIR"/ukui-keyboard-properties-layout-chooser.ui", NULL) == 0) { g_warning("Can not find ui file in /usr/share/ukui-control-center\n"); if (gtk_builder_add_from_file(chooser_dialog, "../panels/keyboard/ukui-keyboard-properties-layout-chooser.ui",NULL) == 0) { g_warning("Can not find ui file in locale content"); } return; } GtkWidget *chooser = CWID ("xkb_layout_chooser"); GtkWidget *lang_chooser = CWID ("xkb_languages_available"); GtkWidget *notebook = CWID ("choosers_nb"); GtkWidget *kbdraw = NULL; GtkWidget *toplevel = NULL; gtk_window_set_transient_for (GTK_WINDOW (chooser), GTK_WINDOW (WID("keyboard_dialog"))); xkb_layout_chooser_available_layouts_fill (chooser_dialog, "xkb_countries_available", "xkb_country_variants_available", xkl_config_registry_foreach_country, (ConfigItemProcessFunc) xkb_layout_chooser_add_country_to_available_countries, G_CALLBACK(xkb_layout_chooser_available_country_changed)); xkb_layout_chooser_available_layouts_fill (chooser_dialog, "xkb_languages_available", "xkb_language_variants_available", xkl_config_registry_foreach_language, (ConfigItemProcessFunc) xkb_layout_chooser_add_language_to_available_languages, G_CALLBACK(xkb_layout_chooser_available_language_changed)); g_signal_connect_after (G_OBJECT (notebook), "switch_page", G_CALLBACK (xkb_layout_chooser_page_changed), chooser_dialog); gtk_combo_box_set_active (GTK_COMBO_BOX (CWID ("xkb_countries_available")), 10); if (gtk_tree_model_iter_n_children (gtk_combo_box_get_model (GTK_COMBO_BOX (lang_chooser)), NULL)) { gtk_combo_box_set_active (GTK_COMBO_BOX (CWID("xkb_languages_available")), 10); } else { /* If language info is not available - remove the corresponding tab, pretend there is no notebook at all */ gtk_notebook_remove_page (GTK_NOTEBOOK (notebook), 1); gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE); gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE); } // #ifdef HAVE_X11_EXTENSIONS_XKB_H if (!strcmp (xkl_engine_get_backend_name (engine), "XKB")) { kbdraw = xkb_layout_preview_create_widget (chooser_dialog); g_object_set_data (G_OBJECT (chooser), "kbdraw", kbdraw); gtk_container_add (GTK_CONTAINER (CWID ("previewFrame")), kbdraw); gtk_widget_show_all (kbdraw); gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (CWID("hbtnBox")), CWID("btnPrint"), TRUE); } else // #endif { #if GTK_CHECK_VERSION (3, 0, 0) gtk_widget_hide (CWID ("vboxPreview")); #else gtk_widget_hide_all (CWID ("vboxPreview")); #endif gtk_widget_hide (CWID ("btnPrint")); } g_signal_connect (G_OBJECT (chooser), "response", G_CALLBACK (xkb_layout_chooser_response), chooser_dialog); toplevel = gtk_widget_get_toplevel (chooser); if (gtk_widget_is_toplevel (toplevel)) { GdkRectangle *rect = matekbd_preview_load_position (); if (rect != NULL) { gtk_window_move (GTK_WINDOW (toplevel), rect->x, rect->y); gtk_window_resize (GTK_WINDOW (toplevel), rect->width, rect->height); g_free (rect); } } xkb_layout_preview_update (chooser_dialog); gtk_widget_set_name(GTK_WIDGET(chooser), "ukuicc"); gtk_dialog_run (GTK_DIALOG (chooser)); gtk_widget_destroy (chooser); } gchar * xkb_layout_chooser_get_selected_id (GtkBuilder * chooser_dialog) { GtkWidget *cbv = CWID (gtk_notebook_get_current_page (GTK_NOTEBOOK (CWID ("choosers_nb"))) ? "xkb_language_variants_available" : "xkb_country_variants_available"); GtkTreeModel *vm = gtk_combo_box_get_model (GTK_COMBO_BOX (cbv)); GtkTreeIter viter; gchar *v_id; if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (cbv), &viter)) return NULL; gtk_tree_model_get (vm, &viter, COMBO_BOX_MODEL_COL_XKB_ID, &v_id, -1); return v_id; } ukui-control-center/panels/keyboard/eggcellrendererkeys.h0000664000175000017500000000641013057175444022704 0ustar fengfeng/* gtkcellrendererkeybinding.h * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __EGG_CELL_RENDERER_KEYS_H__ #define __EGG_CELL_RENDERER_KEYS_H__ #include #include "eggaccelerators.h" #ifdef __cplusplus extern "C" { #endif #define EGG_TYPE_CELL_RENDERER_KEYS (egg_cell_renderer_keys_get_type ()) #define EGG_CELL_RENDERER_KEYS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_CELL_RENDERER_KEYS, EggCellRendererKeys)) #define EGG_CELL_RENDERER_KEYS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_CELL_RENDERER_KEYS, EggCellRendererKeysClass)) #define EGG_IS_CELL_RENDERER_KEYS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_CELL_RENDERER_KEYS)) #define EGG_IS_CELL_RENDERER_KEYS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_CELL_RENDERER_KEYS)) #define EGG_CELL_RENDERER_KEYS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_CELL_RENDERER_KEYS, EggCellRendererKeysClass)) typedef struct _EggCellRendererKeys EggCellRendererKeys; typedef struct _EggCellRendererKeysClass EggCellRendererKeysClass; typedef enum { EGG_CELL_RENDERER_KEYS_MODE_GTK, EGG_CELL_RENDERER_KEYS_MODE_X } EggCellRendererKeysMode; struct _EggCellRendererKeys { GtkCellRendererText parent; guint accel_key; guint keycode; EggVirtualModifierType accel_mask; GtkWidget *edit_widget; GtkWidget *grab_widget; guint edit_key; GtkWidget *sizing_label; EggCellRendererKeysMode accel_mode; }; struct _EggCellRendererKeysClass { GtkCellRendererTextClass parent_class; void (* accel_edited) (EggCellRendererKeys *keys, const char *path_string, guint keyval, EggVirtualModifierType mask, guint hardware_keycode); void (* accel_cleared) (EggCellRendererKeys *keys, const char *path_string); }; GType egg_cell_renderer_keys_get_type (void); GtkCellRenderer *egg_cell_renderer_keys_new (void); void egg_cell_renderer_keys_set_accelerator (EggCellRendererKeys *keys, guint keyval, guint keycode, EggVirtualModifierType mask); void egg_cell_renderer_keys_get_accelerator (EggCellRendererKeys *keys, guint *keyval, EggVirtualModifierType *mask); void egg_cell_renderer_keys_set_accel_mode (EggCellRendererKeys *keys, EggCellRendererKeysMode accel_mode); #ifdef __cplusplus } #endif #endif /* __GTK_CELL_RENDERER_KEYS_H__ */ ukui-control-center/panels/keyboard/eggaccelerators.c0000664000175000017500000004406113057175444022010 0ustar fengfeng/* eggaccelerators.c * Copyright (C) 2002 Red Hat, Inc.; * Copyright 1998, 2001 Tim Janik * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * Developed by Havoc Pennington, Tim Janik * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "eggaccelerators.h" #include #include #include #include #include #if GTK_CHECK_VERSION (3, 0, 0) #include #endif enum { EGG_MODMAP_ENTRY_SHIFT = 0, EGG_MODMAP_ENTRY_LOCK = 1, EGG_MODMAP_ENTRY_CONTROL = 2, EGG_MODMAP_ENTRY_MOD1 = 3, EGG_MODMAP_ENTRY_MOD2 = 4, EGG_MODMAP_ENTRY_MOD3 = 5, EGG_MODMAP_ENTRY_MOD4 = 6, EGG_MODMAP_ENTRY_MOD5 = 7, EGG_MODMAP_ENTRY_LAST = 8 }; #define MODMAP_ENTRY_TO_MODIFIER(x) (1 << (x)) typedef struct { EggVirtualModifierType mapping[EGG_MODMAP_ENTRY_LAST]; } EggModmap; const EggModmap* egg_keymap_get_modmap(GdkKeymap* keymap); static inline gboolean is_alt(const gchar* string) { return ((string[0] == '<') && (string[1] == 'a' || string[1] == 'A') && (string[2] == 'l' || string[2] == 'L') && (string[3] == 't' || string[3] == 'T') && (string[4] == '>')); } static inline gboolean is_ctl (const gchar* string) { return ((string[0] == '<') && (string[1] == 'c' || string[1] == 'C') && (string[2] == 't' || string[2] == 'T') && (string[3] == 'l' || string[3] == 'L') && (string[4] == '>')); } static inline gboolean is_modx(const gchar* string) { return ((string[0] == '<') && (string[1] == 'm' || string[1] == 'M') && (string[2] == 'o' || string[2] == 'O') && (string[3] == 'd' || string[3] == 'D') && (string[4] >= '1' && string[4] <= '5') && (string[5] == '>')); } static inline gboolean is_ctrl(const gchar* string) { return ((string[0] == '<') && (string[1] == 'c' || string[1] == 'C') && (string[2] == 't' || string[2] == 'T') && (string[3] == 'r' || string[3] == 'R') && (string[4] == 'l' || string[4] == 'L') && (string[5] == '>')); } static inline gboolean is_shft (const gchar* string) { return ((string[0] == '<') && (string[1] == 's' || string[1] == 'S') && (string[2] == 'h' || string[2] == 'H') && (string[3] == 'f' || string[3] == 'F') && (string[4] == 't' || string[4] == 'T') && (string[5] == '>')); } static inline gboolean is_shift(const gchar* string) { return ((string[0] == '<') && (string[1] == 's' || string[1] == 'S') && (string[2] == 'h' || string[2] == 'H') && (string[3] == 'i' || string[3] == 'I') && (string[4] == 'f' || string[4] == 'F') && (string[5] == 't' || string[5] == 'T') && (string[6] == '>')); } static inline gboolean is_control(const gchar* string) { return ((string[0] == '<') && (string[1] == 'c' || string[1] == 'C') && (string[2] == 'o' || string[2] == 'O') && (string[3] == 'n' || string[3] == 'N') && (string[4] == 't' || string[4] == 'T') && (string[5] == 'r' || string[5] == 'R') && (string[6] == 'o' || string[6] == 'O') && (string[7] == 'l' || string[7] == 'L') && (string[8] == '>')); } static inline gboolean is_release(const gchar* string) { return ((string[0] == '<') && (string[1] == 'r' || string[1] == 'R') && (string[2] == 'e' || string[2] == 'E') && (string[3] == 'l' || string[3] == 'L') && (string[4] == 'e' || string[4] == 'E') && (string[5] == 'a' || string[5] == 'A') && (string[6] == 's' || string[6] == 'S') && (string[7] == 'e' || string[7] == 'E') && (string[8] == '>')); } static inline gboolean is_meta(const gchar* string) { return ((string[0] == '<') && (string[1] == 'm' || string[1] == 'M') && (string[2] == 'e' || string[2] == 'E') && (string[3] == 't' || string[3] == 'T') && (string[4] == 'a' || string[4] == 'A') && (string[5] == '>')); } static inline gboolean is_super(const gchar* string) { return ((string[0] == '<') && (string[1] == 's' || string[1] == 'S') && (string[2] == 'u' || string[2] == 'U') && (string[3] == 'p' || string[3] == 'P') && (string[4] == 'e' || string[4] == 'E') && (string[5] == 'r' || string[5] == 'R') && (string[6] == '>')); } static inline gboolean is_hyper(const gchar *string) { return ((string[0] == '<') && (string[1] == 'h' || string[1] == 'H') && (string[2] == 'y' || string[2] == 'Y') && (string[3] == 'p' || string[3] == 'P') && (string[4] == 'e' || string[4] == 'E') && (string[5] == 'r' || string[5] == 'R') && (string[6] == '>')); } static inline gboolean is_primary(const gchar* string) { return ((string[0] == '<') && (string[1] == 'p' || string[1] == 'P') && (string[2] == 'r' || string[2] == 'R') && (string[3] == 'i' || string[3] == 'I') && (string[4] == 'm' || string[4] == 'M') && (string[5] == 'a' || string[5] == 'A') && (string[6] == 'r' || string[6] == 'R') && (string[7] == 'y' || string[7] == 'Y') && (string[8] == '>')); } static inline gboolean is_keycode(const gchar *string) { return ((string[0] == '0') && (string[1] == 'x')); } /** * egg_accelerator_parse_virtual: * @accelerator: string representing an accelerator * @accelerator_key: return location for accelerator keyval * @accelerator_mods: return location for accelerator modifier mask * * Parses a string representing a virtual accelerator. The format * looks like "<Control>a" or "<Shift><Alt>F1" or * "<Release>z" (the last one is for key release). The parser * is fairly liberal and allows lower or upper case, and also * abbreviations such as "<Ctl>" and "<Ctrl>". * * If the parse fails, @accelerator_key and @accelerator_mods will * be set to 0 (zero) and %FALSE will be returned. If the string contains * only modifiers, @accelerator_key will be set to 0 but %TRUE will be * returned. * * The virtual vs. concrete accelerator distinction is a relic of * how the X Window System works; there are modifiers Mod2-Mod5 that * can represent various keyboard keys (numlock, meta, hyper, etc.), * the virtual modifier represents the keyboard key, the concrete * modifier the actual Mod2-Mod5 bits in the key press event. * * Returns: %TRUE on success. */ gboolean egg_accelerator_parse_virtual (const gchar *accelerator, guint *accelerator_key, guint *keycode, EggVirtualModifierType *accelerator_mods) { guint keyval; GdkModifierType mods; gint len; gboolean bad_keyval; if (accelerator_key) *accelerator_key = 0; if (accelerator_mods) *accelerator_mods = 0; if (keycode) *keycode = 0; g_return_val_if_fail (accelerator != NULL, FALSE); bad_keyval = FALSE; keyval = 0; mods = 0; len = strlen (accelerator); while (len) { if (*accelerator == '<') { if (len >= 9 && is_release (accelerator)) { accelerator += 9; len -= 9; mods |= EGG_VIRTUAL_RELEASE_MASK; } else if (len >= 9 && is_control (accelerator)) { accelerator += 9; len -= 9; mods |= EGG_VIRTUAL_CONTROL_MASK; } else if (len >= 9 && is_primary (accelerator)) { accelerator += 9; len -= 9; mods |= EGG_VIRTUAL_CONTROL_MASK; } else if (len >= 7 && is_shift (accelerator)) { accelerator += 7; len -= 7; mods |= EGG_VIRTUAL_SHIFT_MASK; } else if (len >= 6 && is_shft (accelerator)) { accelerator += 6; len -= 6; mods |= EGG_VIRTUAL_SHIFT_MASK; } else if (len >= 6 && is_ctrl (accelerator)) { accelerator += 6; len -= 6; mods |= EGG_VIRTUAL_CONTROL_MASK; } else if (len >= 6 && is_modx (accelerator)) { static const guint mod_vals[] = { EGG_VIRTUAL_ALT_MASK, EGG_VIRTUAL_MOD2_MASK, EGG_VIRTUAL_MOD3_MASK, EGG_VIRTUAL_MOD4_MASK, EGG_VIRTUAL_MOD5_MASK }; len -= 6; accelerator += 4; mods |= mod_vals[*accelerator - '1']; accelerator += 2; } else if (len >= 5 && is_ctl (accelerator)) { accelerator += 5; len -= 5; mods |= EGG_VIRTUAL_CONTROL_MASK; } else if (len >= 5 && is_alt (accelerator)) { accelerator += 5; len -= 5; mods |= EGG_VIRTUAL_ALT_MASK; } else if (len >= 6 && is_meta (accelerator)) { accelerator += 6; len -= 6; mods |= EGG_VIRTUAL_META_MASK; } else if (len >= 7 && is_hyper (accelerator)) { accelerator += 7; len -= 7; mods |= EGG_VIRTUAL_HYPER_MASK; } else if (len >= 7 && is_super (accelerator)) { accelerator += 7; len -= 7; mods |= EGG_VIRTUAL_SUPER_MASK; } else { gchar last_ch; last_ch = *accelerator; while (last_ch && last_ch != '>') { last_ch = *accelerator; accelerator += 1; len -= 1; } } } else { keyval = gdk_keyval_from_name (accelerator); if (keyval == 0) { /* If keyval is 0, then maybe it's a keycode. Check for 0x## */ if (len >= 4 && is_keycode (accelerator)) { char keystring[5]; gchar *endptr; gint tmp_keycode; memcpy (keystring, accelerator, 4); keystring [4] = '\000'; tmp_keycode = strtol (keystring, &endptr, 16); if (endptr == NULL || *endptr != '\000') { bad_keyval = TRUE; } else if (keycode != NULL) { *keycode = tmp_keycode; /* 0x00 is an invalid keycode too. */ if (*keycode == 0) bad_keyval = TRUE; } } } else if (keycode != NULL) { *keycode = XKeysymToKeycode (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), keyval); if (*keycode == 0) bad_keyval = TRUE; } accelerator += len; len -= len; } } if (accelerator_key) *accelerator_key = gdk_keyval_to_lower (keyval); if (accelerator_mods) *accelerator_mods = mods; return !bad_keyval; } /** * egg_virtual_accelerator_name: * @accelerator_key: accelerator keyval * @accelerator_mods: accelerator modifier mask * @returns: a newly-allocated accelerator name * * Converts an accelerator keyval and modifier mask * into a string parseable by egg_accelerator_parse_virtual(). * For example, if you pass in #GDK_q and #EGG_VIRTUAL_CONTROL_MASK, * this function returns "<Control>q". * * The caller of this function must free the returned string. */ gchar* egg_virtual_accelerator_name (guint accelerator_key, guint keycode, EggVirtualModifierType accelerator_mods) { /* Acá esta el problema... * */ gchar* gtk_name; GdkModifierType gdkmods = 0; egg_keymap_resolve_virtual_modifiers(NULL, accelerator_mods, &gdkmods); /* en la funcion gtk_accelerator_name, desde la modificacion del 16 de sep * del 2011 en GTK+, la tecla es tomada como (?) */ gtk_name = gtk_accelerator_name(accelerator_key, gdkmods); if (!accelerator_key) { gchar *name; name = g_strdup_printf ("%s0x%02x", gtk_name, keycode); g_free (gtk_name); return name; } return gtk_name; } /** * egg_virtual_accelerator_label: * @accelerator_key: accelerator keyval * @accelerator_mods: accelerator modifier mask * @returns: a newly-allocated accelerator label * * Converts an accelerator keyval and modifier mask * into a (possibly translated) string that can be displayed to * a user. * For example, if you pass in #GDK_q and #EGG_VIRTUAL_CONTROL_MASK, * and you use a German locale, this function returns "Strg+Q". * * The caller of this function must free the returned string. */ gchar* egg_virtual_accelerator_label (guint accelerator_key, guint keycode, EggVirtualModifierType accelerator_mods) { gchar *gtk_label; GdkModifierType gdkmods = 0; egg_keymap_resolve_virtual_modifiers (NULL, accelerator_mods, &gdkmods); gtk_label = gtk_accelerator_get_label (accelerator_key, gdkmods); if (!accelerator_key) { gchar *label; label = g_strdup_printf ("%s0x%02x", gtk_label, keycode); g_free (gtk_label); return label; } return gtk_label; } void egg_keymap_resolve_virtual_modifiers (GdkKeymap* keymap, EggVirtualModifierType virtual_mods, GdkModifierType* concrete_mods) { GdkModifierType concrete; int i; const EggModmap* modmap; g_return_if_fail (concrete_mods != NULL); g_return_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap)); modmap = egg_keymap_get_modmap(keymap); /* Not so sure about this algorithm. */ concrete = 0; for (i = 0; i < EGG_MODMAP_ENTRY_LAST; ++i) { if (modmap->mapping[i] & virtual_mods) { concrete |= MODMAP_ENTRY_TO_MODIFIER (i); } } *concrete_mods = concrete; } void egg_keymap_virtualize_modifiers (GdkKeymap *keymap, GdkModifierType concrete_mods, EggVirtualModifierType *virtual_mods) { GdkModifierType virtual; int i; const EggModmap *modmap; g_return_if_fail (virtual_mods != NULL); g_return_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap)); modmap = egg_keymap_get_modmap (keymap); /* Not so sure about this algorithm. */ virtual = 0; for (i = 0; i < EGG_MODMAP_ENTRY_LAST; ++i) { if (MODMAP_ENTRY_TO_MODIFIER (i) & concrete_mods) { EggVirtualModifierType cleaned; cleaned = modmap->mapping[i] & ~(EGG_VIRTUAL_MOD2_MASK | EGG_VIRTUAL_MOD3_MASK | EGG_VIRTUAL_MOD4_MASK | EGG_VIRTUAL_MOD5_MASK); if (cleaned != 0) { virtual |= cleaned; } else { /* Rather than dropping mod2->mod5 if not bound, * go ahead and use the concrete names */ virtual |= modmap->mapping[i]; } } } *virtual_mods = virtual; } static void reload_modmap (GdkKeymap *keymap, EggModmap *modmap) { XModifierKeymap *xmodmap; int map_size; int i; /* FIXME multihead */ xmodmap = XGetModifierMapping (gdk_x11_get_default_xdisplay ()); memset (modmap->mapping, 0, sizeof (modmap->mapping)); /* there are 8 modifiers in the order shift, shift lock, * control, mod1-5 with up to max_keypermod bindings each */ map_size = 8 * xmodmap->max_keypermod; for (i = 3 * xmodmap->max_keypermod; i < map_size; ++i) { /* get the key code at this point in the map, * see if its keysym is one we're interested in */ int keycode = xmodmap->modifiermap[i]; GdkKeymapKey *keys; guint *keyvals; int n_entries; int j; EggVirtualModifierType mask; keys = NULL; keyvals = NULL; n_entries = 0; gdk_keymap_get_entries_for_keycode (keymap, keycode, &keys, &keyvals, &n_entries); mask = 0; for (j = 0; j < n_entries; ++j) { if (keyvals[j] == GDK_Num_Lock) mask |= EGG_VIRTUAL_NUM_LOCK_MASK; else if (keyvals[j] == GDK_Scroll_Lock) mask |= EGG_VIRTUAL_SCROLL_LOCK_MASK; else if (keyvals[j] == GDK_Meta_L || keyvals[j] == GDK_Meta_R) mask |= EGG_VIRTUAL_META_MASK; else if (keyvals[j] == GDK_Hyper_L || keyvals[j] == GDK_Hyper_R) mask |= EGG_VIRTUAL_HYPER_MASK; else if (keyvals[j] == GDK_Super_L || keyvals[j] == GDK_Super_R) mask |= EGG_VIRTUAL_SUPER_MASK; else if (keyvals[j] == GDK_Mode_switch) mask |= EGG_VIRTUAL_MODE_SWITCH_MASK; } /* Mod1Mask is 1 << 3 for example, i.e. the * fourth modifier, i / keyspermod is the modifier * index */ modmap->mapping[i/xmodmap->max_keypermod] |= mask; g_free (keyvals); g_free (keys); } /* Add in the not-really-virtual fixed entries */ modmap->mapping[EGG_MODMAP_ENTRY_SHIFT] |= EGG_VIRTUAL_SHIFT_MASK; modmap->mapping[EGG_MODMAP_ENTRY_CONTROL] |= EGG_VIRTUAL_CONTROL_MASK; modmap->mapping[EGG_MODMAP_ENTRY_LOCK] |= EGG_VIRTUAL_LOCK_MASK; modmap->mapping[EGG_MODMAP_ENTRY_MOD1] |= EGG_VIRTUAL_ALT_MASK; modmap->mapping[EGG_MODMAP_ENTRY_MOD2] |= EGG_VIRTUAL_MOD2_MASK; modmap->mapping[EGG_MODMAP_ENTRY_MOD3] |= EGG_VIRTUAL_MOD3_MASK; modmap->mapping[EGG_MODMAP_ENTRY_MOD4] |= EGG_VIRTUAL_MOD4_MASK; modmap->mapping[EGG_MODMAP_ENTRY_MOD5] |= EGG_VIRTUAL_MOD5_MASK; XFreeModifiermap (xmodmap); } const EggModmap* egg_keymap_get_modmap (GdkKeymap *keymap) { EggModmap *modmap; if (keymap == NULL) keymap = gdk_keymap_get_default (); /* This is all a hack, much simpler when we can just * modify GDK directly. */ modmap = g_object_get_data (G_OBJECT (keymap), "egg-modmap"); if (modmap == NULL) { modmap = g_new0 (EggModmap, 1); /* FIXME modify keymap change events with an event filter * and force a reload if we get one */ reload_modmap (keymap, modmap); g_object_set_data_full (G_OBJECT (keymap), "egg-modmap", modmap, g_free); } g_assert (modmap != NULL); return modmap; } ukui-control-center/panels/keyboard/ukui-keyboard-properties-xkbmc.c0000664000175000017500000002351113253611037024711 0ustar fengfeng/* -*- mode: c; style: linux -*- */ /* ukui-keyboard-properties-xkbmc.c * Copyright (C) 2003-2007 Sergey V. Udaltsov * * Written by: Sergey V. Udaltsov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include #include #include #if GTK_CHECK_VERSION (3, 0, 0) #define gtk_widget_hide_all gtk_widget_hide #endif #include "ukui-keyboard-properties-xkb.h" static gchar *current_model_name = NULL; static gchar *current_vendor_name = NULL; static void fill_models_list (GtkBuilder * chooser_dialog); static gboolean fill_vendors_list (GtkBuilder * chooser_dialog); static GtkTreePath * gtk_list_store_find_entry (GtkListStore * list_store, GtkTreeIter * iter, gchar * name, int column_id) { GtkTreePath *path; char *current_name = NULL; if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), iter)) { do { gtk_tree_model_get (GTK_TREE_MODEL (list_store), iter, column_id, ¤t_name, -1); if (!g_ascii_strcasecmp (name, current_name)) { path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_store), iter); return path; } g_free (current_name); } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (list_store), iter)); } return NULL; } static void add_vendor_to_list (XklConfigRegistry * config_registry, XklConfigItem * config_item, GtkTreeView * vendors_list) { GtkTreeIter iter; GtkTreePath *found_existing; GtkListStore *list_store; gchar *vendor_name = (gchar *) g_object_get_data (G_OBJECT (config_item), XCI_PROP_VENDOR); if (vendor_name == NULL) return; list_store = GTK_LIST_STORE (gtk_tree_view_get_model (vendors_list)); if (!g_ascii_strcasecmp (config_item->name, current_model_name)) { current_vendor_name = g_strdup (vendor_name); } found_existing = gtk_list_store_find_entry (list_store, &iter, vendor_name, 0); /* This vendor is already there */ if (found_existing != NULL) { gtk_tree_path_free (found_existing); return; } gtk_list_store_append (list_store, &iter); gtk_list_store_set (list_store, &iter, 0, vendor_name, -1); } static void add_model_to_list (XklConfigRegistry * config_registry, XklConfigItem * config_item, GtkTreeView * models_list) { GtkTreeIter iter; GtkListStore *list_store = GTK_LIST_STORE (gtk_tree_view_get_model (models_list)); char *utf_model_name; if (current_vendor_name != NULL) { gchar *vendor_name = (gchar *) g_object_get_data (G_OBJECT (config_item), XCI_PROP_VENDOR); if (vendor_name == NULL) return; if (g_ascii_strcasecmp (vendor_name, current_vendor_name)) return; } utf_model_name = xci_desc_to_utf8 (config_item); gtk_list_store_append (list_store, &iter); gtk_list_store_set (list_store, &iter, 0, utf_model_name, 1, config_item->name, -1); g_free (utf_model_name); } static void xkb_model_chooser_change_vendor_sel (GtkTreeSelection * selection, GtkBuilder * chooser_dialog) { GtkTreeIter iter; GtkTreeModel *list_store = NULL; if (gtk_tree_selection_get_selected (selection, &list_store, &iter)) { gchar *vendor_name = NULL; gtk_tree_model_get (list_store, &iter, 0, &vendor_name, -1); current_vendor_name = vendor_name; fill_models_list (chooser_dialog); g_free (vendor_name); } else { current_vendor_name = NULL; fill_models_list (chooser_dialog); } } static void xkb_model_chooser_change_model_sel (GtkTreeSelection * selection, GtkBuilder * chooser_dialog) { gboolean anysel = gtk_tree_selection_get_selected (selection, NULL, NULL); gtk_dialog_set_response_sensitive (GTK_DIALOG (CWID ("xkb_model_chooser")), GTK_RESPONSE_OK, anysel); } static void prepare_vendors_list (GtkBuilder * chooser_dialog) { GtkWidget *vendors_list = CWID ("vendors_list"); GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); GtkTreeViewColumn *vendor_col = gtk_tree_view_column_new_with_attributes ("Vendors", renderer, "text", 0, NULL); gtk_tree_view_column_set_visible (vendor_col, TRUE); gtk_tree_view_append_column (GTK_TREE_VIEW (vendors_list), vendor_col); } static gboolean fill_vendors_list (GtkBuilder * chooser_dialog) { GtkWidget *vendors_list = CWID ("vendors_list"); GtkListStore *list_store = gtk_list_store_new (1, G_TYPE_STRING); GtkTreeIter iter; GtkTreePath *path; gtk_tree_view_set_model (GTK_TREE_VIEW (vendors_list), GTK_TREE_MODEL (list_store)); gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store), 0, GTK_SORT_ASCENDING); current_vendor_name = NULL; xkl_config_registry_foreach_model (config_registry, (ConfigItemProcessFunc) add_vendor_to_list, vendors_list); if (current_vendor_name != NULL) { path = gtk_list_store_find_entry (list_store, &iter, current_vendor_name, 0); if (path != NULL) { gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (vendors_list)), &iter); gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (vendors_list), path, NULL, TRUE, 0.5, 0); gtk_tree_path_free (path); } fill_models_list (chooser_dialog); g_free (current_vendor_name); } else { fill_models_list (chooser_dialog); } g_signal_connect (G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (vendors_list))), "changed", G_CALLBACK (xkb_model_chooser_change_vendor_sel), chooser_dialog); return gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), &iter); } static void prepare_models_list (GtkBuilder * chooser_dialog) { GtkWidget *models_list = CWID ("models_list"); GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); GtkTreeViewColumn *description_col = gtk_tree_view_column_new_with_attributes ("Models", renderer, "text", 0, NULL); gtk_tree_view_column_set_visible (description_col, TRUE); gtk_tree_view_append_column (GTK_TREE_VIEW (models_list), description_col); } static void fill_models_list (GtkBuilder * chooser_dialog) { GtkWidget *models_list = CWID ("models_list"); GtkTreeIter iter; GtkTreePath *path; GtkListStore *list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store), 0, GTK_SORT_ASCENDING); gtk_tree_view_set_model (GTK_TREE_VIEW (models_list), GTK_TREE_MODEL (list_store)); xkl_config_registry_foreach_model (config_registry, (ConfigItemProcessFunc) add_model_to_list, models_list); if (current_model_name != NULL) { path = gtk_list_store_find_entry (list_store, &iter, current_model_name, 1); if (path != NULL) { gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (models_list)), &iter); gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (models_list), path, NULL, TRUE, 0.5, 0); gtk_tree_path_free (path); } } g_signal_connect (G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (models_list))), "changed", G_CALLBACK (xkb_model_chooser_change_model_sel), chooser_dialog); } static void xkb_model_chooser_response (GtkDialog * dialog, gint response, GtkBuilder * chooser_dialog) { if (response == GTK_RESPONSE_OK) { GtkWidget *models_list = CWID ("models_list"); GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (models_list)); GtkTreeIter iter; GtkTreeModel *list_store = NULL; if (gtk_tree_selection_get_selected (selection, &list_store, &iter)) { gchar *model_name = NULL; gtk_tree_model_get (list_store, &iter, 1, &model_name, -1); g_settings_set_string (xkb_kbd_settings, "model", model_name); g_free (model_name); } } } void choose_model (GtkBuilder * dialog) { GtkBuilder *chooser_dialog; GtkWidget *chooser; chooser_dialog = gtk_builder_new (); if (gtk_builder_add_from_file(chooser_dialog, UIDIR"/ukui-keyboard-properties-model-chooser.ui",NULL) == 0) { g_warning("Can not find ui file in /usr/share/ukui-control-center/ui"); if (gtk_builder_add_from_file (chooser_dialog, "../panels/keyboard/ukui-keyboard-properties-model-chooser.ui", NULL) == 0) { g_warning("Can not find ui file"); return; } } chooser = CWID ("xkb_model_chooser"); gtk_window_set_transient_for (GTK_WINDOW (chooser), GTK_WINDOW (WID ("keyboard_dialog"))); current_model_name = g_settings_get_string (xkb_kbd_settings, "model"); prepare_vendors_list (chooser_dialog); prepare_models_list (chooser_dialog); if (!fill_vendors_list (chooser_dialog)) { gtk_widget_hide_all (CWID ("vendors_label")); gtk_widget_hide_all (CWID ("vendors_scrolledwindow")); current_vendor_name = NULL; fill_models_list (chooser_dialog); } g_signal_connect (G_OBJECT (chooser), "response", G_CALLBACK (xkb_model_chooser_response), chooser_dialog); gtk_widget_set_name(GTK_WIDGET(chooser), "ukuicc"); gtk_dialog_run (GTK_DIALOG (chooser)); gtk_widget_destroy (chooser); g_free (current_model_name); } ukui-control-center/panels/keyboard/wm-common.h0000664000175000017500000000130013253611037020550 0ustar fengfeng#ifndef WM_COMMON_H #define WM_COMMON_H #define WM_COMMON_MARCO "Marco" #define WM_COMMON_UKWM "Ukwm" #define WM_COMMON_SAWFISH "Sawfish" #define WM_COMMON_METACITY "Metacity" #define WM_COMMON_COMPIZ "Compiz" #define WM_COMMON_COMPIZ_OLD "compiz" #define WM_COMMON_UNKNOWN "Unknown" gchar *wm_common_get_current_window_manager (void); /* Returns a strv of keybinding names for the window manager; * using _UKUI_WM_KEYBINDINGS if available, _NET_WM_NAME otherwise. */ char **wm_common_get_current_keybindings (void); void wm_common_register_window_manager_change (GFunc func, gpointer data); void wm_common_update_window (void); #endif /* WM_COMMON_H */ ukui-control-center/panels/keyboard/ukui-keyboard-properties-xkb.c0000664000175000017500000001676213253611037024403 0ustar fengfeng/* -*- mode: c; style: linux -*- */ /* ukui-keyboard-properties-xkb.c * Copyright (C) 2003-2007 Sergey V. Udaltsov * * Written by: Sergey V. Udaltsov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include #include #include #include "ukui-keyboard-properties-xkb.h" #include #define XKB_GENERAL_SCHEMA "org.mate.peripherals-keyboard-xkb.general" #define XKB_KBD_SCHEMA "org.mate.peripherals-keyboard-xkb.kbd" XklEngine *engine; XklConfigRegistry *config_registry; MatekbdKeyboardConfig initial_config; MatekbdDesktopConfig desktop_config; GSettings *xkb_general_settings; GSettings *xkb_kbd_settings; char * xci_desc_to_utf8 (XklConfigItem * ci) { char *sd = g_strstrip (ci->description); return sd[0] == 0 ? g_strdup (ci->name) : g_strdup (sd); } static void set_model_text (GtkWidget * picker, gchar * value) { XklConfigItem *ci = xkl_config_item_new (); char *model = NULL; if (value != NULL) { model = g_strdup(value); if (model != NULL && model[0] == '\0') model = NULL; } if (model == NULL) { model = g_strdup(initial_config.model); if (model == NULL) model = g_strdup(""); } g_snprintf (ci->name, sizeof (ci->name), "%s", model); if (xkl_config_registry_find_model (config_registry, ci)) { char *d; d = xci_desc_to_utf8 (ci); gtk_button_set_label (GTK_BUTTON (picker), d); g_free (d); } else { gtk_button_set_label (GTK_BUTTON (picker), "Unknown"); } g_object_unref (G_OBJECT (ci)); if (value != NULL) g_free (value); g_free (model); } static void model_key_changed (GSettings * settings, gchar * key, GtkBuilder * dialog) { //set_model_text (WID ("xkb_model_pick"), // g_settings_get_string (settings, key)); enable_disable_restoring (dialog); } static void setup_model_entry (GtkBuilder * dialog) { gchar *value; value = g_settings_get_string (xkb_kbd_settings, "model"); //set_model_text (WID ("xkb_model_pick"), value); g_signal_connect (xkb_kbd_settings, "changed::model", G_CALLBACK (model_key_changed), dialog); } static void cleanup_xkb_tabs (GtkBuilder * dialog) { matekbd_desktop_config_term (&desktop_config); matekbd_keyboard_config_term (&initial_config); g_object_unref (G_OBJECT (config_registry)); config_registry = NULL; g_object_unref (G_OBJECT (engine)); engine = NULL; g_object_unref (G_OBJECT (xkb_kbd_settings)); xkb_kbd_settings = NULL; g_object_unref (G_OBJECT (xkb_general_settings)); xkb_general_settings = NULL; } static void reset_to_defaults (GtkWidget * button, GtkBuilder * dialog) { MatekbdKeyboardConfig empty_kbd_config; matekbd_keyboard_config_init (&empty_kbd_config, engine); matekbd_keyboard_config_save_to_gsettings (&empty_kbd_config); matekbd_keyboard_config_term (&empty_kbd_config); g_settings_reset (xkb_general_settings, "default-group"); /* all the rest is g-s-d's business */ } static void chk_separate_group_per_window_toggled (GSettings * settings, gchar * key, GtkBuilder * dialog) { gtk_widget_set_sensitive (WID ("chk_new_windows_inherit_layout"), g_settings_get_boolean (settings, key)); } static void chk_new_windows_inherit_layout_toggled (GtkWidget * chk_new_windows_inherit_layout, GtkBuilder * dialog) { xkb_save_default_group (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (chk_new_windows_inherit_layout)) ? -1 : 0); } void setup_xkb_tabs (GtkBuilder * dialog) { GtkWidget *chk_new_windows_inherit_layout = WID ("chk_new_windows_inherit_layout"); xkb_general_settings = g_settings_new (XKB_GENERAL_SCHEMA); xkb_kbd_settings = g_settings_new (XKB_KBD_SCHEMA); engine = xkl_engine_get_instance (GDK_DISPLAY_XDISPLAY(gdk_display_get_default())); config_registry = xkl_config_registry_get_instance (engine); matekbd_desktop_config_init (&desktop_config, engine); matekbd_desktop_config_load_from_gsettings (&desktop_config); xkl_config_registry_load (config_registry, desktop_config.load_extra_items); matekbd_keyboard_config_init (&initial_config, engine); matekbd_keyboard_config_load_from_x_initial (&initial_config, NULL); setup_model_entry (dialog); g_settings_bind (xkb_general_settings, "group-per-window", WID ("chk_separate_group_per_window"), "active", G_SETTINGS_BIND_DEFAULT); g_signal_connect (xkb_general_settings, "changed::group-per-window", G_CALLBACK (chk_separate_group_per_window_toggled), dialog); //don't have x11-extensions-xkb.h we need write code regularly #ifdef HAVE_X11_EXTENSIONS_XKB_H if (strcmp (xkl_engine_get_backend_name (engine), "XKB")) #endif xkb_layouts_prepare_selected_tree (dialog); xkb_layouts_fill_selected_tree (dialog); gtk_widget_set_sensitive (chk_new_windows_inherit_layout, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (WID ("chk_separate_group_per_window")))); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (chk_new_windows_inherit_layout), xkb_get_default_group () < 0); xkb_layouts_register_buttons_handlers (dialog); g_signal_connect (G_OBJECT (WID ("xkb_reset_to_defaults")), "clicked", G_CALLBACK (reset_to_defaults), dialog); g_signal_connect (G_OBJECT (chk_new_windows_inherit_layout), "toggled", (GCallback) chk_new_windows_inherit_layout_toggled, dialog); // g_signal_connect_swapped (G_OBJECT (WID ("xkb_layout_options")), // "clicked", // G_CALLBACK (xkb_options_popup_dialog), // dialog); // g_signal_connect_swapped (G_OBJECT (WID ("xkb_model_pick")), // "clicked", G_CALLBACK (choose_model), // dialog); xkb_layouts_register_gsettings_listener (dialog); xkb_options_register_gsettings_listener (dialog); /*g_signal_connect (G_OBJECT (WID ("keyboard_dialog")), "destroy", G_CALLBACK (cleanup_xkb_tabs), dialog); */ enable_disable_restoring (dialog); } void enable_disable_restoring (GtkBuilder * dialog) { MatekbdKeyboardConfig gswic; gboolean enable; matekbd_keyboard_config_init (&gswic, engine); matekbd_keyboard_config_load_from_gsettings (&gswic, NULL); enable = !matekbd_keyboard_config_equals (&gswic, &initial_config); matekbd_keyboard_config_term (&gswic); gtk_widget_set_sensitive (WID ("xkb_reset_to_defaults"), enable); } void xkb_save_gslist_as_strv (gchar *schema, gchar *key, GSList *list) { GSettings *settings; GArray *array; GSList *l; array = g_array_new (TRUE, TRUE, sizeof (gchar *)); for (l = list; l; l = l->next) { array = g_array_append_val (array, l->data); } settings = g_settings_new (schema); g_settings_set_strv (settings, key, (const gchar **) array->data); g_array_free (array, TRUE); g_object_unref (settings); } void xkb_layouts_set_selected_list(GSList *list) { xkb_save_gslist_as_strv (XKB_KBD_SCHEMA, "layouts", list); } void xkb_options_set_selected_list(GSList *list) { xkb_save_gslist_as_strv (XKB_KBD_SCHEMA, "options", list); } ukui-control-center/panels/keyboard/wm-common.c0000664000175000017500000001142013253611037020547 0ustar fengfeng#include #include #include #include #include #include #include "wm-common.h" typedef struct _WMCallbackData { GFunc func; gpointer data; } WMCallbackData; /* Our WM Window */ static Window wm_window = None; static char * wm_common_get_window_manager_property (Atom atom) { Atom utf8_string, type; int result; char *retval; int format; gulong nitems; gulong bytes_after; gchar *val; if (wm_window == None) return NULL; utf8_string = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "UTF8_STRING", False); gdk_error_trap_push (); val = NULL; result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), wm_window, atom, 0, G_MAXLONG, False, utf8_string, &type, &format, &nitems, &bytes_after, (guchar **) &val); if (gdk_error_trap_pop () || result != Success || type != utf8_string || format != 8 || nitems == 0 || !g_utf8_validate (val, nitems, NULL)) { retval = NULL; } else { retval = g_strndup (val, nitems); } if (val) XFree (val); return retval; } char* wm_common_get_current_window_manager (void) { Atom atom = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "_NET_WM_NAME", False); char *result; result = wm_common_get_window_manager_property (atom); if (result) return result; else return g_strdup (WM_COMMON_UNKNOWN); } char** wm_common_get_current_keybindings (void) { Atom keybindings_atom = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "_UKUI_WM_KEYBINDINGS", False); char *keybindings = wm_common_get_window_manager_property (keybindings_atom); char **results; if (keybindings) { char **p; results = g_strsplit(keybindings, ",", -1); for (p = results; *p; p++) g_strstrip (*p); g_free (keybindings); } else { Atom wm_atom = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "_NET_WM_NAME", False); char *wm_name = wm_common_get_window_manager_property (wm_atom); char *to_copy[] = { NULL, NULL }; to_copy[0] = wm_name ? wm_name : WM_COMMON_UNKNOWN; results = g_strdupv (to_copy); g_free (wm_name); } return results; } static void update_wm_window (void) { Window *xwindow; Atom type; gint format; gulong nitems; gulong bytes_after; XGetWindowProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), GDK_ROOT_WINDOW (), XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "_NET_SUPPORTING_WM_CHECK", False), 0, G_MAXLONG, False, XA_WINDOW, &type, &format, &nitems, &bytes_after, (guchar **) &xwindow); if (type != XA_WINDOW) { wm_window = None; return; } gdk_error_trap_push (); XSelectInput (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), *xwindow, StructureNotifyMask | PropertyChangeMask); XSync (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), False); if (gdk_error_trap_pop ()) { XFree (xwindow); wm_window = None; return; } wm_window = *xwindow; XFree (xwindow); } static GdkFilterReturn wm_window_event_filter (GdkXEvent *xev, GdkEvent *event, gpointer data) { WMCallbackData *ncb_data = (WMCallbackData*) data; XEvent *xevent = (XEvent *)xev; if ((xevent->type == DestroyNotify && wm_window != None && xevent->xany.window == wm_window) || (xevent->type == PropertyNotify && xevent->xany.window == GDK_ROOT_WINDOW () && xevent->xproperty.atom == (XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "_NET_SUPPORTING_WM_CHECK", False))) || (xevent->type == PropertyNotify && wm_window != None && xevent->xany.window == wm_window && xevent->xproperty.atom == (XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "_NET_WM_NAME", False)))) { update_wm_window (); (* ncb_data->func) ((gpointer)wm_common_get_current_window_manager(), ncb_data->data); } return GDK_FILTER_CONTINUE; } void wm_common_register_window_manager_change (GFunc func, gpointer data) { WMCallbackData *ncb_data; ncb_data = g_new0 (WMCallbackData, 1); ncb_data->func = func; ncb_data->data = data; gdk_window_add_filter (NULL, wm_window_event_filter, ncb_data); update_wm_window (); XSelectInput (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), GDK_ROOT_WINDOW (), PropertyChangeMask); XSync (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), False); } void wm_common_update_window () { update_wm_window(); } ukui-control-center/panels/keyboard/ukui-keybinding-properties.h0000664000175000017500000000017313245450076024143 0ustar fengfeng#include void init_keybinding_tabs(GtkBuilder * builder); void destroy_keybinding_tabs(GtkBuilder * builder); ukui-control-center/panels/keyboard/ukui-keyboard-properties.c0000664000175000017500000001436013253611037023611 0ustar fengfeng/* -*- mode: c; style: linux -*- */ /* keyboard-properties.c * Copyright (C) 2000-2001 Ximian, Inc. * Copyright (C) 2001 Jonathan Blandford * * Written by: Bradford Hovinen * Rachel Hestilow * Jonathan Blandford * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "ukui-keyboard-properties.h" #include #include #include #include #include "ukui-keyboard-properties-a11y.h" #include "ukui-keyboard-properties-xkb.h" #include "ukui-keybinding-properties.h" #define KEYBOARD_SCHEMA "org.mate.peripherals-keyboard" #define INTERFACE_SCHEMA "org.mate.interface" #define TYPING_BREAK_SCHEMA "org.mate.typing-break" #define MWID(s) GTK_WIDGET(gtk_builder_get_object(builder, s)) enum { RESPONSE_APPLY = 1, RESPONSE_CLOSE }; static GSettings * keyboard_settings = NULL; static GSettings * interface_settings = NULL; static GSettings * typing_break_settings = NULL; gboolean activate_settings_daemon(); gboolean activate_settings_daemon() { DBusGConnection * connection = NULL; DBusGProxy * proxy =NULL; GError * error = NULL; connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error); if (connection == NULL) { g_warning("keyboard connect error\n"); g_error_free(error); return FALSE; } proxy = dbus_g_proxy_new_for_name(connection, "org.ukui.SettingsDaemon", "/org/ukui/SettingsDaemon", "org.ukui.SettingsDaemon"); dbus_g_connection_unref(connection); if (proxy ==NULL) { g_warning("Keyboard's SettingsDaemon proxy get error"); return FALSE; } if (!org_ukui_SettingsDaemon_awake(proxy, &error)) { g_warning("awake SettingsDaemon error%s\n",error->message); return FALSE; } return TRUE; } void create_dialog (GtkBuilder * builder) { GtkSizeGroup *size_group; GtkWidget *image; size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); gtk_size_group_add_widget (size_group, MWID ("repeat_slow_label")); gtk_size_group_add_widget (size_group, MWID ("delay_short_label")); gtk_size_group_add_widget (size_group, MWID ("blink_slow_label")); g_object_unref (G_OBJECT (size_group)); size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); gtk_size_group_add_widget (size_group, MWID ("repeat_fast_label")); gtk_size_group_add_widget (size_group, MWID ("delay_long_label")); gtk_size_group_add_widget (size_group, MWID ("blink_fast_label")); g_object_unref (G_OBJECT (size_group)); size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); gtk_size_group_add_widget (size_group, MWID ("repeat_delay_scale")); gtk_size_group_add_widget (size_group, MWID ("repeat_speed_scale")); gtk_size_group_add_widget (size_group, MWID ("cursor_blink_time_scale")); g_object_unref (G_OBJECT (size_group)); image = gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON); gtk_button_set_image (GTK_BUTTON (MWID ("xkb_layouts_add")), image); image = gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_BUTTON); gtk_button_set_image (GTK_BUTTON (MWID ("xkb_reset_to_defaults")), image); } void setup_dialog (GtkBuilder * builder) { gchar *monitor; GtkWidget *label_entry = GTK_WIDGET(gtk_builder_get_object(builder, "label20")); gtk_label_set_xalign(GTK_LABEL(label_entry), 0.0); g_settings_bind (keyboard_settings, "repeat", MWID ("repeat_toggle"), "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (keyboard_settings, "repeat", MWID ("repeat_table"), "sensitive", G_SETTINGS_BIND_DEFAULT); g_settings_bind (keyboard_settings, "delay", gtk_range_get_adjustment (GTK_RANGE (MWID ("repeat_delay_scale"))), "value", G_SETTINGS_BIND_DEFAULT); g_settings_bind (keyboard_settings, "rate", gtk_range_get_adjustment (GTK_RANGE (MWID ("repeat_speed_scale"))), "value", G_SETTINGS_BIND_DEFAULT); g_settings_bind (interface_settings, "cursor-blink", MWID ("cursor_toggle"), "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (interface_settings, "cursor-blink", MWID ("cursor_hbox"), "sensitive", G_SETTINGS_BIND_DEFAULT); g_settings_bind (interface_settings, "cursor-blink-time", gtk_range_get_adjustment (GTK_RANGE (MWID ("cursor_blink_time_scale"))), "value", G_SETTINGS_BIND_DEFAULT); setup_xkb_tabs (builder); //hide two parts by Spy //gtk_widget_hide(MWID("xkb_models_box")); //gtk_widget_hide(MWID("xkb_layout_options")); // setup_a11y_tabs (builder); } void add_keyboard_app(GtkBuilder *builder) { g_debug("add_keyboard_app"); GtkWidget *keyboard_notebook; keyboard_notebook = GTK_WIDGET(gtk_builder_get_object(builder, "keyboard_notebook")); //gtk_notebook_remove_page(GTK_NOTEBOOK(keyboard_notebook), 2); activate_settings_daemon(); keyboard_settings = g_settings_new (KEYBOARD_SCHEMA); interface_settings = g_settings_new (INTERFACE_SCHEMA); typing_break_settings = g_settings_new (TYPING_BREAK_SCHEMA); init_keybinding_tabs(builder); create_dialog (builder); setup_dialog (builder); } void destory_keyboard_app(GtkBuilder * builder) { //finalize_a11y_tabs (); destroy_keybinding_tabs(builder); g_object_unref (keyboard_settings); g_object_unref (interface_settings); g_object_unref (typing_break_settings); } ukui-control-center/panels/keyboard/ukui-keybinding-properties.c0000664000175000017500000020065713253611037024142 0ustar fengfeng#include "ukui-keybinding-properties.h" #include #include #include #include #include #include #include #include #include #if GTK_CHECK_VERSION (3, 0, 0) #include #endif #include "wm-common.h" #include "eggcellrendererkeys.h" #include "dconf-util.h" #define GSETTINGS_KEYBINDINGS_DIR "/org/mate/desktop/keybindings/" #define GSETTINGS_KEYBINDINGS_SYSTEM "/org/gnome/desktop/wm/keybindings/" #define CUSTOM_KEYBINDING_SCHEMA "org.ukui.control-center.keybinding" #define MARCO_KEY "org.gnome.desktop.wm.keybindings" #define MAX_ELEMENTS_BEFORE_SCROLLING 10 #define MAX_CUSTOM_SHORTCUTS 1000 #define RESPONSE_ADD 0 #define RESPONSE_REMOVE 1 typedef struct { /* The untranslated name, combine with ->package to translate */ char *name; /* The gettext package to use to translate the section title */ char *package; /* Name of the window manager the keys would apply to */ char *wm_name; /* The GSettings schema for the whole file */ char *schema; /* an array of KeyListEntry */ GArray *entries; } KeyList; GArray * system_entries; typedef enum { COMPARISON_NONE = 0, COMPARISON_GT, COMPARISON_LT, COMPARISON_EQ } Comparison; typedef struct { char *gsettings_path; char *schema; char *name; int value; char *value_schema; /* gsettings schema for key/value */ char *value_key; char *description; char *description_key; char *cmd_key; Comparison comparison; } KeyListEntry; typedef struct { char *gsettings_path; char *imp_key; EggVirtualModifierType mask; guint keyval; guint keycode; } KeySysEntry; enum { DESCRIPTION_COLUMN, KEYENTRY_COLUMN, N_COLUMNS }; typedef struct { GSettings *settings; char *gsettings_path; char *gsettings_key; guint keyval; guint keycode; EggVirtualModifierType mask; gboolean editable; GtkTreeModel *model; char *description; char *desc_gsettings_key; gboolean desc_editable; char *command; char *cmd_gsettings_key; gboolean cmd_editable; gulong gsettings_cnxn; gulong gsettings_cnxn_desc; gulong gsettings_cnxn_cmd; } KeyEntry; static GtkBuilder * shortcut_builder; static GSettings *marco_settings; static gboolean block_accels = FALSE; static GtkWidget *custom_shortcut_dialog = NULL; static GtkWidget *custom_shortcut_name_entry = NULL; static GtkWidget *custom_shortcut_command_entry = NULL; static GtkWidget *custom_shortcut_lookup_button = NULL; static GtkWidget* _gtk_builder_get_widget(GtkBuilder* builder, const gchar* name) { return GTK_WIDGET (gtk_builder_get_object (builder, name)); } static char* binding_name(guint keyval, guint keycode, EggVirtualModifierType mask, gboolean translate) { if (keyval != 0 || keycode != 0) { if (translate) { return egg_virtual_accelerator_label (keyval, keycode, mask); } else { return egg_virtual_accelerator_name (keyval, keycode, mask); } } else { return g_strdup (translate ? "Disabled" : ""); } } static gboolean binding_from_string (const char *str, guint *accelerator_key, guint *keycode, EggVirtualModifierType *accelerator_mods) { g_return_val_if_fail (accelerator_key != NULL, FALSE); if (str == NULL || strcmp (str, "disabled") == 0) { *accelerator_key = 0; *keycode = 0; *accelerator_mods = 0; return TRUE; } egg_accelerator_parse_virtual (str, accelerator_key, keycode, accelerator_mods); if (*accelerator_key == 0) return FALSE; else return TRUE; } static void accel_set_func (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { KeyEntry *key_entry; gtk_tree_model_get (model, iter, KEYENTRY_COLUMN, &key_entry, -1); if (key_entry == NULL) g_object_set (cell, "visible", FALSE, NULL); else if (! key_entry->editable) g_object_set (cell, "visible", TRUE, "editable", FALSE, "accel_key", key_entry->keyval, "accel_mask", key_entry->mask, "keycode", key_entry->keycode, "style", PANGO_STYLE_ITALIC, NULL); else g_object_set (cell, "visible", TRUE, "editable", TRUE, "accel_key", key_entry->keyval, "accel_mask", key_entry->mask, "keycode", key_entry->keycode, "style", PANGO_STYLE_NORMAL, NULL); } static void description_set_func (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { KeyEntry *key_entry; gtk_tree_model_get (model, iter, KEYENTRY_COLUMN, &key_entry, -1); if (key_entry != NULL) g_object_set (cell, "editable", FALSE, "text", key_entry->description != NULL ? key_entry->description : "", NULL); else g_object_set (cell, "editable", FALSE, NULL); } static gboolean keybinding_key_changed_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data) { KeyEntry *key_entry; KeyEntry *tmp_key_entry; key_entry = (KeyEntry *)user_data; gtk_tree_model_get (key_entry->model, iter, KEYENTRY_COLUMN, &tmp_key_entry, -1); if (key_entry == tmp_key_entry) { gtk_tree_model_row_changed (key_entry->model, path, iter); return TRUE; } return FALSE; } static void keybinding_key_changed (GSettings *settings, gchar *key, KeyEntry *key_entry) { gchar *key_value; key_value = g_settings_get_string (settings, key); binding_from_string (key_value, &key_entry->keyval, &key_entry->keycode, &key_entry->mask); key_entry->editable = g_settings_is_writable (settings, key); /* update the model */ gtk_tree_model_foreach (key_entry->model, keybinding_key_changed_foreach, key_entry); } static void keybinding_description_changed (GSettings *settings, gchar *key, KeyEntry *key_entry) { gchar *key_value; key_value = g_settings_get_string (settings, key); g_free (key_entry->description); key_entry->description = key_value ? g_strdup (key_value) : NULL; g_free (key_value); key_entry->desc_editable = g_settings_is_writable (settings, key); /* update the model */ gtk_tree_model_foreach (key_entry->model, keybinding_key_changed_foreach, key_entry); } static void keybinding_command_changed (GSettings *settings, gchar *key, KeyEntry *key_entry) { gchar *key_value; key_value = g_settings_get_string (settings, key); g_free (key_entry->command); key_entry->command = key_value ? g_strdup (key_value) : NULL; key_entry->cmd_editable = g_settings_is_writable (settings, key); g_free (key_value); /* update the model */ gtk_tree_model_foreach (key_entry->model, keybinding_key_changed_foreach, key_entry); } static int keyentry_sort_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) { KeyEntry *key_entry_a; KeyEntry *key_entry_b; int retval; key_entry_a = NULL; gtk_tree_model_get (model, a, KEYENTRY_COLUMN, &key_entry_a, -1); key_entry_b = NULL; gtk_tree_model_get (model, b, KEYENTRY_COLUMN, &key_entry_b, -1); if (key_entry_a && key_entry_b) { if ((key_entry_a->keyval || key_entry_a->keycode) && (key_entry_b->keyval || key_entry_b->keycode)) { gchar *name_a, *name_b; name_a = binding_name (key_entry_a->keyval, key_entry_a->keycode, key_entry_a->mask, TRUE); name_b = binding_name (key_entry_b->keyval, key_entry_b->keycode, key_entry_b->mask, TRUE); retval = g_utf8_collate (name_a, name_b); g_free (name_a); g_free (name_b); } else if (key_entry_a->keyval || key_entry_a->keycode) retval = -1; else if (key_entry_b->keyval || key_entry_b->keycode) retval = 1; else retval = 0; } else if (key_entry_a) retval = -1; else if (key_entry_b) retval = 1; else retval = 0; return retval; } static void clear_old_model (GtkBuilder *builder) { GtkWidget *tree_view; GtkWidget *actions_swindow; GtkTreeModel *model; tree_view = _gtk_builder_get_widget (builder, "shortcut_treeview"); model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); if (model == NULL) { /* create a new model */ model = (GtkTreeModel *) gtk_tree_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER); gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model), KEYENTRY_COLUMN, keyentry_sort_func, NULL, NULL); gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), model); g_object_unref (model); } else { /* clear the existing model */ gboolean valid; GtkTreeIter iter; KeyEntry *key_entry; for (valid = gtk_tree_model_get_iter_first (model, &iter); valid; valid = gtk_tree_model_iter_next (model, &iter)) { gtk_tree_model_get (model, &iter, KEYENTRY_COLUMN, &key_entry, -1); if (key_entry != NULL) { g_signal_handler_disconnect (key_entry->settings, key_entry->gsettings_cnxn); if (key_entry->gsettings_cnxn_desc != 0) g_signal_handler_disconnect (key_entry->settings, key_entry->gsettings_cnxn_desc); if (key_entry->gsettings_cnxn_cmd != 0) g_signal_handler_disconnect (key_entry->settings, key_entry->gsettings_cnxn_cmd); g_object_unref (key_entry->settings); if (key_entry->gsettings_path) g_free (key_entry->gsettings_path); g_free (key_entry->gsettings_key); g_free (key_entry->description); g_free (key_entry->desc_gsettings_key); g_free (key_entry->command); g_free (key_entry->cmd_gsettings_key); g_free (key_entry); } } gtk_tree_store_clear (GTK_TREE_STORE (model)); } actions_swindow = _gtk_builder_get_widget (builder, "actions_swindow"); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (actions_swindow), GTK_POLICY_NEVER, GTK_POLICY_NEVER); gtk_widget_set_size_request (actions_swindow, -1, -1); } typedef struct { const char *key; const char *path; const char *schema; gboolean found; } KeyMatchData; static gboolean key_match(GtkTreeModel* model, GtkTreePath* path, GtkTreeIter* iter, gpointer data) { KeyMatchData* match_data = data; KeyEntry* element = NULL; gchar *element_schema = NULL; gchar *element_path = NULL; gtk_tree_model_get(model, iter, KEYENTRY_COLUMN, &element, -1); if (element && element->settings && G_IS_SETTINGS(element->settings)) { #if GLIB_CHECK_VERSION (2, 32, 0) g_object_get (element->settings, "schema-id", &element_schema, NULL); #else g_object_get (element->settings, "schema", &element_schema, NULL); #endif g_object_get (element->settings, "path", &element_path, NULL); } if (element && g_strcmp0(element->gsettings_key, match_data->key) == 0 && g_strcmp0(element_schema, match_data->schema) == 0 && g_strcmp0(element_path, match_data->path) == 0) { match_data->found = TRUE; return TRUE; } return FALSE; } static gboolean key_is_already_shown(GtkTreeModel* model, const KeyListEntry* entry) { KeyMatchData data; data.key = entry->name; data.schema = entry->schema; data.path = entry->gsettings_path; data.found = FALSE; gtk_tree_model_foreach(model, key_match, &data); return data.found; } static gboolean should_show_key(const KeyListEntry* entry) { GSettings *settings; int value; if (entry->comparison == COMPARISON_NONE) { return TRUE; } g_return_val_if_fail(entry->value_key != NULL, FALSE); g_return_val_if_fail(entry->value_schema != NULL, FALSE); settings = g_settings_new (entry->value_schema); value = g_settings_get_int (settings, entry->value_key); g_object_unref (settings); switch (entry->comparison) { case COMPARISON_NONE: /* For compiler warnings */ g_assert_not_reached (); return FALSE; case COMPARISON_GT: if (value > entry->value) { return TRUE; } break; case COMPARISON_LT: if (value < entry->value) { return TRUE; } break; case COMPARISON_EQ: if (value == entry->value) { return TRUE; } break; } return FALSE; } static gboolean count_rows_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { gint *rows = data; (*rows)++; return FALSE; } static void ensure_scrollbar (GtkBuilder *builder, int i) { if (i == MAX_ELEMENTS_BEFORE_SCROLLING) { GtkRequisition rectangle; GObject *actions_swindow = gtk_builder_get_object (builder, "actions_swindow"); GtkWidget *treeview = _gtk_builder_get_widget (builder, "shortcut_treeview"); gtk_widget_ensure_style (treeview); gtk_widget_size_request (treeview, &rectangle); gtk_widget_set_size_request (treeview, -1, rectangle.height); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (actions_swindow), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); } } static void find_section (GtkTreeModel *model, GtkTreeIter *iter, const char *title) { gboolean success; success = gtk_tree_model_get_iter_first (model, iter); while (success) { char *description = NULL; gtk_tree_model_get (model, iter, DESCRIPTION_COLUMN, &description, -1); if (g_strcmp0 (description, title) == 0) return; success = gtk_tree_model_iter_next (model, iter); } gtk_tree_store_append (GTK_TREE_STORE (model), iter, NULL); gtk_tree_store_set (GTK_TREE_STORE (model), iter, DESCRIPTION_COLUMN, title, -1); } static void append_keys_to_tree (GtkBuilder *builder, const gchar *title, const gchar *schema, const gchar *package, const KeyListEntry *keys_list) { GtkTreeIter parent_iter, iter; GtkTreeModel *model; gint i, j; model = gtk_tree_view_get_model (GTK_TREE_VIEW (gtk_builder_get_object (builder, "shortcut_treeview"))); /* Try to find a section parent iter, if it already exists */ find_section (model, &iter, title); parent_iter = iter; i = 0; gtk_tree_model_foreach (model, count_rows_foreach, &i); /* If the header we just added is the MAX_ELEMENTS_BEFORE_SCROLLING th, * then we need to scroll now */ ensure_scrollbar (builder, i - 1); for (j = 0; keys_list[j].name != NULL; j++) { GSettings *settings = NULL; gchar *settings_path; KeyEntry *key_entry; const gchar *key_string; gchar *key_value; gchar *description; gchar *command; if (!should_show_key (&keys_list[j])) continue; if (key_is_already_shown (model, &keys_list[j])) continue; key_string = keys_list[j].name; if (keys_list[j].gsettings_path != NULL) { settings = g_settings_new_with_path (schema, keys_list[j].gsettings_path); settings_path = g_strdup(keys_list[j].gsettings_path); } else { settings = g_settings_new (schema); settings_path = NULL; } if (keys_list[j].description_key != NULL) { /* it's a custom shortcut, so description is in gsettings */ description = g_settings_get_string (settings, keys_list[j].description_key); } else { /* it's from keyfile, so description need to be translated */ description = keys_list[j].description; if (package) { bind_textdomain_codeset (package, "UTF-8"); description = dgettext (package, description); } else { description = description; } } if (description == NULL) { /* Only print a warning for keys that should have a schema */ if (keys_list[j].description_key == NULL) g_warning ("No description for key '%s'", key_string); } if (keys_list[j].cmd_key != NULL) { command = g_settings_get_string (settings, keys_list[j].cmd_key); } else { command = NULL; } key_entry = g_new0 (KeyEntry, 1); key_entry->settings = settings; key_entry->gsettings_path = settings_path; key_entry->gsettings_key = g_strdup (key_string); key_entry->editable = g_settings_is_writable (settings, key_string); key_entry->model = model; key_entry->description = description; key_entry->command = command; if (keys_list[j].description_key != NULL) { key_entry->desc_gsettings_key = g_strdup (keys_list[j].description_key); key_entry->desc_editable = g_settings_is_writable (settings, key_entry->desc_gsettings_key); gchar *gsettings_signal = g_strconcat ("changed::", key_entry->desc_gsettings_key, NULL); key_entry->gsettings_cnxn_desc = g_signal_connect (settings, gsettings_signal, G_CALLBACK (keybinding_description_changed), key_entry); g_free (gsettings_signal); } if (keys_list[j].cmd_key != NULL) { key_entry->cmd_gsettings_key = g_strdup (keys_list[j].cmd_key); key_entry->cmd_editable = g_settings_is_writable (settings, key_entry->cmd_gsettings_key); gchar *gsettings_signal = g_strconcat ("changed::", key_entry->cmd_gsettings_key, NULL); key_entry->gsettings_cnxn_cmd = g_signal_connect (settings, gsettings_signal, G_CALLBACK (keybinding_command_changed), key_entry); g_free (gsettings_signal); } gchar *gsettings_signal = g_strconcat ("changed::", key_string, NULL); key_entry->gsettings_cnxn = g_signal_connect (settings, gsettings_signal, G_CALLBACK (keybinding_key_changed), key_entry); g_free (gsettings_signal); key_value = g_settings_get_string (settings, key_string); binding_from_string (key_value, &key_entry->keyval, &key_entry->keycode, &key_entry->mask); //g_warning("keyvalue=%s keyval=%d & keycode%d\n",key_value,key_entry->keyval, key_entry->keycode); g_free (key_value); ensure_scrollbar (builder, i); ++i; gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent_iter); /* we use the DESCRIPTION_COLUMN only for the section headers */ gtk_tree_store_set (GTK_TREE_STORE (model), &iter, KEYENTRY_COLUMN, key_entry, -1); gtk_tree_view_expand_all (GTK_TREE_VIEW (gtk_builder_get_object (builder, "shortcut_treeview"))); } /* Don't show an empty section */ if (gtk_tree_model_iter_n_children (model, &parent_iter) == 0) gtk_tree_store_remove (GTK_TREE_STORE (model), &parent_iter); if (i == 0) gtk_widget_hide (_gtk_builder_get_widget (builder, "shortcuts_vbox")); else gtk_widget_show (_gtk_builder_get_widget (builder, "shortcuts_vbox")); } static void parse_start_tag (GMarkupParseContext *ctx, const gchar *element_name, const gchar **attr_names, const gchar **attr_values, gpointer user_data, GError **error) { KeyList *keylist = (KeyList *) user_data; KeyListEntry key; const char *name, *value_key, *description, *value_schema; int value; Comparison comparison; const char *schema = NULL; name = NULL; /* The top-level element, names the section in the tree */ if (g_str_equal (element_name, "KeyListEntries")) { const char *wm_name = NULL; const char *package = NULL; while (*attr_names && *attr_values) { if (g_str_equal (*attr_names, "name")) { if (**attr_values) name = *attr_values; } else if (g_str_equal (*attr_names, "wm_name")) { if (**attr_values) wm_name = *attr_values; } else if (g_str_equal (*attr_names, "package")) { if (**attr_values) package = *attr_values; } else if (g_str_equal (*attr_names, "schema")) { if (**attr_values) schema = *attr_values; } ++attr_names; ++attr_values; } if (name) { if (keylist->name) g_warning ("Duplicate section name"); g_free (keylist->name); keylist->name = g_strdup (name); } if (wm_name) { if (keylist->wm_name) g_warning ("Duplicate window manager name"); g_free (keylist->wm_name); keylist->wm_name = g_strdup (wm_name); } if (package) { if (keylist->package) g_warning ("Duplicate gettext package name"); g_free (keylist->package); keylist->package = g_strdup (package); } if (schema) { if (keylist->schema) g_warning ("Duplicate schema name"); g_free (keylist->schema); keylist->schema = g_strdup (schema); } return; } if (!g_str_equal (element_name, "KeyListEntry") || attr_names == NULL || attr_values == NULL) return; value = 0; comparison = COMPARISON_NONE; value_key = NULL; value_schema = NULL; description = NULL; while (*attr_names && *attr_values) { if (g_str_equal (*attr_names, "name")) { /* skip if empty */ if (**attr_values) name = *attr_values; } else if (g_str_equal (*attr_names, "value")) { if (**attr_values) { value = (int) g_ascii_strtoull (*attr_values, NULL, 0); } } else if (g_str_equal (*attr_names, "key")) { if (**attr_values) { value_key = *attr_values; } } else if (g_str_equal (*attr_names, "comparison")) { if (**attr_values) { if (g_str_equal (*attr_values, "gt")) { comparison = COMPARISON_GT; } else if (g_str_equal (*attr_values, "lt")) { comparison = COMPARISON_LT; } else if (g_str_equal (*attr_values, "eq")) { comparison = COMPARISON_EQ; } } } else if (g_str_equal (*attr_names, "description")) { if (**attr_values) { description = *attr_values; } } else if (g_str_equal (*attr_names, "schema")) { if (**attr_values) { value_schema = *attr_values; } } ++attr_names; ++attr_values; } if (name == NULL) return; key.name = g_strdup (name); key.gsettings_path = NULL; key.description_key = NULL; key.description = g_strdup(description); key.schema = g_strdup(schema); key.value = value; if (value_key) { key.value_key = g_strdup (value_key); key.value_schema = g_strdup (value_schema); } else { key.value_key = NULL; key.value_schema = NULL; } key.comparison = comparison; key.cmd_key = NULL; g_array_append_val (keylist->entries, key); } static gboolean strv_contains (char **strv, char *str) { char **p = strv; for (p = strv; *p; p++) if (strcmp (*p, str) == 0) return TRUE; return FALSE; } static void append_keys_to_tree_from_file (GtkBuilder *builder, const char *filename, char **wm_keybindings) { GMarkupParseContext *ctx; GMarkupParser parser = { parse_start_tag, NULL, NULL, NULL, NULL }; KeyList *keylist; KeyListEntry key, *keys; GError *err = NULL; char *buf; const char *title; gsize buf_len; guint i; if (!g_file_get_contents (filename, &buf, &buf_len, &err)) return; keylist = g_new0 (KeyList, 1); keylist->entries = g_array_new (FALSE, TRUE, sizeof (KeyListEntry)); ctx = g_markup_parse_context_new (&parser, 0, keylist, NULL); if (!g_markup_parse_context_parse (ctx, buf, buf_len, &err)) { g_warning ("Failed to parse '%s': '%s'", filename, err->message); g_error_free (err); g_free (keylist->name); g_free (keylist->package); g_free (keylist->wm_name); g_free (keylist->schema); for (i = 0; i < keylist->entries->len; i++) g_free (((KeyListEntry *) &(keylist->entries->data[i]))->name); g_array_free (keylist->entries, TRUE); g_free (keylist); keylist = NULL; } g_markup_parse_context_free (ctx); g_free (buf); if (keylist == NULL) return; /* If there's no keys to add, or the settings apply to a window manager * that's not the one we're running */ if (keylist->entries->len == 0 || (keylist->wm_name != NULL && !strv_contains (wm_keybindings, keylist->wm_name)) || keylist->name == NULL) { g_free (keylist->name); g_free (keylist->package); g_free (keylist->wm_name); g_free (keylist->schema); g_array_free (keylist->entries, TRUE); g_free (keylist); return; } /* Empty KeyListEntry to end the array */ key.name = NULL; // Every times we should notice that pointer must be initialization if you // want to use it key.schema = NULL; key.description_key = NULL; key.value_key = NULL; key.value = 0; key.comparison = COMPARISON_NONE; g_array_append_val (keylist->entries, key); keys = (KeyListEntry *) g_array_free (keylist->entries, FALSE); if (keylist->package) { bind_textdomain_codeset (keylist->package, "UTF-8"); title = dgettext (keylist->package, keylist->name); } else { title = keylist->name; } append_keys_to_tree (builder, title, keylist->schema, keylist->package, keys); g_free (keylist->name); g_free (keylist->package); for (i = 0; keys[i].name != NULL; i++) g_free (keys[i].name); g_free (keylist); } static void append_keys_to_tree_from_system(GtkBuilder *builder, const gchar *gsettings_path){ gchar ** custom_list; KeySysEntry key; gint i; system_entries = g_array_new(FALSE, TRUE, sizeof(KeySysEntry)); key.gsettings_path = MARCO_KEY; key.imp_key = NULL; key.keyval = 0; key.keycode = 0; //custom_list = dconf_utils_list_children(gsettings_path, FALSE); GSettings * gsetting = g_settings_new(MARCO_KEY); char ** gs = g_settings_list_keys(gsetting); for (i=0; gs[i]!= NULL; i++){ //切换为mutter后,原先为string的变为字符串数组,这块只取了字符串数组的第一个元素 GVariant *variant = g_settings_get_value(gsetting, gs[i]); gsize size = g_variant_get_size(variant); gchar **tmp = g_variant_get_strv(variant, &size); gchar *str = tmp[0]; if(!str) continue; key.imp_key = gs[i]; binding_from_string(str,&(key.keyval), &(key.keycode), &(key.mask)); g_array_append_val(system_entries, key); //g_warning("system****str=%s keyval=%d &keycode=%d\n",str, key.keyval, key.keycode); } g_object_unref(gsetting); //g_array_free(system_entries, TRUE); } //load custom shortcuts and add null gsettings to end view static void append_keys_to_tree_from_gsettings (GtkBuilder *builder, const gchar *gsettings_path) { gchar **custom_list; GArray *entries; KeyListEntry key; gint i; /* load custom shortcuts from GSettings */ entries = g_array_new (FALSE, TRUE, sizeof (KeyListEntry)); //initialiation all member of keylistentry key.value_key = NULL; key.value = 0; key.comparison = COMPARISON_NONE; key.description = NULL; key.schema = NULL; key.value_schema =NULL; custom_list = dconf_util_list_subdirs (gsettings_path, FALSE); if (custom_list != NULL) { for (i = 0; custom_list[i] != NULL; i++) { key.gsettings_path = g_strdup_printf("%s%s", gsettings_path, custom_list[i]); key.name = g_strdup("binding"); key.cmd_key = g_strdup("action"); key.description_key = g_strdup("name"); g_array_append_val (entries, key); } } g_strfreev (custom_list); if (entries->len > 0) { KeyListEntry *keys; int i; /* Empty KeyListEntry to end the array */ key.gsettings_path = NULL; key.name = NULL; key.description_key = NULL; key.cmd_key = NULL; key.description = NULL; key.description_key =NULL; key.schema = NULL; key.value = 0; key.value_key = NULL; key.value_schema = NULL; g_array_append_val (entries, key); keys = (KeyListEntry *) entries->data; append_keys_to_tree (builder,_("Custom Shortcuts"), CUSTOM_KEYBINDING_SCHEMA, NULL, keys); for (i = 0; i < entries->len; ++i) { g_free (keys[i].name); g_free (keys[i].description_key); g_free (keys[i].cmd_key); g_free (keys[i].gsettings_path); } } g_array_free (entries, TRUE); } static void reload_key_entries (GtkBuilder *builder) { gchar **wm_keybindings; GDir *dir; const char *name; GList *list, *l; wm_keybindings = wm_common_get_current_keybindings(); clear_old_model (builder); dir = g_dir_open (UKUI_KEYBINDINGS_DIR, 0, NULL); if (!dir) return; list = NULL; for (name = g_dir_read_name (dir) ; name ; name = g_dir_read_name (dir)) { if (g_str_has_suffix (name, ".xml")) { list = g_list_insert_sorted (list, g_strdup (name), (GCompareFunc) g_ascii_strcasecmp); } } g_dir_close (dir); append_keys_to_tree_from_gsettings (builder, GSETTINGS_KEYBINDINGS_DIR); append_keys_to_tree_from_system(builder, GSETTINGS_KEYBINDINGS_SYSTEM); for (l = list; l != NULL; l = l->next) { gchar *path; path = g_build_filename (UKUI_KEYBINDINGS_DIR, l->data, NULL); append_keys_to_tree_from_file (builder, path, wm_keybindings); g_free (l->data); g_free (path); } g_list_free (list); /* Load custom shortcuts _after_ system-provided ones, * since some of the custom shortcuts may also be listed * in a file. Loading the custom shortcuts last makes * such keys not show up in the custom section. */ g_strfreev (wm_keybindings); } static void key_entry_controlling_key_changed (GSettings *settings, gchar *key, gpointer user_data) { reload_key_entries (user_data); } static void check_with_system(KeyEntry * new_key){ KeySysEntry * sysentry; gint i; sysentry = (KeySysEntry *)system_entries->data; if(!new_key->editable) return; //g_warning("new_key keyval=%d keycode=%d\n",new_key->keyval, new_key->keycode); for (i=0; sysentry[i].gsettings_path != NULL; i++){ //g_warning("sysentry keyval=%d keycode=%d\n",sysentry[i].keyval, sysentry[i].keycode); if(new_key->keyval != 0){ if(new_key->keyval != sysentry[i].keyval) continue; } else if(sysentry[i].keyval !=0 || new_key->keycode != sysentry[i].keycode) continue; new_key->editable = FALSE; new_key->settings = sysentry[i].gsettings_path; new_key->gsettings_key = sysentry[i].imp_key; } } static gboolean cb_check_for_uniqueness(GtkTreeModel* model, GtkTreePath* path, GtkTreeIter* iter, KeyEntry* new_key) { KeyEntry* element; gtk_tree_model_get (new_key->model, iter, KEYENTRY_COLUMN, &element, -1); /* no conflict for : blanks, different modifiers, or ourselves */ if (element == NULL || new_key->mask != element->mask) { return FALSE; } gchar *new_key_schema = NULL; gchar *element_schema = NULL; gchar *new_key_path = NULL; gchar *element_path = NULL; if (new_key && new_key->settings) { #if GLIB_CHECK_VERSION (2, 32, 0) g_object_get (new_key->settings, "schema-id", &new_key_schema, NULL); #else g_object_get (new_key->settings, "schema", &new_key_schema, NULL); #endif g_object_get (new_key->settings, "path", &new_key_path, NULL); } if (element->settings) { #if GLIB_CHECK_VERSION (2, 32, 0) g_object_get (element->settings, "schema-id", &element_schema, NULL); #else g_object_get (element->settings, "schema", &element_schema, NULL); #endif g_object_get (element->settings, "path", &element_path, NULL); } if (!g_strcmp0 (new_key->gsettings_key, element->gsettings_key) && !g_strcmp0 (new_key_schema, element_schema) && !g_strcmp0 (new_key_path, element_path)) { return FALSE; } if (new_key->keyval != 0) { if (new_key->keyval != element->keyval) { return FALSE; } } else if (element->keyval != 0 || new_key->keycode != element->keycode) { return FALSE; } new_key->editable = FALSE; new_key->settings = element->settings; new_key->gsettings_key = element->gsettings_key; new_key->description = element->description; new_key->desc_gsettings_key = element->desc_gsettings_key; new_key->desc_editable = element->desc_editable; return TRUE; } static const guint forbidden_keyvals[] = { /* Navigation keys */ GDK_Home, GDK_Left, GDK_Up, GDK_Right, GDK_Down, GDK_Page_Up, GDK_Page_Down, GDK_End, GDK_Tab, /* Return */ GDK_KP_Enter, GDK_Return, GDK_space, GDK_Mode_switch }; static gboolean keyval_is_forbidden(guint keyval) { guint i; for (i = 0; i < G_N_ELEMENTS(forbidden_keyvals); i++) { if (keyval == forbidden_keyvals[i]) { return TRUE; } } return FALSE; } static void show_error(GtkWindow* parent, GError* err) { GtkWidget *dialog; dialog = gtk_message_dialog_new (parent, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error saving the new shortcut"); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", err->message); gtk_widget_set_name(GTK_WIDGET(dialog), "ukuicc"); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } static void accel_edited_callback(GtkCellRendererText* cell, const char* path_string, guint keyval, EggVirtualModifierType mask, guint keycode, gpointer data) { GtkTreeView* view = (GtkTreeView*) data; GtkTreeModel* model; GtkTreePath* path = gtk_tree_path_new_from_string (path_string); GtkTreeIter iter; KeyEntry* key_entry, tmp_key; char* str; block_accels = FALSE; model = gtk_tree_view_get_model (view); gtk_tree_model_get_iter (model, &iter, path); gtk_tree_path_free (path); gtk_tree_model_get (model, &iter, KEYENTRY_COLUMN, &key_entry, -1); /* sanity check */ if (key_entry == NULL) { return; } /* CapsLock isn't supported as a keybinding modifier, so keep it from confusing us */ mask &= ~EGG_VIRTUAL_LOCK_MASK; tmp_key.model = model; tmp_key.keyval = keyval; tmp_key.keycode = keycode; tmp_key.mask = mask; tmp_key.settings = key_entry->settings; tmp_key.gsettings_key = key_entry->gsettings_key; tmp_key.description = NULL; tmp_key.editable = TRUE; /* kludge to stuff in a return flag */ if (keyval != 0 || keycode != 0) /* any number of keys can be disabled */ { gtk_tree_model_foreach(model, (GtkTreeModelForeachFunc) cb_check_for_uniqueness, &tmp_key); check_with_system(&tmp_key); } /* Check for unmodified keys */ if (tmp_key.mask == 0 && tmp_key.keycode != 0) { if ((tmp_key.keyval >= GDK_a && tmp_key.keyval <= GDK_z) || (tmp_key.keyval >= GDK_A && tmp_key.keyval <= GDK_Z) || (tmp_key.keyval >= GDK_0 && tmp_key.keyval <= GDK_9) || (tmp_key.keyval >= GDK_kana_fullstop && tmp_key.keyval <= GDK_semivoicedsound) || (tmp_key.keyval >= GDK_Arabic_comma && tmp_key.keyval <= GDK_Arabic_sukun) || (tmp_key.keyval >= GDK_Serbian_dje && tmp_key.keyval <= GDK_Cyrillic_HARDSIGN) || (tmp_key.keyval >= GDK_Greek_ALPHAaccent && tmp_key.keyval <= GDK_Greek_omega) || (tmp_key.keyval >= GDK_hebrew_doublelowline && tmp_key.keyval <= GDK_hebrew_taf) || (tmp_key.keyval >= GDK_Thai_kokai && tmp_key.keyval <= GDK_Thai_lekkao) || (tmp_key.keyval >= GDK_Hangul && tmp_key.keyval <= GDK_Hangul_Special) || (tmp_key.keyval >= GDK_Hangul_Kiyeog && tmp_key.keyval <= GDK_Hangul_J_YeorinHieuh) || keyval_is_forbidden (tmp_key.keyval)) { GtkWidget *dialog; char *name; name = binding_name (keyval, keycode, mask, TRUE); dialog = gtk_message_dialog_new ( GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))), GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_CANCEL, _("The shortcut \"%s\" cannot be used because it will become impossible to type using this key.\n" "Please try with a key such as Control, Alt or Shift at the same time."), name); g_free (name); gtk_widget_set_name(GTK_WIDGET(dialog), "ukuicc"); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); /* set it back to its previous value. */ egg_cell_renderer_keys_set_accelerator( EGG_CELL_RENDERER_KEYS(cell), key_entry->keyval, key_entry->keycode, key_entry->mask); return; } } /* flag to see if the new accelerator was in use by something */ if (!tmp_key.editable) { GtkWidget* dialog; char* name; int response; name = binding_name(keyval, keycode, mask, TRUE); dialog = gtk_message_dialog_new( GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))), GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_CANCEL, _("The shortcut \"%s\" is already used for\n\"%s\",please reset!!!"), name, tmp_key.description ? tmp_key.description : tmp_key.gsettings_key); g_free (name); /* gtk_message_dialog_format_secondary_text ( GTK_MESSAGE_DIALOG (dialog), "If you reassign the shortcut to \"%s\", the \"%s\" shortcut " "will be disabled.", key_entry->description ? key_entry->description : key_entry->gsettings_key, tmp_key.description ? tmp_key.description : tmp_key.gsettings_key); gtk_dialog_add_button(GTK_DIALOG (dialog), "_Reassign", GTK_RESPONSE_ACCEPT); gtk_dialog_set_default_response(GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); */ gtk_widget_set_name(GTK_WIDGET(dialog), "ukuicc"); response = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); if (response == GTK_RESPONSE_ACCEPT) { g_settings_set_string (tmp_key.settings, tmp_key.gsettings_key, "disabled"); str = binding_name (keyval, keycode, mask, FALSE); g_settings_set_string (key_entry->settings, key_entry->gsettings_key, str); g_free (str); } else { /* set it back to its previous value. */ egg_cell_renderer_keys_set_accelerator( EGG_CELL_RENDERER_KEYS(cell), key_entry->keyval, key_entry->keycode, key_entry->mask); } return; } str = binding_name (keyval, keycode, mask, FALSE); g_settings_set_string( key_entry->settings, key_entry->gsettings_key, str); g_free (str); } static void accel_cleared_callback (GtkCellRendererText *cell, const char *path_string, gpointer data) { GtkTreeView *view = (GtkTreeView *) data; GtkTreePath *path = gtk_tree_path_new_from_string (path_string); KeyEntry *key_entry; GtkTreeIter iter; GtkTreeModel *model; block_accels = FALSE; model = gtk_tree_view_get_model (view); gtk_tree_model_get_iter (model, &iter, path); gtk_tree_path_free (path); gtk_tree_model_get (model, &iter, KEYENTRY_COLUMN, &key_entry, -1); /* sanity check */ if (key_entry == NULL) return; /* Unset the key */ g_settings_set_string (key_entry->settings, key_entry->gsettings_key, "disabled"); } static void description_edited_callback (GtkCellRendererText *renderer, gchar *path_string, gchar *new_text, gpointer user_data) { GtkTreeView *view = GTK_TREE_VIEW (user_data); GtkTreeModel *model; GtkTreePath *path = gtk_tree_path_new_from_string (path_string); GtkTreeIter iter; KeyEntry *key_entry; model = gtk_tree_view_get_model (view); gtk_tree_model_get_iter (model, &iter, path); gtk_tree_path_free (path); gtk_tree_model_get (model, &iter, KEYENTRY_COLUMN, &key_entry, -1); /* sanity check */ if (key_entry == NULL || key_entry->desc_gsettings_key == NULL) return; if (!g_settings_set_string (key_entry->settings, key_entry->desc_gsettings_key, new_text)) key_entry->desc_editable = FALSE; } typedef struct { GtkTreeView *tree_view; GtkTreePath *path; GtkTreeViewColumn *column; } IdleData; static gboolean real_start_editing_cb (IdleData *idle_data) { gtk_widget_grab_focus (GTK_WIDGET (idle_data->tree_view)); gtk_tree_view_set_cursor (idle_data->tree_view, idle_data->path, idle_data->column, TRUE); gtk_tree_path_free (idle_data->path); g_free (idle_data); return FALSE; } static gboolean edit_custom_shortcut (KeyEntry *key) { gint result; const gchar *text; gboolean ret; gtk_entry_set_text (GTK_ENTRY (custom_shortcut_name_entry), key->description ? key->description : ""); gtk_widget_set_sensitive (custom_shortcut_name_entry, key->desc_editable); gtk_widget_grab_focus (custom_shortcut_name_entry); gtk_entry_set_text (GTK_ENTRY (custom_shortcut_command_entry), key->command ? key->command : ""); gtk_widget_set_sensitive (custom_shortcut_command_entry, key->cmd_editable); gtk_window_set_title(GTK_WINDOW(custom_shortcut_dialog),_("Add Shortcuts")); gtk_window_present (GTK_WINDOW (custom_shortcut_dialog)); gtk_widget_set_name(GTK_WIDGET(custom_shortcut_dialog), "ukuicc"); result = gtk_dialog_run (GTK_DIALOG (custom_shortcut_dialog)); switch (result) { case GTK_RESPONSE_OK: text = gtk_entry_get_text (GTK_ENTRY (custom_shortcut_name_entry)); g_free (key->description); key->description = g_strdup (text); text = gtk_entry_get_text (GTK_ENTRY (custom_shortcut_command_entry)); g_free (key->command); key->command = g_strdup (text); ret = TRUE; break; default: ret = FALSE; break; } gtk_widget_hide (custom_shortcut_dialog); return ret; } static gboolean remove_custom_shortcut (GtkTreeModel *model, GtkTreeIter *iter) { GtkTreeIter parent; KeyEntry *key; gtk_tree_model_get (model, iter, KEYENTRY_COLUMN, &key, -1); /* not a custom shortcut */ if (key->command == NULL) return FALSE; g_signal_handler_disconnect (key->settings, key->gsettings_cnxn); if (key->gsettings_cnxn_desc != 0) g_signal_handler_disconnect (key->settings, key->gsettings_cnxn_desc); if (key->gsettings_cnxn_cmd != 0) g_signal_handler_disconnect (key->settings, key->gsettings_cnxn_cmd); dconf_util_recursive_reset (key->gsettings_path, NULL); g_object_unref (key->settings); g_free (key->gsettings_path); g_free (key->gsettings_key); g_free (key->description); g_free (key->desc_gsettings_key); g_free (key->command); g_free (key->cmd_gsettings_key); g_free (key); gtk_tree_model_iter_parent (model, &parent, iter); gtk_tree_store_remove (GTK_TREE_STORE (model), iter); if (!gtk_tree_model_iter_has_child (model, &parent)) gtk_tree_store_remove (GTK_TREE_STORE (model), &parent); return TRUE; } static void update_custom_shortcut (GtkTreeModel *model, GtkTreeIter *iter) { KeyEntry *key; gtk_tree_model_get (model, iter, KEYENTRY_COLUMN, &key, -1); edit_custom_shortcut (key); if (key->command == NULL || key->command[0] == '\0') { remove_custom_shortcut (model, iter); } else { gtk_tree_store_set (GTK_TREE_STORE (model), iter, KEYENTRY_COLUMN, key, -1); if (key->description != NULL) g_settings_set_string (key->settings, key->desc_gsettings_key, key->description); else g_settings_reset (key->settings, key->desc_gsettings_key); g_settings_set_string (key->settings, key->cmd_gsettings_key, key->command); } } static gchar * find_free_gsettings_path (GError **error) { gchar **existing_dirs; gchar *dir = NULL; gchar *fulldir = NULL; int i; int j; gboolean found; existing_dirs = dconf_util_list_subdirs (GSETTINGS_KEYBINDINGS_DIR, FALSE); for (i = 0; i < MAX_CUSTOM_SHORTCUTS; i++) { found = TRUE; dir = g_strdup_printf ("custom%d/", i); for (j = 0; existing_dirs[j] != NULL; j++) if (!g_strcmp0(dir, existing_dirs[j])) { found = FALSE; g_free (dir); break; } if (found) break; } g_strfreev (existing_dirs); if (i == MAX_CUSTOM_SHORTCUTS) { g_free (dir); dir = NULL; g_set_error_literal (error, g_quark_from_string ("Keyboard Shortcuts"), 0, "Too many custom shortcuts"); } fulldir = g_strdup_printf ("%s%s", GSETTINGS_KEYBINDINGS_DIR, dir); g_free (dir); return fulldir; } static void add_custom_shortcut (GtkTreeView *tree_view, GtkTreeModel *model) { KeyEntry *key_entry; GtkTreeIter iter; GtkTreeIter parent_iter; GtkTreePath *path; gchar *dir; GError *error; error = NULL; dir = find_free_gsettings_path (&error); if (dir == NULL) { show_error (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tree_view))), error); g_error_free (error); return; } key_entry = g_new0 (KeyEntry, 1); key_entry->gsettings_path = g_strdup(dir); key_entry->gsettings_key = g_strdup("binding"); key_entry->editable = TRUE; key_entry->model = model; key_entry->desc_gsettings_key = g_strdup("name"); key_entry->description = g_strdup (""); key_entry->desc_editable = TRUE; key_entry->cmd_gsettings_key = g_strdup("action"); key_entry->command = g_strdup (""); key_entry->cmd_editable = TRUE; g_free (dir); if (edit_custom_shortcut (key_entry) && key_entry->command && key_entry->command[0]) { find_section (model, &iter, _("Custom Shortcuts")); parent_iter = iter; gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent_iter); gtk_tree_store_set (GTK_TREE_STORE (model), &iter, KEYENTRY_COLUMN, key_entry, -1); /* store in gsettings */ key_entry->settings = g_settings_new_with_path (CUSTOM_KEYBINDING_SCHEMA, key_entry->gsettings_path); g_settings_set_string (key_entry->settings, key_entry->gsettings_key, "disabled"); g_settings_set_string (key_entry->settings, key_entry->desc_gsettings_key, key_entry->description); g_settings_set_string (key_entry->settings, key_entry->cmd_gsettings_key, key_entry->command); /* add gsettings watches */ key_entry->gsettings_cnxn_desc = g_signal_connect (key_entry->settings, "changed::name", G_CALLBACK (keybinding_description_changed), key_entry); key_entry->gsettings_cnxn_cmd = g_signal_connect (key_entry->settings, "changed::action", G_CALLBACK (keybinding_command_changed), key_entry); key_entry->gsettings_cnxn = g_signal_connect (key_entry->settings, "changed::binding", G_CALLBACK (keybinding_key_changed), key_entry); /* make the new shortcut visible */ path = gtk_tree_model_get_path (model, &iter); gtk_tree_view_expand_to_path (tree_view, path); gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0, 0); gtk_tree_path_free (path); } else { g_free (key_entry->gsettings_path); g_free (key_entry->gsettings_key); g_free (key_entry->description); g_free (key_entry->desc_gsettings_key); g_free (key_entry->command); g_free (key_entry->cmd_gsettings_key); g_free (key_entry); } } static void start_editing_kb_cb (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data) { GtkTreeModel *model; GtkTreeIter iter; KeyEntry *key; model = gtk_tree_view_get_model (treeview); gtk_tree_model_get_iter (model, &iter, path); gtk_tree_model_get (model, &iter, KEYENTRY_COLUMN, &key, -1); if (key == NULL) { /* This is a section heading - expand or collapse */ if (gtk_tree_view_row_expanded (treeview, path)) gtk_tree_view_collapse_row (treeview, path); else gtk_tree_view_expand_row (treeview, path, FALSE); return; } /* if only the accel can be edited on the selected row * always select the accel column */ if (key->desc_editable && column == gtk_tree_view_get_column (treeview, 0)) { gtk_widget_grab_focus (GTK_WIDGET (treeview)); gtk_tree_view_set_cursor (treeview, path, gtk_tree_view_get_column (treeview, 0), FALSE); update_custom_shortcut (model, &iter); } else { gtk_widget_grab_focus (GTK_WIDGET (treeview)); gtk_tree_view_set_cursor (treeview, path, gtk_tree_view_get_column (treeview, 1), TRUE); } } static gboolean start_editing_cb (GtkTreeView *tree_view, GdkEventButton *event, gpointer user_data) { GtkTreePath *path; GtkTreeViewColumn *column; if (event->window != gtk_tree_view_get_bin_window (tree_view)) return FALSE; if (gtk_tree_view_get_path_at_pos (tree_view, (gint) event->x, (gint) event->y, &path, &column, NULL, NULL)) { IdleData *idle_data; GtkTreeModel *model; GtkTreeIter iter; KeyEntry *key; if (gtk_tree_path_get_depth (path) == 1) { gtk_tree_path_free (path); return FALSE; } model = gtk_tree_view_get_model (tree_view); gtk_tree_model_get_iter (model, &iter, path); gtk_tree_model_get (model, &iter, KEYENTRY_COLUMN, &key, -1); /* if only the accel can be edited on the selected row * always select the accel column */ if (key->desc_editable && column == gtk_tree_view_get_column (tree_view, 0)) { gtk_widget_grab_focus (GTK_WIDGET (tree_view)); gtk_tree_view_set_cursor (tree_view, path, gtk_tree_view_get_column (tree_view, 0), FALSE); update_custom_shortcut (model, &iter); } else { idle_data = g_new (IdleData, 1); idle_data->tree_view = tree_view; idle_data->path = path; idle_data->column = key->desc_editable ? column : gtk_tree_view_get_column (tree_view, 1); g_idle_add ((GSourceFunc) real_start_editing_cb, idle_data); block_accels = TRUE; } g_signal_stop_emission_by_name (tree_view, "button_press_event"); } return TRUE; } /* this handler is used to keep accels from activating while the user * is assigning a new shortcut so that he won't accidentally trigger one * of the widgets */ static gboolean maybe_block_accels(GtkWidget* widget, GdkEventKey* event, gpointer user_data) { if (block_accels) { return gtk_window_propagate_key_event(GTK_WINDOW(widget), event); } return FALSE; } static void cb_add_button_clicked(GtkWidget * widget, gpointer data){ GtkBuilder * builder = data; GtkTreeView * treeview; GtkTreeModel * model; treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "shortcut_treeview")); model = gtk_tree_view_get_model(treeview); add_custom_shortcut(treeview, model); } static void cb_remove_button_clicked(GtkWidget * widget, gpointer data){ GtkBuilder * builder = data; GtkTreeView * treeview; GtkTreeModel * model; GtkTreeSelection * selection; GtkTreeIter iter; treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "shortcut_treeview")); model = gtk_tree_view_get_model(treeview); selection = gtk_tree_view_get_selection(treeview); if (gtk_tree_selection_get_selected(selection, NULL, &iter)) { remove_custom_shortcut(model, &iter); } return; } static void selection_changed (GtkTreeSelection *selection, gpointer data) { GtkWidget *button = data; GtkTreeModel *model; GtkTreeIter iter; KeyEntry *key; gboolean can_remove; can_remove = FALSE; if (gtk_tree_selection_get_selected (selection, &model, &iter)) { gtk_tree_model_get (model, &iter, KEYENTRY_COLUMN, &key, -1); if (key && key->command != NULL && key->editable) can_remove = TRUE; } gtk_widget_set_sensitive (button, can_remove); } static void filechoose_result(GtkButton * button, gpointer user_data) { GtkWidget * filechoose_dialog; gint res; filechoose_dialog = gtk_file_chooser_dialog_new("", GTK_WINDOW(custom_shortcut_dialog), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_window_set_title(GTK_WINDOW(filechoose_dialog), _("Selection Program")); gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechoose_dialog),"/usr/share/applications/"); gtk_widget_set_name(GTK_WIDGET(filechoose_dialog), "ukuicc"); gtk_widget_show(filechoose_dialog); res = gtk_dialog_run(GTK_DIALOG(filechoose_dialog)); if (res == GTK_RESPONSE_ACCEPT) { char * desktop_id; char * exec; GDesktopAppInfo * appinfo; desktop_id = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechoose_dialog)); if (desktop_id == NULL) return; appinfo = g_desktop_app_info_new_from_filename(desktop_id); exec = g_desktop_app_info_get_string(appinfo, "Exec"); //去掉Exec命令中的参数,防止有些参数可能会影响快捷键的使用 gchar **tmp = g_strsplit(exec, " ", 5); gchar *short_exec = g_strdup(tmp[0]); gtk_entry_set_text(GTK_ENTRY(custom_shortcut_command_entry), short_exec); } gtk_widget_destroy(filechoose_dialog); } static void setup_dialog (GtkBuilder *builder, GSettings *marco_settings) { GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkWidget *widget; GtkTreeView *treeview; GtkTreeSelection *selection; treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "shortcut_treeview")); gtk_tree_view_set_headers_clickable(treeview, FALSE); g_signal_connect (treeview, "button_press_event", G_CALLBACK (start_editing_cb), builder); g_signal_connect (treeview, "row-activated", G_CALLBACK (start_editing_kb_cb), NULL); renderer = gtk_cell_renderer_text_new (); g_signal_connect (renderer, "edited", G_CALLBACK (description_edited_callback), treeview); column = gtk_tree_view_column_new_with_attributes (_("Function description"), renderer, "text", DESCRIPTION_COLUMN, NULL); gtk_tree_view_column_set_min_width(column, 300); gtk_tree_view_column_set_cell_data_func (column, renderer, description_set_func, NULL, NULL); gtk_tree_view_column_set_resizable (column, FALSE); gtk_tree_view_append_column (treeview, column); //gtk_tree_view_column_set_sort_column_id (column, DESCRIPTION_COLUMN); renderer = (GtkCellRenderer *) g_object_new (EGG_TYPE_CELL_RENDERER_KEYS, "accel_mode", EGG_CELL_RENDERER_KEYS_MODE_X, NULL); gtk_cell_renderer_set_padding(renderer, 0, 6); g_signal_connect (renderer, "accel_edited", G_CALLBACK (accel_edited_callback), treeview); g_signal_connect (renderer, "accel_cleared", G_CALLBACK (accel_cleared_callback), treeview); column = gtk_tree_view_column_new_with_attributes (_("Hotkey"), renderer, NULL); gtk_tree_view_column_set_min_width(column, 200); gtk_tree_view_column_set_cell_data_func (column, renderer, accel_set_func, NULL, NULL); gtk_tree_view_column_set_resizable (column, FALSE); gtk_tree_view_append_column (treeview, column); //gtk_tree_view_column_set_sort_column_id (column, KEYENTRY_COLUMN); g_signal_connect (marco_settings, "changed::num-workspaces", G_CALLBACK (key_entry_controlling_key_changed), builder); /* set up the dialog */ reload_key_entries (builder); widget = _gtk_builder_get_widget (builder, "shortcut_dialog"); g_signal_connect (widget, "key_press_event", G_CALLBACK (maybe_block_accels), NULL); g_signal_connect(_gtk_builder_get_widget(builder, "add-button"), "clicked", G_CALLBACK(cb_add_button_clicked), builder); g_signal_connect(_gtk_builder_get_widget(builder, "remove-button"), "clicked", G_CALLBACK(cb_remove_button_clicked), builder); //g_signal_connect(_gtk_builder_get_widget(builder, "close-button"), "clicked", G_CALLBACK(cb_dialog_response), builder); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); g_signal_connect (selection, "changed", G_CALLBACK (selection_changed), _gtk_builder_get_widget (builder, "remove-button")); /* setup the custom shortcut dialog */ shortcut_builder = gtk_builder_new(); if(gtk_builder_add_from_file(shortcut_builder, UIDIR"/shortcut_dialog.ui", NULL) ==0) { g_warning("Can not find ui file in UIDIR\n"); if (gtk_builder_add_from_file(shortcut_builder, "shortcut_dialog.ui", NULL)==0) { g_warning("Can not fild ui file in locale\n"); return; } } custom_shortcut_dialog = _gtk_builder_get_widget (shortcut_builder, "custom-shortcut-dialog"); custom_shortcut_name_entry = _gtk_builder_get_widget (shortcut_builder, "custom-shortcut-name-entry"); custom_shortcut_command_entry = _gtk_builder_get_widget (shortcut_builder, "custom-shortcut-command-entry"); custom_shortcut_lookup_button = _gtk_builder_get_widget (shortcut_builder, "custom-shortcut-lookup-button"); g_signal_connect(GTK_BUTTON(custom_shortcut_lookup_button), "clicked", G_CALLBACK(filechoose_result), NULL); //Fixme:I know that was wrong use toplevel window for transient's parent //because keyboard was used as static library, there should not be others information gtk_dialog_set_default_response (GTK_DIALOG (custom_shortcut_dialog), GTK_RESPONSE_OK); gtk_window_set_transient_for (GTK_WINDOW (custom_shortcut_dialog), GTK_WINDOW (_gtk_builder_get_widget(builder, "window1"))); } static void on_window_manager_change (const char *wm_name, GtkBuilder *builder) { reload_key_entries (builder); } void init_keybinding_tabs(GtkBuilder * builder) { wm_common_register_window_manager_change ((GFunc) on_window_manager_change, builder); marco_settings = g_settings_new ("org.gnome.desktop.wm.preferences"); setup_dialog (builder, marco_settings); } void destroy_keybinding_tabs(GtkBuilder * builder) { clear_old_model(builder); g_object_unref(marco_settings); g_object_unref(shortcut_builder); g_array_free(system_entries, TRUE); //Fixme: we need clear old model } ukui-control-center/panels/keyboard/ukui-keyboard-properties-xkblt.c0000664000175000017500000003233213253611037024732 0ustar fengfeng/* -*- mode: c; style: linux -*- */ /* ukui-keyboard-properties-xkblt.c * Copyright (C) 2003-2007 Sergey V. Udaltsov * * Written by: Sergey V. Udaltsov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include #include #include #include #include "ukui-keyboard-properties-xkb.h" #define SEL_LAYOUT_TREE_COL_DESCRIPTION 0 #define SEL_LAYOUT_TREE_COL_ID 1 #define SEL_LAYOUT_TREE_COL_ENABLED 2 static int idx2select = -1; static int max_selected_layouts = -1; static int default_group = -1; static GtkCellRenderer *text_renderer; static gboolean disable_buttons_sensibility_update = FALSE; void clear_xkb_elements_list (GSList * list) { while (list != NULL) { GSList *p = list; list = list->next; g_free (p->data); g_slist_free_1 (p); } } static gint find_selected_layout_idx (GtkBuilder * dialog) { GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("xkb_layouts_selected"))); GtkTreeIter selected_iter; GtkTreeModel *model; GtkTreePath *path; gint *indices; gint rv; if (!gtk_tree_selection_get_selected (selection, &model, &selected_iter)) return -1; path = gtk_tree_model_get_path (model, &selected_iter); if (path == NULL) return -1; indices = gtk_tree_path_get_indices (path); rv = indices[0]; gtk_tree_path_free (path); return rv; } GSList * xkb_layouts_get_selected_list (void) { gchar **array; GSList *retval = NULL; gint i; array = g_settings_get_strv (xkb_kbd_settings, "layouts"); if (array != NULL) { for (i = 0; array[i]; i++) { retval = g_slist_append (retval, g_strdup (array[i])); } } g_strfreev (array); if (retval == NULL) { if (initial_config.layouts_variants != NULL) { for (i = 0; initial_config.layouts_variants[i] != NULL; i++) retval = g_slist_prepend (retval, g_strdup (initial_config.layouts_variants[i])); } retval = g_slist_reverse (retval); } return retval; } gint xkb_get_default_group () { return g_settings_get_int (xkb_general_settings, "default-group"); } void xkb_save_default_group (gint default_group) { if (default_group != xkb_get_default_group ()) g_settings_set_int (xkb_general_settings, "default-group", default_group); } static void xkb_layouts_enable_disable_buttons (GtkBuilder * dialog) { GtkWidget *add_layout_btn = WID ("xkb_layouts_add"); GtkWidget *show_layout_btn = WID ("xkb_layouts_show"); GtkWidget *del_layout_btn = WID ("xkb_layouts_remove"); GtkWidget *selected_layouts_tree = WID ("xkb_layouts_selected"); GtkWidget *move_up_layout_btn = WID ("xkb_layouts_move_up"); GtkWidget *move_down_layout_btn = WID ("xkb_layouts_move_down"); GtkTreeSelection *s_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (selected_layouts_tree)); const int n_selected_selected_layouts = gtk_tree_selection_count_selected_rows (s_selection); GtkTreeModel *selected_layouts_model = gtk_tree_view_get_model (GTK_TREE_VIEW (selected_layouts_tree)); const int n_selected_layouts = gtk_tree_model_iter_n_children (selected_layouts_model, NULL); gint sidx = find_selected_layout_idx (dialog); if (disable_buttons_sensibility_update) return; gtk_widget_set_sensitive (add_layout_btn, (n_selected_layouts < max_selected_layouts || max_selected_layouts == 0)); gtk_widget_set_sensitive (del_layout_btn, (n_selected_layouts > 1) && (n_selected_selected_layouts > 0)); gtk_widget_set_sensitive (show_layout_btn, (n_selected_selected_layouts > 0)); gtk_widget_set_sensitive (move_up_layout_btn, sidx > 0); gtk_widget_set_sensitive (move_down_layout_btn, sidx >= 0 && sidx < (n_selected_layouts - 1)); } static void xkb_layouts_dnd_data_get (GtkWidget * widget, GdkDragContext * dc, GtkSelectionData * selection_data, guint info, guint t, GtkBuilder * dialog) { /* Storing the value into selection - * while it is actually not used */ gint idx = find_selected_layout_idx (dialog); gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_INTEGER, 32, (guchar *) & idx, sizeof (idx)); } static void xkb_layouts_dnd_data_received (GtkWidget * widget, GdkDragContext * dc, gint x, gint y, GtkSelectionData * selection_data, guint info, guint t, GtkBuilder * dialog) { gint sidx = find_selected_layout_idx (dialog); GtkWidget *tree_view = WID ("xkb_layouts_selected"); GtkTreePath *path = NULL; GtkTreeViewDropPosition pos; gint didx; gchar *id; GSList *layouts_list; GSList *node2Remove; if (sidx == -1) return; layouts_list = xkb_layouts_get_selected_list (); node2Remove = g_slist_nth (layouts_list, sidx); id = (gchar *) node2Remove->data; layouts_list = g_slist_delete_link (layouts_list, node2Remove); if (!gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (tree_view), x, y, &path, &pos)) { /* Move to the very end */ layouts_list = g_slist_append (layouts_list, g_strdup (id)); xkb_layouts_set_selected_list (layouts_list); } else if (path != NULL) { gint *indices = gtk_tree_path_get_indices (path); didx = indices[0]; gtk_tree_path_free (path); /* Move to the new position */ if (sidx != didx) { layouts_list = g_slist_insert (layouts_list, g_strdup (id), didx); xkb_layouts_set_selected_list (layouts_list); } } g_free (id); clear_xkb_elements_list (layouts_list); } void xkb_layouts_prepare_selected_tree (GtkBuilder * dialog) { GtkListStore *list_store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); GtkWidget *tree_view = WID ("xkb_layouts_selected"); GtkTreeSelection *selection; GtkTargetEntry self_drag_target = { "xkb_layouts_selected", GTK_TARGET_SAME_WIDGET, 0 }; GtkTreeViewColumn *desc_column; text_renderer = GTK_CELL_RENDERER (gtk_cell_renderer_text_new ()); desc_column = gtk_tree_view_column_new_with_attributes ("Layout", text_renderer, "text", SEL_LAYOUT_TREE_COL_DESCRIPTION, "sensitive", SEL_LAYOUT_TREE_COL_ENABLED, NULL); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (list_store)); gtk_tree_view_column_set_sizing (desc_column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); gtk_tree_view_column_set_resizable (desc_column, TRUE); gtk_tree_view_column_set_expand (desc_column, TRUE); gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), desc_column); g_signal_connect_swapped (G_OBJECT (selection), "changed", G_CALLBACK (xkb_layouts_enable_disable_buttons), dialog); max_selected_layouts = xkl_engine_get_max_num_groups (engine); /* Setting up DnD */ gtk_drag_source_set (tree_view, GDK_BUTTON1_MASK, &self_drag_target, 1, GDK_ACTION_MOVE); gtk_drag_source_set_icon_name (tree_view, "input-keyboard"); gtk_drag_dest_set (tree_view, GTK_DEST_DEFAULT_ALL, &self_drag_target, 1, GDK_ACTION_MOVE); g_signal_connect (G_OBJECT (tree_view), "drag_data_get", G_CALLBACK (xkb_layouts_dnd_data_get), dialog); g_signal_connect (G_OBJECT (tree_view), "drag_data_received", G_CALLBACK (xkb_layouts_dnd_data_received), dialog); } gchar * xkb_layout_description_utf8 (const gchar * visible) { char *l, *sl, *v, *sv; if (matekbd_keyboard_config_get_descriptions (config_registry, visible, &sl, &l, &sv, &v)) visible = matekbd_keyboard_config_format_full_layout (l, v); return g_strstrip (g_strdup (visible)); } void xkb_layouts_fill_selected_tree (GtkBuilder * dialog) { GSList *layouts = xkb_layouts_get_selected_list (); GSList *cur_layout; GtkListStore *list_store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (WID ("xkb_layouts_selected")))); int counter = 0; /* temporarily disable the buttons' status update */ disable_buttons_sensibility_update = TRUE; gtk_list_store_clear (list_store); for (cur_layout = layouts; cur_layout != NULL; cur_layout = cur_layout->next, counter++) { GtkTreeIter iter; const char *visible = (char *) cur_layout->data; gchar *utf_visible = xkb_layout_description_utf8 (visible); gtk_list_store_append (list_store, &iter); gtk_list_store_set (list_store, &iter, SEL_LAYOUT_TREE_COL_DESCRIPTION, utf_visible, SEL_LAYOUT_TREE_COL_ID, cur_layout->data, SEL_LAYOUT_TREE_COL_ENABLED, counter < max_selected_layouts, -1); g_free (utf_visible); } clear_xkb_elements_list (layouts); /* enable the buttons' status update */ disable_buttons_sensibility_update = FALSE; if (idx2select != -1) { GtkTreeSelection *selection = gtk_tree_view_get_selection ((GTK_TREE_VIEW (WID ("xkb_layouts_selected")))); GtkTreePath *path = gtk_tree_path_new_from_indices (idx2select, -1); gtk_tree_selection_select_path (selection, path); gtk_tree_path_free (path); idx2select = -1; } else { /* if there is nothing to select - just enable/disable the buttons, otherwise it would be done by the selection change */ xkb_layouts_enable_disable_buttons (dialog); } } static void add_selected_layout (GtkWidget * button, GtkBuilder * dialog) { xkb_layout_choose (dialog); } static void show_selected_layout (GtkWidget * button, GtkBuilder * dialog) { gint idx = find_selected_layout_idx (dialog); if (idx != -1) { GSList *layouts_list = xkb_layouts_get_selected_list (); const gchar *id = g_slist_nth_data (layouts_list, idx); char *descr = xkb_layout_description_utf8 (id); GtkWidget *parent = WID ("keyboard_dialog"); GtkWidget *popup = matekbd_keyboard_drawing_new_dialog (idx, descr); gtk_window_set_skip_taskbar_hint(GTK_WINDOW(popup), TRUE); gtk_widget_set_parent (popup, parent); clear_xkb_elements_list (layouts_list); g_free (descr); } } static void remove_selected_layout (GtkWidget * button, GtkBuilder * dialog) { gint idx = find_selected_layout_idx (dialog); if (idx != -1) { GSList *layouts_list = xkb_layouts_get_selected_list (); char *id = NULL; GSList *node2Remove = g_slist_nth (layouts_list, idx); layouts_list = g_slist_remove_link (layouts_list, node2Remove); id = (char *) node2Remove->data; g_slist_free_1 (node2Remove); g_free (id); if (default_group > idx) xkb_save_default_group (default_group - 1); else if (default_group == idx) xkb_save_default_group (-1); xkb_layouts_set_selected_list (layouts_list); clear_xkb_elements_list (layouts_list); } } static void move_up_selected_layout (GtkWidget * button, GtkBuilder * dialog) { gint idx = find_selected_layout_idx (dialog); if (idx != -1) { GSList *layouts_list = xkb_layouts_get_selected_list (); GSList *node2Remove = g_slist_nth (layouts_list, idx); layouts_list = g_slist_remove_link (layouts_list, node2Remove); layouts_list = g_slist_insert (layouts_list, node2Remove->data, idx - 1); g_slist_free_1 (node2Remove); idx2select = idx - 1; xkb_layouts_set_selected_list (layouts_list); clear_xkb_elements_list (layouts_list); } } static void move_down_selected_layout (GtkWidget * button, GtkBuilder * dialog) { gint idx = find_selected_layout_idx (dialog); if (idx != -1) { GSList *layouts_list = xkb_layouts_get_selected_list (); GSList *node2Remove = g_slist_nth (layouts_list, idx); layouts_list = g_slist_remove_link (layouts_list, node2Remove); layouts_list = g_slist_insert (layouts_list, node2Remove->data, idx + 1); g_slist_free_1 (node2Remove); idx2select = idx + 1; xkb_layouts_set_selected_list (layouts_list); clear_xkb_elements_list (layouts_list); } } void xkb_layouts_register_buttons_handlers (GtkBuilder * dialog) { g_signal_connect (G_OBJECT (WID ("xkb_layouts_add")), "clicked", G_CALLBACK (add_selected_layout), dialog); g_signal_connect (G_OBJECT (WID ("xkb_layouts_show")), "clicked", G_CALLBACK (show_selected_layout), dialog); g_signal_connect (G_OBJECT (WID ("xkb_layouts_remove")), "clicked", G_CALLBACK (remove_selected_layout), dialog); g_signal_connect (G_OBJECT (WID ("xkb_layouts_move_up")), "clicked", G_CALLBACK (move_up_selected_layout), dialog); g_signal_connect (G_OBJECT (WID ("xkb_layouts_move_down")), "clicked", G_CALLBACK (move_down_selected_layout), dialog); } static void xkb_layouts_update_list (GSettings * settings, gchar * key, GtkBuilder * dialog) { xkb_layouts_fill_selected_tree (dialog); enable_disable_restoring (dialog); } void xkb_layouts_register_gsettings_listener (GtkBuilder * dialog) { g_signal_connect (xkb_kbd_settings, "changed::layouts", G_CALLBACK (xkb_layouts_update_list), dialog); } ukui-control-center/panels/keyboard/eggcellrendererkeys.c0000664000175000017500000005017413057175444022705 0ustar fengfeng/* gtkcellrendererkeybinding.c * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #if GTK_CHECK_VERSION (3, 0, 0) #include #endif #include "eggcellrendererkeys.h" #include "eggaccelerators.h" #ifndef EGG_COMPILATION #ifndef _ #define _(x) dgettext (GETTEXT_PACKAGE, x) #define N_(x) x #endif #else #define _(x) x #define N_(x) x #endif #define EGG_CELL_RENDERER_TEXT_PATH "egg-cell-renderer-text" #define TOOLTIP_TEXT "New shortcut..." static void egg_cell_renderer_keys_finalize (GObject *object); static void egg_cell_renderer_keys_init (EggCellRendererKeys *cell_keys); static void egg_cell_renderer_keys_class_init (EggCellRendererKeysClass *cell_keys_class); static GtkCellEditable *egg_cell_renderer_keys_start_editing (GtkCellRenderer *cell, GdkEvent *event, GtkWidget *widget, const gchar *path, GdkRectangle *background_area, GdkRectangle *cell_area, GtkCellRendererState flags); static void egg_cell_renderer_keys_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec); static void egg_cell_renderer_keys_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec); static void egg_cell_renderer_keys_get_size (GtkCellRenderer *cell, GtkWidget *widget, GdkRectangle *cell_area, gint *x_offset, gint *y_offset, gint *width, gint *height); enum { PROP_0, PROP_ACCEL_KEY, PROP_ACCEL_MASK, PROP_KEYCODE, PROP_ACCEL_MODE }; static GtkCellRendererTextClass* parent_class = NULL; GType egg_cell_renderer_keys_get_type(void) { static GType cell_keys_type = 0; if (!cell_keys_type) { static const GTypeInfo cell_keys_info = { sizeof (EggCellRendererKeysClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc)egg_cell_renderer_keys_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (EggCellRendererKeys), 0, /* n_preallocs */ (GInstanceInitFunc) egg_cell_renderer_keys_init }; cell_keys_type = g_type_register_static (GTK_TYPE_CELL_RENDERER_TEXT, "EggCellRendererKeys", &cell_keys_info, 0); } return cell_keys_type; } static void egg_cell_renderer_keys_init(EggCellRendererKeys* cell_keys) { cell_keys->accel_mode = EGG_CELL_RENDERER_KEYS_MODE_GTK; } /* FIXME setup stuff to generate this */ /* VOID:STRING,UINT,FLAGS,UINT */ static void marshal_VOID__STRING_UINT_FLAGS_UINT(GClosure* closure, GValue* return_value, guint n_param_values, const GValue* param_values, gpointer invocation_hint, gpointer marshal_data) { /* typedef inside a function? wow */ typedef void (*GMarshalFunc_VOID__STRING_UINT_FLAGS_UINT) ( gpointer data1, const char* arg_1, guint arg_2, int arg_3, guint arg_4, gpointer data2); register GMarshalFunc_VOID__STRING_UINT_FLAGS_UINT callback; register GCClosure* cc = (GCClosure*) closure; register gpointer data1, data2; g_return_if_fail (n_param_values == 5); if (G_CCLOSURE_SWAP_DATA(closure)) { data1 = closure->data; data2 = g_value_peek_pointer(param_values + 0); } else { data1 = g_value_peek_pointer(param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_VOID__STRING_UINT_FLAGS_UINT) (marshal_data ? marshal_data : cc->callback); callback(data1, g_value_get_string(param_values + 1), g_value_get_uint(param_values + 2), g_value_get_flags(param_values + 3), g_value_get_uint(param_values + 4), data2); } static void egg_cell_renderer_keys_class_init (EggCellRendererKeysClass *cell_keys_class) { GObjectClass *object_class; GtkCellRendererClass *cell_renderer_class; object_class = G_OBJECT_CLASS (cell_keys_class); cell_renderer_class = GTK_CELL_RENDERER_CLASS (cell_keys_class); parent_class = g_type_class_peek_parent (object_class); GTK_CELL_RENDERER_CLASS (cell_keys_class)->start_editing = egg_cell_renderer_keys_start_editing; object_class->set_property = egg_cell_renderer_keys_set_property; object_class->get_property = egg_cell_renderer_keys_get_property; cell_renderer_class->get_size = egg_cell_renderer_keys_get_size; object_class->finalize = egg_cell_renderer_keys_finalize; /* FIXME if this gets moved to a real library, rename the properties * to match whatever the GTK convention is */ g_object_class_install_property (object_class, PROP_ACCEL_KEY, g_param_spec_uint ("accel_key", "Accelerator key", "Accelerator key", 0, G_MAXINT, 0, G_PARAM_READABLE | G_PARAM_WRITABLE)); g_object_class_install_property (object_class, PROP_ACCEL_MASK, g_param_spec_flags ("accel_mask", "Accelerator modifiers", "Accelerator modifiers", GDK_TYPE_MODIFIER_TYPE, 0, G_PARAM_READABLE | G_PARAM_WRITABLE)); g_object_class_install_property (object_class, PROP_KEYCODE, g_param_spec_uint ("keycode", "Accelerator keycode", "Accelerator keycode", 0, G_MAXINT, 0, G_PARAM_READABLE | G_PARAM_WRITABLE)); /* FIXME: Register the enum when moving to GTK+ */ g_object_class_install_property (object_class, PROP_ACCEL_MODE, g_param_spec_int ("accel_mode", "Accel Mode", "The type of accelerator.", 0, 2, 0, G_PARAM_READABLE | G_PARAM_WRITABLE)); g_signal_new ("accel_edited", EGG_TYPE_CELL_RENDERER_KEYS, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggCellRendererKeysClass, accel_edited), NULL, NULL, marshal_VOID__STRING_UINT_FLAGS_UINT, G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_UINT, GDK_TYPE_MODIFIER_TYPE, G_TYPE_UINT); g_signal_new ("accel_cleared", EGG_TYPE_CELL_RENDERER_KEYS, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggCellRendererKeysClass, accel_cleared), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); } GtkCellRenderer* egg_cell_renderer_keys_new(void) { return GTK_CELL_RENDERER(g_object_new(EGG_TYPE_CELL_RENDERER_KEYS, NULL)); } static void egg_cell_renderer_keys_finalize(GObject* object) { (*G_OBJECT_CLASS(parent_class)->finalize)(object); } static gchar* convert_keysym_state_to_string(guint keysym, guint keycode, EggVirtualModifierType mask) { if (keysym == 0 && keycode == 0) { return g_strdup ("Disabled"); } else { return egg_virtual_accelerator_label(keysym, keycode, mask); } } static void egg_cell_renderer_keys_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec) { EggCellRendererKeys *keys; g_return_if_fail (EGG_IS_CELL_RENDERER_KEYS (object)); keys = EGG_CELL_RENDERER_KEYS (object); switch (param_id) { case PROP_ACCEL_KEY: g_value_set_uint (value, keys->accel_key); break; case PROP_ACCEL_MASK: g_value_set_flags (value, keys->accel_mask); break; case PROP_ACCEL_MODE: g_value_set_int (value, keys->accel_mode); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); } } static void egg_cell_renderer_keys_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { EggCellRendererKeys *keys; g_return_if_fail (EGG_IS_CELL_RENDERER_KEYS (object)); keys = EGG_CELL_RENDERER_KEYS (object); switch (param_id) { case PROP_ACCEL_KEY: egg_cell_renderer_keys_set_accelerator (keys, g_value_get_uint (value), keys->keycode, keys->accel_mask); break; case PROP_ACCEL_MASK: egg_cell_renderer_keys_set_accelerator (keys, keys->accel_key, keys->keycode, g_value_get_flags (value)); break; case PROP_KEYCODE: egg_cell_renderer_keys_set_accelerator (keys, keys->accel_key, g_value_get_uint (value), keys->accel_mask); break; case PROP_ACCEL_MODE: egg_cell_renderer_keys_set_accel_mode (keys, g_value_get_int (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); } } static gboolean is_modifier(guint keycode) { gint i; gint map_size; XModifierKeymap* mod_keymap; gboolean retval = FALSE; #if GTK_CHECK_VERSION (3, 0, 0) mod_keymap = XGetModifierMapping(gdk_x11_display_get_xdisplay(gdk_display_get_default())); #else mod_keymap = XGetModifierMapping(gdk_display); #endif map_size = 8 * mod_keymap->max_keypermod; i = 0; while (i < map_size) { if (keycode == mod_keymap->modifiermap[i]) { retval = TRUE; break; } ++i; } XFreeModifiermap(mod_keymap); return retval; } static void egg_cell_renderer_keys_get_size (GtkCellRenderer *cell, GtkWidget *widget, GdkRectangle *cell_area, gint *x_offset, gint *y_offset, gint *width, gint *height) { EggCellRendererKeys *keys = (EggCellRendererKeys *) cell; GtkRequisition requisition; if (keys->sizing_label == NULL) keys->sizing_label = gtk_label_new (TOOLTIP_TEXT); gtk_widget_size_request (keys->sizing_label, &requisition); (* GTK_CELL_RENDERER_CLASS (parent_class)->get_size) (cell, widget, cell_area, x_offset, y_offset, width, height); /* FIXME: need to take the cell_area et al. into account */ if (width) *width = MAX (*width, requisition.width); if (height) *height = MAX (*height, requisition.height); } /* FIXME: Currently we don't differentiate between a 'bogus' key (like tab in * GTK mode) and a removed key. */ static gboolean grab_key_callback(GtkWidget* widget, GdkEventKey* event, void* data) { GdkModifierType accel_mods = 0; guint accel_keyval; EggCellRendererKeys *keys; char *path; gboolean edited; gboolean cleared; GdkModifierType consumed_modifiers; guint upper; GdkModifierType ignored_modifiers; keys = EGG_CELL_RENDERER_KEYS(data); if (is_modifier(event->hardware_keycode)) { return TRUE; } edited = FALSE; cleared = FALSE; consumed_modifiers = 0; gdk_keymap_translate_keyboard_state(gdk_keymap_get_default(), event->hardware_keycode, event->state, event->group, NULL, NULL, NULL, &consumed_modifiers); upper = event->keyval; accel_keyval = gdk_keyval_to_lower(upper); if (accel_keyval == GDK_ISO_Left_Tab) { accel_keyval = GDK_Tab; } /* Put shift back if it changed the case of the key, not otherwise. */ if (upper != accel_keyval && (consumed_modifiers & GDK_SHIFT_MASK)) { consumed_modifiers &= ~(GDK_SHIFT_MASK); } egg_keymap_resolve_virtual_modifiers(gdk_keymap_get_default(), EGG_VIRTUAL_NUM_LOCK_MASK | EGG_VIRTUAL_SCROLL_LOCK_MASK | EGG_VIRTUAL_LOCK_MASK, &ignored_modifiers); /* http://bugzilla.gnome.org/show_bug.cgi?id=139605 * mouse keys should effect keybindings */ ignored_modifiers |= GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | GDK_BUTTON5_MASK; /* filter consumed/ignored modifiers */ if (keys->accel_mode == EGG_CELL_RENDERER_KEYS_MODE_GTK) { accel_mods = event->state & GDK_MODIFIER_MASK & ~(consumed_modifiers | ignored_modifiers); } else if (keys->accel_mode == EGG_CELL_RENDERER_KEYS_MODE_X) { accel_mods = event->state & GDK_MODIFIER_MASK & ~(ignored_modifiers); } else { g_assert_not_reached(); } if (accel_mods == 0 && accel_keyval == GDK_Escape) { goto out; /* cancel */ } /* clear the accelerator on Backspace */ if (accel_mods == 0 && accel_keyval == GDK_BackSpace) { cleared = TRUE; goto out; } if (keys->accel_mode == EGG_CELL_RENDERER_KEYS_MODE_GTK) { if (!gtk_accelerator_valid (accel_keyval, accel_mods)) { accel_keyval = 0; accel_mods = 0; } } edited = TRUE; out: gdk_keyboard_ungrab(event->time); gdk_pointer_ungrab(event->time); path = g_strdup(g_object_get_data(G_OBJECT(keys->edit_widget), EGG_CELL_RENDERER_TEXT_PATH)); gtk_cell_editable_editing_done(GTK_CELL_EDITABLE(keys->edit_widget)); gtk_cell_editable_remove_widget(GTK_CELL_EDITABLE(keys->edit_widget)); keys->edit_widget = NULL; keys->grab_widget = NULL; if (edited) { g_signal_emit_by_name(G_OBJECT(keys), "accel_edited", path, accel_keyval, accel_mods, event->hardware_keycode); } else if (cleared) { g_signal_emit_by_name(G_OBJECT(keys), "accel_cleared", path); } g_free (path); return TRUE; } static void ungrab_stuff(GtkWidget* widget, gpointer data) { EggCellRendererKeys* keys = EGG_CELL_RENDERER_KEYS(data); gdk_keyboard_ungrab(GDK_CURRENT_TIME); gdk_pointer_ungrab(GDK_CURRENT_TIME); g_signal_handlers_disconnect_by_func(G_OBJECT(keys->grab_widget), G_CALLBACK(grab_key_callback), data); } static void pointless_eventbox_start_editing(GtkCellEditable* cell_editable, GdkEvent* event) { /* do nothing, because we are pointless */ } static void pointless_eventbox_cell_editable_init(GtkCellEditableIface* iface) { iface->start_editing = pointless_eventbox_start_editing; } static GType pointless_eventbox_subclass_get_type (void) { static GType eventbox_type = 0; if (!eventbox_type) { static const GTypeInfo eventbox_info = { sizeof (GtkEventBoxClass), NULL, /* base_init */ NULL, /* base_finalize */ NULL, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (GtkEventBox), 0, /* n_preallocs */ (GInstanceInitFunc) NULL, }; static const GInterfaceInfo cell_editable_info = { (GInterfaceInitFunc) pointless_eventbox_cell_editable_init, NULL, NULL }; eventbox_type = g_type_register_static (GTK_TYPE_EVENT_BOX, "EggCellEditableEventBox", &eventbox_info, 0); g_type_add_interface_static (eventbox_type, GTK_TYPE_CELL_EDITABLE, &cell_editable_info); } return eventbox_type; } static GtkCellEditable * egg_cell_renderer_keys_start_editing (GtkCellRenderer *cell, GdkEvent *event, GtkWidget *widget, const gchar *path, GdkRectangle *background_area, GdkRectangle *cell_area, GtkCellRendererState flags) { GtkCellRendererText *celltext; EggCellRendererKeys *keys; GtkWidget *label; GtkWidget *eventbox; GValue celltext_editable = {0}; celltext = GTK_CELL_RENDERER_TEXT (cell); keys = EGG_CELL_RENDERER_KEYS (cell); /* If the cell isn't editable we return NULL. */ g_value_init (&celltext_editable, G_TYPE_BOOLEAN); g_object_get_property (G_OBJECT (celltext), "editable", &celltext_editable); if (g_value_get_boolean (&celltext_editable) == FALSE) return NULL; g_return_val_if_fail (gtk_widget_get_window (widget) != NULL, NULL); if (gdk_keyboard_grab (gtk_widget_get_window (widget), FALSE, gdk_event_get_time (event)) != GDK_GRAB_SUCCESS) return NULL; if (gdk_pointer_grab (gtk_widget_get_window (widget), FALSE, GDK_BUTTON_PRESS_MASK, NULL, NULL, gdk_event_get_time (event)) != GDK_GRAB_SUCCESS) { gdk_keyboard_ungrab (gdk_event_get_time (event)); return NULL; } keys->grab_widget = widget; g_signal_connect (G_OBJECT (widget), "key_press_event", G_CALLBACK (grab_key_callback), keys); eventbox = g_object_new (pointless_eventbox_subclass_get_type (), NULL); keys->edit_widget = eventbox; g_object_add_weak_pointer (G_OBJECT (keys->edit_widget), (void**) &keys->edit_widget); label = gtk_label_new (NULL); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_widget_modify_bg (eventbox, GTK_STATE_NORMAL, >k_widget_get_style (widget)->bg[GTK_STATE_SELECTED]); gtk_widget_modify_fg (label, GTK_STATE_NORMAL, >k_widget_get_style (widget)->fg[GTK_STATE_SELECTED]); gtk_label_set_text (GTK_LABEL (label), TOOLTIP_TEXT); gtk_container_add (GTK_CONTAINER (eventbox), label); g_object_set_data_full (G_OBJECT (keys->edit_widget), EGG_CELL_RENDERER_TEXT_PATH, g_strdup (path), g_free); gtk_widget_show_all (keys->edit_widget); g_signal_connect (G_OBJECT (keys->edit_widget), "unrealize", G_CALLBACK (ungrab_stuff), keys); keys->edit_key = keys->accel_key; return GTK_CELL_EDITABLE (keys->edit_widget); } void egg_cell_renderer_keys_set_accelerator(EggCellRendererKeys* keys, guint keyval, guint keycode, EggVirtualModifierType mask) { char *text; gboolean changed; g_return_if_fail (EGG_IS_CELL_RENDERER_KEYS (keys)); g_object_freeze_notify (G_OBJECT (keys)); changed = FALSE; if (keyval != keys->accel_key) { keys->accel_key = keyval; g_object_notify (G_OBJECT (keys), "accel_key"); changed = TRUE; } if (mask != keys->accel_mask) { keys->accel_mask = mask; g_object_notify (G_OBJECT (keys), "accel_mask"); changed = TRUE; } if (keycode != keys->keycode) { keys->keycode = keycode; g_object_notify (G_OBJECT (keys), "keycode"); changed = TRUE; } g_object_thaw_notify (G_OBJECT (keys)); if (changed) { /* sync string to the key values */ text = convert_keysym_state_to_string (keys->accel_key, keys->keycode, keys->accel_mask); g_object_set (keys, "text", text, NULL); g_free (text); } } void egg_cell_renderer_keys_get_accelerator(EggCellRendererKeys* keys, guint* keyval, EggVirtualModifierType* mask) { g_return_if_fail(EGG_IS_CELL_RENDERER_KEYS(keys)); if (keyval) { *keyval = keys->accel_key; } if (mask) { *mask = keys->accel_mask; } } void egg_cell_renderer_keys_set_accel_mode (EggCellRendererKeys* keys, EggCellRendererKeysMode accel_mode) { g_return_if_fail(EGG_IS_CELL_RENDERER_KEYS(keys)); keys->accel_mode = accel_mode; g_object_notify(G_OBJECT(keys), "accel_mode"); } ukui-control-center/panels/keyboard/01-desktop-key.xml.in0000664000175000017500000000111713253611037022300 0ustar fengfeng ukui-control-center/panels/keyboard/ukui-keyboard-properties-layout-chooser.ui0000664000175000017500000003670013245450076026766 0ustar fengfeng True False 5 Select the keyboard layout 670 350 dialog True True False vertical 2 True False end gtk-print True True True False True False False 0 True gtk-cancel True True True False True False False 1 gtk-add True True True False True False False 2 False True end 0 True False 5 vertical 6 True True True False 3 3 3 6 True False 6 12 True False 1 1 True False 1 0 True False _Variants: True xkb_country_variants_available 0 1 True False _Country: True xkb_countries_available 0 0 True False By _country True False True False 3 3 3 3 True False 6 12 True False 1 1 True False 1 0 True False _Variants: True xkb_country_variants_available 0 1 True False _Language: True xkb_countries_available 0 0 1 True False By _language True 1 False False False 0 True False vertical 6 True False 6 True False Preview: False False 0 False False 0 True False 0 in True True 1 True True 1 True True 1 btnPrint cancelbutton2 btnOk1 ukui-control-center/panels/keyboard/ukui-keyboard-properties-a11y.c0000664000175000017500000002423313253611037024362 0ustar fengfeng/* -*- mode: c; style: linux -*- */ /* * Copyright (C) 2007 The GNOME Foundation * Written by Denis Washington * All Rights Reserved * * This program is free software; you can redistribute 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. */ #include "ukui-keyboard-properties-a11y.h" #include #define NWID(s) GTK_WIDGET (gtk_builder_get_object (notifications_dialog, s)) #define WID(s) GTK_WIDGET(gtk_builder_get_object(dialog,s)) #define A11Y_SCHEMA "org.mate.accessibility-keyboard" static GtkBuilder *notifications_dialog = NULL; static GSettings *a11y_settings = NULL; enum { VISUAL_BELL_TYPE_INVALID, VISUAL_BELL_TYPE_FULLSCREEN, VISUAL_BELL_TYPE_FRAME_FLASH }; /*static void stickykeys_enable_toggled_cb (GtkWidget *w, GtkBuilder *dialog) { gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)); gtk_widget_set_sensitive (WID ("stickykeys_two_key_off"), active); if (notifications_dialog) gtk_widget_set_sensitive (NWID ("stickykeys_notifications_box"), active); }*/ /*static void slowkeys_enable_toggled_cb (GtkWidget *w, GtkBuilder *dialog) { gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)); gtk_widget_set_sensitive (WID ("slowkeys_delay_box"), active); if (notifications_dialog) gtk_widget_set_sensitive (NWID ("slowkeys_notifications_box"), active); }*/ /*static void bouncekeys_enable_toggled_cb (GtkWidget *w, GtkBuilder *dialog) { gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)); gtk_widget_set_sensitive (WID ("bouncekeys_delay_box"), active); if (notifications_dialog) gtk_widget_set_sensitive (NWID ("bouncekeys_notifications_box"), active); }*/ /*static void visual_bell_enable_toggled_cb (GtkWidget *w, GtkBuilder *dialog) { gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)); if (notifications_dialog) { gtk_widget_set_sensitive (NWID ("visual_bell_titlebar"), active); gtk_widget_set_sensitive (NWID ("visual_bell_fullscreen"), active); } } static void bell_flash_gsettings_changed (GSettings *settings, gchar *key, GtkBuilder *dialog) { int bell_flash_type = g_settings_get_enum (settings, key); if (bell_flash_type == VISUAL_BELL_TYPE_FULLSCREEN) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (NWID ("visual_bell_fullscreen")), TRUE); } else if (bell_flash_type == VISUAL_BELL_TYPE_FRAME_FLASH) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (NWID ("visual_bell_titlebar")), TRUE); } } static void bell_flash_radio_changed (GtkWidget *widget, GtkBuilder *builder) { GSettings *marco_settings; marco_settings = g_settings_new (MARCO_SCHEMA); int old_bell_flash_type = g_settings_get_enum (marco_settings, "visual-bell-type"); int new_bell_flash_type = VISUAL_BELL_TYPE_INVALID; if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (NWID ("visual_bell_fullscreen")))) new_bell_flash_type = VISUAL_BELL_TYPE_FULLSCREEN; else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (NWID ("visual_bell_titlebar")))) new_bell_flash_type = VISUAL_BELL_TYPE_FRAME_FLASH; if (old_bell_flash_type != new_bell_flash_type) g_settings_set_enum (marco_settings, "visual-bell-type", new_bell_flash_type); g_object_unref (marco_settings); } static void a11y_notifications_dialog_response_cb (GtkWidget *w, gint response) { if (response == GTK_RESPONSE_HELP) { } else { gtk_widget_destroy (w); } }*/ /*static void notifications_button_clicked_cb (GtkWidget *button, GtkBuilder *dialog) { GtkWidget *w; notifications_dialog = gtk_builder_new (); gtk_builder_add_from_file (notifications_dialog, "../panels/keyboard/ukui-keyboard-properties-a11y-notifications.ui", NULL); stickykeys_enable_toggled_cb (WID ("stickykeys_enable"), dialog); slowkeys_enable_toggled_cb (WID ("slowkeys_enable"), dialog); bouncekeys_enable_toggled_cb (WID ("bouncekeys_enable"), dialog); w = NWID ("feature_state_change_beep"); g_settings_bind (a11y_settings, "feature-state-change-beep", w, "active", G_SETTINGS_BIND_DEFAULT); w = NWID ("togglekeys_enable"); g_settings_bind (a11y_settings, "togglekeys-enable", w, "active", G_SETTINGS_BIND_DEFAULT); w = NWID ("stickykeys_modifier_beep"); g_settings_bind (a11y_settings, "stickykeys-modifier-beep", w, "active", G_SETTINGS_BIND_DEFAULT); w = NWID ("slowkeys_beep_press"); g_settings_bind (a11y_settings, "slowkeys-beep-press", w, "active", G_SETTINGS_BIND_DEFAULT); w = NWID ("slowkeys_beep_accept"); g_settings_bind (a11y_settings, "slowkeys-beep-accept", w, "active", G_SETTINGS_BIND_DEFAULT); w = NWID ("slowkeys_beep_reject"); g_settings_bind (a11y_settings, "slowkeys-beep-reject", w, "active", G_SETTINGS_BIND_DEFAULT); w = NWID ("bouncekeys_beep_reject"); g_settings_bind (a11y_settings, "bouncekeys-beep-reject", w, "active", G_SETTINGS_BIND_DEFAULT); GSettings *marco_settings = g_settings_new (MARCO_SCHEMA); w = NWID ("visual_bell_enable"); g_settings_bind (marco_settings, "visual-bell", w, "active", G_SETTINGS_BIND_DEFAULT); g_signal_connect (w, "toggled", G_CALLBACK (visual_bell_enable_toggled_cb), dialog); visual_bell_enable_toggled_cb (w, dialog); bell_flash_gsettings_changed (marco_settings, "visual-bell-type", NULL); g_signal_connect (NWID ("visual_bell_titlebar"), "clicked", G_CALLBACK(bell_flash_radio_changed), notifications_dialog); g_signal_connect (NWID ("visual_bell_fullscreen"), "clicked", G_CALLBACK(bell_flash_radio_changed), notifications_dialog); g_signal_connect (marco_settings, "changed::visual-bell-type", G_CALLBACK (bell_flash_gsettings_changed), notifications_dialog); w = NWID ("a11y_notifications_dialog"); gtk_window_set_transient_for (GTK_WINDOW (w), GTK_WINDOW (WID ("keyboard_dialog"))); g_signal_connect (w, "response", G_CALLBACK (a11y_notifications_dialog_response_cb), NULL); gtk_dialog_run (GTK_DIALOG (w)); g_object_unref (marco_settings); g_object_unref (notifications_dialog); notifications_dialog = NULL; } */ /*static void mousekeys_enable_toggled_cb (GtkWidget *w, GtkBuilder *dialog) { gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)); gtk_widget_set_sensitive (WID ("mousekeys_table"), active); } */ /*void finalize_a11y_tabs (void) { g_object_unref (a11y_settings); } */ /*void setup_a11y_tabs (GtkBuilder *dialog) { GtkWidget *w; a11y_settings = g_settings_new (A11Y_SCHEMA); */ /* Accessibility tab */ /*g_settings_bind (a11y_settings, "enable", WID ("master_enable"), "active", G_SETTINGS_BIND_DEFAULT);*/ /* w = WID ("stickykeys_enable"); g_settings_bind (a11y_settings, "stickykeys-enable", w, "active", G_SETTINGS_BIND_DEFAULT); g_signal_connect (w, "toggled", G_CALLBACK (stickykeys_enable_toggled_cb), dialog); stickykeys_enable_toggled_cb (w, dialog); g_settings_bind (a11y_settings, "stickykeys-two-key-off", WID ("stickykeys_two_key_off"), "active", G_SETTINGS_BIND_DEFAULT); w = WID ("slowkeys_enable"); g_settings_bind (a11y_settings, "slowkeys-enable", w, "active", G_SETTINGS_BIND_DEFAULT); g_signal_connect (w, "toggled", G_CALLBACK (slowkeys_enable_toggled_cb), dialog); slowkeys_enable_toggled_cb (w, dialog); w = WID ("bouncekeys_enable"); g_settings_bind (a11y_settings, "bouncekeys-enable", w, "active", G_SETTINGS_BIND_DEFAULT); g_signal_connect (w, "toggled", G_CALLBACK (bouncekeys_enable_toggled_cb), dialog); bouncekeys_enable_toggled_cb (w, dialog); g_settings_bind (a11y_settings, "slowkeys-delay", gtk_range_get_adjustment (GTK_RANGE (WID ("slowkeys_delay_slide"))), "value", G_SETTINGS_BIND_DEFAULT); g_settings_bind (a11y_settings, "bouncekeys-delay", gtk_range_get_adjustment (GTK_RANGE (WID ("bouncekeys_delay_slide"))), "value", G_SETTINGS_BIND_DEFAULT); w = WID ("notifications_button"); g_signal_connect (w, "clicked", G_CALLBACK (notifications_button_clicked_cb), dialog); */ /* Mouse Keys tab */ /* w = WID ("mousekeys_enable"); g_settings_bind (a11y_settings, "mousekeys-enable", w, "active", G_SETTINGS_BIND_DEFAULT); g_signal_connect (w, "toggled", G_CALLBACK (mousekeys_enable_toggled_cb), dialog); mousekeys_enable_toggled_cb (w, dialog); g_settings_bind (a11y_settings, "slowkeys-delay", gtk_range_get_adjustment (GTK_RANGE (WID ("slowkeys_delay_slide"))), "value", G_SETTINGS_BIND_DEFAULT); g_settings_bind (a11y_settings, "bouncekeys-delay", gtk_range_get_adjustment (GTK_RANGE (WID ("bouncekeys_delay_slide"))), "value", G_SETTINGS_BIND_DEFAULT); g_settings_bind (a11y_settings, "slowkeys-delay", gtk_range_get_adjustment (GTK_RANGE (WID ("slowkeys_delay_slide"))), "value", G_SETTINGS_BIND_DEFAULT); g_settings_bind (a11y_settings, "bouncekeys-delay", gtk_range_get_adjustment (GTK_RANGE (WID ("bouncekeys_delay_slide"))), "value", G_SETTINGS_BIND_DEFAULT); g_settings_bind (a11y_settings, "mousekeys-accel-time", gtk_range_get_adjustment (GTK_RANGE (WID ("mousekeys_accel_time_slide"))), "value", G_SETTINGS_BIND_DEFAULT); g_settings_bind (a11y_settings, "mousekeys-max-speed", gtk_range_get_adjustment (GTK_RANGE (WID ("mousekeys_max_speed_slide"))), "value", G_SETTINGS_BIND_DEFAULT); g_settings_bind (a11y_settings, "mousekeys-init-delay", gtk_range_get_adjustment (GTK_RANGE (WID ("mousekeys_init_delay_slide"))), "value", G_SETTINGS_BIND_DEFAULT); }*/ ukui-control-center/panels/keyboard/dconf-util.c0000664000175000017500000000467613057175444020732 0ustar fengfeng/* * dconf-util.h: helper API for dconf * * Copyright (C) 2012 Stefano Karapetsas * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Authors: * Stefano Karapetsas * Vincent Untz */ #include #include #include "dconf-util.h" static DConfClient * dconf_util_client_get (void) { return dconf_client_new (); } gboolean dconf_util_write_sync (const gchar *key, GVariant *value, GError **error) { gboolean ret; DConfClient *client = dconf_util_client_get (); ret = dconf_client_write_sync (client, key, value, NULL, NULL, error); g_object_unref (client); return ret; } gboolean dconf_util_recursive_reset (const gchar *dir, GError **error) { gboolean ret; DConfClient *client = dconf_util_client_get (); ret = dconf_client_write_sync (client, dir, NULL, NULL, NULL, error); g_object_unref (client); return ret; } gchar ** dconf_util_list_subdirs (const gchar *dir, gboolean remove_trailing_slash) { GArray *array; gchar **children; int len; int i; DConfClient *client = dconf_util_client_get (); array = g_array_new (TRUE, TRUE, sizeof (gchar *)); children = dconf_client_list (client, dir, &len); g_object_unref (client); for (i = 0; children[i] != NULL; i++) { if (dconf_is_rel_dir (children[i], NULL)) { char *val = g_strdup (children[i]); if (remove_trailing_slash) val[strlen (val) - 1] = '\0'; array = g_array_append_val (array, val); } } g_strfreev (children); return (gchar **) g_array_free (array, FALSE); } ukui-control-center/panels/keyboard/shortcut_dialog.ui0000664000175000017500000001552213245450076022237 0ustar fengfeng 440 220 False Custom Shortcut dialog True True False vertical True False end gtk-cancel True True False True False False 0 gtk-apply True True True False True False False 1 False True 10 end 0 True False 70 35 True False Name: True custom-shortcut-name-entry 20 20 70 40 True False Command True 20 63 260 35 True True True False False 90 20 260 35 True True True False False 90 63 Scan 80 35 True True True 354 63 True True 1 cancelbutton1 okbutton1 ukui-control-center/panels/keyboard/eggaccelerators.h0000664000175000017500000000663313057175444022020 0ustar fengfeng/* eggaccelerators.h * Copyright (C) 2002 Red Hat, Inc.; * Copyright 1998, 2001 Tim Janik * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * Developed by Havoc Pennington * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __EGG_ACCELERATORS_H__ #define __EGG_ACCELERATORS_H__ #include #include #ifdef __cplusplus extern "C" { #endif /* Where a value is also in GdkModifierType we coincide, * otherwise we don't overlap. */ typedef enum { EGG_VIRTUAL_SHIFT_MASK = 1 << 0, EGG_VIRTUAL_LOCK_MASK = 1 << 1, EGG_VIRTUAL_CONTROL_MASK = 1 << 2, EGG_VIRTUAL_ALT_MASK = 1 << 3, /* fixed as Mod1 */ EGG_VIRTUAL_MOD2_MASK = 1 << 4, EGG_VIRTUAL_MOD3_MASK = 1 << 5, EGG_VIRTUAL_MOD4_MASK = 1 << 6, EGG_VIRTUAL_MOD5_MASK = 1 << 7, #if 0 GDK_BUTTON1_MASK = 1 << 8, GDK_BUTTON2_MASK = 1 << 9, GDK_BUTTON3_MASK = 1 << 10, GDK_BUTTON4_MASK = 1 << 11, GDK_BUTTON5_MASK = 1 << 12, /* 13, 14 are used by Xkb for the keyboard group */ #endif EGG_VIRTUAL_MODE_SWITCH_MASK = 1 << 23, EGG_VIRTUAL_NUM_LOCK_MASK = 1 << 24, EGG_VIRTUAL_SCROLL_LOCK_MASK = 1 << 25, /* Also in GdkModifierType */ EGG_VIRTUAL_SUPER_MASK = 1 << 26, EGG_VIRTUAL_HYPER_MASK = 1 << 27, EGG_VIRTUAL_META_MASK = 1 << 28, /* Also in GdkModifierType */ EGG_VIRTUAL_RELEASE_MASK = 1 << 30, /* 28-31 24-27 20-23 16-19 12-15 8-11 4-7 0-3 * 5 f 8 0 0 0 f f */ EGG_VIRTUAL_MODIFIER_MASK = 0x5f8000ff } EggVirtualModifierType; gboolean egg_accelerator_parse_virtual (const gchar *accelerator, guint *accelerator_key, guint *keycode, EggVirtualModifierType *accelerator_mods); void egg_keymap_resolve_virtual_modifiers (GdkKeymap *keymap, EggVirtualModifierType virtual_mods, GdkModifierType *concrete_mods); void egg_keymap_virtualize_modifiers (GdkKeymap *keymap, GdkModifierType concrete_mods, EggVirtualModifierType *virtual_mods); gchar* egg_virtual_accelerator_name (guint accelerator_key, guint keycode, EggVirtualModifierType accelerator_mods); gchar* egg_virtual_accelerator_label (guint accelerator_key, guint keycode, EggVirtualModifierType accelerator_mods); #ifdef __cplusplus } #endif #endif /* __EGG_ACCELERATORS_H__ */ ukui-control-center/panels/keyboard/ukui-keyboard-properties-xkb.h0000664000175000017500000000604113253611037024375 0ustar fengfeng/* -*- mode: c; style: linux -*- */ /* ukui-keyboard-properties-xkb.h * Copyright (C) 2003-2007 Sergey V Udaltsov * * Written by Sergey V. Udaltsov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifndef __UKUI_KEYBOARD_PROPERTY_XKB_H #define __UKUI_KEYBOARD_PROPERTY_XKB_H #include #include #include "libmatekbd/matekbd-keyboard-config.h" #define WID(s) GTK_WIDGET (gtk_builder_get_object(dialog, s)) #ifdef __cplusplus extern "C" { #endif #define CWID(s) GTK_WIDGET (gtk_builder_get_object (chooser_dialog, s)) extern XklEngine *engine; extern XklConfigRegistry *config_registry; extern GSettings *xkb_kbd_settings; extern GSettings *xkb_general_settings; extern MatekbdKeyboardConfig initial_config; extern void setup_xkb_tabs (GtkBuilder * dialog); extern void xkb_layouts_fill_selected_tree (GtkBuilder * dialog); extern void xkb_layouts_register_buttons_handlers (GtkBuilder * dialog); extern void xkb_layouts_register_gsettings_listener (GtkBuilder * dialog); extern void xkb_options_register_gsettings_listener (GtkBuilder * dialog); extern void xkb_layouts_prepare_selected_tree (GtkBuilder * dialog); extern void xkb_options_load_options (GtkBuilder * dialog); extern void xkb_options_popup_dialog (GtkBuilder * dialog); extern void clear_xkb_elements_list (GSList * list); extern char *xci_desc_to_utf8 (XklConfigItem * ci); extern gchar *xkb_layout_description_utf8 (const gchar * visible); extern void enable_disable_restoring (GtkBuilder * dialog); extern void preview_toggled (GtkBuilder * dialog, GtkWidget * button); extern void choose_model (GtkBuilder * dialog); extern void xkb_layout_choose (GtkBuilder * dialog); extern GSList *xkb_layouts_get_selected_list (void); extern GSList *xkb_options_get_selected_list (void); extern void xkb_layouts_set_selected_list(GSList *list); extern void xkb_options_set_selected_list(GSList *list); extern GtkWidget *xkb_layout_preview_create_widget (GtkBuilder * chooser_dialog); extern void xkb_layout_preview_update (GtkBuilder * chooser_dialog); extern void xkb_layout_preview_set_drawing_layout (GtkWidget * kbdraw, const gchar * id); extern gchar *xkb_layout_chooser_get_selected_id (GtkBuilder * chooser_dialog); extern void xkb_save_default_group (gint group_no); extern gint xkb_get_default_group (void); #ifdef __cplusplus } #endif #endif /* __UKUI_KEYBOARD_PROPERTY_XKB_H */ ukui-control-center/panels/time-data/0000775000175000017500000000000013263647163016553 5ustar fengfengukui-control-center/panels/time-data/spy-time.h0000664000175000017500000000176213057175444020500 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef _SPY_TIME #define _SPY_TIME #include void add_time_and_data_app(GtkBuilder *builder); void time_data_destory(); #endif ukui-control-center/panels/time-data/Makefile.am0000664000175000017500000000065313057175444020612 0ustar fengfengcappletname=time_data noinst_LTLIBRARIES=libtime.la AUTOMAKE_OPTIONS = foreign #INCLUDES= `pkg-config --cflags gtk+-2.0 glib-2.0` #LIBS = `pkg-config --libs gtk+-2.0 glib-2.0` AM_CPPFLAGS = \ $(GTK_CFLAGS) \ $(GLIB_CFLAGS) \ $(NULL) libtime_la_LIBADD = \ $(GTK_LIBS) \ $(GLIB_LIBS) \ $(NULL) libtime_la_SOURCES= \ spy-time.c \ spt-time.h -include $(top_srcdir)/git.mk clean-local : rm -f *~ Makefile.in Makefile ukui-control-center/panels/time-data/spy-time.c0000664000175000017500000006567713256625660020513 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "spy-time.h" #include #include #include #include #include #include #include #include #define TZ_DATA_FILE "/usr/share/zoneinfo/zone_utc" #define _GMT 1970 #define MAXYAERRANGE 100 #define USE_24_FORMAT "use-24h-format" typedef struct _TzDB TzDB; typedef struct _TimeDate TimeDate; typedef struct _TzLocation TzLocation; typedef struct _TzUTC TzUTC; struct _TzUTC{ GPtrArray *tz_rtc; gchar *tz_utc; }; struct _TzDB { GPtrArray *locations; }; struct _TimeDate { TzDB *tzdb; GtkWidget * tzcombo; GtkWidget * hours; GtkWidget * minutes; GtkWidget * seconds; GtkWidget * calendar; GtkWidget * viewportlayout; GtkWidget * timesetting_checkbutton; GtkWidget * td_month_add_button; GtkWidget * td_combo_year; GtkWidget * td_combo_month; GtkWidget * td_month_del_button; GtkWidget * ntp_label; GtkWidget * hr12_radio; GtkWidget * hr24_radio; //config GDBusProxy *proxy; //datetime gint year; gint month; gint day; gint hour; gint minute; gint second; gchar ** tmptime; //show time component increase guint show_timeout_clock; //when you change the time,it will be used guint apply_timeout_clock; }; //why we do that? i need to avoid to load timeanddataapp use long time static const char* year_tab[100]={ "1970","1971","1972","1973","1974","1975","1976","1977","1978","1979", "1980","1981","1982","1983","1984","1985","1986","1987","1988","1989", "1990","1991","1992","1993","1994","1995","1996","1997","1998","1999", "2000","2001","2002","2003","2004","2005","2006","2007","2008","2009", "2010","2011","2012","2013","2014","2015","2016","2017","2018","2019", "2020","2021","2022","2023","2024","2025","2026","2027","2028","2029", "2030","2031","2032","2033","2034","2035","2036","2037","2038","2039", "2040","2041","2042","2043","2044","2045","2046","2047","2048","2049", "2050","2051","2052","2053","2054","2055","2056","2057","2058","2059", "2060","2061","2062","2063","2064","2065","2066","2067","2068","2069", }; struct _TzLocation { gchar * country; gchar * zone; }; static GSettings *time_format; TimeDate timedata; TzDB * init_timedb(); void init_dbus_proxy(); void init_time_config(); void freeze_clock(); void thaw_clock(); void on_editable_changed(); void stop_update_show_time_clock(); void start_update_show_time_clock(); gboolean on_apply_timeout(GtkWidget *widget,gpointer user_data); gboolean update_show_time(gpointer user_date); void init_calendar_time(gchar *month,gchar *day, gchar *year); void on_day_selected(GtkWidget *widget, gpointer user_data); void on_timezone_changed(GtkWidget *widget, gpointer user_data); void on_timesetting_changed(GtkWidget *widget, gpointer user_data); void init_calendar(); void dbus_set_answered(GObject *object, GAsyncResult *res, gpointer command); gchar * get_current_time(); void init_time_setting(); void network_sensitive(); enum{ Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec }; void time_data_destory(){ g_clear_object(&timedata.proxy); g_strfreev(timedata.tmptime); g_object_unref(time_format); } void init_time_setting(){ GVariant *value; value = g_dbus_proxy_get_cached_property(timedata.proxy, "CanNTP"); if (value !=NULL) { if (g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)){ gtk_widget_set_sensitive(timedata.timesetting_checkbutton, TRUE); } }else { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(timedata.timesetting_checkbutton), 0); gtk_widget_set_sensitive(timedata.timesetting_checkbutton, FALSE); } g_variant_unref(value); value = g_dbus_proxy_get_cached_property(timedata.proxy, "NTP"); if (value){ if (g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)){ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(timedata.timesetting_checkbutton), g_variant_get_boolean(value)); } //因为ntpd和systemd的网络时间同步会有冲突,所以安装了ntp的话,禁止使用控制面板设置网络时间同步 if(!access("/usr/sbin/ntpd", F_OK)){ gtk_widget_set_sensitive(timedata.timesetting_checkbutton, FALSE); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(timedata.timesetting_checkbutton), FALSE); gtk_widget_show(GTK_WIDGET(timedata.ntp_label)); } //将信号处理放在初始化完成之后,可以防止第一次启动控制面板时执行setntp g_signal_connect(G_OBJECT(timedata.timesetting_checkbutton), "clicked", G_CALLBACK(on_timesetting_changed), NULL); network_sensitive(); g_variant_unref(value); return; }else g_warning("Can't get the NTP value from the cache!"); } void init_calendar(){ if(strcmp(timedata.tmptime[2],"")==0){ init_calendar_time(timedata.tmptime[1],timedata.tmptime[3],timedata.tmptime[5]); } else{ init_calendar_time(timedata.tmptime[1],timedata.tmptime[2],timedata.tmptime[4]); } } void freeze_clock(){ g_signal_handlers_block_by_func(timedata.hours, on_editable_changed, NULL); g_signal_handlers_block_by_func(timedata.minutes, on_editable_changed, NULL); g_signal_handlers_block_by_func(timedata.seconds, on_editable_changed, NULL); } void thaw_clock(){ g_signal_handlers_unblock_by_func(timedata.hours, on_editable_changed, NULL); g_signal_handlers_unblock_by_func(timedata.minutes, on_editable_changed, NULL); g_signal_handlers_unblock_by_func(timedata.seconds, on_editable_changed, NULL); } void dbus_set_answered(GObject *object, GAsyncResult *res, gpointer command){ GError *error =NULL; GVariant *answers; answers = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), res, &error); if(error !=NULL){ if(!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)){ g_warning("Could not set '%s' using timedated:%s",(gchar *)command, error->message); } g_error_free(error); return; } g_variant_unref(answers); } //与网络时间同步的回调,由于里面包含了sleep,所以使用该回调单独处理 void dbus_set_answered_network(GObject *object, GAsyncResult *res, gpointer command){ GError *error =NULL; GVariant *answers; answers = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), res, &error); if(error !=NULL){ if(!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)){ g_warning("Could not set '%s' using timedated:%s",(gchar *)command, error->message); } g_error_free(error); return; } g_variant_unref(answers); //等待与网络时间同步完成,只有恢复到当前时间,才能获取到当前年月份,最后再同步过来 sleep(1); if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(timedata.timesetting_checkbutton))) { //获取当前的时间 init_time_config(); //禁用on_day_selected这个回调,防止日期变化时会触发这个回调,会再去进行时间设置 g_signal_handlers_block_by_func(timedata.calendar, on_day_selected, NULL); init_calendar(); g_signal_handlers_unblock_by_func(timedata.calendar, on_day_selected, NULL); } } gboolean on_apply_timeout(GtkWidget * widget,gpointer user_data){ GDateTime *now; gint64 newtime; guint year,month,day,hour,minute,second; hour = gtk_spin_button_get_value((GtkSpinButton *)timedata.hours); minute = gtk_spin_button_get_value((GtkSpinButton *)timedata.minutes); second = gtk_spin_button_get_value((GtkSpinButton *)timedata.seconds); gtk_calendar_get_date((GtkCalendar *)timedata.calendar, &year, &month, &day); now = g_date_time_new_local(year,month+1,day,hour,minute,(gdouble)second); newtime = g_date_time_to_unix(now); g_dbus_proxy_call(timedata.proxy, "SetTime", g_variant_new("(xbb)", (newtime * G_TIME_SPAN_SECOND), FALSE,TRUE), G_DBUS_CALL_FLAGS_NONE,-1,NULL,dbus_set_answered, "time"); start_update_show_time_clock(); //中断前,先清除apply_timeout_clock timedata.apply_timeout_clock = 0; //返回false会自动中断计时器,中断是因为为了防止在同步状态下设置时间 return FALSE; } //与网络时间同步时设置置灰某些部件 void network_sensitive() { gint timesetting_check; timesetting_check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(timedata.timesetting_checkbutton)); if(!timesetting_check) { gtk_widget_set_sensitive(timedata.hours, TRUE); gtk_widget_set_sensitive(timedata.minutes, TRUE); gtk_widget_set_sensitive(timedata.seconds, TRUE); gtk_widget_set_sensitive(timedata.td_combo_month, TRUE); gtk_widget_set_sensitive(timedata.td_combo_year, TRUE); gtk_widget_set_sensitive(timedata.td_month_add_button, TRUE); gtk_widget_set_sensitive(timedata.td_month_del_button, TRUE); gtk_widget_set_sensitive(timedata.calendar, TRUE); } else { gtk_widget_set_sensitive(timedata.hours, FALSE); gtk_widget_set_sensitive(timedata.minutes, FALSE); gtk_widget_set_sensitive(timedata.seconds, FALSE); gtk_widget_set_sensitive(timedata.td_combo_month, FALSE); gtk_widget_set_sensitive(timedata.td_combo_year, FALSE); gtk_widget_set_sensitive(timedata.td_month_add_button, FALSE); gtk_widget_set_sensitive(timedata.td_month_del_button, FALSE); gtk_widget_set_sensitive(timedata.calendar, FALSE); } } void on_timesetting_changed(GtkWidget *widget, gpointer user_data){ gboolean timesetting_check; timesetting_check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(timedata.timesetting_checkbutton)); g_dbus_proxy_call(timedata.proxy, "SetNTP", g_variant_new("(bb)", timesetting_check, TRUE), G_DBUS_CALL_FLAGS_NONE, -1,NULL, dbus_set_answered_network, "NTP"); network_sensitive(); } void on_timezone_changed(GtkWidget *widget, gpointer user_data){ GtkTreeModel *model; GtkTreeIter iter; gchar * location; gchar *rtc; TzUTC *tmp; GPtrArray *translate; translate = timedata.tzdb->locations; if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter)) { model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget)); gtk_tree_model_get(model, &iter,0 ,&location, -1); //环境变量LANG为空或者是非中文的话直接使用rtc时区 if(!getenv("LANG") || strcmp(getenv("LANG"), "zh_CN.UTF-8")) rtc = location; else{ for(int i=0; i != timedata.tzdb->locations->len; ++i){ tmp = g_ptr_array_index(timedata.tzdb->locations, i); if(tmp->tz_utc && strcmp(tmp->tz_utc, location) == 0){ rtc = g_ptr_array_index(tmp->tz_rtc,0); break; } } } g_dbus_proxy_call(timedata.proxy, "SetTimezone", g_variant_new("(sb)", rtc, TRUE), G_DBUS_CALL_FLAGS_NONE, -1,NULL, dbus_set_answered, "timezone"); } g_free(location); return; } void on_day_selected(GtkWidget *widget, gpointer user_data){ on_editable_changed(); } void on_editable_changed(){ //先清除两个计时器,然后再添加一个新的计时器 stop_update_show_time_clock(); if(timedata.apply_timeout_clock){ g_source_remove(timedata.apply_timeout_clock); timedata.apply_timeout_clock = 0; } //设置当前的时间,当前的时间保存在timedate.tmptime[]数组中,由update_show_time实时更新 timedata.apply_timeout_clock = g_timeout_add(1000,(GSourceFunc)on_apply_timeout,NULL); } void stop_update_show_time_clock(){ if(timedata.show_timeout_clock){ g_source_remove(timedata.show_timeout_clock); timedata.show_timeout_clock = 0; } } gboolean update_show_time(gpointer user_date){ init_time_config(); return TRUE; } void start_update_show_time_clock(){ if (!timedata.show_timeout_clock){ // we need to wait system to set time sleep(1); //每隔一秒不断的去更新当前的时间 timedata.show_timeout_clock= g_timeout_add(1000,(GSourceFunc)update_show_time,NULL); } } void show_timezone_system_sets(GPtrArray *loc){ const gchar * timezone; GtkTreeModel * model; GtkTreeIter iter; gboolean valid; gchar * location; GVariant *str; TzUTC *tmp; int flag = 0; str = g_dbus_proxy_get_cached_property(timedata.proxy,"Timezone"); timezone = g_variant_get_string(str, NULL); model = gtk_combo_box_get_model(GTK_COMBO_BOX(timedata.tzcombo)); valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); //获取和当前系统rtc时区对应的时区文件中的utc时区 for(int i =0; i != loc->len; ++i){ tmp = g_ptr_array_index(loc,i); for(int j =0; j != tmp->tz_rtc->len; ++j){ if(g_ptr_array_index(tmp->tz_rtc, j) && strcmp(timezone, g_ptr_array_index(tmp->tz_rtc, j)) == 0){ flag = 1; break; } } if(flag) break; //g_free(tmp); } char *lang = (!getenv("LANG") || strcmp(getenv("LANG"), "zh_CN.UTF-8")) ? g_ptr_array_index(tmp->tz_rtc, 0): tmp->tz_utc; while (valid) { gtk_tree_model_get(model, &iter, 0, &location, -1); if (strcmp (location, lang) == 0){ gtk_combo_box_set_active_iter (GTK_COMBO_BOX(timedata.tzcombo), &iter); valid = FALSE; } else { valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); } } } void init_dbus_proxy(){ GError *error=NULL; timedata.proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE,NULL, "org.freedesktop.timedate1", "/org/freedesktop/timedate1", "org.freedesktop.timedate1", NULL,&error); if (error !=NULL) { g_warning("Error :%s\n",error->message); } } void string_to_int(gchar * tmp){ gchar ** c_time; c_time = g_strsplit(tmp, ":",3); timedata.hour = atoi(c_time[0]); timedata.minute = atoi(c_time[1]); timedata.second = atoi(c_time[2]); g_strfreev(c_time); freeze_clock(); gtk_spin_button_set_value(GTK_SPIN_BUTTON(timedata.hours),(gfloat)timedata.hour); gtk_spin_button_set_value(GTK_SPIN_BUTTON(timedata.minutes),(gfloat)timedata.minute); gtk_spin_button_set_value(GTK_SPIN_BUTTON(timedata.seconds),(gfloat)timedata.second); thaw_clock(); } static void month_combo_changed(GtkComboBox *combobox, gpointer user_data){ //month combobox changed and then tell calendar gint current_month; gint current_year; current_month = gtk_combo_box_get_active(GTK_COMBO_BOX(timedata.td_combo_month)); current_year = gtk_combo_box_get_active(GTK_COMBO_BOX(timedata.td_combo_year)); if (current_year == -1) return; current_year = current_year + _GMT; gtk_calendar_select_month((GtkCalendar *)timedata.calendar, current_month, current_year); on_editable_changed(); } static void year_combo_changed(GtkComboBox * combobox, gpointer user_data){ //year comboboxtext changed and then tell calendar gint current_month; gint current_year; current_month = gtk_combo_box_get_active(GTK_COMBO_BOX(timedata.td_combo_month)); if (current_month == -1) return; current_year = gtk_combo_box_get_active(GTK_COMBO_BOX(timedata.td_combo_year)) +_GMT ; gtk_calendar_select_month((GtkCalendar *)timedata.calendar, current_month, current_year); on_editable_changed(); } void init_calendar_time(gchar *month, gchar *day, gchar *year){ //we need start month from 0 to 11 if(strcmp(month,"Jan")==0){ timedata.month = 0; }else if(strcmp(month,"Feb")==0){ timedata.month =1; }else if(strcmp(month,"Mar")==0){ timedata.month =2; }else if(strcmp(month,"Apr")==0){ timedata.month =3; }else if(strcmp(month,"May")==0){ timedata.month =4; }else if(strcmp(month,"Jun")==0){ timedata.month =5; }else if(strcmp(month,"Jul")==0){ timedata.month =6; }else if(strcmp(month,"Aug")==0){ timedata.month =7; }else if(strcmp(month,"Sep")==0){ timedata.month =8; }else if(strcmp(month,"Oct")==0){ timedata.month =9; }else if(strcmp(month,"Nov")==0){ timedata.month =10; }else if(strcmp(month,"Dec")==0){ timedata.month =11; }else{ g_warning("Wrong month"); } timedata.day = atoi(day); timedata.year = atoi(year); gtk_calendar_select_month((GtkCalendar *)timedata.calendar, timedata.month, timedata.year); gtk_calendar_select_day((GtkCalendar *)timedata.calendar, timedata.day); g_signal_handlers_block_by_func(timedata.td_combo_year,year_combo_changed,NULL); gtk_combo_box_set_active(GTK_COMBO_BOX(timedata.td_combo_year),timedata.year - _GMT); g_signal_handlers_unblock_by_func(timedata.td_combo_year,year_combo_changed,NULL); g_signal_handlers_block_by_func(timedata.td_combo_month,month_combo_changed,NULL); gtk_combo_box_set_active(GTK_COMBO_BOX(timedata.td_combo_month),timedata.month); g_signal_handlers_unblock_by_func(timedata.td_combo_month, month_combo_changed,NULL); } gchar * get_current_time(){ gchar * current_time_and_date; time_t now; struct tm *timenow; time(&now); timenow = localtime(&now); current_time_and_date = asctime(timenow); return current_time_and_date; } //获取当前系统时间并保存到tmptime数组当中 void init_time_config() { gchar * current_time_and_date; current_time_and_date = get_current_time(); g_strchomp(current_time_and_date); //split to 6,i found the date(for example 2015-07-01,01 will set 1bit and a block) timedata.tmptime = g_strsplit(current_time_and_date,"\040",6); if(strcmp(timedata.tmptime[2],"")==0){ string_to_int(timedata.tmptime[4]); } else { string_to_int(timedata.tmptime[3]); } } gchar *time_location_get_zone(TzUTC *loc){ char *lang = getenv("LANG"); if(!lang || strcmp(lang, "zh_CN.UTF-8")) return g_ptr_array_index(loc->tz_rtc,0); else return loc->tz_utc; } TzDB *init_timedb (){ gchar *tz_data_file; TzDB *tz_db; FILE *tzfile; char buf[4096]; tz_data_file = g_strdup(TZ_DATA_FILE); if (!tz_data_file){ g_warning("Could not get timedb source\n"); return NULL; } tzfile = fopen(tz_data_file, "r"); if (!tzfile) { g_warning("Could not open tzfile *%s*\n",tz_data_file); g_free(tz_data_file); return NULL; } tz_db = g_new0(TzDB, 1); tz_db->locations = g_ptr_array_new(); while(fgets(buf, sizeof(buf), tzfile)){ gchar **tmpstrarr; TzUTC *loc; loc = g_new0(TzUTC, 1); loc->tz_rtc = g_ptr_array_new(); g_strchomp(buf); tmpstrarr = g_strsplit(buf, "\t",2); gchar ***tmp_rtc = g_strsplit(tmpstrarr[0], " ", 6); for(int i =0; i!=6; ++i){ if(tmp_rtc[i] != NULL){ g_ptr_array_add (loc->tz_rtc, (gpointer)g_strdup(tmp_rtc[i])); } else break; } loc->tz_utc = g_strdup(tmpstrarr[1]); g_ptr_array_add (tz_db->locations, loc); g_strfreev(tmp_rtc); g_strfreev(tmpstrarr); } fclose(tzfile); g_free(tz_data_file); return tz_db; } static void init_timedate_data(GtkWidget * widget, gpointer user_data){ guint i; GPtrArray *loc; TzUTC *tmp; //初始化时区数据库 timedata.tzdb= init_timedb(); //init config init_time_config(); timedata.show_timeout_clock= g_timeout_add(1000,(GSourceFunc)update_show_time,NULL); //init calendar g_signal_handlers_block_by_func(timedata.calendar, on_day_selected, NULL); init_calendar(); g_signal_handlers_unblock_by_func(timedata.calendar, on_day_selected, NULL); //init dbus, get proxy init_dbus_proxy(); init_time_setting(); //初始化时区combobox loc = timedata.tzdb->locations; for (i=0; i< loc->len; i++){ //拆开是因为编译时会有一个类型不匹配的错误 tmp = g_ptr_array_index(loc, i); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(timedata.tzcombo),time_location_get_zone(tmp)); //gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(timedata.tzcombo),time_location_get_zone(g_ptr_array_index(loc,i))); } // Show the timezone what the system sets show_timezone_system_sets(loc); //g_signal_handlers_block_by_func(timedata.viewportlayout, init_timedate_data,NULL); } static void add_year_and_month_data(){ //add td_combo_year comboboxtext data gint i; for (i=0;i #include #include #include #include #include #include "gvc-mixer-source.h" #define GVC_MIXER_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SOURCE, GvcMixerSourcePrivate)) struct GvcMixerSourcePrivate { gpointer dummy; }; static void gvc_mixer_source_class_init (GvcMixerSourceClass *klass); static void gvc_mixer_source_init (GvcMixerSource *mixer_source); static void gvc_mixer_source_finalize (GObject *object); static void gvc_mixer_source_dispose (GObject *object); G_DEFINE_TYPE (GvcMixerSource, gvc_mixer_source, GVC_TYPE_MIXER_STREAM) static gboolean gvc_mixer_source_push_volume (GvcMixerStream *stream, gpointer *op) { pa_operation *o; guint index; const GvcChannelMap *map; pa_context *context; const pa_cvolume *cv; index = gvc_mixer_stream_get_index (stream); map = gvc_mixer_stream_get_channel_map (stream); /* set the volume */ cv = gvc_channel_map_get_cvolume (map); context = gvc_mixer_stream_get_pa_context (stream); o = pa_context_set_source_volume_by_index (context, index, cv, NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_source_volume_by_index() failed: %s", pa_strerror(pa_context_errno(context))); return FALSE; } *op = o; return TRUE; } static gboolean gvc_mixer_source_change_is_muted (GvcMixerStream *stream, gboolean is_muted) { pa_operation *o; guint index; pa_context *context; index = gvc_mixer_stream_get_index (stream); context = gvc_mixer_stream_get_pa_context (stream); o = pa_context_set_source_mute_by_index (context, index, is_muted, NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_source_mute_by_index() failed: %s", pa_strerror(pa_context_errno(context))); return FALSE; } pa_operation_unref(o); return TRUE; } static gboolean gvc_mixer_source_change_port (GvcMixerStream *stream, const char *port) { #if PA_MICRO > 15 pa_operation *o; guint index; pa_context *context; index = gvc_mixer_stream_get_index (stream); context = gvc_mixer_stream_get_pa_context (stream); o = pa_context_set_source_port_by_index (context, index, port, NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_source_port_by_index() failed: %s", pa_strerror(pa_context_errno(context))); return FALSE; } pa_operation_unref(o); return TRUE; #else return FALSE; #endif /* PA_MICRO > 15 */ } static GObject * gvc_mixer_source_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; GvcMixerSource *self; object = G_OBJECT_CLASS (gvc_mixer_source_parent_class)->constructor (type, n_construct_properties, construct_params); self = GVC_MIXER_SOURCE (object); return object; } static void gvc_mixer_source_class_init (GvcMixerSourceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass); object_class->constructor = gvc_mixer_source_constructor; object_class->dispose = gvc_mixer_source_dispose; object_class->finalize = gvc_mixer_source_finalize; stream_class->push_volume = gvc_mixer_source_push_volume; stream_class->change_is_muted = gvc_mixer_source_change_is_muted; stream_class->change_port = gvc_mixer_source_change_port; g_type_class_add_private (klass, sizeof (GvcMixerSourcePrivate)); } static void gvc_mixer_source_init (GvcMixerSource *source) { source->priv = GVC_MIXER_SOURCE_GET_PRIVATE (source); } static void gvc_mixer_source_dispose (GObject *object) { GvcMixerSource *mixer_source; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_SOURCE (object)); mixer_source = GVC_MIXER_SOURCE (object); G_OBJECT_CLASS (gvc_mixer_source_parent_class)->dispose (object); } static void gvc_mixer_source_finalize (GObject *object) { GvcMixerSource *mixer_source; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_SOURCE (object)); mixer_source = GVC_MIXER_SOURCE (object); g_return_if_fail (mixer_source->priv != NULL); G_OBJECT_CLASS (gvc_mixer_source_parent_class)->finalize (object); } GvcMixerStream * gvc_mixer_source_new (pa_context *context, guint index, GvcChannelMap *channel_map) { GObject *object; object = g_object_new (GVC_TYPE_MIXER_SOURCE, "pa-context", context, "index", index, "channel-map", channel_map, NULL); return GVC_MIXER_STREAM (object); } ukui-control-center/panels/volume-control/sound-theme-file-utils.h0000664000175000017500000000260013057175444024344 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * Copyright (C) 2008 Bastien Nocera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifndef __SOUND_THEME_FILE_UTILS_HH__ #define __SOUND_THEME_FILE_UTILS_HH__ #include char *custom_theme_dir_path (const char *child); gboolean custom_theme_dir_is_empty (void); void create_custom_theme (const char *parent); void delete_custom_theme_dir (void); void delete_old_files (const char **sounds); void delete_disabled_files (const char **sounds); void add_disabled_file (const char **sounds); void add_custom_file (const char **sounds, const char *filename); void custom_theme_update_time (void); #endif /* __SOUND_THEME_FILE_UTILS_HH__ */ ukui-control-center/panels/volume-control/gvc-mixer-stream.h0000664000175000017500000001472213057175444023243 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __GVC_MIXER_STREAM_H #define __GVC_MIXER_STREAM_H #include #include #include "gvc-channel-map.h" G_BEGIN_DECLS #define GVC_TYPE_MIXER_STREAM (gvc_mixer_stream_get_type ()) #define GVC_MIXER_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_STREAM, GvcMixerStream)) #define GVC_MIXER_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_STREAM, GvcMixerStreamClass)) #define GVC_IS_MIXER_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_STREAM)) #define GVC_IS_MIXER_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_STREAM)) #define GVC_MIXER_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_STREAM, GvcMixerStreamClass)) typedef struct GvcMixerStreamPrivate GvcMixerStreamPrivate; typedef struct { GObject parent; GvcMixerStreamPrivate *priv; } GvcMixerStream; typedef struct { GObjectClass parent_class; /* vtable */ gboolean (*push_volume) (GvcMixerStream *stream, gpointer *operation); gboolean (*change_is_muted) (GvcMixerStream *stream, gboolean is_muted); gboolean (*change_port) (GvcMixerStream *stream, const char *port); } GvcMixerStreamClass; typedef struct { char *port; char *human_port; guint priority; } GvcMixerStreamPort; GType gvc_mixer_stream_get_type (void); pa_context * gvc_mixer_stream_get_pa_context (GvcMixerStream *stream); guint gvc_mixer_stream_get_index (GvcMixerStream *stream); guint gvc_mixer_stream_get_id (GvcMixerStream *stream); const GvcChannelMap *gvc_mixer_stream_get_channel_map(GvcMixerStream *stream); const GvcMixerStreamPort *gvc_mixer_stream_get_port (GvcMixerStream *stream); const GList * gvc_mixer_stream_get_ports (GvcMixerStream *stream); gboolean gvc_mixer_stream_change_port (GvcMixerStream *stream, const char *port); pa_volume_t gvc_mixer_stream_get_volume (GvcMixerStream *stream); gdouble gvc_mixer_stream_get_decibel (GvcMixerStream *stream); gboolean gvc_mixer_stream_push_volume (GvcMixerStream *stream); pa_volume_t gvc_mixer_stream_get_base_volume (GvcMixerStream *stream); gboolean gvc_mixer_stream_get_is_muted (GvcMixerStream *stream); gboolean gvc_mixer_stream_get_can_decibel (GvcMixerStream *stream); gboolean gvc_mixer_stream_change_is_muted (GvcMixerStream *stream, gboolean is_muted); gboolean gvc_mixer_stream_is_running (GvcMixerStream *stream); const char * gvc_mixer_stream_get_name (GvcMixerStream *stream); const char * gvc_mixer_stream_get_icon_name (GvcMixerStream *stream); const char * gvc_mixer_stream_get_description (GvcMixerStream *stream); const char * gvc_mixer_stream_get_application_id (GvcMixerStream *stream); gboolean gvc_mixer_stream_is_event_stream (GvcMixerStream *stream); gboolean gvc_mixer_stream_is_virtual (GvcMixerStream *stream); gint gvc_mixer_stream_get_card_index (GvcMixerStream *stream); /* private */ gboolean gvc_mixer_stream_set_volume (GvcMixerStream *stream, pa_volume_t volume); gboolean gvc_mixer_stream_set_decibel (GvcMixerStream *stream, gdouble db); gboolean gvc_mixer_stream_set_is_muted (GvcMixerStream *stream, gboolean is_muted); gboolean gvc_mixer_stream_set_can_decibel (GvcMixerStream *stream, gboolean can_decibel); gboolean gvc_mixer_stream_set_name (GvcMixerStream *stream, const char *name); gboolean gvc_mixer_stream_set_description (GvcMixerStream *stream, const char *description); gboolean gvc_mixer_stream_set_icon_name (GvcMixerStream *stream, const char *name); gboolean gvc_mixer_stream_set_is_event_stream (GvcMixerStream *stream, gboolean is_event_stream); gboolean gvc_mixer_stream_set_is_virtual (GvcMixerStream *stream, gboolean is_event_stream); gboolean gvc_mixer_stream_set_application_id (GvcMixerStream *stream, const char *application_id); gboolean gvc_mixer_stream_set_base_volume (GvcMixerStream *stream, pa_volume_t base_volume); gboolean gvc_mixer_stream_set_port (GvcMixerStream *stream, const char *port); gboolean gvc_mixer_stream_set_ports (GvcMixerStream *stream, GList *ports); gboolean gvc_mixer_stream_set_card_index (GvcMixerStream *stream, gint card_index); G_END_DECLS #endif /* __GVC_MIXER_STREAM_H */ ukui-control-center/panels/volume-control/gvc-mixer-dialog.c0000664000175000017500000026114013253611037023167 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #if GTK_CHECK_VERSION (3, 0, 0) #include #endif #include "gvc-channel-bar.h" #include "gvc-balance-bar.h" #include "gvc-combo-box.h" #include "gvc-mixer-control.h" #include "gvc-mixer-card.h" #include "gvc-mixer-sink.h" #include "gvc-mixer-source.h" #include "gvc-mixer-source-output.h" #include "gvc-mixer-dialog.h" #include "gvc-sound-theme-chooser.h" #include "gvc-level-bar.h" #include "gvc-speaker-test.h" #define SCALE_SIZE 128 #define GVC_MIXER_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_DIALOG, GvcMixerDialogPrivate)) struct GvcMixerDialogPrivate { GvcMixerControl *mixer_control; GHashTable *bars; GtkWidget *notebook; GtkWidget *output_bar; GtkWidget *input_bar; GtkWidget *input_level_bar; GtkWidget *effects_bar; GtkWidget *output_stream_box; GtkWidget *sound_effects_box; GtkWidget *hw_box; GtkWidget *hw_treeview; GtkWidget *hw_settings_box; GtkWidget *hw_profile_combo; GtkWidget *input_box; GtkWidget *output_box; GtkWidget *applications_box; GtkWidget *applications_scrolled_window; GtkWidget *applications_main_box; GtkWidget *no_apps_label; GtkWidget *output_treeview; GtkWidget *output_settings_box; GtkWidget *output_balance_bar; GtkWidget *output_fade_bar; GtkWidget *output_lfe_bar; GtkWidget *output_port_combo; GtkWidget *input_treeview; GtkWidget *input_port_combo; GtkWidget *input_settings_box; GtkWidget *sound_theme_chooser; GtkWidget *click_feedback_button; GtkWidget *audible_bell_button; GtkSizeGroup *size_group; GtkSizeGroup *apps_size_group; gdouble last_input_peak; guint num_apps; }; enum { NAME_COLUMN, DEVICE_COLUMN, ACTIVE_COLUMN, ID_COLUMN, SPEAKERS_COLUMN, NUM_COLUMNS }; enum { HW_ID_COLUMN, HW_ICON_COLUMN, HW_NAME_COLUMN, HW_STATUS_COLUMN, HW_PROFILE_COLUMN, HW_PROFILE_HUMAN_COLUMN, HW_SENSITIVE_COLUMN, HW_NUM_COLUMNS }; enum { PROP_0, PROP_MIXER_CONTROL }; GtkBuilder * main_builder; static void gvc_mixer_dialog_class_init (GvcMixerDialogClass *klass); static void gvc_mixer_dialog_init (GvcMixerDialog *mixer_dialog); static void gvc_mixer_dialog_finalize (GObject *object); static void bar_set_stream (GvcMixerDialog *dialog, GtkWidget *bar, GvcMixerStream *stream); static void on_adjustment_value_changed (GtkAdjustment *adjustment, GvcMixerDialog *dialog); G_DEFINE_TYPE (GvcMixerDialog, gvc_mixer_dialog, GTK_TYPE_DIALOG) static void update_default_input (GvcMixerDialog *dialog) { GtkTreeModel *model; GtkTreeIter iter; gboolean ret; model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview)); ret = gtk_tree_model_get_iter_first (model, &iter); if (ret == FALSE) { g_debug ("No default input selected or available"); return; } do { gboolean toggled; gboolean is_default; guint id; GvcMixerStream *stream; gtk_tree_model_get (model, &iter, ID_COLUMN, &id, ACTIVE_COLUMN, &toggled, -1); stream = gvc_mixer_control_lookup_stream_id (dialog->priv->mixer_control, id); if (stream == NULL) { g_warning ("Unable to find stream for id: %u", id); continue; } is_default = FALSE; if (stream == gvc_mixer_control_get_default_source (dialog->priv->mixer_control)) { is_default = TRUE; } gtk_list_store_set (GTK_LIST_STORE (model), &iter, ACTIVE_COLUMN, is_default, -1); } while (gtk_tree_model_iter_next (model, &iter)); } static void update_description (GvcMixerDialog *dialog, guint column, const char *value, GvcMixerStream *stream) { GtkTreeModel *model; GtkTreeIter iter; guint id; if (GVC_IS_MIXER_SOURCE (stream)) model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview)); else if (GVC_IS_MIXER_SINK (stream)) model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview)); else g_assert_not_reached (); gtk_tree_model_get_iter_first (model, &iter); id = gvc_mixer_stream_get_id (stream); do { guint current_id; gtk_tree_model_get (model, &iter, ID_COLUMN, ¤t_id, -1); if (id != current_id) continue; gtk_list_store_set (GTK_LIST_STORE (model), &iter, column, value, -1); break; } while (gtk_tree_model_iter_next (model, &iter)); } static void port_selection_changed (GvcComboBox *combo_box, const char *port, GvcMixerDialog *dialog) { GvcMixerStream *stream; stream = g_object_get_data (G_OBJECT (combo_box), "stream"); if (stream == NULL) { g_warning ("Could not find stream for port combo box"); return; } if (gvc_mixer_stream_change_port (stream, port) == FALSE) { g_warning ("Could not change port for stream"); } } static void update_output_settings (GvcMixerDialog *dialog) { GvcMixerStream *stream; const GvcChannelMap *map; const GList *ports; g_debug ("Updating output settings"); if (dialog->priv->output_balance_bar != NULL) { gtk_container_remove (GTK_CONTAINER (dialog->priv->output_settings_box), dialog->priv->output_balance_bar); dialog->priv->output_balance_bar = NULL; } if (dialog->priv->output_fade_bar != NULL) { gtk_container_remove (GTK_CONTAINER (dialog->priv->output_settings_box), dialog->priv->output_fade_bar); dialog->priv->output_fade_bar = NULL; } if (dialog->priv->output_lfe_bar != NULL) { gtk_container_remove (GTK_CONTAINER (dialog->priv->output_settings_box), dialog->priv->output_lfe_bar); dialog->priv->output_lfe_bar = NULL; } if (dialog->priv->output_port_combo != NULL) { gtk_container_remove (GTK_CONTAINER (dialog->priv->output_settings_box), dialog->priv->output_port_combo); dialog->priv->output_port_combo = NULL; } stream = gvc_mixer_control_get_default_sink (dialog->priv->mixer_control); if (stream == NULL) { g_warning ("Default sink stream not found"); return; } gvc_channel_bar_set_base_volume (GVC_CHANNEL_BAR (dialog->priv->output_bar), gvc_mixer_stream_get_base_volume (stream)); gvc_channel_bar_set_is_amplified (GVC_CHANNEL_BAR (dialog->priv->output_bar), gvc_mixer_stream_get_can_decibel (stream)); map = gvc_mixer_stream_get_channel_map (stream); if (map == NULL) { g_warning ("Default sink stream has no channel map"); return; } dialog->priv->output_balance_bar = gvc_balance_bar_new (map, BALANCE_TYPE_RL); if (dialog->priv->size_group != NULL) { gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (dialog->priv->output_balance_bar), dialog->priv->size_group, TRUE); } gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box), dialog->priv->output_balance_bar, FALSE, FALSE, 6); gtk_widget_show (dialog->priv->output_balance_bar); if (gvc_channel_map_can_fade (map)) { dialog->priv->output_fade_bar = gvc_balance_bar_new (map, BALANCE_TYPE_FR); if (dialog->priv->size_group != NULL) { gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (dialog->priv->output_fade_bar), dialog->priv->size_group, TRUE); } gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box), dialog->priv->output_fade_bar, FALSE, FALSE, 6); gtk_widget_show (dialog->priv->output_fade_bar); } if (gvc_channel_map_has_lfe (map)) { dialog->priv->output_lfe_bar = gvc_balance_bar_new (map, BALANCE_TYPE_LFE); if (dialog->priv->size_group != NULL) { gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (dialog->priv->output_lfe_bar), dialog->priv->size_group, TRUE); } gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box), dialog->priv->output_lfe_bar, FALSE, FALSE, 6); gtk_widget_show (dialog->priv->output_lfe_bar); } ports = gvc_mixer_stream_get_ports (stream); if (ports != NULL) { const GvcMixerStreamPort *port; port = gvc_mixer_stream_get_port (stream); dialog->priv->output_port_combo = gvc_combo_box_new (_("Co_nnector")); gvc_combo_box_set_ports (GVC_COMBO_BOX (dialog->priv->output_port_combo), ports); gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->output_port_combo), port->port); g_object_set_data (G_OBJECT (dialog->priv->output_port_combo), "stream", stream); g_signal_connect (G_OBJECT (dialog->priv->output_port_combo), "changed", G_CALLBACK (port_selection_changed), dialog); gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box), dialog->priv->output_port_combo, TRUE, FALSE, 6); gvc_combo_box_set_size_group (GVC_COMBO_BOX (dialog->priv->output_port_combo), dialog->priv->size_group, FALSE); gtk_widget_show (dialog->priv->output_port_combo); } /* FIXME: We could make this into a "No settings" label instead */ gtk_widget_set_sensitive (dialog->priv->output_balance_bar, gvc_channel_map_can_balance (map)); } static void update_default_output (GvcMixerDialog *dialog) { GtkTreeModel *model; GtkTreeIter iter; model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview)); gtk_tree_model_get_iter_first (model, &iter); do { gboolean toggled; gboolean is_default; guint id; GvcMixerStream *stream; gtk_tree_model_get (model, &iter, ID_COLUMN, &id, ACTIVE_COLUMN, &toggled, -1); stream = gvc_mixer_control_lookup_stream_id (dialog->priv->mixer_control, id); if (stream == NULL) { g_warning ("Unable to find stream for id: %u", id); continue; } is_default = FALSE; if (stream == gvc_mixer_control_get_default_sink (dialog->priv->mixer_control)) { is_default = TRUE; } gtk_list_store_set (GTK_LIST_STORE (model), &iter, ACTIVE_COLUMN, is_default, -1); } while (gtk_tree_model_iter_next (model, &iter)); } static void on_mixer_control_default_sink_changed (GvcMixerControl *control, guint id, GvcMixerDialog *dialog) { GvcMixerStream *stream; g_debug ("GvcMixerDialog: default sink changed: %u", id); if (id == PA_INVALID_INDEX) stream = NULL; else stream = gvc_mixer_control_lookup_stream_id (dialog->priv->mixer_control, id); bar_set_stream (dialog, dialog->priv->output_bar, stream); update_output_settings (dialog); update_default_output (dialog); } #define DECAY_STEP .15 static void update_input_peak (GvcMixerDialog *dialog, gdouble v) { GtkAdjustment *adj; if (dialog->priv->last_input_peak >= DECAY_STEP) { if (v < dialog->priv->last_input_peak - DECAY_STEP) { v = dialog->priv->last_input_peak - DECAY_STEP; } } dialog->priv->last_input_peak = v; adj = gvc_level_bar_get_peak_adjustment (GVC_LEVEL_BAR (dialog->priv->input_level_bar)); if (v >= 0) { gtk_adjustment_set_value (adj, v); } else { gtk_adjustment_set_value (adj, 0.0); } } static void update_input_meter (GvcMixerDialog *dialog, uint32_t source_index, uint32_t sink_input_idx, double v) { update_input_peak (dialog, v); } static void on_monitor_suspended_callback (pa_stream *s, void *userdata) { GvcMixerDialog *dialog; dialog = userdata; if (pa_stream_is_suspended (s)) { g_debug ("Stream suspended"); update_input_meter (dialog, pa_stream_get_device_index (s), PA_INVALID_INDEX, -1); } } static void on_monitor_read_callback (pa_stream *s, size_t length, void *userdata) { GvcMixerDialog *dialog; const void *data; double v; dialog = userdata; if (pa_stream_peek (s, &data, &length) < 0) { g_warning ("Failed to read data from stream"); return; } assert (length > 0); assert (length % sizeof (float) == 0); v = ((const float *) data)[length / sizeof (float) -1]; pa_stream_drop (s); if (v < 0) { v = 0; } if (v > 1) { v = 1; } update_input_meter (dialog, pa_stream_get_device_index (s), pa_stream_get_monitor_stream (s), v); } static void create_monitor_stream_for_source (GvcMixerDialog *dialog, GvcMixerStream *stream) { pa_stream *s; char t[16]; pa_buffer_attr attr; pa_sample_spec ss; pa_context *context; int res; pa_proplist *proplist; gboolean has_monitor; if (stream == NULL) { return; } has_monitor = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (stream), "has-monitor")); if (has_monitor != FALSE) { return; } g_debug ("Create monitor for %u", gvc_mixer_stream_get_index (stream)); context = gvc_mixer_control_get_pa_context (dialog->priv->mixer_control); if (pa_context_get_server_protocol_version (context) < 13) { return; } ss.channels = 1; ss.format = PA_SAMPLE_FLOAT32; ss.rate = 25; memset (&attr, 0, sizeof (attr)); attr.fragsize = sizeof (float); attr.maxlength = (uint32_t) -1; snprintf (t, sizeof (t), "%u", gvc_mixer_stream_get_index (stream)); proplist = pa_proplist_new (); pa_proplist_sets (proplist, PA_PROP_APPLICATION_ID, "org.ukui.VolumeControl"); s = pa_stream_new_with_proplist (context, _("Peak detect"), &ss, NULL, proplist); pa_proplist_free (proplist); if (s == NULL) { g_warning ("Failed to create monitoring stream"); return; } pa_stream_set_read_callback (s, on_monitor_read_callback, dialog); pa_stream_set_suspended_callback (s, on_monitor_suspended_callback, dialog); res = pa_stream_connect_record (s, t, &attr, (pa_stream_flags_t) (PA_STREAM_DONT_MOVE |PA_STREAM_PEAK_DETECT |PA_STREAM_ADJUST_LATENCY)); if (res < 0) { g_warning ("Failed to connect monitoring stream"); pa_stream_unref (s); } else { g_object_set_data (G_OBJECT (stream), "has-monitor", GINT_TO_POINTER (TRUE)); g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream", s); g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "stream", stream); } } static void stop_monitor_stream_for_source (GvcMixerDialog *dialog) { pa_stream *s; pa_context *context; int res; GvcMixerStream *stream; s = g_object_get_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream"); if (s == NULL) return; stream = g_object_get_data (G_OBJECT (dialog->priv->input_level_bar), "stream"); g_assert (stream != NULL); g_debug ("Stopping monitor for %u", pa_stream_get_index (s)); context = gvc_mixer_control_get_pa_context (dialog->priv->mixer_control); if (pa_context_get_server_protocol_version (context) < 13) { return; } res = pa_stream_disconnect (s); if (res == 0) g_object_set_data (G_OBJECT (stream), "has-monitor", GINT_TO_POINTER (FALSE)); g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream", NULL); g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "stream", NULL); } static void update_input_settings (GvcMixerDialog *dialog) { const GList *ports; GvcMixerStream *stream; g_debug ("Updating input settings"); stop_monitor_stream_for_source (dialog); if (dialog->priv->input_port_combo != NULL) { gtk_container_remove (GTK_CONTAINER (dialog->priv->input_settings_box), dialog->priv->input_port_combo); dialog->priv->input_port_combo = NULL; } stream = gvc_mixer_control_get_default_source (dialog->priv->mixer_control); if (stream == NULL) { g_debug ("Default source stream not found"); return; } gvc_channel_bar_set_base_volume (GVC_CHANNEL_BAR (dialog->priv->input_bar), gvc_mixer_stream_get_base_volume (stream)); gvc_channel_bar_set_is_amplified (GVC_CHANNEL_BAR (dialog->priv->input_bar), gvc_mixer_stream_get_can_decibel (stream)); ports = gvc_mixer_stream_get_ports (stream); if (ports != NULL) { const GvcMixerStreamPort *port; port = gvc_mixer_stream_get_port (stream); dialog->priv->input_port_combo = gvc_combo_box_new (_("Co_nnector:")); gvc_combo_box_set_ports (GVC_COMBO_BOX (dialog->priv->input_port_combo), ports); gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->input_port_combo), port->port); g_object_set_data (G_OBJECT (dialog->priv->input_port_combo), "stream", stream); g_signal_connect (G_OBJECT (dialog->priv->input_port_combo), "changed", G_CALLBACK (port_selection_changed), dialog); gvc_combo_box_set_size_group (GVC_COMBO_BOX (dialog->priv->input_port_combo), dialog->priv->size_group, FALSE); gtk_box_pack_start (GTK_BOX (dialog->priv->input_settings_box), dialog->priv->input_port_combo, TRUE, TRUE, 0); gtk_widget_show (dialog->priv->input_port_combo); } create_monitor_stream_for_source (dialog, stream); } static void on_mixer_control_default_source_changed (GvcMixerControl *control, guint id, GvcMixerDialog *dialog) { GvcMixerStream *stream; GtkAdjustment *adj; g_debug ("GvcMixerDialog: default source changed: %u", id); if (id == PA_INVALID_INDEX) stream = NULL; else stream = gvc_mixer_control_lookup_stream_id (dialog->priv->mixer_control, id); /* Disconnect the adj, otherwise it might change if is_amplified changes */ adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->input_bar))); g_signal_handlers_disconnect_by_func(adj, on_adjustment_value_changed, dialog); bar_set_stream (dialog, dialog->priv->input_bar, stream); update_input_settings (dialog); g_signal_connect (adj, "value-changed", G_CALLBACK (on_adjustment_value_changed), dialog); update_default_input (dialog); } static void gvc_mixer_dialog_set_mixer_control (GvcMixerDialog *dialog, GvcMixerControl *control) { g_return_if_fail (GVC_MIXER_DIALOG (dialog)); g_return_if_fail (GVC_IS_MIXER_CONTROL (control)); g_object_ref (control); if (dialog->priv->mixer_control != NULL) { g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control, G_CALLBACK (on_mixer_control_default_sink_changed), dialog); g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control, G_CALLBACK (on_mixer_control_default_source_changed), dialog); g_object_unref (dialog->priv->mixer_control); } dialog->priv->mixer_control = control; g_signal_connect (dialog->priv->mixer_control, "default-sink-changed", G_CALLBACK (on_mixer_control_default_sink_changed), dialog); g_signal_connect (dialog->priv->mixer_control, "default-source-changed", G_CALLBACK (on_mixer_control_default_source_changed), dialog); g_object_notify (G_OBJECT (dialog), "mixer-control"); } static GvcMixerControl * gvc_mixer_dialog_get_mixer_control (GvcMixerDialog *dialog) { g_return_val_if_fail (GVC_IS_MIXER_DIALOG (dialog), NULL); return dialog->priv->mixer_control; } static void gvc_mixer_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GvcMixerDialog *self = GVC_MIXER_DIALOG (object); switch (prop_id) { case PROP_MIXER_CONTROL: gvc_mixer_dialog_set_mixer_control (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gvc_mixer_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GvcMixerDialog *self = GVC_MIXER_DIALOG (object); switch (prop_id) { case PROP_MIXER_CONTROL: g_value_set_object (value, gvc_mixer_dialog_get_mixer_control (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void on_adjustment_value_changed (GtkAdjustment *adjustment, GvcMixerDialog *dialog) { GvcMixerStream *stream; stream = g_object_get_data (G_OBJECT (adjustment), "gvc-mixer-dialog-stream"); if (stream != NULL) { GObject *bar; gdouble volume, rounded; char *name; volume = gtk_adjustment_get_value (adjustment); rounded = round (volume); bar = g_object_get_data (G_OBJECT (adjustment), "gvc-mixer-dialog-bar"); g_object_get (bar, "name", &name, NULL); g_debug ("Setting stream volume %lf (rounded: %lf) for bar '%s'", volume, rounded, name); g_free (name); /* FIXME would need to do that in the balance bar really... */ /* Make sure we do not unmute muted streams, there's a button for that */ //控制声音是否为静音 if (volume == 0.0) gvc_mixer_stream_set_is_muted (stream, TRUE); /* Only push the volume if it's actually changed */ //控制声音对其进行放大缩小 if (gvc_mixer_stream_set_volume(stream, (pa_volume_t) rounded) != FALSE) gvc_mixer_stream_push_volume (stream); //将放大缩小后的声音播放出来 } } static void on_bar_is_muted_notify (GObject *object, GParamSpec *pspec, GvcMixerDialog *dialog) { gboolean is_muted; GvcMixerStream *stream; is_muted = gvc_channel_bar_get_is_muted (GVC_CHANNEL_BAR (object)); stream = g_object_get_data (object, "gvc-mixer-dialog-stream"); if (stream != NULL) { gvc_mixer_stream_change_is_muted (stream, is_muted); } else { char *name; g_object_get (object, "name", &name, NULL); g_warning ("Unable to find stream for bar '%s'", name); g_free (name); } } static GtkWidget * lookup_bar_for_stream (GvcMixerDialog *dialog, GvcMixerStream *stream) { GtkWidget *bar; bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream))); return bar; } static GtkWidget * lookup_combo_box_for_stream (GvcMixerDialog *dialog, GvcMixerStream *stream) { GvcMixerStream *combo_stream; guint id; id = gvc_mixer_stream_get_id (stream); if (dialog->priv->output_port_combo != NULL) { combo_stream = g_object_get_data (G_OBJECT (dialog->priv->output_port_combo), "stream"); if (combo_stream != NULL) { if (id == gvc_mixer_stream_get_id (combo_stream)) return dialog->priv->output_port_combo; } } if (dialog->priv->input_port_combo != NULL) { combo_stream = g_object_get_data (G_OBJECT (dialog->priv->input_port_combo), "stream"); if (combo_stream != NULL) { if (id == gvc_mixer_stream_get_id (combo_stream)) return dialog->priv->input_port_combo; } } return NULL; } static void on_stream_description_notify (GvcMixerStream *stream, GParamSpec *pspec, GvcMixerDialog *dialog) { update_description (dialog, NAME_COLUMN, gvc_mixer_stream_get_description (stream), stream); } static void on_stream_port_notify (GObject *object, GParamSpec *pspec, GvcMixerDialog *dialog) { GvcComboBox *combo_box; char *port; combo_box = GVC_COMBO_BOX (lookup_combo_box_for_stream (dialog, GVC_MIXER_STREAM (object))); if (combo_box == NULL) return; g_signal_handlers_block_by_func (G_OBJECT (combo_box), port_selection_changed, dialog); g_object_get (object, "port", &port, NULL); gvc_combo_box_set_active (GVC_COMBO_BOX (combo_box), port); g_signal_handlers_unblock_by_func (G_OBJECT (combo_box), port_selection_changed, dialog); } static void on_stream_volume_notify (GObject *object, GParamSpec *pspec, GvcMixerDialog *dialog) { GvcMixerStream *stream; GtkWidget *bar; GtkAdjustment *adj; stream = GVC_MIXER_STREAM (object); bar = lookup_bar_for_stream (dialog, stream); if (bar == NULL) { g_warning ("Unable to find bar for stream %s in on_stream_volume_notify()", gvc_mixer_stream_get_name (stream)); return; } adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar))); g_signal_handlers_block_by_func (adj, on_adjustment_value_changed, dialog); gtk_adjustment_set_value (adj, gvc_mixer_stream_get_volume (stream)); g_signal_handlers_unblock_by_func (adj, on_adjustment_value_changed, dialog); } static void on_stream_is_muted_notify (GObject *object, GParamSpec *pspec, GvcMixerDialog *dialog) { GvcMixerStream *stream; GtkWidget *bar; gboolean is_muted; stream = GVC_MIXER_STREAM (object); bar = lookup_bar_for_stream (dialog, stream); if (bar == NULL) { g_warning ("Unable to find bar for stream %s in on_stream_is_muted_notify()", gvc_mixer_stream_get_name (stream)); return; } is_muted = gvc_mixer_stream_get_is_muted (stream); gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (bar), is_muted); if (stream == gvc_mixer_control_get_default_sink (dialog->priv->mixer_control)) { gtk_widget_set_sensitive (dialog->priv->applications_box, !is_muted); } } static void save_bar_for_stream (GvcMixerDialog *dialog, GvcMixerStream *stream, GtkWidget *bar) { g_hash_table_insert (dialog->priv->bars, GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)), bar); } static GtkWidget * create_bar (GvcMixerDialog *dialog, GtkSizeGroup *size_group, gboolean symmetric) { GtkWidget *bar; bar = gvc_channel_bar_new (); gtk_widget_set_sensitive (bar, FALSE); if (size_group != NULL) { gvc_channel_bar_set_size_group (GVC_CHANNEL_BAR (bar), size_group, symmetric); } gvc_channel_bar_set_orientation (GVC_CHANNEL_BAR (bar), GTK_ORIENTATION_HORIZONTAL); gvc_channel_bar_set_show_mute (GVC_CHANNEL_BAR (bar), TRUE); g_signal_connect (bar, "notify::is-muted", G_CALLBACK (on_bar_is_muted_notify), dialog); return bar; } static void bar_set_stream (GvcMixerDialog *dialog, GtkWidget *bar, GvcMixerStream *stream) { GtkAdjustment *adj; GvcMixerStream *old_stream; g_assert (bar != NULL); old_stream = g_object_get_data (G_OBJECT (bar), "gvc-mixer-dialog-stream"); if (old_stream != NULL) { char *name; g_object_get (bar, "name", &name, NULL); g_debug ("Disconnecting old stream '%s' from bar '%s'", gvc_mixer_stream_get_name (old_stream), name); g_free (name); g_signal_handlers_disconnect_by_func (old_stream, on_stream_is_muted_notify, dialog); g_signal_handlers_disconnect_by_func (old_stream, on_stream_volume_notify, dialog); g_signal_handlers_disconnect_by_func (old_stream, on_stream_port_notify, dialog); g_hash_table_remove (dialog->priv->bars, GUINT_TO_POINTER (gvc_mixer_stream_get_id (old_stream))); } gtk_widget_set_sensitive (bar, (stream != NULL)); adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar))); g_signal_handlers_disconnect_by_func (adj, on_adjustment_value_changed, dialog); g_object_set_data (G_OBJECT (bar), "gvc-mixer-dialog-stream", stream); g_object_set_data (G_OBJECT (adj), "gvc-mixer-dialog-stream", stream); g_object_set_data (G_OBJECT (adj), "gvc-mixer-dialog-bar", bar); if (stream != NULL) { gboolean is_muted; is_muted = gvc_mixer_stream_get_is_muted (stream); gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (bar), is_muted); save_bar_for_stream (dialog, stream, bar); gtk_adjustment_set_value (adj, gvc_mixer_stream_get_volume (stream)); g_signal_connect (stream, "notify::is-muted", G_CALLBACK (on_stream_is_muted_notify), dialog); g_signal_connect (stream, "notify::volume", G_CALLBACK (on_stream_volume_notify), dialog); g_signal_connect (stream, "notify::port", G_CALLBACK (on_stream_port_notify), dialog); g_signal_connect (adj, "value-changed", G_CALLBACK (on_adjustment_value_changed), dialog); } } static void add_stream (GvcMixerDialog *dialog, GvcMixerStream *stream) { GtkWidget *bar; gboolean is_muted; gboolean is_default; GtkAdjustment *adj; const char *id; g_assert (stream != NULL); if (gvc_mixer_stream_is_event_stream (stream) != FALSE) return; const char *alsa_name = gvc_mixer_stream_get_name (stream); if(NULL!=strstr(alsa_name,"ALSA")) return; bar = NULL; is_default = FALSE; id = gvc_mixer_stream_get_application_id (stream); if (stream == gvc_mixer_control_get_default_sink (dialog->priv->mixer_control)) { bar = dialog->priv->output_bar; is_muted = gvc_mixer_stream_get_is_muted (stream); is_default = TRUE; gtk_widget_set_sensitive (dialog->priv->applications_box, !is_muted); adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar))); g_signal_handlers_disconnect_by_func(adj, on_adjustment_value_changed, dialog); update_output_settings (dialog); } else if (stream == gvc_mixer_control_get_default_source (dialog->priv->mixer_control)) { bar = dialog->priv->input_bar; adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar))); g_signal_handlers_disconnect_by_func(adj, on_adjustment_value_changed, dialog); update_input_settings (dialog); is_default = TRUE; } else if (stream == gvc_mixer_control_get_event_sink_input (dialog->priv->mixer_control)) { bar = dialog->priv->effects_bar; g_debug ("Adding effects stream"); } else if (! GVC_IS_MIXER_SOURCE (stream) && !GVC_IS_MIXER_SINK (stream) && !gvc_mixer_stream_is_virtual (stream) && g_strcmp0 (id, "org.ukui.VolumeControl") != 0 && g_strcmp0 (id, "org.PulseAudio.pavucontrol") != 0) { const char *name; bar = create_bar (dialog, dialog->priv->apps_size_group, FALSE); name = gvc_mixer_stream_get_name (stream); if (name == NULL || strchr (name, '_') == NULL) { gvc_channel_bar_set_name (GVC_CHANNEL_BAR (bar), name); } else { char **tokens, *escaped; tokens = g_strsplit (name, "_", -1); escaped = g_strjoinv ("__", tokens); g_strfreev (tokens); gvc_channel_bar_set_name (GVC_CHANNEL_BAR (bar), escaped); g_free (escaped); } gvc_channel_bar_set_icon_name (GVC_CHANNEL_BAR (bar), gvc_mixer_stream_get_icon_name (stream)); gtk_box_pack_start (GTK_BOX (dialog->priv->applications_box), bar, FALSE, FALSE, 12); dialog->priv->num_apps++; gtk_widget_hide (dialog->priv->no_apps_label); } if (GVC_IS_MIXER_SOURCE (stream)) { GtkTreeModel *model; GtkTreeIter iter; model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview)); gtk_list_store_append (GTK_LIST_STORE (model), &iter); gtk_list_store_set (GTK_LIST_STORE (model), &iter, NAME_COLUMN, gvc_mixer_stream_get_description (stream), DEVICE_COLUMN, "", ACTIVE_COLUMN, is_default, ID_COLUMN, gvc_mixer_stream_get_id (stream), -1); g_signal_connect (stream, "notify::description", G_CALLBACK (on_stream_description_notify), dialog); } else if (GVC_IS_MIXER_SINK (stream)) { GtkTreeModel *model; GtkTreeIter iter; const GvcChannelMap *map; model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview)); gtk_list_store_append (GTK_LIST_STORE (model), &iter); map = gvc_mixer_stream_get_channel_map (stream); gtk_list_store_set (GTK_LIST_STORE (model), &iter, NAME_COLUMN, gvc_mixer_stream_get_description (stream), DEVICE_COLUMN, "", ACTIVE_COLUMN, is_default, ID_COLUMN, gvc_mixer_stream_get_id (stream), SPEAKERS_COLUMN, gvc_channel_map_get_mapping (map), -1); g_signal_connect (stream, "notify::description", G_CALLBACK (on_stream_description_notify), dialog); } if (bar != NULL) { bar_set_stream (dialog, bar, stream); gtk_widget_show (bar); } } static void on_control_stream_added (GvcMixerControl *control, guint id, GvcMixerDialog *dialog) { GvcMixerStream *stream; GtkWidget *bar; bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (id)); if (bar != NULL) { g_debug ("GvcMixerDialog: Stream %u already added", id); return; } stream = gvc_mixer_control_lookup_stream_id (control, id); if (stream != NULL) { add_stream (dialog, stream); } } static gboolean find_item_by_id (GtkTreeModel *model, guint id, guint column, GtkTreeIter *iter) { gboolean found_item; found_item = FALSE; if (!gtk_tree_model_get_iter_first (model, iter)) { return FALSE; } do { guint t_id; gtk_tree_model_get (model, iter, column, &t_id, -1); if (id == t_id) { found_item = TRUE; } } while (!found_item && gtk_tree_model_iter_next (model, iter)); return found_item; } static void remove_stream (GvcMixerDialog *dialog, guint id) { GtkWidget *bar; gboolean found; GtkTreeIter iter; GtkTreeModel *model; /* remove bars for applications and reset fixed bars */ bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (id)); if (bar == dialog->priv->output_bar || bar == dialog->priv->input_bar // if (bar == dialog->priv->input_bar || bar == dialog->priv->effects_bar) { char *name; g_object_get (bar, "name", &name, NULL); g_debug ("Removing stream for bar '%s'", name); g_free (name); bar_set_stream (dialog, bar, NULL); } else if (bar != NULL) { g_hash_table_remove (dialog->priv->bars, GUINT_TO_POINTER (id)); gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (bar)), bar); dialog->priv->num_apps--; if (dialog->priv->num_apps == 0) { gtk_widget_show (dialog->priv->no_apps_label); } } /* remove from any models */ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview)); found = find_item_by_id (GTK_TREE_MODEL (model), id, ID_COLUMN, &iter); if (found) { gtk_list_store_remove (GTK_LIST_STORE (model), &iter); } model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview)); found = find_item_by_id (GTK_TREE_MODEL (model), id, ID_COLUMN, &iter); if (found) { gtk_list_store_remove (GTK_LIST_STORE (model), &iter); } } static void on_control_stream_removed (GvcMixerControl *control, guint id, GvcMixerDialog *dialog) { remove_stream (dialog, id); } static void add_card (GvcMixerDialog *dialog, GvcMixerCard *card) { GtkTreeModel *model; GtkTreeIter iter; GtkTreeSelection *selection; GvcMixerCardProfile *profile; GIcon *icon; guint index; model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->hw_treeview)); index = gvc_mixer_card_get_index (card); if (find_item_by_id (GTK_TREE_MODEL (model), index, HW_ID_COLUMN, &iter) == FALSE) gtk_list_store_append (GTK_LIST_STORE (model), &iter); profile = gvc_mixer_card_get_profile (card); g_assert (profile != NULL); icon = g_themed_icon_new_with_default_fallbacks (gvc_mixer_card_get_icon_name (card)); //FIXME we need the status (default for a profile?) here gtk_list_store_set (GTK_LIST_STORE (model), &iter, HW_NAME_COLUMN, gvc_mixer_card_get_name (card), HW_ID_COLUMN, index, HW_ICON_COLUMN, icon, HW_PROFILE_COLUMN, profile->profile, HW_PROFILE_HUMAN_COLUMN, profile->human_profile, HW_STATUS_COLUMN, profile->status, HW_SENSITIVE_COLUMN, g_strcmp0 (profile->profile, "off") != 0, -1); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->hw_treeview)); if (gtk_tree_selection_get_selected (selection, NULL, NULL) == FALSE) { gtk_tree_selection_select_iter (selection, &iter); } else if (dialog->priv->hw_profile_combo != NULL) { GvcMixerCard *selected; /* Set the current profile if it changed for the selected card */ selected = g_object_get_data (G_OBJECT (dialog->priv->hw_profile_combo), "card"); if (gvc_mixer_card_get_index (selected) == gvc_mixer_card_get_index (card)) { gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->hw_profile_combo), profile->profile); g_object_set (G_OBJECT (dialog->priv->hw_profile_combo), "show-button", profile->n_sinks == 1, NULL); } } } static void on_control_card_added (GvcMixerControl *control, guint id, GvcMixerDialog *dialog) { GvcMixerCard *card; card = gvc_mixer_control_lookup_card_id (control, id); if (card != NULL) { add_card (dialog, card); } } static void remove_card (GvcMixerDialog *dialog, guint id) { gboolean found; GtkTreeIter iter; GtkTreeModel *model; /* remove from any models */ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->hw_treeview)); found = find_item_by_id (GTK_TREE_MODEL (model), id, HW_ID_COLUMN, &iter); if (found) { gtk_list_store_remove (GTK_LIST_STORE (model), &iter); } } static void on_control_card_removed (GvcMixerControl *control, guint id, GvcMixerDialog *dialog) { remove_card (dialog, id); } static void _gtk_label_make_bold (GtkLabel *label) { PangoFontDescription *font_desc; font_desc = pango_font_description_new (); pango_font_description_set_weight (font_desc, PANGO_WEIGHT_BOLD); /* This will only affect the weight of the font, the rest is * from the current state of the widget, which comes from the * theme or user prefs, since the font desc only has the * weight flag turned on. */ gtk_widget_override_font (GTK_WIDGET (label), font_desc); pango_font_description_free (font_desc); } static void on_input_radio_toggled (GtkCellRendererToggle *renderer, char *path_str, GvcMixerDialog *dialog) { GtkTreeModel *model; GtkTreeIter iter; GtkTreePath *path; gboolean toggled; guint id; model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview)); path = gtk_tree_path_new_from_string (path_str); gtk_tree_model_get_iter (model, &iter, path); gtk_tree_path_free (path); gtk_tree_model_get (model, &iter, ID_COLUMN, &id, ACTIVE_COLUMN, &toggled, -1); toggled ^= 1; if (toggled) { GvcMixerStream *stream; g_debug ("Default input selected: %u", id); stream = gvc_mixer_control_lookup_stream_id (dialog->priv->mixer_control, id); if (stream == NULL) { g_warning ("Unable to find stream for id: %u", id); return; } gvc_mixer_control_set_default_source (dialog->priv->mixer_control, stream); } } static void on_output_radio_toggled (GtkCellRendererToggle *renderer, char *path_str, GvcMixerDialog *dialog) { GtkTreeModel *model; GtkTreeIter iter; GtkTreePath *path; gboolean toggled; guint id; model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview)); path = gtk_tree_path_new_from_string (path_str); gtk_tree_model_get_iter (model, &iter, path); gtk_tree_path_free (path); gtk_tree_model_get (model, &iter, ID_COLUMN, &id, ACTIVE_COLUMN, &toggled, -1); toggled ^= 1; if (toggled) { GvcMixerStream *stream; g_debug ("Default output selected: %u", id); stream = gvc_mixer_control_lookup_stream_id (dialog->priv->mixer_control, id); if (stream == NULL) { g_warning ("Unable to find stream for id: %u", id); return; } gvc_mixer_control_set_default_sink (dialog->priv->mixer_control, stream); } } static void name_to_text (GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) { char *name, *mapping; int len; gtk_tree_model_get(model, iter, NAME_COLUMN, &name, SPEAKERS_COLUMN, &mapping, -1); len = strlen(name); if(len>75) { //g_printf("---------len----%d\n",len); GString *string = g_string_new(name); g_string_insert(string,75,"\n"); if (mapping == NULL) { g_object_set (cell, "text", string->str, NULL); } else { char *str; str = g_strdup_printf ("%s\n%s", string->str, mapping); g_object_set (cell, "markup", str, NULL); g_free (str); } g_string_free(string,FALSE); } else { if (mapping == NULL) { g_object_set (cell, "text", name, NULL); } else { char *str; str = g_strdup_printf ("%s\n%s", name, mapping); g_object_set (cell, "markup", str, NULL); g_free (str); } } g_free (name); g_free (mapping); } static GtkWidget * create_stream_treeview (GvcMixerDialog *dialog, GCallback on_toggled) { GtkWidget *treeview; GtkListStore *store; GtkCellRenderer *renderer; GtkTreeViewColumn *column; treeview = gtk_tree_view_new (); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE); store = gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_UINT, G_TYPE_STRING); gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store)); renderer = gtk_cell_renderer_toggle_new (); gtk_cell_renderer_toggle_set_radio (GTK_CELL_RENDERER_TOGGLE (renderer), TRUE); column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "active", ACTIVE_COLUMN, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); g_signal_connect (renderer, "toggled", G_CALLBACK (on_toggled), dialog); gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview), -1, "名称", gtk_cell_renderer_text_new (), name_to_text, NULL, NULL); #if 0 renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes (_("Device"), renderer, "text", DEVICE_COLUMN, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); #endif return treeview; } static void on_profile_changed (GvcComboBox *widget, const char *profile, gpointer user_data) { GvcMixerCard *card; card = g_object_get_data (G_OBJECT (widget), "card"); if (card == NULL) { g_warning ("Could not find card for combobox"); return; } g_debug ("Profile changed to %s for card %s", profile, gvc_mixer_card_get_name (card)); gvc_mixer_card_change_profile (card, profile); } static void on_test_speakers_clicked (GvcComboBox *widget, gpointer user_data) { GvcMixerDialog *dialog = GVC_MIXER_DIALOG (user_data); GvcMixerCard *card; GvcMixerCardProfile *profile; GtkWidget *d, *speaker_test, *container; char *title; card = g_object_get_data (G_OBJECT (widget), "card"); if (card == NULL) { g_warning ("Could not find card for combobox"); return; } profile = gvc_mixer_card_get_profile (card); g_debug ("XXX Start speaker testing for profile '%s', card %s XXX", profile->profile, gvc_mixer_card_get_name (card)); title = g_strdup_printf (_("Speaker Testing for %s"), gvc_mixer_card_get_name (card)); d = gtk_dialog_new_with_buttons (title, GTK_WINDOW (dialog), GTK_DIALOG_MODAL | #if !GTK_CHECK_VERSION (2, 21, 8) GTK_DIALOG_NO_SEPARATOR | #endif GTK_DIALOG_DESTROY_WITH_PARENT, NULL); gtk_window_set_icon_from_file (GTK_WINDOW(d), "/usr/share/ukui-control-center/icons/声音.png", NULL); g_free (title); speaker_test = gvc_speaker_test_new (dialog->priv->mixer_control, card); gtk_widget_show (speaker_test); container = gtk_dialog_get_content_area (GTK_DIALOG (d)); gtk_container_add (GTK_CONTAINER (container), speaker_test); gtk_widget_set_name(GTK_WIDGET(d), "ukuicc"); gtk_dialog_run (GTK_DIALOG (d)); gtk_widget_destroy (d); } static void on_card_selection_changed (GtkTreeSelection *selection, gpointer user_data) { GvcMixerDialog *dialog = GVC_MIXER_DIALOG (user_data); GtkTreeModel *model; GtkTreeIter iter; const GList *profiles; guint id; GvcMixerCard *card; GvcMixerCardProfile *current_profile; g_debug ("Card selection changed"); if (dialog->priv->hw_profile_combo != NULL) { gtk_container_remove (GTK_CONTAINER (dialog->priv->hw_settings_box), dialog->priv->hw_profile_combo); dialog->priv->hw_profile_combo = NULL; } if (gtk_tree_selection_get_selected (selection, NULL, &iter) == FALSE) { return; } model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->hw_treeview)); gtk_tree_model_get (model, &iter, HW_ID_COLUMN, &id, -1); card = gvc_mixer_control_lookup_card_id (dialog->priv->mixer_control, id); if (card == NULL) { g_warning ("Unable to find card for id: %u", id); return; } current_profile = gvc_mixer_card_get_profile (card); profiles = gvc_mixer_card_get_profiles (card); dialog->priv->hw_profile_combo = gvc_combo_box_new (_("_Profiles:")); g_object_set (G_OBJECT (dialog->priv->hw_profile_combo), "button-label", _("Test Speakers"), NULL); gvc_combo_box_set_profiles (GVC_COMBO_BOX (dialog->priv->hw_profile_combo), profiles); gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->hw_profile_combo), current_profile->profile); gtk_box_pack_start (GTK_BOX (dialog->priv->hw_settings_box), dialog->priv->hw_profile_combo, TRUE, TRUE, 6); g_object_set (G_OBJECT (dialog->priv->hw_profile_combo), "show-button", current_profile->n_sinks == 1, NULL); gtk_widget_show (dialog->priv->hw_profile_combo); g_object_set_data (G_OBJECT (dialog->priv->hw_profile_combo), "card", card); g_signal_connect (G_OBJECT (dialog->priv->hw_profile_combo), "changed", G_CALLBACK (on_profile_changed), dialog); g_signal_connect (G_OBJECT (dialog->priv->hw_profile_combo), "button-clicked", G_CALLBACK (on_test_speakers_clicked), dialog); } static void card_to_text (GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) { char *name, *status, *profile, *str; gboolean sensitive; gtk_tree_model_get(model, iter, HW_NAME_COLUMN, &name, HW_STATUS_COLUMN, &status, HW_PROFILE_HUMAN_COLUMN, &profile, HW_SENSITIVE_COLUMN, &sensitive, -1); int len = strlen(name); if(len>75) { GString *string = g_string_new(name); g_string_insert(string,75,"\n"); str = g_strdup_printf ("%s\n%s\n%s", string->str, status, profile); g_string_free(string,FALSE); } else { str = g_strdup_printf ("%s\n%s\n%s", name, status, profile); } g_object_set (cell, "markup", str, "sensitive", sensitive, NULL); g_free (str); g_free (name); g_free (status); g_free (profile); } static GtkWidget * create_cards_treeview (GvcMixerDialog *dialog, GCallback on_changed) { GtkWidget *treeview; GtkListStore *store; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *selection; treeview = gtk_tree_view_new (); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); g_signal_connect (G_OBJECT (selection), "changed", on_changed, dialog); store = gtk_list_store_new (HW_NUM_COLUMNS, G_TYPE_UINT, G_TYPE_ICON, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store)); renderer = gtk_cell_renderer_pixbuf_new (); g_object_set (G_OBJECT (renderer), "stock-size", GTK_ICON_SIZE_DIALOG, NULL); column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "gicon", HW_ICON_COLUMN, "sensitive", HW_SENSITIVE_COLUMN, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview), -1, _("Name"), gtk_cell_renderer_text_new (), card_to_text, NULL, NULL); return treeview; } static const guint tab_accel_keys[] = { GDK_1, GDK_2, GDK_3, GDK_4, GDK_5 }; static void dialog_accel_cb (GtkAccelGroup *accelgroup, GObject *object, guint key, GdkModifierType mod, GvcMixerDialog *self) { gint num = -1; gint i; for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++) { if (tab_accel_keys[i] == key) { num = i; break; } } if (num != -1) { gtk_notebook_set_current_page (GTK_NOTEBOOK (self->priv->notebook), num); } } static GObject * gvc_mixer_dialog_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; GvcMixerDialog *self; // GtkWidget *main_vbox; GtkWidget *label; GtkWidget *alignment; GtkWidget *box; // GtkWidget *box1; // GtkWidget *box2; GtkWidget *sbox; GtkWidget *ebox; GSList *streams; GSList *cards; GSList *l; GvcMixerStream *stream; GvcMixerCard *card; GtkTreeSelection *selection; GtkAccelGroup *accel_group; GClosure *closure; gint i; GtkWidget *layout; object = G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->constructor (type, n_construct_properties, construct_params); self = GVC_MIXER_DIALOG (object); //gtk_dialog_add_button (GTK_DIALOG (self), "gtk-close", GTK_RESPONSE_OK); //main_vbox = gtk_dialog_get_content_area (GTK_DIALOG (self)); //gtk_box_set_spacing (GTK_BOX (main_vbox), 2); //gtk_container_set_border_width (GTK_CONTAINER (self), 6); //self->priv->output_stream_box = gtk_hbox_new (FALSE, 12); //alignment = gtk_alignment_new (0, 0, 1, 1); //gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 12, 0, 0, 0); //gtk_container_add (GTK_CONTAINER (alignment), self->priv->output_stream_box); //gtk_box_pack_start (GTK_BOX (main_vbox), // alignment, // FALSE, FALSE, 0); //self->priv->output_bar = create_bar (self, self->priv->size_group, TRUE); //gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->output_bar), // _("Sound Output Volume")); //gtk_widget_set_sensitive (self->priv->output_bar, FALSE); //gtk_box_pack_start (GTK_BOX (self->priv->output_stream_box), // self->priv->output_bar, TRUE, TRUE, 12); layout = gtk_dialog_get_content_area (GTK_DIALOG (self)); self->priv->notebook = gtk_notebook_new (); gtk_container_add(GTK_CONTAINER(layout), self->priv->notebook); //gtk_box_pack_start (GTK_BOX (main_vbox), // self->priv->notebook, // TRUE, TRUE, 0); //gtk_container_set_border_width (GTK_CONTAINER (self->priv->notebook), 5); /* Set up accels (borrowed from Empathy) */ accel_group = gtk_accel_group_new (); gtk_window_add_accel_group (GTK_WINDOW (self), accel_group); for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++) { closure = g_cclosure_new (G_CALLBACK (dialog_accel_cb), self, NULL); gtk_accel_group_connect (accel_group, tab_accel_keys[i], GDK_MOD1_MASK, 0, closure); } g_object_unref (accel_group); /* Applications */ self->priv->applications_main_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 15); gtk_widget_set_size_request(self->priv->applications_main_box, -1, 500); gtk_container_set_border_width(GTK_CONTAINER(self->priv->applications_main_box),10); self->priv->output_stream_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); alignment = gtk_alignment_new (0, 0, 0.5, 1); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 12, 0, 0, 0); gtk_container_add (GTK_CONTAINER (alignment), self->priv->output_stream_box); gtk_box_pack_start (GTK_BOX (self->priv->applications_main_box), alignment, FALSE, FALSE, 0); self->priv->output_bar = create_bar (self, self->priv->size_group, TRUE); gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->output_bar), _("Sound Output Volume")); gtk_widget_set_sensitive (self->priv->output_bar, FALSE); gtk_box_pack_start (GTK_BOX (self->priv->output_stream_box), self->priv->output_bar, TRUE, TRUE, 10); /* GtkWidget *applications_label = gtk_label_new(""); GtkWidget *viewport_separator = gtk_viewport_new(NULL, NULL); gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport_separator), GTK_SHADOW_NONE); gtk_container_add(GTK_CONTAINER(viewport_separator), applications_label); gtk_box_pack_start(GTK_BOX(self->priv->applications_main_box), viewport_separator, FALSE, FALSE, 0); */ self->priv->applications_scrolled_window = gtk_scrolled_window_new (NULL, NULL); alignment = gtk_alignment_new (0, 0, 0.7, 1); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 12, 0, 0, 0); gtk_container_add (GTK_CONTAINER (alignment), self->priv->applications_scrolled_window); gtk_box_pack_start(GTK_BOX(self->priv->applications_main_box), alignment, TRUE, TRUE, 0); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self->priv->applications_scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (self->priv->applications_scrolled_window), GTK_SHADOW_IN); self->priv->applications_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); gtk_container_set_border_width (GTK_CONTAINER (self->priv->applications_box), 12); gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (self->priv->applications_scrolled_window), self->priv->applications_box); label = gtk_label_new (_("Applications")); gtk_widget_set_size_request(GTK_WIDGET(label), 100, 30); gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook), self->priv->applications_main_box, label); self->priv->no_apps_label = gtk_label_new (_("No application is currently playing or recording audio.")); gtk_box_pack_start (GTK_BOX (self->priv->applications_box), self->priv->no_apps_label, TRUE, TRUE, 0); /* Effects page */ self->priv->sound_effects_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_container_set_border_width (GTK_CONTAINER (self->priv->sound_effects_box), 12); label = gtk_label_new (_("Sound Effects")); gtk_widget_set_size_request(GTK_WIDGET(label), 100, 30); gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook), self->priv->sound_effects_box, label); self->priv->effects_bar = create_bar (self, self->priv->size_group, TRUE); gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->effects_bar), _("_Alert volume: ")); gtk_widget_set_sensitive (self->priv->effects_bar, FALSE); alignment = gtk_alignment_new (0, 0, 0.5, 1); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 0, 0); gtk_container_add (GTK_CONTAINER (alignment), self->priv->effects_bar); gtk_box_pack_start (GTK_BOX (self->priv->sound_effects_box), alignment, FALSE, FALSE, 0); self->priv->sound_theme_chooser = gvc_sound_theme_chooser_new (); alignment = gtk_alignment_new (0, 0, 0.8, 1); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 12, 0, 0, 0); gtk_container_add (GTK_CONTAINER (alignment), self->priv->sound_theme_chooser); gtk_box_pack_start (GTK_BOX (self->priv->sound_effects_box), alignment, TRUE, TRUE, 0); /* Input page */ self->priv->input_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); gtk_container_set_border_width (GTK_CONTAINER (self->priv->input_box), 12); label = gtk_label_new (_("Input")); gtk_widget_set_size_request(GTK_WIDGET(label), 100, 30); gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook), self->priv->input_box, label); self->priv->input_bar = create_bar (self, self->priv->size_group, TRUE); gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->input_bar), _("_Input volume: ")); gvc_channel_bar_set_low_icon_name (GVC_CHANNEL_BAR (self->priv->input_bar), "audio-input-microphone-low"); gvc_channel_bar_set_high_icon_name (GVC_CHANNEL_BAR (self->priv->input_bar), "audio-input-microphone-high"); gtk_widget_set_sensitive (self->priv->input_bar, FALSE); alignment = gtk_alignment_new (0.06, 0, 0.5, 1); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 9, 0, 0, 0); gtk_container_add (GTK_CONTAINER (alignment), self->priv->input_bar); gtk_box_pack_start (GTK_BOX (self->priv->input_box), alignment, FALSE, FALSE, 0); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_box_pack_start (GTK_BOX (self->priv->input_box), box, FALSE, FALSE, 6); sbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0); label = gtk_label_new (_("Input level:")); gtk_box_pack_start (GTK_BOX (sbox), label, FALSE, FALSE, 0); gtk_size_group_add_widget (self->priv->size_group, sbox); self->priv->input_level_bar = gvc_level_bar_new (); gvc_level_bar_set_orientation (GVC_LEVEL_BAR (self->priv->input_level_bar), GTK_ORIENTATION_HORIZONTAL); gvc_level_bar_set_scale (GVC_LEVEL_BAR (self->priv->input_level_bar), GVC_LEVEL_SCALE_LINEAR); alignment = gtk_alignment_new (0, 0, 0.7, 1); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 0, 0); gtk_container_add (GTK_CONTAINER (alignment), self->priv->input_level_bar); gtk_box_pack_start (GTK_BOX (box), alignment, TRUE, TRUE, 6); ebox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, FALSE, 0); gtk_size_group_add_widget (self->priv->size_group, ebox); self->priv->input_settings_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_box_pack_start (GTK_BOX (self->priv->input_box), self->priv->input_settings_box, FALSE, FALSE, 0); box = gtk_frame_new (_("C_hoose a device for sound input:")); label = gtk_frame_get_label_widget (GTK_FRAME (box)); _gtk_label_make_bold (GTK_LABEL (label)); gtk_label_set_use_underline (GTK_LABEL (label), TRUE); gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE); gtk_box_pack_start (GTK_BOX (self->priv->input_box), box, TRUE, TRUE, 0); alignment = gtk_alignment_new (0.06, 0, 0.7, 1); gtk_container_add (GTK_CONTAINER (box), alignment); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0); self->priv->input_treeview = create_stream_treeview (self, G_CALLBACK (on_input_radio_toggled)); gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->priv->input_treeview); box = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (box), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (box), GTK_SHADOW_IN); gtk_container_add (GTK_CONTAINER (box), self->priv->input_treeview); gtk_container_add (GTK_CONTAINER (alignment), box); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->input_treeview)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); /* Output page */ self->priv->output_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); gtk_container_set_border_width (GTK_CONTAINER (self->priv->output_box), 12); label = gtk_label_new (_("Output")); gtk_widget_set_size_request(GTK_WIDGET(label), 100, 30); gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook), self->priv->output_box, label); box = gtk_frame_new (_("C_hoose a device for sound output:")); label = gtk_frame_get_label_widget (GTK_FRAME (box)); _gtk_label_make_bold (GTK_LABEL (label)); gtk_label_set_use_underline (GTK_LABEL (label), TRUE); gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE); gtk_box_pack_start (GTK_BOX (self->priv->output_box), box, TRUE, TRUE, 0); alignment = gtk_alignment_new (0, 0, 0.7, 1); gtk_container_add (GTK_CONTAINER (box), alignment); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0); self->priv->output_treeview = create_stream_treeview (self, G_CALLBACK (on_output_radio_toggled)); gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->priv->output_treeview); box = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (box), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (box), GTK_SHADOW_IN); gtk_container_add (GTK_CONTAINER (box), self->priv->output_treeview); gtk_container_add (GTK_CONTAINER (alignment), box); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->output_treeview)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); box = gtk_frame_new (_("Settings for the selected device:")); label = gtk_frame_get_label_widget (GTK_FRAME (box)); _gtk_label_make_bold (GTK_LABEL (label)); gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE); gtk_box_pack_start (GTK_BOX (self->priv->output_box), box, FALSE, FALSE, 12); self->priv->output_settings_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_add (GTK_CONTAINER (box), self->priv->output_settings_box); /* Hardware page */ self->priv->hw_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); gtk_container_set_border_width (GTK_CONTAINER (self->priv->hw_box), 20); label = gtk_label_new (_("Hardware")); gtk_widget_set_size_request(GTK_WIDGET(label), 100, 30); gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook), self->priv->hw_box, label); box = gtk_frame_new (_("C_hoose a device to configure:")); label = gtk_frame_get_label_widget (GTK_FRAME (box)); _gtk_label_make_bold (GTK_LABEL (label)); gtk_label_set_use_underline (GTK_LABEL (label), TRUE); gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE); gtk_box_pack_start (GTK_BOX (self->priv->hw_box), box, TRUE, TRUE, 0); alignment = gtk_alignment_new (0, 0, 0.7, 1); gtk_container_add (GTK_CONTAINER (box), alignment); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0); self->priv->hw_treeview = create_cards_treeview (self, G_CALLBACK (on_card_selection_changed)); gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->priv->hw_treeview); box = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (box), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (box), GTK_SHADOW_IN); gtk_container_add (GTK_CONTAINER (box), self->priv->hw_treeview); gtk_container_add (GTK_CONTAINER (alignment), box); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->hw_treeview)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); box = gtk_frame_new (_("Settings for the selected device:")); label = gtk_frame_get_label_widget (GTK_FRAME (box)); _gtk_label_make_bold (GTK_LABEL (label)); gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE); gtk_box_pack_start (GTK_BOX (self->priv->hw_box), box, FALSE, TRUE, 12); self->priv->hw_settings_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); alignment = gtk_alignment_new (0, 0, 0.7, 1); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0); gtk_container_add (GTK_CONTAINER (alignment), self->priv->hw_settings_box); gtk_container_add (GTK_CONTAINER (box), alignment); g_signal_connect (self->priv->mixer_control, "stream-added", G_CALLBACK (on_control_stream_added), self); g_signal_connect (self->priv->mixer_control, "stream-removed", G_CALLBACK (on_control_stream_removed), self); g_signal_connect (self->priv->mixer_control, "card-added", G_CALLBACK (on_control_card_added), self); g_signal_connect (self->priv->mixer_control, "card-removed", G_CALLBACK (on_control_card_removed), self); gtk_widget_show_all(layout); gtk_widget_reparent(layout, GTK_WIDGET(gtk_builder_get_object(main_builder, "volume_control_viewport"))); //gtk_widget_show_all (main_vbox); //gtk_widget_reparent (main_vbox, GTK_WIDGET(gtk_builder_get_object(main_builder, "volume_control_viewport"))); streams = gvc_mixer_control_get_streams (self->priv->mixer_control); for (l = streams; l != NULL; l = l->next) { stream = l->data; add_stream (self, stream); } g_slist_free (streams); cards = gvc_mixer_control_get_cards (self->priv->mixer_control); for (l = cards; l != NULL; l = l->next) { card = l->data; add_card (self, card); } g_slist_free (cards); return object; } static void gvc_mixer_dialog_dispose (GObject *object) { GvcMixerDialog *dialog = GVC_MIXER_DIALOG (object); if (dialog->priv->mixer_control != NULL) { g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control, on_control_stream_added, dialog); g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control, on_control_stream_removed, dialog); g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control, on_control_card_added, dialog); g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control, on_control_card_removed, dialog); g_object_unref (dialog->priv->mixer_control); dialog->priv->mixer_control = NULL; } if (dialog->priv->bars != NULL) { g_hash_table_destroy (dialog->priv->bars); dialog->priv->bars = NULL; } G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->dispose (object); } static void gvc_mixer_dialog_class_init (GvcMixerDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = gvc_mixer_dialog_constructor; object_class->dispose = gvc_mixer_dialog_dispose; object_class->finalize = gvc_mixer_dialog_finalize; object_class->set_property = gvc_mixer_dialog_set_property; object_class->get_property = gvc_mixer_dialog_get_property; g_object_class_install_property (object_class, PROP_MIXER_CONTROL, g_param_spec_object ("mixer-control", "mixer control", "mixer control", GVC_TYPE_MIXER_CONTROL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_type_class_add_private (klass, sizeof (GvcMixerDialogPrivate)); } static void gvc_mixer_dialog_init (GvcMixerDialog *dialog) { dialog->priv = GVC_MIXER_DIALOG_GET_PRIVATE (dialog); dialog->priv->bars = g_hash_table_new (NULL, NULL); dialog->priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); dialog->priv->apps_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); } static void gvc_mixer_dialog_finalize (GObject *object) { GvcMixerDialog *mixer_dialog; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_DIALOG (object)); mixer_dialog = GVC_MIXER_DIALOG (object); g_return_if_fail (mixer_dialog->priv != NULL); G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->finalize (object); } GvcMixerDialog * gvc_mixer_dialog_new (GvcMixerControl *control, GtkBuilder * top_builder) { GObject *dialog; main_builder = top_builder; dialog = g_object_new (GVC_TYPE_MIXER_DIALOG, "icon-name", "multimedia-volume-control", "title", _("Sound Preferences"), #if !GTK_CHECK_VERSION (3, 0, 0) "has-separator", FALSE, #endif "mixer-control", control, NULL); return GVC_MIXER_DIALOG (dialog); } enum { PAGE_EVENTS, PAGE_HARDWARE, PAGE_INPUT, PAGE_OUTPUT, PAGE_APPLICATIONS }; gboolean gvc_mixer_dialog_set_page (GvcMixerDialog *self, const char *page) { guint num; g_return_val_if_fail (self != NULL, FALSE); if (page == NULL) num = 0; else if (g_str_equal (page, "effects")) num = PAGE_EVENTS; else if (g_str_equal (page, "hardware")) num = PAGE_HARDWARE; else if (g_str_equal (page, "input")) num = PAGE_INPUT; else if (g_str_equal (page, "output")) num = PAGE_OUTPUT; else if (g_str_equal (page, "applications")) num = PAGE_APPLICATIONS; else num = 0; gtk_notebook_set_current_page (GTK_NOTEBOOK (self->priv->notebook), num); return TRUE; } ukui-control-center/panels/volume-control/gvc-mixer-event-role.c0000664000175000017500000001742313057175444024024 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include "gvc-mixer-event-role.h" #define GVC_MIXER_EVENT_ROLE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRolePrivate)) struct GvcMixerEventRolePrivate { char *device; }; enum { PROP_0, PROP_DEVICE }; static void gvc_mixer_event_role_class_init (GvcMixerEventRoleClass *klass); static void gvc_mixer_event_role_init (GvcMixerEventRole *mixer_event_role); static void gvc_mixer_event_role_finalize (GObject *object); G_DEFINE_TYPE (GvcMixerEventRole, gvc_mixer_event_role, GVC_TYPE_MIXER_STREAM) static gboolean update_settings (GvcMixerEventRole *role, gboolean is_muted, gpointer *op) { pa_operation *o; guint index; const GvcChannelMap *map; pa_context *context; pa_ext_stream_restore_info info; index = gvc_mixer_stream_get_index (GVC_MIXER_STREAM (role)); map = gvc_mixer_stream_get_channel_map (GVC_MIXER_STREAM(role)); info.volume = *gvc_channel_map_get_cvolume(map); info.name = "sink-input-by-media-role:event"; info.channel_map = *gvc_channel_map_get_pa_channel_map(map); info.device = role->priv->device; info.mute = is_muted; context = gvc_mixer_stream_get_pa_context (GVC_MIXER_STREAM (role)); o = pa_ext_stream_restore_write (context, PA_UPDATE_REPLACE, &info, 1, TRUE, NULL, NULL); if (o == NULL) { g_warning ("pa_ext_stream_restore_write() failed"); return FALSE; } if (op != NULL) *op = o; return TRUE; } static gboolean gvc_mixer_event_role_push_volume (GvcMixerStream *stream, gpointer *op) { return update_settings (GVC_MIXER_EVENT_ROLE (stream), gvc_mixer_stream_get_is_muted (stream), op); } static gboolean gvc_mixer_event_role_change_is_muted (GvcMixerStream *stream, gboolean is_muted) { return update_settings (GVC_MIXER_EVENT_ROLE (stream), is_muted, NULL); } static gboolean gvc_mixer_event_role_set_device (GvcMixerEventRole *role, const char *device) { g_return_val_if_fail (GVC_IS_MIXER_EVENT_ROLE (role), FALSE); g_free (role->priv->device); role->priv->device = g_strdup (device); g_object_notify (G_OBJECT (role), "device"); return TRUE; } static void gvc_mixer_event_role_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GvcMixerEventRole *self = GVC_MIXER_EVENT_ROLE (object); switch (prop_id) { case PROP_DEVICE: gvc_mixer_event_role_set_device (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gvc_mixer_event_role_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GvcMixerEventRole *self = GVC_MIXER_EVENT_ROLE (object); switch (prop_id) { case PROP_DEVICE: g_value_set_string (value, self->priv->device); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GObject * gvc_mixer_event_role_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; GvcMixerEventRole *self; object = G_OBJECT_CLASS (gvc_mixer_event_role_parent_class)->constructor (type, n_construct_properties, construct_params); self = GVC_MIXER_EVENT_ROLE (object); return object; } static void gvc_mixer_event_role_class_init (GvcMixerEventRoleClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass); object_class->constructor = gvc_mixer_event_role_constructor; object_class->finalize = gvc_mixer_event_role_finalize; object_class->set_property = gvc_mixer_event_role_set_property; object_class->get_property = gvc_mixer_event_role_get_property; stream_class->push_volume = gvc_mixer_event_role_push_volume; stream_class->change_is_muted = gvc_mixer_event_role_change_is_muted; g_object_class_install_property (object_class, PROP_DEVICE, g_param_spec_string ("device", "Device", "Device", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_type_class_add_private (klass, sizeof (GvcMixerEventRolePrivate)); } static void gvc_mixer_event_role_init (GvcMixerEventRole *event_role) { event_role->priv = GVC_MIXER_EVENT_ROLE_GET_PRIVATE (event_role); } static void gvc_mixer_event_role_finalize (GObject *object) { GvcMixerEventRole *mixer_event_role; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_EVENT_ROLE (object)); mixer_event_role = GVC_MIXER_EVENT_ROLE (object); g_return_if_fail (mixer_event_role->priv != NULL); g_free (mixer_event_role->priv->device); G_OBJECT_CLASS (gvc_mixer_event_role_parent_class)->finalize (object); } GvcMixerStream * gvc_mixer_event_role_new (pa_context *context, const char *device, GvcChannelMap *channel_map) { GObject *object; object = g_object_new (GVC_TYPE_MIXER_EVENT_ROLE, "pa-context", context, "index", 0, "device", device, "channel-map", channel_map, NULL); return GVC_MIXER_STREAM (object); } ukui-control-center/panels/volume-control/gvc-channel-bar.c0000664000175000017500000011230613253611037022757 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include "gvc-channel-bar.h" #define SCALE_SIZE 256 #define ADJUSTMENT_MAX_NORMAL 65536.0 /* PA_VOLUME_NORM */ #define ADJUSTMENT_MAX_AMPLIFIED 98304.0 /* 1.5 * ADJUSTMENT_MAX_NORMAL */ #define ADJUSTMENT_MAX (bar->priv->is_amplified ? ADJUSTMENT_MAX_AMPLIFIED : ADJUSTMENT_MAX_NORMAL) #define SCROLLSTEP (ADJUSTMENT_MAX / 100.0 * 5.0) #define GVC_CHANNEL_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_CHANNEL_BAR, GvcChannelBarPrivate)) struct GvcChannelBarPrivate { GtkOrientation orientation; GtkWidget *scale_box; GtkWidget *start_box; GtkWidget *end_box; GtkWidget *image; GtkWidget *label; GtkWidget *low_image; GtkWidget *scale; GtkWidget *high_image; GtkWidget *mute_box; GtkWidget *mute_button; GtkAdjustment *adjustment; GtkAdjustment *zero_adjustment; gboolean show_mute; gboolean is_muted; char *name; char *icon_name; char *low_icon_name; char *high_icon_name; GtkSizeGroup *size_group; gboolean symmetric; gboolean click_lock; gboolean is_amplified; guint32 base_volume; }; enum { PROP_0, PROP_ORIENTATION, PROP_SHOW_MUTE, PROP_IS_MUTED, PROP_ADJUSTMENT, PROP_NAME, PROP_ICON_NAME, PROP_LOW_ICON_NAME, PROP_HIGH_ICON_NAME, PROP_IS_AMPLIFIED, }; static void gvc_channel_bar_class_init (GvcChannelBarClass *klass); static void gvc_channel_bar_init (GvcChannelBar *channel_bar); static void gvc_channel_bar_finalize (GObject *object); static gboolean on_scale_button_press_event (GtkWidget *widget, GdkEventButton *event, GvcChannelBar *bar); static gboolean on_scale_button_release_event (GtkWidget *widget, GdkEventButton *event, GvcChannelBar *bar); static gboolean on_scale_scroll_event (GtkWidget *widget, GdkEventScroll *event, GvcChannelBar *bar); #if GTK_CHECK_VERSION (3, 0, 0) G_DEFINE_TYPE (GvcChannelBar, gvc_channel_bar, GTK_TYPE_BOX) #else G_DEFINE_TYPE (GvcChannelBar, gvc_channel_bar, GTK_TYPE_HBOX) #endif static GtkWidget * _scale_box_new (GvcChannelBar *bar) { GvcChannelBarPrivate *priv = bar->priv; GtkWidget *box; GtkWidget *sbox; GtkWidget *ebox; if (priv->orientation == GTK_ORIENTATION_VERTICAL) { bar->priv->scale_box = box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); priv->scale = gtk_scale_new (GTK_ORIENTATION_VERTICAL, priv->adjustment); gtk_widget_set_size_request (priv->scale, -1, SCALE_SIZE); gtk_range_set_inverted (GTK_RANGE (priv->scale), TRUE); bar->priv->start_box = sbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (sbox), priv->image, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (sbox), priv->label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (sbox), priv->high_image, FALSE, FALSE, 0); gtk_widget_hide (priv->high_image); gtk_box_pack_start (GTK_BOX (box), priv->scale, TRUE, TRUE, 0); bar->priv->end_box = ebox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (ebox), priv->low_image, FALSE, FALSE, 0); gtk_widget_hide (priv->low_image); gtk_box_pack_start (GTK_BOX (ebox), priv->mute_box, FALSE, FALSE, 0); } else { bar->priv->scale_box = box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); priv->scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, priv->adjustment); gtk_widget_set_size_request (priv->scale, SCALE_SIZE, -1); bar->priv->start_box = sbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0); gtk_box_pack_end (GTK_BOX (sbox), priv->low_image, FALSE, FALSE, 0); gtk_widget_show (priv->low_image); gtk_box_pack_start (GTK_BOX (sbox), priv->image, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (sbox), priv->label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (box), priv->scale, TRUE, TRUE, 0); bar->priv->end_box = ebox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (ebox), priv->high_image, FALSE, FALSE, 0); gtk_widget_show (priv->high_image); gtk_box_pack_start (GTK_BOX (ebox), priv->mute_box, FALSE, FALSE, 0); } #if !GTK_CHECK_VERSION (3, 0, 0) gtk_range_set_update_policy (GTK_RANGE (priv->scale), GTK_UPDATE_CONTINUOUS); #endif ca_gtk_widget_disable_sounds (bar->priv->scale, FALSE); gtk_widget_add_events (bar->priv->scale, GDK_SCROLL_MASK); g_signal_connect (G_OBJECT (bar->priv->scale), "button-press-event", G_CALLBACK (on_scale_button_press_event), bar); g_signal_connect (G_OBJECT (bar->priv->scale), "button-release-event", G_CALLBACK (on_scale_button_release_event), bar); g_signal_connect (G_OBJECT (bar->priv->scale), "scroll-event", G_CALLBACK (on_scale_scroll_event), bar); if (bar->priv->size_group != NULL) { gtk_size_group_add_widget (bar->priv->size_group, sbox); if (bar->priv->symmetric) { gtk_size_group_add_widget (bar->priv->size_group, ebox); } } gtk_scale_set_draw_value (GTK_SCALE (priv->scale), FALSE); return box; } static void update_image (GvcChannelBar *bar) { gtk_image_set_from_icon_name (GTK_IMAGE (bar->priv->image), bar->priv->icon_name, GTK_ICON_SIZE_DIALOG); if (bar->priv->icon_name != NULL) { gtk_widget_show (bar->priv->image); } else { gtk_widget_hide (bar->priv->image); } } static void update_label (GvcChannelBar *bar) { if (bar->priv->name != NULL) { gtk_label_set_text_with_mnemonic (GTK_LABEL (bar->priv->label), bar->priv->name); gtk_label_set_mnemonic_widget (GTK_LABEL (bar->priv->label), bar->priv->scale); gtk_widget_show (bar->priv->label); } else { gtk_label_set_text (GTK_LABEL (bar->priv->label), NULL); gtk_widget_hide (bar->priv->label); } } static void update_layout (GvcChannelBar *bar) { GtkWidget *box; GtkWidget *frame; if (bar->priv->scale == NULL) { return; } box = bar->priv->scale_box; frame = gtk_widget_get_parent (box); g_object_ref (bar->priv->image); g_object_ref (bar->priv->label); g_object_ref (bar->priv->mute_box); g_object_ref (bar->priv->low_image); g_object_ref (bar->priv->high_image); gtk_container_remove (GTK_CONTAINER (bar->priv->start_box), bar->priv->image); gtk_container_remove (GTK_CONTAINER (bar->priv->start_box), bar->priv->label); gtk_container_remove (GTK_CONTAINER (bar->priv->end_box), bar->priv->mute_box); if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) { gtk_container_remove (GTK_CONTAINER (bar->priv->start_box), bar->priv->low_image); gtk_container_remove (GTK_CONTAINER (bar->priv->end_box), bar->priv->high_image); } else { gtk_container_remove (GTK_CONTAINER (bar->priv->end_box), bar->priv->low_image); gtk_container_remove (GTK_CONTAINER (bar->priv->start_box), bar->priv->high_image); } gtk_container_remove (GTK_CONTAINER (box), bar->priv->start_box); gtk_container_remove (GTK_CONTAINER (box), bar->priv->scale); gtk_container_remove (GTK_CONTAINER (box), bar->priv->end_box); gtk_container_remove (GTK_CONTAINER (frame), box); bar->priv->scale_box = _scale_box_new (bar); gtk_container_add (GTK_CONTAINER (frame), bar->priv->scale_box); g_object_unref (bar->priv->image); g_object_unref (bar->priv->label); g_object_unref (bar->priv->mute_box); g_object_unref (bar->priv->low_image); g_object_unref (bar->priv->high_image); gtk_widget_show_all (frame); } void gvc_channel_bar_set_size_group (GvcChannelBar *bar, GtkSizeGroup *group, gboolean symmetric) { g_return_if_fail (GVC_IS_CHANNEL_BAR (bar)); bar->priv->size_group = group; bar->priv->symmetric = symmetric; if (bar->priv->size_group != NULL) { gtk_size_group_add_widget (bar->priv->size_group, bar->priv->start_box); if (bar->priv->symmetric) { gtk_size_group_add_widget (bar->priv->size_group, bar->priv->end_box); } } gtk_widget_queue_draw (GTK_WIDGET (bar)); } void gvc_channel_bar_set_name (GvcChannelBar *bar, const char *name) { g_return_if_fail (GVC_IS_CHANNEL_BAR (bar)); g_free (bar->priv->name); bar->priv->name = g_strdup (name); update_label (bar); g_object_notify (G_OBJECT (bar), "name"); } void gvc_channel_bar_set_icon_name (GvcChannelBar *bar, const char *name) { g_return_if_fail (GVC_IS_CHANNEL_BAR (bar)); g_free (bar->priv->icon_name); bar->priv->icon_name = g_strdup (name); update_image (bar); g_object_notify (G_OBJECT (bar), "icon-name"); } void gvc_channel_bar_set_low_icon_name (GvcChannelBar *bar, const char *name) { g_return_if_fail (GVC_IS_CHANNEL_BAR (bar)); if (name != NULL && strcmp (bar->priv->low_icon_name, name) != 0) { g_free (bar->priv->low_icon_name); bar->priv->low_icon_name = g_strdup (name); gtk_image_set_from_icon_name (GTK_IMAGE (bar->priv->low_image), bar->priv->low_icon_name, GTK_ICON_SIZE_BUTTON); g_object_notify (G_OBJECT (bar), "low-icon-name"); } } void gvc_channel_bar_set_high_icon_name (GvcChannelBar *bar, const char *name) { g_return_if_fail (GVC_IS_CHANNEL_BAR (bar)); if (name != NULL && strcmp (bar->priv->high_icon_name, name) != 0) { g_free (bar->priv->high_icon_name); bar->priv->high_icon_name = g_strdup (name); gtk_image_set_from_icon_name (GTK_IMAGE (bar->priv->high_image), bar->priv->high_icon_name, GTK_ICON_SIZE_BUTTON); g_object_notify (G_OBJECT (bar), "high-icon-name"); } } void gvc_channel_bar_set_orientation (GvcChannelBar *bar, GtkOrientation orientation) { g_return_if_fail (GVC_IS_CHANNEL_BAR (bar)); if (orientation != bar->priv->orientation) { bar->priv->orientation = orientation; update_layout (bar); g_object_notify (G_OBJECT (bar), "orientation"); } } static void gvc_channel_bar_set_adjustment (GvcChannelBar *bar, GtkAdjustment *adjustment) { g_return_if_fail (GVC_CHANNEL_BAR (bar)); g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); if (bar->priv->adjustment != NULL) { g_object_unref (bar->priv->adjustment); } bar->priv->adjustment = g_object_ref_sink (adjustment); if (bar->priv->scale != NULL) { gtk_range_set_adjustment (GTK_RANGE (bar->priv->scale), adjustment); } g_object_notify (G_OBJECT (bar), "adjustment"); } GtkAdjustment * gvc_channel_bar_get_adjustment (GvcChannelBar *bar) { g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), NULL); return bar->priv->adjustment; } static gboolean on_scale_button_press_event (GtkWidget *widget, GdkEventButton *event, GvcChannelBar *bar) { /* HACK: we want the behaviour you get with the middle button, so we * mangle the event. clicking with other buttons moves the slider in * step increments, clicking with the middle button moves the slider to * the location of the click. */ // if (event->button == 1) // event->button = 2; bar->priv->click_lock = TRUE; return FALSE; } static gboolean on_scale_button_release_event (GtkWidget *widget, GdkEventButton *event, GvcChannelBar *bar) { GtkAdjustment *adj; gdouble value; /* HACK: see on_scale_button_press_event() */ // if (event->button == 1) // event->button = 2; bar->priv->click_lock = FALSE; adj = gtk_range_get_adjustment (GTK_RANGE (widget)); value = gtk_adjustment_get_value (adj); /* this means the adjustment moved away from zero and * therefore we should unmute and set the volume. */ gvc_channel_bar_set_is_muted (bar, (value == 0.0)); /* Play a sound! */ ca_gtk_play_for_widget (GTK_WIDGET (bar), 0, CA_PROP_EVENT_ID, "audio-volume-change", CA_PROP_EVENT_DESCRIPTION, "foobar event happened", CA_PROP_APPLICATION_ID, "org.ukui.VolumeControl", NULL); return FALSE; } gboolean gvc_channel_bar_scroll (GvcChannelBar *bar, GdkScrollDirection direction) { GtkAdjustment *adj; gdouble value; g_return_val_if_fail (bar != NULL, FALSE); g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE); if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) { if (direction != GDK_SCROLL_UP && direction != GDK_SCROLL_DOWN) return FALSE; } else { /* Switch direction for RTL */ if (gtk_widget_get_direction (GTK_WIDGET (bar)) == GTK_TEXT_DIR_RTL) { if (direction == GDK_SCROLL_RIGHT) direction = GDK_SCROLL_LEFT; else if (direction == GDK_SCROLL_LEFT) direction = GDK_SCROLL_RIGHT; } /* Switch side scroll to vertical */ if (direction == GDK_SCROLL_RIGHT) direction = GDK_SCROLL_UP; else if (direction == GDK_SCROLL_LEFT) direction = GDK_SCROLL_DOWN; } adj = gtk_range_get_adjustment (GTK_RANGE (bar->priv->scale)); if (adj == bar->priv->zero_adjustment) { if (direction == GDK_SCROLL_UP) gvc_channel_bar_set_is_muted (bar, FALSE); return TRUE; } value = gtk_adjustment_get_value (adj); if (direction == GDK_SCROLL_UP) { if (value + SCROLLSTEP > ADJUSTMENT_MAX) value = ADJUSTMENT_MAX; else value = value + SCROLLSTEP; } else if (direction == GDK_SCROLL_DOWN) { if (value - SCROLLSTEP < 0) value = 0.0; else value = value - SCROLLSTEP; } gvc_channel_bar_set_is_muted (bar, (value == 0.0)); adj = gtk_range_get_adjustment (GTK_RANGE (bar->priv->scale)); gtk_adjustment_set_value (adj, value); return TRUE; } static gboolean on_scale_scroll_event (GtkWidget *widget, GdkEventScroll *event, GvcChannelBar *bar) { return gvc_channel_bar_scroll (bar, event->direction); } static void on_zero_adjustment_value_changed (GtkAdjustment *adjustment, GvcChannelBar *bar) { gdouble value; if (bar->priv->click_lock != FALSE) { return; } value = gtk_adjustment_get_value (bar->priv->zero_adjustment); gtk_adjustment_set_value (bar->priv->adjustment, value); if (bar->priv->show_mute == FALSE) { /* this means the adjustment moved away from zero and * therefore we should unmute and set the volume. */ gvc_channel_bar_set_is_muted (bar, value > 0.0); } } static void update_mute_button (GvcChannelBar *bar) { if (bar->priv->show_mute) { gtk_widget_show (bar->priv->mute_button); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bar->priv->mute_button), bar->priv->is_muted); } else { // gtk_widget_hide (bar->priv->mute_button); if (bar->priv->is_muted) { /* If we aren't showing the mute button then * move slider to the zero. But we don't want to * change the adjustment. */ g_signal_handlers_block_by_func (bar->priv->zero_adjustment, on_zero_adjustment_value_changed, bar); gtk_adjustment_set_value (bar->priv->zero_adjustment, 0); g_signal_handlers_unblock_by_func (bar->priv->zero_adjustment, on_zero_adjustment_value_changed, bar); gtk_range_set_adjustment (GTK_RANGE (bar->priv->scale), bar->priv->zero_adjustment); } else { /* no longer muted so restore the original adjustment * and tell the front-end that the value changed */ gtk_range_set_adjustment (GTK_RANGE (bar->priv->scale), bar->priv->adjustment); gtk_adjustment_value_changed (bar->priv->adjustment); } } } void gvc_channel_bar_set_is_muted (GvcChannelBar *bar, gboolean is_muted) { g_return_if_fail (GVC_IS_CHANNEL_BAR (bar)); if (is_muted != bar->priv->is_muted) { /* Update our internal state before telling the * front-end about our changes */ bar->priv->is_muted = is_muted; update_mute_button (bar); g_object_notify (G_OBJECT (bar), "is-muted"); } } gboolean gvc_channel_bar_get_is_muted (GvcChannelBar *bar) { g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE); return bar->priv->is_muted; } void gvc_channel_bar_set_show_mute (GvcChannelBar *bar, gboolean show_mute) { g_return_if_fail (GVC_IS_CHANNEL_BAR (bar)); if (show_mute != bar->priv->show_mute) { bar->priv->show_mute = show_mute; g_object_notify (G_OBJECT (bar), "show-mute"); update_mute_button (bar); } } gboolean gvc_channel_bar_get_show_mute (GvcChannelBar *bar) { g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE); return bar->priv->show_mute; } void gvc_channel_bar_set_is_amplified (GvcChannelBar *bar, gboolean amplified) { g_return_if_fail (GVC_IS_CHANNEL_BAR (bar)); bar->priv->is_amplified = amplified; gtk_adjustment_set_upper (bar->priv->adjustment, ADJUSTMENT_MAX); gtk_adjustment_set_upper (bar->priv->zero_adjustment, ADJUSTMENT_MAX); gtk_scale_clear_marks (GTK_SCALE (bar->priv->scale)); if (amplified) { char *str; if (bar->priv->base_volume == ADJUSTMENT_MAX_NORMAL) { str = g_strdup_printf ("%s", "100%"); gtk_scale_add_mark (GTK_SCALE (bar->priv->scale), ADJUSTMENT_MAX_NORMAL, GTK_POS_BOTTOM, str); } else { str = g_strdup_printf ("%s", _("Unamplified")); gtk_scale_add_mark (GTK_SCALE (bar->priv->scale), bar->priv->base_volume, GTK_POS_BOTTOM, str); /* Only show 100% if it's higher than the base volume */ if (bar->priv->base_volume < ADJUSTMENT_MAX_NORMAL) { str = g_strdup_printf ("%s", "100%"); gtk_scale_add_mark (GTK_SCALE (bar->priv->scale), ADJUSTMENT_MAX_NORMAL, GTK_POS_BOTTOM, str); } } g_free (str); gtk_alignment_set (GTK_ALIGNMENT (bar->priv->mute_box), 0.5, 0, 0, 0); gtk_misc_set_alignment (GTK_MISC (bar->priv->low_image), 0.5, 0); gtk_misc_set_alignment (GTK_MISC (bar->priv->high_image), 0.5, 0); gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0, 0); } else { gtk_alignment_set (GTK_ALIGNMENT (bar->priv->mute_box), 0.5, 0.5, 0, 0); gtk_misc_set_alignment (GTK_MISC (bar->priv->low_image), 0.5, 0.5); gtk_misc_set_alignment (GTK_MISC (bar->priv->high_image), 0.5, 0.5); gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0, 0.5); } } void gvc_channel_bar_set_base_volume (GvcChannelBar *bar, pa_volume_t base_volume) { g_return_if_fail (GVC_IS_CHANNEL_BAR (bar)); if (base_volume == 0) { bar->priv->base_volume = ADJUSTMENT_MAX_NORMAL; return; } /* Note that you need to call _is_amplified() afterwards to update the marks */ bar->priv->base_volume = base_volume; } static void gvc_channel_bar_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GvcChannelBar *self = GVC_CHANNEL_BAR (object); switch (prop_id) { case PROP_ORIENTATION: gvc_channel_bar_set_orientation (self, g_value_get_enum (value)); break; case PROP_IS_MUTED: gvc_channel_bar_set_is_muted (self, g_value_get_boolean (value)); break; case PROP_SHOW_MUTE: gvc_channel_bar_set_show_mute (self, g_value_get_boolean (value)); break; case PROP_NAME: gvc_channel_bar_set_name (self, g_value_get_string (value)); break; case PROP_ICON_NAME: gvc_channel_bar_set_icon_name (self, g_value_get_string (value)); break; case PROP_LOW_ICON_NAME: gvc_channel_bar_set_low_icon_name (self, g_value_get_string (value)); break; case PROP_HIGH_ICON_NAME: gvc_channel_bar_set_high_icon_name (self, g_value_get_string (value)); break; case PROP_ADJUSTMENT: gvc_channel_bar_set_adjustment (self, g_value_get_object (value)); break; case PROP_IS_AMPLIFIED: gvc_channel_bar_set_is_amplified (self, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gvc_channel_bar_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GvcChannelBar *self = GVC_CHANNEL_BAR (object); GvcChannelBarPrivate *priv = self->priv; switch (prop_id) { case PROP_ORIENTATION: g_value_set_enum (value, priv->orientation); break; case PROP_IS_MUTED: g_value_set_boolean (value, priv->is_muted); break; case PROP_SHOW_MUTE: g_value_set_boolean (value, priv->show_mute); break; case PROP_NAME: g_value_set_string (value, priv->name); break; case PROP_ICON_NAME: g_value_set_string (value, priv->icon_name); break; case PROP_LOW_ICON_NAME: g_value_set_string (value, priv->low_icon_name); break; case PROP_HIGH_ICON_NAME: g_value_set_string (value, priv->high_icon_name); break; case PROP_ADJUSTMENT: g_value_set_object (value, gvc_channel_bar_get_adjustment (self)); break; case PROP_IS_AMPLIFIED: g_value_set_boolean (value, priv->is_amplified); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GObject * gvc_channel_bar_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; GvcChannelBar *self; object = G_OBJECT_CLASS (gvc_channel_bar_parent_class)->constructor (type, n_construct_properties, construct_params); self = GVC_CHANNEL_BAR (object); update_mute_button (self); return object; } static void gvc_channel_bar_class_init (GvcChannelBarClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = gvc_channel_bar_constructor; object_class->finalize = gvc_channel_bar_finalize; object_class->set_property = gvc_channel_bar_set_property; object_class->get_property = gvc_channel_bar_get_property; g_object_class_install_property (object_class, PROP_ORIENTATION, g_param_spec_enum ("orientation", "Orientation", "The orientation of the scale", GTK_TYPE_ORIENTATION, GTK_ORIENTATION_VERTICAL, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_IS_MUTED, g_param_spec_boolean ("is-muted", "is muted", "Whether stream is muted", FALSE, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_SHOW_MUTE, g_param_spec_boolean ("show-mute", "show mute", "Whether stream is muted", FALSE, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_ADJUSTMENT, g_param_spec_object ("adjustment", "Adjustment", "The GtkAdjustment that contains the current value of this scale button object", GTK_TYPE_ADJUSTMENT, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_NAME, g_param_spec_string ("name", "Name", "Name to display for this stream", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_ICON_NAME, g_param_spec_string ("icon-name", "Icon Name", "Name of icon to display for this stream", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_LOW_ICON_NAME, g_param_spec_string ("low-icon-name", "Icon Name", "Name of icon to display for this stream", "audio-volume-low", G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_HIGH_ICON_NAME, g_param_spec_string ("high-icon-name", "Icon Name", "Name of icon to display for this stream", "audio-volume-high", G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_IS_AMPLIFIED, g_param_spec_boolean ("is-amplified", "is amplified", "Whether the stream is digitally amplified", FALSE, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_type_class_add_private (klass, sizeof (GvcChannelBarPrivate)); } static void on_mute_button_toggled (GtkToggleButton *button, GvcChannelBar *bar) { gboolean is_muted; is_muted = gtk_toggle_button_get_active (button); gvc_channel_bar_set_is_muted (bar, is_muted); } static void gvc_channel_bar_init (GvcChannelBar *bar) { GtkWidget *frame; bar->priv = GVC_CHANNEL_BAR_GET_PRIVATE (bar); bar->priv->base_volume = ADJUSTMENT_MAX_NORMAL; bar->priv->low_icon_name = g_strdup ("audio-volume-low"); bar->priv->high_icon_name = g_strdup ("audio-volume-high"); bar->priv->orientation = GTK_ORIENTATION_VERTICAL; bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, ADJUSTMENT_MAX_NORMAL, ADJUSTMENT_MAX_NORMAL/100.0, ADJUSTMENT_MAX_NORMAL/10.0, 0.0)); g_object_ref_sink (bar->priv->adjustment); bar->priv->zero_adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, ADJUSTMENT_MAX_NORMAL, ADJUSTMENT_MAX_NORMAL/100.0, ADJUSTMENT_MAX_NORMAL/10.0, 0.0)); g_object_ref_sink (bar->priv->zero_adjustment); g_signal_connect (bar->priv->zero_adjustment, "value-changed", G_CALLBACK (on_zero_adjustment_value_changed), bar); bar->priv->mute_button = gtk_check_button_new_with_label (_("Mute")); gtk_widget_set_no_show_all (bar->priv->mute_button, TRUE); g_signal_connect (bar->priv->mute_button, "toggled", G_CALLBACK (on_mute_button_toggled), bar); bar->priv->mute_box = gtk_alignment_new (0.5, 0.5, 0, 0); gtk_container_add (GTK_CONTAINER (bar->priv->mute_box), bar->priv->mute_button); bar->priv->low_image = gtk_image_new_from_icon_name ("audio-volume-low", GTK_ICON_SIZE_BUTTON); gtk_widget_set_no_show_all (bar->priv->low_image, TRUE); bar->priv->high_image = gtk_image_new_from_icon_name ("audio-volume-high", GTK_ICON_SIZE_BUTTON); gtk_widget_set_no_show_all (bar->priv->high_image, TRUE); bar->priv->image = gtk_image_new (); gtk_widget_set_no_show_all (bar->priv->image, TRUE); bar->priv->label = gtk_label_new (NULL); gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0.0, 0.5); gtk_widget_set_no_show_all (bar->priv->label, TRUE); /* frame */ frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE); gtk_container_add (GTK_CONTAINER (bar), frame); gtk_widget_show_all (frame); /* box with scale */ bar->priv->scale_box = _scale_box_new (bar); gtk_container_add (GTK_CONTAINER (frame), bar->priv->scale_box); } static void gvc_channel_bar_finalize (GObject *object) { GvcChannelBar *channel_bar; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_CHANNEL_BAR (object)); channel_bar = GVC_CHANNEL_BAR (object); g_return_if_fail (channel_bar->priv != NULL); g_free (channel_bar->priv->name); g_free (channel_bar->priv->icon_name); g_free (channel_bar->priv->low_icon_name); g_free (channel_bar->priv->high_icon_name); G_OBJECT_CLASS (gvc_channel_bar_parent_class)->finalize (object); } GtkWidget * gvc_channel_bar_new (void) { GObject *bar; bar = g_object_new (GVC_TYPE_CHANNEL_BAR, NULL); return GTK_WIDGET (bar); } ukui-control-center/panels/volume-control/gvc-log.c0000664000175000017500000000343413057175444021400 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2009 Red Hat, Inc. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include "gvc-log.h" static int log_levels = G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_DEBUG; static void gvc_log_default_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer unused_data) { if ((log_level & log_levels) == 0) return; g_log_default_handler (log_domain, log_level, message, unused_data); } void gvc_log_init (void) { g_log_set_default_handler (gvc_log_default_handler, NULL); } void gvc_log_set_debug (gboolean debug) { if (debug) { log_levels |= G_LOG_LEVEL_DEBUG; g_debug ("Enabling debugging"); } else { log_levels &= ~G_LOG_LEVEL_DEBUG; } } ukui-control-center/panels/volume-control/gvc-mixer-source.h0000664000175000017500000000417413057175444023250 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __GVC_MIXER_SOURCE_H #define __GVC_MIXER_SOURCE_H #include #include "gvc-mixer-stream.h" G_BEGIN_DECLS #define GVC_TYPE_MIXER_SOURCE (gvc_mixer_source_get_type ()) #define GVC_MIXER_SOURCE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SOURCE, GvcMixerSource)) #define GVC_MIXER_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SOURCE, GvcMixerSourceClass)) #define GVC_IS_MIXER_SOURCE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SOURCE)) #define GVC_IS_MIXER_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SOURCE)) #define GVC_MIXER_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SOURCE, GvcMixerSourceClass)) typedef struct GvcMixerSourcePrivate GvcMixerSourcePrivate; typedef struct { GvcMixerStream parent; GvcMixerSourcePrivate *priv; } GvcMixerSource; typedef struct { GvcMixerStreamClass parent_class; } GvcMixerSourceClass; GType gvc_mixer_source_get_type (void); GvcMixerStream * gvc_mixer_source_new (pa_context *context, guint index, GvcChannelMap *map); G_END_DECLS #endif /* __GVC_MIXER_SOURCE_H */ ukui-control-center/panels/volume-control/Makefile.am0000664000175000017500000000315113253611037021715 0ustar fengfengcappletname = volumecontrol noinst_LTLIBRARIES = libvolume.la SUBDIRS = \ icons \ $(NULL) libvolume_la_SOURCES = \ dialog-main.c \ dialog-main.h \ gvc-balance-bar.c \ gvc-balance-bar.h \ gvc-channel-bar.c \ gvc-channel-bar.h \ gvc-channel-map.c \ gvc-channel-map.h \ gvc-combo-box.c \ gvc-combo-box.h \ gvc-level-bar.c \ gvc-level-bar.h \ gvc-log.c \ gvc-log.h \ gvc-mixer-card.c \ gvc-mixer-card.h \ gvc-mixer-control.c \ gvc-mixer-control.h \ gvc-mixer-dialog.c \ gvc-mixer-dialog.h \ gvc-mixer-event-role.c \ gvc-mixer-event-role.h \ gvc-mixer-sink.c \ gvc-mixer-sink.h \ gvc-mixer-sink-input.c \ gvc-mixer-sink-input.h \ gvc-mixer-source.c \ gvc-mixer-source.h \ gvc-mixer-source-output.c \ gvc-mixer-source-output.h \ gvc-mixer-stream.c \ gvc-mixer-stream.h \ gvc-sound-theme-chooser.c \ gvc-sound-theme-chooser.h \ gvc-speaker-test.c \ gvc-speaker-test.h \ sound-theme-file-utils.c \ sound-theme-file-utils.h \ $(NULL) AUTOMAKE_OPTIONS = foreign #INCLUDES = `pkg-config --cflags gtk+-2.0 glib-2.0 unique-1.0 libcanberra-gtk libpulse gdk-2.0 gio-2.0 libxml-2.0 libpulse-mainloop-glib` #LIBS = `pkg-config --libs gtk+-2.0 glib-2.0 unique-1.0 libcanberra-gtk libpulse gdk-2.0 gio-2.0 libxml-2.0 libpulse-mainloop-glib` AM_CPPFLAGS = \ -DSOUND_SET_DIR="\"/usr/share/ukui-media/sounds\"" \ $(GTK_CFLAGS) \ $(GLIB_CFLAGS) \ $(CANBERRA_CFLAGS) \ $(PULSE_CFLAGS) \ $(GDK_CFLAGS) \ $(LIBXML_CFLAGS) \ $(NULL) libvolume_la_LIBADD = \ $(GTK_LIBS) \ $(GLIB_LIBS) \ $(CANBERRA_LIBS) \ $(PULSE_LIBS) \ $(GDK_LIBS) \ $(LIBXML_LIBS) \ $(NULL) clean-local : rm -f *~ Makefile.in Makefile ukui-control-center/panels/volume-control/gvc-channel-map.c0000664000175000017500000001641513057175444023005 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include "gvc-channel-map.h" #define GVC_CHANNEL_MAP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_CHANNEL_MAP, GvcChannelMapPrivate)) struct GvcChannelMapPrivate { pa_channel_map pa_map; gboolean pa_volume_is_set; pa_cvolume pa_volume; gdouble extern_volume[NUM_TYPES]; /* volume, balance, fade, lfe */ gboolean can_balance; gboolean can_fade; }; enum { VOLUME_CHANGED, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0, }; static void gvc_channel_map_class_init (GvcChannelMapClass *klass); static void gvc_channel_map_init (GvcChannelMap *channel_map); static void gvc_channel_map_finalize (GObject *object); G_DEFINE_TYPE (GvcChannelMap, gvc_channel_map, G_TYPE_OBJECT) guint gvc_channel_map_get_num_channels (const GvcChannelMap *map) { g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), 0); if (!pa_channel_map_valid(&map->priv->pa_map)) return 0; return map->priv->pa_map.channels; } const gdouble * gvc_channel_map_get_volume (GvcChannelMap *map) { g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL); if (!pa_channel_map_valid(&map->priv->pa_map)) return NULL; map->priv->extern_volume[VOLUME] = (gdouble) pa_cvolume_max (&map->priv->pa_volume); if (gvc_channel_map_can_balance (map)) map->priv->extern_volume[BALANCE] = (gdouble) pa_cvolume_get_balance (&map->priv->pa_volume, &map->priv->pa_map); else map->priv->extern_volume[BALANCE] = 0; if (gvc_channel_map_can_fade (map)) map->priv->extern_volume[FADE] = (gdouble) pa_cvolume_get_fade (&map->priv->pa_volume, &map->priv->pa_map); else map->priv->extern_volume[FADE] = 0; if (gvc_channel_map_has_lfe (map)) map->priv->extern_volume[LFE] = (gdouble) pa_cvolume_get_position (&map->priv->pa_volume, &map->priv->pa_map, PA_CHANNEL_POSITION_LFE); else map->priv->extern_volume[LFE] = 0; return map->priv->extern_volume; } gboolean gvc_channel_map_can_balance (const GvcChannelMap *map) { g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE); return map->priv->can_balance; } gboolean gvc_channel_map_can_fade (const GvcChannelMap *map) { g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE); return map->priv->can_fade; } const char * gvc_channel_map_get_mapping (const GvcChannelMap *map) { g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL); if (!pa_channel_map_valid(&map->priv->pa_map)) return NULL; return pa_channel_map_to_pretty_name (&map->priv->pa_map); } gboolean gvc_channel_map_has_position (const GvcChannelMap *map, pa_channel_position_t position) { g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE); return pa_channel_map_has_position (&(map->priv->pa_map), position); } const pa_channel_map * gvc_channel_map_get_pa_channel_map (const GvcChannelMap *map) { g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL); if (!pa_channel_map_valid(&map->priv->pa_map)) return NULL; return &map->priv->pa_map; } const pa_cvolume * gvc_channel_map_get_cvolume (const GvcChannelMap *map) { g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL); if (!pa_channel_map_valid(&map->priv->pa_map)) return NULL; return &map->priv->pa_volume; } static void gvc_channel_map_class_init (GvcChannelMapClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = gvc_channel_map_finalize; signals [VOLUME_CHANGED] = g_signal_new ("volume-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcChannelMapClass, volume_changed), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); g_type_class_add_private (klass, sizeof (GvcChannelMapPrivate)); } void gvc_channel_map_volume_changed (GvcChannelMap *map, const pa_cvolume *cv, gboolean set) { g_return_if_fail (GVC_IS_CHANNEL_MAP (map)); g_return_if_fail (cv != NULL); g_return_if_fail (pa_cvolume_compatible_with_channel_map(cv, &map->priv->pa_map)); if (pa_cvolume_equal(cv, &map->priv->pa_volume)) return; map->priv->pa_volume = *cv; if (map->priv->pa_volume_is_set == FALSE) { map->priv->pa_volume_is_set = TRUE; return; } g_signal_emit (map, signals[VOLUME_CHANGED], 0, set); } static void gvc_channel_map_init (GvcChannelMap *map) { map->priv = GVC_CHANNEL_MAP_GET_PRIVATE (map); map->priv->pa_volume_is_set = FALSE; } static void gvc_channel_map_finalize (GObject *object) { GvcChannelMap *channel_map; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_CHANNEL_MAP (object)); channel_map = GVC_CHANNEL_MAP (object); g_return_if_fail (channel_map->priv != NULL); G_OBJECT_CLASS (gvc_channel_map_parent_class)->finalize (object); } GvcChannelMap * gvc_channel_map_new (void) { GObject *map; map = g_object_new (GVC_TYPE_CHANNEL_MAP, NULL); return GVC_CHANNEL_MAP (map); } static void set_from_pa_map (GvcChannelMap *map, const pa_channel_map *pa_map) { g_assert (pa_channel_map_valid(pa_map)); map->priv->can_balance = pa_channel_map_can_balance (pa_map); map->priv->can_fade = pa_channel_map_can_fade (pa_map); map->priv->pa_map = *pa_map; pa_cvolume_set(&map->priv->pa_volume, pa_map->channels, PA_VOLUME_NORM); } GvcChannelMap * gvc_channel_map_new_from_pa_channel_map (const pa_channel_map *pa_map) { GObject *map; map = g_object_new (GVC_TYPE_CHANNEL_MAP, NULL); set_from_pa_map (GVC_CHANNEL_MAP (map), pa_map); return GVC_CHANNEL_MAP (map); } ukui-control-center/panels/volume-control/gvc-mixer-control.c0000664000175000017500000022060113253611051023401 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2006-2008 Lennart Poettering * Copyright (C) 2008 Sjoerd Simons * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include "gvc-mixer-control.h" #include "gvc-mixer-sink.h" #include "gvc-mixer-source.h" #include "gvc-mixer-sink-input.h" #include "gvc-mixer-source-output.h" #include "gvc-mixer-event-role.h" #include "gvc-mixer-card.h" #define GVC_MIXER_CONTROL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_CONTROL, GvcMixerControlPrivate)) #define RECONNECT_DELAY 5 enum { PROP_0, PROP_NAME }; struct GvcMixerControlPrivate { pa_glib_mainloop *pa_mainloop; pa_mainloop_api *pa_api; pa_context *pa_context; int n_outstanding; guint reconnect_id; char *name; GtkBuilder * builder; gboolean default_sink_is_set; guint default_sink_id; char *default_sink_name; gboolean default_source_is_set; guint default_source_id; char *default_source_name; gboolean event_sink_input_is_set; guint event_sink_input_id; GHashTable *all_streams; GHashTable *sinks; /* fixed outputs */ GHashTable *sources; /* fixed inputs */ GHashTable *sink_inputs; /* routable output streams */ GHashTable *source_outputs; /* routable input streams */ GHashTable *clients; GHashTable *cards; GvcMixerStream *new_default_stream; /* new default stream, used in gvc_mixer_control_set_default_sink () */ }; enum { CONNECTING, READY, STREAM_ADDED, STREAM_REMOVED, CARD_ADDED, CARD_REMOVED, DEFAULT_SINK_CHANGED, DEFAULT_SOURCE_CHANGED, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0, }; static void gvc_mixer_control_class_init (GvcMixerControlClass *klass); static void gvc_mixer_control_init (GvcMixerControl *mixer_control); static void gvc_mixer_control_finalize (GObject *object); G_DEFINE_TYPE (GvcMixerControl, gvc_mixer_control, G_TYPE_OBJECT) pa_context * gvc_mixer_control_get_pa_context (GvcMixerControl *control) { g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); return control->priv->pa_context; } GvcMixerStream * gvc_mixer_control_get_event_sink_input (GvcMixerControl *control) { GvcMixerStream *stream; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); stream = g_hash_table_lookup (control->priv->all_streams, GUINT_TO_POINTER (control->priv->event_sink_input_id)); return stream; } static void gvc_mixer_control_stream_restore_cb (pa_context *c, const pa_ext_stream_restore_info *info, int eol, void *userdata) { pa_operation *o; GvcMixerControl *control = (GvcMixerControl *) userdata; pa_ext_stream_restore_info new_info; if (eol || control->priv->new_default_stream == NULL) return; new_info.name = info->name; new_info.channel_map = info->channel_map; new_info.volume = info->volume; new_info.mute = info->mute; new_info.device = gvc_mixer_stream_get_name (control->priv->new_default_stream); o = pa_ext_stream_restore_write (control->priv->pa_context, PA_UPDATE_REPLACE, &new_info, 1, TRUE, NULL, NULL); if (o == NULL) { g_warning ("pa_ext_stream_restore_write() failed: %s", pa_strerror (pa_context_errno (control->priv->pa_context))); return; } g_debug ("Changed default device for %s to %s", info->name, info->device); pa_operation_unref (o); } gboolean gvc_mixer_control_set_default_sink (GvcMixerControl *control, GvcMixerStream *stream) { pa_operation *o; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); o = pa_context_set_default_sink (control->priv->pa_context, gvc_mixer_stream_get_name (stream), NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_default_sink() failed: %s", pa_strerror (pa_context_errno (control->priv->pa_context))); return FALSE; } pa_operation_unref (o); control->priv->new_default_stream = stream; g_object_add_weak_pointer (G_OBJECT (stream), (gpointer *) &control->priv->new_default_stream); o = pa_ext_stream_restore_read (control->priv->pa_context, gvc_mixer_control_stream_restore_cb, control); if (o == NULL) { g_warning ("pa_ext_stream_restore_read() failed: %s", pa_strerror (pa_context_errno (control->priv->pa_context))); return FALSE; } pa_operation_unref (o); return TRUE; } gboolean gvc_mixer_control_set_default_source (GvcMixerControl *control, GvcMixerStream *stream) { pa_operation *o; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); o = pa_context_set_default_source (control->priv->pa_context, gvc_mixer_stream_get_name (stream), NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_default_source() failed"); return FALSE; } pa_operation_unref (o); return TRUE; } GvcMixerStream * gvc_mixer_control_get_default_sink (GvcMixerControl *control) { GvcMixerStream *stream; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); if (control->priv->default_sink_is_set) { stream = g_hash_table_lookup (control->priv->all_streams, GUINT_TO_POINTER (control->priv->default_sink_id)); } else { stream = NULL; } return stream; } GvcMixerStream * gvc_mixer_control_get_default_source (GvcMixerControl *control) { GvcMixerStream *stream; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); if (control->priv->default_source_is_set) { stream = g_hash_table_lookup (control->priv->all_streams, GUINT_TO_POINTER (control->priv->default_source_id)); } else { stream = NULL; } return stream; } static gpointer gvc_mixer_control_lookup_id (GHashTable *hash_table, guint id) { return g_hash_table_lookup (hash_table, GUINT_TO_POINTER (id)); } GvcMixerStream * gvc_mixer_control_lookup_stream_id (GvcMixerControl *control, guint id) { g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); return gvc_mixer_control_lookup_id (control->priv->all_streams, id); } GvcMixerCard * gvc_mixer_control_lookup_card_id (GvcMixerControl *control, guint id) { g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); return gvc_mixer_control_lookup_id (control->priv->cards, id); } static void listify_hash_values_hfunc (gpointer key, gpointer value, gpointer user_data) { GSList **list = user_data; *list = g_slist_prepend (*list, value); } static int gvc_name_collate (const char *namea, const char *nameb) { if (nameb == NULL && namea == NULL) return 0; if (nameb == NULL) return 1; if (namea == NULL) return -1; return g_utf8_collate (namea, nameb); } static int gvc_card_collate (GvcMixerCard *a, GvcMixerCard *b) { const char *namea; const char *nameb; g_return_val_if_fail (a == NULL || GVC_IS_MIXER_CARD (a), 0); g_return_val_if_fail (b == NULL || GVC_IS_MIXER_CARD (b), 0); namea = gvc_mixer_card_get_name (a); nameb = gvc_mixer_card_get_name (b); return gvc_name_collate (namea, nameb); } GSList * gvc_mixer_control_get_cards (GvcMixerControl *control) { GSList *retval; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); retval = NULL; g_hash_table_foreach (control->priv->cards, listify_hash_values_hfunc, &retval); return g_slist_sort (retval, (GCompareFunc) gvc_card_collate); } static int gvc_stream_collate (GvcMixerStream *a, GvcMixerStream *b) { const char *namea; const char *nameb; g_return_val_if_fail (a == NULL || GVC_IS_MIXER_STREAM (a), 0); g_return_val_if_fail (b == NULL || GVC_IS_MIXER_STREAM (b), 0); namea = gvc_mixer_stream_get_name (a); nameb = gvc_mixer_stream_get_name (b); return gvc_name_collate (namea, nameb); } GSList * gvc_mixer_control_get_streams (GvcMixerControl *control) { GSList *retval; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); retval = NULL; g_hash_table_foreach (control->priv->all_streams, listify_hash_values_hfunc, &retval); return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); } GSList * gvc_mixer_control_get_sinks (GvcMixerControl *control) { GSList *retval; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); retval = NULL; g_hash_table_foreach (control->priv->sinks, listify_hash_values_hfunc, &retval); return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); } GSList * gvc_mixer_control_get_sources (GvcMixerControl *control) { GSList *retval; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); retval = NULL; g_hash_table_foreach (control->priv->sources, listify_hash_values_hfunc, &retval); return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); } GSList * gvc_mixer_control_get_sink_inputs (GvcMixerControl *control) { GSList *retval; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); retval = NULL; g_hash_table_foreach (control->priv->sink_inputs, listify_hash_values_hfunc, &retval); return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); } GSList * gvc_mixer_control_get_source_outputs (GvcMixerControl *control) { GSList *retval; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); retval = NULL; g_hash_table_foreach (control->priv->source_outputs, listify_hash_values_hfunc, &retval); return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); } static void dec_outstanding (GvcMixerControl *control) { if (control->priv->n_outstanding <= 0) { return; } if (--control->priv->n_outstanding <= 0) { g_signal_emit (G_OBJECT (control), signals[READY], 0); } } gboolean gvc_mixer_control_is_ready (GvcMixerControl *control) { g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); return (control->priv->n_outstanding == 0); } static void _set_default_source (GvcMixerControl *control, GvcMixerStream *stream) { guint new_id; if (stream == NULL) { control->priv->default_source_id = 0; control->priv->default_source_is_set = FALSE; g_signal_emit (control, signals[DEFAULT_SOURCE_CHANGED], 0, PA_INVALID_INDEX); return; } new_id = gvc_mixer_stream_get_id (stream); if (control->priv->default_source_id != new_id) { control->priv->default_source_id = new_id; control->priv->default_source_is_set = TRUE; g_signal_emit (control, signals[DEFAULT_SOURCE_CHANGED], 0, new_id); } } static void _set_default_sink (GvcMixerControl *control, GvcMixerStream *stream) { guint new_id; if (stream == NULL) { /* Don't tell front-ends about an unset default * sink if it's already unset */ if (control->priv->default_sink_is_set == FALSE) return; control->priv->default_sink_id = 0; control->priv->default_sink_is_set = FALSE; g_signal_emit (control, signals[DEFAULT_SINK_CHANGED], 0, PA_INVALID_INDEX); return; } new_id = gvc_mixer_stream_get_id (stream); if (control->priv->default_sink_id != new_id) { control->priv->default_sink_id = new_id; control->priv->default_sink_is_set = TRUE; g_signal_emit (control, signals[DEFAULT_SINK_CHANGED], 0, new_id); } } static gboolean _stream_has_name (gpointer key, GvcMixerStream *stream, const char *name) { const char *t_name; t_name = gvc_mixer_stream_get_name (stream); if (t_name != NULL && name != NULL && strcmp (t_name, name) == 0) { return TRUE; } return FALSE; } static GvcMixerStream * find_stream_for_name (GvcMixerControl *control, const char *name) { GvcMixerStream *stream; stream = g_hash_table_find (control->priv->all_streams, (GHRFunc)_stream_has_name, (char *)name); return stream; } static void update_default_source_from_name (GvcMixerControl *control, const char *name) { gboolean changed; if ((control->priv->default_source_name == NULL && name != NULL) || (control->priv->default_source_name != NULL && name == NULL) || strcmp (control->priv->default_source_name, name) != 0) { changed = TRUE; } if (changed) { GvcMixerStream *stream; g_free (control->priv->default_source_name); control->priv->default_source_name = g_strdup (name); stream = find_stream_for_name (control, name); _set_default_source (control, stream); } } static void update_default_sink_from_name (GvcMixerControl *control, const char *name) { gboolean changed; if ((control->priv->default_sink_name == NULL && name != NULL) || (control->priv->default_sink_name != NULL && name == NULL) || strcmp (control->priv->default_sink_name, name) != 0) { changed = TRUE; } if (changed) { GvcMixerStream *stream; g_free (control->priv->default_sink_name); control->priv->default_sink_name = g_strdup (name); stream = find_stream_for_name (control, name); _set_default_sink (control, stream); } } static void update_server (GvcMixerControl *control, const pa_server_info *info) { if (info->default_source_name != NULL) { update_default_source_from_name (control, info->default_source_name); } if (info->default_sink_name != NULL) { update_default_sink_from_name (control, info->default_sink_name); } } static void remove_stream (GvcMixerControl *control, GvcMixerStream *stream) { guint id; g_object_ref (stream); id = gvc_mixer_stream_get_id (stream); if (id == control->priv->default_sink_id) { _set_default_sink (control, NULL); } else if (id == control->priv->default_source_id) { _set_default_source (control, NULL); } g_hash_table_remove (control->priv->all_streams, GUINT_TO_POINTER (id)); g_signal_emit (G_OBJECT (control), signals[STREAM_REMOVED], 0, gvc_mixer_stream_get_id (stream)); g_object_unref (stream); } static void add_stream (GvcMixerControl *control, GvcMixerStream *stream) { g_hash_table_insert (control->priv->all_streams, GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)), stream); g_signal_emit (G_OBJECT (control), signals[STREAM_ADDED], 0, gvc_mixer_stream_get_id (stream)); } static void update_sink (GvcMixerControl *control, const pa_sink_info *info) { GvcMixerStream *stream; gboolean is_new; pa_volume_t max_volume; GvcChannelMap *map; char map_buff[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_channel_map_snprint (map_buff, PA_CHANNEL_MAP_SNPRINT_MAX, &info->channel_map); #if 1 g_debug ("Updating sink: index=%u name='%s' description='%s' map='%s'", info->index, info->name, info->description, map_buff); #endif map = NULL; is_new = FALSE; stream = g_hash_table_lookup (control->priv->sinks, GUINT_TO_POINTER (info->index)); if (stream == NULL) { #if PA_MICRO > 15 GList *list = NULL; guint i; #endif /* PA_MICRO > 15 */ map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map); stream = gvc_mixer_sink_new (control->priv->pa_context, info->index, map); #if PA_MICRO > 15 for (i = 0; i < info->n_ports; i++) { GvcMixerStreamPort *port; port = g_new0 (GvcMixerStreamPort, 1); port->port = g_strdup (info->ports[i]->name); port->human_port = g_strdup (info->ports[i]->description); port->priority = info->ports[i]->priority; list = g_list_prepend (list, port); } gvc_mixer_stream_set_ports (stream, list); #endif /* PA_MICRO > 15 */ g_object_unref (map); is_new = TRUE; } else if (gvc_mixer_stream_is_running (stream)) { /* Ignore events if volume changes are outstanding */ g_debug ("Ignoring event, volume changes are outstanding"); return; } max_volume = pa_cvolume_max (&info->volume); gvc_mixer_stream_set_name (stream, info->name); gvc_mixer_stream_set_card_index (stream, info->card); gvc_mixer_stream_set_description (stream, info->description); gvc_mixer_stream_set_icon_name (stream, "audio-card"); gvc_mixer_stream_set_volume (stream, (guint)max_volume); gvc_mixer_stream_set_is_muted (stream, info->mute); gvc_mixer_stream_set_can_decibel (stream, !!(info->flags & PA_SINK_DECIBEL_VOLUME)); gvc_mixer_stream_set_base_volume (stream, (guint32) info->base_volume); #if PA_MICRO > 15 if (info->active_port != NULL) gvc_mixer_stream_set_port (stream, info->active_port->name); #endif /* PA_MICRO > 15 */ if (is_new) { g_hash_table_insert (control->priv->sinks, GUINT_TO_POINTER (info->index), g_object_ref (stream)); add_stream (control, stream); } if (control->priv->default_sink_name != NULL && info->name != NULL && strcmp (control->priv->default_sink_name, info->name) == 0) { _set_default_sink (control, stream); } if (map == NULL) map = (GvcChannelMap *) gvc_mixer_stream_get_channel_map (stream); gvc_channel_map_volume_changed (map, &info->volume, FALSE); } static void update_source (GvcMixerControl *control, const pa_source_info *info) { GvcMixerStream *stream; gboolean is_new; pa_volume_t max_volume; #if 1 g_debug ("Updating source: index=%u name='%s' description='%s'", info->index, info->name, info->description); #endif /* completely ignore monitors, they're not real sources */ if (info->monitor_of_sink != PA_INVALID_INDEX) { return; } is_new = FALSE; stream = g_hash_table_lookup (control->priv->sources, GUINT_TO_POINTER (info->index)); if (stream == NULL) { #if PA_MICRO > 15 GList *list = NULL; guint i; #endif /* PA_MICRO > 15 */ GvcChannelMap *map; map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map); stream = gvc_mixer_source_new (control->priv->pa_context, info->index, map); #if PA_MICRO > 15 for (i = 0; i < info->n_ports; i++) { GvcMixerStreamPort *port; port = g_new0 (GvcMixerStreamPort, 1); port->port = g_strdup (info->ports[i]->name); port->human_port = g_strdup (info->ports[i]->description); port->priority = info->ports[i]->priority; list = g_list_prepend (list, port); } gvc_mixer_stream_set_ports (stream, list); #endif /* PA_MICRO > 15 */ g_object_unref (map); is_new = TRUE; } else if (gvc_mixer_stream_is_running (stream)) { /* Ignore events if volume changes are outstanding */ g_debug ("Ignoring event, volume changes are outstanding"); return; } max_volume = pa_cvolume_max (&info->volume); gvc_mixer_stream_set_name (stream, info->name); gvc_mixer_stream_set_card_index (stream, info->card); gvc_mixer_stream_set_description (stream, info->description); gvc_mixer_stream_set_icon_name (stream, "audio-input-microphone"); gvc_mixer_stream_set_volume (stream, (guint)max_volume); gvc_mixer_stream_set_is_muted (stream, info->mute); gvc_mixer_stream_set_can_decibel (stream, !!(info->flags & PA_SOURCE_DECIBEL_VOLUME)); gvc_mixer_stream_set_base_volume (stream, (guint32) info->base_volume); #if PA_MICRO > 15 if (info->active_port != NULL) gvc_mixer_stream_set_port (stream, info->active_port->name); #endif /* PA_MICRO > 15 */ if (is_new) { g_hash_table_insert (control->priv->sources, GUINT_TO_POINTER (info->index), g_object_ref (stream)); add_stream (control, stream); } if (control->priv->default_source_name != NULL && info->name != NULL && strcmp (control->priv->default_source_name, info->name) == 0) { _set_default_source (control, stream); } } static void set_icon_name_from_proplist (GvcMixerStream *stream, pa_proplist *l, const char *default_icon_name) { const char *t; if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ICON_NAME))) { goto finish; } if ((t = pa_proplist_gets (l, PA_PROP_WINDOW_ICON_NAME))) { goto finish; } if ((t = pa_proplist_gets (l, PA_PROP_APPLICATION_ICON_NAME))) { goto finish; } if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ROLE))) { if (strcmp (t, "video") == 0 || strcmp (t, "phone") == 0) { goto finish; } if (strcmp (t, "music") == 0) { t = "audio"; goto finish; } if (strcmp (t, "game") == 0) { t = "applications-games"; goto finish; } if (strcmp (t, "event") == 0) { t = "dialog-information"; goto finish; } } t = default_icon_name; finish: gvc_mixer_stream_set_icon_name (stream, t); } static void set_is_event_stream_from_proplist (GvcMixerStream *stream, pa_proplist *l) { const char *t; gboolean is_event_stream; is_event_stream = FALSE; if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ROLE))) { if (g_str_equal (t, "event")) is_event_stream = TRUE; } gvc_mixer_stream_set_is_event_stream (stream, is_event_stream); } static void set_application_id_from_proplist (GvcMixerStream *stream, pa_proplist *l) { const char *t; if ((t = pa_proplist_gets (l, PA_PROP_APPLICATION_ID))) { gvc_mixer_stream_set_application_id (stream, t); } } static void update_sink_input (GvcMixerControl *control, const pa_sink_input_info *info) { GvcMixerStream *stream; gboolean is_new; pa_volume_t max_volume; const char *name; #if 0 g_debug ("Updating sink input: index=%u name='%s' client=%u sink=%u", info->index, info->name, info->client, info->sink); #endif is_new = FALSE; stream = g_hash_table_lookup (control->priv->sink_inputs, GUINT_TO_POINTER (info->index)); if (stream == NULL) { GvcChannelMap *map; map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map); stream = gvc_mixer_sink_input_new (control->priv->pa_context, info->index, map); g_object_unref (map); is_new = TRUE; } else if (gvc_mixer_stream_is_running (stream)) { /* Ignore events if volume changes are outstanding */ g_debug ("Ignoring event, volume changes are outstanding"); return; } max_volume = pa_cvolume_max (&info->volume); name = (const char *)g_hash_table_lookup (control->priv->clients, GUINT_TO_POINTER (info->client)); gvc_mixer_stream_set_name (stream, name); gvc_mixer_stream_set_description (stream, info->name); set_application_id_from_proplist (stream, info->proplist); set_is_event_stream_from_proplist (stream, info->proplist); set_icon_name_from_proplist (stream, info->proplist, "applications-multimedia"); gvc_mixer_stream_set_volume (stream, (guint)max_volume); gvc_mixer_stream_set_is_muted (stream, info->mute); gvc_mixer_stream_set_is_virtual (stream, info->client == PA_INVALID_INDEX); if (is_new) { g_hash_table_insert (control->priv->sink_inputs, GUINT_TO_POINTER (info->index), g_object_ref (stream)); add_stream (control, stream); } } static void update_source_output (GvcMixerControl *control, const pa_source_output_info *info) { GvcMixerStream *stream; gboolean is_new; const char *name; #if 1 g_debug ("Updating source output: index=%u name='%s' client=%u source=%u", info->index, info->name, info->client, info->source); #endif is_new = FALSE; stream = g_hash_table_lookup (control->priv->source_outputs, GUINT_TO_POINTER (info->index)); if (stream == NULL) { GvcChannelMap *map; map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map); stream = gvc_mixer_source_output_new (control->priv->pa_context, info->index, map); g_object_unref (map); is_new = TRUE; } name = (const char *)g_hash_table_lookup (control->priv->clients, GUINT_TO_POINTER (info->client)); gvc_mixer_stream_set_name (stream, name); gvc_mixer_stream_set_description (stream, info->name); set_application_id_from_proplist (stream, info->proplist); set_is_event_stream_from_proplist (stream, info->proplist); set_icon_name_from_proplist (stream, info->proplist, "audio-input-microphone"); if (is_new) { g_hash_table_insert (control->priv->source_outputs, GUINT_TO_POINTER (info->index), g_object_ref (stream)); add_stream (control, stream); } } static void update_client (GvcMixerControl *control, const pa_client_info *info) { #if 1 g_debug ("Updating client: index=%u name='%s'", info->index, info->name); #endif g_hash_table_insert (control->priv->clients, GUINT_TO_POINTER (info->index), g_strdup (info->name)); } static char * card_num_streams_to_status (guint sinks, guint sources) { char *sinks_str; char *sources_str; char *ret; if (sinks == 0 && sources == 0) { /* translators: * The device has been disabled */ return g_strdup (_("Disabled")); } if (sinks == 0) { sinks_str = NULL; } else { /* translators: * The number of sound outputs on a particular device */ sinks_str = g_strdup_printf (ngettext ("%u Output", "%u Outputs", sinks), sinks); } if (sources == 0) { sources_str = NULL; } else { /* translators: * The number of sound inputs on a particular device */ sources_str = g_strdup_printf (ngettext ("%u Input", "%u Inputs", sources), sources); } if (sources_str == NULL) return sinks_str; if (sinks_str == NULL) return sources_str; ret = g_strdup_printf ("%s / %s", sinks_str, sources_str); g_free (sinks_str); g_free (sources_str); return ret; } static void update_card (GvcMixerControl *control, const pa_card_info *info) { GvcMixerCard *card; gboolean is_new; #if 1 guint i; const char *key; void *state; g_debug ("Updating card %s (index: %u driver: %s):", info->name, info->index, info->driver); for (i = 0; i < info->n_profiles; i++) { struct pa_card_profile_info pi = info->profiles[i]; gboolean is_default; is_default = (g_strcmp0 (pi.name, info->active_profile->name) == 0); g_debug ("\tProfile '%s': %d sources %d sinks%s", pi.name, pi.n_sources, pi.n_sinks, is_default ? " (Current)" : ""); } state = NULL; key = pa_proplist_iterate (info->proplist, &state); while (key != NULL) { g_debug ("\tProperty: '%s' = '%s'", key, pa_proplist_gets (info->proplist, key)); key = pa_proplist_iterate (info->proplist, &state); } #endif card = g_hash_table_lookup (control->priv->cards, GUINT_TO_POINTER (info->index)); if (card == NULL) { GList *list = NULL; for (i = 0; i < info->n_profiles; i++) { struct pa_card_profile_info pi = info->profiles[i]; GvcMixerCardProfile *profile; profile = g_new0 (GvcMixerCardProfile, 1); profile->profile = g_strdup (pi.name); profile->human_profile = g_strdup (pi.description); profile->status = card_num_streams_to_status (pi.n_sinks, pi.n_sources); profile->n_sinks = pi.n_sinks; profile->n_sources = pi.n_sources; profile->priority = pi.priority; list = g_list_prepend (list, profile); } card = gvc_mixer_card_new (control->priv->pa_context, info->index); gvc_mixer_card_set_profiles (card, list); is_new = TRUE; } gvc_mixer_card_set_name (card, pa_proplist_gets (info->proplist, "device.description")); gvc_mixer_card_set_icon_name (card, pa_proplist_gets (info->proplist, "device.icon_name")); gvc_mixer_card_set_profile (card, info->active_profile->name); if (is_new) { g_hash_table_insert (control->priv->cards, GUINT_TO_POINTER (info->index), g_object_ref (card)); } g_signal_emit (G_OBJECT (control), signals[CARD_ADDED], 0, info->index); } static void _pa_context_get_sink_info_cb (pa_context *context, const pa_sink_info *i, int eol, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); if (eol < 0) { if (pa_context_errno (context) == PA_ERR_NOENTITY) { return; } g_warning ("Sink callback failure"); return; } if (eol > 0) { dec_outstanding (control); return; } update_sink (control, i); } static void _pa_context_get_source_info_cb (pa_context *context, const pa_source_info *i, int eol, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); if (eol < 0) { if (pa_context_errno (context) == PA_ERR_NOENTITY) { return; } g_warning ("Source callback failure"); return; } if (eol > 0) { dec_outstanding (control); return; } update_source (control, i); } static void _pa_context_get_sink_input_info_cb (pa_context *context, const pa_sink_input_info *i, int eol, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); if (eol < 0) { if (pa_context_errno (context) == PA_ERR_NOENTITY) { return; } g_warning ("Sink input callback failure"); return; } if (eol > 0) { dec_outstanding (control); return; } update_sink_input (control, i); } static void _pa_context_get_source_output_info_cb (pa_context *context, const pa_source_output_info *i, int eol, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); if (eol < 0) { if (pa_context_errno (context) == PA_ERR_NOENTITY) { return; } g_warning ("Source output callback failure"); return; } if (eol > 0) { dec_outstanding (control); return; } update_source_output (control, i); } static void _pa_context_get_client_info_cb (pa_context *context, const pa_client_info *i, int eol, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); if (eol < 0) { if (pa_context_errno (context) == PA_ERR_NOENTITY) { return; } g_warning ("Client callback failure"); return; } if (eol > 0) { dec_outstanding (control); return; } update_client (control, i); } static void _pa_context_get_card_info_by_index_cb (pa_context *context, const pa_card_info *i, int eol, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); if (eol < 0) { if (pa_context_errno (context) == PA_ERR_NOENTITY) return; g_warning ("Card callback failure"); return; } if (eol > 0) { dec_outstanding (control); return; } update_card (control, i); } static void _pa_context_get_server_info_cb (pa_context *context, const pa_server_info *i, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); if (i == NULL) { g_warning ("Server info callback failure"); return; } update_server (control, i); dec_outstanding (control); } static void remove_event_role_stream (GvcMixerControl *control) { g_debug ("Removing event role"); } static void update_event_role_stream (GvcMixerControl *control, const pa_ext_stream_restore_info *info) { GvcMixerStream *stream; gboolean is_new; pa_volume_t max_volume; if (strcmp (info->name, "sink-input-by-media-role:event") != 0) { return; } #if 0 g_debug ("Updating event role: name='%s' device='%s'", info->name, info->device); #endif is_new = FALSE; if (!control->priv->event_sink_input_is_set) { pa_channel_map pa_map; GvcChannelMap *map; pa_map.channels = 1; pa_map.map[0] = PA_CHANNEL_POSITION_MONO; map = gvc_channel_map_new_from_pa_channel_map (&pa_map); stream = gvc_mixer_event_role_new (control->priv->pa_context, info->device, map); control->priv->event_sink_input_id = gvc_mixer_stream_get_id (stream); control->priv->event_sink_input_is_set = TRUE; is_new = TRUE; } else { stream = g_hash_table_lookup (control->priv->all_streams, GUINT_TO_POINTER (control->priv->event_sink_input_id)); } max_volume = pa_cvolume_max (&info->volume); gvc_mixer_stream_set_name (stream, "系统声音"); gvc_mixer_stream_set_icon_name (stream, "multimedia-volume-control"); gvc_mixer_stream_set_volume (stream, (guint)max_volume); gvc_mixer_stream_set_is_muted (stream, info->mute); if (is_new) { add_stream (control, stream); } } static void _pa_ext_stream_restore_read_cb (pa_context *context, const pa_ext_stream_restore_info *i, int eol, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); if (eol < 0) { g_debug ("Failed to initialized stream_restore extension: %s", pa_strerror (pa_context_errno (context))); remove_event_role_stream (control); return; } if (eol > 0) { dec_outstanding (control); /* If we don't have an event stream to restore, then * set one up with a default 100% volume */ if (!control->priv->event_sink_input_is_set) { pa_ext_stream_restore_info info; memset (&info, 0, sizeof(info)); info.name = "sink-input-by-media-role:event"; info.volume.channels = 1; info.volume.values[0] = PA_VOLUME_NORM; update_event_role_stream (control, &info); } return; } update_event_role_stream (control, i); } static void _pa_ext_stream_restore_subscribe_cb (pa_context *context, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); pa_operation *o; o = pa_ext_stream_restore_read (context, _pa_ext_stream_restore_read_cb, control); if (o == NULL) { g_warning ("pa_ext_stream_restore_read() failed"); return; } pa_operation_unref (o); } static void req_update_server_info (GvcMixerControl *control, int index) { pa_operation *o; o = pa_context_get_server_info (control->priv->pa_context, _pa_context_get_server_info_cb, control); if (o == NULL) { g_warning ("pa_context_get_server_info() failed"); return; } pa_operation_unref (o); } static void req_update_client_info (GvcMixerControl *control, int index) { pa_operation *o; if (index < 0) { o = pa_context_get_client_info_list (control->priv->pa_context, _pa_context_get_client_info_cb, control); } else { o = pa_context_get_client_info (control->priv->pa_context, index, _pa_context_get_client_info_cb, control); } if (o == NULL) { g_warning ("pa_context_client_info_list() failed"); return; } pa_operation_unref (o); } static void req_update_card (GvcMixerControl *control, int index) { pa_operation *o; if (index < 0) { o = pa_context_get_card_info_list (control->priv->pa_context, _pa_context_get_card_info_by_index_cb, control); } else { o = pa_context_get_card_info_by_index (control->priv->pa_context, index, _pa_context_get_card_info_by_index_cb, control); } if (o == NULL) { g_warning ("pa_context_get_card_info_by_index() failed"); return; } pa_operation_unref (o); } static void req_update_sink_info (GvcMixerControl *control, int index) { pa_operation *o; if (index < 0) { o = pa_context_get_sink_info_list (control->priv->pa_context, _pa_context_get_sink_info_cb, control); } else { o = pa_context_get_sink_info_by_index (control->priv->pa_context, index, _pa_context_get_sink_info_cb, control); } if (o == NULL) { g_warning ("pa_context_get_sink_info_list() failed"); return; } pa_operation_unref (o); } static void req_update_source_info (GvcMixerControl *control, int index) { pa_operation *o; if (index < 0) { o = pa_context_get_source_info_list (control->priv->pa_context, _pa_context_get_source_info_cb, control); } else { o = pa_context_get_source_info_by_index(control->priv->pa_context, index, _pa_context_get_source_info_cb, control); } if (o == NULL) { g_warning ("pa_context_get_source_info_list() failed"); return; } pa_operation_unref (o); } static void req_update_sink_input_info (GvcMixerControl *control, int index) { pa_operation *o; if (index < 0) { o = pa_context_get_sink_input_info_list (control->priv->pa_context, _pa_context_get_sink_input_info_cb, control); } else { o = pa_context_get_sink_input_info (control->priv->pa_context, index, _pa_context_get_sink_input_info_cb, control); } if (o == NULL) { g_warning ("pa_context_get_sink_input_info_list() failed"); return; } pa_operation_unref (o); } static void req_update_source_output_info (GvcMixerControl *control, int index) { pa_operation *o; if (index < 0) { o = pa_context_get_source_output_info_list (control->priv->pa_context, _pa_context_get_source_output_info_cb, control); } else { o = pa_context_get_source_output_info (control->priv->pa_context, index, _pa_context_get_source_output_info_cb, control); } if (o == NULL) { g_warning ("pa_context_get_source_output_info_list() failed"); return; } pa_operation_unref (o); } static void remove_client (GvcMixerControl *control, guint index) { g_hash_table_remove (control->priv->clients, GUINT_TO_POINTER (index)); } static void remove_card (GvcMixerControl *control, guint index) { g_hash_table_remove (control->priv->cards, GUINT_TO_POINTER (index)); g_signal_emit (G_OBJECT (control), signals[CARD_REMOVED], 0, index); } static void remove_sink (GvcMixerControl *control, guint index) { GvcMixerStream *stream; #if 0 g_debug ("Removing sink: index=%u", index); #endif stream = g_hash_table_lookup (control->priv->sinks, GUINT_TO_POINTER (index)); if (stream == NULL) { return; } g_hash_table_remove (control->priv->sinks, GUINT_TO_POINTER (index)); remove_stream (control, stream); } static void remove_source (GvcMixerControl *control, guint index) { GvcMixerStream *stream; #if 0 g_debug ("Removing source: index=%u", index); #endif stream = g_hash_table_lookup (control->priv->sources, GUINT_TO_POINTER (index)); if (stream == NULL) { return; } g_hash_table_remove (control->priv->sources, GUINT_TO_POINTER (index)); remove_stream (control, stream); } static void remove_sink_input (GvcMixerControl *control, guint index) { GvcMixerStream *stream; #if 0 g_debug ("Removing sink input: index=%u", index); #endif stream = g_hash_table_lookup (control->priv->sink_inputs, GUINT_TO_POINTER (index)); if (stream == NULL) { return; } g_hash_table_remove (control->priv->sink_inputs, GUINT_TO_POINTER (index)); remove_stream (control, stream); } static void remove_source_output (GvcMixerControl *control, guint index) { GvcMixerStream *stream; #if 0 g_debug ("Removing source output: index=%u", index); #endif stream = g_hash_table_lookup (control->priv->source_outputs, GUINT_TO_POINTER (index)); if (stream == NULL) { return; } g_hash_table_remove (control->priv->source_outputs, GUINT_TO_POINTER (index)); remove_stream (control, stream); } static void _pa_context_subscribe_cb (pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { case PA_SUBSCRIPTION_EVENT_SINK: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { remove_sink (control, index); } else { req_update_sink_info (control, index); } break; case PA_SUBSCRIPTION_EVENT_SOURCE: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { remove_source (control, index); } else { req_update_source_info (control, index); } break; case PA_SUBSCRIPTION_EVENT_SINK_INPUT: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { remove_sink_input (control, index); } else { req_update_sink_input_info (control, index); } break; case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { remove_source_output (control, index); } else { req_update_source_output_info (control, index); } break; case PA_SUBSCRIPTION_EVENT_CLIENT: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { remove_client (control, index); } else { req_update_client_info (control, index); } break; case PA_SUBSCRIPTION_EVENT_SERVER: req_update_server_info (control, index); break; case PA_SUBSCRIPTION_EVENT_CARD: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { remove_card (control, index); } else { req_update_card (control, index); } break; } } static void gvc_mixer_control_ready (GvcMixerControl *control) { pa_operation *o; pa_context_set_subscribe_callback (control->priv->pa_context, _pa_context_subscribe_cb, control); o = pa_context_subscribe (control->priv->pa_context, (pa_subscription_mask_t) (PA_SUBSCRIPTION_MASK_SINK| PA_SUBSCRIPTION_MASK_SOURCE| PA_SUBSCRIPTION_MASK_SINK_INPUT| PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT| PA_SUBSCRIPTION_MASK_CLIENT| PA_SUBSCRIPTION_MASK_SERVER| PA_SUBSCRIPTION_MASK_CARD), NULL, NULL); if (o == NULL) { g_warning ("pa_context_subscribe() failed"); return; } pa_operation_unref (o); req_update_server_info (control, -1); req_update_client_info (control, -1); req_update_sink_info (control, -1); req_update_source_info (control, -1); req_update_sink_input_info (control, -1); req_update_source_output_info (control, -1); req_update_card (control, -1); control->priv->n_outstanding = 6; /* This call is not always supported */ o = pa_ext_stream_restore_read (control->priv->pa_context, _pa_ext_stream_restore_read_cb, control); if (o != NULL) { pa_operation_unref (o); control->priv->n_outstanding++; pa_ext_stream_restore_set_subscribe_cb (control->priv->pa_context, _pa_ext_stream_restore_subscribe_cb, control); o = pa_ext_stream_restore_subscribe (control->priv->pa_context, 1, NULL, NULL); if (o != NULL) { pa_operation_unref (o); } } else { g_debug ("Failed to initialized stream_restore extension: %s", pa_strerror (pa_context_errno (control->priv->pa_context))); } } static void gvc_mixer_new_pa_context (GvcMixerControl *self) { pa_proplist *proplist; g_return_if_fail (self); g_return_if_fail (!self->priv->pa_context); proplist = pa_proplist_new (); pa_proplist_sets (proplist, PA_PROP_APPLICATION_NAME, self->priv->name); pa_proplist_sets (proplist, PA_PROP_APPLICATION_ID, "org.ukui.VolumeControl"); pa_proplist_sets (proplist, PA_PROP_APPLICATION_ICON_NAME, "multimedia-volume-control"); pa_proplist_sets (proplist, PA_PROP_APPLICATION_VERSION, PACKAGE_VERSION); self->priv->pa_context = pa_context_new_with_proplist (self->priv->pa_api, NULL, proplist); pa_proplist_free (proplist); g_assert (self->priv->pa_context); } static void remove_all_streams (GvcMixerControl *control, GHashTable *hash_table) { GHashTableIter iter; gpointer key, value; g_hash_table_iter_init (&iter, hash_table); while (g_hash_table_iter_next (&iter, &key, &value)) { remove_stream (control, value); g_hash_table_iter_remove (&iter); } } static gboolean idle_reconnect (gpointer data) { GvcMixerControl *control = GVC_MIXER_CONTROL (data); GHashTableIter iter; gpointer key, value; g_return_val_if_fail (control, FALSE); if (control->priv->pa_context) { pa_context_unref (control->priv->pa_context); control->priv->pa_context = NULL; gvc_mixer_new_pa_context (control); } remove_all_streams (control, control->priv->sinks); remove_all_streams (control, control->priv->sources); remove_all_streams (control, control->priv->sink_inputs); remove_all_streams (control, control->priv->source_outputs); g_hash_table_iter_init (&iter, control->priv->clients); while (g_hash_table_iter_next (&iter, &key, &value)) g_hash_table_iter_remove (&iter); gvc_mixer_control_open (control); /* cannot fail */ control->priv->reconnect_id = 0; return FALSE; } static void _pa_context_state_cb (pa_context *context, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); switch (pa_context_get_state (context)) { case PA_CONTEXT_UNCONNECTED: case PA_CONTEXT_CONNECTING: case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: break; case PA_CONTEXT_READY: gvc_mixer_control_ready (control); break; case PA_CONTEXT_FAILED: g_warning ("Connection failed, reconnecting..."); if (control->priv->reconnect_id == 0) control->priv->reconnect_id = g_timeout_add_seconds (RECONNECT_DELAY, idle_reconnect, control); break; case PA_CONTEXT_TERMINATED: default: /* FIXME: */ break; } } gboolean gvc_mixer_control_open (GvcMixerControl *control) { int res; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); g_return_val_if_fail (control->priv->pa_context != NULL, FALSE); g_return_val_if_fail (pa_context_get_state (control->priv->pa_context) == PA_CONTEXT_UNCONNECTED, FALSE); pa_context_set_state_callback (control->priv->pa_context, _pa_context_state_cb, control); g_signal_emit (G_OBJECT (control), signals[CONNECTING], 0); res = pa_context_connect (control->priv->pa_context, NULL, (pa_context_flags_t) PA_CONTEXT_NOFAIL, NULL); if (res < 0) { g_warning ("Failed to connect context: %s", pa_strerror (pa_context_errno (control->priv->pa_context))); } return res; } gboolean gvc_mixer_control_close (GvcMixerControl *control) { g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); g_return_val_if_fail (control->priv->pa_context != NULL, FALSE); pa_context_disconnect (control->priv->pa_context); return TRUE; } static void gvc_mixer_control_dispose (GObject *object) { GvcMixerControl *control = GVC_MIXER_CONTROL (object); if (control->priv->pa_context != NULL) { pa_context_unref (control->priv->pa_context); control->priv->pa_context = NULL; } if (control->priv->default_source_name != NULL) { g_free (control->priv->default_source_name); control->priv->default_source_name = NULL; } if (control->priv->default_sink_name != NULL) { g_free (control->priv->default_sink_name); control->priv->default_sink_name = NULL; } if (control->priv->pa_mainloop != NULL) { pa_glib_mainloop_free (control->priv->pa_mainloop); control->priv->pa_mainloop = NULL; } if (control->priv->all_streams != NULL) { g_hash_table_destroy (control->priv->all_streams); control->priv->all_streams = NULL; } if (control->priv->sinks != NULL) { g_hash_table_destroy (control->priv->sinks); control->priv->sinks = NULL; } if (control->priv->sources != NULL) { g_hash_table_destroy (control->priv->sources); control->priv->sources = NULL; } if (control->priv->sink_inputs != NULL) { g_hash_table_destroy (control->priv->sink_inputs); control->priv->sink_inputs = NULL; } if (control->priv->source_outputs != NULL) { g_hash_table_destroy (control->priv->source_outputs); control->priv->source_outputs = NULL; } if (control->priv->clients != NULL) { g_hash_table_destroy (control->priv->clients); control->priv->clients = NULL; } if (control->priv->cards != NULL) { g_hash_table_destroy (control->priv->cards); control->priv->cards = NULL; } G_OBJECT_CLASS (gvc_mixer_control_parent_class)->dispose (object); } static void gvc_mixer_control_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GvcMixerControl *self = GVC_MIXER_CONTROL (object); switch (prop_id) { case PROP_NAME: g_free (self->priv->name); self->priv->name = g_value_dup_string (value); g_object_notify (G_OBJECT (self), "name"); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gvc_mixer_control_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GvcMixerControl *self = GVC_MIXER_CONTROL (object); switch (prop_id) { case PROP_NAME: g_value_set_string (value, self->priv->name); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GObject * gvc_mixer_control_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; GvcMixerControl *self; object = G_OBJECT_CLASS (gvc_mixer_control_parent_class)->constructor (type, n_construct_properties, construct_params); self = GVC_MIXER_CONTROL (object); gvc_mixer_new_pa_context (self); return object; } static void gvc_mixer_control_class_init (GvcMixerControlClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = gvc_mixer_control_constructor; object_class->dispose = gvc_mixer_control_dispose; object_class->finalize = gvc_mixer_control_finalize; object_class->set_property = gvc_mixer_control_set_property; object_class->get_property = gvc_mixer_control_get_property; g_object_class_install_property (object_class, PROP_NAME, g_param_spec_string ("name", "Name", "Name to display for this mixer control", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); signals [CONNECTING] = g_signal_new ("connecting", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcMixerControlClass, connecting), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals [READY] = g_signal_new ("ready", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcMixerControlClass, ready), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals [STREAM_ADDED] = g_signal_new ("stream-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcMixerControlClass, stream_added), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [STREAM_REMOVED] = g_signal_new ("stream-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcMixerControlClass, stream_removed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [CARD_ADDED] = g_signal_new ("card-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcMixerControlClass, card_added), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [CARD_REMOVED] = g_signal_new ("card-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcMixerControlClass, card_removed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [DEFAULT_SINK_CHANGED] = g_signal_new ("default-sink-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcMixerControlClass, default_sink_changed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [DEFAULT_SOURCE_CHANGED] = g_signal_new ("default-source-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcMixerControlClass, default_source_changed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); g_type_class_add_private (klass, sizeof (GvcMixerControlPrivate)); } static void gvc_mixer_control_init (GvcMixerControl *control) { control->priv = GVC_MIXER_CONTROL_GET_PRIVATE (control); control->priv->pa_mainloop = pa_glib_mainloop_new (g_main_context_default ()); g_assert (control->priv->pa_mainloop); control->priv->pa_api = pa_glib_mainloop_get_api (control->priv->pa_mainloop); g_assert (control->priv->pa_api); control->priv->all_streams = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); control->priv->sinks = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); control->priv->sources = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); control->priv->sink_inputs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); control->priv->source_outputs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); control->priv->cards = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); control->priv->clients = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_free); } static void gvc_mixer_control_finalize (GObject *object) { GvcMixerControl *mixer_control; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_CONTROL (object)); mixer_control = GVC_MIXER_CONTROL (object); g_free (mixer_control->priv->name); mixer_control->priv->name = NULL; g_return_if_fail (mixer_control->priv != NULL); G_OBJECT_CLASS (gvc_mixer_control_parent_class)->finalize (object); } GvcMixerControl * gvc_mixer_control_new (const char *name) { GObject *control; control = g_object_new (GVC_TYPE_MIXER_CONTROL, "name", name, NULL); return GVC_MIXER_CONTROL (control); } ukui-control-center/panels/volume-control/sound-theme-file-utils.c0000664000175000017500000002130613057175444024343 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * Copyright (C) 2008 Bastien Nocera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include #include #include #include #include #include #include "sound-theme-file-utils.h" #define CUSTOM_THEME_NAME "__custom" /* This function needs to be called after each individual * changeset to the theme */ void custom_theme_update_time (void) { char *path; path = custom_theme_dir_path (NULL); utime (path, NULL); g_free (path); } char * custom_theme_dir_path (const char *child) { static char *dir = NULL; const char *data_dir; if (dir == NULL) { data_dir = g_get_user_data_dir (); dir = g_build_filename (data_dir, "sounds", CUSTOM_THEME_NAME, NULL); } if (child == NULL) return g_strdup (dir); return g_build_filename (dir, child, NULL); } static gboolean directory_delete_recursive (GFile *directory, GError **error) { GFileEnumerator *enumerator; GFileInfo *info; gboolean success = TRUE; enumerator = g_file_enumerate_children (directory, G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, error); if (enumerator == NULL) return FALSE; while (success && (info = g_file_enumerator_next_file (enumerator, NULL, NULL))) { GFile *child; child = g_file_get_child (directory, g_file_info_get_name (info)); if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { success = directory_delete_recursive (child, error); } g_object_unref (info); if (success) success = g_file_delete (child, NULL, error); } g_file_enumerator_close (enumerator, NULL, NULL); if (success) success = g_file_delete (directory, NULL, error); return success; } /** * capplet_file_delete_recursive : * @file : * @error : * * A utility routine to delete files and/or directories, * including non-empty directories. **/ static gboolean capplet_file_delete_recursive (GFile *file, GError **error) { GFileInfo *info; GFileType type; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, error); if (info == NULL) return FALSE; type = g_file_info_get_file_type (info); g_object_unref (info); if (type == G_FILE_TYPE_DIRECTORY) return directory_delete_recursive (file, error); else return g_file_delete (file, NULL, error); } void delete_custom_theme_dir (void) { char *dir; GFile *file; dir = custom_theme_dir_path (NULL); file = g_file_new_for_path (dir); g_free (dir); capplet_file_delete_recursive (file, NULL); g_object_unref (file); g_debug ("deleted the custom theme dir"); } gboolean custom_theme_dir_is_empty (void) { char *dir; GFile *file; gboolean is_empty; GFileEnumerator *enumerator; GFileInfo *info; GError *error = NULL; dir = custom_theme_dir_path (NULL); file = g_file_new_for_path (dir); g_free (dir); is_empty = TRUE; enumerator = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, &error); if (enumerator == NULL) { g_warning ("Unable to enumerate files: %s", error->message); g_error_free (error); goto out; } while (is_empty && (info = g_file_enumerator_next_file (enumerator, NULL, NULL))) { if (strcmp ("index.theme", g_file_info_get_name (info)) != 0) { is_empty = FALSE; } g_object_unref (info); } g_file_enumerator_close (enumerator, NULL, NULL); out: g_object_unref (file); return is_empty; } static void delete_one_file (const char *sound_name, const char *pattern) { GFile *file; char *name, *filename; name = g_strdup_printf (pattern, sound_name); filename = custom_theme_dir_path (name); g_free (name); file = g_file_new_for_path (filename); g_free (filename); capplet_file_delete_recursive (file, NULL); g_object_unref (file); } void delete_old_files (const char **sounds) { guint i; for (i = 0; sounds[i] != NULL; i++) { delete_one_file (sounds[i], "%s.ogg"); } } void delete_disabled_files (const char **sounds) { guint i; for (i = 0; sounds[i] != NULL; i++) delete_one_file (sounds[i], "%s.disabled"); } static void create_one_file (GFile *file) { GFileOutputStream* stream; stream = g_file_create (file, G_FILE_CREATE_NONE, NULL, NULL); if (stream != NULL) { g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, NULL); g_object_unref (stream); } } void add_disabled_file (const char **sounds) { guint i; for (i = 0; sounds[i] != NULL; i++) { GFile *file; char *name, *filename; name = g_strdup_printf ("%s.disabled", sounds[i]); filename = custom_theme_dir_path (name); g_free (name); file = g_file_new_for_path (filename); g_free (filename); create_one_file (file); g_object_unref (file); } } void add_custom_file (const char **sounds, const char *filename) { guint i; for (i = 0; sounds[i] != NULL; i++) { GFile *file; char *name, *path; /* We use *.ogg because it's the first type of file that * libcanberra looks at */ name = g_strdup_printf ("%s.ogg", sounds[i]); path = custom_theme_dir_path (name); g_free (name); /* In case there's already a link there, delete it */ g_unlink (path); file = g_file_new_for_path (path); g_free (path); /* Create the link */ g_file_make_symbolic_link (file, filename, NULL, NULL); g_object_unref (file); } } void create_custom_theme (const char *parent) { GKeyFile *keyfile; char *data; char *path; /* Create the custom directory */ path = custom_theme_dir_path (NULL); g_mkdir_with_parents (path, 0755); g_free (path); /* Set the data for index.theme */ keyfile = g_key_file_new (); g_key_file_set_string (keyfile, "Sound Theme", "Name", _("Custom")); g_key_file_set_string (keyfile, "Sound Theme", "Inherits", parent); g_key_file_set_string (keyfile, "Sound Theme", "Directories", "."); data = g_key_file_to_data (keyfile, NULL, NULL); g_key_file_free (keyfile); /* Save the index.theme */ path = custom_theme_dir_path ("index.theme"); g_file_set_contents (path, data, -1, NULL); g_free (path); g_free (data); custom_theme_update_time (); } ukui-control-center/panels/volume-control/icons/0000775000175000017500000000000013263647163021006 5ustar fengfengukui-control-center/panels/volume-control/icons/Makefile.am0000664000175000017500000000105513057175444023042 0ustar fengfengNULL = SUBDIRS = \ scalable \ 16x16 \ 22x22 \ 24x24 \ 32x32 \ $(NULL) gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/ukui-icon-theme install-data-hook: update-icon-cache uninstall-hook: update-icon-cache update-icon-cache: @-if test -z "$(DESTDIR)"; then \ echo "Updating Gtk icon cache."; \ $(gtk_update_icon_cache); \ else \ echo "*** Icon cache not updated. After (un)install, run this:"; \ echo "*** $(gtk_update_icon_cache)"; \ fi -include $(top_srcdir)/git.mk clean-local: rm -f *~ Makefile.in Makefile ukui-control-center/panels/volume-control/icons/scalable/0000775000175000017500000000000013263647163022554 5ustar fengfengukui-control-center/panels/volume-control/icons/scalable/Makefile.am0000664000175000017500000000014513057175444024607 0ustar fengfengSUBDIRS = status devices -include $(top_srcdir)/git.mk clean-local: rm -f *~ Makefile.in Makefile ukui-control-center/panels/volume-control/icons/scalable/devices/0000775000175000017500000000000013263647163024176 5ustar fengfeng././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-right-side-testing.svgukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-right-side-testing.sv0000664000175000017500000005046513253611037033011 0ustar fengfeng image/svg+xml audio device speaker output right-side testing highlighted audio-speaker-right-side-testing Evangeline McGlynn ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-right-back-testing.svgukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-right-back-testing.sv0000664000175000017500000005052613253611037032763 0ustar fengfeng image/svg+xml audio device speaker output right-back testing highlighted audio-speaker-right-back-testing Evangeline McGlynn ukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-right.svg0000664000175000017500000004654113253611037030563 0ustar fengfeng image/svg+xml audio device speaker output right audio-speaker-right Evangeline McGlynn ukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-center.svg0000664000175000017500000004650713253611037030730 0ustar fengfeng image/svg+xml audio device speaker output center audio-speaker-center Evangeline McGlynn ukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-left-side.svg0000664000175000017500000004653113253611037031321 0ustar fengfeng image/svg+xml audio device speaker output left-side audio-speaker-left-side Evangeline McGlynn ukui-control-center/panels/volume-control/icons/scalable/devices/Makefile.am0000664000175000017500000000156713057175444026242 0ustar fengfengNULL = themedir = $(datadir)/icons/ukui-icon-theme size = 48x48 context = devices iconsdir = $(themedir)/$(size)/$(context) icons_DATA = \ audio-speaker-center.svg \ audio-speaker-center-testing.svg \ audio-speaker-left-back.svg \ audio-speaker-left-back-testing.svg \ audio-speaker-left.svg \ audio-speaker-left-side.svg \ audio-speaker-left-side-testing.svg \ audio-speaker-left-testing.svg \ audio-speaker-right-back.svg \ audio-speaker-right-back-testing.svg \ audio-speaker-right.svg \ audio-speaker-right-side.svg \ audio-speaker-right-side-testing.svg \ audio-speaker-right-testing.svg \ audio-speaker-center-back-testing.svg \ audio-speaker-center-back.svg \ audio-subwoofer.svg \ audio-subwoofer-testing.svg \ $(NULL) EXTRA_DIST = \ $(icons_DATA) \ $(NULL) -include $(top_srcdir)/git.mk clean-local: rm -f *~ Makefile.in Makefile ukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-center-back.svg0000664000175000017500000004513613253611037031623 0ustar fengfeng image/svg+xml audio device speaker output center audio-speaker-center Evangeline McGlynn ukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-right-side.svg0000664000175000017500000004653313253611037031506 0ustar fengfeng image/svg+xml audio device speaker output right-side audio-speaker-right-side Evangeline McGlynn ukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-left-side-testing.svg0000664000175000017500000005046413253611037032774 0ustar fengfeng image/svg+xml audio device speaker output left-side testing highlighted audio-speaker-left-side-testing Evangeline McGlynn ukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-left-testing.svg0000664000175000017500000005050213253611037032043 0ustar fengfeng image/svg+xml audio device speaker output left testing highlighted audio-speaker-left-testing Evangeline McGlynn ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-center-back-testing.svgukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-center-back-testing.s0000664000175000017500000004706413253611037032743 0ustar fengfeng image/svg+xml audio device speaker output center testing highlighted audio-speaker-center-testing Evangeline McGlynn ukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-left.svg0000664000175000017500000004654413253611037030403 0ustar fengfeng image/svg+xml audio device speaker output left audio-speaker-left Evangeline McGlynn ukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-center-testing.svg0000664000175000017500000005044513253611037032377 0ustar fengfeng image/svg+xml audio device speaker output center testing highlighted audio-speaker-center-testing Evangeline McGlynn ukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-left-back-testing.svg0000664000175000017500000005051213253611037032742 0ustar fengfeng image/svg+xml audio device speaker output left-back testing highlighted audio-speaker-left-b-testing Evangeline McGlynn ukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-right-back.svg0000664000175000017500000004657313253611037031466 0ustar fengfeng image/svg+xml audio device speaker output right-back audio-speaker-right-back Evangeline McGlynn ukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-right-testing.svg0000664000175000017500000007767113253611037032246 0ustar fengfeng image/svg+xml audio device speaker output right testing highlighted audio-speaker-right-testing Evangeline McGlynn ukui-control-center/panels/volume-control/icons/scalable/devices/audio-speaker-left-back.svg0000664000175000017500000004656313253611037031302 0ustar fengfeng image/svg+xml audio device speaker output left-back audio-speaker-left-back Evangeline McGlynn ukui-control-center/panels/volume-control/icons/scalable/devices/audio-subwoofer-testing.svg0000664000175000017500000002625313253611037031502 0ustar fengfeng image/svg+xml audio device subwoofer output testing highlighted audio-subwoofer-testing Evangeline McGlynn ukui-control-center/panels/volume-control/icons/scalable/devices/audio-subwoofer.svg0000664000175000017500000003353013253611037030023 0ustar fengfeng image/svg+xml audio device subwoofer output audio-subwoofer Evangeline McGlynn ukui-control-center/panels/volume-control/icons/scalable/status/0000775000175000017500000000000013263647163024077 5ustar fengfengukui-control-center/panels/volume-control/icons/scalable/status/audio-input-microphone-low.svg0000664000175000017500000015615713057175444032034 0ustar fengfeng image/svg+xml ukui-control-center/panels/volume-control/icons/scalable/status/Makefile.am0000664000175000017500000000065413057175444026137 0ustar fengfengNULL = themedir = $(datadir)/icons/ukui-icon-theme size = scalable context = status iconsdir = $(themedir)/$(size)/$(context) icons_DATA = \ audio-input-microphone-high.svg \ audio-input-microphone-low.svg \ audio-input-microphone-medium.svg \ audio-input-microphone-muted.svg \ $(NULL) EXTRA_DIST = \ $(icons_DATA) \ $(NULL) -include $(top_srcdir)/git.mk clean-local: rm -f *~ Makefile.in Makefile ukui-control-center/panels/volume-control/icons/scalable/status/audio-input-microphone-medium.svg0000664000175000017500000016007413057175444032504 0ustar fengfeng image/svg+xml ukui-control-center/panels/volume-control/icons/scalable/status/audio-input-microphone-muted.svg0000664000175000017500000015623113057175444032342 0ustar fengfeng image/svg+xml ukui-control-center/panels/volume-control/icons/scalable/status/audio-input-microphone-high.svg0000664000175000017500000016126113057175444032142 0ustar fengfeng image/svg+xml ukui-control-center/panels/volume-control/icons/24x24/0000775000175000017500000000000013263647163021571 5ustar fengfengukui-control-center/panels/volume-control/icons/24x24/Makefile.am0000664000175000017500000000013513057175444023623 0ustar fengfengSUBDIRS = status -include $(top_srcdir)/git.mk clean-local: rm -f *~ Makefile.in Makefile ukui-control-center/panels/volume-control/icons/24x24/status/0000775000175000017500000000000013263647163023114 5ustar fengfengukui-control-center/panels/volume-control/icons/24x24/status/audio-input-microphone-low.png0000664000175000017500000000152113057175444031016 0ustar fengfengPNG  IHDRw=tEXtSoftwareAdobe ImageReadyqe<IDATxb?- !b1 i6@0K:"al>w+LdpMU{~?~2wA1 R<ëoDݼà ϰk!I qde[T 2ܽAANȱS z: =F>| syYiW ߲}(رRb >`PUb8pó/`nU91n\&E]zZ03EyY2X3޳A\LYu- M\5Dod$nݹǠɰQkkkb[3?\ < 榆 ;wdŞo\ ̲s/$ 2\W[a V ߼w=gMep"ν̌ vnߊRuLo"w))F @Cb|4Y@MRa^Pyұl|F.%l n#2S6q.H?#V\53'aG0iO&(hYXݻ7N~2 PZxb& jCgϞ?~dpx`iioLDI [7oc`dl乀:L? 3 o_/qfϛ7o?`}M|Q !S~:fhIENDB`ukui-control-center/panels/volume-control/icons/24x24/status/audio-input-microphone-high.png0000664000175000017500000000227613057175444031144 0ustar fengfengPNG  IHDRw=tEXtSoftwareAdobe ImageReadyqe<`IDATxڴmL[U~HQ1(E6`24ll&!L )dF s35SpLt JH:3mP ݨҖzﳭ&ƓwϽ|{>x]uU:ɚULϖ?~y9_47x?' NyGGD3r8H=Ed\@c퇻X(M+9-eHaPDA==}`;h9>vֽ}YqY$|N CAeܛ5@D h@z(y?J\@xOu@q sl *bZF:~ɠ'V(PwV$i[YeΆ<%~r^X9/ p[]=Iȉ?*EL*96\\FEba;-xxZ0B#㐼!£[`zFN\n) y2aak0i VXcy ,Ӡ[o  Χ iSlMrJ"PV*( iE,M ``]AB#1Hݜ} ɩU(XvqNwbq8;yA$akf:T*\Ǟɷ53_7oq#̩eq/&$ԇ૶vX6dh4PCt&%f]dZ^^_oÆD%z!+Puu? ^vܙU֔97}^+նj]GA# &`( :NtU:eOJ6Z&,4os`գd/$òTr$Z,~ n(d僿l{ MI?ҋҘT}jbbzIЫDNV&);J݁WMP*0+rUAϵ~xg[LM 9K115zV1g\dy>!dge@"N3PP<4cG0[~˲&7~ c$QB:6е_3l2 `G"@~aT5afCqQ쨼zORm.s-dRbGdzBDzAWUU !Z-\H=j#NnlU=Ġ[]pr֋(n)n+!]%cZ|.h'&߭`YoVxv?!SQIȟLy:}rB>űX,|~~D 7$,HIENDB`ukui-control-center/panels/volume-control/icons/24x24/status/audio-input-microphone-medium.png0000664000175000017500000000175113057175444031502 0ustar fengfengPNG  IHDRw=tEXtSoftwareAdobe ImageReadyqe<IDATxb?- !b1 i6@0K:"al>w+LdpMU{~?~2wA1 PU$eEyW01\yAQAaC P-`f?5Z=7 @VXH r2 Gb`x1JXp{[k!~~_~Az薄4q1<~A^V`÷l #-> n0hJ5r\r_HO"Y) 1[w0h*18|Ԉ0A^^@L\䪜L7'ĿN@7䰈W\ 99=yƠ(/pUKsc{22 [%נN<|\-j@߾3HI0ܺsAWGa ?6؂y~X7Tp#?`njȰsNIqQ9Ƶ;@>|V| >'I Wodfx-v{9Up|9+Y_ 1(2{؀aa-YgΤ6Km'^-cKIy 802g fl #zFs 2X7M-HʧaRVj.l n#(k\~FBjg.O Ž<`ҞLVq 7Pв.]woO>?.,d1p{%NLԆϞ=3>~Ƞ5ޘ ( #&ӗn700s1u2(~5f 2޾^(@ e̞7o0445~VHU6D0muIENDB`ukui-control-center/panels/volume-control/icons/22x22/0000775000175000017500000000000013263647163021565 5ustar fengfengukui-control-center/panels/volume-control/icons/22x22/Makefile.am0000664000175000017500000000013513057175444023617 0ustar fengfengSUBDIRS = status -include $(top_srcdir)/git.mk clean-local: rm -f *~ Makefile.in Makefile ukui-control-center/panels/volume-control/icons/22x22/status/0000775000175000017500000000000013263647163023110 5ustar fengfengukui-control-center/panels/volume-control/icons/22x22/status/audio-input-microphone-low.png0000664000175000017500000000147313057175444031020 0ustar fengfengPNG  IHDRĴl;tEXtSoftwareAdobe ImageReadyqe<IDATxڜmHSa[}HmnӹR3[}+$ H%)BQDD Cԁ5(|:֜^6tkw8>Ϲs8Ep8M{gK~IcC Da=p8(e۩aE="8UU^8NQl6:b>owsc\3Dc`pDڵ'zoL ( HL'NW0a<".,>yva!0N! D_•սD`75wbCq(wK`2OaL@ZXtKƆb rY<#7GN-XxqSI+K+EEFz*]=PT0':Wlu:VEDxF'{>|FNv&4 ℱ^~#I=b _XdJfJWݯwG=[oHNCar4mܱz{,^b 'u"ΟTudhypDZwFj JTM[0ݡaq+${AM4XfR9\ kLMM_#J,V+RG6_9vW{4j[stq c'h}KKsddePq?j7Sh(-yǏyz*hpŊ 6>:OPpIENDB`ukui-control-center/panels/volume-control/icons/22x22/status/audio-input-microphone-high.png0000664000175000017500000000224413057175444031133 0ustar fengfengPNG  IHDRĴl;tEXtSoftwareAdobe ImageReadyqe<FIDATxڌUPecmD?dP 90%ܧ)!-`@? I oX+Q+&BsBQġI-=O ğ_E&67| MtE<C q E*!>Wb(A qUzE'!Z Wu0>a+ְc>&bȥۘt?&O.عfqaqIWݰa}i!&z9X)kSO*Eb_L4o)$:g8 BTжwAvv6 | &p`qpS8Np92)qaph>34 ,{{O`3d37c^m c[U-BƊp{嫗U,K QUe &QSx|rlʕ#ԝEFISS95sx ޡc0 7,N2'd2A[=+(vGGE":vg~ju4e/15;seM( ]k8CSҶgGHPeb]e-YOLn7Bj yx< bEuu%wnqTU`*] #Rd0 AQ{]}>i[vg;k+q9~X~Nfa~<̬Uff_VL&WTadFrnz^jr3-鮐C[uTR?[Q0u-%|g^DDIw"4iZW<*mZ ӻBVl"_:gAjLm@HP>AK #vmaX$3K@bL*A}S " VǬ WI|k%覷XX3w-1ynӇqlwAkr5$ak _{R/oOH,ۂȃCIQ،eQPWT#!!v+F,, s#Iaq=y\=bVBRo{mc!ޢ|~3p_Zli8=|5 `0t054c0w/XP+*y61!Pm4 ,t]t& X$LPJܥRpr<ֱQ1pT 7>|('7;]]Nh4EIQC!؉#C޺z) HIVTTXTTBXH[3<@81DURj߂t  n02 rWZA% /P`tS[C.CsP~c >Om iۿvSs m,|"' z6j~LMMN"Zw1$=ZdJpS!87pR+%ɤj%: ˯:\wYa*6rmRt!`(##p~x+d[[o ׎;heロ-{hR{pa؝O_ye{7tE:"#-[;w|s#ܾW~o͍b2؈Lf|&|Q0jjZsfNŤ&-e[K#ϪcڪjSklhT^5H԰j5wF}_6[*bV*ZQȁOLnIFƣxG ?s˦tc;xmojl`-MMa +I"Jn "? t"Cҗ{M[dW^nyфƤ8%<Ս  FG:`JJK 9w za͵b@PY@3HDĠdefT8/5dZ>>X=U j5H>% A< a4Q+@(RagffA;HI.6\g8a4f,Ɋ!ќ:!bE2FSg΍tpK@v/X/}hw8L";Mx؋%L'3s/b;Z6[ۜ9+3s-qKt:v$QD\vL ӡO;O'z9^T/^\III'ДFg|TKsٳIENDB`ukui-control-center/panels/volume-control/icons/32x32/status/audio-input-microphone-high.png0000664000175000017500000000420613057175444031135 0ustar fengfengPNG  IHDR szztEXtSoftwareAdobe ImageReadyqe<(IDATxڴV{PT~X( vy(X5)[b4S'eb[H8MgI6vtjLTl.]$ (. ˲\`pA&3s;;c!Vs9)$*fcE0T܏zͺRc&DgNq nyGG<_K떚򦞣.{m D@x'!/9stdw~e`Y_q.6˒A7ӧO;WZVpe}H_c? 0ONyp 8a!nNr OKK $drb8ڇ1X?(/vMOX t:H[Vput}HLHdhq[,J2+M01Pr, p8 ??l6d2'UxuO>(p^.2MXz!7: ;wH;.Bvv89`(Ҙy0/x:<\aWIx eF0>,-N L& ?l怾:2}+o-`-JdZ "B's~'LTW ٔ7y|HLE&41Ջ̄4۽Η:K22>ٮ!u@~Akj >F JVS0 vnfv*~$1=>ʊ*E(4 Nx.|r`XCZZx<Izf5CA퇭Si?M~j @?qAtqpq֯ ==:;;,C#^$buc9g;0XQ{8]3 쁓ŋVO48Mt ҖZ߬^NIIA:YE&!Q&Bm(Ƣ1]у'ZZZz=nݮjkʶliZr^^7闆#Ly,xù+~E%t, :۾es(@ǶoGgpּOu횲p\)=Cɵ=Ф'lnj][Vt0CSՕv5OCSceuuu g(L{7X25eаBwOw@FG3r Y>"]oڢnR޶Ά؞3ɾ}od|sgdc2끾^{ +E׾T[[{kZKV3NR/;pHPVV}}}P\\ ]PPPi@$$J5ʇa%~r{g  08eytED@\ 6 @=Jw:-?` 0yN6;!`QQtvvBNNܺ}B<'!$9wJWڷOj^:Ef!%+8}e2l6 qbx'c`h(؃};LaIN?~dX %Ǹ uAqI `Xd0Iz$`DPSW3U\L6}Z={@mok55zeaJ#'^kP~|_ l6\rdyK7&n7 ^Y͛7+1wp3[Oe({|řE(~I&$+d$r{~/_9GGǾlݜmp1NssXԛkude lU`vvfVN=&G67J͖ݺ ff}p}Gҽ{wEZJi`pІ;}{MHkiy( )ZlH0̰n~011cH^<+MMMZvaZa^s6l{qcȝ %w9d_n֨H2Sc׽wK>{y r h4͕U_6j/ӟ3~Mɨ~R+Mj:RښZk Ű *Rag{~;w7!99\EzQI+h9C&(sD'Lݞ u:v:uҗvסƍO))AH0!>M&Ш5 4Q! -:=SPDiSzE)LZX GT@렻3Mi(PT;syǔ( (*ދ=Y-sOMQ@ lKi%ҏ?{.+H4"/r<'g"zϾ ן)ךLrB3LwQ*p9]h6իdLӋ̇d|[|weZhhhxݿyp8)E 1ٳo'"ńb|I"ڵEjѾ+QUQ"TpCbP)022\5j/ 9./ P5Ȝ ,Yz]?o=;oO ]Ծa}qAuu53Kґ$p٪?{aC}#]#8Ec{7NJhiC_(1xsw*+W/Jd")I@z4ؼEz`vvfV+xRxnJ9.RiTݲ03D zX,2 yk w#5'}Sb˱k!9|* XV$ t!Z@0cpkl+|igg_;9Ԍ2|?tg%GE+v|#]кlAroO3"u-rC;el歃] \s>!+36rsr >//r>PB0mmm1<|c#bҤ^+~4/X EJZ[ C%rL+'vnMVV,L!OF3>iZ@|"TӱHrǙ3g>OkJWvvO`!LLLɗ{{.DA\攸 =r  #19qK:j;UO(T*) {0i?xxs}Xglݶ-;+gwNvVJFpz,Gc|(-,,v~]Q96!ǘ{UYYY!ʎ)1|/>%4\p  S#g_䣘$ih8kZ`gt1={DaÀV'߾3h1?yښ㧈@|vy `3:{AZRѣ Ғ> <]JkT4T]fΚ  v= @ IjҀ@ 4hH1"P>H(3 hR@V\ FAm@ہ`DZb<IENDB`ukui-control-center/panels/volume-control/icons/16x16/status/audio-input-microphone-high.png0000664000175000017500000000152513057175444031142 0ustar fengfengPNG  IHDRatEXtSoftwareAdobe ImageReadyqe<IDATxb?wG*ʁ\ &HB<2@!A@Рn$wdO/v n>7._)h8\SU %)?~2w `adfy\]ƈl<Ùv= )!c6?/?俿أx [ ;Šc8ȋL }AHop 77 n^d8_ ּei)80Yxw 8e RsÁ',L=bR\uGHXP_/XXDƅ  `47fؽg/(q N\U+ot4<`mmSD ><{k|9 piIqG2JK" s+>|o߭/_/ w))aPUVdPU`pwg9k.H|6؀[+ y߽շ_~25$H6t0L2a6pd4 EٯSŴJ)p5D@>̨)_=f^\L\YY / S4H% \ Ԥ}WnfJ nj"^4=.<Aj-d_JIENDB`ukui-control-center/panels/volume-control/icons/16x16/status/Makefile.am0000664000175000017500000000065113057175444025153 0ustar fengfengNULL = themedir = $(datadir)/icons/ukui-icon-theme size = 16x16 context = status iconsdir = $(themedir)/$(size)/$(context) icons_DATA = \ audio-input-microphone-high.png \ audio-input-microphone-low.png \ audio-input-microphone-medium.png \ audio-input-microphone-muted.png \ $(NULL) EXTRA_DIST = \ $(icons_DATA) \ $(NULL) -include $(top_srcdir)/git.mk clean-local: rm -f *~ Makefile.in Makefile ukui-control-center/panels/volume-control/icons/16x16/status/audio-input-microphone-muted.png0000664000175000017500000000101013057175444031326 0ustar fengfengPNG  IHDRatEXtSoftwareAdobe ImageReadyqe<IDATxb?!n# .?###|8&!߼}ϟ?߾{?Į 5Ue R {a'CXXH|0(+39AQAaC p9dC Yl2d0cXn Gr /Y5ѣ /]k޲}X835>`aj Xhxp/]`in̰{^q1Q&B6:j Oefx)\]riIq𐕖 t ݐkB ʊ 323̜5$<S%專իV &e w7% fq- 4thHА XcK5ˌ2Ѐ 2HOx.Fbr#Ԡ6 U @Ucf r-IENDB`ukui-control-center/panels/volume-control/icons/16x16/status/audio-input-microphone-medium.png0000664000175000017500000000125713057175444031505 0ustar fengfengPNG  IHDRatEXtSoftwareAdobe ImageReadyqe<QIDATxb?!n# .?###|8&!߼}ϟ?߾{?Į }:;<8pMUÞG6 LPVg8s<î$%rLw7l?U [ ;Šc8ȋL }AHop 68_ ּei)80Yxw AsÁ',L=bR\uGHXP9,"hB e)[v 0U+ot4<`mmSD ><{k ^`g8z($€ϟ>GG :,]JkT4T]fΚ  6 v^.wo?D}zm.5$H6t0L2a6pd4 EٯSmxfm``c$c(H]fTރ۰h@Jb$'@<hp#1jPv*x *|00 RLIENDB`ukui-control-center/panels/volume-control/gvc-mixer-dialog.h0000664000175000017500000000414713057175444023207 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __GVC_MIXER_DIALOG_H #define __GVC_MIXER_DIALOG_H #include #include "gvc-mixer-control.h" G_BEGIN_DECLS #define GVC_TYPE_MIXER_DIALOG (gvc_mixer_dialog_get_type ()) #define GVC_MIXER_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_DIALOG, GvcMixerDialog)) #define GVC_MIXER_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_DIALOG, GvcMixerDialogClass)) #define GVC_IS_MIXER_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_DIALOG)) #define GVC_IS_MIXER_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_DIALOG)) #define GVC_MIXER_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_DIALOG, GvcMixerDialogClass)) typedef struct GvcMixerDialogPrivate GvcMixerDialogPrivate; typedef struct { GtkDialog parent; GvcMixerDialogPrivate *priv; } GvcMixerDialog; typedef struct { GtkDialogClass parent_class; } GvcMixerDialogClass; GType gvc_mixer_dialog_get_type (void); GvcMixerDialog * gvc_mixer_dialog_new (GvcMixerControl *control,GtkBuilder * builder); gboolean gvc_mixer_dialog_set_page (GvcMixerDialog *dialog, const gchar* page); G_END_DECLS #endif /* __GVC_MIXER_DIALOG_H */ ukui-control-center/panels/volume-control/gvc-mixer-sink-input.c0000664000175000017500000001365313057175444024046 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include "gvc-mixer-sink-input.h" #define GVC_MIXER_SINK_INPUT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInputPrivate)) struct GvcMixerSinkInputPrivate { gpointer dummy; }; static void gvc_mixer_sink_input_class_init (GvcMixerSinkInputClass *klass); static void gvc_mixer_sink_input_init (GvcMixerSinkInput *mixer_sink_input); static void gvc_mixer_sink_input_finalize (GObject *object); static void gvc_mixer_sink_input_dispose (GObject *object); G_DEFINE_TYPE (GvcMixerSinkInput, gvc_mixer_sink_input, GVC_TYPE_MIXER_STREAM) static gboolean gvc_mixer_sink_input_push_volume (GvcMixerStream *stream, gpointer *op) { pa_operation *o; guint index; const GvcChannelMap *map; pa_context *context; const pa_cvolume *cv; guint num_channels; index = gvc_mixer_stream_get_index (stream); map = gvc_mixer_stream_get_channel_map (stream); num_channels = gvc_channel_map_get_num_channels (map); cv = gvc_channel_map_get_cvolume(map); context = gvc_mixer_stream_get_pa_context (stream); o = pa_context_set_sink_input_volume (context, index, cv, NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_sink_input_volume() failed"); return FALSE; } *op = o; return TRUE; } static gboolean gvc_mixer_sink_input_change_is_muted (GvcMixerStream *stream, gboolean is_muted) { pa_operation *o; guint index; pa_context *context; index = gvc_mixer_stream_get_index (stream); context = gvc_mixer_stream_get_pa_context (stream); o = pa_context_set_sink_input_mute (context, index, is_muted, NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_sink_input_mute_by_index() failed"); return FALSE; } pa_operation_unref(o); return TRUE; } static GObject * gvc_mixer_sink_input_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; GvcMixerSinkInput *self; object = G_OBJECT_CLASS (gvc_mixer_sink_input_parent_class)->constructor (type, n_construct_properties, construct_params); self = GVC_MIXER_SINK_INPUT (object); return object; } static void gvc_mixer_sink_input_class_init (GvcMixerSinkInputClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass); object_class->constructor = gvc_mixer_sink_input_constructor; object_class->dispose = gvc_mixer_sink_input_dispose; object_class->finalize = gvc_mixer_sink_input_finalize; stream_class->push_volume = gvc_mixer_sink_input_push_volume; stream_class->change_is_muted = gvc_mixer_sink_input_change_is_muted; g_type_class_add_private (klass, sizeof (GvcMixerSinkInputPrivate)); } static void gvc_mixer_sink_input_init (GvcMixerSinkInput *sink_input) { sink_input->priv = GVC_MIXER_SINK_INPUT_GET_PRIVATE (sink_input); } static void gvc_mixer_sink_input_dispose (GObject *object) { GvcMixerSinkInput *mixer_sink_input; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_SINK_INPUT (object)); mixer_sink_input = GVC_MIXER_SINK_INPUT (object); G_OBJECT_CLASS (gvc_mixer_sink_input_parent_class)->dispose (object); } static void gvc_mixer_sink_input_finalize (GObject *object) { GvcMixerSinkInput *mixer_sink_input; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_SINK_INPUT (object)); mixer_sink_input = GVC_MIXER_SINK_INPUT (object); g_return_if_fail (mixer_sink_input->priv != NULL); G_OBJECT_CLASS (gvc_mixer_sink_input_parent_class)->finalize (object); } GvcMixerStream * gvc_mixer_sink_input_new (pa_context *context, guint index, GvcChannelMap *channel_map) { GObject *object; object = g_object_new (GVC_TYPE_MIXER_SINK_INPUT, "pa-context", context, "index", index, "channel-map", channel_map, NULL); return GVC_MIXER_STREAM (object); } ukui-control-center/panels/volume-control/gvc-mixer-source-output.h0000664000175000017500000000444713057175444024611 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __GVC_MIXER_SOURCE_OUTPUT_H #define __GVC_MIXER_SOURCE_OUTPUT_H #include #include "gvc-mixer-stream.h" G_BEGIN_DECLS #define GVC_TYPE_MIXER_SOURCE_OUTPUT (gvc_mixer_source_output_get_type ()) #define GVC_MIXER_SOURCE_OUTPUT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutput)) #define GVC_MIXER_SOURCE_OUTPUT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutputClass)) #define GVC_IS_MIXER_SOURCE_OUTPUT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT)) #define GVC_IS_MIXER_SOURCE_OUTPUT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SOURCE_OUTPUT)) #define GVC_MIXER_SOURCE_OUTPUT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutputClass)) typedef struct GvcMixerSourceOutputPrivate GvcMixerSourceOutputPrivate; typedef struct { GvcMixerStream parent; GvcMixerSourceOutputPrivate *priv; } GvcMixerSourceOutput; typedef struct { GvcMixerStreamClass parent_class; } GvcMixerSourceOutputClass; GType gvc_mixer_source_output_get_type (void); GvcMixerStream * gvc_mixer_source_output_new (pa_context *context, guint index, GvcChannelMap *map); G_END_DECLS #endif /* __GVC_MIXER_SOURCE_OUTPUT_H */ ukui-control-center/panels/volume-control/gvc-combo-box.c0000644000175000017500000003475013111751271022474 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2009 Bastien Nocera * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include "gvc-combo-box.h" #include "gvc-mixer-stream.h" #include "gvc-mixer-card.h" #define GVC_COMBO_BOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_COMBO_BOX, GvcComboBoxPrivate)) struct GvcComboBoxPrivate { GtkWidget *drop_box; GtkWidget *start_box; GtkWidget *end_box; GtkWidget *label; GtkWidget *button; GtkTreeModel *model; GtkWidget *combobox; gboolean set_called; GtkSizeGroup *size_group; gboolean symmetric; }; enum { COL_NAME, COL_HUMAN_NAME, NUM_COLS }; enum { CHANGED, BUTTON_CLICKED, LAST_SIGNAL }; enum { PROP_0, PROP_LABEL, PROP_SHOW_BUTTON, PROP_BUTTON_LABEL }; static guint signals [LAST_SIGNAL] = { 0, }; static void gvc_combo_box_class_init (GvcComboBoxClass *klass); static void gvc_combo_box_init (GvcComboBox *combo_box); static void gvc_combo_box_finalize (GObject *object); #if GTK_CHECK_VERSION (3, 0, 0) G_DEFINE_TYPE (GvcComboBox, gvc_combo_box, GTK_TYPE_BOX) #else G_DEFINE_TYPE (GvcComboBox, gvc_combo_box, GTK_TYPE_HBOX) #endif void gvc_combo_box_set_size_group (GvcComboBox *combo_box, GtkSizeGroup *group, gboolean symmetric) { g_return_if_fail (GVC_IS_COMBO_BOX (combo_box)); combo_box->priv->size_group = group; combo_box->priv->symmetric = symmetric; if (combo_box->priv->size_group != NULL) { gtk_size_group_add_widget (combo_box->priv->size_group, combo_box->priv->start_box); if (combo_box->priv->symmetric) { gtk_size_group_add_widget (combo_box->priv->size_group, combo_box->priv->end_box); } } gtk_widget_queue_draw (GTK_WIDGET (combo_box)); } static void gvc_combo_box_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GvcComboBox *self = GVC_COMBO_BOX (object); switch (prop_id) { case PROP_LABEL: gtk_label_set_text_with_mnemonic (GTK_LABEL (self->priv->label), g_value_get_string (value)); break; case PROP_BUTTON_LABEL: gtk_button_set_label (GTK_BUTTON (self->priv->button), g_value_get_string (value)); break; case PROP_SHOW_BUTTON: gtk_widget_set_visible (self->priv->button, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gvc_combo_box_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GvcComboBox *self = GVC_COMBO_BOX (object); switch (prop_id) { case PROP_LABEL: g_value_set_string (value, gtk_label_get_text (GTK_LABEL (self->priv->label))); break; case PROP_BUTTON_LABEL: g_value_set_string (value, gtk_button_get_label (GTK_BUTTON (self->priv->button))); break; case PROP_SHOW_BUTTON: g_value_set_boolean (value, gtk_widget_get_visible (self->priv->button)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gvc_combo_box_class_init (GvcComboBoxClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gvc_combo_box_finalize; object_class->set_property = gvc_combo_box_set_property; object_class->get_property = gvc_combo_box_get_property; g_object_class_install_property (object_class, PROP_LABEL, g_param_spec_string ("label", "label", "The combo box label", _("_Profile(_P):"), G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_SHOW_BUTTON, g_param_spec_boolean ("show-button", "show-button", "Whether to show the button", FALSE, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_BUTTON_LABEL, g_param_spec_string ("button-label", "button-label", "The button's label", "APPLICATION BUG", G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); signals [CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcComboBoxClass, changed), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); signals [BUTTON_CLICKED] = g_signal_new ("button-clicked", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcComboBoxClass, button_clicked), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); g_type_class_add_private (klass, sizeof (GvcComboBoxPrivate)); } void gvc_combo_box_set_profiles (GvcComboBox *combo_box, const GList *profiles) { const GList *l; g_return_if_fail (GVC_IS_COMBO_BOX (combo_box)); g_return_if_fail (combo_box->priv->set_called == FALSE); for (l = profiles; l != NULL; l = l->next) { GvcMixerCardProfile *p = l->data; gtk_list_store_insert_with_values (GTK_LIST_STORE (combo_box->priv->model), NULL, G_MAXINT, COL_NAME, p->profile, COL_HUMAN_NAME, p->human_profile, -1); } combo_box->priv->set_called = TRUE; } void gvc_combo_box_set_ports (GvcComboBox *combo_box, const GList *ports) { const GList *l; g_return_if_fail (GVC_IS_COMBO_BOX (combo_box)); g_return_if_fail (combo_box->priv->set_called == FALSE); for (l = ports; l != NULL; l = l->next) { GvcMixerStreamPort *p = l->data; gtk_list_store_insert_with_values (GTK_LIST_STORE (combo_box->priv->model), NULL, G_MAXINT, COL_NAME, p->port, COL_HUMAN_NAME, p->human_port, -1); } combo_box->priv->set_called = TRUE; } void gvc_combo_box_set_active (GvcComboBox *combo_box, const char *id) { GtkTreeIter iter; gboolean cont; cont = gtk_tree_model_get_iter_first (combo_box->priv->model, &iter); while (cont != FALSE) { char *name; gtk_tree_model_get (combo_box->priv->model, &iter, COL_NAME, &name, -1); if (g_strcmp0 (name, id) == 0) { gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box->priv->combobox), &iter); return; } gtk_tree_model_iter_next (combo_box->priv->model, &iter); } g_warning ("Could not find id '%s' in combo box", id); } static void on_combo_box_changed (GtkComboBox *widget, GvcComboBox *combo_box) { GtkTreeIter iter; char *profile; if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter) == FALSE) { g_warning ("Could not find an active profile or port"); return; } gtk_tree_model_get (combo_box->priv->model, &iter, COL_NAME, &profile, -1); g_signal_emit (combo_box, signals[CHANGED], 0, profile); g_free (profile); } static void on_combo_box_button_clicked (GtkButton *button, GvcComboBox *combo_box) { g_signal_emit (combo_box, signals[BUTTON_CLICKED], 0); } static void gvc_combo_box_init (GvcComboBox *combo_box) { GtkWidget *frame; GtkWidget *box; GtkWidget *sbox; GtkWidget *ebox; GtkCellRenderer *renderer; combo_box->priv = GVC_COMBO_BOX_GET_PRIVATE (combo_box); combo_box->priv->model = GTK_TREE_MODEL (gtk_list_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_STRING)); combo_box->priv->label = gtk_label_new (NULL); gtk_misc_set_alignment (GTK_MISC (combo_box->priv->label), 0.0, 0.5); /* frame */ frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE); gtk_container_add (GTK_CONTAINER (combo_box), frame); combo_box->priv->drop_box = box = gtk_hbox_new (FALSE, 6); combo_box->priv->combobox = gtk_combo_box_new_with_model (combo_box->priv->model); renderer = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box->priv->combobox), renderer, FALSE); gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->combobox), renderer, "text", COL_HUMAN_NAME); /* gtk_widget_set_size_request (combo_box->priv->combobox, 128, -1); */ combo_box->priv->start_box = sbox = gtk_hbox_new (FALSE, 6); gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (sbox), combo_box->priv->label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (box), combo_box->priv->combobox, TRUE, TRUE, 0); combo_box->priv->button = gtk_button_new_with_label ("APPLICATION BUG"); gtk_widget_set_no_show_all (GTK_WIDGET(combo_box->priv->button), TRUE); gtk_box_pack_start (GTK_BOX (box), combo_box->priv->button, FALSE, FALSE, 0); combo_box->priv->end_box = ebox = gtk_hbox_new (FALSE, 6); gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, FALSE, 0); if (combo_box->priv->size_group != NULL) { gtk_size_group_add_widget (combo_box->priv->size_group, sbox); if (combo_box->priv->symmetric) { gtk_size_group_add_widget (combo_box->priv->size_group, ebox); } } gtk_container_add (GTK_CONTAINER (frame), combo_box->priv->drop_box); gtk_widget_show_all (frame); gtk_label_set_mnemonic_widget (GTK_LABEL (combo_box->priv->label), combo_box->priv->combobox); g_signal_connect (G_OBJECT (combo_box->priv->combobox), "changed", G_CALLBACK (on_combo_box_changed), combo_box); g_signal_connect (G_OBJECT (combo_box->priv->button), "clicked", G_CALLBACK (on_combo_box_button_clicked), combo_box); } static void gvc_combo_box_finalize (GObject *object) { GvcComboBox *combo_box; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_COMBO_BOX (object)); combo_box = GVC_COMBO_BOX (object); g_return_if_fail (combo_box->priv != NULL); g_object_unref (combo_box->priv->model); combo_box->priv->model = NULL; G_OBJECT_CLASS (gvc_combo_box_parent_class)->finalize (object); } GtkWidget * gvc_combo_box_new (const char *label) { GObject *combo_box; combo_box = g_object_new (GVC_TYPE_COMBO_BOX, "label", label, NULL); return GTK_WIDGET (combo_box); } ukui-control-center/panels/volume-control/gvc-combo-box.h0000664000175000017500000000556513057175444022520 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2009 Red Hat, Inc. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __GVC_COMBO_BOX_H #define __GVC_COMBO_BOX_H #include G_BEGIN_DECLS #define GVC_TYPE_COMBO_BOX (gvc_combo_box_get_type ()) #define GVC_COMBO_BOX(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_COMBO_BOX, GvcComboBox)) #define GVC_COMBO_BOX_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_COMBO_BOX, GvcComboBoxClass)) #define GVC_IS_COMBO_BOX(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_COMBO_BOX)) #define GVC_IS_COMBO_BOX_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_COMBO_BOX)) #define GVC_COMBO_BOX_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_COMBO_BOX, GvcComboBoxClass)) typedef struct GvcComboBoxPrivate GvcComboBoxPrivate; typedef struct { #if GTK_CHECK_VERSION (3, 0, 0) GtkBox parent; #else GtkHBox parent; #endif GvcComboBoxPrivate *priv; } GvcComboBox; typedef struct { #if GTK_CHECK_VERSION (3, 0, 0) GtkBoxClass parent_class; #else GtkHBoxClass parent_class; #endif void (* changed) (GvcComboBox *combobox, const char *name); void (* button_clicked) (GvcComboBox *combobox); } GvcComboBoxClass; GType gvc_combo_box_get_type (void); GtkWidget * gvc_combo_box_new (const char *label); void gvc_combo_box_set_size_group (GvcComboBox *combo_box, GtkSizeGroup *group, gboolean symmetric); void gvc_combo_box_set_profiles (GvcComboBox *combo_box, const GList *profiles); void gvc_combo_box_set_ports (GvcComboBox *combo_box, const GList *ports); void gvc_combo_box_set_active (GvcComboBox *combo_box, const char *id); G_END_DECLS #endif /* __GVC_COMBO_BOX_H */ ukui-control-center/panels/volume-control/dialog-main.h0000664000175000017500000000171613057175444022231 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include void add_volume_control_app(GtkBuilder * builer); void destroy_volume_control(); ukui-control-center/panels/volume-control/gvc-mixer-source-output.c0000664000175000017500000001014213057175444024571 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include "gvc-mixer-source-output.h" #define GVC_MIXER_SOURCE_OUTPUT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutputPrivate)) struct GvcMixerSourceOutputPrivate { gpointer dummy; }; static void gvc_mixer_source_output_class_init (GvcMixerSourceOutputClass *klass); static void gvc_mixer_source_output_init (GvcMixerSourceOutput *mixer_source_output); static void gvc_mixer_source_output_finalize (GObject *object); G_DEFINE_TYPE (GvcMixerSourceOutput, gvc_mixer_source_output, GVC_TYPE_MIXER_STREAM) static gboolean gvc_mixer_source_output_push_volume (GvcMixerStream *stream, gpointer *op) { /* FIXME: */ *op = NULL; return TRUE; } static gboolean gvc_mixer_source_output_change_is_muted (GvcMixerStream *stream, gboolean is_muted) { /* FIXME: */ return TRUE; } static GObject * gvc_mixer_source_output_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; GvcMixerSourceOutput *self; object = G_OBJECT_CLASS (gvc_mixer_source_output_parent_class)->constructor (type, n_construct_properties, construct_params); self = GVC_MIXER_SOURCE_OUTPUT (object); return object; } static void gvc_mixer_source_output_class_init (GvcMixerSourceOutputClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass); object_class->constructor = gvc_mixer_source_output_constructor; object_class->finalize = gvc_mixer_source_output_finalize; stream_class->push_volume = gvc_mixer_source_output_push_volume; stream_class->change_is_muted = gvc_mixer_source_output_change_is_muted; g_type_class_add_private (klass, sizeof (GvcMixerSourceOutputPrivate)); } static void gvc_mixer_source_output_init (GvcMixerSourceOutput *source_output) { source_output->priv = GVC_MIXER_SOURCE_OUTPUT_GET_PRIVATE (source_output); } static void gvc_mixer_source_output_finalize (GObject *object) { GvcMixerSourceOutput *mixer_source_output; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_SOURCE_OUTPUT (object)); mixer_source_output = GVC_MIXER_SOURCE_OUTPUT (object); g_return_if_fail (mixer_source_output->priv != NULL); G_OBJECT_CLASS (gvc_mixer_source_output_parent_class)->finalize (object); } GvcMixerStream * gvc_mixer_source_output_new (pa_context *context, guint index, GvcChannelMap *channel_map) { GObject *object; object = g_object_new (GVC_TYPE_MIXER_SOURCE_OUTPUT, "pa-context", context, "index", index, "channel-map", channel_map, NULL); return GVC_MIXER_STREAM (object); } ukui-control-center/panels/volume-control/gvc-mixer-control.h0000664000175000017500000001131113057175444023417 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __GVC_MIXER_CONTROL_H #define __GVC_MIXER_CONTROL_H #include #include #include "gvc-mixer-stream.h" #include "gvc-mixer-card.h" G_BEGIN_DECLS #define GVC_TYPE_MIXER_CONTROL (gvc_mixer_control_get_type ()) #define GVC_MIXER_CONTROL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_CONTROL, GvcMixerControl)) #define GVC_MIXER_CONTROL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_CONTROL, GvcMixerControlClass)) #define GVC_IS_MIXER_CONTROL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_CONTROL)) #define GVC_IS_MIXER_CONTROL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_CONTROL)) #define GVC_MIXER_CONTROL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_CONTROL, GvcMixerControlClass)) typedef struct GvcMixerControlPrivate GvcMixerControlPrivate; typedef struct { GObject parent; GvcMixerControlPrivate *priv; } GvcMixerControl; typedef struct { GObjectClass parent_class; void (*connecting) (GvcMixerControl *control); void (*ready) (GvcMixerControl *control); void (*stream_added) (GvcMixerControl *control, guint id); void (*stream_removed) (GvcMixerControl *control, guint id); void (*card_added) (GvcMixerControl *control, guint id); void (*card_removed) (GvcMixerControl *control, guint id); void (*default_sink_changed) (GvcMixerControl *control, guint id); void (*default_source_changed) (GvcMixerControl *control, guint id); } GvcMixerControlClass; GType gvc_mixer_control_get_type (void); GvcMixerControl * gvc_mixer_control_new (const char *name); gboolean gvc_mixer_control_open (GvcMixerControl *control); gboolean gvc_mixer_control_close (GvcMixerControl *control); gboolean gvc_mixer_control_is_ready (GvcMixerControl *control); pa_context * gvc_mixer_control_get_pa_context (GvcMixerControl *control); GSList * gvc_mixer_control_get_cards (GvcMixerControl *control); GSList * gvc_mixer_control_get_streams (GvcMixerControl *control); GSList * gvc_mixer_control_get_sinks (GvcMixerControl *control); GSList * gvc_mixer_control_get_sources (GvcMixerControl *control); GSList * gvc_mixer_control_get_sink_inputs (GvcMixerControl *control); GSList * gvc_mixer_control_get_source_outputs (GvcMixerControl *control); GvcMixerStream * gvc_mixer_control_lookup_stream_id (GvcMixerControl *control, guint id); GvcMixerCard * gvc_mixer_control_lookup_card_id (GvcMixerControl *control, guint id); GvcMixerStream * gvc_mixer_control_get_default_sink (GvcMixerControl *control); GvcMixerStream * gvc_mixer_control_get_default_source (GvcMixerControl *control); GvcMixerStream * gvc_mixer_control_get_event_sink_input (GvcMixerControl *control); gboolean gvc_mixer_control_set_default_sink (GvcMixerControl *control, GvcMixerStream *stream); gboolean gvc_mixer_control_set_default_source (GvcMixerControl *control, GvcMixerStream *stream); G_END_DECLS #endif /* __GVC_MIXER_CONTROL_H */ ukui-control-center/panels/volume-control/gvc-balance-bar.c0000664000175000017500000004767713245450076022763 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include "gvc-balance-bar.h" #define SCALE_SIZE 256 #define ADJUSTMENT_MAX_NORMAL 65536.0 /* PA_VOLUME_NORM */ #define GVC_BALANCE_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_BALANCE_BAR, GvcBalanceBarPrivate)) struct GvcBalanceBarPrivate { GvcChannelMap *channel_map; GvcBalanceType btype; GtkWidget *scale_box; GtkWidget *start_box; GtkWidget *end_box; GtkWidget *label; GtkWidget *scale; GtkAdjustment *adjustment; GtkSizeGroup *size_group; gboolean symmetric; gboolean click_lock; }; enum { PROP_0, PROP_CHANNEL_MAP, PROP_BALANCE_TYPE, }; static void gvc_balance_bar_class_init (GvcBalanceBarClass *klass); static void gvc_balance_bar_init (GvcBalanceBar *balance_bar); static void gvc_balance_bar_finalize (GObject *object); static gboolean on_scale_button_press_event (GtkWidget *widget, GdkEventButton *event, GvcBalanceBar *bar); static gboolean on_scale_button_release_event (GtkWidget *widget, GdkEventButton *event, GvcBalanceBar *bar); static gboolean on_scale_scroll_event (GtkWidget *widget, GdkEventScroll *event, GvcBalanceBar *bar); static void on_adjustment_value_changed (GtkAdjustment *adjustment, GvcBalanceBar *bar); #if GTK_CHECK_VERSION (3, 0, 0) G_DEFINE_TYPE (GvcBalanceBar, gvc_balance_bar, GTK_TYPE_BOX) #else G_DEFINE_TYPE (GvcBalanceBar, gvc_balance_bar, GTK_TYPE_HBOX) #endif static GtkWidget * _scale_box_new (GvcBalanceBar *bar) { GvcBalanceBarPrivate *priv = bar->priv; GtkWidget *box; GtkWidget *sbox; GtkWidget *ebox; GtkAdjustment *adjustment = bar->priv->adjustment; char *str_lower, *str_upper; gdouble lower, upper; bar->priv->scale_box = box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); priv->scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, priv->adjustment); gtk_widget_set_size_request (priv->scale, SCALE_SIZE, -1); gtk_widget_set_name (priv->scale, "balance-bar-scale"); gtk_rc_parse_string ("style \"balance-bar-scale-style\" {\n" " GtkScale::trough-side-details = 0\n" "}\n" "widget \"*.balance-bar-scale\" style : rc \"balance-bar-scale-style\"\n"); bar->priv->start_box = sbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (sbox), priv->label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (box), priv->scale, TRUE, TRUE, 0); switch (bar->priv->btype) { case BALANCE_TYPE_RL: str_lower = g_strdup_printf ("%s", _("Left")); str_upper = g_strdup_printf ("%s", _("Right")); break; case BALANCE_TYPE_FR: str_lower = g_strdup_printf ("%s", _("Rear")); str_upper = g_strdup_printf ("%s", _("Front")); break; case BALANCE_TYPE_LFE: str_lower = g_strdup_printf ("%s", _("Minimum")); str_upper = g_strdup_printf ("%s", _("Maximum")); break; default: g_assert_not_reached (); } lower = gtk_adjustment_get_lower (adjustment); gtk_scale_add_mark (GTK_SCALE (priv->scale), lower, GTK_POS_BOTTOM, str_lower); g_free (str_lower); upper = gtk_adjustment_get_upper (adjustment); gtk_scale_add_mark (GTK_SCALE (priv->scale), upper, GTK_POS_BOTTOM, str_upper); g_free (str_upper); if (bar->priv->btype != BALANCE_TYPE_LFE) { gtk_scale_add_mark (GTK_SCALE (priv->scale), (upper - lower)/2 + lower, GTK_POS_BOTTOM, NULL); } bar->priv->end_box = ebox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, FALSE, 0); #if !GTK_CHECK_VERSION (3, 0, 0) gtk_range_set_update_policy (GTK_RANGE (priv->scale), GTK_UPDATE_CONTINUOUS); #endif ca_gtk_widget_disable_sounds (bar->priv->scale, FALSE); gtk_widget_add_events (bar->priv->scale, GDK_SCROLL_MASK); g_signal_connect (G_OBJECT (bar->priv->scale), "button-press-event", G_CALLBACK (on_scale_button_press_event), bar); g_signal_connect (G_OBJECT (bar->priv->scale), "button-release-event", G_CALLBACK (on_scale_button_release_event), bar); g_signal_connect (G_OBJECT (bar->priv->scale), "scroll-event", G_CALLBACK (on_scale_scroll_event), bar); if (bar->priv->size_group != NULL) { gtk_size_group_add_widget (bar->priv->size_group, sbox); if (bar->priv->symmetric) { gtk_size_group_add_widget (bar->priv->size_group, ebox); } } gtk_scale_set_draw_value (GTK_SCALE (priv->scale), FALSE); return box; } void gvc_balance_bar_set_size_group (GvcBalanceBar *bar, GtkSizeGroup *group, gboolean symmetric) { g_return_if_fail (GVC_IS_BALANCE_BAR (bar)); bar->priv->size_group = group; bar->priv->symmetric = symmetric; if (bar->priv->size_group != NULL) { gtk_size_group_add_widget (bar->priv->size_group, bar->priv->start_box); if (bar->priv->symmetric) { gtk_size_group_add_widget (bar->priv->size_group, bar->priv->end_box); } } gtk_widget_queue_draw (GTK_WIDGET (bar)); } static const char * btype_to_string (guint btype) { switch (btype) { case BALANCE_TYPE_RL: return "Balance"; case BALANCE_TYPE_FR: return "Fade"; break; case BALANCE_TYPE_LFE: return "LFE"; default: g_assert_not_reached (); } return NULL; } static void update_level_from_map (GvcBalanceBar *bar, GvcChannelMap *map) { const gdouble *volumes; gdouble val; g_debug ("Volume changed (for %s bar)", btype_to_string (bar->priv->btype)); volumes = gvc_channel_map_get_volume (map); switch (bar->priv->btype) { case BALANCE_TYPE_RL: val = volumes[BALANCE]; break; case BALANCE_TYPE_FR: val = volumes[FADE]; break; case BALANCE_TYPE_LFE: val = volumes[LFE]; break; default: g_assert_not_reached (); } gtk_adjustment_set_value (bar->priv->adjustment, val); } static void on_channel_map_volume_changed (GvcChannelMap *map, gboolean set, GvcBalanceBar *bar) { update_level_from_map (bar, map); } static void gvc_balance_bar_set_channel_map (GvcBalanceBar *bar, GvcChannelMap *map) { g_return_if_fail (GVC_BALANCE_BAR (bar)); if (bar->priv->channel_map != NULL) { g_signal_handlers_disconnect_by_func (G_OBJECT (bar->priv->channel_map), on_channel_map_volume_changed, bar); g_object_unref (bar->priv->channel_map); } bar->priv->channel_map = g_object_ref (map); update_level_from_map (bar, map); g_signal_connect (G_OBJECT (map), "volume-changed", G_CALLBACK (on_channel_map_volume_changed), bar); g_object_notify (G_OBJECT (bar), "channel-map"); } static void gvc_balance_bar_set_balance_type (GvcBalanceBar *bar, GvcBalanceType btype) { GtkWidget *frame; g_return_if_fail (GVC_BALANCE_BAR (bar)); bar->priv->btype = btype; if (bar->priv->btype != BALANCE_TYPE_LFE) { bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, -1.0, 1.0, 0.5, 0.5, 0.0)); } else { bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, ADJUSTMENT_MAX_NORMAL, ADJUSTMENT_MAX_NORMAL/100.0, ADJUSTMENT_MAX_NORMAL/10.0, 0.0)); } g_object_ref_sink (bar->priv->adjustment); g_signal_connect (bar->priv->adjustment, "value-changed", G_CALLBACK (on_adjustment_value_changed), bar); switch (btype) { case BALANCE_TYPE_RL: bar->priv->label = gtk_label_new_with_mnemonic (_("_Balance(_B):")); break; case BALANCE_TYPE_FR: bar->priv->label = gtk_label_new_with_mnemonic (_("_Fade(_F):")); break; case BALANCE_TYPE_LFE: bar->priv->label = gtk_label_new_with_mnemonic (_("_Subwoofer(_S):")); break; default: g_assert_not_reached (); } gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0.0, 0.0); /* frame */ frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE); gtk_container_add (GTK_CONTAINER (bar), frame); /* box with scale */ bar->priv->scale_box = _scale_box_new (bar); gtk_container_add (GTK_CONTAINER (frame), bar->priv->scale_box); gtk_widget_show_all (frame); gtk_widget_set_direction (bar->priv->scale, GTK_TEXT_DIR_LTR); gtk_label_set_mnemonic_widget (GTK_LABEL (bar->priv->label), bar->priv->scale); g_object_notify (G_OBJECT (bar), "balance-type"); } static void gvc_balance_bar_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GvcBalanceBar *self = GVC_BALANCE_BAR (object); switch (prop_id) { case PROP_CHANNEL_MAP: gvc_balance_bar_set_channel_map (self, g_value_get_object (value)); break; case PROP_BALANCE_TYPE: gvc_balance_bar_set_balance_type (self, g_value_get_int (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gvc_balance_bar_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GvcBalanceBar *self = GVC_BALANCE_BAR (object); switch (prop_id) { case PROP_CHANNEL_MAP: g_value_set_object (value, self->priv->channel_map); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GObject * gvc_balance_bar_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { return G_OBJECT_CLASS (gvc_balance_bar_parent_class)->constructor (type, n_construct_properties, construct_params); } static void gvc_balance_bar_class_init (GvcBalanceBarClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = gvc_balance_bar_constructor; object_class->finalize = gvc_balance_bar_finalize; object_class->set_property = gvc_balance_bar_set_property; object_class->get_property = gvc_balance_bar_get_property; g_object_class_install_property (object_class, PROP_CHANNEL_MAP, g_param_spec_object ("channel-map", "channel map", "The channel map", GVC_TYPE_CHANNEL_MAP, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_BALANCE_TYPE, g_param_spec_int ("balance-type", "balance type", "Whether the balance is right-left or front-rear", BALANCE_TYPE_RL, NUM_BALANCE_TYPES - 1, BALANCE_TYPE_RL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); g_type_class_add_private (klass, sizeof (GvcBalanceBarPrivate)); } static gboolean on_scale_button_press_event (GtkWidget *widget, GdkEventButton *event, GvcBalanceBar *bar) { bar->priv->click_lock = TRUE; return FALSE; } static gboolean on_scale_button_release_event (GtkWidget *widget, GdkEventButton *event, GvcBalanceBar *bar) { bar->priv->click_lock = FALSE; return FALSE; } static gboolean on_scale_scroll_event (GtkWidget *widget, GdkEventScroll *event, GvcBalanceBar *bar) { gdouble value; value = gtk_adjustment_get_value (bar->priv->adjustment); if (bar->priv->btype == BALANCE_TYPE_LFE) { if (event->direction == GDK_SCROLL_UP) { if (value + ADJUSTMENT_MAX_NORMAL/100.0 > ADJUSTMENT_MAX_NORMAL) value = ADJUSTMENT_MAX_NORMAL; else value = value + ADJUSTMENT_MAX_NORMAL/100.0; } else if (event->direction == GDK_SCROLL_DOWN) { if (value - ADJUSTMENT_MAX_NORMAL/100.0 < 0) value = 0.0; else value = value - ADJUSTMENT_MAX_NORMAL/100.0; } } else { if (event->direction == GDK_SCROLL_UP) { if (value + 0.01 > 1.0) value = 1.0; else value = value + 0.01; } else if (event->direction == GDK_SCROLL_DOWN) { if (value - 0.01 < 0) value = 0.0; else value = value - 0.01; } } gtk_adjustment_set_value (bar->priv->adjustment, value); return TRUE; } /* FIXME remove when we depend on a newer PA */ static pa_cvolume * gvc_pa_cvolume_set_position (pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t, pa_volume_t v) { unsigned c; gboolean good = FALSE; g_assert(cv); g_assert(map); g_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), NULL); g_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, NULL); for (c = 0; c < map->channels; c++) if (map->map[c] == t) { cv->values[c] = v; good = TRUE; } return good ? cv : NULL; } static void on_adjustment_value_changed (GtkAdjustment *adjustment, GvcBalanceBar *bar) { gdouble val; pa_cvolume cv; const pa_channel_map *pa_map; if (bar->priv->channel_map == NULL) return; cv = *gvc_channel_map_get_cvolume (bar->priv->channel_map); val = gtk_adjustment_get_value (adjustment); pa_map = gvc_channel_map_get_pa_channel_map (bar->priv->channel_map); switch (bar->priv->btype) { case BALANCE_TYPE_RL: pa_cvolume_set_balance (&cv, pa_map, val); break; case BALANCE_TYPE_FR: pa_cvolume_set_fade (&cv, pa_map, val); break; case BALANCE_TYPE_LFE: gvc_pa_cvolume_set_position (&cv, pa_map, PA_CHANNEL_POSITION_LFE, val); break; } gvc_channel_map_volume_changed (bar->priv->channel_map, &cv, TRUE); } static void gvc_balance_bar_init (GvcBalanceBar *bar) { bar->priv = GVC_BALANCE_BAR_GET_PRIVATE (bar); } static void gvc_balance_bar_finalize (GObject *object) { GvcBalanceBar *bar; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_BALANCE_BAR (object)); bar = GVC_BALANCE_BAR (object); g_return_if_fail (bar->priv != NULL); if (bar->priv->channel_map != NULL) { g_signal_handlers_disconnect_by_func (G_OBJECT (bar->priv->channel_map), on_channel_map_volume_changed, bar); g_object_unref (bar->priv->channel_map); } G_OBJECT_CLASS (gvc_balance_bar_parent_class)->finalize (object); } GtkWidget * gvc_balance_bar_new (const GvcChannelMap *channel_map, GvcBalanceType btype) { GObject *bar; bar = g_object_new (GVC_TYPE_BALANCE_BAR, "channel-map", channel_map, "balance-type", btype, NULL); return GTK_WIDGET (bar); } ukui-control-center/panels/volume-control/gvc-mixer-card.c0000664000175000017500000004144213057175444022653 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * Copyright (C) 2009 Bastien Nocera * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include "gvc-mixer-card.h" #define GVC_MIXER_CARD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_CARD, GvcMixerCardPrivate)) static guint32 card_serial = 1; struct GvcMixerCardPrivate { pa_context *pa_context; guint id; guint index; char *name; char *icon_name; char *profile; char *target_profile; char *human_profile; GList *profiles; pa_operation *profile_op; }; enum { PROP_0, PROP_ID, PROP_PA_CONTEXT, PROP_INDEX, PROP_NAME, PROP_ICON_NAME, PROP_PROFILE, PROP_HUMAN_PROFILE, }; static void gvc_mixer_card_class_init (GvcMixerCardClass *klass); static void gvc_mixer_card_init (GvcMixerCard *mixer_card); static void gvc_mixer_card_finalize (GObject *object); G_DEFINE_TYPE (GvcMixerCard, gvc_mixer_card, G_TYPE_OBJECT) static guint32 get_next_card_serial (void) { guint32 serial; serial = card_serial++; if ((gint32)card_serial < 0) { card_serial = 1; } return serial; } pa_context * gvc_mixer_card_get_pa_context (GvcMixerCard *card) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0); return card->priv->pa_context; } guint gvc_mixer_card_get_index (GvcMixerCard *card) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0); return card->priv->index; } guint gvc_mixer_card_get_id (GvcMixerCard *card) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0); return card->priv->id; } const char * gvc_mixer_card_get_name (GvcMixerCard *card) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL); return card->priv->name; } gboolean gvc_mixer_card_set_name (GvcMixerCard *card, const char *name) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE); g_free (card->priv->name); card->priv->name = g_strdup (name); g_object_notify (G_OBJECT (card), "name"); return TRUE; } const char * gvc_mixer_card_get_icon_name (GvcMixerCard *card) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL); return card->priv->icon_name; } gboolean gvc_mixer_card_set_icon_name (GvcMixerCard *card, const char *icon_name) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE); g_free (card->priv->icon_name); card->priv->icon_name = g_strdup (icon_name); g_object_notify (G_OBJECT (card), "icon-name"); return TRUE; } GvcMixerCardProfile * gvc_mixer_card_get_profile (GvcMixerCard *card) { GList *l; g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL); g_return_val_if_fail (card->priv->profiles != NULL, FALSE); for (l = card->priv->profiles; l != NULL; l = l->next) { GvcMixerCardProfile *p = l->data; if (g_str_equal (card->priv->profile, p->profile)) { return p; } } g_assert_not_reached (); return NULL; } gboolean gvc_mixer_card_set_profile (GvcMixerCard *card, const char *profile) { GList *l; g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE); g_return_val_if_fail (card->priv->profiles != NULL, FALSE); g_free (card->priv->profile); card->priv->profile = g_strdup (profile); g_free (card->priv->human_profile); card->priv->human_profile = NULL; for (l = card->priv->profiles; l != NULL; l = l->next) { GvcMixerCardProfile *p = l->data; if (g_str_equal (card->priv->profile, p->profile)) { card->priv->human_profile = g_strdup (p->human_profile); break; } } g_object_notify (G_OBJECT (card), "profile"); return TRUE; } static void _pa_context_set_card_profile_by_index_cb (pa_context *context, int success, void *userdata) { GvcMixerCard *card = GVC_MIXER_CARD (userdata); g_assert (card->priv->target_profile); if (success > 0) { gvc_mixer_card_set_profile (card, card->priv->target_profile); } else { g_debug ("Failed to switch profile on '%s' from '%s' to '%s'", card->priv->name, card->priv->profile, card->priv->target_profile); } g_free (card->priv->target_profile); card->priv->target_profile = NULL; pa_operation_unref (card->priv->profile_op); card->priv->profile_op = NULL; } gboolean gvc_mixer_card_change_profile (GvcMixerCard *card, const char *profile) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE); g_return_val_if_fail (card->priv->profiles != NULL, FALSE); /* Same profile, or already requested? */ if (g_strcmp0 (card->priv->profile, profile) == 0) return TRUE; if (g_strcmp0 (profile, card->priv->target_profile) == 0) return TRUE; if (card->priv->profile_op != NULL) { pa_operation_cancel (card->priv->profile_op); pa_operation_unref (card->priv->profile_op); card->priv->profile_op = NULL; } if (card->priv->profile != NULL) { g_free (card->priv->target_profile); card->priv->target_profile = g_strdup (profile); card->priv->profile_op = pa_context_set_card_profile_by_index (card->priv->pa_context, card->priv->index, card->priv->target_profile, _pa_context_set_card_profile_by_index_cb, card); if (card->priv->profile_op == NULL) { g_warning ("pa_context_set_card_profile_by_index() failed"); return FALSE; } } else { g_assert (card->priv->human_profile == NULL); card->priv->profile = g_strdup (profile); } return TRUE; } const GList * gvc_mixer_card_get_profiles (GvcMixerCard *card) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE); return card->priv->profiles; } static int sort_profiles (GvcMixerCardProfile *a, GvcMixerCardProfile *b) { if (a->priority == b->priority) return 0; if (a->priority > b->priority) return 1; return -1; } gboolean gvc_mixer_card_set_profiles (GvcMixerCard *card, GList *profiles) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE); g_return_val_if_fail (card->priv->profiles == NULL, FALSE); card->priv->profiles = g_list_sort (profiles, (GCompareFunc) sort_profiles); return TRUE; } static void gvc_mixer_card_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GvcMixerCard *self = GVC_MIXER_CARD (object); switch (prop_id) { case PROP_PA_CONTEXT: self->priv->pa_context = g_value_get_pointer (value); break; case PROP_INDEX: self->priv->index = g_value_get_ulong (value); break; case PROP_ID: self->priv->id = g_value_get_ulong (value); break; case PROP_NAME: gvc_mixer_card_set_name (self, g_value_get_string (value)); break; case PROP_ICON_NAME: gvc_mixer_card_set_icon_name (self, g_value_get_string (value)); break; case PROP_PROFILE: gvc_mixer_card_set_profile (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gvc_mixer_card_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GvcMixerCard *self = GVC_MIXER_CARD (object); switch (prop_id) { case PROP_PA_CONTEXT: g_value_set_pointer (value, self->priv->pa_context); break; case PROP_INDEX: g_value_set_ulong (value, self->priv->index); break; case PROP_ID: g_value_set_ulong (value, self->priv->id); break; case PROP_NAME: g_value_set_string (value, self->priv->name); break; case PROP_ICON_NAME: g_value_set_string (value, self->priv->icon_name); break; case PROP_PROFILE: g_value_set_string (value, self->priv->profile); break; case PROP_HUMAN_PROFILE: g_value_set_string (value, self->priv->human_profile); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GObject * gvc_mixer_card_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; GvcMixerCard *self; object = G_OBJECT_CLASS (gvc_mixer_card_parent_class)->constructor (type, n_construct_properties, construct_params); self = GVC_MIXER_CARD (object); self->priv->id = get_next_card_serial (); return object; } static void gvc_mixer_card_class_init (GvcMixerCardClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->constructor = gvc_mixer_card_constructor; gobject_class->finalize = gvc_mixer_card_finalize; gobject_class->set_property = gvc_mixer_card_set_property; gobject_class->get_property = gvc_mixer_card_get_property; g_object_class_install_property (gobject_class, PROP_INDEX, g_param_spec_ulong ("index", "Index", "The index for this card", 0, G_MAXULONG, 0, G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (gobject_class, PROP_ID, g_param_spec_ulong ("id", "id", "The id for this card", 0, G_MAXULONG, 0, G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (gobject_class, PROP_PA_CONTEXT, g_param_spec_pointer ("pa-context", "PulseAudio context", "The PulseAudio context for this card", G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (gobject_class, PROP_NAME, g_param_spec_string ("name", "Name", "Name to display for this card", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_ICON_NAME, g_param_spec_string ("icon-name", "Icon Name", "Name of icon to display for this card", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_PROFILE, g_param_spec_string ("profile", "Profile", "Name of current profile for this card", NULL, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_HUMAN_PROFILE, g_param_spec_string ("human-profile", "Profile (Human readable)", "Name of current profile for this card in human readable form", NULL, G_PARAM_READABLE)); g_type_class_add_private (klass, sizeof (GvcMixerCardPrivate)); } static void gvc_mixer_card_init (GvcMixerCard *card) { card->priv = GVC_MIXER_CARD_GET_PRIVATE (card); } GvcMixerCard * gvc_mixer_card_new (pa_context *context, guint index) { GObject *object; object = g_object_new (GVC_TYPE_MIXER_CARD, "index", index, "pa-context", context, NULL); return GVC_MIXER_CARD (object); } static void free_profile (GvcMixerCardProfile *p) { g_free (p->profile); g_free (p->human_profile); g_free (p->status); g_free (p); } static void gvc_mixer_card_finalize (GObject *object) { GvcMixerCard *mixer_card; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_CARD (object)); mixer_card = GVC_MIXER_CARD (object); g_return_if_fail (mixer_card->priv != NULL); g_free (mixer_card->priv->name); mixer_card->priv->name = NULL; g_free (mixer_card->priv->icon_name); mixer_card->priv->icon_name = NULL; g_free (mixer_card->priv->target_profile); mixer_card->priv->target_profile = NULL; g_free (mixer_card->priv->profile); mixer_card->priv->profile = NULL; g_free (mixer_card->priv->human_profile); mixer_card->priv->human_profile = NULL; g_list_foreach (mixer_card->priv->profiles, (GFunc) free_profile, NULL); g_list_free (mixer_card->priv->profiles); mixer_card->priv->profiles = NULL; G_OBJECT_CLASS (gvc_mixer_card_parent_class)->finalize (object); } ukui-control-center/panels/volume-control/gvc-channel-map.h0000664000175000017500000000665313057175444023015 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __GVC_CHANNEL_MAP_H #define __GVC_CHANNEL_MAP_H #include #include G_BEGIN_DECLS #define GVC_TYPE_CHANNEL_MAP (gvc_channel_map_get_type ()) #define GVC_CHANNEL_MAP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_CHANNEL_MAP, GvcChannelMap)) #define GVC_CHANNEL_MAP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_CHANNEL_MAP, GvcChannelMapClass)) #define GVC_IS_CHANNEL_MAP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_CHANNEL_MAP)) #define GVC_IS_CHANNEL_MAP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_CHANNEL_MAP)) #define GVC_CHANNEL_MAP_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_CHANNEL_MAP, GvcChannelMapClass)) typedef struct GvcChannelMapPrivate GvcChannelMapPrivate; typedef struct { GObject parent; GvcChannelMapPrivate *priv; } GvcChannelMap; typedef struct { GObjectClass parent_class; void (*volume_changed) (GvcChannelMap *channel_map, gboolean set); } GvcChannelMapClass; enum { VOLUME, BALANCE, FADE, LFE, }; #define NUM_TYPES LFE + 1 GType gvc_channel_map_get_type (void); GvcChannelMap * gvc_channel_map_new (void); GvcChannelMap * gvc_channel_map_new_from_pa_channel_map (const pa_channel_map *map); guint gvc_channel_map_get_num_channels (const GvcChannelMap *map); const gdouble * gvc_channel_map_get_volume (GvcChannelMap *map); gboolean gvc_channel_map_can_balance (const GvcChannelMap *map); gboolean gvc_channel_map_can_fade (const GvcChannelMap *map); gboolean gvc_channel_map_has_position (const GvcChannelMap *map, pa_channel_position_t position); #define gvc_channel_map_has_lfe(x) gvc_channel_map_has_position (x, PA_CHANNEL_POSITION_LFE) void gvc_channel_map_volume_changed (GvcChannelMap *map, const pa_cvolume *cv, gboolean set); const char * gvc_channel_map_get_mapping (const GvcChannelMap *map); /* private */ const pa_cvolume * gvc_channel_map_get_cvolume (const GvcChannelMap *map); const pa_channel_map * gvc_channel_map_get_pa_channel_map (const GvcChannelMap *map); G_END_DECLS #endif /* __GVC_CHANNEL_MAP_H */ ukui-control-center/panels/volume-control/gvc-channel-bar.h0000664000175000017500000001027513057175444022777 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __GVC_CHANNEL_BAR_H #define __GVC_CHANNEL_BAR_H #include G_BEGIN_DECLS #define GVC_TYPE_CHANNEL_BAR (gvc_channel_bar_get_type ()) #define GVC_CHANNEL_BAR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_CHANNEL_BAR, GvcChannelBar)) #define GVC_CHANNEL_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_CHANNEL_BAR, GvcChannelBarClass)) #define GVC_IS_CHANNEL_BAR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_CHANNEL_BAR)) #define GVC_IS_CHANNEL_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_CHANNEL_BAR)) #define GVC_CHANNEL_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_CHANNEL_BAR, GvcChannelBarClass)) typedef struct GvcChannelBarPrivate GvcChannelBarPrivate; typedef struct { #if GTK_CHECK_VERSION (3, 0, 0) GtkBox parent; #else GtkHBox parent; #endif GvcChannelBarPrivate *priv; } GvcChannelBar; typedef struct { #if GTK_CHECK_VERSION (3, 0, 0) GtkBoxClass parent_class; #else GtkHBoxClass parent_class; #endif } GvcChannelBarClass; GType gvc_channel_bar_get_type (void); GtkWidget * gvc_channel_bar_new (void); void gvc_channel_bar_set_name (GvcChannelBar *bar, const char *name); void gvc_channel_bar_set_icon_name (GvcChannelBar *bar, const char *icon_name); void gvc_channel_bar_set_low_icon_name (GvcChannelBar *bar, const char *icon_name); void gvc_channel_bar_set_high_icon_name (GvcChannelBar *bar, const char *icon_name); void gvc_channel_bar_set_orientation (GvcChannelBar *bar, GtkOrientation orientation); GtkOrientation gvc_channel_bar_get_orientation (GvcChannelBar *bar); GtkAdjustment * gvc_channel_bar_get_adjustment (GvcChannelBar *bar); gboolean gvc_channel_bar_get_is_muted (GvcChannelBar *bar); void gvc_channel_bar_set_is_muted (GvcChannelBar *bar, gboolean is_muted); gboolean gvc_channel_bar_get_show_mute (GvcChannelBar *bar); void gvc_channel_bar_set_show_mute (GvcChannelBar *bar, gboolean show_mute); void gvc_channel_bar_set_size_group (GvcChannelBar *bar, GtkSizeGroup *group, gboolean symmetric); void gvc_channel_bar_set_is_amplified (GvcChannelBar *bar, gboolean amplified); void gvc_channel_bar_set_base_volume (GvcChannelBar *bar, guint32 base_volume); gboolean gvc_channel_bar_scroll (GvcChannelBar *bar, GdkScrollDirection direction); G_END_DECLS #endif /* __GVC_CHANNEL_BAR_H */ ukui-control-center/panels/volume-control/gvc-mixer-sink.h0000664000175000017500000000411413057175444022706 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __GVC_MIXER_SINK_H #define __GVC_MIXER_SINK_H #include #include "gvc-mixer-stream.h" G_BEGIN_DECLS #define GVC_TYPE_MIXER_SINK (gvc_mixer_sink_get_type ()) #define GVC_MIXER_SINK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SINK, GvcMixerSink)) #define GVC_MIXER_SINK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SINK, GvcMixerSinkClass)) #define GVC_IS_MIXER_SINK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SINK)) #define GVC_IS_MIXER_SINK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SINK)) #define GVC_MIXER_SINK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SINK, GvcMixerSinkClass)) typedef struct GvcMixerSinkPrivate GvcMixerSinkPrivate; typedef struct { GvcMixerStream parent; GvcMixerSinkPrivate *priv; } GvcMixerSink; typedef struct { GvcMixerStreamClass parent_class; } GvcMixerSinkClass; GType gvc_mixer_sink_get_type (void); GvcMixerStream * gvc_mixer_sink_new (pa_context *context, guint index, GvcChannelMap *map); G_END_DECLS #endif /* __GVC_MIXER_SINK_H */ ukui-control-center/panels/volume-control/gvc-level-bar.h0000664000175000017500000000602213057175444022471 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __GVC_LEVEL_BAR_H #define __GVC_LEVEL_BAR_H #include #include G_BEGIN_DECLS #define GVC_TYPE_LEVEL_BAR (gvc_level_bar_get_type ()) #define GVC_LEVEL_BAR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_LEVEL_BAR, GvcLevelBar)) #define GVC_LEVEL_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_LEVEL_BAR, GvcLevelBarClass)) #define GVC_IS_LEVEL_BAR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_LEVEL_BAR)) #define GVC_IS_LEVEL_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_LEVEL_BAR)) #define GVC_LEVEL_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_LEVEL_BAR, GvcLevelBarClass)) typedef struct GvcLevelBarPrivate GvcLevelBarPrivate; typedef struct { #if GTK_CHECK_VERSION (3, 0, 0) GtkBox parent; #else GtkHBox parent; #endif GvcLevelBarPrivate *priv; } GvcLevelBar; typedef struct { #if GTK_CHECK_VERSION (3, 0, 0) GtkBoxClass parent_class; #else GtkHBoxClass parent_class; #endif } GvcLevelBarClass; typedef enum { GVC_LEVEL_SCALE_LINEAR, GVC_LEVEL_SCALE_LOG, GVC_LEVEL_SCALE_LAST } GvcLevelScale; GType gvc_level_bar_get_type (void); GtkWidget * gvc_level_bar_new (void); void gvc_level_bar_set_orientation (GvcLevelBar *bar, GtkOrientation orientation); GtkOrientation gvc_level_bar_get_orientation (GvcLevelBar *bar); void gvc_level_bar_set_peak_adjustment (GvcLevelBar *bar, GtkAdjustment *adjustment); GtkAdjustment * gvc_level_bar_get_peak_adjustment (GvcLevelBar *bar); void gvc_level_bar_set_rms_adjustment (GvcLevelBar *bar, GtkAdjustment *adjustment); GtkAdjustment * gvc_level_bar_get_rms_adjustment (GvcLevelBar *bar); void gvc_level_bar_set_scale (GvcLevelBar *bar, GvcLevelScale scale); G_END_DECLS #endif /* __GVC_LEVEL_BAR_H */ ukui-control-center/panels/volume-control/gvc-speaker-test.h0000664000175000017500000000413213057175444023227 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2009 Red Hat, Inc. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __GVC_SPEAKER_TEST_H #define __GVC_SPEAKER_TEST_H #include #include #include G_BEGIN_DECLS #define GVC_TYPE_SPEAKER_TEST (gvc_speaker_test_get_type ()) #define GVC_SPEAKER_TEST(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_SPEAKER_TEST, GvcSpeakerTest)) #define GVC_SPEAKER_TEST_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_SPEAKER_TEST, GvcSpeakerTestClass)) #define GVC_IS_SPEAKER_TEST(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_SPEAKER_TEST)) #define GVC_IS_SPEAKER_TEST_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_SPEAKER_TEST)) #define GVC_SPEAKER_TEST_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_SPEAKER_TEST, GvcSpeakerTestClass)) typedef struct GvcSpeakerTestPrivate GvcSpeakerTestPrivate; typedef struct { GtkNotebook parent; GvcSpeakerTestPrivate *priv; } GvcSpeakerTest; typedef struct { GtkNotebookClass parent_class; } GvcSpeakerTestClass; GType gvc_speaker_test_get_type (void); GtkWidget * gvc_speaker_test_new (GvcMixerControl *control, GvcMixerCard *card); G_END_DECLS #endif /* __GVC_SPEAKER_TEST_H */ ukui-control-center/panels/volume-control/gvc-mixer-sink-input.h0000664000175000017500000000432313057175444024045 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __GVC_MIXER_SINK_INPUT_H #define __GVC_MIXER_SINK_INPUT_H #include #include "gvc-mixer-stream.h" G_BEGIN_DECLS #define GVC_TYPE_MIXER_SINK_INPUT (gvc_mixer_sink_input_get_type ()) #define GVC_MIXER_SINK_INPUT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInput)) #define GVC_MIXER_SINK_INPUT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInputClass)) #define GVC_IS_MIXER_SINK_INPUT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SINK_INPUT)) #define GVC_IS_MIXER_SINK_INPUT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SINK_INPUT)) #define GVC_MIXER_SINK_INPUT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInputClass)) typedef struct GvcMixerSinkInputPrivate GvcMixerSinkInputPrivate; typedef struct { GvcMixerStream parent; GvcMixerSinkInputPrivate *priv; } GvcMixerSinkInput; typedef struct { GvcMixerStreamClass parent_class; } GvcMixerSinkInputClass; GType gvc_mixer_sink_input_get_type (void); GvcMixerStream * gvc_mixer_sink_input_new (pa_context *context, guint index, GvcChannelMap *map); G_END_DECLS #endif /* __GVC_MIXER_SINK_INPUT_H */ ukui-control-center/panels/volume-control/gvc-mixer-stream.c0000664000175000017500000010006613057175444023233 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include "gvc-mixer-stream.h" #define GVC_MIXER_STREAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_STREAM, GvcMixerStreamPrivate)) static guint32 stream_serial = 1; struct GvcMixerStreamPrivate { pa_context *pa_context; guint id; guint index; gint card_index; GvcChannelMap *channel_map; char *name; char *description; char *application_id; char *icon_name; gboolean is_muted; gboolean can_decibel; gboolean is_event_stream; gboolean is_virtual; pa_volume_t base_volume; pa_operation *change_volume_op; char *port; char *human_port; GList *ports; }; enum { PROP_0, PROP_ID, PROP_PA_CONTEXT, PROP_CHANNEL_MAP, PROP_INDEX, PROP_NAME, PROP_DESCRIPTION, PROP_APPLICATION_ID, PROP_ICON_NAME, PROP_VOLUME, PROP_DECIBEL, PROP_IS_MUTED, PROP_CAN_DECIBEL, PROP_IS_EVENT_STREAM, PROP_IS_VIRTUAL, PROP_CARD_INDEX, PROP_PORT, }; static void gvc_mixer_stream_class_init (GvcMixerStreamClass *klass); static void gvc_mixer_stream_init (GvcMixerStream *mixer_stream); static void gvc_mixer_stream_finalize (GObject *object); G_DEFINE_ABSTRACT_TYPE (GvcMixerStream, gvc_mixer_stream, G_TYPE_OBJECT) static guint32 get_next_stream_serial (void) { guint32 serial; serial = stream_serial++; if ((gint32)stream_serial < 0) { stream_serial = 1; } return serial; } pa_context * gvc_mixer_stream_get_pa_context (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0); return stream->priv->pa_context; } guint gvc_mixer_stream_get_index (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0); return stream->priv->index; } guint gvc_mixer_stream_get_id (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0); return stream->priv->id; } const GvcChannelMap * gvc_mixer_stream_get_channel_map (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL); return stream->priv->channel_map; } pa_volume_t gvc_mixer_stream_get_volume (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0); return (pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME]; } gdouble gvc_mixer_stream_get_decibel (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0); return pa_sw_volume_to_dB( (pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME]); } gboolean gvc_mixer_stream_set_volume (GvcMixerStream *stream, pa_volume_t volume) { pa_cvolume cv; g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map); pa_cvolume_scale(&cv, volume); if (!pa_cvolume_equal(gvc_channel_map_get_cvolume(stream->priv->channel_map), &cv)) { gvc_channel_map_volume_changed(stream->priv->channel_map, &cv, FALSE); g_object_notify (G_OBJECT (stream), "volume"); return TRUE; } return FALSE; } gboolean gvc_mixer_stream_set_decibel (GvcMixerStream *stream, gdouble db) { pa_cvolume cv; g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map); pa_cvolume_scale(&cv, pa_sw_volume_from_dB(db)); if (!pa_cvolume_equal(gvc_channel_map_get_cvolume(stream->priv->channel_map), &cv)) { gvc_channel_map_volume_changed(stream->priv->channel_map, &cv, FALSE); g_object_notify (G_OBJECT (stream), "volume"); } return TRUE; } gboolean gvc_mixer_stream_get_is_muted (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); return stream->priv->is_muted; } gboolean gvc_mixer_stream_get_can_decibel (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); return stream->priv->can_decibel; } gboolean gvc_mixer_stream_set_is_muted (GvcMixerStream *stream, gboolean is_muted) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); if (is_muted != stream->priv->is_muted) { stream->priv->is_muted = is_muted; g_object_notify (G_OBJECT (stream), "is-muted"); } return TRUE; } gboolean gvc_mixer_stream_set_can_decibel (GvcMixerStream *stream, gboolean can_decibel) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); if (can_decibel != stream->priv->can_decibel) { stream->priv->can_decibel = can_decibel; g_object_notify (G_OBJECT (stream), "can-decibel"); } return TRUE; } const char * gvc_mixer_stream_get_name (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL); return stream->priv->name; } const char * gvc_mixer_stream_get_description (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL); return stream->priv->description; } gboolean gvc_mixer_stream_set_name (GvcMixerStream *stream, const char *name) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); g_free (stream->priv->name); stream->priv->name = g_strdup (name); g_object_notify (G_OBJECT (stream), "name"); return TRUE; } gboolean gvc_mixer_stream_set_description (GvcMixerStream *stream, const char *description) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); g_free (stream->priv->description); stream->priv->description = g_strdup (description); g_object_notify (G_OBJECT (stream), "description"); return TRUE; } gboolean gvc_mixer_stream_is_event_stream (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); return stream->priv->is_event_stream; } gboolean gvc_mixer_stream_set_is_event_stream (GvcMixerStream *stream, gboolean is_event_stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); stream->priv->is_event_stream = is_event_stream; g_object_notify (G_OBJECT (stream), "is-event-stream"); return TRUE; } gboolean gvc_mixer_stream_is_virtual (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); return stream->priv->is_virtual; } gboolean gvc_mixer_stream_set_is_virtual (GvcMixerStream *stream, gboolean is_virtual) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); stream->priv->is_virtual = is_virtual; g_object_notify (G_OBJECT (stream), "is-virtual"); return TRUE; } const char * gvc_mixer_stream_get_application_id (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL); return stream->priv->application_id; } gboolean gvc_mixer_stream_set_application_id (GvcMixerStream *stream, const char *application_id) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); g_free (stream->priv->application_id); stream->priv->application_id = g_strdup (application_id); g_object_notify (G_OBJECT (stream), "application-id"); return TRUE; } static void on_channel_map_volume_changed (GvcChannelMap *channel_map, gboolean set, GvcMixerStream *stream) { if (set == TRUE) gvc_mixer_stream_push_volume (stream); g_object_notify (G_OBJECT (stream), "volume"); } static gboolean gvc_mixer_stream_set_channel_map (GvcMixerStream *stream, GvcChannelMap *channel_map) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); if (channel_map != NULL) { g_object_ref (channel_map); } if (stream->priv->channel_map != NULL) { g_signal_handlers_disconnect_by_func (stream->priv->channel_map, on_channel_map_volume_changed, stream); g_object_unref (stream->priv->channel_map); } stream->priv->channel_map = channel_map; if (stream->priv->channel_map != NULL) { g_signal_connect (stream->priv->channel_map, "volume-changed", G_CALLBACK (on_channel_map_volume_changed), stream); g_object_notify (G_OBJECT (stream), "channel-map"); } return TRUE; } const char * gvc_mixer_stream_get_icon_name (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL); return stream->priv->icon_name; } gboolean gvc_mixer_stream_set_icon_name (GvcMixerStream *stream, const char *icon_name) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); g_free (stream->priv->icon_name); stream->priv->icon_name = g_strdup (icon_name); g_object_notify (G_OBJECT (stream), "icon-name"); return TRUE; } pa_volume_t gvc_mixer_stream_get_base_volume (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0); return stream->priv->base_volume; } gboolean gvc_mixer_stream_set_base_volume (GvcMixerStream *stream, pa_volume_t base_volume) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); stream->priv->base_volume = base_volume; return TRUE; } const GvcMixerStreamPort * gvc_mixer_stream_get_port (GvcMixerStream *stream) { GList *l; g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL); g_return_val_if_fail (stream->priv->ports != NULL, NULL); for (l = stream->priv->ports; l != NULL; l = l->next) { GvcMixerStreamPort *p = l->data; if (g_strcmp0 (stream->priv->port, p->port) == 0) { return p; } } g_assert_not_reached (); return NULL; } gboolean gvc_mixer_stream_set_port (GvcMixerStream *stream, const char *port) { GList *l; g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); g_return_val_if_fail (stream->priv->ports != NULL, FALSE); g_free (stream->priv->port); stream->priv->port = g_strdup (port); g_free (stream->priv->human_port); stream->priv->human_port = NULL; for (l = stream->priv->ports; l != NULL; l = l->next) { GvcMixerStreamPort *p = l->data; if (g_str_equal (stream->priv->port, p->port)) { stream->priv->human_port = g_strdup (p->human_port); break; } } g_object_notify (G_OBJECT (stream), "port"); return TRUE; } gboolean gvc_mixer_stream_change_port (GvcMixerStream *stream, const char *port) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); return GVC_MIXER_STREAM_GET_CLASS (stream)->change_port (stream, port); } const GList * gvc_mixer_stream_get_ports (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); return stream->priv->ports; } static int sort_ports (GvcMixerStreamPort *a, GvcMixerStreamPort *b) { if (a->priority == b->priority) return 0; if (a->priority > b->priority) return 1; return -1; } gboolean gvc_mixer_stream_set_ports (GvcMixerStream *stream, GList *ports) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); g_return_val_if_fail (stream->priv->ports == NULL, FALSE); stream->priv->ports = g_list_sort (ports, (GCompareFunc) sort_ports); return TRUE; } gint gvc_mixer_stream_get_card_index (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), PA_INVALID_INDEX); return stream->priv->card_index; } gboolean gvc_mixer_stream_set_card_index (GvcMixerStream *stream, gint card_index) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); stream->priv->card_index = card_index; g_object_notify (G_OBJECT (stream), "card-index"); return TRUE; } static void gvc_mixer_stream_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GvcMixerStream *self = GVC_MIXER_STREAM (object); switch (prop_id) { case PROP_PA_CONTEXT: self->priv->pa_context = g_value_get_pointer (value); break; case PROP_INDEX: self->priv->index = g_value_get_ulong (value); break; case PROP_ID: self->priv->id = g_value_get_ulong (value); break; case PROP_CHANNEL_MAP: gvc_mixer_stream_set_channel_map (self, g_value_get_object (value)); break; case PROP_NAME: gvc_mixer_stream_set_name (self, g_value_get_string (value)); break; case PROP_DESCRIPTION: gvc_mixer_stream_set_description (self, g_value_get_string (value)); break; case PROP_APPLICATION_ID: gvc_mixer_stream_set_application_id (self, g_value_get_string (value)); break; case PROP_ICON_NAME: gvc_mixer_stream_set_icon_name (self, g_value_get_string (value)); break; case PROP_VOLUME: gvc_mixer_stream_set_volume (self, g_value_get_ulong (value)); break; case PROP_DECIBEL: gvc_mixer_stream_set_decibel (self, g_value_get_double (value)); break; case PROP_IS_MUTED: gvc_mixer_stream_set_is_muted (self, g_value_get_boolean (value)); break; case PROP_IS_EVENT_STREAM: gvc_mixer_stream_set_is_event_stream (self, g_value_get_boolean (value)); break; case PROP_IS_VIRTUAL: gvc_mixer_stream_set_is_virtual (self, g_value_get_boolean (value)); break; case PROP_CAN_DECIBEL: gvc_mixer_stream_set_can_decibel (self, g_value_get_boolean (value)); break; case PROP_PORT: gvc_mixer_stream_set_port (self, g_value_get_string (value)); break; case PROP_CARD_INDEX: self->priv->card_index = g_value_get_long (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gvc_mixer_stream_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GvcMixerStream *self = GVC_MIXER_STREAM (object); switch (prop_id) { case PROP_PA_CONTEXT: g_value_set_pointer (value, self->priv->pa_context); break; case PROP_INDEX: g_value_set_ulong (value, self->priv->index); break; case PROP_ID: g_value_set_ulong (value, self->priv->id); break; case PROP_CHANNEL_MAP: g_value_set_object (value, self->priv->channel_map); break; case PROP_NAME: g_value_set_string (value, self->priv->name); break; case PROP_DESCRIPTION: g_value_set_string (value, self->priv->description); break; case PROP_APPLICATION_ID: g_value_set_string (value, self->priv->application_id); break; case PROP_ICON_NAME: g_value_set_string (value, self->priv->icon_name); break; case PROP_VOLUME: g_value_set_ulong (value, pa_cvolume_max(gvc_channel_map_get_cvolume(self->priv->channel_map))); break; case PROP_DECIBEL: g_value_set_double (value, pa_sw_volume_to_dB(pa_cvolume_max(gvc_channel_map_get_cvolume(self->priv->channel_map)))); break; case PROP_IS_MUTED: g_value_set_boolean (value, self->priv->is_muted); break; case PROP_IS_EVENT_STREAM: g_value_set_boolean (value, self->priv->is_event_stream); break; case PROP_IS_VIRTUAL: g_value_set_boolean (value, self->priv->is_virtual); break; case PROP_CAN_DECIBEL: g_value_set_boolean (value, self->priv->can_decibel); break; case PROP_PORT: g_value_set_string (value, self->priv->port); break; case PROP_CARD_INDEX: g_value_set_long (value, self->priv->card_index); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GObject * gvc_mixer_stream_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; GvcMixerStream *self; object = G_OBJECT_CLASS (gvc_mixer_stream_parent_class)->constructor (type, n_construct_properties, construct_params); self = GVC_MIXER_STREAM (object); self->priv->id = get_next_stream_serial (); return object; } static gboolean gvc_mixer_stream_real_change_port (GvcMixerStream *stream, const char *port) { return FALSE; } static gboolean gvc_mixer_stream_real_push_volume (GvcMixerStream *stream, gpointer *op) { return FALSE; } static gboolean gvc_mixer_stream_real_change_is_muted (GvcMixerStream *stream, gboolean is_muted) { return FALSE; } gboolean gvc_mixer_stream_push_volume (GvcMixerStream *stream) { pa_operation *op; gboolean ret; g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); if (stream->priv->is_event_stream != FALSE) return TRUE; g_printf ("Pushing new volume to stream '%s' (%s)\n", stream->priv->description, stream->priv->name); ret = GVC_MIXER_STREAM_GET_CLASS (stream)->push_volume (stream, (gpointer *) &op); if (ret) { if (stream->priv->change_volume_op != NULL) pa_operation_unref (stream->priv->change_volume_op); stream->priv->change_volume_op = op; } return ret; } gboolean gvc_mixer_stream_change_is_muted (GvcMixerStream *stream, gboolean is_muted) { gboolean ret; g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); ret = GVC_MIXER_STREAM_GET_CLASS (stream)->change_is_muted (stream, is_muted); return ret; } gboolean gvc_mixer_stream_is_running (GvcMixerStream *stream) { if (stream->priv->change_volume_op == NULL) return FALSE; if ((pa_operation_get_state(stream->priv->change_volume_op) == PA_OPERATION_RUNNING)) return TRUE; pa_operation_unref(stream->priv->change_volume_op); stream->priv->change_volume_op = NULL; return FALSE; } static void gvc_mixer_stream_class_init (GvcMixerStreamClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->constructor = gvc_mixer_stream_constructor; gobject_class->finalize = gvc_mixer_stream_finalize; gobject_class->set_property = gvc_mixer_stream_set_property; gobject_class->get_property = gvc_mixer_stream_get_property; klass->push_volume = gvc_mixer_stream_real_push_volume; klass->change_port = gvc_mixer_stream_real_change_port; klass->change_is_muted = gvc_mixer_stream_real_change_is_muted; g_object_class_install_property (gobject_class, PROP_INDEX, g_param_spec_ulong ("index", "Index", "The index for this stream", 0, G_MAXULONG, 0, G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (gobject_class, PROP_ID, g_param_spec_ulong ("id", "id", "The id for this stream", 0, G_MAXULONG, 0, G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (gobject_class, PROP_CHANNEL_MAP, g_param_spec_object ("channel-map", "channel map", "The channel map for this stream", GVC_TYPE_CHANNEL_MAP, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_PA_CONTEXT, g_param_spec_pointer ("pa-context", "PulseAudio context", "The PulseAudio context for this stream", G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (gobject_class, PROP_VOLUME, g_param_spec_ulong ("volume", "Volume", "The volume for this stream", 0, G_MAXULONG, 0, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_DECIBEL, g_param_spec_double ("decibel", "Decibel", "The decibel level for this stream", -G_MAXDOUBLE, G_MAXDOUBLE, 0, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_NAME, g_param_spec_string ("name", "Name", "Name to display for this stream", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_DESCRIPTION, g_param_spec_string ("description", "Description", "Description to display for this stream", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_APPLICATION_ID, g_param_spec_string ("application-id", "Application identifier", "Application identifier for this stream", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_ICON_NAME, g_param_spec_string ("icon-name", "Icon Name", "Name of icon to display for this stream", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_IS_MUTED, g_param_spec_boolean ("is-muted", "is muted", "Whether stream is muted", FALSE, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_CAN_DECIBEL, g_param_spec_boolean ("can-decibel", "can decibel", "Whether stream volume can be converted to decibel units", FALSE, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_IS_EVENT_STREAM, g_param_spec_boolean ("is-event-stream", "is event stream", "Whether stream's role is to play an event", FALSE, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_IS_VIRTUAL, g_param_spec_boolean ("is-virtual", "is virtual stream", "Whether the stream is virtual", FALSE, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_PORT, g_param_spec_string ("port", "Port", "The name of the current port for this stream", NULL, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_CARD_INDEX, g_param_spec_long ("card-index", "Card index", "The index of the card for this stream", PA_INVALID_INDEX, G_MAXLONG, PA_INVALID_INDEX, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_type_class_add_private (klass, sizeof (GvcMixerStreamPrivate)); } static void gvc_mixer_stream_init (GvcMixerStream *stream) { stream->priv = GVC_MIXER_STREAM_GET_PRIVATE (stream); } static void free_port (GvcMixerStreamPort *p) { g_free (p->port); g_free (p->human_port); g_free (p); } static void gvc_mixer_stream_finalize (GObject *object) { GvcMixerStream *mixer_stream; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_STREAM (object)); mixer_stream = GVC_MIXER_STREAM (object); g_return_if_fail (mixer_stream->priv != NULL); g_object_unref (mixer_stream->priv->channel_map); mixer_stream->priv->channel_map = NULL; g_free (mixer_stream->priv->name); mixer_stream->priv->name = NULL; g_free (mixer_stream->priv->description); mixer_stream->priv->description = NULL; g_free (mixer_stream->priv->application_id); mixer_stream->priv->application_id = NULL; g_free (mixer_stream->priv->icon_name); mixer_stream->priv->icon_name = NULL; g_free (mixer_stream->priv->port); mixer_stream->priv->port = NULL; g_free (mixer_stream->priv->human_port); mixer_stream->priv->human_port = NULL; g_list_foreach (mixer_stream->priv->ports, (GFunc) free_port, NULL); g_list_free (mixer_stream->priv->ports); mixer_stream->priv->ports = NULL; if (mixer_stream->priv->change_volume_op) { pa_operation_unref(mixer_stream->priv->change_volume_op); mixer_stream->priv->change_volume_op = NULL; } G_OBJECT_CLASS (gvc_mixer_stream_parent_class)->finalize (object); } ukui-control-center/panels/volume-control/dialog-main.c0000664000175000017500000000734013253611037022212 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include #include "dialog-main.h" #include #include #include "gvc-mixer-dialog.h" #include "gvc-log.h" #define GVCA_DBUS_NAME "org.ukui.VolumeControl" #define DIALOG_POPUP_TIMEOUT 3 GtkBuilder * top_builder; static gboolean show_version = FALSE; static gboolean debug = FALSE; static gchar* page = NULL; static guint popup_id = 0; static GtkWidget *dialog = NULL; static GtkWidget *warning_dialog = NULL; static void on_control_ready (GvcMixerControl *control, gpointer app) { if (popup_id != 0) { g_source_remove (popup_id); popup_id = 0; } if (warning_dialog != NULL) { gtk_widget_destroy (warning_dialog); warning_dialog = NULL; } if (dialog) return; dialog = GTK_WIDGET (gvc_mixer_dialog_new (control,top_builder)); gvc_mixer_dialog_set_page(GVC_MIXER_DIALOG (dialog), page); //g_signal_connect (app, "message-received", // G_CALLBACK (message_received_cb), dialog); } static void warning_dialog_answered (GtkDialog *d, gpointer data) { gtk_widget_destroy (warning_dialog); gtk_main_quit (); } static gboolean dialog_popup_timeout (gpointer data) { warning_dialog = gtk_message_dialog_new (GTK_WINDOW(dialog), 0, GTK_MESSAGE_INFO, GTK_BUTTONS_CANCEL, "Waiting for sound system to respond"); g_signal_connect (warning_dialog, "response", G_CALLBACK (warning_dialog_answered), NULL); g_signal_connect (warning_dialog, "close", G_CALLBACK (warning_dialog_answered), NULL); gtk_widget_show (warning_dialog); return FALSE; } static void on_control_connecting (GvcMixerControl *control, gpointer app) { if (popup_id != 0) return; popup_id = g_timeout_add_seconds (DIALOG_POPUP_TIMEOUT, dialog_popup_timeout, NULL); } void add_volume_control_app (GtkBuilder * builder) { g_warning("volume-control"); GError *error; GvcMixerControl *control; top_builder = builder; gvc_log_init (); error = NULL; gvc_log_set_debug (debug); control = gvc_mixer_control_new ("UKUI Volume Control Dialog"); g_signal_connect (control, "connecting", G_CALLBACK (on_control_connecting), NULL); g_signal_connect (control, "ready", G_CALLBACK (on_control_ready), NULL); gvc_mixer_control_open (control); /*if (control != NULL) { g_object_unref (control); } return 0;*/ } void destroy_volume_control(){ //if (control) } ukui-control-center/panels/volume-control/gvc-log.h0000664000175000017500000000200313057175444021374 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2009 Red Hat, Inc. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __GVC_LOG_H #define __GVC_LOG_H #include G_BEGIN_DECLS void gvc_log_init (void); void gvc_log_set_debug (gboolean debug); G_END_DECLS #endif /* __GVC_LOG_H */ ukui-control-center/panels/volume-control/gvc-mixer-event-role.h0000664000175000017500000000433413057175444024026 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __GVC_MIXER_EVENT_ROLE_H #define __GVC_MIXER_EVENT_ROLE_H #include #include "gvc-mixer-stream.h" G_BEGIN_DECLS #define GVC_TYPE_MIXER_EVENT_ROLE (gvc_mixer_event_role_get_type ()) #define GVC_MIXER_EVENT_ROLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRole)) #define GVC_MIXER_EVENT_ROLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRoleClass)) #define GVC_IS_MIXER_EVENT_ROLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_EVENT_ROLE)) #define GVC_IS_MIXER_EVENT_ROLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_EVENT_ROLE)) #define GVC_MIXER_EVENT_ROLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRoleClass)) typedef struct GvcMixerEventRolePrivate GvcMixerEventRolePrivate; typedef struct { GvcMixerStream parent; GvcMixerEventRolePrivate *priv; } GvcMixerEventRole; typedef struct { GvcMixerStreamClass parent_class; } GvcMixerEventRoleClass; GType gvc_mixer_event_role_get_type (void); GvcMixerStream * gvc_mixer_event_role_new (pa_context *context, const char *device, GvcChannelMap *channel_map); G_END_DECLS #endif /* __GVC_MIXER_EVENT_ROLE_H */ ukui-control-center/panels/volume-control/gvc-mixer-sink.c0000664000175000017500000001511213057175444022701 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include "gvc-mixer-sink.h" #define GVC_MIXER_SINK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SINK, GvcMixerSinkPrivate)) struct GvcMixerSinkPrivate { gpointer dummy; }; static void gvc_mixer_sink_class_init (GvcMixerSinkClass *klass); static void gvc_mixer_sink_init (GvcMixerSink *mixer_sink); static void gvc_mixer_sink_finalize (GObject *object); static void gvc_mixer_sink_dispose (GObject *object); G_DEFINE_TYPE (GvcMixerSink, gvc_mixer_sink, GVC_TYPE_MIXER_STREAM) static gboolean gvc_mixer_sink_push_volume (GvcMixerStream *stream, gpointer *op) { pa_operation *o; guint index; const GvcChannelMap *map; pa_context *context; const pa_cvolume *cv; index = gvc_mixer_stream_get_index (stream); map = gvc_mixer_stream_get_channel_map (stream); /* set the volume */ cv = gvc_channel_map_get_cvolume(map); context = gvc_mixer_stream_get_pa_context (stream); o = pa_context_set_sink_volume_by_index (context, index, cv, NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_sink_volume_by_index() failed: %s", pa_strerror(pa_context_errno(context))); return FALSE; } *op = o; return TRUE; } static gboolean gvc_mixer_sink_change_is_muted (GvcMixerStream *stream, gboolean is_muted) { pa_operation *o; guint index; pa_context *context; index = gvc_mixer_stream_get_index (stream); context = gvc_mixer_stream_get_pa_context (stream); o = pa_context_set_sink_mute_by_index (context, index, is_muted, NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_sink_mute_by_index() failed: %s", pa_strerror(pa_context_errno(context))); return FALSE; } pa_operation_unref(o); return TRUE; } static gboolean gvc_mixer_sink_change_port (GvcMixerStream *stream, const char *port) { #if PA_MICRO > 15 pa_operation *o; guint index; pa_context *context; index = gvc_mixer_stream_get_index (stream); context = gvc_mixer_stream_get_pa_context (stream); o = pa_context_set_sink_port_by_index (context, index, port, NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_sink_port_by_index() failed: %s", pa_strerror(pa_context_errno(context))); return FALSE; } pa_operation_unref(o); return TRUE; #else return FALSE; #endif /* PA_MICRO > 15 */ } static GObject * gvc_mixer_sink_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; GvcMixerSink *self; object = G_OBJECT_CLASS (gvc_mixer_sink_parent_class)->constructor (type, n_construct_properties, construct_params); self = GVC_MIXER_SINK (object); return object; } static void gvc_mixer_sink_class_init (GvcMixerSinkClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass); object_class->constructor = gvc_mixer_sink_constructor; object_class->dispose = gvc_mixer_sink_dispose; object_class->finalize = gvc_mixer_sink_finalize; stream_class->push_volume = gvc_mixer_sink_push_volume; stream_class->change_port = gvc_mixer_sink_change_port; stream_class->change_is_muted = gvc_mixer_sink_change_is_muted; g_type_class_add_private (klass, sizeof (GvcMixerSinkPrivate)); } static void gvc_mixer_sink_init (GvcMixerSink *sink) { sink->priv = GVC_MIXER_SINK_GET_PRIVATE (sink); } static void gvc_mixer_sink_dispose (GObject *object) { GvcMixerSink *mixer_sink; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_SINK (object)); mixer_sink = GVC_MIXER_SINK (object); G_OBJECT_CLASS (gvc_mixer_sink_parent_class)->dispose (object); } static void gvc_mixer_sink_finalize (GObject *object) { GvcMixerSink *mixer_sink; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_SINK (object)); mixer_sink = GVC_MIXER_SINK (object); g_return_if_fail (mixer_sink->priv != NULL); G_OBJECT_CLASS (gvc_mixer_sink_parent_class)->finalize (object); } GvcMixerStream * gvc_mixer_sink_new (pa_context *context, guint index, GvcChannelMap *channel_map) { GObject *object; object = g_object_new (GVC_TYPE_MIXER_SINK, "pa-context", context, "index", index, "channel-map", channel_map, NULL); return GVC_MIXER_STREAM (object); } ukui-control-center/panels/volume-control/gvc-sound-theme-chooser.h0000664000175000017500000000414513245450076024510 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __GVC_SOUND_THEME_CHOOSER_H #define __GVC_SOUND_THEME_CHOOSER_H #include G_BEGIN_DECLS #define GVC_TYPE_SOUND_THEME_CHOOSER (gvc_sound_theme_chooser_get_type ()) #define GVC_SOUND_THEME_CHOOSER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_SOUND_THEME_CHOOSER, GvcSoundThemeChooser)) #define GVC_SOUND_THEME_CHOOSER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_SOUND_THEME_CHOOSER, GvcSoundThemeChooserClass)) #define GVC_IS_SOUND_THEME_CHOOSER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_SOUND_THEME_CHOOSER)) #define GVC_IS_SOUND_THEME_CHOOSER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_SOUND_THEME_CHOOSER)) #define GVC_SOUND_THEME_CHOOSER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_SOUND_THEME_CHOOSER, GvcSoundThemeChooserClass)) typedef struct GvcSoundThemeChooserPrivate GvcSoundThemeChooserPrivate; typedef struct { GtkBox parent; GvcSoundThemeChooserPrivate *priv; } GvcSoundThemeChooser; typedef struct { GtkBoxClass parent_class; } GvcSoundThemeChooserClass; GType gvc_sound_theme_chooser_get_type (void); GtkWidget * gvc_sound_theme_chooser_new (void); G_END_DECLS #endif /* __GVC_SOUND_THEME_CHOOSER_H */ ukui-control-center/panels/volume-control/gvc-level-bar.c0000664000175000017500000007347113057175444022500 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include "gvc-level-bar.h" #define NUM_BOXES 15 #define GVC_LEVEL_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_LEVEL_BAR, GvcLevelBarPrivate)) #define MIN_HORIZONTAL_BAR_WIDTH 150 #define HORIZONTAL_BAR_HEIGHT 6 #define VERTICAL_BAR_WIDTH 6 #define MIN_VERTICAL_BAR_HEIGHT 400 typedef struct { int peak_num; int max_peak_num; GdkRectangle area; int delta; int box_width; int box_height; int box_radius; double bg_r; double bg_g; double bg_b; double bdr_r; double bdr_g; double bdr_b; double fl_r; double fl_g; double fl_b; } LevelBarLayout; struct GvcLevelBarPrivate { GtkOrientation orientation; GtkAdjustment *peak_adjustment; GtkAdjustment *rms_adjustment; int scale; gdouble peak_fraction; gdouble rms_fraction; gdouble max_peak; guint max_peak_id; LevelBarLayout layout; }; enum { PROP_0, PROP_PEAK_ADJUSTMENT, PROP_RMS_ADJUSTMENT, PROP_SCALE, PROP_ORIENTATION, }; static void gvc_level_bar_class_init (GvcLevelBarClass *klass); static void gvc_level_bar_init (GvcLevelBar *level_bar); static void gvc_level_bar_finalize (GObject *object); #if GTK_CHECK_VERSION (3, 0, 0) G_DEFINE_TYPE (GvcLevelBar, gvc_level_bar, GTK_TYPE_BOX) #else G_DEFINE_TYPE (GvcLevelBar, gvc_level_bar, GTK_TYPE_HBOX) #endif #define check_rectangle(rectangle1, rectangle2) \ { \ if (rectangle1.x != rectangle2.x) return TRUE; \ if (rectangle1.y != rectangle2.y) return TRUE; \ if (rectangle1.width != rectangle2.width) return TRUE; \ if (rectangle1.height != rectangle2.height) return TRUE; \ } static gboolean layout_changed (LevelBarLayout *layout1, LevelBarLayout *layout2) { check_rectangle (layout1->area, layout2->area); if (layout1->delta != layout2->delta) return TRUE; if (layout1->peak_num != layout2->peak_num) return TRUE; if (layout1->max_peak_num != layout2->max_peak_num) return TRUE; if (layout1->bg_r != layout2->bg_r || layout1->bg_g != layout2->bg_g || layout1->bg_b != layout2->bg_b) return TRUE; if (layout1->bdr_r != layout2->bdr_r || layout1->bdr_g != layout2->bdr_g || layout1->bdr_b != layout2->bdr_b) return TRUE; if (layout1->fl_r != layout2->fl_r || layout1->fl_g != layout2->fl_g || layout1->fl_b != layout2->fl_b) return TRUE; return FALSE; } static gdouble fraction_from_adjustment (GvcLevelBar *bar, GtkAdjustment *adjustment) { gdouble level; gdouble fraction; gdouble min; gdouble max; level = gtk_adjustment_get_value (adjustment); min = gtk_adjustment_get_lower (adjustment); max = gtk_adjustment_get_upper (adjustment); switch (bar->priv->scale) { case GVC_LEVEL_SCALE_LINEAR: fraction = (level - min) / (max - min); break; case GVC_LEVEL_SCALE_LOG: fraction = log10 ((level - min + 1) / (max - min + 1)); break; default: g_assert_not_reached (); } return fraction; } static gboolean reset_max_peak (GvcLevelBar *bar) { gdouble min; min = gtk_adjustment_get_lower (bar->priv->peak_adjustment); bar->priv->max_peak = min; bar->priv->layout.max_peak_num = 0; gtk_widget_queue_draw (GTK_WIDGET (bar)); bar->priv->max_peak_id = 0; return FALSE; } static void bar_calc_layout (GvcLevelBar *bar) { GdkColor color; int peak_level; int max_peak_level; GtkAllocation allocation; GtkStyle *style; gtk_widget_get_allocation (GTK_WIDGET (bar), &allocation); bar->priv->layout.area.width = allocation.width - 2; bar->priv->layout.area.height = allocation.height - 2; style = gtk_widget_get_style (GTK_WIDGET (bar)); color = style->bg [GTK_STATE_NORMAL]; bar->priv->layout.bg_r = (float)color.red / 65535.0; bar->priv->layout.bg_g = (float)color.green / 65535.0; bar->priv->layout.bg_b = (float)color.blue / 65535.0; color = style->dark [GTK_STATE_NORMAL]; bar->priv->layout.bdr_r = (float)color.red / 65535.0; bar->priv->layout.bdr_g = (float)color.green / 65535.0; bar->priv->layout.bdr_b = (float)color.blue / 65535.0; color = style->bg [GTK_STATE_SELECTED]; //bar->priv->layout.fl_r = (float)color.red / 65535.0; bar->priv->layout.fl_r = 0.5; //bar->priv->layout.fl_g = (float)color.green / 65535.0; bar->priv->layout.fl_g = (float)color.green / 65535.0; //bar->priv->layout.fl_b = (float)color.blue / 65535.0; bar->priv->layout.fl_b = (float)color.blue / 65535.0; if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) { peak_level = bar->priv->peak_fraction * bar->priv->layout.area.height; max_peak_level = bar->priv->max_peak * bar->priv->layout.area.height; bar->priv->layout.delta = bar->priv->layout.area.height / NUM_BOXES; bar->priv->layout.area.x = 0; bar->priv->layout.area.y = 0; bar->priv->layout.box_height = bar->priv->layout.delta / 2; bar->priv->layout.box_width = bar->priv->layout.area.width; bar->priv->layout.box_radius = bar->priv->layout.box_width / 2; } else { peak_level = bar->priv->peak_fraction * bar->priv->layout.area.width; max_peak_level = bar->priv->max_peak * bar->priv->layout.area.width; bar->priv->layout.delta = bar->priv->layout.area.width / NUM_BOXES; bar->priv->layout.area.x = 0; bar->priv->layout.area.y = 0; bar->priv->layout.box_width = bar->priv->layout.delta / 2; bar->priv->layout.box_height = bar->priv->layout.area.height; bar->priv->layout.box_radius = bar->priv->layout.box_height / 2; } if (bar->priv->layout.delta == 0){ bar->priv->layout.peak_num = 0; bar->priv->layout.max_peak_num = 0; } else { bar->priv->layout.peak_num = peak_level / bar->priv->layout.delta; bar->priv->layout.max_peak_num = max_peak_level / bar->priv->layout.delta; } } static void update_peak_value (GvcLevelBar *bar) { gdouble val; LevelBarLayout layout; layout = bar->priv->layout; val = fraction_from_adjustment (bar, bar->priv->peak_adjustment); bar->priv->peak_fraction = val; if (val > bar->priv->max_peak) { if (bar->priv->max_peak_id > 0) { g_source_remove (bar->priv->max_peak_id); } bar->priv->max_peak_id = g_timeout_add_seconds (1, (GSourceFunc)reset_max_peak, bar); bar->priv->max_peak = val; } bar_calc_layout (bar); if (layout_changed (&bar->priv->layout, &layout)) { gtk_widget_queue_draw (GTK_WIDGET (bar)); } } static void update_rms_value (GvcLevelBar *bar) { gdouble val; val = fraction_from_adjustment (bar, bar->priv->rms_adjustment); bar->priv->rms_fraction = val; } GtkOrientation gvc_level_bar_get_orientation (GvcLevelBar *bar) { g_return_val_if_fail (GVC_IS_LEVEL_BAR (bar), 0); return bar->priv->orientation; } void gvc_level_bar_set_orientation (GvcLevelBar *bar, GtkOrientation orientation) { g_return_if_fail (GVC_IS_LEVEL_BAR (bar)); if (orientation != bar->priv->orientation) { bar->priv->orientation = orientation; gtk_widget_queue_draw (GTK_WIDGET (bar)); g_object_notify (G_OBJECT (bar), "orientation"); } } static void on_peak_adjustment_value_changed (GtkAdjustment *adjustment, GvcLevelBar *bar) { update_peak_value (bar); } static void on_rms_adjustment_value_changed (GtkAdjustment *adjustment, GvcLevelBar *bar) { update_rms_value (bar); } void gvc_level_bar_set_peak_adjustment (GvcLevelBar *bar, GtkAdjustment *adjustment) { g_return_if_fail (GVC_LEVEL_BAR (bar)); g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); if (bar->priv->peak_adjustment != NULL) { g_signal_handlers_disconnect_by_func (bar->priv->peak_adjustment, G_CALLBACK (on_peak_adjustment_value_changed), bar); g_object_unref (bar->priv->peak_adjustment); } bar->priv->peak_adjustment = g_object_ref_sink (adjustment); g_signal_connect (bar->priv->peak_adjustment, "value-changed", G_CALLBACK (on_peak_adjustment_value_changed), bar); update_peak_value (bar); g_object_notify (G_OBJECT (bar), "peak-adjustment"); } void gvc_level_bar_set_rms_adjustment (GvcLevelBar *bar, GtkAdjustment *adjustment) { g_return_if_fail (GVC_LEVEL_BAR (bar)); g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); if (bar->priv->rms_adjustment != NULL) { g_signal_handlers_disconnect_by_func (bar->priv->peak_adjustment, G_CALLBACK (on_rms_adjustment_value_changed), bar); g_object_unref (bar->priv->rms_adjustment); } bar->priv->rms_adjustment = g_object_ref_sink (adjustment); g_signal_connect (bar->priv->peak_adjustment, "value-changed", G_CALLBACK (on_peak_adjustment_value_changed), bar); update_rms_value (bar); g_object_notify (G_OBJECT (bar), "rms-adjustment"); } GtkAdjustment * gvc_level_bar_get_peak_adjustment (GvcLevelBar *bar) { g_return_val_if_fail (GVC_IS_LEVEL_BAR (bar), NULL); return bar->priv->peak_adjustment; } GtkAdjustment * gvc_level_bar_get_rms_adjustment (GvcLevelBar *bar) { g_return_val_if_fail (GVC_IS_LEVEL_BAR (bar), NULL); return bar->priv->rms_adjustment; } void gvc_level_bar_set_scale (GvcLevelBar *bar, GvcLevelScale scale) { g_return_if_fail (GVC_IS_LEVEL_BAR (bar)); if (scale != bar->priv->scale) { bar->priv->scale = scale; update_peak_value (bar); update_rms_value (bar); g_object_notify (G_OBJECT (bar), "scale"); } } static void gvc_level_bar_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GvcLevelBar *self = GVC_LEVEL_BAR (object); switch (prop_id) { case PROP_SCALE: gvc_level_bar_set_scale (self, g_value_get_int (value)); break; case PROP_ORIENTATION: gvc_level_bar_set_orientation (self, g_value_get_enum (value)); break; case PROP_PEAK_ADJUSTMENT: gvc_level_bar_set_peak_adjustment (self, g_value_get_object (value)); break; case PROP_RMS_ADJUSTMENT: gvc_level_bar_set_rms_adjustment (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gvc_level_bar_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GvcLevelBar *self = GVC_LEVEL_BAR (object); switch (prop_id) { case PROP_SCALE: g_value_set_int (value, self->priv->scale); break; case PROP_ORIENTATION: g_value_set_enum (value, self->priv->orientation); break; case PROP_PEAK_ADJUSTMENT: g_value_set_object (value, self->priv->peak_adjustment); break; case PROP_RMS_ADJUSTMENT: g_value_set_object (value, self->priv->rms_adjustment); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GObject * gvc_level_bar_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { return G_OBJECT_CLASS (gvc_level_bar_parent_class)->constructor (type, n_construct_properties, construct_params); } static void gvc_level_bar_size_request (GtkWidget *widget, GtkRequisition *requisition) { GvcLevelBar *bar; g_return_if_fail (GVC_IS_LEVEL_BAR (widget)); g_return_if_fail (requisition != NULL); bar = GVC_LEVEL_BAR (widget); switch (bar->priv->orientation) { case GTK_ORIENTATION_VERTICAL: requisition->width = VERTICAL_BAR_WIDTH; requisition->height = MIN_VERTICAL_BAR_HEIGHT; break; case GTK_ORIENTATION_HORIZONTAL: requisition->width = MIN_HORIZONTAL_BAR_WIDTH; requisition->height = HORIZONTAL_BAR_HEIGHT; break; default: g_assert_not_reached (); break; } } static void gvc_level_bar_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural) { GtkRequisition requisition; gvc_level_bar_size_request (widget, &requisition); *minimum = *natural = requisition.width; } static void gvc_level_bar_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural) { GtkRequisition requisition; gvc_level_bar_size_request (widget, &requisition); *minimum = *natural = requisition.height; } static void gvc_level_bar_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { GvcLevelBar *bar; g_return_if_fail (GVC_IS_LEVEL_BAR (widget)); g_return_if_fail (allocation != NULL); bar = GVC_LEVEL_BAR (widget); /* FIXME: add height property, labels, etc */ GTK_WIDGET_CLASS (gvc_level_bar_parent_class)->size_allocate (widget, allocation); gtk_widget_set_allocation (widget, allocation); gtk_widget_get_allocation (widget, allocation); if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) { allocation->height = MIN (allocation->height, MIN_VERTICAL_BAR_HEIGHT); allocation->width = MAX (allocation->width, VERTICAL_BAR_WIDTH); } else { allocation->width = MIN (allocation->width, MIN_HORIZONTAL_BAR_WIDTH); allocation->height = MAX (allocation->height, HORIZONTAL_BAR_HEIGHT); } bar_calc_layout (bar); } static void curved_rectangle (cairo_t *cr, double x0, double y0, double width, double height, double radius) { double x1; double y1; x1 = x0 + width; y1 = y0 + height; if (!width || !height) { return; } if (width / 2 < radius) { if (height / 2 < radius) { cairo_move_to (cr, x0, (y0 + y1) / 2); cairo_curve_to (cr, x0 ,y0, x0, y0, (x0 + x1) / 2, y0); cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2); cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1); cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2); } else { cairo_move_to (cr, x0, y0 + radius); cairo_curve_to (cr, x0, y0, x0, y0, (x0 + x1) / 2, y0); cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius); cairo_line_to (cr, x1, y1 - radius); cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1); cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius); } } else { if (height / 2 < radius) { cairo_move_to (cr, x0, (y0 + y1) / 2); cairo_curve_to (cr, x0, y0, x0 , y0, x0 + radius, y0); cairo_line_to (cr, x1 - radius, y0); cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2); cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1); cairo_line_to (cr, x0 + radius, y1); cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2); } else { cairo_move_to (cr, x0, y0 + radius); cairo_curve_to (cr, x0 , y0, x0 , y0, x0 + radius, y0); cairo_line_to (cr, x1 - radius, y0); cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius); cairo_line_to (cr, x1, y1 - radius); cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1); cairo_line_to (cr, x0 + radius, y1); cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius); } } cairo_close_path (cr); } static int #if GTK_CHECK_VERSION (3, 0, 0) gvc_level_bar_draw (GtkWidget *widget, cairo_t *cr) #else gvc_level_bar_expose (GtkWidget *widget, GdkEventExpose *event) #endif { GvcLevelBar *bar; #if !GTK_CHECK_VERSION (3, 0, 0) cairo_t *cr; GtkAllocation allocation; #endif g_return_val_if_fail (GVC_IS_LEVEL_BAR (widget), FALSE); #if !GTK_CHECK_VERSION (3, 0, 0) g_return_val_if_fail (event != NULL, FALSE); /* event queue compression */ if (event->count > 0) { return FALSE; } #endif bar = GVC_LEVEL_BAR (widget); #if !GTK_CHECK_VERSION (3, 0, 0) cr = gdk_cairo_create (gtk_widget_get_window (widget)); gtk_widget_get_allocation (widget, &allocation); cairo_translate (cr, allocation.x, allocation.y); #endif if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) { int i; int by; for (i = 0; i < NUM_BOXES; i++) { by = i * bar->priv->layout.delta; curved_rectangle (cr, bar->priv->layout.area.x + 0.5, by + 0.5, bar->priv->layout.box_width - 1, bar->priv->layout.box_height - 1, bar->priv->layout.box_radius); if ((bar->priv->layout.max_peak_num - 1) == i) { /* fill peak foreground */ cairo_set_source_rgb (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b); cairo_fill_preserve (cr); } else if ((bar->priv->layout.peak_num - 1) >= i) { /* fill background */ cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b); cairo_fill_preserve (cr); /* fill foreground */ cairo_set_source_rgba (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b, 0.5); cairo_fill_preserve (cr); } else { /* fill background */ cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b); cairo_fill_preserve (cr); } /* stroke border */ cairo_set_source_rgb (cr, bar->priv->layout.bdr_r, bar->priv->layout.bdr_g, bar->priv->layout.bdr_b); cairo_set_line_width (cr, 1); cairo_stroke (cr); } } else { int i; int bx; for (i = 0; i < NUM_BOXES; i++) { bx = i * bar->priv->layout.delta; curved_rectangle (cr, bx + 0.5, bar->priv->layout.area.y + 0.5, bar->priv->layout.box_width - 1, bar->priv->layout.box_height - 1, bar->priv->layout.box_radius); if ((bar->priv->layout.max_peak_num - 1) == i) { /* fill peak foreground */ cairo_set_source_rgb (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b); cairo_fill_preserve (cr); } else if ((bar->priv->layout.peak_num - 1) >= i) { /* fill background */ cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b); cairo_fill_preserve (cr); /* fill foreground */ cairo_set_source_rgba (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b, 0.5); cairo_fill_preserve (cr); } else { /* fill background */ cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b); cairo_fill_preserve (cr); } /* stroke border */ cairo_set_source_rgb (cr, bar->priv->layout.bdr_r, bar->priv->layout.bdr_g, bar->priv->layout.bdr_b); cairo_set_line_width (cr, 1); cairo_stroke (cr); } } #if !GTK_CHECK_VERSION (3, 0, 0) cairo_destroy (cr); #endif return FALSE; } static void gvc_level_bar_class_init (GvcLevelBarClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->constructor = gvc_level_bar_constructor; object_class->finalize = gvc_level_bar_finalize; object_class->set_property = gvc_level_bar_set_property; object_class->get_property = gvc_level_bar_get_property; #if GTK_CHECK_VERSION (3, 0, 0) widget_class->draw = gvc_level_bar_draw; widget_class->get_preferred_width = gvc_level_bar_get_preferred_width; widget_class->get_preferred_height = gvc_level_bar_get_preferred_height; #else widget_class->expose_event = gvc_level_bar_expose; widget_class->size_request = gvc_level_bar_size_request; #endif widget_class->size_allocate = gvc_level_bar_size_allocate; g_object_class_install_property (object_class, PROP_ORIENTATION, g_param_spec_enum ("orientation", "Orientation", "The orientation of the bar", GTK_TYPE_ORIENTATION, GTK_ORIENTATION_HORIZONTAL, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_PEAK_ADJUSTMENT, g_param_spec_object ("peak-adjustment", "Peak Adjustment", "The GtkAdjustment that contains the current peak value", GTK_TYPE_ADJUSTMENT, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_RMS_ADJUSTMENT, g_param_spec_object ("rms-adjustment", "RMS Adjustment", "The GtkAdjustment that contains the current rms value", GTK_TYPE_ADJUSTMENT, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_SCALE, g_param_spec_int ("scale", "Scale", "Scale", 0, G_MAXINT, GVC_LEVEL_SCALE_LINEAR, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_type_class_add_private (klass, sizeof (GvcLevelBarPrivate)); } static void gvc_level_bar_init (GvcLevelBar *bar) { bar->priv = GVC_LEVEL_BAR_GET_PRIVATE (bar); bar->priv->peak_adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 1.0, 0.05, 0.1, 0.1)); g_object_ref_sink (bar->priv->peak_adjustment); g_signal_connect (bar->priv->peak_adjustment, "value-changed", G_CALLBACK (on_peak_adjustment_value_changed), bar); bar->priv->rms_adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 1.0, 0.05, 0.1, 0.1)); g_object_ref_sink (bar->priv->rms_adjustment); g_signal_connect (bar->priv->rms_adjustment, "value-changed", G_CALLBACK (on_rms_adjustment_value_changed), bar); gtk_widget_set_has_window (GTK_WIDGET (bar), FALSE); } static void gvc_level_bar_finalize (GObject *object) { GvcLevelBar *bar; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_LEVEL_BAR (object)); bar = GVC_LEVEL_BAR (object); if (bar->priv->max_peak_id > 0) { g_source_remove (bar->priv->max_peak_id); } g_return_if_fail (bar->priv != NULL); G_OBJECT_CLASS (gvc_level_bar_parent_class)->finalize (object); } GtkWidget * gvc_level_bar_new (void) { GObject *bar; bar = g_object_new (GVC_TYPE_LEVEL_BAR, NULL); return GTK_WIDGET (bar); } ukui-control-center/panels/volume-control/gvc-balance-bar.h0000664000175000017500000000513213057175444022750 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __GVC_BALANCE_BAR_H #define __GVC_BALANCE_BAR_H #include #include "gvc-channel-map.h" G_BEGIN_DECLS #define GVC_TYPE_BALANCE_BAR (gvc_balance_bar_get_type ()) #define GVC_BALANCE_BAR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_BALANCE_BAR, GvcBalanceBar)) #define GVC_BALANCE_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_BALANCE_BAR, GvcBalanceBarClass)) #define GVC_IS_BALANCE_BAR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_BALANCE_BAR)) #define GVC_IS_BALANCE_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_BALANCE_BAR)) #define GVC_BALANCE_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_BALANCE_BAR, GvcBalanceBarClass)) typedef enum { BALANCE_TYPE_RL, BALANCE_TYPE_FR, BALANCE_TYPE_LFE, } GvcBalanceType; #define NUM_BALANCE_TYPES BALANCE_TYPE_LFE + 1 typedef struct GvcBalanceBarPrivate GvcBalanceBarPrivate; typedef struct { #if GTK_CHECK_VERSION (3, 0, 0) GtkBox parent; #else GtkHBox parent; #endif GvcBalanceBarPrivate *priv; } GvcBalanceBar; typedef struct { #if GTK_CHECK_VERSION (3, 0, 0) GtkBoxClass parent_class; #else GtkHBoxClass parent_class; #endif } GvcBalanceBarClass; GType gvc_balance_bar_get_type (void); GtkWidget * gvc_balance_bar_new (const GvcChannelMap *map, GvcBalanceType btype); void gvc_balance_bar_set_size_group (GvcBalanceBar *bar, GtkSizeGroup *group, gboolean symmetric); G_END_DECLS #endif /* __GVC_BALANCE_BAR_H */ ukui-control-center/panels/volume-control/gvc-speaker-test.c0000664000175000017500000004405113253611037023215 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2009 Bastien Nocera * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include "gvc-speaker-test.h" #include "gvc-mixer-stream.h" #include "gvc-mixer-card.h" #define GVC_SPEAKER_TEST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_SPEAKER_TEST, GvcSpeakerTestPrivate)) struct GvcSpeakerTestPrivate { GtkWidget *channel_controls[PA_CHANNEL_POSITION_MAX]; ca_context *canberra; GvcMixerCard *card; GvcMixerControl *control; }; enum { COL_NAME, COL_HUMAN_NAME, NUM_COLS }; enum { PROP_0, PROP_CARD, PROP_CONTROL }; static void gvc_speaker_test_class_init (GvcSpeakerTestClass *klass); static void gvc_speaker_test_init (GvcSpeakerTest *speaker_test); static void gvc_speaker_test_finalize (GObject *object); static void update_channel_map (GvcSpeakerTest *speaker_test); G_DEFINE_TYPE (GvcSpeakerTest, gvc_speaker_test, GTK_TYPE_TABLE) static const int position_table[] = { /* Position, X, Y */ PA_CHANNEL_POSITION_FRONT_LEFT, 0, 0, PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, 1, 0, PA_CHANNEL_POSITION_FRONT_CENTER, 2, 0, PA_CHANNEL_POSITION_MONO, 2, 0, PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, 3, 0, PA_CHANNEL_POSITION_FRONT_RIGHT, 4, 0, PA_CHANNEL_POSITION_SIDE_LEFT, 0, 1, PA_CHANNEL_POSITION_SIDE_RIGHT, 4, 1, PA_CHANNEL_POSITION_REAR_LEFT, 0, 2, PA_CHANNEL_POSITION_REAR_CENTER, 2, 2, PA_CHANNEL_POSITION_REAR_RIGHT, 4, 2, PA_CHANNEL_POSITION_LFE, 3, 2 }; static void gvc_speaker_test_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GvcSpeakerTest *self = GVC_SPEAKER_TEST (object); switch (prop_id) { case PROP_CARD: self->priv->card = g_value_dup_object (value); if (self->priv->control != NULL) update_channel_map (self); break; case PROP_CONTROL: self->priv->control = g_value_dup_object (value); if (self->priv->card != NULL) update_channel_map (self); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gvc_speaker_test_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GvcSpeakerTest *self = GVC_SPEAKER_TEST (object); switch (prop_id) { case PROP_CARD: g_value_set_object (value, self->priv->card); break; case PROP_CONTROL: g_value_set_object (value, self->priv->control); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gvc_speaker_test_class_init (GvcSpeakerTestClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gvc_speaker_test_finalize; object_class->set_property = gvc_speaker_test_set_property; object_class->get_property = gvc_speaker_test_get_property; g_object_class_install_property (object_class, PROP_CARD, g_param_spec_object ("card", "card", "The card", GVC_TYPE_MIXER_CARD, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_CONTROL, g_param_spec_object ("control", "control", "The mixer controller", GVC_TYPE_MIXER_CONTROL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); g_type_class_add_private (klass, sizeof (GvcSpeakerTestPrivate)); } static const char * sound_name (pa_channel_position_t position) { switch (position) { case PA_CHANNEL_POSITION_FRONT_LEFT: return "audio-channel-front-left"; case PA_CHANNEL_POSITION_FRONT_RIGHT: return "audio-channel-front-right"; case PA_CHANNEL_POSITION_FRONT_CENTER: return "audio-channel-front-center"; case PA_CHANNEL_POSITION_REAR_LEFT: return "audio-channel-rear-left"; case PA_CHANNEL_POSITION_REAR_RIGHT: return "audio-channel-rear-right"; case PA_CHANNEL_POSITION_REAR_CENTER: return "audio-channel-rear-center"; case PA_CHANNEL_POSITION_LFE: return "audio-channel-lfe"; case PA_CHANNEL_POSITION_SIDE_LEFT: return "audio-channel-side-left"; case PA_CHANNEL_POSITION_SIDE_RIGHT: return "audio-channel-side-right"; default: return NULL; } } static const char * icon_name (pa_channel_position_t position, gboolean playing) { switch (position) { case PA_CHANNEL_POSITION_FRONT_LEFT: return playing ? "audio-speaker-left-testing" : "audio-speaker-left"; case PA_CHANNEL_POSITION_FRONT_RIGHT: return playing ? "audio-speaker-right-testing" : "audio-speaker-right"; case PA_CHANNEL_POSITION_FRONT_CENTER: return playing ? "audio-speaker-center-testing" : "audio-speaker-center"; case PA_CHANNEL_POSITION_REAR_LEFT: return playing ? "audio-speaker-left-back-testing" : "audio-speaker-left-back"; case PA_CHANNEL_POSITION_REAR_RIGHT: return playing ? "audio-speaker-right-back-testing" : "audio-speaker-right-back"; case PA_CHANNEL_POSITION_REAR_CENTER: return playing ? "audio-speaker-center-back-testing" : "audio-speaker-center-back"; case PA_CHANNEL_POSITION_LFE: return playing ? "audio-subwoofer-testing" : "audio-subwoofer"; case PA_CHANNEL_POSITION_SIDE_LEFT: return playing ? "audio-speaker-left-side-testing" : "audio-speaker-left-side"; case PA_CHANNEL_POSITION_SIDE_RIGHT: return playing ? "audio-speaker-right-side-testing" : "audio-speaker-right-side"; default: return NULL; } } static void update_button (GtkWidget *control) { GtkWidget *button; GtkWidget *image; pa_channel_position_t position; gboolean playing; button = g_object_get_data (G_OBJECT (control), "button"); image = g_object_get_data (G_OBJECT (control), "image"); position = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (control), "position")); playing = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (control), "playing")); gtk_button_set_label (GTK_BUTTON (button), playing ? _("Stop") : _("Test")); gtk_image_set_from_icon_name (GTK_IMAGE (image), icon_name (position, playing), GTK_ICON_SIZE_DIALOG); } static const char * pretty_position (pa_channel_position_t position) { if (position == PA_CHANNEL_POSITION_LFE) return _("Subwoofer"); return pa_channel_position_to_pretty_string (position); } static gboolean idle_cb (GtkWidget *control) { if (control == NULL) return FALSE; /* This is called in the background thread, hence * forward to main thread via idle callback */ g_object_set_data (G_OBJECT (control), "playing", GINT_TO_POINTER(FALSE)); update_button (control); return FALSE; } static void finish_cb (ca_context *c, uint32_t id, int error_code, void *userdata) { GtkWidget *control = (GtkWidget *) userdata; if (error_code == CA_ERROR_DESTROYED || control == NULL) return; g_idle_add ((GSourceFunc) idle_cb, control); } static void on_test_button_clicked (GtkButton *button, GtkWidget *control) { gboolean playing; ca_context *canberra; canberra = g_object_get_data (G_OBJECT (control), "canberra"); ca_context_cancel (canberra, 1); playing = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (control), "playing")); if (playing) { g_object_set_data (G_OBJECT (control), "playing", GINT_TO_POINTER(FALSE)); } else { pa_channel_position_t position; const char *name; ca_proplist *proplist; position = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (control), "position")); ca_proplist_create (&proplist); ca_proplist_sets (proplist, CA_PROP_MEDIA_ROLE, "test"); ca_proplist_sets (proplist, CA_PROP_MEDIA_NAME, pretty_position (position)); ca_proplist_sets (proplist, CA_PROP_CANBERRA_FORCE_CHANNEL, pa_channel_position_to_string (position)); ca_proplist_sets (proplist, CA_PROP_CANBERRA_ENABLE, "1"); name = sound_name (position); if (name != NULL) { ca_proplist_sets (proplist, CA_PROP_EVENT_ID, name); playing = ca_context_play_full (canberra, 1, proplist, finish_cb, control) >= 0; } if (!playing) { ca_proplist_sets (proplist, CA_PROP_EVENT_ID, "audio-test-signal"); playing = ca_context_play_full (canberra, 1, proplist, finish_cb, control) >= 0; } if (!playing) { ca_proplist_sets(proplist, CA_PROP_EVENT_ID, "bell-window-system"); playing = ca_context_play_full (canberra, 1, proplist, finish_cb, control) >= 0; } g_object_set_data (G_OBJECT (control), "playing", GINT_TO_POINTER(playing)); } update_button (control); } static GtkWidget * channel_control_new (ca_context *canberra, pa_channel_position_t position) { GtkWidget *control; GtkWidget *box; GtkWidget *label; GtkWidget *image; GtkWidget *test_button; const char *name; control = gtk_vbox_new (FALSE, 6); g_object_set_data (G_OBJECT (control), "playing", GINT_TO_POINTER(FALSE)); g_object_set_data (G_OBJECT (control), "position", GINT_TO_POINTER(position)); g_object_set_data (G_OBJECT (control), "canberra", canberra); name = icon_name (position, FALSE); if (name == NULL) name = "audio-volume-medium"; image = gtk_image_new_from_icon_name (name, GTK_ICON_SIZE_DIALOG); g_object_set_data (G_OBJECT (control), "image", image); gtk_box_pack_start (GTK_BOX (control), image, FALSE, FALSE, 0); label = gtk_label_new (pretty_position (position)); gtk_box_pack_start (GTK_BOX (control), label, FALSE, FALSE, 0); test_button = gtk_button_new_with_label (_("Test")); g_signal_connect (G_OBJECT (test_button), "clicked", G_CALLBACK (on_test_button_clicked), control); g_object_set_data (G_OBJECT (control), "button", test_button); box = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (box), test_button, TRUE, FALSE, 0); gtk_box_pack_start (GTK_BOX (control), box, FALSE, FALSE, 0); gtk_widget_show_all (control); return control; } static void create_channel_controls (GvcSpeakerTest *speaker_test) { guint i; for (i = 0; i < G_N_ELEMENTS (position_table); i += 3) { speaker_test->priv->channel_controls[position_table[i]] = channel_control_new (speaker_test->priv->canberra, (pa_channel_position_t) position_table[i]); gtk_table_attach (GTK_TABLE (speaker_test), speaker_test->priv->channel_controls[position_table[i]], position_table[i+1], position_table[i+1]+1, position_table[i+2], position_table[i+2]+1, GTK_EXPAND, GTK_EXPAND, 0, 0); } } static const GvcChannelMap * get_channel_map_for_card (GvcMixerControl *control, GvcMixerCard *card, char **output_name) { int card_index; GSList *sinks, *l; GvcMixerStream *stream; const GvcChannelMap *map; /* This gets the channel map for the only * output for the card */ card_index = gvc_mixer_card_get_index (card); if (card_index == PA_INVALID_INDEX) return NULL; sinks = gvc_mixer_control_get_sinks (control); stream = NULL; for (l = sinks; l != NULL; l = l->next) { GvcMixerStream *s = l->data; if (gvc_mixer_stream_get_card_index (s) == card_index) { stream = g_object_ref (s); break; } } g_slist_free (sinks); g_assert (stream); g_debug ("Found stream '%s' for card '%s'", gvc_mixer_stream_get_name (stream), gvc_mixer_card_get_name (card)); *output_name = g_strdup (gvc_mixer_stream_get_name (stream)); map = gvc_mixer_stream_get_channel_map (stream); g_debug ("Got channel map '%s' for port '%s'", gvc_channel_map_get_mapping (map), *output_name); return map; } static void update_channel_map (GvcSpeakerTest *speaker_test) { guint i; const GvcChannelMap *map; char *output_name; g_return_if_fail (speaker_test->priv->control != NULL); g_return_if_fail (speaker_test->priv->card != NULL); g_debug ("XXX update_channel_map called XXX"); map = get_channel_map_for_card (speaker_test->priv->control, speaker_test->priv->card, &output_name); g_return_if_fail (map != NULL); ca_context_change_device (speaker_test->priv->canberra, output_name); g_free (output_name); for (i = 0; i < G_N_ELEMENTS (position_table); i += 3) { gtk_widget_set_visible (speaker_test->priv->channel_controls[position_table[i]], gvc_channel_map_has_position(map, position_table[i])); } } static void gvc_speaker_test_init (GvcSpeakerTest *speaker_test) { GtkWidget *face; speaker_test->priv = GVC_SPEAKER_TEST_GET_PRIVATE (speaker_test); ca_context_create (&speaker_test->priv->canberra); ca_context_set_driver (speaker_test->priv->canberra, "pulse"); ca_context_change_props (speaker_test->priv->canberra, CA_PROP_APPLICATION_ID, "org.ukui.VolumeControl", NULL); gtk_table_resize (GTK_TABLE (speaker_test), 3, 5); gtk_container_set_border_width (GTK_CONTAINER (speaker_test), 12); gtk_table_set_homogeneous (GTK_TABLE (speaker_test), TRUE); gtk_table_set_row_spacings (GTK_TABLE (speaker_test), 12); gtk_table_set_col_spacings (GTK_TABLE (speaker_test), 12); create_channel_controls (speaker_test); face = gtk_image_new_from_icon_name ("face-smile", GTK_ICON_SIZE_DIALOG); gtk_table_attach (GTK_TABLE (speaker_test), face, 2, 3, 1, 2, GTK_EXPAND, GTK_EXPAND, 0, 0); gtk_widget_show (face); } static void gvc_speaker_test_finalize (GObject *object) { GvcSpeakerTest *speaker_test; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_SPEAKER_TEST (object)); speaker_test = GVC_SPEAKER_TEST (object); g_return_if_fail (speaker_test->priv != NULL); g_object_unref (speaker_test->priv->card); speaker_test->priv->card = NULL; g_object_unref (speaker_test->priv->control); speaker_test->priv->control = NULL; ca_context_destroy (speaker_test->priv->canberra); speaker_test->priv->canberra = NULL; G_OBJECT_CLASS (gvc_speaker_test_parent_class)->finalize (object); } GtkWidget * gvc_speaker_test_new (GvcMixerControl *control, GvcMixerCard *card) { GObject *speaker_test; g_return_val_if_fail (card != NULL, NULL); g_return_val_if_fail (control != NULL, NULL); speaker_test = g_object_new (GVC_TYPE_SPEAKER_TEST, "card", card, "control", control, NULL); return GTK_WIDGET (speaker_test); } ukui-control-center/panels/volume-control/gvc-sound-theme-chooser.c0000664000175000017500000012613613253611037024503 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Bastien Nocera * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include "gvc-sound-theme-chooser.h" #include "sound-theme-file-utils.h" #define GVC_SOUND_THEME_CHOOSER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_SOUND_THEME_CHOOSER, GvcSoundThemeChooserPrivate)) struct GvcSoundThemeChooserPrivate { GtkWidget *combo_box; GtkWidget *treeview; GtkWidget *theme_box; GtkWidget *selection_box; GtkWidget *click_feedback_button; GSettings *sound_settings; GSettings *marco_settings; }; static void gvc_sound_theme_chooser_class_init (GvcSoundThemeChooserClass *klass); static void gvc_sound_theme_chooser_init (GvcSoundThemeChooser *sound_theme_chooser); static void gvc_sound_theme_chooser_finalize (GObject *object); #if GTK_CHECK_VERSION (3, 0, 0) G_DEFINE_TYPE (GvcSoundThemeChooser, gvc_sound_theme_chooser, GTK_TYPE_BOX) #else G_DEFINE_TYPE (GvcSoundThemeChooser, gvc_sound_theme_chooser, GTK_TYPE_VBOX) #endif #define KEY_SOUNDS_SCHEMA "org.mate.sound" #define EVENT_SOUNDS_KEY "event-sounds" #define INPUT_SOUNDS_KEY "input-feedback-sounds" #define SOUND_THEME_KEY "theme-name" #define KEY_MARCO_SCHEMA "org.gnome.desktop.wm.preferences" #define AUDIO_BELL_KEY "audible-bell" #define DEFAULT_ALERT_ID "__default" #define CUSTOM_THEME_NAME "__custom" #define NO_SOUNDS_THEME_NAME "__no_sounds" enum { THEME_DISPLAY_COL, THEME_IDENTIFIER_COL, THEME_PARENT_ID_COL, THEME_NUM_COLS }; enum { ALERT_DISPLAY_COL, ALERT_IDENTIFIER_COL, ALERT_SOUND_TYPE_COL, ALERT_ACTIVE_COL, ALERT_NUM_COLS }; enum { SOUND_TYPE_UNSET, SOUND_TYPE_OFF, SOUND_TYPE_DEFAULT_FROM_THEME, SOUND_TYPE_BUILTIN, SOUND_TYPE_CUSTOM }; static void on_combobox_changed (GtkComboBox *widget, GvcSoundThemeChooser *chooser) { GtkTreeIter iter; GtkTreeModel *model; char *theme_name; if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (chooser->priv->combo_box), &iter) == FALSE) { return; } model = gtk_combo_box_get_model (GTK_COMBO_BOX (chooser->priv->combo_box)); gtk_tree_model_get (model, &iter, THEME_IDENTIFIER_COL, &theme_name, -1); g_assert (theme_name != NULL); //更新theme_name必须要放在其他gsettings的设置之前,因为其他的设置更改会触发changed信号而重新加载combo_box的内容 g_settings_set_string (chooser->priv->sound_settings, SOUND_THEME_KEY, theme_name); /* special case for no sounds */ if (strcmp (theme_name, NO_SOUNDS_THEME_NAME) == 0) { g_settings_set_boolean (chooser->priv->sound_settings, EVENT_SOUNDS_KEY, FALSE); return; } else { g_settings_set_boolean (chooser->priv->sound_settings, EVENT_SOUNDS_KEY, TRUE); } //g_settings_set_string (chooser->priv->sound_settings, SOUND_THEME_KEY, theme_name); g_free (theme_name); /* FIXME: reset alert model */ } static char * load_index_theme_name (const char *index, char **parent) { GKeyFile *file; char *indexname = NULL; gboolean hidden; file = g_key_file_new (); if (g_key_file_load_from_file (file, index, G_KEY_FILE_KEEP_TRANSLATIONS, NULL) == FALSE) { g_key_file_free (file); return NULL; } /* Don't add hidden themes to the list */ hidden = g_key_file_get_boolean (file, "Sound Theme", "Hidden", NULL); if (!hidden) { indexname = g_key_file_get_locale_string (file, "Sound Theme", "Name", NULL, NULL); /* Save the parent theme, if there's one */ if (parent != NULL) { *parent = g_key_file_get_string (file, "Sound Theme", "Inherits", NULL); } } g_key_file_free (file); return indexname; } static void sound_theme_in_dir (GHashTable *hash, const char *dir) { GDir *d; const char *name; d = g_dir_open (dir, 0, NULL); if (d == NULL) { return; } while ((name = g_dir_read_name (d)) != NULL) { char *dirname, *index, *indexname; /* Look for directories */ dirname = g_build_filename (dir, name, NULL); if (g_file_test (dirname, G_FILE_TEST_IS_DIR) == FALSE) { g_free (dirname); continue; } /* Look for index files */ index = g_build_filename (dirname, "index.theme", NULL); g_free (dirname); /* Check the name of the theme in the index.theme file */ indexname = load_index_theme_name (index, NULL); g_free (index); if (indexname == NULL) { continue; } g_hash_table_insert (hash, g_strdup (name), indexname); } g_dir_close (d); } static void add_theme_to_store (const char *key, const char *value, GtkListStore *store) { char *parent; parent = NULL; /* Get the parent, if we're checking the custom theme */ if (strcmp (key, CUSTOM_THEME_NAME) == 0) { char *name, *path; path = custom_theme_dir_path ("index.theme"); name = load_index_theme_name (path, &parent); g_free (name); g_free (path); } if(strcmp (value, "Default") == 0) { gtk_list_store_insert_with_values (store, NULL, G_MAXINT, THEME_DISPLAY_COL, _("Default"), THEME_IDENTIFIER_COL, key, THEME_PARENT_ID_COL, parent, -1); } else { gtk_list_store_insert_with_values (store, NULL, G_MAXINT, THEME_DISPLAY_COL, value, THEME_IDENTIFIER_COL, key, THEME_PARENT_ID_COL, parent, -1); } g_free (parent); } static void set_combox_for_theme_name (GvcSoundThemeChooser *chooser, const char *name) { GtkTreeIter iter; GtkTreeModel *model; gboolean found; /* If the name is empty, use "freedesktop" */ if (name == NULL || *name == '\0') { name = "freedesktop"; } model = gtk_combo_box_get_model (GTK_COMBO_BOX (chooser->priv->combo_box)); if (gtk_tree_model_get_iter_first (model, &iter) == FALSE) { return; } do { char *value; gtk_tree_model_get (model, &iter, THEME_IDENTIFIER_COL, &value, -1); found = (value != NULL && strcmp (value, name) == 0); g_free (value); } while (!found && gtk_tree_model_iter_next (model, &iter)); /* When we can't find the theme we need to set, try to set the default * one "freedesktop" */ if (found) { gtk_combo_box_set_active_iter (GTK_COMBO_BOX (chooser->priv->combo_box), &iter); } else if (strcmp (name, "freedesktop") != 0) { g_debug ("not found, falling back to fdo"); set_combox_for_theme_name (chooser, "freedesktop"); } } static void set_input_feedback_enabled (GvcSoundThemeChooser *chooser, gboolean enabled) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (chooser->priv->click_feedback_button), enabled); } static void setup_theme_selector (GvcSoundThemeChooser *chooser) { GHashTable *hash; GtkListStore *store; GtkCellRenderer *renderer; const char * const *data_dirs; const char *data_dir; char *dir; guint i; /* Add the theme names and their display name to a hash table, * makes it easy to avoid duplicate themes */ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); data_dirs = g_get_system_data_dirs (); for (i = 0; data_dirs[i] != NULL; i++) { dir = g_build_filename (data_dirs[i], "sounds", NULL); sound_theme_in_dir (hash, dir); g_free (dir); } data_dir = g_get_user_data_dir (); dir = g_build_filename (data_dir, "sounds", NULL); sound_theme_in_dir (hash, dir); g_free (dir); /* If there isn't at least one theme, make everything * insensitive, LAME! */ if (g_hash_table_size (hash) == 0) { gtk_widget_set_sensitive (GTK_WIDGET (chooser), FALSE); g_warning ("Bad setup, install the freedesktop sound theme"); g_hash_table_destroy (hash); return; } /* Setup the tree model, 3 columns: * - internal theme name/directory * - display theme name * - the internal id for the parent theme, used for the custom theme */ store = gtk_list_store_new (THEME_NUM_COLS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); /* Add the themes to a combobox */ gtk_list_store_insert_with_values (store, NULL, G_MAXINT, THEME_DISPLAY_COL, _("No sounds"), THEME_IDENTIFIER_COL, "__no_sounds", THEME_PARENT_ID_COL, NULL, -1); g_hash_table_foreach (hash, (GHFunc) add_theme_to_store, store); g_hash_table_destroy (hash); /* Set the display */ gtk_combo_box_set_model (GTK_COMBO_BOX (chooser->priv->combo_box), GTK_TREE_MODEL (store)); renderer = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (chooser->priv->combo_box), renderer, TRUE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (chooser->priv->combo_box), renderer, "text", THEME_DISPLAY_COL, NULL); g_signal_connect (chooser->priv->combo_box, "changed", G_CALLBACK (on_combobox_changed), chooser); } #define GVC_SOUND_SOUND (xmlChar *) "sound" #define GVC_SOUND_NAME (xmlChar *) "name" #define GVC_SOUND_FILENAME (xmlChar *) "filename" /* Adapted from yelp-toc-pager.c */ static xmlChar * xml_get_and_trim_names (xmlNodePtr node) { xmlNodePtr cur, keep = NULL; xmlChar *keep_lang = NULL; xmlChar *value; int j, keep_pri = INT_MAX; const gchar * const * langs = g_get_language_names (); value = NULL; for (cur = node->children; cur; cur = cur->next) { if (! xmlStrcmp (cur->name, GVC_SOUND_NAME)) { xmlChar *cur_lang = NULL; int cur_pri = INT_MAX; cur_lang = xmlNodeGetLang (cur); if (cur_lang) { for (j = 0; langs[j]; j++) { if (g_str_equal (cur_lang, langs[j])) { cur_pri = j; break; } } } else { cur_pri = INT_MAX - 1; } if (cur_pri <= keep_pri) { if (keep_lang) xmlFree (keep_lang); if (value) xmlFree (value); value = xmlNodeGetContent (cur); keep_lang = cur_lang; keep_pri = cur_pri; keep = cur; } else { if (cur_lang) xmlFree (cur_lang); } } } /* Delete all GVC_SOUND_NAME nodes */ cur = node->children; while (cur) { xmlNodePtr this = cur; cur = cur->next; if (! xmlStrcmp (this->name, GVC_SOUND_NAME)) { xmlUnlinkNode (this); xmlFreeNode (this); } } return value; } static void populate_model_from_node (GvcSoundThemeChooser *chooser, GtkTreeModel *model, xmlNodePtr node) { xmlNodePtr child; xmlChar *filename; xmlChar *name; filename = NULL; name = xml_get_and_trim_names (node); for (child = node->children; child; child = child->next) { if (xmlNodeIsText (child)) { continue; } if (xmlStrcmp (child->name, GVC_SOUND_FILENAME) == 0) { filename = xmlNodeGetContent (child); } else if (xmlStrcmp (child->name, GVC_SOUND_NAME) == 0) { /* EH? should have been trimmed */ } } if (filename != NULL && name != NULL) { gtk_list_store_insert_with_values (GTK_LIST_STORE (model), NULL, G_MAXINT, ALERT_IDENTIFIER_COL, filename, ALERT_DISPLAY_COL, name, ALERT_SOUND_TYPE_COL, _("Built-in"), ALERT_ACTIVE_COL, FALSE, -1); } xmlFree (filename); xmlFree (name); } static void populate_model_from_file (GvcSoundThemeChooser *chooser, GtkTreeModel *model, const char *filename) { xmlDocPtr doc; xmlNodePtr root; xmlNodePtr child; gboolean exists; exists = g_file_test (filename, G_FILE_TEST_EXISTS); if (! exists) { return; } doc = xmlParseFile (filename); if (doc == NULL) { return; } root = xmlDocGetRootElement (doc); for (child = root->children; child; child = child->next) { if (xmlNodeIsText (child)) { continue; } if (xmlStrcmp (child->name, GVC_SOUND_SOUND) != 0) { continue; } populate_model_from_node (chooser, model, child); } xmlFreeDoc (doc); } static void populate_model_from_dir (GvcSoundThemeChooser *chooser, GtkTreeModel *model, const char *dirname) { GDir *d; const char *name; d = g_dir_open (dirname, 0, NULL); if (d == NULL) { return; } while ((name = g_dir_read_name (d)) != NULL) { char *path; if (! g_str_has_suffix (name, ".xml")) { continue; } path = g_build_filename (dirname, name, NULL); populate_model_from_file (chooser, model, path); g_free (path); } g_dir_close (d); } static gboolean save_alert_sounds (GvcSoundThemeChooser *chooser, const char *id) { const char *sounds[3] = { "bell-terminal", "bell-window-system", NULL }; char *path; if (strcmp (id, DEFAULT_ALERT_ID) == 0) { delete_old_files (sounds); delete_disabled_files (sounds); } else { delete_old_files (sounds); delete_disabled_files (sounds); add_custom_file (sounds, id); } /* And poke the directory so the theme gets updated */ path = custom_theme_dir_path (NULL); if (utime (path, NULL) != 0) { g_warning ("Failed to update mtime for directory '%s': %s", path, g_strerror (errno)); } g_free (path); return FALSE; } static void update_alert_model (GvcSoundThemeChooser *chooser, const char *id) { GtkTreeModel *model; GtkTreeIter iter; model = gtk_tree_view_get_model (GTK_TREE_VIEW (chooser->priv->treeview)); gtk_tree_model_get_iter_first (model, &iter); do { gboolean toggled; char *this_id; gtk_tree_model_get (model, &iter, ALERT_IDENTIFIER_COL, &this_id, -1); if (strcmp (this_id, id) == 0) { toggled = TRUE; } else { toggled = FALSE; } g_free (this_id); gtk_list_store_set (GTK_LIST_STORE (model), &iter, ALERT_ACTIVE_COL, toggled, -1); } while (gtk_tree_model_iter_next (model, &iter)); } static void update_alert (GvcSoundThemeChooser *chooser, const char *alert_id) { GtkTreeModel *theme_model; GtkTreeIter iter; char *theme; char *parent; gboolean is_custom; gboolean is_default; gboolean add_custom; gboolean remove_custom; theme_model = gtk_combo_box_get_model (GTK_COMBO_BOX (chooser->priv->combo_box)); /* Get the current theme's name, and set the parent */ if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (chooser->priv->combo_box), &iter) == FALSE) { return; } gtk_tree_model_get (theme_model, &iter, THEME_IDENTIFIER_COL, &theme, THEME_IDENTIFIER_COL, &parent, -1); is_custom = strcmp (theme, CUSTOM_THEME_NAME) == 0; is_default = strcmp (alert_id, DEFAULT_ALERT_ID) == 0; /* So a few possibilities: * 1. Named theme, default alert selected: noop * 2. Named theme, alternate alert selected: create new custom with sound * 3. Custom theme, default alert selected: remove sound and possibly custom * 4. Custom theme, alternate alert selected: update custom sound */ add_custom = FALSE; remove_custom = FALSE; if (! is_custom && is_default) { /* remove custom just in case */ remove_custom = TRUE; } else if (! is_custom && ! is_default) { create_custom_theme (parent); save_alert_sounds (chooser, alert_id); add_custom = TRUE; } else if (is_custom && is_default) { save_alert_sounds (chooser, alert_id); /* after removing files check if it is empty */ if (custom_theme_dir_is_empty ()) { remove_custom = TRUE; } } else if (is_custom && ! is_default) { save_alert_sounds (chooser, alert_id); } if (add_custom) { gtk_list_store_insert_with_values (GTK_LIST_STORE (theme_model), NULL, G_MAXINT, THEME_DISPLAY_COL, _("Custom"), THEME_IDENTIFIER_COL, CUSTOM_THEME_NAME, THEME_PARENT_ID_COL, theme, -1); set_combox_for_theme_name (chooser, CUSTOM_THEME_NAME); } else if (remove_custom) { gtk_tree_model_get_iter_first (theme_model, &iter); do { char *this_parent; gtk_tree_model_get (theme_model, &iter, THEME_PARENT_ID_COL, &this_parent, -1); if (this_parent != NULL && strcmp (this_parent, CUSTOM_THEME_NAME) != 0) { g_free (this_parent); gtk_list_store_remove (GTK_LIST_STORE (theme_model), &iter); break; } g_free (this_parent); } while (gtk_tree_model_iter_next (theme_model, &iter)); delete_custom_theme_dir (); set_combox_for_theme_name (chooser, parent); } update_alert_model (chooser, alert_id); g_free (theme); g_free (parent); } static void on_alert_toggled (GtkCellRendererToggle *renderer, char *path_str, GvcSoundThemeChooser *chooser) { GtkTreeModel *model; GtkTreeIter iter; GtkTreePath *path; gboolean toggled; char *id; model = gtk_tree_view_get_model (GTK_TREE_VIEW (chooser->priv->treeview)); path = gtk_tree_path_new_from_string (path_str); gtk_tree_model_get_iter (model, &iter, path); gtk_tree_path_free (path); id = NULL; gtk_tree_model_get (model, &iter, ALERT_IDENTIFIER_COL, &id, ALERT_ACTIVE_COL, &toggled, -1); toggled ^= 1; if (toggled) { update_alert (chooser, id); } g_free (id); } static void play_preview_for_path (GvcSoundThemeChooser *chooser, GtkTreePath *path) { GtkTreeModel *model; GtkTreeIter iter; GtkTreeIter theme_iter; char *id; char *parent_theme; model = gtk_tree_view_get_model (GTK_TREE_VIEW (chooser->priv->treeview)); if (gtk_tree_model_get_iter (model, &iter, path) == FALSE) { return; } id = NULL; gtk_tree_model_get (model, &iter, ALERT_IDENTIFIER_COL, &id, -1); if (id == NULL) { return; } parent_theme = NULL; if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (chooser->priv->combo_box), &theme_iter)) { GtkTreeModel *theme_model; char *theme_id; char *parent_id; theme_model = gtk_combo_box_get_model (GTK_COMBO_BOX (chooser->priv->combo_box)); theme_id = NULL; parent_id = NULL; gtk_tree_model_get (theme_model, &theme_iter, THEME_IDENTIFIER_COL, &theme_id, THEME_PARENT_ID_COL, &parent_id, -1); if (theme_id && strcmp (theme_id, CUSTOM_THEME_NAME) == 0) { parent_theme = g_strdup (parent_id); } g_free (theme_id); g_free (parent_id); } /* special case: for the default item on custom themes * play the alert for the parent theme */ if (strcmp (id, DEFAULT_ALERT_ID) == 0) { if (parent_theme != NULL) { ca_gtk_play_for_widget (GTK_WIDGET (chooser), 0, CA_PROP_APPLICATION_NAME, _("Sound Preferences"), CA_PROP_EVENT_ID, "bell-window-system", CA_PROP_CANBERRA_XDG_THEME_NAME, parent_theme, CA_PROP_EVENT_DESCRIPTION, _("Testing event sound"), CA_PROP_CANBERRA_CACHE_CONTROL, "never", CA_PROP_APPLICATION_ID, "org.ukui.VolumeControl", #ifdef CA_PROP_CANBERRA_ENABLE CA_PROP_CANBERRA_ENABLE, "1", #endif NULL); } else { ca_gtk_play_for_widget (GTK_WIDGET (chooser), 0, CA_PROP_APPLICATION_NAME, _("Sound Preferences"), CA_PROP_EVENT_ID, "bell-window-system", CA_PROP_EVENT_DESCRIPTION, _("Testing event sound"), CA_PROP_CANBERRA_CACHE_CONTROL, "never", CA_PROP_APPLICATION_ID, "org.ukui.VolumeControl", #ifdef CA_PROP_CANBERRA_ENABLE CA_PROP_CANBERRA_ENABLE, "1", #endif NULL); } } else { ca_gtk_play_for_widget (GTK_WIDGET (chooser), 0, CA_PROP_APPLICATION_NAME, _("Sound Preferences"), CA_PROP_MEDIA_FILENAME, id, CA_PROP_EVENT_DESCRIPTION, _("Testing event sound"), CA_PROP_CANBERRA_CACHE_CONTROL, "never", CA_PROP_APPLICATION_ID, "org.ukui.VolumeControl", #ifdef CA_PROP_CANBERRA_ENABLE CA_PROP_CANBERRA_ENABLE, "1", #endif NULL); } g_free (parent_theme); g_free (id); } static void on_treeview_row_activated (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, GvcSoundThemeChooser *chooser) { play_preview_for_path (chooser, path); } static void on_treeview_selection_changed (GtkTreeSelection *selection, GvcSoundThemeChooser *chooser) { GList *paths; GtkTreeModel *model; GtkTreePath *path; if (chooser->priv->treeview == NULL) { return; } model = gtk_tree_view_get_model (GTK_TREE_VIEW (chooser->priv->treeview)); paths = gtk_tree_selection_get_selected_rows (selection, &model); if (paths == NULL) { return; } path = paths->data; play_preview_for_path (chooser, path); g_list_foreach (paths, (GFunc)gtk_tree_path_free, NULL); g_list_free (paths); } static GtkWidget * create_alert_treeview (GvcSoundThemeChooser *chooser) { GtkListStore *store; GtkWidget *treeview; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *selection; treeview = gtk_tree_view_new (); g_signal_connect (treeview, "row-activated", G_CALLBACK (on_treeview_row_activated), chooser); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); g_signal_connect (selection, "changed", G_CALLBACK (on_treeview_selection_changed), chooser); /* Setup the tree model, 3 columns: * - display name * - sound id * - sound type */ store = gtk_list_store_new (ALERT_NUM_COLS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); gtk_list_store_insert_with_values (store, NULL, G_MAXINT, ALERT_IDENTIFIER_COL, DEFAULT_ALERT_ID, ALERT_DISPLAY_COL, _("Default"), ALERT_SOUND_TYPE_COL, _("From theme"), ALERT_ACTIVE_COL, TRUE, -1); populate_model_from_dir (chooser, GTK_TREE_MODEL (store), SOUND_SET_DIR); gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store)); renderer = gtk_cell_renderer_toggle_new (); gtk_cell_renderer_toggle_set_radio (GTK_CELL_RENDERER_TOGGLE (renderer), TRUE); column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "active", ALERT_ACTIVE_COL, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); g_signal_connect (renderer, "toggled", G_CALLBACK (on_alert_toggled), chooser); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes (_("Name"), renderer, "text", ALERT_DISPLAY_COL, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes (_("Type"), renderer, "text", ALERT_SOUND_TYPE_COL, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); return treeview; } static int get_file_type (const char *sound_name, char **linked_name) { char *name, *filename; *linked_name = NULL; name = g_strdup_printf ("%s.disabled", sound_name); filename = custom_theme_dir_path (name); g_free (name); if (g_file_test (filename, G_FILE_TEST_IS_REGULAR) != FALSE) { g_free (filename); return SOUND_TYPE_OFF; } g_free (filename); /* We only check for .ogg files because those are the * only ones we create */ name = g_strdup_printf ("%s.ogg", sound_name); filename = custom_theme_dir_path (name); g_free (name); if (g_file_test (filename, G_FILE_TEST_IS_SYMLINK) != FALSE) { *linked_name = g_file_read_link (filename, NULL); g_free (filename); return SOUND_TYPE_CUSTOM; } g_free (filename); return SOUND_TYPE_BUILTIN; } static void update_alerts_from_theme_name (GvcSoundThemeChooser *chooser, const char *name) { if (strcmp (name, CUSTOM_THEME_NAME) != 0) { /* reset alert to default */ update_alert (chooser, DEFAULT_ALERT_ID); } else { int sound_type; char *linkname; linkname = NULL; sound_type = get_file_type ("bell-terminal", &linkname); g_debug ("Found link: %s", linkname); if (sound_type == SOUND_TYPE_CUSTOM) { update_alert (chooser, linkname); } } } static void update_theme (GvcSoundThemeChooser *chooser) { char *theme_name; gboolean events_enabled; gboolean bell_enabled; gboolean feedback_enabled; bell_enabled = g_settings_get_boolean (chooser->priv->marco_settings, AUDIO_BELL_KEY); //set_audible_bell_enabled (chooser, bell_enabled); feedback_enabled = g_settings_get_boolean (chooser->priv->sound_settings, INPUT_SOUNDS_KEY); set_input_feedback_enabled (chooser, feedback_enabled); events_enabled = g_settings_get_boolean (chooser->priv->sound_settings, EVENT_SOUNDS_KEY); if (events_enabled) { theme_name = g_settings_get_string (chooser->priv->sound_settings, SOUND_THEME_KEY); } else { theme_name = g_strdup (NO_SOUNDS_THEME_NAME); } gtk_widget_set_sensitive (chooser->priv->selection_box, events_enabled); gtk_widget_set_sensitive (chooser->priv->click_feedback_button, events_enabled); set_combox_for_theme_name (chooser, theme_name); update_alerts_from_theme_name (chooser, theme_name); g_free (theme_name); } static GObject * gvc_sound_theme_chooser_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; GvcSoundThemeChooser *self; object = G_OBJECT_CLASS (gvc_sound_theme_chooser_parent_class)->constructor (type, n_construct_properties, construct_params); self = GVC_SOUND_THEME_CHOOSER (object); setup_theme_selector (self); update_theme (self); return object; } static void gvc_sound_theme_chooser_class_init (GvcSoundThemeChooserClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = gvc_sound_theme_chooser_constructor; object_class->finalize = gvc_sound_theme_chooser_finalize; g_type_class_add_private (klass, sizeof (GvcSoundThemeChooserPrivate)); } static void on_click_feedback_toggled (GtkToggleButton *button, GvcSoundThemeChooser *chooser) { gboolean enabled; enabled = gtk_toggle_button_get_active (button); g_settings_set_boolean (chooser->priv->sound_settings, INPUT_SOUNDS_KEY, enabled); } static void on_key_changed (GSettings *settings, gchar *key, GvcSoundThemeChooser *chooser) { if (strcmp (key, EVENT_SOUNDS_KEY) == 0) { update_theme (chooser); } else if (strcmp (key, SOUND_THEME_KEY) == 0) { update_theme (chooser); } else if (strcmp (key, INPUT_SOUNDS_KEY) == 0) { update_theme (chooser); } else if (strcmp (key, AUDIO_BELL_KEY) == 0) { update_theme (chooser); } } static void constrain_list_size (GtkWidget *widget, GtkRequisition *requisition, GtkWidget *to_size) { GtkRequisition req; int max_height; /* constrain height to be the tree height up to a max */ max_height = (gdk_screen_get_height (gtk_widget_get_screen (widget))) / 4; gtk_widget_size_request (to_size, &req); requisition->height = MIN (req.height, max_height); } static void setup_list_size_constraint (GtkWidget *widget, GtkWidget *to_size) { g_signal_connect (widget, "size-request", G_CALLBACK (constrain_list_size), to_size); } static void gvc_sound_theme_chooser_init (GvcSoundThemeChooser *chooser) { GtkWidget *box; GtkWidget *label; GtkWidget *scrolled_window; GtkWidget *alignment; GtkWidget *alignment2; GtkWidget *tmp_vbox; char *str; chooser->priv = GVC_SOUND_THEME_CHOOSER_GET_PRIVATE (chooser); chooser->priv->theme_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); // gtk_box_pack_start (GTK_BOX (chooser), // chooser->priv->theme_box, FALSE, FALSE, 0); label = gtk_label_new_with_mnemonic (_("Sound _theme:")); gtk_box_pack_start (GTK_BOX (chooser->priv->theme_box), label, FALSE, FALSE, 0); chooser->priv->combo_box = gtk_combo_box_new (); gtk_box_pack_start (GTK_BOX (chooser->priv->theme_box), chooser->priv->combo_box, FALSE, FALSE, 6); gtk_label_set_mnemonic_widget (GTK_LABEL (label), chooser->priv->combo_box); tmp_vbox=gtk_box_new(GTK_ORIENTATION_VERTICAL,0); gtk_box_pack_start (GTK_BOX (tmp_vbox), chooser->priv->theme_box, FALSE, FALSE, 0); chooser->priv->sound_settings = g_settings_new (KEY_SOUNDS_SCHEMA); chooser->priv->marco_settings = g_settings_new (KEY_MARCO_SCHEMA); str = g_strdup_printf ("%s", _("C_hoose an alert sound:")); chooser->priv->selection_box = box = gtk_frame_new (str); g_free (str); label = gtk_frame_get_label_widget (GTK_FRAME (box)); gtk_label_set_use_underline (GTK_LABEL (label), TRUE); gtk_label_set_use_markup (GTK_LABEL (label), TRUE); gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE); alignment = gtk_alignment_new (0, 0, 1, 1); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0); gtk_container_add (GTK_CONTAINER (alignment), box); //gtk_box_pack_start (GTK_BOX (chooser), alignment, TRUE, TRUE, 6); alignment2 = gtk_alignment_new (0, 0, 1, 1); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment2), 6, 0, 0, 0); gtk_container_add (GTK_CONTAINER (box), alignment2); chooser->priv->treeview = create_alert_treeview (chooser); gtk_label_set_mnemonic_widget (GTK_LABEL (label), chooser->priv->treeview); scrolled_window = gtk_scrolled_window_new (NULL, NULL); setup_list_size_constraint (scrolled_window, chooser->priv->treeview); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN); gtk_container_add (GTK_CONTAINER (scrolled_window), chooser->priv->treeview); gtk_container_add (GTK_CONTAINER (alignment2), scrolled_window); gtk_box_pack_start(GTK_BOX(tmp_vbox),alignment,TRUE,TRUE,6); gtk_box_pack_start(GTK_BOX(chooser),tmp_vbox,TRUE,TRUE,0); chooser->priv->click_feedback_button = gtk_check_button_new_with_mnemonic (_("Enable _window and button sounds")); gtk_widget_set_no_show_all(GTK_WIDGET(chooser->priv->click_feedback_button),TRUE); gtk_widget_hide(GTK_WIDGET(chooser->priv->click_feedback_button)); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (chooser->priv->click_feedback_button), g_settings_get_boolean (chooser->priv->sound_settings, INPUT_SOUNDS_KEY)); // gtk_box_pack_start (GTK_BOX (chooser), // chooser->priv->click_feedback_button, // FALSE, FALSE, 0); g_signal_connect (chooser->priv->click_feedback_button, "toggled", G_CALLBACK (on_click_feedback_toggled), chooser); g_signal_connect (chooser->priv->sound_settings, "changed", G_CALLBACK (on_key_changed), chooser); g_signal_connect (chooser->priv->marco_settings, "changed::" AUDIO_BELL_KEY, G_CALLBACK (on_key_changed), chooser); /* FIXME: should accept drag and drop themes. should also add an "Add Theme..." item to the theme combobox */ } static void gvc_sound_theme_chooser_finalize (GObject *object) { GvcSoundThemeChooser *sound_theme_chooser; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_SOUND_THEME_CHOOSER (object)); sound_theme_chooser = GVC_SOUND_THEME_CHOOSER (object); if (sound_theme_chooser->priv != NULL) { g_object_unref (sound_theme_chooser->priv->sound_settings); sound_theme_chooser->priv->sound_settings = NULL; g_object_unref (sound_theme_chooser->priv->marco_settings); sound_theme_chooser->priv->marco_settings = NULL; } G_OBJECT_CLASS (gvc_sound_theme_chooser_parent_class)->finalize (object); } GtkWidget * gvc_sound_theme_chooser_new (void) { GObject *chooser; chooser = g_object_new (GVC_TYPE_SOUND_THEME_CHOOSER, "spacing", 6, NULL); return GTK_WIDGET (chooser); } ukui-control-center/panels/volume-control/gvc-mixer-card.h0000664000175000017500000000677513057175444022672 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008-2009 Red Hat, Inc. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __GVC_MIXER_CARD_H #define __GVC_MIXER_CARD_H #include #include G_BEGIN_DECLS #define GVC_TYPE_MIXER_CARD (gvc_mixer_card_get_type ()) #define GVC_MIXER_CARD(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_CARD, GvcMixerCard)) #define GVC_MIXER_CARD_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_CARD, GvcMixerCardClass)) #define GVC_IS_MIXER_CARD(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_CARD)) #define GVC_IS_MIXER_CARD_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_CARD)) #define GVC_MIXER_CARD_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_CARD, GvcMixerCardClass)) typedef struct GvcMixerCardPrivate GvcMixerCardPrivate; typedef struct { GObject parent; GvcMixerCardPrivate *priv; } GvcMixerCard; typedef struct { GObjectClass parent_class; /* vtable */ } GvcMixerCardClass; typedef struct { char *profile; char *human_profile; char *status; guint priority; guint n_sinks, n_sources; } GvcMixerCardProfile; GType gvc_mixer_card_get_type (void); GvcMixerCard * gvc_mixer_card_new (pa_context *context, guint index); guint gvc_mixer_card_get_id (GvcMixerCard *card); guint gvc_mixer_card_get_index (GvcMixerCard *card); const char * gvc_mixer_card_get_name (GvcMixerCard *card); const char * gvc_mixer_card_get_icon_name (GvcMixerCard *card); GvcMixerCardProfile * gvc_mixer_card_get_profile (GvcMixerCard *card); const GList * gvc_mixer_card_get_profiles (GvcMixerCard *card); pa_context * gvc_mixer_card_get_pa_context (GvcMixerCard *card); gboolean gvc_mixer_card_change_profile (GvcMixerCard *card, const char *profile); /* private */ gboolean gvc_mixer_card_set_name (GvcMixerCard *card, const char *name); gboolean gvc_mixer_card_set_icon_name (GvcMixerCard *card, const char *name); gboolean gvc_mixer_card_set_profile (GvcMixerCard *card, const char *profile); gboolean gvc_mixer_card_set_profiles (GvcMixerCard *card, GList *profiles); G_END_DECLS #endif /* __GVC_MIXER_CARD_H */ ukui-control-center/panels/default-app/0000775000175000017500000000000013265607112017100 5ustar fengfengukui-control-center/panels/default-app/Makefile.am0000664000175000017500000000103313057175444021140 0ustar fengfengcappletname=default_app noinst_LTLIBRARIES=libdefaultapp.la AUTOMAKE_OPTIONS = foreign #INCLUDES= `pkg-config --cflags gtk+-2.0 gio-2.0 glib-2.0 gdk-pixbuf-2.0` #LIBS= `pkg-config --libs gtk+-2.0 gio-2.0 glib-2.0 gdk-pixbuf-2.0` AM_CPPFLAGS = \ $(GTK_CFLAGS) \ $(GLIB_CFLAGS) \ $(GTK_PIXBUF_CFLAGS) \ $(NULL) libdefaultapp_la_LIBADD = \ $(GTK_LIBS) $(GLIB_LIBS) $(GTK_PIXBUF_LIBS) $(NULL) libdefaultapp_la_SOURCES= \ default-app.c \ default-app.h \ -include $(top_srcdir)/git.mk clean-local : rm -f *~ Makefile.in Makefile ukui-control-center/panels/default-app/default-app.h0000664000175000017500000000177113057175444021470 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef _DEFAULT_APP_H #define _DEFAULT_APP_H #include void add_default_app(GtkBuilder * builder); void default_app_destory(); #endif ukui-control-center/panels/default-app/default-app.c0000664000175000017500000005072113265607112021453 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "default-app.h" #include #include #include #include #include #define APPLICATIONSDIR "/usr/share/applications" #define TERMINAL_SCHEMA "org.mate.applications-terminal" #define TERMINAL_KEY "exec" #define VISUAL_SCHEMA "org.mate.applications-at-visual" #define VISUAL_KEY "exec" #define VISUAL_STARTUP_KEY "startup" #define MOBILITY_SCHEMA "org.mate.applications-at-mobility" #define MOBILITY_KEY "exec" #define MOBILITY_STARTUP_KEY "startup" typedef struct _UkuiDACapplet { //combo box GtkWidget* web_combo_box; GtkWidget* mail_combo_box; GtkWidget* term_combo_box; GtkWidget* media_combo_box; GtkWidget* video_combo_box; GtkWidget* visual_combo_box; GtkWidget* mobility_combo_box; GtkWidget* file_combo_box; GtkWidget* text_combo_box; GtkWidget* image_combo_box; //Lists of available apps GList* web_browsers; GList* mail_readers; GList* terminals; GList* media_players; GList* video_players; GList* visual_ats; GList* mobility_ats; GList* file_managers; GList* text_editors; GList* image_viewers; //Settings object GSettings * terminal_settings; GSettings * visual_settings; GSettings * mobility_settings; GtkIconTheme * icon_theme; }UkuiDACapplet; UkuiDACapplet * capplet; enum { DA_TYPE_WEB_BROWSER, DA_TYPE_EMAIL, DA_TYPE_TERMINAL, DA_TYPE_MEDIA, DA_TYPE_VIDEO, DA_TYPE_VISUAL, DA_TYPE_MOBILITY, DA_TYPE_IMAGE, DA_TYPE_TEXT, DA_TYPE_FILE, DA_N_COLUMNS }; /* For combo box */ enum { PIXBUF_COL, TEXT_COL, ID_COL, ICONAME_COL, N_COLUMNS }; static void set_changed(GtkComboBox* combo, UkuiDACapplet* capplet, GList* list, gint type) { guint index; GAppInfo* item; GSettings* settings; index = gtk_combo_box_get_active(combo); if (index < g_list_length(list)) { item = (GAppInfo*) g_list_nth_data(list, index); switch (type) { case DA_TYPE_WEB_BROWSER: g_app_info_set_as_default_for_type(item, "x-scheme-handler/http", NULL); g_app_info_set_as_default_for_type(item, "x-scheme-handler/https", NULL); /* about:config is used by firefox and others */ g_app_info_set_as_default_for_type(item, "x-scheme-handler/about", NULL); g_app_info_set_as_default_for_type(item, "text/html", NULL); break; case DA_TYPE_EMAIL: g_app_info_set_as_default_for_type(item, "x-scheme-handler/mailto", NULL); g_app_info_set_as_default_for_type(item, "application/x-extension-eml", NULL); g_app_info_set_as_default_for_type(item, "message/rfc822", NULL); break; case DA_TYPE_FILE: g_app_info_set_as_default_for_type(item, "inode/directory", NULL); break; case DA_TYPE_TEXT: g_app_info_set_as_default_for_type(item, "text/plain", NULL); break; case DA_TYPE_MEDIA: g_app_info_set_as_default_for_type(item, "audio/mpeg", NULL); g_app_info_set_as_default_for_type(item, "audio/x-mpegurl", NULL); g_app_info_set_as_default_for_type(item, "audio/x-scpls", NULL); g_app_info_set_as_default_for_type(item, "audio/x-vorbis+ogg", NULL); g_app_info_set_as_default_for_type(item, "audio/x-wav", NULL); break; case DA_TYPE_VIDEO: g_app_info_set_as_default_for_type(item, "video/mp4", NULL); g_app_info_set_as_default_for_type(item, "video/mpeg", NULL); g_app_info_set_as_default_for_type(item, "video/mp2t", NULL); g_app_info_set_as_default_for_type(item, "video/msvideo", NULL); g_app_info_set_as_default_for_type(item, "video/quicktime", NULL); g_app_info_set_as_default_for_type(item, "video/webm", NULL); g_app_info_set_as_default_for_type(item, "video/x-avi", NULL); g_app_info_set_as_default_for_type(item, "video/x-flv", NULL); g_app_info_set_as_default_for_type(item, "video/x-matroska", NULL); g_app_info_set_as_default_for_type(item, "video/x-mpeg", NULL); g_app_info_set_as_default_for_type(item, "video/x-ogm+ogg", NULL); break; case DA_TYPE_IMAGE: g_app_info_set_as_default_for_type(item, "image/bmp", NULL); g_app_info_set_as_default_for_type(item, "image/gif", NULL); g_app_info_set_as_default_for_type(item, "image/jpeg", NULL); g_app_info_set_as_default_for_type(item, "image/png", NULL); g_app_info_set_as_default_for_type(item, "image/tiff", NULL); break; case DA_TYPE_TERMINAL: g_settings_set_string (capplet->terminal_settings, TERMINAL_KEY, g_app_info_get_executable (item)); break; case DA_TYPE_VISUAL: g_settings_set_string (capplet->visual_settings, VISUAL_KEY, g_app_info_get_executable (item)); break; case DA_TYPE_MOBILITY: g_settings_set_string (capplet->mobility_settings, MOBILITY_KEY, g_app_info_get_executable (item)); break; default: break; } } } /* Combo boxes callbacks */ static void web_combo_changed_cb(GtkComboBox* combo, UkuiDACapplet* capplet) { set_changed(combo, capplet, capplet->web_browsers, DA_TYPE_WEB_BROWSER); } static void mail_combo_changed_cb(GtkComboBox* combo, UkuiDACapplet* capplet) { set_changed(combo, capplet, capplet->mail_readers, DA_TYPE_EMAIL); } static void file_combo_changed_cb(GtkComboBox* combo, UkuiDACapplet* capplet) { set_changed(combo, capplet, capplet->file_managers, DA_TYPE_FILE); } static void text_combo_changed_cb(GtkComboBox* combo, UkuiDACapplet* capplet) { set_changed(combo, capplet, capplet->text_editors, DA_TYPE_TEXT); } static void media_combo_changed_cb(GtkComboBox* combo, UkuiDACapplet* capplet) { set_changed(combo, capplet, capplet->media_players, DA_TYPE_MEDIA); } static void video_combo_changed_cb(GtkComboBox* combo, UkuiDACapplet* capplet) { set_changed(combo, capplet, capplet->video_players, DA_TYPE_VIDEO); } /*static void terminal_combo_changed_cb(GtkComboBox* combo, UkuiDACapplet* capplet) { set_changed(combo, capplet, capplet->terminals, DA_TYPE_TERMINAL); }*/ static void visual_combo_changed_cb(GtkComboBox* combo, UkuiDACapplet* capplet) { set_changed(combo, capplet, capplet->visual_ats, DA_TYPE_VISUAL); } static void mobility_combo_changed_cb(GtkComboBox* combo, UkuiDACapplet* capplet) { set_changed(combo, capplet, capplet->mobility_ats, DA_TYPE_MOBILITY); } static void image_combo_changed_cb(GtkComboBox* combo, UkuiDACapplet* capplet) { set_changed(combo, capplet, capplet->image_viewers, DA_TYPE_IMAGE); } static void refresh_combo_box_icons(GtkIconTheme* theme, GtkComboBox* combo_box, GList* app_list) { GtkTreeIter iter; GtkTreeModel* model; gboolean valid; GdkPixbuf* pixbuf; gchar* icon_name; model = gtk_combo_box_get_model(combo_box); if (model == NULL) { //g_warning("refresh_combobox, but model=NULL"); return; } valid = gtk_tree_model_get_iter_first(model, &iter); while (valid) { gtk_tree_model_get(model, &iter, ICONAME_COL, &icon_name, -1); pixbuf = gtk_icon_theme_load_icon(theme, icon_name, 22, 0, NULL); if (pixbuf == NULL) { g_warning("pixbuf ==NULL"); } else { gtk_list_store_set(GTK_LIST_STORE(model), &iter, PIXBUF_COL, pixbuf, -1); } if (pixbuf) { g_object_unref(pixbuf); } g_free(icon_name); valid = gtk_tree_model_iter_next(model, &iter); } } static struct { const char* name; const char* icon; } icons[] = { {"web_browser_image", "web-browser"}, {"mail_reader_image", "emblem-mail"}, {"media_player_image", "audio-x-generic"}, {"visual_image", "zoom-best-fit"}, {"mobility_image", "preferences-desktop-accessibility"}, {"filemanager_image", "file-manager"}, {"imageviewer_image", "image-x-generic"}, {"video_image", "video-x-generic"}, {"text_image", "text-editor"}, }; /* Callback for icon theme change */ static void theme_changed_cb(GtkIconTheme* theme, GtkBuilder * builder) { /*GObject* icon; gint i; for (i = 0; i < G_N_ELEMENTS(icons); i++) { icon = gtk_builder_get_object(builder, icons[i].name); GdkPixbuf* pixbuf = gtk_icon_theme_load_icon(theme, icons[i].icon, 32, 0, NULL); gtk_image_set_from_pixbuf(GTK_IMAGE(icon), pixbuf); if (pixbuf) { g_object_unref(pixbuf); } }*/ refresh_combo_box_icons(theme, GTK_COMBO_BOX(capplet->web_combo_box), capplet->web_browsers); refresh_combo_box_icons(theme, GTK_COMBO_BOX(capplet->mail_combo_box), capplet->mail_readers); refresh_combo_box_icons(theme, GTK_COMBO_BOX(capplet->media_combo_box), capplet->media_players); refresh_combo_box_icons(theme, GTK_COMBO_BOX(capplet->video_combo_box), capplet->video_players); //refresh_combo_box_icons(theme, GTK_COMBO_BOX(capplet->term_combo_box), capplet->terminals); //refresh_combo_box_icons(theme, GTK_COMBO_BOX(capplet->visual_combo_box), capplet->visual_ats); //refresh_combo_box_icons(theme, GTK_COMBO_BOX(capplet->mobility_combo_box), capplet->mobility_ats); refresh_combo_box_icons(theme, GTK_COMBO_BOX(capplet->file_combo_box), capplet->file_managers); refresh_combo_box_icons(theme, GTK_COMBO_BOX(capplet->text_combo_box), capplet->text_editors); } static void screen_changed_cb(GtkWidget* widget, GdkScreen* screen, GtkBuilder * builder) { GtkIconTheme* theme; theme = gtk_icon_theme_get_for_screen (screen); if (capplet->icon_theme != NULL) { g_signal_handlers_disconnect_by_func (capplet->icon_theme, theme_changed_cb, builder); } g_signal_connect (theme, "changed", G_CALLBACK (theme_changed_cb), builder); theme_changed_cb (theme, builder); capplet->icon_theme = theme; } static void fill_combo_box(GtkIconTheme* theme, GtkComboBox* combo_box, GList* app_list, gchar* mime) { guint index = 0; GList* entry; GtkTreeModel* model; GtkCellRenderer* renderer; GtkTreeIter iter; GdkPixbuf* pixbuf; GAppInfo* default_app; default_app = NULL; if (g_strcmp0(mime, "terminal") == 0) { GSettings *terminal_settings = g_settings_new (TERMINAL_SCHEMA); gchar *default_terminal = g_settings_get_string (terminal_settings, TERMINAL_KEY); for (entry = app_list; entry != NULL; entry = g_list_next(entry)) { GAppInfo* item = (GAppInfo*) entry->data; if (g_strcmp0 (g_app_info_get_executable (item), default_terminal) == 0) { default_app = item; } } g_free (default_terminal); g_object_unref (terminal_settings); } else if (g_strcmp0(mime, "visual") == 0) { GSettings *visual_settings = g_settings_new (VISUAL_SCHEMA); gchar *default_visual = g_settings_get_string (visual_settings, VISUAL_KEY); for (entry = app_list; entry != NULL; entry = g_list_next(entry)) { GAppInfo* item = (GAppInfo*) entry->data; if (g_strcmp0 (g_app_info_get_executable (item), default_visual) == 0) { default_app = item; } } g_free (default_visual); g_object_unref (visual_settings); } else if (g_strcmp0(mime, "mobility") == 0) { GSettings *mobility_settings = g_settings_new (MOBILITY_SCHEMA); gchar *default_mobility = g_settings_get_string (mobility_settings, MOBILITY_KEY); for (entry = app_list; entry != NULL; entry = g_list_next(entry)) { GAppInfo* item = (GAppInfo*) entry->data; if (g_strcmp0 (g_app_info_get_executable (item), default_mobility) == 0) { default_app = item; } } g_free (default_mobility); g_object_unref (mobility_settings); } //设置默认的文件管理器为peony,这样做是有问题的,每次打开控制面板都会将文件管理器设为peony //但因为这里屏蔽掉了nautilus,只有一个文件管理器,先暂时这样 //正确的做法是修改系统配置来修改默认的应用 else if (g_strcmp0(mime, "inode/directory") == 0) { for (entry = app_list; entry != NULL; entry = g_list_next(entry)) { GAppInfo* item = (GAppInfo*) entry->data; if(g_strcmp0(g_app_info_get_id(item), "peony-folder-handler.desktop") == 0) default_app = item; } } else { default_app = g_app_info_get_default_for_type (mime, FALSE); } if (theme == NULL) { theme = gtk_icon_theme_get_default(); } model = GTK_TREE_MODEL(gtk_list_store_new(4, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING)); gtk_combo_box_set_model(combo_box, model); renderer = gtk_cell_renderer_pixbuf_new(); /* Not all cells have a pixbuf, this prevents the combo box to shrink */ //这里指定宽度,是为了防止读不到正确尺寸的图标时而导致下拉框变宽 gtk_cell_renderer_set_fixed_size(renderer, -1, 26); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box), renderer, FALSE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), renderer, "pixbuf", PIXBUF_COL, NULL); renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box), renderer, TRUE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), renderer, "text", TEXT_COL, NULL); for (entry = app_list; entry != NULL; entry = g_list_next(entry)) { GAppInfo* item = (GAppInfo*) entry->data; /* Icon */ GIcon* icon = g_app_info_get_icon(item); gchar* icon_name = g_icon_to_string(icon); if(g_strcmp0(g_app_info_get_id(item), "org.gnome.Nautilus.desktop") == 0 || g_strcmp0(g_app_info_get_id(item), "org.gnome.baobab.desktop") == 0 || g_strcmp0(g_app_info_get_id(item), "nautilus-folder-handler.desktop") == 0 || g_strcmp0(g_app_info_get_id(item), "vim.desktop") == 0) continue; //因为浏览器的desktop文件的图标路径不是相对路径,所以稍作转换。 if(g_strrstr(icon_name,"webbrowser")){ icon_name = g_strdup("webbrowser-app"); } if (icon_name == NULL) { /* Default icon */ icon_name = g_strdup("binary"); } pixbuf = gtk_icon_theme_load_icon(theme, icon_name, 20, GTK_ICON_LOOKUP_NO_SVG, NULL); gtk_list_store_append(GTK_LIST_STORE(model), &iter); //Fixme: when pixbuf == NULL if (pixbuf ==NULL) { g_warning("pixbuf == NULL"); gtk_list_store_set(GTK_LIST_STORE(model), &iter, TEXT_COL, g_app_info_get_display_name(item), ID_COL, g_app_info_get_id(item), ICONAME_COL, icon_name, -1); } else { gtk_list_store_set(GTK_LIST_STORE(model), &iter, PIXBUF_COL, pixbuf, TEXT_COL, g_app_info_get_display_name(item), ID_COL, g_app_info_get_id(item), ICONAME_COL, icon_name, -1); } /* Set the index for the default app */ //if (default_app != NULL && g_app_info_equal(item, default_app)) if (default_app != NULL && !strcmp(g_app_info_get_name(item), g_app_info_get_name(default_app))) { //g_warning("text_col=%s\tid_col=%s\ticon_name=%s\n",g_app_info_get_display_name(item), g_app_info_get_id(item),icon_name); gtk_combo_box_set_active(combo_box, index); } if (pixbuf) { g_object_unref(pixbuf); } g_free(icon_name); index++; } } static GList* fill_list_from_desktop_file (GList* app_list, const gchar *desktop_id) { GList* list = app_list; GDesktopAppInfo* appinfo; appinfo = g_desktop_app_info_new_from_filename (desktop_id); if (appinfo != NULL) { list = g_list_prepend (list, appinfo); } return list; } void show_dialog(GtkBuilder * builder) { #define get_widget(name) GTK_WIDGET(gtk_builder_get_object(builder, name)) capplet->web_combo_box = get_widget("web_browser_combobox"); capplet->mail_combo_box = get_widget("mail_reader_combobox"); capplet->term_combo_box = get_widget("terminal_combobox"); capplet->media_combo_box = get_widget("media_player_combobox"); capplet->video_combo_box = get_widget("video_combobox"); //capplet->visual_combo_box = get_widget("visual_combobox"); //capplet->mobility_combo_box = get_widget("mobility_combobox"); capplet->text_combo_box = get_widget("text_combobox"); capplet->file_combo_box = get_widget("filemanager_combobox"); capplet->image_combo_box = get_widget("image_combobox"); screen_changed_cb(NULL, gdk_screen_get_default(), builder); capplet->web_browsers = g_app_info_get_all_for_type("x-scheme-handler/http"); capplet->mail_readers = g_app_info_get_all_for_type("x-scheme-handler/mailto"); capplet->media_players = g_app_info_get_all_for_type("audio/x-vorbis+ogg"); capplet->video_players = g_app_info_get_all_for_type("video/x-ogm+ogg"); capplet->text_editors = g_app_info_get_all_for_type("text/plain"); capplet->image_viewers = g_app_info_get_all_for_type("image/png"); capplet->file_managers = g_app_info_get_all_for_type("inode/directory"); capplet->visual_ats = NULL; capplet->visual_ats = fill_list_from_desktop_file (capplet->visual_ats, APPLICATIONSDIR "/orca.desktop"); capplet->visual_ats = g_list_reverse (capplet->visual_ats); capplet->mobility_ats = NULL; capplet->mobility_ats = fill_list_from_desktop_file (capplet->mobility_ats, APPLICATIONSDIR "/dasher.desktop"); capplet->mobility_ats = fill_list_from_desktop_file (capplet->mobility_ats, APPLICATIONSDIR "/gok.desktop"); capplet->mobility_ats = fill_list_from_desktop_file (capplet->mobility_ats, APPLICATIONSDIR "/onboard.desktop"); capplet->mobility_ats = g_list_reverse (capplet->mobility_ats); fill_combo_box(capplet->icon_theme, GTK_COMBO_BOX(capplet->web_combo_box), capplet->web_browsers, "x-scheme-handler/http"); fill_combo_box(capplet->icon_theme, GTK_COMBO_BOX(capplet->mail_combo_box), capplet->mail_readers, "x-scheme-handler/mailto"); //fill_combo_box(capplet->icon_theme, GTK_COMBO_BOX(capplet->term_combo_box), capplet->terminals, "terminal"); fill_combo_box(capplet->icon_theme, GTK_COMBO_BOX(capplet->media_combo_box), capplet->media_players, "audio/x-vorbis+ogg"); fill_combo_box(capplet->icon_theme, GTK_COMBO_BOX(capplet->video_combo_box), capplet->video_players, "video/x-ogm+ogg"); fill_combo_box(capplet->icon_theme, GTK_COMBO_BOX(capplet->image_combo_box), capplet->image_viewers, "image/png"); fill_combo_box(capplet->icon_theme, GTK_COMBO_BOX(capplet->text_combo_box), capplet->text_editors, "text/plain"); fill_combo_box(capplet->icon_theme, GTK_COMBO_BOX(capplet->file_combo_box), capplet->file_managers, "inode/directory"); //fill_combo_box(capplet->icon_theme, GTK_COMBO_BOX(capplet->visual_combo_box), capplet->visual_ats, "visual"); //fill_combo_box(capplet->icon_theme, GTK_COMBO_BOX(capplet->mobility_combo_box), capplet->mobility_ats, "mobility"); g_signal_connect(capplet->web_combo_box, "changed", G_CALLBACK(web_combo_changed_cb), capplet); g_signal_connect(capplet->mail_combo_box, "changed", G_CALLBACK(mail_combo_changed_cb), capplet); //g_signal_connect(capplet->term_combo_box, "changed", G_CALLBACK(terminal_combo_changed_cb), capplet); g_signal_connect(capplet->media_combo_box, "changed", G_CALLBACK(media_combo_changed_cb), capplet); g_signal_connect(capplet->video_combo_box, "changed", G_CALLBACK(video_combo_changed_cb), capplet); //g_signal_connect(capplet->visual_combo_box, "changed", G_CALLBACK(visual_combo_changed_cb), capplet); //g_signal_connect(capplet->mobility_combo_box, "changed", G_CALLBACK(mobility_combo_changed_cb), capplet); g_signal_connect(capplet->image_combo_box, "changed", G_CALLBACK(image_combo_changed_cb), capplet); g_signal_connect(capplet->text_combo_box, "changed", G_CALLBACK(text_combo_changed_cb), capplet); g_signal_connect(capplet->file_combo_box, "changed", G_CALLBACK(file_combo_changed_cb), capplet); #undef get_widget } void add_default_app(GtkBuilder * builder) { g_debug("add_default_app"); capplet = g_new0(UkuiDACapplet, 1); capplet->terminal_settings = g_settings_new (TERMINAL_SCHEMA); capplet->mobility_settings = g_settings_new (MOBILITY_SCHEMA); capplet->visual_settings = g_settings_new (VISUAL_SCHEMA); show_dialog(builder); } void default_app_destory() { g_list_free(capplet->web_browsers); g_list_free(capplet->mail_readers); g_list_free(capplet->media_players); g_list_free(capplet->video_players); g_list_free(capplet->text_editors); g_list_free(capplet->image_viewers); g_list_free(capplet->file_managers); g_object_unref (capplet->terminal_settings); g_object_unref (capplet->mobility_settings); g_object_unref (capplet->visual_settings); } ukui-control-center/panels/network-proxy/0000775000175000017500000000000013263647163017556 5ustar fengfengukui-control-center/panels/network-proxy/network-proxy.c0000664000175000017500000003476213253611037022574 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include "network-proxy.h" /* With GSettings migration, UKUI is going to share proxy settings with * GNOME3 (in gsettings-desktop-schemas package). * GSettings schemas is http://git.gnome.org/browse/gsettings-desktop-schemas/tree/ * schemas/org.gnome.system.proxy.gschema.xml.in.in * Sharing the same schema, we lose the locations feature. */ /* * FIXME use enum from gsettings-desktop-schema * http://git.gnome.org/browse/gsettings-desktop-schemas/tree/headers/gdesktop-enums.h#n26 */ enum ProxyMode { PROXYMODE_NONE, PROXYMODE_MANUAL, PROXYMODE_AUTO }; enum { COL_NAME, COL_STYLE }; typedef struct _NetworkProxy NetworkProxy; struct _NetworkProxy { GtkBuilder * builder; }; NetworkProxy networkproxy; #define PROXY_SCHEMA "org.gnome.system.proxy" #define PROXY_MODE_KEY "mode" #define PROXY_AUTOCONFIG_URL_KEY "autoconfig-url" #define IGNORE_HOSTS_KEY "ignore-hosts" #define HTTP_PROXY_SCHEMA "org.gnome.system.proxy.http" #define HTTP_PROXY_HOST_KEY "host" #define HTTP_PROXY_PORT_KEY "port" #define HTTP_USE_AUTH_KEY "use-authentication" #define HTTP_AUTH_USER_KEY "authentication-user" #define HTTP_AUTH_PASSWD_KEY "authentication-password" #define HTTPS_PROXY_SCHEMA "org.gnome.system.proxy.https" #define SECURE_PROXY_HOST_KEY "host" #define SECURE_PROXY_PORT_KEY "port" #define FTP_PROXY_SCHEMA "org.gnome.system.proxy.ftp" #define FTP_PROXY_HOST_KEY "host" #define FTP_PROXY_PORT_KEY "port" #define SOCKS_PROXY_SCHEMA "org.gnome.system.proxy.socks" #define SOCKS_PROXY_HOST_KEY "host" #define SOCKS_PROXY_PORT_KEY "port" static GtkWidget *details_dialog = NULL; static GSList *ignore_hosts = NULL; static GtkTreeModel *model = NULL; static GSettings *proxy_settings = NULL; static GSettings *http_proxy_settings = NULL; static GSettings *https_proxy_settings = NULL; static GSettings *ftp_proxy_settings = NULL; static GSettings *socks_proxy_settings = NULL; static GtkTreeModel * create_listmodel(void) { GtkListStore *store; store = gtk_list_store_new(1, G_TYPE_STRING); return GTK_TREE_MODEL(store); } static GtkTreeModel * populate_listmodel(GtkListStore *store, GSList *list) { GtkTreeIter iter; GSList *pointer; gtk_list_store_clear(store); pointer = list; while(pointer) { gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, (char *) pointer->data, -1); pointer = g_slist_next(pointer); } return GTK_TREE_MODEL(store); } static GtkWidget * config_treeview(GtkTreeView *tree, GtkTreeModel *model) { GtkCellRenderer *renderer; renderer = gtk_cell_renderer_text_new(); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(tree), -1, "Hosts", renderer, "text", 0, NULL); gtk_tree_view_set_model(GTK_TREE_VIEW(tree), model); return GTK_WIDGET(tree); } static GtkWidget* _gtk_builder_get_widget (GtkBuilder *builder, const gchar *name) { return GTK_WIDGET (gtk_builder_get_object (builder, name)); } static void read_ignore_hosts_from_gsettings (void) { gchar **array; ignore_hosts = NULL; gint i; array = g_settings_get_strv (proxy_settings, IGNORE_HOSTS_KEY); if (array != NULL) { for (i = 0; array[i]; i++) { ignore_hosts = g_slist_append (ignore_hosts, g_strdup (array[i])); } } g_strfreev (array); } static void save_ignore_hosts_to_gsettings (void) { GArray *array; GSList *l; array = g_array_new (TRUE, TRUE, sizeof (gchar *)); for (l = ignore_hosts; l; l = l->next) { array = g_array_append_val (array, l->data); } g_settings_set_strv (proxy_settings, IGNORE_HOSTS_KEY, (const gchar **) array->data); g_array_free (array, TRUE); } static void cb_add_url (GtkButton *button, gpointer data) { GtkBuilder *builder = GTK_BUILDER (data); gchar *new_url = NULL; new_url = g_strdup (gtk_entry_get_text (GTK_ENTRY (gtk_builder_get_object (builder, "entry_url")))); if (strlen (new_url) == 0) return; ignore_hosts = g_slist_append(ignore_hosts, new_url); populate_listmodel(GTK_LIST_STORE(model), ignore_hosts); gtk_entry_set_text(GTK_ENTRY (gtk_builder_get_object (builder, "entry_url")), ""); save_ignore_hosts_to_gsettings (); } static void cb_remove_url (GtkButton *button, gpointer data) { GtkBuilder *builder = GTK_BUILDER (data); GtkTreeSelection *selection; GtkTreeIter iter; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview_ignore_host"))); if (gtk_tree_selection_get_selected(selection, &model, &iter)) { gchar *url; GSList *pointer; gtk_tree_model_get (model, &iter, 0, &url, -1); pointer = ignore_hosts; while(pointer) { if(strcmp(url, (char *) pointer->data) == 0) { g_free (pointer->data); ignore_hosts = g_slist_delete_link(ignore_hosts, pointer); break; } pointer = g_slist_next(pointer); } g_free(url); populate_listmodel(GTK_LIST_STORE(model), ignore_hosts); save_ignore_hosts_to_gsettings (); } } static void network_proxy_details_respone(GtkDialog *dialog, gint response_id, gpointer user_data){ gtk_widget_destroy(GTK_WIDGET(dialog)); details_dialog = NULL; } static void cb_use_auth_toggled (GtkToggleButton *toggle, GtkWidget *table) { gtk_widget_set_sensitive (table, gtk_toggle_button_get_active (toggle)); } static void cb_http_details_button_clicked (GtkWidget *button, GtkWidget *parent) { GtkBuilder *builder; GError *error = NULL; GtkWidget *widget; builder = gtk_builder_new(); gtk_builder_add_from_file(builder, UIDIR "/network.ui", &error); if(error != NULL){ g_warning("Load network.ui false, error=%s\n",error->message); g_error_free(error); g_object_unref(builder); return; } details_dialog = widget = _gtk_builder_get_widget (builder, "network_proxy_details_dialog"); gtk_window_set_skip_taskbar_hint(GTK_WINDOW(widget), TRUE); //gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (parent)); //if(details_dialog != NULL){ // gtk_window_present(GTK_WINDOW(details_dialog)); // return; //} g_signal_connect (gtk_builder_get_object (builder, "use_auth_checkbutton"), "toggled", G_CALLBACK (cb_use_auth_toggled), _gtk_builder_get_widget (builder, "auth_table")); g_settings_bind (http_proxy_settings, HTTP_USE_AUTH_KEY, gtk_builder_get_object (builder, "use_auth_checkbutton"), "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (http_proxy_settings, HTTP_AUTH_USER_KEY, gtk_builder_get_object (builder, "username_entry"), "text", G_SETTINGS_BIND_DEFAULT); g_settings_bind (http_proxy_settings, HTTP_AUTH_PASSWD_KEY, gtk_builder_get_object (builder, "password_entry"), "text", G_SETTINGS_BIND_DEFAULT); g_signal_connect(details_dialog, "response", G_CALLBACK(network_proxy_details_respone), NULL); gtk_widget_show_all (widget); } static void proxy_mode_gsettings_changed (GSettings *settings, gchar *key, GtkBuilder *builder) { int mode; mode = g_settings_get_enum (settings, PROXY_MODE_KEY); if (mode == PROXYMODE_NONE) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object(builder, "none_radiobutton")), TRUE); else if (mode == PROXYMODE_AUTO) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object(builder, "auto_radiobutton")), TRUE); else if (mode == PROXYMODE_MANUAL) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object(builder, "manual_radiobutton")), TRUE); gtk_widget_set_sensitive (_gtk_builder_get_widget (builder, "manual_box"), mode == PROXYMODE_MANUAL); gtk_widget_set_sensitive (_gtk_builder_get_widget (builder, "auto_box"), mode == PROXYMODE_AUTO); } static void proxy_mode_radiobutton_clicked_cb (GtkWidget *widget, GtkBuilder *builder) { GSList *mode_group; int mode; int old_mode; if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget))) return; mode_group = g_slist_copy (gtk_radio_button_get_group ((GtkRadioButton *)GTK_WIDGET(gtk_builder_get_object (builder, "none_radiobutton")))); mode_group = g_slist_reverse (mode_group); mode = g_slist_index (mode_group, widget); g_slist_free (mode_group); old_mode = g_settings_get_enum (proxy_settings, PROXY_MODE_KEY); if (mode == old_mode) return; g_settings_set_enum (proxy_settings, PROXY_MODE_KEY, mode); } static void connect_sensitivity_signals (GtkBuilder *builder, GSList *mode_group) { for (; mode_group != NULL; mode_group = mode_group->next) { g_signal_connect (G_OBJECT (mode_group->data), "clicked", G_CALLBACK(proxy_mode_radiobutton_clicked_cb), builder); } } static void cb_ignore_hosts_gsettings_changed (GSettings *settings, gchar *key, gpointer user_data) { g_slist_foreach (ignore_hosts, (GFunc) g_free, NULL); g_slist_free (ignore_hosts); read_ignore_hosts_from_gsettings (); populate_listmodel (GTK_LIST_STORE (model), ignore_hosts); } static void setup_dialog (GtkBuilder *builder) { GSList *mode_group; GtkListStore *store; g_signal_connect (proxy_settings, "changed::" IGNORE_HOSTS_KEY, G_CALLBACK (cb_ignore_hosts_gsettings_changed), NULL); /* Mode */ proxy_mode_gsettings_changed (proxy_settings, PROXY_MODE_KEY, builder); mode_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (gtk_builder_get_object (builder, "none_radiobutton"))); connect_sensitivity_signals (builder, mode_group); g_signal_connect (proxy_settings, "changed::" PROXY_MODE_KEY, G_CALLBACK (proxy_mode_gsettings_changed), builder); /* Http */ g_settings_bind (http_proxy_settings, HTTP_PROXY_PORT_KEY, gtk_builder_get_object (builder, "http_port_spinbutton"), "value", G_SETTINGS_BIND_DEFAULT); g_settings_bind (http_proxy_settings, HTTP_PROXY_HOST_KEY, gtk_builder_get_object (builder, "http_host_entry"), "text", G_SETTINGS_BIND_DEFAULT); g_signal_connect (gtk_builder_get_object (builder, "details_button1"), "clicked", G_CALLBACK (cb_http_details_button_clicked), _gtk_builder_get_widget (builder, "dialog-vbox1")); /* Secure */ g_settings_bind (https_proxy_settings, SECURE_PROXY_PORT_KEY, gtk_builder_get_object (builder, "secure_port_spinbutton"), "value", G_SETTINGS_BIND_DEFAULT); g_settings_bind (https_proxy_settings, SECURE_PROXY_HOST_KEY, gtk_builder_get_object (builder, "secure_host_entry"), "text", G_SETTINGS_BIND_DEFAULT); /* Ftp */ g_settings_bind (ftp_proxy_settings, FTP_PROXY_PORT_KEY, gtk_builder_get_object (builder, "ftp_port_spinbutton"), "value", G_SETTINGS_BIND_DEFAULT); g_settings_bind (ftp_proxy_settings, FTP_PROXY_HOST_KEY, gtk_builder_get_object (builder, "ftp_host_entry"), "text", G_SETTINGS_BIND_DEFAULT); /* Socks */ g_settings_bind (socks_proxy_settings, SOCKS_PROXY_PORT_KEY, gtk_builder_get_object (builder, "socks_port_spinbutton"), "value", G_SETTINGS_BIND_DEFAULT); g_settings_bind (socks_proxy_settings, SOCKS_PROXY_HOST_KEY, gtk_builder_get_object (builder, "socks_host_entry"), "text", G_SETTINGS_BIND_DEFAULT); /* Autoconfiguration */ g_settings_bind (proxy_settings, PROXY_AUTOCONFIG_URL_KEY, gtk_builder_get_object (builder, "autoconfig_entry"), "text", G_SETTINGS_BIND_DEFAULT); //g_signal_connect (gtk_builder_get_object (builder, "network_dialog"), // "response", G_CALLBACK (cb_dialog_response), NULL); read_ignore_hosts_from_gsettings (); model = create_listmodel(); populate_listmodel(GTK_LIST_STORE(model), ignore_hosts); config_treeview(GTK_TREE_VIEW(gtk_builder_get_object (builder, "treeview_ignore_host")), model); g_signal_connect (gtk_builder_get_object (builder, "button_add_url"), "clicked", G_CALLBACK (cb_add_url), builder); g_signal_connect (gtk_builder_get_object (builder, "entry_url"), "activate", G_CALLBACK (cb_add_url), builder); g_signal_connect (gtk_builder_get_object (builder, "button_remove_url"), "clicked", G_CALLBACK (cb_remove_url), builder); } void add_network_app(GtkBuilder * builder) { g_debug("add_network_app"); networkproxy.builder = builder; proxy_settings = g_settings_new(PROXY_SCHEMA); http_proxy_settings = g_settings_new(HTTP_PROXY_SCHEMA); https_proxy_settings = g_settings_new(HTTPS_PROXY_SCHEMA); ftp_proxy_settings = g_settings_new(FTP_PROXY_SCHEMA); socks_proxy_settings = g_settings_new(SOCKS_PROXY_SCHEMA); setup_dialog(builder); } void destory_network_app() { if (ignore_hosts) { g_slist_foreach (ignore_hosts, (GFunc) g_free, NULL); g_slist_free (ignore_hosts); } g_object_unref (proxy_settings); g_object_unref (http_proxy_settings); g_object_unref (https_proxy_settings); g_object_unref (ftp_proxy_settings); g_object_unref (socks_proxy_settings); } ukui-control-center/panels/network-proxy/Makefile.am0000664000175000017500000000105313057175444021610 0ustar fengfengcappletname=network_proxy noinst_LTLIBRARIES=libnetworkproxy.la AUTOMAKE_OPTIONS=foreign #INCLUDES=`pkg-config --cflags gtk+-2.0 glib-2.0 gio-2.0` #LIBS=`pkg-config --libs gtk+-2.0 glib-2.0 gio-2.0` AM_CPPFLAGS = \ -DUIDIR="\"$(uidir)\"" \ $(GTK_CFLAGS) \ $(GLIB_CFLAGS) \ $(NULL) libnetworkproxy_la_LIBADD = \ $(GTK_LIBS) \ $(GLIB_LIBS) \ $(NULL) uidir = $(pkgdatadir)/ui ui_DATA = network.ui libnetworkproxy_la_SOURCES=\ network-proxy.c \ network-proxy.h \ -include $(top_srcdir)/git.mk clean-local : rm -f *~ Makefile.in Makefile ukui-control-center/panels/network-proxy/network.ui0000664000175000017500000002143013245450076021601 0ustar fengfeng 350 200 False 5 Network Proxy Details False dialog True True False vertical 2 True False end gtk-close True True True False True False False 0 False True end 0 True False 5 vertical 15 True True False True True True False <b>User authentication</b> True True False False 0 True False True False False False 0 True False False 12 12 True False start Username: True username_entry 0 0 True False start Password: True password_entry 0 1 222 True True False False False 1 1 222 True True False False 1 0 True True 1 True True 1 True True 1 closebutton2 ukui-control-center/panels/network-proxy/network-proxy.h0000664000175000017500000000013613057175444022576 0ustar fengfeng#include void add_network_app(GtkBuilder * builder); void destory_network_app(); ukui-control-center/panels/user-accounts/0000775000175000017500000000000013265607112017471 5ustar fengfengukui-control-center/panels/user-accounts/delete-user.ui0000664000175000017500000001614113245450076022254 0ustar fengfeng 465 260 False 5 Delete User dialog True True True False vertical 2 True False end Cancel True True True False False 0 Keep File True True True False False 1 Delete File True True True False False 2 True True 0 125 True False vertical 20 60 True False 388 50 True False none True False label 20 False False 0 60 True False 388 60 True False none True False label 20 False False 1 True True 1 buttoncancel buttonstore buttondelete ukui-control-center/panels/user-accounts/change-pwd.ui0000664000175000017500000003315213245450076022054 0ustar fengfeng 465 356 False 5 Change Password True dialog True True True False vertical 2 True False end Cancel True True True False False 0 Ok True True True False False 1 False False 10 end 0 True False vertical 10 True False 8 90 90 True False gtk-missing-image False False 10 0 233 True False vertical True False label True True 0 True False label True True 1 True False label True True 2 True True 1 True True 0 170 True False none 170 True False 318 True False vertical 30 True True False False True True 0 25 True False True True 1 30 True True False False True True 2 25 True False True True 3 30 True True False False True True 4 25 True False True True 5 10 True True 5 1 False False 15 1 buttoncancel buttonok ukui-control-center/panels/user-accounts/Makefile.am0000664000175000017500000000217213245450076021532 0ustar fengfengcappletname = user-accounts AM_CPPFLAGS = \ @PACKAGE_CFLAGS@ \ -DUIDIR="\"$(uidir)\"" \ -fPIC \ -I$(srcdir)/../../shell/ \ -DCONF_DIR=\""$(confdir)"\" \ $(PANEL_CFLAGS) \ $(OOBS_CFLAGS) \ $(MATE_DESKTOP_CFLAGS) \ $(NULL) ccpanelsdir = $(PANELS_DIR) ccpanels_LTLIBRARIES = libuser-accounts.la libuser_accounts_la_SOURCES = \ user-accounts.c \ user-accounts.h \ run-passwd.c \ run-passwd.h \ check-passwd.h \ check-passwd.c \ $(NULL) libuser_accounts_la_LIBADD = \ @PACKAGE_LIBS@ \ $(OOBS_LIBS) \ $(MATE_DESKTOP_LIBS) \ -lcrypt \ $(NULL) libuser_accounts_la_LDFLAGS = -export-dynamic @PACKAGE_LDFLAGS@ uidir = $(pkgdatadir)/ui ui_DATA = user-create.ui \ change-pwd.ui \ change-name.ui \ change-face.ui \ delete-user.ui \ change-type.ui EXTRA_DIST = \ $(ui_DATA) clean-local : rm -f *~ Makefile.in Makefile ukui-control-center/panels/user-accounts/user-create.ui0000664000175000017500000004361313265607112022256 0ustar fengfeng 500 True True True 5 Create Account True True dialog True True True True False vertical 25 60 True False end Cancel True True True False False 0 Create Account True True True False False 1 False True 0 300 True False vertical 10 180 True False Automatic Logon 402 24 True True False True 6 146 422 143 True False 26 True False 109 109 True True True True False vertical True False select picture True True 0 True False gtk-missing-image True True 1 True True 0 280 True False vertical True True False False False True 0 10 True False True True 1 True True False False False True 2 10 True False True True 3 True True False False False True 4 10 True False True True 5 False False 1 True True 0 56 True False vertical Standard User True True False True True radiobutton2 True True 0 True False Standard users can use most software, but you can not install software and change settings that affect all users. True True 1 False True 1 56 True False vertical Administrators True True False True True True True 0 True False Administrator can make any changes needed on the system, including  installing and upgrading software. True True 1 False True 2 False True 7 1 buttoncancel buttoncreate ukui-control-center/panels/user-accounts/change-type.ui0000664000175000017500000003370413245450076022246 0ustar fengfeng 505 False 5 Change Usertype True dialog True True True False vertical 25 60 True False end Cancel True True True False False 0 Ok True True True False False 1 False True 10 0 316 True False vertical 10 200 True False automatic login 402 24 True True False True 10 115 388 80 True False 8 80 80 True False gtk-missing-image False False 0 True False vertical True False label True True 0 True False label True True 1 True False label True True 2 True True 1 10 10 480 28 True False Please make sure that the computer has at least one user is the administrator 10 160 470 True False 10 150 True True 0 56 True False vertical Standard User True True False True True True radiobutton2 True True 0 True False True Standard users can use most software, but you can not install software and change settings that affect all users. True True 1 False True 1 56 True False vertical Administrators True True False True True True True 0 True False Administrator can make any changes needed on the system, including  installing and upgrading software. True True 1 False True 2 True True 7 1 buttoncancel buttonok ukui-control-center/panels/user-accounts/check-passwd.h0000664000175000017500000000321113245450076022216 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef CHECKPASSWD_H #define CHECKPASSWD_H #include #define CO_RETRY_TIMES 1 #define CO_DIFF_OK 5 #define CO_MIN_LENGTH 9 #define CO_MIN_LENGTH_BASE 5 #define CO_DIG_CREDIT 1 #define CO_UP_CREDIT 1 #define CO_LOW_CREDIT 1 #define CO_OTH_CREDIT 1 #define CO_MIN_WORD_LENGTH 4 struct cracklib_options { int retry_times; int diff_ok; int min_length; int dig_credit; int up_credit; int low_credit; int oth_credit; int min_class; int max_repeat; int max_sequence; int max_class_repeat; int reject_user; int gecos_check; int enforce_for_root; }; const char *passwd_check(const char *old, const char *new, const char *user); GPtrArray *get_passwd_configuration(); #endif // CHECKPASSWD_H ukui-control-center/panels/user-accounts/user-accounts.c0000644000175000017500000030547113263623274022445 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include #include #include #define MATE_DESKTOP_USE_UNSTABLE_API #include #include "run-passwd.h" #include "user-accounts.h" #include "check-passwd.h" GList *userlist = NULL; GtkDialog *dialog; GtkBuilder *ui = NULL; #define ROW_SPAN 6 #define FACES_PATH "/usr/share/pixmaps/faces/" enum { COL_PIXBUF, NUM_COLS }; static void file_icon_selected (GtkMenuItem *menuitem, UserInfo *user); void find_all_face_file(GtkListStore *list_store, GtkTreeIter iter) { if (!g_file_test(FACES_PATH, G_FILE_TEST_IS_DIR)) { g_warning("dir is not exists"); exit(0); } GError *error = NULL; GError *err = NULL; GFile *directory; GFileEnumerator *enumer; GFileInfo *info; GdkPixbuf *pixbuf; GFileType type; const gchar *target; directory = g_file_new_for_path(FACES_PATH); enumer = g_file_enumerate_children(directory, G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK "," G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET, G_FILE_QUERY_INFO_NONE, NULL, &error); if (error != NULL) { g_warning("enumer is wrong"); g_error_free(error); exit(0); } while ((info = g_file_enumerator_next_file(enumer, NULL, NULL))) { char *fullpath; type = g_file_info_get_file_type(info); if(type != G_FILE_TYPE_REGULAR && type != G_FILE_TYPE_SYMBOLIC_LINK){ g_object_unref(info); continue; } target = g_file_info_get_symlink_target(info); if(target != NULL && g_str_has_prefix(target, "legacy/")){ g_object_unref(info); continue; } const char *filename = g_file_info_get_name (info); fullpath = g_build_filename(FACES_PATH, filename, NULL, NULL); pixbuf = gdk_pixbuf_new_from_file(fullpath, &err); pixbuf = gdk_pixbuf_scale_simple(pixbuf, 64, 64, GDK_INTERP_BILINEAR); gtk_list_store_append(list_store, &iter); gtk_list_store_set(list_store, &iter, COL_PIXBUF, pixbuf, -1); g_object_set_data_full (G_OBJECT (pixbuf), "filename", g_strdup (fullpath), (GDestroyNotify) g_free); if (err) g_error_free(err); g_object_unref(info); g_free(fullpath); } g_file_enumerator_close(enumer, NULL, NULL); g_object_unref(directory); } void user_bt_clicked(GtkWidget *widget, gpointer userdata) { GList *it = NULL; for (it = userlist; it; it = it->next) { UserInfo *user = (UserInfo *)it->data; GtkNotebook *notebook = GTK_NOTEBOOK(user->notebook); gtk_notebook_set_show_border(notebook, FALSE); gtk_container_set_border_width(GTK_CONTAINER(notebook), 0); gtk_notebook_set_show_tabs(GTK_NOTEBOOK(userdata), FALSE); gtk_notebook_set_current_page(notebook, 1); } gtk_notebook_set_show_border(GTK_NOTEBOOK(userdata), TRUE); gtk_container_set_border_width(GTK_CONTAINER(userdata), 1); gtk_notebook_set_current_page(GTK_NOTEBOOK(userdata), 0); gtk_notebook_set_show_tabs(GTK_NOTEBOOK(userdata), FALSE); gtk_widget_grab_focus(widget); } void modify_font_color(GtkWidget *button, char *textcolor) { GtkWidget *label; label = gtk_bin_get_child((GtkBin*)button); GdkColor color; gdk_color_parse(textcolor, &color); gtk_widget_modify_fg(GTK_WIDGET(label), GTK_STATE_NORMAL, &color); } static gchar salt_char (GRand *rand) { gchar salt[] = "ABCDEFGHIJKLMNOPQRSTUVXYZ" "abcdefghijklmnopqrstuvxyz" "./0123456789"; return salt[g_rand_int_range (rand, 0, G_N_ELEMENTS (salt))]; } static gchar * make_crypted (const gchar *plain) { GString *salt; gchar *result; GRand *rand; gint i; rand = g_rand_new (); salt = g_string_sized_new (21); /* SHA 256 */ g_string_append (salt, "$6$"); for (i = 0; i < 16; i++) { g_string_append_c (salt, salt_char (rand)); } g_string_append_c (salt, '$'); result = g_strdup ((const gchar *)crypt(plain, salt->str)); g_string_free (salt, TRUE); g_rand_free (rand); return result; } static gboolean textChanged(GtkWidget *widget, gpointer userdata) { GtkWidget *buttoncreate = GTK_WIDGET(gtk_builder_get_object (ui, "buttoncreate")); GtkWidget *entryname = GTK_WIDGET(gtk_builder_get_object (ui, "entryname")); GtkWidget *labelname = GTK_WIDGET(gtk_builder_get_object (ui, "labelname")); GtkWidget *labelpwd = GTK_WIDGET(gtk_builder_get_object (ui, "labelpwd")); GtkWidget *labelensurepwd = GTK_WIDGET(gtk_builder_get_object (ui, "labelensurepwd")); gtk_label_set_xalign(GTK_LABEL(labelname), 0.0); gtk_label_set_xalign(GTK_LABEL(labelpwd), 0.0); gtk_label_set_xalign(GTK_LABEL(labelensurepwd), 0.0); if (widget == entryname) { const char *name = gtk_entry_get_text(GTK_ENTRY(widget)); if (strlen(name) < 1) { gtk_label_set_text(GTK_LABEL(labelname), _("User name cannot be empty!")); gtk_widget_set_sensitive(buttoncreate, FALSE); return FALSE; } else gtk_label_set_text(GTK_LABEL(labelname), ""); } GtkWidget *entrypwd = GTK_WIDGET(gtk_builder_get_object (ui, "entrypwd")); const char *pwd = gtk_entry_get_text(GTK_ENTRY(entrypwd)); char *msg = NULL; //判断是否配置了密码复杂度模块,没有配置的话就不进行密码复杂度检验 GPtrArray *tmp_array = get_passwd_configuration(); if(tmp_array->len != 0) //因为这只是创建用户时的密码复杂度检查,所以旧密码为空 msg = passwd_check("", pwd, g_get_user_name()); g_ptr_array_free(tmp_array, TRUE); if (widget == entrypwd) { GtkWidget *entryensurepwd = GTK_WIDGET(gtk_builder_get_object (ui, "entryensurepwd")); const char *ensurepwd = gtk_entry_get_text(GTK_ENTRY(entryensurepwd)); GtkWidget *labelpwd = GTK_WIDGET(gtk_builder_get_object (ui, "labelpwd")); GtkWidget *labelensurepwd = GTK_WIDGET(gtk_builder_get_object (ui, "labelensurepwd")); if (strlen(pwd) < 6) { gtk_label_set_text(GTK_LABEL(labelpwd), _("Password length needs to more than 5 digits!")); gtk_label_set_text(GTK_LABEL(labelensurepwd), ""); gtk_widget_set_sensitive(buttoncreate, FALSE); return FALSE; } else if (strlen(pwd) > 63) { gtk_label_set_text(GTK_LABEL(labelpwd), _("Password length needs to less than 64 digits!")); gtk_widget_set_sensitive(buttoncreate, FALSE); return FALSE; } else if(msg) { gtk_label_set_text(GTK_LABEL(labelpwd), msg); gtk_widget_set_sensitive(buttoncreate, FALSE); return FALSE; } else gtk_label_set_text(GTK_LABEL(labelpwd), ""); if (strcmp(pwd, ensurepwd) != 0 && strcmp(ensurepwd, _("Please confirm the new password")) != 0) { gtk_label_set_text(GTK_LABEL(labelensurepwd), _("enter the password twice inconsistencies!")); gtk_widget_set_sensitive(buttoncreate, FALSE); return FALSE; } else { gtk_label_set_text(GTK_LABEL(labelensurepwd), ""); } } GtkWidget *entryensurepwd = GTK_WIDGET(gtk_builder_get_object (ui, "entryensurepwd")); if (widget == entryensurepwd) { const char *pwd = gtk_entry_get_text(GTK_ENTRY(entrypwd)); const char *ensurepwd = gtk_entry_get_text(GTK_ENTRY(widget)); GtkWidget *labelensurepwd = GTK_WIDGET(gtk_builder_get_object (ui, "labelensurepwd")); if (strcmp(pwd, ensurepwd) != 0) { gtk_label_set_text(GTK_LABEL(labelensurepwd), _("enter the password twice inconsistencies!")); gtk_widget_set_sensitive(buttoncreate, FALSE); return FALSE; } else gtk_label_set_text(GTK_LABEL(labelensurepwd), ""); } char *username = (char *)gtk_entry_get_text(GTK_ENTRY(entryname)); int i; for (i = 0; *(username + i) != 0; i++) { if (*(username) == 95) { gtk_label_set_text(GTK_LABEL(labelname), _("The first character cannot be underlined!")); gtk_widget_set_sensitive(buttoncreate, FALSE); return FALSE; } if (isupper(*(username + i))) { gtk_label_set_text(GTK_LABEL(labelname), _("User name can not contain capital letters!")); gtk_widget_set_sensitive(buttoncreate, FALSE); return FALSE; } if ((*(username + i) >=48 && *(username + i) <= 57 ) || (*(username + i) >= 97 && *(username + i) <= 122 ) || ( *(username + i) == 95)) continue; else { gtk_label_set_text(GTK_LABEL(labelname), _("The user name can only be composed of letters, numbers and underline!")); gtk_widget_set_sensitive(buttoncreate, FALSE); return FALSE; } } if (isdigit(*username)) { gtk_label_set_text(GTK_LABEL(labelname), _("The first character cannot be numeric!")); gtk_widget_set_sensitive(buttoncreate, FALSE); return FALSE; } char *password = (char *)gtk_entry_get_text(GTK_ENTRY(entrypwd)); char *ensurepassword = (char *)gtk_entry_get_text(GTK_ENTRY(entryensurepwd)); if (password && username && (strcmp(password, ensurepassword) == 0) && (strlen(password) > 5) && (strlen(password) < 64) && (strlen(username) >= 1) && (strcmp(username, _("Please enter the username")) != 0) && (strcmp(password, _("Please enter the password ")) != 0) && !msg) gtk_widget_set_sensitive(buttoncreate, TRUE); else gtk_widget_set_sensitive(buttoncreate, FALSE); GList *list; for(list = userlist; list; list = list->next) { UserInfo *info = (UserInfo *)list->data; if (strcmp(info->username, username) == 0) { gtk_label_set_text(GTK_LABEL(labelname), _("The user name is already in use, please use a different one.")); gtk_widget_set_sensitive(buttoncreate, FALSE); return FALSE; } else gtk_label_set_text(GTK_LABEL(labelname), " "); } if (strlen(username) > 0 && strlen(username) < 32) { char cmd[50]; sprintf(cmd, "getent group %s", username); pid_t status; status = system(cmd); if (WIFEXITED(status)) { if (0 == WEXITSTATUS(status)) { printf("run shell script successfully.\n"); //gtk_widget_set_size_request(GTK_WIDGET(labelname), -1, 18); gtk_label_set_text(GTK_LABEL(labelname),_("The user name corresponds to the group already exists,please use a different user name")); gtk_widget_set_sensitive(buttoncreate, FALSE); return FALSE; } else gtk_widget_set_size_request(GTK_WIDGET(labelname), -1, 8); } gtk_label_set_text(GTK_LABEL(labelname), " "); } else { //gtk_widget_set_size_request(GTK_WIDGET(labelname), -1, 32); gtk_label_set_text(GTK_LABEL(labelname),_("username length need to less than 32!")); gtk_widget_set_sensitive(buttoncreate, FALSE); return FALSE; } return FALSE; } static gboolean focusIn(GtkWidget *widget, gpointer userdata) { const char *text = gtk_entry_get_text(GTK_ENTRY(widget)); if (strcmp(text, _("Please enter the username")) == 0 || strcmp(text, _("Please enter the new username")) == 0) gtk_entry_set_text(GTK_ENTRY(widget), ""); if( strcmp(text, _("Please enter the password")) == 0 || strcmp(text, _("Please enter new password")) == 0 || strcmp(text, _("Please enter the current password")) == 0 || strcmp(text, _("Please enter the new password")) == 0 || strcmp(text, _("Please confirm the new password")) == 0) { gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE); gtk_entry_set_text(GTK_ENTRY(widget), ""); } GdkColor color; gdk_color_parse("#000000", &color); gtk_widget_modify_text(widget, GTK_STATE_NORMAL, &color); return FALSE; } static void pwdTextChanged(GtkWidget *widget, gpointer userdata) { const char *pwd1, *pwd2, *pwd3, *msg; GtkWidget *entry1 = GTK_WIDGET(gtk_builder_get_object (ui, "entry1")); GtkWidget *entry2 = GTK_WIDGET(gtk_builder_get_object (ui, "entry2")); GtkWidget *entry3 = GTK_WIDGET(gtk_builder_get_object (ui, "entry3")); GtkWidget *label2 = GTK_WIDGET(gtk_builder_get_object (ui, "label2")); GtkWidget *label4 = GTK_WIDGET(gtk_builder_get_object (ui, "label4")); guint16 length2 = gtk_entry_get_text_length(GTK_ENTRY(entry2)); guint16 length3 = gtk_entry_get_text_length(GTK_ENTRY(entry3)); pwd1 = gtk_entry_get_text (GTK_ENTRY(entry1)); pwd2 = gtk_entry_get_text (GTK_ENTRY(entry2)); pwd3 = gtk_entry_get_text (GTK_ENTRY(entry3)); msg = passwd_check(pwd1, pwd2, g_get_user_name()); GtkWidget *buttonok = GTK_WIDGET(gtk_builder_get_object (ui, "buttonok")); gboolean visible = gtk_widget_get_visible(entry1); // gtk_label_set_text(GTK_LABEL(label2), ""); gtk_label_set_text(GTK_LABEL(label4), ""); gtk_label_set_xalign(GTK_LABEL(label2), 0.0); gtk_label_set_xalign(GTK_LABEL(label4), 0.0); if (visible) { if(strlen(pwd1) > 0 && strlen(pwd2) > 0 && strlen(pwd3) > 0 && strcmp(pwd1, _("Please enter the current password")) != 0 && strcmp(pwd2, _("Please enter the new password")) != 0 && strcmp(pwd3, _("Please confirm the new password")) != 0 ) gtk_widget_set_sensitive(buttonok, TRUE); else gtk_widget_set_sensitive(buttonok, FALSE); } if(strlen(pwd2) > 0 && strlen(pwd3) > 0 && strcmp(pwd2, _("Please enter the new password")) != 0 && strcmp(pwd3, _("Please confirm the new password")) != 0 && length2 <= 63 && length3 <= 63 && !msg ) gtk_widget_set_sensitive(buttonok, TRUE); else if(length2 > 63 || length3 >63) { gtk_label_set_text(GTK_LABEL(label2), _("Password length needs to less than 64 digits!")); gtk_widget_set_sensitive(buttonok, FALSE); } else gtk_widget_set_sensitive(buttonok, FALSE); if(strcmp(pwd2, pwd3) != 0 && strcmp(pwd2, _("Please enter the new password")) != 0 && strcmp(pwd3, _("Please confirm the new password")) != 0 ) { gtk_label_set_text(GTK_LABEL(label4), _("enter the password twice inconsistencies!")); gtk_widget_set_sensitive(buttonok, FALSE); } } void dialog_quit(GtkWidget *widget, gpointer userdata) { gtk_widget_destroy(GTK_WIDGET(dialog)); g_object_unref(ui); } static void chpasswd_cb (PasswdHandler *passwd_handler, GError *error, gpointer user_data) { GtkWidget *user_passwd_dialog; GtkWidget *dialog; GtkWidget *entry; char *primary_text; char *secondary_text; user_passwd_dialog = GTK_WIDGET(gtk_builder_get_object (ui, "changepwd")); /* Restore dialog sensitivity and reset cursor */ gtk_widget_set_sensitive (GTK_WIDGET (user_passwd_dialog), TRUE); gdk_window_set_cursor (gtk_widget_get_window (user_passwd_dialog), NULL); if (!error) { //finish_password_change (TRUE); gtk_widget_destroy(user_passwd_dialog); g_object_unref(ui); passwd_destroy (passwd_handler); return; } if (error->code == PASSWD_ERROR_REJECTED) { primary_text = error->message; secondary_text = _("Please choose another password."); entry = GTK_WIDGET(gtk_builder_get_object(ui, "entry1")); gtk_entry_set_text (GTK_ENTRY (entry), ""); gtk_widget_grab_focus (entry); entry = GTK_WIDGET(gtk_builder_get_object (ui, "entry2")); gtk_entry_set_text (GTK_ENTRY (entry), ""); entry = GTK_WIDGET(gtk_builder_get_object (ui, "entry3")); gtk_entry_set_text (GTK_ENTRY (entry), ""); } else if (error->code == PASSWD_ERROR_AUTH_FAILED) { primary_text = error->message; secondary_text = _("Please reenter the current password."); entry = GTK_WIDGET(gtk_builder_get_object(ui, "entry1")); gtk_widget_grab_focus (entry); gtk_entry_set_text (GTK_ENTRY (entry), ""); } else { primary_text = _("Password can not be modified."); secondary_text = error->message; } GtkWidget *widget = GTK_WIDGET(gtk_builder_get_object(ui, "changepwd")); dialog = gtk_message_dialog_new (GTK_WINDOW (widget), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", primary_text); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", secondary_text); gtk_widget_set_name(GTK_WIDGET(dialog), "ukuicc"); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } void change_pwd(GtkWidget *widget, gpointer userdata) { GtkWidget *user_passwd_dialog; PasswdHandler *passwd_handler = NULL; const char *passwd; UserInfo *user = (UserInfo *)userdata; user_passwd_dialog = GTK_WIDGET(gtk_builder_get_object (ui, "changepwd")); GtkWidget *user_passwd_current = GTK_WIDGET(gtk_builder_get_object (ui, "entry1")); GtkWidget *new_passwd_entry = GTK_WIDGET(gtk_builder_get_object (ui, "entry2")); passwd_handler = g_object_get_data (G_OBJECT (user_passwd_current), "passwd_handler"); //要修改的新密码 passwd = gtk_entry_get_text (GTK_ENTRY (new_passwd_entry)); if(!passwd) return; //如果是修改root的密码,通过chpasswd修改以避免交互 if(!getuid() && user->currentuser) { char buffer[256]; sprintf(buffer, "echo 'root:%s' | chpasswd", passwd); int sysback = system(buffer); if(sysback == -1) g_warning("Change the root password failed!"); gtk_widget_destroy(user_passwd_dialog); g_object_unref(ui); return; } if (user->currentuser) { passwd_change_password (passwd_handler, passwd, chpasswd_cb, NULL); /* chpasswd_cb() will run finish_passwd_change() when done */ gtk_widget_set_sensitive (GTK_WIDGET (user_passwd_dialog), FALSE); GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (user_passwd_current)); GdkCursor *cursor; cursor = gdk_cursor_new_for_display (display, GDK_WATCH); gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (user_passwd_current)), cursor); gdk_display_flush (display); g_object_unref (cursor); } /* For other users, set password via the dbus */ else { char *crypted = make_crypted(passwd); g_dbus_proxy_call(user->proxy, "SetPassword", g_variant_new("(ss)", crypted, ""), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); if (passwd_handler) passwd_destroy (passwd_handler); gtk_widget_destroy(user_passwd_dialog); g_object_unref(ui); } } static void auth_cb (PasswdHandler *passwd_handler, GError *error, gpointer user_data) { GtkWidget *entry = GTK_WIDGET (user_data); GdkColor color; gdk_color_parse ("red", &color); gtk_widget_modify_base (entry, GTK_STATE_NORMAL, error ? &color : NULL); GtkWidget *label1 = GTK_WIDGET(gtk_builder_get_object (ui, "label1")); gtk_label_set_xalign(GTK_LABEL(label1), 0.0); gtk_label_set_text(GTK_LABEL(label1), error ? _("Password input error, please re-enter!"): ""); gtk_widget_modify_fg(label1, GTK_STATE_NORMAL, error ? &color : NULL); } gboolean on_user_passwd_focus_out (GtkWidget *entry, GdkEventFocus *event, gpointer user_data) { PasswdHandler *passwd_handler; const char *password; GdkColor color; gdk_color_parse("#999999", &color); GtkWidget *entry1 = GTK_WIDGET(gtk_builder_get_object (ui, "entry1")); GtkWidget *entry2 = GTK_WIDGET(gtk_builder_get_object (ui, "entry2")); GtkWidget *entry3 = GTK_WIDGET(gtk_builder_get_object (ui, "entry3")); GtkWidget *label2 = GTK_WIDGET(gtk_builder_get_object (ui, "label2")); const char *current_passwd = gtk_entry_get_text (GTK_ENTRY (entry1)); if(entry == entry1) { password = gtk_entry_get_text (GTK_ENTRY (entry)); if (strlen (password) > 0) { passwd_handler = g_object_get_data (G_OBJECT (entry), "passwd_handler"); /* * 通过spawn_backend()在后台启动passwd * 验证当前输入的密码是否正确, * 是将输入的当前密码先运行一次passwd,如果passwd通过,就说明输入的当前密码是正确的 */ passwd_authenticate (passwd_handler, password, auth_cb, entry); } else { gtk_entry_set_visibility(GTK_ENTRY(entry), TRUE); gtk_entry_set_text(GTK_ENTRY(entry), _("Please enter the current password")); gtk_widget_modify_text(entry, GTK_STATE_NORMAL, &color); GtkWidget *label1 = GTK_WIDGET(gtk_builder_get_object (ui, "label1")); gtk_label_set_text(GTK_LABEL(label1), ""); gdk_color_parse("white", &color); gtk_widget_modify_base (entry, GTK_STATE_NORMAL, &color); } } if(entry == entry2) { password = gtk_entry_get_text (GTK_ENTRY (entry2)); const char *msg = NULL; msg = passwd_check(current_passwd, password, g_get_user_name()); if(msg){ gtk_label_set_text(GTK_LABEL(label2), msg); } else gtk_label_set_text(GTK_LABEL(label2), ""); if (strlen (password) < 1) { gtk_entry_set_visibility(GTK_ENTRY(entry2), TRUE); gtk_entry_set_text(GTK_ENTRY(entry2), _("Please enter new password")); gtk_widget_modify_text(entry2, GTK_STATE_NORMAL, &color); } } if(entry == entry3) { password = gtk_entry_get_text (GTK_ENTRY (entry3)); if (strlen (password) < 1) { gtk_entry_set_visibility(GTK_ENTRY(entry3), TRUE); gtk_entry_set_text(GTK_ENTRY(entry3), _("Please confirm the new password")); gtk_widget_modify_text(entry3, GTK_STATE_NORMAL, &color); } } return FALSE; } void show_change_pwd_dialog(GtkButton *button, gpointer user_data) { GError *err = NULL; PasswdHandler *passwd_handler = NULL; UserInfo *user = (UserInfo *)user_data; ui = gtk_builder_new(); gtk_builder_add_from_file(ui, UIDIR "/change-pwd.ui", &err); if (err) { g_warning("Could not load user interface file: %s", err->message); g_error_free(err); g_object_unref(ui); return; } dialog = GTK_DIALOG(gtk_builder_get_object (ui, "changepwd")); gtk_window_set_icon_from_file (GTK_WINDOW(dialog), "/usr/share/ukui-control-center/icons/用户账号.png", NULL); GtkWidget *image = GTK_WIDGET(gtk_builder_get_object (ui, "image1")); GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(user->iconfile, NULL); if (!pixbuf) pixbuf = gdk_pixbuf_new_from_file("/usr/share/pixmaps/faces/stock_person.png", NULL); if (pixbuf){ GdkPixbuf *face = gdk_pixbuf_scale_simple(pixbuf, 88, 88, GDK_INTERP_BILINEAR); gtk_image_set_from_pixbuf (GTK_IMAGE(image), face); g_object_unref(face); } g_object_unref(pixbuf); GtkWidget *labelname = GTK_WIDGET(gtk_builder_get_object (ui, "labelname")); gtk_label_set_xalign(GTK_LABEL(labelname), 0.0); gtk_label_set_text(GTK_LABEL(labelname), user->username); char *markup = g_markup_printf_escaped ("%s", user->username); gtk_label_set_markup(GTK_LABEL(labelname), markup); GtkWidget *labeltype = GTK_WIDGET(gtk_builder_get_object (ui, "labeltype")); gtk_label_set_xalign(GTK_LABEL(labeltype), 0.0); if (user->accounttype == ADMINISTRATOR) gtk_label_set_text(GTK_LABEL(labeltype), _("Administrators")); else if (user->accounttype == STANDARDUSER) gtk_label_set_text(GTK_LABEL(labeltype), _("Standard user")); GtkWidget *label3 = GTK_WIDGET(gtk_builder_get_object (ui, "label3")); gtk_label_set_xalign(GTK_LABEL(label3), 0.0); if (user->currentuser) { gtk_label_set_text(GTK_LABEL(label3), _("Logged(Current User)")); passwd_handler = passwd_init (); } else if (user->logined && !user->currentuser) { gtk_label_set_text(GTK_LABEL(label3), _("Logged(Other Users)")); } else { gtk_label_set_text(GTK_LABEL(label3), _("Un-login(Other Users)")); } GtkWidget *user_passwd_current = GTK_WIDGET(gtk_builder_get_object (ui, "entry1")); //root用户修改密码时,不需要输入当前密码 if(!getuid() && user->currentuser) gtk_widget_hide(user_passwd_current); //只是将passwd_handler这个字符串key转换成一个PasswdHandler的类型 g_object_set_data (G_OBJECT (user_passwd_current), "passwd_handler", passwd_handler); if (user->currentuser) { gtk_entry_set_text(GTK_ENTRY(user_passwd_current), _("Please enter the current password")); GdkColor color; gdk_color_parse("#999999", &color); gtk_widget_modify_text(user_passwd_current, GTK_STATE_NORMAL, &color); g_signal_connect(user_passwd_current, "focus-in-event", G_CALLBACK(focusIn), NULL); g_signal_connect(user_passwd_current, "focus-out-event", G_CALLBACK(on_user_passwd_focus_out), NULL); g_signal_connect(user_passwd_current, "changed", G_CALLBACK(pwdTextChanged), user); } else { gtk_widget_hide(GTK_WIDGET(user_passwd_current)); } GtkWidget *entry2 = GTK_WIDGET(gtk_builder_get_object (ui, "entry2")); gtk_entry_set_text(GTK_ENTRY(entry2), _("Please enter new password")); GdkColor color; gdk_color_parse("#999999", &color); gtk_widget_modify_text(entry2, GTK_STATE_NORMAL, &color); g_signal_connect(entry2, "focus-in-event", G_CALLBACK(focusIn), NULL); g_signal_connect(entry2, "focus-out-event", G_CALLBACK(on_user_passwd_focus_out), NULL); g_signal_connect(entry2, "changed", G_CALLBACK(pwdTextChanged), user); GtkWidget *entry3 = GTK_WIDGET(gtk_builder_get_object (ui, "entry3")); gtk_entry_set_text(GTK_ENTRY(entry3), _("Please confirm the new password")); gtk_widget_modify_text(entry3, GTK_STATE_NORMAL, &color); g_signal_connect(entry3, "focus-in-event", G_CALLBACK(focusIn), NULL); g_signal_connect(entry3, "focus-out-event", G_CALLBACK(on_user_passwd_focus_out), NULL); g_signal_connect(entry3, "changed", G_CALLBACK(pwdTextChanged), user); GtkWidget *buttoncancel = GTK_WIDGET(gtk_builder_get_object (ui, "buttoncancel")); g_signal_connect(buttoncancel, "clicked", G_CALLBACK(dialog_quit), NULL); gtk_widget_grab_focus(buttoncancel); GtkWidget *buttonok = GTK_WIDGET(gtk_builder_get_object (ui, "buttonok")); g_signal_connect(buttonok, "clicked", G_CALLBACK(change_pwd), user); gtk_widget_set_sensitive(buttonok, FALSE); gtk_widget_set_name(GTK_WIDGET(dialog), "ukuicc"); gtk_widget_show(GTK_WIDGET(dialog)); } void usernameChanged(GtkWidget *widget, gpointer userdata) { char *primary_text; const char *username = gtk_entry_get_text(GTK_ENTRY(widget)); GtkWidget *label1 = GTK_WIDGET(gtk_builder_get_object (ui, "label1")); gtk_label_set_xalign(GTK_LABEL(label1), 0.0); GtkWidget *buttonok = GTK_WIDGET(gtk_builder_get_object (ui, "buttonok")); guint16 length = gtk_entry_get_text_length(GTK_ENTRY(widget)); if (strlen(username) > 0) { int i; for (i = 0; *(username + i) != 0; i++) { if (*(username) == 95) { gtk_label_set_text(GTK_LABEL(label1), _("The first character cannot be underlined!")); gtk_widget_set_sensitive(buttonok, FALSE); return; } if (isupper(*(username + i))) { gtk_label_set_text(GTK_LABEL(label1), _("User name can not contain capital letters!")); gtk_widget_set_sensitive(buttonok, FALSE); return; } if ((*(username + i) >=48 && *(username + i) <= 57 ) || (*(username + i) >= 97 && *(username + i) <= 122 ) || ( *(username + i) == 95)) continue; else { gtk_label_set_text(GTK_LABEL(label1), _("The user name can only be composed of letters, numbers and underline!")); gtk_widget_set_sensitive(buttonok, FALSE); return; } } if (isdigit(*username)) { gtk_label_set_text(GTK_LABEL(label1), _("User name cannot start with number!")); gtk_widget_set_sensitive(buttonok, FALSE); return; } if (length > 31) { gtk_label_set_text(GTK_LABEL(label1), _("Username length need to less than 32!")); gtk_widget_set_sensitive(buttonok, FALSE); return; } GList *list; for(list = userlist; list; list = list->next) { UserInfo *info = (UserInfo *)list->data; if (strcmp(info->username, username) == 0) { primary_text = _("The user name has been used, please replace with another one!"); gtk_widget_set_sensitive(buttonok, FALSE); gtk_label_set_text(GTK_LABEL(label1), primary_text); return; } } gtk_widget_set_sensitive(buttonok, TRUE); gtk_label_set_text(GTK_LABEL(label1), ""); } else gtk_widget_set_sensitive(buttonok, FALSE); } void set_username_callback(GObject *object, GAsyncResult *res, gpointer user_data) { GError * error = NULL; GVariant *result; UserInfo *user = (UserInfo *)user_data; result = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), res, &error); if (result == NULL) { g_warning("Callback Result is null"); return; } if (error != NULL) { g_warning("DBUS error:%s", error->message); g_error_free(error); char *primary_text = _("Modify username failed!"); GtkWidget *w = GTK_WIDGET(gtk_builder_get_object(ui, "changename")); GtkWidget *d = gtk_message_dialog_new (GTK_WINDOW (w), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", primary_text); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (d), "%s", error->message); gtk_widget_set_name(GTK_WIDGET(d), "ukuicc"); gtk_dialog_run (GTK_DIALOG (d)); gtk_widget_destroy (d); g_object_unref(ui); return; } GtkWidget *entry1 = GTK_WIDGET(gtk_builder_get_object (ui, "entry1")); const char *username = gtk_entry_get_text(GTK_ENTRY(entry1)); strcpy(user->username, username); char *markup = g_markup_printf_escaped ("%s", user->username); gtk_label_set_markup(GTK_LABEL(user->labelname0), markup); gtk_label_set_markup(GTK_LABEL(user->labelname1), markup); gtk_widget_destroy(GTK_WIDGET(dialog)); g_object_unref(ui); } void change_username(GtkWidget *widget, gpointer userdata) { GtkWidget *entry1 = GTK_WIDGET(gtk_builder_get_object (ui, "entry1")); const char *username = gtk_entry_get_text(GTK_ENTRY(entry1)); UserInfo *user = (UserInfo *)userdata; if(user->logined) { char *primary_text = _("Modify username failed!"); GtkWidget *w = GTK_WIDGET(gtk_builder_get_object(ui, "changename")); GtkWidget *d = gtk_message_dialog_new (GTK_WINDOW (w), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", primary_text); char *secondary_text = _("the user has logged in, please log out and modify!"); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (d), "%s", secondary_text); gtk_widget_set_name(GTK_WIDGET(d), "ukuicc"); gtk_dialog_run (GTK_DIALOG (d)); gtk_widget_destroy (d); //g_object_unref(ui); return; } g_dbus_proxy_call(user->proxy, "SetUserName", g_variant_new("(s)", username), G_DBUS_CALL_FLAGS_NONE, -1, NULL, set_username_callback, user); } void show_change_name_dialog(GtkButton *button, gpointer user_data) { GError *err = NULL; UserInfo *user = (UserInfo *)user_data; ui = gtk_builder_new(); gtk_builder_add_from_file(ui, UIDIR "/change-name.ui", &err); //gtk_builder_add_from_file(ui, "../panels/user-accounts/change-name.ui", &err); if (err) { g_warning("Could not load user interface file: %s", err->message); g_error_free(err); g_object_unref(ui); return; } dialog = GTK_DIALOG(gtk_builder_get_object (ui, "changename")); gtk_window_set_icon_from_file (GTK_WINDOW(dialog), "/usr/share/ukui-control-center/icons/用户账号.png", NULL); GtkWidget *image = GTK_WIDGET(gtk_builder_get_object (ui, "image1")); GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(user->iconfile, NULL); if (!pixbuf){ pixbuf = gdk_pixbuf_new_from_file("/usr/share/pixmaps/faces/stock_person.png", NULL); gtk_image_set_from_pixbuf (GTK_IMAGE(image), pixbuf); } else{ GdkPixbuf *face = gdk_pixbuf_scale_simple(pixbuf, 88, 88, GDK_INTERP_BILINEAR); gtk_image_set_from_pixbuf (GTK_IMAGE(image), face); g_object_unref(face); } g_object_unref(pixbuf); GtkWidget *labelname = GTK_WIDGET(gtk_builder_get_object (ui, "labelname")); gtk_label_set_xalign(GTK_LABEL(labelname), 0.03); gtk_label_set_yalign(GTK_LABEL(labelname), 1.0); gtk_label_set_text(GTK_LABEL(labelname), user->username); char *markup = g_markup_printf_escaped ("%s", user->username); gtk_label_set_markup(GTK_LABEL(labelname), markup); GtkWidget *labeltype = GTK_WIDGET(gtk_builder_get_object (ui, "labeltype")); gtk_label_set_xalign(GTK_LABEL(labeltype), 0.03); if (user->accounttype == ADMINISTRATOR) gtk_label_set_text(GTK_LABEL(labeltype), _("Administrators")); else if (user->accounttype == STANDARDUSER) gtk_label_set_text(GTK_LABEL(labeltype), _("Standard user")); GtkWidget *label3 = GTK_WIDGET(gtk_builder_get_object (ui, "label3")); gtk_label_set_xalign(GTK_LABEL(label3), 0.03); gtk_label_set_yalign(GTK_LABEL(label3), 0.0); if (user->currentuser) gtk_label_set_text(GTK_LABEL(label3), _("Logged(Current User)")); else if (user->logined && !user->currentuser) gtk_label_set_text(GTK_LABEL(label3), _("Logged(Other Users)")); else gtk_label_set_text(GTK_LABEL(label3), _("Un-login(Other Users)")); GtkWidget *entry1 = GTK_WIDGET(gtk_builder_get_object (ui, "entry1")); gtk_entry_set_text(GTK_ENTRY(entry1), _("Please enter the new username")); GdkColor color; gdk_color_parse("#999999", &color); gtk_widget_modify_text(entry1, GTK_STATE_NORMAL, &color); g_signal_connect(entry1, "focus-in-event", G_CALLBACK(focusIn), NULL); g_signal_connect(entry1, "changed", G_CALLBACK(usernameChanged), user); GtkWidget *buttoncancel = GTK_WIDGET(gtk_builder_get_object (ui, "buttoncancel")); g_signal_connect(buttoncancel, "clicked", G_CALLBACK(dialog_quit), NULL); gtk_widget_grab_focus(buttoncancel); GtkWidget *buttonok = GTK_WIDGET(gtk_builder_get_object (ui, "buttonok")); g_signal_connect(buttonok, "clicked", G_CALLBACK(change_username), user); gtk_widget_set_sensitive(buttonok, FALSE); gtk_widget_set_name(GTK_WIDGET(dialog), "ukuicc"); gtk_widget_show(GTK_WIDGET(dialog)); } void change_face_callback(GObject *object, GAsyncResult *res, gpointer user_data) { GError * error = NULL; GVariant *result; UserInfo *user = (UserInfo *)user_data; result = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), res, &error); if (result == NULL) { g_warning("Callback Result is null"); return; } if (error != NULL) { g_warning("DBUS error:%s", error->message); g_error_free(error); return; } GdkPixbuf *buf = gdk_pixbuf_new_from_file(user->iconfile, NULL); buf = gdk_pixbuf_scale_simple(buf, FACEHEIGHT, FACEWIDTH, GDK_INTERP_BILINEAR); gtk_image_set_from_pixbuf(GTK_IMAGE(user->image0), buf); gtk_image_set_from_pixbuf(GTK_IMAGE(user->image1), buf); g_object_unref(buf); system("gsettings set org.ukui.ukui-menu user-icon-changed true"); } void change_face(GtkWidget *widget, gpointer userdata) { UserInfo *user = (UserInfo *)userdata; GtkWidget *image = GTK_WIDGET(gtk_builder_get_object (ui, "imageuser")); GdkPixbuf *pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(image)); const char *filename = g_object_get_data (G_OBJECT (pixbuf), "filename"); if (filename) user->iconfile = (gchar *)filename; g_dbus_proxy_call(user->proxy, "SetIconFile", g_variant_new("(s)", user->iconfile), G_DBUS_CALL_FLAGS_NONE, -1, NULL, change_face_callback, user); g_object_unref(pixbuf); gtk_widget_destroy(GTK_WIDGET(dialog)); g_object_unref(ui); } GtkTreeModel *init_model(void) { GtkListStore *list_store; GtkTreeIter iter; list_store = gtk_list_store_new(NUM_COLS, GDK_TYPE_PIXBUF); find_all_face_file(list_store, iter); return GTK_TREE_MODEL(list_store); } void itemSelected(GtkWidget *widget, gpointer userdata) { GList *selected; GdkPixbuf *pixbuf; GtkTreeModel *smodel; selected = gtk_icon_view_get_selected_items(GTK_ICON_VIEW(widget)); smodel = gtk_icon_view_get_model(GTK_ICON_VIEW(widget)); if (selected != NULL){ GtkTreeIter sel_iter; gtk_tree_model_get_iter(smodel, &sel_iter, selected->data); gtk_tree_model_get(smodel, &sel_iter, COL_PIXBUF, &pixbuf, -1); GtkWidget *image = GTK_WIDGET(gtk_builder_get_object (ui, "imageuser")); gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf); } } //如果已经设置了自动登陆用户,提示用户是否覆盖原先的设置 static void confirm_dialog(GtkWidget *widget, gpointer user_data) { UserInfo *user = (UserInfo *)user_data; if(!user->autologin){ GList *it = NULL; for (it = userlist; it; it = it->next) { UserInfo *system_user = (UserInfo *)it->data; if(system_user->autologin == TRUE) { if(0 == strcmp(user->username,system_user->username) || !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) continue; GtkWidget *label; //GtkWidget *hbox; GtkWidget *dialog = gtk_dialog_new_with_buttons( _("auto login"), window, GTK_DIALOG_MODAL, _("_Cancel"), GTK_RESPONSE_REJECT, _("_OK"), GTK_RESPONSE_ACCEPT, NULL); label = gtk_label_new(_("\tAlready have other users set to automatically log in,\t\n \tclick OK will overwrite the existing settings!")); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label, TRUE, TRUE, 30); gtk_widget_show_all(dialog); gint result = gtk_dialog_run(GTK_DIALOG(dialog)); if(result == GTK_RESPONSE_ACCEPT) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE); else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), FALSE); gtk_widget_destroy(dialog); } } }//end-if } void show_change_face_dialog(GtkButton *button, gpointer user_data) { GError *err = NULL; UserInfo *user = (UserInfo *)user_data; ui = gtk_builder_new(); gtk_builder_add_from_file(ui, UIDIR "/change-face.ui", &err); //gtk_builder_add_from_file(ui, "../panels/user-accounts/change-face.ui", &err); if (err) { g_warning("Could not load user interface file: %s", err->message); g_error_free(err); g_object_unref(ui); return; } dialog = GTK_DIALOG(gtk_builder_get_object (ui, "changeface")); gtk_window_set_icon_from_file (GTK_WINDOW(dialog), "/usr/share/ukui-control-center/icons/用户账号.png", NULL); GtkWidget *image = GTK_WIDGET(gtk_builder_get_object (ui, "imageuser")); GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(user->iconfile, NULL); if (!pixbuf) pixbuf = gdk_pixbuf_new_from_file("/usr/share/pixmaps/faces/stock_person.png", NULL); GdkPixbuf *face = gdk_pixbuf_scale_simple(pixbuf, 88, 88, GDK_INTERP_BILINEAR); gtk_image_set_from_pixbuf (GTK_IMAGE(image), face); g_object_unref(pixbuf); g_object_unref(face); GtkWidget *labelname = GTK_WIDGET(gtk_builder_get_object (ui, "labelname")); gtk_label_set_xalign(GTK_LABEL(labelname), 0.0); gtk_label_set_text(GTK_LABEL(labelname), user->username); char *markup = g_markup_printf_escaped ("%s", user->username); gtk_label_set_markup(GTK_LABEL(labelname), markup); GtkWidget *labeltype = GTK_WIDGET(gtk_builder_get_object (ui, "labeltype")); gtk_label_set_xalign(GTK_LABEL(labeltype), 0.0); if (user->accounttype == ADMINISTRATOR) gtk_label_set_text(GTK_LABEL(labeltype), _("Administrators")); else if (user->accounttype == STANDARDUSER) gtk_label_set_text(GTK_LABEL(labeltype), _("Standard user")); GtkWidget *label3 = GTK_WIDGET(gtk_builder_get_object (ui, "label3")); gtk_label_set_xalign(GTK_LABEL(label3), 0.0); if (user->currentuser) gtk_label_set_text(GTK_LABEL(label3), _("Logged(Current User)")); else if (user->logined && !user->currentuser) gtk_label_set_text(GTK_LABEL(label3), _("Logged(Other Users)")); else gtk_label_set_text(GTK_LABEL(label3), _("Un-login(Other Users)")); GtkWidget *facecontainer = GTK_WIDGET(gtk_builder_get_object (ui, "scrolledwindow1")); GtkWidget *icon_view = gtk_icon_view_new_with_model(init_model()); gtk_container_add(GTK_CONTAINER(facecontainer), icon_view); gtk_widget_show_all(icon_view); g_signal_connect(icon_view, "selection-changed", G_CALLBACK(itemSelected), NULL); gtk_icon_view_set_pixbuf_column(GTK_ICON_VIEW(icon_view), COL_PIXBUF); gtk_icon_view_set_selection_mode(GTK_ICON_VIEW(icon_view), GTK_SELECTION_MULTIPLE); gtk_icon_view_set_item_padding (GTK_ICON_VIEW(icon_view), 3); gtk_icon_view_set_spacing (GTK_ICON_VIEW(icon_view), 1); GtkWidget *bt_add = GTK_WIDGET(gtk_builder_get_object (ui, "bt_add")); g_signal_connect(bt_add, "clicked", G_CALLBACK(file_icon_selected), user); GtkWidget *buttoncancel = GTK_WIDGET(gtk_builder_get_object (ui, "buttoncancel")); g_signal_connect(buttoncancel, "clicked", G_CALLBACK(dialog_quit), NULL); gtk_widget_grab_focus(buttoncancel); GtkWidget *buttonok = GTK_WIDGET(gtk_builder_get_object (ui, "buttonok")); g_signal_connect(buttonok, "clicked", G_CALLBACK(change_face), user); gtk_widget_set_name(GTK_WIDGET(dialog), "ukuicc"); gtk_widget_show(GTK_WIDGET(dialog)); } void set_accounttype_callback(GObject *object, GAsyncResult *res, gpointer user_data) { GError * error = NULL; GError * err = NULL; GVariant *result; UserInfo *user = (UserInfo *)user_data; ui = gtk_builder_new(); gtk_builder_add_from_file(ui, UIDIR "/change-type.ui", &err); if (err) { g_warning("Could not load user interface file: %s", err->message); g_error_free(err); g_object_unref(ui); return; } GtkWidget *radio_admin = GTK_WIDGET (gtk_builder_get_object (ui, "radiobutton2")); GtkWidget *radio_standard_user = GTK_WIDGET (gtk_builder_get_object (ui, "radiobutton1")); GVariant *value = NULL; result = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), res, &error); //调用未成功或取消了调用 if (result == NULL) { //若取消调用,radiobutton的状态应不改变,这时不能直接使用user->accounttype,应该获取dbus的accounttype属性的值 g_warning("Callback Result is null.\n"); value = g_dbus_proxy_get_cached_property(user->proxy, "AccountType"); user->accounttype = (gint)g_variant_get_int32(value); if(user->accounttype == 1) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_admin), TRUE); else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_standard_user), TRUE); return; } if (error != NULL) { g_warning("DBUS error:%s", error->message); g_error_free(error); return; } g_warning("----------%s\n",user->username); if(user->autologin == TRUE) //确保自动登录用户只有最新设置的生效 { g_warning("------1----%s\n",user->username); GList *it = NULL; for (it = userlist; it; it = it->next) { UserInfo *system_user = (UserInfo *)it->data; if(system_user->autologin == TRUE) { if(0 == strcmp(user->username,system_user->username)) continue; system_user->autologin = FALSE; g_dbus_proxy_call(user->proxy, "SetAutomaticLogin", g_variant_new("(b)", system_user->autologin), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); } } } if (error != NULL) { g_warning("DBUS error:%s", error->message); g_error_free(error); return; } g_dbus_proxy_call(user->proxy, "SetAutomaticLogin", g_variant_new("(b)", user->autologin), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); if (user->accounttype) { gtk_label_set_text(GTK_LABEL(user->labeltype0), _("Administrators")); gtk_label_set_text(GTK_LABEL(user->labeltype1), _("Administrators")); } else { gtk_label_set_text(GTK_LABEL(user->labeltype0), _("Standard user")); gtk_label_set_text(GTK_LABEL(user->labeltype1), _("Standard user")); } } void change_accounttype(GtkWidget *widget, gpointer userdata) { UserInfo *user = (UserInfo *)userdata; GtkWidget *admin = GTK_WIDGET (gtk_builder_get_object (ui, "radiobutton2")); gboolean state = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(admin)); if (state) user->accounttype = ADMINISTRATOR; else user->accounttype = STANDARDUSER; g_dbus_proxy_call(user->proxy, "SetAccountType", g_variant_new("(i)", user->accounttype), G_DBUS_CALL_FLAGS_NONE, -1, NULL, set_accounttype_callback, user); GtkWidget *btautologin = GTK_WIDGET(gtk_builder_get_object (ui, "btautologin")); state = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btautologin)); if (state) user->autologin = TRUE; else user->autologin = FALSE; gtk_widget_destroy(GTK_WIDGET(dialog)); g_object_unref(ui); } //获取系统的管理员数量,判断sudo组有多少个成员,其实还须判断admin组 int get_adm_count() { int account_count = 0; FILE *file; char buffer[128]; file = fopen("/etc/group", "r"); if(!file) g_warning("/etc/group not exist!"); while(fgets(buffer, 128, file)){ gchar **tmp = g_strsplit(buffer, ":", 4); tmp[0] = g_strstrip(tmp[0]); tmp[3] = g_strstrip(tmp[3]); if(!strcmp(tmp[0], "sudo")) { if(!tmp[3]){ g_strfreev(tmp); fclose(file); return 0; } else{ int i = 0; while(tmp[3][i] != '\0'){ if(tmp[3][i] == ',') ++account_count; ++i; } if(!account_count){ g_strfreev(tmp); fclose(file); return 1; } } break; } } fclose(file); return account_count + 1; } void show_change_accounttype_dialog(GtkButton *button, gpointer user_data) { GError *err = NULL; UserInfo *user = (UserInfo *)user_data; ui = gtk_builder_new(); gtk_builder_add_from_file(ui, UIDIR "/change-type.ui", &err); if (err) { g_warning("Could not load user interface file: %s", err->message); g_error_free(err); g_object_unref(ui); return; } dialog = GTK_DIALOG(gtk_builder_get_object (ui, "changetype")); gtk_window_set_icon_from_file (GTK_WINDOW(dialog), "/usr/share/ukui-control-center/icons/用户账号.png", NULL); GtkWidget *image = GTK_WIDGET(gtk_builder_get_object (ui, "image1")); GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(user->iconfile, NULL); if (!pixbuf) pixbuf = gdk_pixbuf_new_from_file("/usr/share/pixmaps/faces/stock_person.png", NULL); GdkPixbuf *face = gdk_pixbuf_scale_simple(pixbuf, 88, 88, GDK_INTERP_BILINEAR); gtk_image_set_from_pixbuf (GTK_IMAGE(image), face); g_object_unref(pixbuf); g_object_unref(face); GtkWidget *label6 = GTK_WIDGET(gtk_builder_get_object (ui, "label6")); gtk_label_set_xalign(GTK_LABEL(label6), 0.0); GtkWidget *labelname = GTK_WIDGET(gtk_builder_get_object (ui, "labelname")); gtk_label_set_xalign(GTK_LABEL(labelname), 0.05); gtk_label_set_text(GTK_LABEL(labelname), user->username); char *markup = g_markup_printf_escaped ("%s", user->username); gtk_label_set_markup(GTK_LABEL(labelname), markup); GtkWidget *stard = GTK_WIDGET (gtk_builder_get_object (ui, "radiobutton1")); GtkWidget *stard_label = GTK_WIDGET (gtk_builder_get_object (ui, "label2")); GtkWidget *admin = GTK_WIDGET (gtk_builder_get_object (ui, "radiobutton2")); GtkWidget *labeltype = GTK_WIDGET(gtk_builder_get_object (ui, "labeltype")); gtk_label_set_xalign(GTK_LABEL(labeltype), 0.05); if (user->accounttype == ADMINISTRATOR) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(admin), TRUE); gtk_label_set_text(GTK_LABEL(labeltype), _("Administrators")); } else if (user->accounttype == STANDARDUSER) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(stard), TRUE); gtk_label_set_text(GTK_LABEL(labeltype), _("Standard user")); } int adm_count = get_adm_count(); //确保系统至少有一个管理员 if(adm_count == 1 && user->accounttype) { gtk_widget_set_sensitive(stard, FALSE); gtk_widget_set_sensitive(stard_label, FALSE); } GtkWidget *label3 = GTK_WIDGET(gtk_builder_get_object (ui, "label3")); gtk_label_set_xalign(GTK_LABEL(label3), 0.05); if (user->currentuser) gtk_label_set_text(GTK_LABEL(label3), _("Logged(Current User)")); else if (user->logined && !user->currentuser) gtk_label_set_text(GTK_LABEL(label3), _("Logged(Other Users)")); else gtk_label_set_text(GTK_LABEL(label3), _("Un-login(Other Users)")); GtkWidget *btautologin = GTK_WIDGET(gtk_builder_get_object (ui, "btautologin")); if (user->autologin) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(btautologin), user->autologin); g_signal_connect(btautologin, "clicked", G_CALLBACK(confirm_dialog), user); GtkWidget *buttoncancel = GTK_WIDGET(gtk_builder_get_object (ui, "buttoncancel")); g_signal_connect(buttoncancel, "clicked", G_CALLBACK(dialog_quit), NULL); gtk_widget_grab_focus(buttoncancel); GtkWidget *buttonok = GTK_WIDGET(gtk_builder_get_object (ui, "buttonok")); g_signal_connect(buttonok, "clicked", G_CALLBACK(change_accounttype), user); gtk_widget_set_name(GTK_WIDGET(dialog), "ukuicc"); gtk_widget_show(GTK_WIDGET(dialog)); } static void deleteUserDone(GObject *object, GAsyncResult *res, gpointer user_data) { GError * error = NULL; GVariant *result; result = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), res, &error); if (result == NULL) { g_warning("Callback Result is null"); return; } if (error != NULL) { g_warning("DBUS error:%s", error->message); g_error_free(error); if (result) g_variant_unref(result); return; } UserInfo *user = (UserInfo *)user_data; GtkWidget *box = GTK_WIDGET (gtk_builder_get_object (builder, "other_users")); GtkWidget *other_hbox = GTK_WIDGET (gtk_builder_get_object (builder, "hbox6")); gtk_container_remove(GTK_CONTAINER(box), GTK_WIDGET(user->notebook)); gtk_widget_show_all(box); userlist = g_list_remove(userlist, user); if (g_list_length(userlist) == 1) gtk_widget_hide(other_hbox); free(user); if (result) g_variant_unref(result); } void storeFiles(GtkWidget *widget, gpointer userdata) { GError *error = NULL; GDBusProxy *account_proxy; account_proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.Accounts", "/org/freedesktop/Accounts", "org.freedesktop.Accounts", NULL, &error); if (error != NULL) { g_error("Could not connect to org.freedesktop.Accounts:%s\n",error->message); if (account_proxy) g_object_unref(account_proxy); return; } UserInfo *user = (UserInfo *)userdata; g_dbus_proxy_call(account_proxy, "DeleteUser", g_variant_new("(xb)", user->uid, FALSE), G_DBUS_CALL_FLAGS_NONE, -1, NULL, deleteUserDone, user); if (account_proxy) g_object_unref(account_proxy); } void deleteFiles(GtkWidget *widget, gpointer userdata) { GError *error = NULL; GDBusProxy *account_proxy; account_proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.Accounts", "/org/freedesktop/Accounts", "org.freedesktop.Accounts", NULL, &error); if (error != NULL) { g_error("Could not connect to org.freedesktop.Accounts:%s\n",error->message); if (account_proxy) g_object_unref(account_proxy); return; } UserInfo *user = (UserInfo *)userdata; g_dbus_proxy_call(account_proxy, "DeleteUser", g_variant_new("(xb)", user->uid, TRUE), G_DBUS_CALL_FLAGS_NONE, -1, NULL, deleteUserDone, user); if (account_proxy) g_object_unref(account_proxy); } void delete_user(GtkWidget *widget, gpointer userdata) { GError *err = NULL; UserInfo *user = (UserInfo *)userdata; if (user->logined) { char *primary_text = _("The user can not be deleted!"); GtkWidget *d = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", primary_text); gtk_window_set_icon_from_file (GTK_WINDOW(d), "/usr/share/ukui-control-center/icons/用户账号.png", NULL); char *secondary_text = _("The user has logged in, please perform the delete operation after logging out!"); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (d), "%s", secondary_text); gtk_widget_set_name(GTK_WIDGET(d), "ukuicc"); gtk_dialog_run (GTK_DIALOG (d)); gtk_widget_destroy (d); return; } ui = gtk_builder_new(); gtk_builder_add_from_file(ui, UIDIR "/delete-user.ui", &err); //gtk_builder_add_from_file(ui, "../panels/user-accounts/delete-user.ui", &err); if (err) { g_warning("Could not load user interface file: %s", err->message); g_error_free(err); g_object_unref(ui); return; } dialog = GTK_DIALOG(gtk_builder_get_object (ui, "deleteuser")); gtk_window_set_icon_from_file (GTK_WINDOW(dialog), "/usr/share/ukui-control-center/icons/用户账号.png", NULL); GtkWidget *label1 = GTK_WIDGET(gtk_builder_get_object (ui, "label1")); gtk_label_set_xalign(GTK_LABEL(label1), 0.0); char *markup = g_markup_printf_escaped (_("do you confirm to delete all the files of %s?"), user->username); gtk_label_set_markup(GTK_LABEL(label1), markup); GtkWidget *label2 = GTK_WIDGET(gtk_builder_get_object (ui, "label2")); gtk_label_set_xalign(GTK_LABEL(label2), 0.0); gtk_label_set_yalign(GTK_LABEL(label2), 0.1); char *message = g_strdup_printf(_("if you want to delete the %s user, belonging to the user's \ndesktop, documents, favorites, music, pictures and video \nfolder will be deleted!"), user->username); gtk_label_set_text(GTK_LABEL(label2), message); GtkWidget *dialog_action_area1 = GTK_WIDGET(gtk_builder_get_object (ui, "dialog-action_area1")); GdkColor color; gdk_color_parse("red", &color); gtk_widget_modify_fg(dialog_action_area1, GTK_STATE_NORMAL, &color); GtkWidget *buttonstore = GTK_WIDGET(gtk_builder_get_object (ui, "buttonstore")); g_signal_connect(buttonstore, "clicked", G_CALLBACK(storeFiles), user); GtkWidget *buttondelete = GTK_WIDGET(gtk_builder_get_object (ui, "buttondelete")); g_signal_connect(buttondelete, "clicked", G_CALLBACK(deleteFiles), user); gtk_widget_set_name(GTK_WIDGET(dialog), "ukuicc"); gtk_dialog_run(dialog); gtk_widget_destroy(GTK_WIDGET(dialog)); g_object_unref(ui); } void init_notebook(UserInfo *userinfo, gint page) { GtkWidget *label1, *label2, *label3, *hbox1, *bt_ch_name, *bt_ch_pwd, *bt_ch_face, *bt_ch_accounttype, *bt_del_user, *sep1, *sep2, *sep3, *sep4; char *markup; if (page == 0) { GtkWidget *hbox; hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); GtkWidget *image; GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(userinfo->iconfile, NULL); if (!pixbuf) pixbuf = gdk_pixbuf_new_from_file("/usr/share/pixmaps/faces/stock_person.png", NULL); GdkPixbuf *face = gdk_pixbuf_scale_simple(pixbuf, FACEHEIGHT, FACEWIDTH, GDK_INTERP_BILINEAR); image = gtk_image_new_from_pixbuf (face); userinfo->image0 = image; g_object_unref(pixbuf); g_object_unref(face); gtk_widget_show(image); gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, TRUE, 27); GtkWidget *vbox; vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_widget_set_size_request(vbox, -1, 90); gtk_widget_show(vbox); gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); label1 = gtk_label_new(userinfo->username); markup = g_markup_printf_escaped ("%s", userinfo->username); gtk_label_set_markup(GTK_LABEL(label1), markup); gtk_label_set_xalign(GTK_LABEL(label1), 0.0); hbox1 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); label2 = gtk_label_new(""); userinfo->labeltype0 = label2; if (userinfo->accounttype == ADMINISTRATOR) gtk_label_set_text(GTK_LABEL(label2), _("Administrators")); else if (userinfo->accounttype == STANDARDUSER) gtk_label_set_text(GTK_LABEL(label2), _("Standard user")); else gtk_label_set_text(GTK_LABEL(label2), _("Super user")); gtk_label_set_xalign(GTK_LABEL(label2), 0.0); bt_ch_name = gtk_button_new_with_label(_("Rename")); modify_font_color(bt_ch_name, "#074ca6"); gtk_button_set_relief(GTK_BUTTON(bt_ch_name), GTK_RELIEF_NONE); userinfo->labelname0 = label1; g_signal_connect (G_OBJECT (bt_ch_name), "clicked", G_CALLBACK (show_change_name_dialog), userinfo); sep1 = gtk_separator_new(GTK_ORIENTATION_VERTICAL); bt_ch_pwd = gtk_button_new_with_label(_("Change PWD")); modify_font_color(bt_ch_pwd, "#074ca6"); gtk_button_set_relief(GTK_BUTTON(bt_ch_pwd), GTK_RELIEF_NONE); g_signal_connect (G_OBJECT (bt_ch_pwd), "clicked", G_CALLBACK (show_change_pwd_dialog), userinfo); sep2 = gtk_separator_new(GTK_ORIENTATION_VERTICAL); bt_ch_face = gtk_button_new_with_label(_("Change Face")); modify_font_color(bt_ch_face, "#074ca6"); gtk_button_set_relief(GTK_BUTTON(bt_ch_face), GTK_RELIEF_NONE); g_signal_connect (G_OBJECT (bt_ch_face), "clicked", G_CALLBACK (show_change_face_dialog), userinfo); sep3 = gtk_separator_new(GTK_ORIENTATION_VERTICAL); bt_ch_accounttype = gtk_button_new_with_label(_("Change Type")); modify_font_color(bt_ch_accounttype, "#074ca6"); gtk_button_set_relief(GTK_BUTTON(bt_ch_accounttype), GTK_RELIEF_NONE); g_signal_connect (G_OBJECT (bt_ch_accounttype), "clicked", G_CALLBACK (show_change_accounttype_dialog), userinfo); sep4 = gtk_separator_new(GTK_ORIENTATION_VERTICAL); bt_del_user = gtk_button_new_with_label(_("Delete")); modify_font_color(bt_del_user, "#074ca6"); gtk_button_set_relief(GTK_BUTTON(bt_del_user), GTK_RELIEF_NONE); g_signal_connect (G_OBJECT (bt_del_user), "clicked", G_CALLBACK (delete_user), userinfo); label3 = gtk_label_new(""); if (userinfo->currentuser) { gtk_label_set_text(GTK_LABEL(label3), _("Logged(Current User)")); } else if (userinfo->logined && !userinfo->currentuser) { gtk_label_set_text(GTK_LABEL(label3), _("Logged(Other Users)")); } else { gtk_label_set_text(GTK_LABEL(label3), _("Un-login(Other Users)")); } gtk_label_set_xalign(GTK_LABEL(label3), 0.0); gtk_widget_show(label1); gtk_widget_show(label2); gtk_widget_show(label3); gtk_box_pack_start(GTK_BOX(vbox), label1, TRUE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox1, TRUE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox1), label2, TRUE, TRUE, 0); //label_space1和label_space2只是为了调整按钮位置的空白label GtkWidget *label_space1 = gtk_label_new(""); gtk_box_pack_start(GTK_BOX(hbox1), label_space1, TRUE, TRUE, 30); gtk_box_pack_start(GTK_BOX(hbox1), bt_ch_name, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox1), sep1, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox1), bt_ch_pwd, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox1), sep2, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox1), bt_ch_face, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox1), sep3, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox1), bt_ch_accounttype, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox1), sep4, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox1), bt_del_user, TRUE, TRUE, 0); //------------------同上--------------------- GtkWidget *label_space2 = gtk_label_new(""); gtk_box_pack_start(GTK_BOX(hbox1), label_space2, TRUE, TRUE, 30); gtk_box_pack_start(GTK_BOX(vbox), label3, TRUE, FALSE, 0); gtk_container_add(GTK_CONTAINER(userinfo->notebook), hbox); //屏蔽掉修改用户名按钮,因为修改了一个假的用户名 gtk_widget_set_no_show_all(bt_ch_name, TRUE); gtk_widget_set_no_show_all(sep1, TRUE); gtk_widget_hide(bt_ch_name); gtk_widget_hide(sep1); //kycc -u时要显示当前用户的所有控件 gtk_widget_show_all(GTK_WIDGET(userinfo->notebook)); } else if (page == 1) { GtkWidget *button; button = gtk_button_new(); gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); GtkWidget *hbox; hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_widget_show(hbox); gtk_container_add(GTK_CONTAINER(button), hbox); GtkWidget *image; GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(userinfo->iconfile, NULL); if (!pixbuf) pixbuf = gdk_pixbuf_new_from_file("/usr/share/pixmaps/faces/stock_person.png", NULL); GdkPixbuf *face = gdk_pixbuf_scale_simple(pixbuf, FACEHEIGHT, FACEWIDTH, GDK_INTERP_BILINEAR); image = gtk_image_new_from_pixbuf (face); userinfo->image1 = image; g_object_unref(pixbuf); g_object_unref(face); gtk_widget_show(image); gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, TRUE, 20); GtkWidget *vbox; vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); // gtk_box_set_spacing(GTK_BOX(vbox), 4); gtk_widget_set_size_request(vbox, -1, 90); gtk_widget_show(vbox); gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 7); label1 = gtk_label_new(userinfo->username); markup = g_markup_printf_escaped ("%s", userinfo->username); gtk_label_set_markup(GTK_LABEL(label1), markup); gtk_label_set_xalign(GTK_LABEL(label1), 0.0); userinfo->labelname1 = label1; label2 = gtk_label_new(""); userinfo->labeltype1 = label2; if (userinfo->accounttype == ADMINISTRATOR) gtk_label_set_text(GTK_LABEL(label2), _("Administrators")); else if (userinfo->accounttype == STANDARDUSER) gtk_label_set_text(GTK_LABEL(label2), _("Standard user")); else gtk_label_set_text(GTK_LABEL(label2), _("Super user")); // gtk_misc_set_alignment(GTK_MISC(label2), 0, 0.5); gtk_label_set_xalign(GTK_LABEL(label2), 0.0); label3 = gtk_label_new(""); if (userinfo->currentuser) { gtk_label_set_text(GTK_LABEL(label3), _("Logged(Current User)")); } else if (userinfo->logined && !userinfo->currentuser) { gtk_label_set_text(GTK_LABEL(label3), _("Logged(Other Users)")); } else { gtk_label_set_text(GTK_LABEL(label3), _("Un-login(Other Users)")); } gtk_label_set_xalign(GTK_LABEL(label3), 0.0); gtk_widget_show(label1); gtk_widget_show(label2); gtk_widget_show(label3); gtk_box_pack_start(GTK_BOX(vbox), label1, TRUE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), label2, TRUE, FALSE, 16); gtk_box_pack_start(GTK_BOX(vbox), label3, TRUE, FALSE, 0); gtk_widget_show_all(button); gtk_container_add(GTK_CONTAINER(userinfo->notebook), button); g_signal_connect(G_OBJECT(button), "enter", G_CALLBACK(user_bt_clicked), userinfo->notebook); } } void init_user_button(GtkBox *box, UserInfo *user) { gtk_notebook_set_show_border(user->notebook, FALSE); gtk_notebook_set_show_tabs (user->notebook, FALSE); gtk_widget_set_size_request(GTK_WIDGET(user->notebook), -1, 90); gtk_notebook_set_current_page(user->notebook, 0); init_notebook(user, 0); init_notebook(user, 1); gtk_notebook_set_current_page(user->notebook, 1); gtk_box_pack_start(box, GTK_WIDGET(user->notebook), FALSE, FALSE, 0); } void init_user_info(const gchar *object_path) { GError *error = NULL; GVariant *value = NULL; gsize size; UserInfo *user = (UserInfo *)malloc(sizeof(UserInfo)); user->currentuser = FALSE; user->logined = FALSE; user->autologin = FALSE; user->proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.Accounts", object_path, "org.freedesktop.Accounts.User", NULL, &error); value = g_dbus_proxy_get_cached_property(user->proxy, "UserName"); size = g_variant_get_size(value); user->username = (char *)g_variant_get_string(value, &size); const char *username = g_get_user_name(); if (g_strcmp0((const char *)user->username, username) == 0) { user->currentuser = TRUE; } OobsUser *obsuser = oobs_user_new(user->username); user->logined = oobs_user_get_active(obsuser); value = g_dbus_proxy_get_cached_property(user->proxy, "AccountType"); user->accounttype = (gint)g_variant_get_int32(value); value = g_dbus_proxy_get_cached_property(user->proxy, "IconFile"); size = g_variant_get_size(value); user->iconfile = (char *)g_variant_get_string(value, &size); value = g_dbus_proxy_get_cached_property(user->proxy, "PasswordMode"); user->passwdtype = g_variant_get_int32(value); value = g_dbus_proxy_get_cached_property(user->proxy, "Uid"); user->uid = (gint)g_variant_get_uint64(value); value = g_dbus_proxy_get_cached_property(user->proxy, "AutomaticLogin"); user->autologin = (gint)g_variant_get_boolean(value); user->notebook = GTK_NOTEBOOK(gtk_notebook_new()); if (user->currentuser) userlist = g_list_insert(userlist, user, 0); else userlist = g_list_append(userlist, user); g_variant_unref(value); } //写死root用户的一些信息 void init_root_info() { UserInfo *user = (UserInfo *)malloc(sizeof(UserInfo)); user->accounttype = 2; //代表超级用户 user->currentuser = TRUE; user->autologin = FALSE; user->username = g_get_user_name(); user->iconfile = "/usr/share/pixmaps/faces/stock_person.svg"; OobsUser *obsuser = oobs_user_new(user->username); user->logined = oobs_user_get_active(obsuser); user->uid = 0; user->notebook = GTK_NOTEBOOK(gtk_notebook_new()); userlist = g_list_insert(userlist, user, 0); } void update_user_box(GtkWidget *widget, gpointer data) { GList *list; GtkWidget *other_hbox = GTK_WIDGET (gtk_builder_get_object (builder, "hbox6")); //init_label(GTK_BOX(widget), TRUE); if (g_list_length(userlist) == 1) gtk_widget_hide(other_hbox); else gtk_widget_show(other_hbox); GtkWidget *current_user_box = GTK_WIDGET (gtk_builder_get_object (builder, "current_user_box")); gtk_widget_show_all(current_user_box); for(list = userlist; list; list = list->next) { UserInfo *info = (UserInfo *)list->data; if (!info->currentuser) init_user_button (GTK_BOX(widget), info); else init_user_button (GTK_BOX(current_user_box), info); } gtk_widget_show_all(widget); } void get_all_users_in_callback(GObject *object, GAsyncResult *res, gpointer user_data) { GError * error = NULL; const gchar **users_name; GVariant *result, *users_name_variant; gsize size, number; gint i; result = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), res, &error); if (result == NULL) { g_warning("Callback Result is null"); return; } if (error != NULL) { g_warning("DBUS error:%s", error->message); g_error_free(error); return; } size = g_variant_get_size(result); users_name_variant = g_variant_get_child_value(result, 0); number = g_variant_n_children(users_name_variant); users_name = g_variant_get_objv(users_name_variant, &size); for(i =0; i< (gint)number; i++) { init_user_info(users_name[i]); } //root用户单独处理 if(!getuid()) init_root_info(); GtkWidget *box = GTK_WIDGET (gtk_builder_get_object (builder, "other_users")); update_user_box(box, NULL); } void dbus_get_users_in_system() { GError * error=NULL; GDBusProxy * account_proxy; account_proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.Accounts", "/org/freedesktop/Accounts", "org.freedesktop.Accounts", NULL, &error); if (error != NULL) { g_error("Could not connect to org.freedesktop.Accounts:%s\n",error->message); if (account_proxy) g_object_unref(account_proxy); return; } g_dbus_proxy_call(account_proxy, "ListCachedUsers", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, get_all_users_in_callback, "ListCachedUsers"); if (account_proxy) g_object_unref(account_proxy); } void update_user(GtkWidget *widget, gpointer data) { GtkWidget *label1; label1 = gtk_label_new(""); gtk_widget_set_size_request(label1, -1, 1); gtk_label_set_xalign(GTK_LABEL(label1), 0.0); gtk_box_pack_start(GTK_BOX(widget), GTK_WIDGET(label1), FALSE, FALSE, 0); gtk_widget_show_all(widget); } static void stock_icon_selected (GtkMenuItem *menuitem, UserInfo *user) { const char *filename; filename = g_object_get_data (G_OBJECT (menuitem), "filename"); user->iconfile = (char *)filename; GtkWidget *image = GTK_WIDGET(gtk_builder_get_object (ui, "imageuser")); GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(user->iconfile, NULL); GdkPixbuf *face = gdk_pixbuf_scale_simple(pixbuf, 99, 99, GDK_INTERP_BILINEAR); gtk_image_set_from_pixbuf(GTK_IMAGE(image), face); GtkWidget *label = GTK_WIDGET(gtk_builder_get_object (ui, "labeluser")); gtk_widget_hide(label); gtk_widget_show(image); GtkWidget *button = GTK_WIDGET(gtk_builder_get_object (ui, "user-icon-button")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE); g_object_unref(pixbuf); g_object_unref(face); } static void none_icon_selected (GtkMenuItem *menuitem, UserInfo *user) { user->iconfile = ""; } static GtkWidget * menu_item_for_filename (UserInfo *user, const char *filename){ GtkWidget *image, *menuitem; GFile *file; GIcon *icon; file = g_file_new_for_path (filename); icon = g_file_icon_new (file); g_object_unref (file); image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_DIALOG); g_object_unref (icon); menuitem = gtk_menu_item_new (); gtk_container_add (GTK_CONTAINER (menuitem), image); gtk_widget_show_all (menuitem); g_object_set_data_full (G_OBJECT (menuitem), "filename", g_strdup (filename), (GDestroyNotify) g_free); g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (stock_icon_selected), user); return menuitem; } static void file_chooser_response (GtkDialog *chooser, gint response, UserInfo *user) { gchar *filename; GError *error; GdkPixbuf *pixbuf; if (response != GTK_RESPONSE_ACCEPT) { gtk_widget_destroy (GTK_WIDGET (chooser)); return; } filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser)); user->iconfile = filename; GtkWidget *image = GTK_WIDGET(gtk_builder_get_object (ui, "imageuser")); error = NULL; pixbuf = gdk_pixbuf_new_from_file (user->iconfile, &error); if (pixbuf == NULL) { g_warning ("Failed to load %s: %s", filename, error->message); g_error_free (error); } GdkPixbuf *face = gdk_pixbuf_scale_simple(pixbuf, 99, 99, GDK_INTERP_BILINEAR); gtk_image_set_from_pixbuf(GTK_IMAGE(image), face); GtkWidget *label = GTK_WIDGET(gtk_builder_get_object (ui, "labeluser")); if (label) { gtk_widget_hide(label); gtk_widget_show(image); GtkWidget *button = GTK_WIDGET(gtk_builder_get_object (ui, "user-icon-button")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE); } gtk_widget_destroy (GTK_WIDGET (chooser)); //um_photo_dialog_crop (um, pixbuf); g_object_unref (pixbuf); g_object_unref (face); } static void update_preview (GtkFileChooser *chooser, MateDesktopThumbnailFactory *thumb_factory) { gchar *uri; uri = gtk_file_chooser_get_preview_uri (chooser); if (uri) { GdkPixbuf *pixbuf = NULL; const gchar *mime_type = NULL; GFile *file; GFileInfo *file_info; GtkWidget *preview; preview = gtk_file_chooser_get_preview_widget (chooser); file = g_file_new_for_uri (uri); file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL); g_object_unref (file); if (file_info != NULL) { mime_type = g_file_info_get_content_type (file_info); g_object_unref (file_info); } if (mime_type) { pixbuf = mate_desktop_thumbnail_factory_generate_thumbnail (thumb_factory, uri, mime_type); } gtk_dialog_set_response_sensitive (GTK_DIALOG (chooser), GTK_RESPONSE_ACCEPT, (pixbuf != NULL)); if (pixbuf != NULL) { gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf); g_object_unref (pixbuf); } else { gtk_image_set_from_icon_name (GTK_IMAGE (preview), NULL, GTK_ICON_SIZE_DIALOG); } g_free (uri); } gtk_file_chooser_set_preview_widget_active (chooser, TRUE); } static void user_photo_dialog_select_file (UserInfo *user) { GtkWidget *chooser; const gchar *folder; GtkWidget *preview; chooser = gtk_file_chooser_dialog_new (_("Browse more pictures"), NULL, GTK_FILE_CHOOSER_ACTION_OPEN, _("Cancel"), GTK_RESPONSE_CANCEL, _("Ok"), GTK_RESPONSE_ACCEPT, NULL); gtk_window_set_modal (GTK_WINDOW (chooser), TRUE); MateDesktopThumbnailFactory* thumb_factory = mate_desktop_thumbnail_factory_new (MATE_DESKTOP_THUMBNAIL_SIZE_NORMAL); preview = gtk_image_new (); gtk_widget_set_size_request (preview, 128, -1); gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (chooser), preview); gtk_file_chooser_set_use_preview_label (GTK_FILE_CHOOSER (chooser), FALSE); gtk_widget_show (preview); g_signal_connect (chooser, "update-preview", G_CALLBACK (update_preview), thumb_factory); folder = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES); if (folder) gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser), folder); g_signal_connect (chooser, "response", G_CALLBACK (file_chooser_response), user); gtk_widget_set_name(GTK_WIDGET(chooser), "ukuicc"); gtk_window_present (GTK_WINDOW (chooser)); } static void file_icon_selected (GtkMenuItem *menuitem, UserInfo *user) { user_photo_dialog_select_file (user); } GtkWidget * setup_photo_popup (UserInfo *user) { GtkWidget *menu, *menuitem; guint x, y; const gchar * const * dirs; guint i; GDir *dir; const char *face; gboolean none_item_shown; gboolean added_faces; menu = gtk_menu_new (); x = 0; y = 0; none_item_shown = added_faces = FALSE; dirs = g_get_system_data_dirs (); for (i = 0; dirs[i] != NULL; i++) { char *path; path = g_build_filename (dirs[i], "pixmaps", "faces", NULL); dir = g_dir_open (path, 0, NULL); if (dir == NULL) { g_free (path); continue; } while ((face = g_dir_read_name (dir)) != NULL) { char *filename; added_faces = TRUE; filename = g_build_filename (path, face, NULL); menuitem = menu_item_for_filename (user, filename); g_free (filename); if (menuitem == NULL) continue; gtk_menu_attach (GTK_MENU (menu), GTK_WIDGET (menuitem), x, x + 1, y, y + 1); gtk_widget_show (menuitem); x++; if (x >= ROW_SPAN - 1) { y++; x = 0; } } g_dir_close (dir); g_free (path); if (added_faces) break; } if (!added_faces) goto skip_faces; /*image = gtk_image_new_from_icon_name ("avatar-default", GTK_ICON_SIZE_DIALOG); menuitem = gtk_menu_item_new (); gtk_container_add (GTK_CONTAINER (menuitem), image); gtk_widget_show_all (menuitem); gtk_menu_attach (GTK_MENU (menu), GTK_WIDGET (menuitem), x, x + 1, y, y + 1); g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (none_icon_selected), user);*/ gtk_widget_set_name(GTK_WIDGET(menuitem), "ukuicc"); gtk_widget_show (menuitem); none_item_shown = TRUE; y++; skip_faces: if (!none_item_shown) { menuitem = gtk_menu_item_new_with_label ("Disable image"); gtk_menu_attach (GTK_MENU (menu), GTK_WIDGET (menuitem), 0, ROW_SPAN - 1, y, y + 1); g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (none_icon_selected), user); gtk_widget_show (menuitem); y++; } /* Separator */ menuitem = gtk_separator_menu_item_new (); gtk_menu_attach (GTK_MENU (menu), GTK_WIDGET (menuitem), 0, ROW_SPAN - 1, y, y + 1); gtk_widget_show (menuitem); y++; /*#ifdef HAVE_CHEESE um->take_photo_menuitem = gtk_menu_item_new_with_label (_("Take a photo…")); gtk_menu_attach (GTK_MENU (menu), GTK_WIDGET (um->take_photo_menuitem), 0, ROW_SPAN - 1, y, y + 1); g_signal_connect (G_OBJECT (um->take_photo_menuitem), "activate", G_CALLBACK (webcam_icon_selected), um); gtk_widget_set_sensitive (um->take_photo_menuitem, FALSE); gtk_widget_show (um->take_photo_menuitem); um->monitor = cheese_camera_device_monitor_new (); g_signal_connect (G_OBJECT (um->monitor), "added", G_CALLBACK (device_added), um); g_signal_connect (G_OBJECT (um->monitor), "removed", G_CALLBACK (device_removed), um); cheese_camera_device_monitor_coldplug (um->monitor); y++; #endif*/ /* HAVE_CHEESE */ menuitem = gtk_menu_item_new_with_label (_("Browse more pictures...")); gtk_menu_attach (GTK_MENU (menu), GTK_WIDGET (menuitem), 0, ROW_SPAN - 1, y, y + 1); g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (file_icon_selected), user); gtk_widget_set_name(GTK_WIDGET(menuitem), "ukuicc"); gtk_widget_show (menuitem); return menu; } void popup_menu_below_button (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, GtkWidget *button) { GtkRequisition menu_req; GtkTextDirection direction; GtkAllocation allocation; gtk_widget_get_preferred_size(GTK_WIDGET (menu), NULL, &menu_req); direction = gtk_widget_get_direction (button); gdk_window_get_origin (gtk_widget_get_window (button), x, y); gtk_widget_get_allocation (button, &allocation); *x += allocation.x; *y += allocation.y + allocation.height; if (direction == GTK_TEXT_DIR_LTR) *x += MAX (allocation.width - menu_req.width, 0); else if (menu_req.width > allocation.width) *x -= menu_req.width - allocation.width; *push_in = FALSE; } static void popup_icon_menu (GtkToggleButton *button, GtkWidget *menu) { if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) && !gtk_widget_get_visible (menu)) { gtk_menu_popup (GTK_MENU (menu), NULL, NULL, (GtkMenuPositionFunc) popup_menu_below_button, button, 0, gtk_get_current_event_time ()); } else { gtk_menu_popdown (GTK_MENU(menu)); // gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (user->popup_button), FALSE); } } static gboolean on_popup_button_button_pressed (GtkToggleButton *button, GdkEventButton *event, GtkWidget *menu) { if (event->button == 1) { if (!gtk_widget_get_visible (menu)) { popup_icon_menu (button, menu); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE); } else { gtk_menu_popdown (GTK_MENU (menu)); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE); } return TRUE; } return FALSE; } static void popup_button_focus_changed (GObject *button, GParamSpec *pspec, UserInfo *user) { gtk_widget_queue_draw (gtk_bin_get_child (GTK_BIN (button))); } static void on_photo_popup_unmap (GtkWidget *popup_menu, GtkWidget *button) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE); } static void autologin(GtkWidget *widget, gpointer userdata) { UserInfo *user = (UserInfo *)userdata; if(!user->autologin){ GList *it = NULL; for (it = userlist; it; it = it->next) { UserInfo *system_user = (UserInfo *)it->data; if(system_user->autologin == TRUE) { //为什么一个clicked信号,会触发两次这个回调?这里过滤掉了第二次的回调。 if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) continue; GtkWidget *label; GtkWidget *dialog = gtk_dialog_new_with_buttons( _("auto login"), window, GTK_DIALOG_MODAL, _("_Cancel"), GTK_RESPONSE_REJECT, _("_OK"), GTK_RESPONSE_ACCEPT, NULL); label = gtk_label_new(_("\tAlready have other users set to automatically log in,\t\n \tclick OK will overwrite the existing settings!")); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label, TRUE, TRUE, 30); gtk_widget_show_all(dialog); gint result = gtk_dialog_run(GTK_DIALOG(dialog)); if(result == GTK_RESPONSE_ACCEPT) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE); else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), FALSE); gtk_widget_destroy(dialog); } } }//end-if gboolean toggled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)); user->autologin = toggled; } static void toggled(GtkWidget *widget, gpointer userdata) { UserInfo *userinfo = (UserInfo *)userdata; gboolean toggled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)); GtkWidget *w = GTK_WIDGET (gtk_builder_get_object (ui, "radiobutton1")); if (toggled && widget == w) { userinfo->accounttype = STANDARDUSER; } else userinfo->accounttype = ADMINISTRATOR; } gboolean update_user_autologin(gpointer user_date) { UserInfo *user = (UserInfo *)user_date; g_warning("--xiaoyi-----autologin = %d",user->autologin); g_dbus_proxy_call(user->proxy, "SetAutomaticLogin", g_variant_new("(b)", user->autologin), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); return FALSE; } static void createUserDone(GObject *object, GAsyncResult *res, gpointer user_data) { GError * error = NULL; GVariant *result, *value; result = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), res, &error); if (result == NULL) { g_warning("Callback Result is null"); return; } if (error != NULL) { g_warning("DBUS error:%s", error->message); g_error_free(error); return; } UserInfo *user = (UserInfo *)user_data; char *path = (char *)g_variant_get_data(result); user->proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.Accounts", path, "org.freedesktop.Accounts.User", NULL, &error); if (user->iconfile == NULL) user->iconfile = "/usr/share/pixmaps/faces/stock_person.png"; g_dbus_proxy_call(user->proxy, "SetIconFile", g_variant_new("(s)", user->iconfile), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); char *crypted = make_crypted(user->password); g_dbus_proxy_call(user->proxy, "SetPassword", g_variant_new("(ss)", crypted, ""), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); g_dbus_proxy_call(user->proxy, "SetAccountType", g_variant_new("(i)", user->accounttype), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); // g_warning("--xiaoyi-----autologin = %d",user->autologin); if(user->autologin == TRUE) //确保自动登录用户只有最新设置的生效 { GList *it = NULL; for (it = userlist; it; it = it->next) { UserInfo *system_user = (UserInfo *)it->data; if(system_user->autologin == TRUE) { if(0 == strcmp(user->username,system_user->username)) continue; system_user->autologin = FALSE; g_dbus_proxy_call(user->proxy, "SetAutomaticLogin", g_variant_new("(b)", system_user->autologin), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); } } } g_timeout_add(1000,(GSourceFunc)update_user_autologin,user); value = g_dbus_proxy_get_cached_property(user->proxy, "Uid"); user->uid = (gint)g_variant_get_uint64(value); user->notebook = GTK_NOTEBOOK(gtk_notebook_new()); if (user->currentuser) userlist = g_list_insert(userlist, user, 0); else userlist = g_list_append(userlist, user); GtkWidget *box = GTK_WIDGET (gtk_builder_get_object (builder, "other_users")); if (g_list_length(userlist) == 2) { GtkWidget *other_hbox = GTK_WIDGET (gtk_builder_get_object (builder, "hbox6")); gtk_widget_show(other_hbox); } init_user_button(GTK_BOX(box), user); gtk_widget_show_all(box); gtk_widget_destroy(GTK_WIDGET(dialog)); g_object_unref(ui); } static void createuser(GtkWidget *widget, gpointer userdata) { UserInfo *user = (UserInfo *)userdata; user->username = NULL; user->password = NULL; GtkWidget *entryname = GTK_WIDGET(gtk_builder_get_object (ui, "entryname")); GtkWidget *entrypwd = GTK_WIDGET(gtk_builder_get_object (ui, "entrypwd")); char *username = (char *)gtk_entry_get_text(GTK_ENTRY(entryname)); user->username = (char *)malloc(strlen(username)*sizeof(char)); strcpy(user->username, username); char *password = (char *)gtk_entry_get_text(GTK_ENTRY(entrypwd)); user->password = (char *)malloc(strlen(password)*sizeof(char)); strcpy(user->password, password); gtk_widget_hide(GTK_WIDGET(dialog)); GError *error = NULL; GDBusProxy *account_proxy; account_proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.Accounts", "/org/freedesktop/Accounts", "org.freedesktop.Accounts", NULL, &error); if (error != NULL) { g_error("Could not connect to org.freedesktop.Accounts:%s\n",error->message); if (account_proxy) g_object_unref(account_proxy); return; } g_dbus_proxy_call(account_proxy, "CreateUser", g_variant_new("(ssi)", user->username, "", user->accounttype), G_DBUS_CALL_FLAGS_NONE, -1, NULL, createUserDone, user); if (account_proxy) g_object_unref(account_proxy); } static void createCancel(GtkWidget *widget, gpointer userdata) { if (userdata != NULL) { UserInfo *user = (UserInfo *)userdata; /*if (user->username) { free(user->username); } if (user->password) { free(user->password); }*/ free(user); } gtk_widget_destroy(GTK_WIDGET(dialog)); g_object_unref(ui); } //用于修改密码的时候 gboolean createuser_pwd_focus_out(GtkWidget *entry, GdkEventFocus *event, gpointer user_data) { char *msg = NULL; GtkWidget *entrypwd = GTK_WIDGET(gtk_builder_get_object (ui, "entrypwd")); GtkWidget *labelpwd = GTK_WIDGET(gtk_builder_get_object (ui, "labelpwd")); const char *user_passwd = gtk_entry_get_text (GTK_ENTRY (entrypwd)); msg = passwd_check("", user_passwd, g_get_user_name()); if(msg) gtk_label_set_text(GTK_LABEL(labelpwd), msg); else gtk_label_set_text(GTK_LABEL(labelpwd), ""); } void show_create_user_dialog(GtkWidget *widget, gpointer data) { GError *err = NULL; ui = gtk_builder_new(); gtk_builder_add_from_file(ui, UIDIR "/user-create.ui", &err); if (err) { g_warning("Could not load user interface file: %s", err->message); g_error_free(err); g_object_unref(ui); return; } UserInfo *user = (UserInfo *)malloc(sizeof(UserInfo)); user->currentuser = FALSE; user->logined = FALSE; user->autologin = FALSE; user->iconfile = NULL; dialog = GTK_DIALOG(gtk_builder_get_object (ui, "usercreate")); gtk_window_set_icon_from_file (GTK_WINDOW(dialog), "/usr/share/ukui-control-center/icons/用户账号.png", NULL); GtkWidget *imageuser = GTK_WIDGET(gtk_builder_get_object (ui, "imageuser")); gtk_widget_hide(imageuser); GtkWidget *button = GTK_WIDGET(gtk_builder_get_object (ui, "user-icon-button")); GtkWidget *menu = setup_photo_popup(user); g_signal_connect (button, "toggled", G_CALLBACK (popup_icon_menu), menu); g_signal_connect (button, "button-press-event", G_CALLBACK (on_popup_button_button_pressed), menu); g_signal_connect (button, "notify::is-focus", G_CALLBACK (popup_button_focus_changed), user); /* g_signal_connect_after (button, "draw", G_CALLBACK (popup_button_draw), user);*/ g_signal_connect (menu, "unmap", G_CALLBACK (on_photo_popup_unmap), button); GtkWidget *entryname = GTK_WIDGET(gtk_builder_get_object (ui, "entryname")); gtk_entry_set_text(GTK_ENTRY(entryname), _("Please enter the username")); GdkColor color; gdk_color_parse("#999999", &color); gtk_widget_modify_text(entryname, GTK_STATE_NORMAL, &color); g_signal_connect(entryname, "focus-in-event", G_CALLBACK(focusIn), NULL); g_signal_connect(entryname, "changed", G_CALLBACK(textChanged), user); GtkWidget *entrypwd = GTK_WIDGET(gtk_builder_get_object (ui, "entrypwd")); gtk_entry_set_text(GTK_ENTRY(entrypwd), _("Please enter the password")); gtk_widget_modify_text(entrypwd, GTK_STATE_NORMAL, &color); g_signal_connect(entrypwd, "focus-in-event", G_CALLBACK(focusIn), NULL); g_signal_connect(entrypwd, "changed", G_CALLBACK(textChanged), user); GtkWidget *entryensurepwd = GTK_WIDGET(gtk_builder_get_object (ui, "entryensurepwd")); gtk_entry_set_text(GTK_ENTRY(entryensurepwd), _("Please confirm the new password")); gtk_widget_modify_text(entryensurepwd, GTK_STATE_NORMAL, &color); g_signal_connect(entryensurepwd, "focus-in-event", G_CALLBACK(focusIn), NULL); g_signal_connect(entryensurepwd, "changed", G_CALLBACK(textChanged), user); GtkWidget *btautologin = GTK_WIDGET(gtk_builder_get_object (ui, "btautologin")); g_signal_connect(btautologin, "clicked", G_CALLBACK(autologin), user); GtkWidget *bt_normal = GTK_WIDGET(gtk_builder_get_object (ui, "radiobutton1")); gtk_toggle_button_set_active((GtkToggleButton *)bt_normal, TRUE); user->accounttype = STANDARDUSER; g_signal_connect(bt_normal, "toggled", G_CALLBACK(toggled), user); GtkWidget *bt_admin = GTK_WIDGET(gtk_builder_get_object (ui, "radiobutton2")); g_signal_connect(bt_admin, "toggled", G_CALLBACK(toggled), user); GtkWidget *buttoncreate = GTK_WIDGET(gtk_builder_get_object (ui, "buttoncreate")); g_signal_connect(buttoncreate, "clicked", G_CALLBACK(createuser), user); GtkWidget *buttoncancel = GTK_WIDGET(gtk_builder_get_object (ui, "buttoncancel")); g_signal_connect(buttoncancel, "clicked", G_CALLBACK(createCancel), user); gtk_widget_grab_focus(buttoncancel); gtk_widget_set_sensitive(buttoncreate, FALSE); gtk_widget_set_name(GTK_WIDGET(dialog), "ukuicc"); // gtk_dialog_run(dialog); gtk_widget_show(GTK_WIDGET(dialog)); } void init_user_accounts() { g_warning("user accounts"); GtkWidget *widget; GtkWidget *other_users; GtkWidget *current_user; other_users = GTK_WIDGET (gtk_builder_get_object (builder, "other_users")); current_user = GTK_WIDGET (gtk_builder_get_object (builder, "current_user_box")); g_signal_connect(G_OBJECT(other_users), "realize", G_CALLBACK(update_user), NULL); g_signal_connect(G_OBJECT(current_user), "realize", G_CALLBACK(update_user), NULL); dbus_get_users_in_system(); widget = GTK_WIDGET (gtk_builder_get_object (builder, "bt_new")); g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(show_create_user_dialog), NULL); } void users_data_destory() { GList *it = NULL; for (it = userlist; it; it = it->next) g_free(it->data); } ukui-control-center/panels/user-accounts/change-face.ui0000664000175000017500000002727013245450076022164 0ustar fengfeng 675 545 False 5 Changge Face True dialog True True True False vertical 2 True False end Cancel True True True False False 0 Ok True True True False False 1 False False 10 end 0 True False vertical True False 3 90 80 True False gtk-missing-image False True 10 0 True False 150 30 True False start label 10 21 150 30 True False start label 10 45 150 30 True False start False label 10 69 110 40 True False none 110 33 True True False True True False True False 16 add False False 0 True False Browse more pictures False True 1 425 75 True True 1 True True 5 0 300 True False 10 True True never True True 1 True True 1 buttoncancel buttonok ukui-control-center/panels/user-accounts/user-accounts.h0000664000175000017500000000310013057175444022436 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __USER_ACCOUNTS_H #define __USER_ACCOUNTS_H #include #include #include #include #include #include "mainwindow.h" #define FACEHEIGHT 72 #define FACEWIDTH 72 #define STANDARDUSER 0 #define ADMINISTRATOR 1 typedef struct { GtkNotebook *notebook; GtkWidget *labelname0; GtkWidget *labelname1; GtkWidget *labeltype0; GtkWidget *labeltype1; GtkWidget *image0; GtkWidget *image1; gchar *username; gchar *iconfile; gchar *password; gint accounttype; gint passwdtype; gboolean currentuser; gboolean logined; gboolean autologin; gint uid; GDBusProxy *proxy; } UserInfo; void init_user_accounts(); #endif /* __USER_ACCOUNTS_H */ ukui-control-center/panels/user-accounts/check-passwd.c0000664000175000017500000004206313245450076022221 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "check-passwd.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define x_strdup(s) ( (s) ? strdup(s):NULL ) #ifdef MIN #undef MIN #endif #define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) /* Helper functions */ /* * can't be a palindrome - like `R A D A R' or `M A D A M' */ static int palindrome(const char *new) { int i, j; i = strlen (new); for (j = 0;j < i;j++) if (new[i - j - 1] != new[j]) return 0; return 1; } /* * Calculate how different two strings are in terms of the number of * character removals, additions, and changes needed to go from one to * the other */ static int distdifferent(const char *old, const char *new, size_t i, size_t j) { char c, d; if ((i == 0) || (strlen(old) < i)) { c = 0; } else { c = old[i - 1]; } if ((j == 0) || (strlen(new) < j)) { d = 0; } else { d = new[j - 1]; } return (c != d); } static int distcalculate(int **distances, const char *old, const char *new, size_t i, size_t j) { int tmp = 0; if (distances[i][j] != -1) { return distances[i][j]; } tmp = distcalculate(distances, old, new, i - 1, j - 1); tmp = MIN(tmp, distcalculate(distances, old, new, i, j - 1)); tmp = MIN(tmp, distcalculate(distances, old, new, i - 1, j)); tmp += distdifferent(old, new, i, j); distances[i][j] = tmp; return tmp; } static int distance(const char *old, const char *new) { int **distances = NULL; size_t m, n, i, j, r; m = strlen(old); n = strlen(new); distances = malloc(sizeof(int*) * (m + 1)); for (i = 0; i <= m; i++) { distances[i] = malloc(sizeof(int) * (n + 1)); for(j = 0; j <= n; j++) { distances[i][j] = -1; } } for (i = 0; i <= m; i++) { distances[i][0] = i; } for (j = 0; j <= n; j++) { distances[0][j] = j; } distances[0][0] = 0; r = distcalculate(distances, old, new, m, n); for (i = 0; i <= m; i++) { memset(distances[i], 0, sizeof(int) * (n + 1)); free(distances[i]); } free(distances); return r; } static int similar(struct cracklib_options *opt, const char *old, const char *new) { if (distance(old, new) >= opt->diff_ok) { return 0; } if (strlen(new) >= (strlen(old) * 2)) { return 0; } /* passwords are too similar */ return 1; } /* * enough classes of charecters */ static int minclass (struct cracklib_options *opt, const char *new) { int digits = 0; int uppers = 0; int lowers = 0; int others = 0; int total_class; int i; int retval; // D(( "called" )); for (i = 0; new[i]; i++) { if (isdigit (new[i])) digits = 1; else if (isupper (new[i])) uppers = 1; else if (islower (new[i])) lowers = 1; else others = 1; } total_class = digits + uppers + lowers + others; // D (("total class: %d\tmin class: %d", total_class, opt->min_class)); if (total_class >= opt->min_class) retval = 0; else retval = 1; return retval; } /* * a nice mix of characters. */ static int simple(struct cracklib_options *opt, const char *new) { int digits = 0; int uppers = 0; int lowers = 0; int others = 0; int size; int i; enum { NONE, DIGIT, UCASE, LCASE, OTHER } prevclass = NONE; int sameclass = 0; for (i = 0;new[i];i++) { if (isdigit (new[i])) { digits++; if (prevclass != DIGIT) { prevclass = DIGIT; sameclass = 1; } else sameclass++; } else if (isupper (new[i])) { uppers++; if (prevclass != UCASE) { prevclass = UCASE; sameclass = 1; } else sameclass++; } else if (islower (new[i])) { lowers++; if (prevclass != LCASE) { prevclass = LCASE; sameclass = 1; } else sameclass++; } else { others++; if (prevclass != OTHER) { prevclass = OTHER; sameclass = 1; } else sameclass++; } if (opt->max_class_repeat > 1 && sameclass > opt->max_class_repeat) { return 1; } } /* * The scam was this - a password of only one character type * must be 8 letters long. Two types, 7, and so on. * This is now changed, the base size and the credits or defaults * see the docs on the module for info on these parameters, the * defaults cause the effect to be the same as before the change */ if ((opt->dig_credit >= 0) && (digits > opt->dig_credit)) //满足密码复杂度的数字条件 digits = opt->dig_credit; if ((opt->up_credit >= 0) && (uppers > opt->up_credit)) //满足大写字母要求 uppers = opt->up_credit; if ((opt->low_credit >= 0) && (lowers > opt->low_credit)) //满足小写字母要求 lowers = opt->low_credit; if ((opt->oth_credit >= 0) && (others > opt->oth_credit)) others = opt->oth_credit; size = opt->min_length; if (opt->dig_credit >= 0) size -= digits; else if (digits < opt->dig_credit * -1) return 1; if (opt->up_credit >= 0) size -= uppers; else if (uppers < opt->up_credit * -1) return 1; if (opt->low_credit >= 0) size -= lowers; else if (lowers < opt->low_credit * -1) return 1; if (opt->oth_credit >= 0) size -= others; else if (others < opt->oth_credit * -1) return 1; if (size <= i){ return 0; } return 1; } static int consecutive(struct cracklib_options *opt, const char *new) { char c; int i; int same; if (opt->max_repeat == 0) return 0; for (i = 0; new[i]; i++) { if (i > 0 && new[i] == c) { ++same; if (same > opt->max_repeat) return 1; } else { c = new[i]; same = 1; } } return 0; } static int sequence(struct cracklib_options *opt, const char *new) { char c; int i; int sequp = 1; int seqdown = 1; if (opt->max_sequence == 0) return 0; if (new[0] == '\0') return 0; for (i = 1; new[i]; i++) { c = new[i-1]; if (new[i] == c+1) { ++sequp; if (sequp > opt->max_sequence) return 1; seqdown = 1; } else if (new[i] == c-1) { ++seqdown; if (seqdown > opt->max_sequence) return 1; sequp = 1; } else { sequp = 1; seqdown = 1; } } return 0; } static int wordcheck(const char *new, char *word) { char *f, *b; if (strstr(new, word) != NULL) return 1; /* now reverse the word, we can do that in place as it is strdup-ed */ f = word; b = word+strlen(word)-1; while (f < b) { char c; c = *f; *f = *b; *b = c; --b; ++f; } if (strstr(new, word) != NULL) return 1; return 0; } static int usercheck(struct cracklib_options *opt, const char *new, char *user) { // if (!opt->reject_user) // return 0; return wordcheck(new, user); } static char * str_lower(char *string) { char *cp; if (!string) return NULL; for (cp = string; *cp; cp++) *cp = tolower(*cp); return string; } /* * 配置common-password文件时,必须保证各个区块之间是以tab键分隔, * 最后一个区块的用户密码复杂度要求之间要以空格分隔 */ GPtrArray *get_passwd_configuration() { GPtrArray *pam_conf = g_ptr_array_new(); FILE *pam_file; char buffer[1024]; pam_file = fopen("/etc/pam.d/common-password", "r"); if (!pam_file) { g_warning("Could not open common-passwd.\n"); return NULL; } while(fgets(buffer, 1024, pam_file)){ if(*buffer == '#') continue; if(strstr(buffer, "pam_cracklib.so") == NULL) continue; if(strstr(buffer, "\t") == NULL) { g_warning("请检查common-passwd文件是否配置正确,各个区块应以Tab键分隔"); continue; } gchar **tmp = g_strsplit(buffer, "\t", 4); gchar ***tmp_tmp = g_strsplit(tmp[3], " ", 10); for(int i = 0; i != 10; ++i){ if(tmp_tmp[i] != NULL) g_ptr_array_add (pam_conf, (gpointer)g_strdup(tmp_tmp[i])); else break; } g_strfreev(tmp_tmp); g_strfreev(tmp); } fclose(pam_file); return pam_conf; } //初始化密码复杂度的要求 void init_options(GPtrArray *pam_array, struct cracklib_options *opt) { for (int i=0; i != pam_array->len; ++i) { char *tmp = g_ptr_array_index(pam_array,i); if(!tmp) continue; char *ep = NULL; /* generic options */ if (!strncmp(tmp,"retry=",6)) { opt->retry_times = strtol(tmp+6,&ep,10); if (!ep || (opt->retry_times < 1)) opt->retry_times = CO_RETRY_TIMES; } else if (!strncmp(tmp,"difok=",6)) { opt->diff_ok = strtol(tmp+6,&ep,10); if (!ep || (opt->diff_ok < 0)) opt->diff_ok = CO_DIFF_OK; } else if (!strncmp(tmp,"difignore=",10)) { /* just ignore */ } else if (!strncmp(tmp,"minlen=",7)) { opt->min_length = strtol(tmp+7,&ep,10); if (!ep || (opt->min_length < CO_MIN_LENGTH_BASE)) opt->min_length = CO_MIN_LENGTH_BASE; } else if (!strncmp(tmp,"dcredit=",8)) { opt->dig_credit = strtol(tmp+8,&ep,10); if (!ep) opt->dig_credit = 0; } else if (!strncmp(tmp,"ucredit=",8)) { opt->up_credit = strtol(tmp+8,&ep,10); if (!ep) opt->up_credit = 0; } else if (!strncmp(tmp,"lcredit=",8)) { opt->low_credit = strtol(tmp+8,&ep,10); if (!ep) opt->low_credit = 0; } else if (!strncmp(tmp,"ocredit=",8)) { opt->oth_credit = strtol(tmp+8,&ep,10); if (!ep) opt->oth_credit = 0; } else if (!strncmp(tmp,"minclass=",9)) { opt->min_class = strtol(tmp+9,&ep,10); if (!ep) opt->min_class = 0; if (opt->min_class > 4) opt->min_class = 4; } else if (!strncmp(tmp,"maxrepeat=",10)) { opt->max_repeat = strtol(tmp+10,&ep,10); if (!ep) opt->max_repeat = 0; } else if (!strncmp(tmp,"maxsequence=",12)) { opt->max_sequence = strtol(tmp+12,&ep,10); if (!ep) opt->max_sequence = 0; } else if (!strncmp(tmp,"maxclassrepeat=",15)) { opt->max_class_repeat = strtol(tmp+15,&ep,10); if (!ep) opt->max_class_repeat = 0; } else if (!strncmp(tmp,"reject_username",15)) { opt->reject_user = 1; } else if (!strncmp(tmp,"gecoscheck",10)) { opt->gecos_check = 1; } else if (!strncmp(tmp,"enforce_for_root",16)) { opt->enforce_for_root = 1; } else if (!strncmp(tmp,"authtok_type",12)) { /* for pam_get_authtok, ignore */; } else if (!strncmp(tmp,"use_authtok",11)) { /* for pam_get_authtok, ignore */; } else if (!strncmp(tmp,"use_first_pass",14)) { /* for pam_get_authtok, ignore */; } else if (!strncmp(tmp,"try_first_pass",14)) { /* for pam_get_authtok, ignore */; } } //查看是否初始化成功 // g_warning("\n-------diff_ok = %d-------\n" // "-------dig_credit = %d-------\n" // "-------enforce_for_root = %d-------\n" // "-------gecos_check = %d-------\n" // "-------low_credit = %d-------\n" // "-------max_class_repeat = %d-------\n" // "-------max_repeat = %d-------\n" // "-------max_sequence = %d-------\n" // "-------min_class = %d-------\n" // "-------min_length = %d-------\n" // "-------oth_credit = %d-------\n" // "-------reject_user = %d-------\n" // "-------retry_times = %d-------\n" // "-------up_credit = %d-------\n", // opt->diff_ok, // opt->dig_credit, // opt->enforce_for_root, // opt->gecos_check, // opt->low_credit, // opt->max_class_repeat, // opt->max_repeat, // opt->max_sequence, // opt->min_class, // opt->min_length, // opt->oth_credit, // opt->reject_user, // opt->retry_times, // opt->up_credit); // else if (!strncmp(tmp,"dictpath=",9)) { // opt->cracklib_dictpath = tmp+9; // if (!*(opt->cracklib_dictpath)) { // opt->cracklib_dictpath = CRACKLIB_DICTS; // } // } // else { // pam_syslog(pamh,LOG_ERR,"pam_parse: unknown option; %s",tmp); // } // } // return ctrl; } const char *passwd_check(const char *old, const char *new, const char *user) { const char *msg = NULL; char *oldmono = NULL, *newmono, *wrapped = NULL; char *usermono = NULL; struct cracklib_options options; memset(&options, 0, sizeof(options)); options.retry_times = CO_RETRY_TIMES; options.diff_ok = CO_DIFF_OK; options.min_length = CO_MIN_LENGTH; options.dig_credit = CO_DIG_CREDIT; options.up_credit = CO_UP_CREDIT; options.low_credit = CO_LOW_CREDIT; options.oth_credit = CO_OTH_CREDIT; //从common-passwd文件中读取用户设置的密码复杂度要求 GPtrArray *pam_array = get_passwd_configuration(); init_options(pam_array, &options); g_ptr_array_free(pam_array, TRUE); struct cracklib_options *opt = &options; if (old && strcmp(old, "") != 0 && strcmp(new, old) == 0) { msg = _("is the same as the old one"); return msg; } newmono = str_lower(x_strdup(new)); if (!newmono) msg = _("memory allocation error"); usermono = str_lower(x_strdup(user)); if (!usermono) msg = _("memory allocation error"); if (!msg && old) { oldmono = str_lower(x_strdup(old)); if (oldmono) wrapped = malloc(strlen(oldmono) * 2 + 1); if (wrapped) { strcpy (wrapped, oldmono); strcat (wrapped, oldmono); } else { msg = _("memory allocation error"); } } if (!msg && strcmp(old, "") != 0 && strcmp(new, "") != 0 && palindrome(newmono)) msg = _("is a palindrome"); if (!msg && strcmp(old, "") != 0 && oldmono && strcmp(oldmono, newmono) == 0) msg = _("case changes only"); if (!msg && strcmp(old, "") != 0 && oldmono && similar(opt, oldmono, newmono)) msg = _("is too similar to the old one"); if (!msg && simple(opt, new)) msg = _("is too simple"); if (!msg && wrapped && strstr(wrapped, newmono)) msg = _("is rotated"); if (!msg && minclass (opt, new)) msg = _("not enough character classes"); if (!msg && consecutive(opt, new)) msg = _("contains too many same characters consecutively"); if (!msg && sequence(opt, new)) msg = _("contains too long of a monotonic character sequence"); if (!msg && (usercheck(opt, newmono, usermono))) //|| gecoscheck(pamh, opt, newmono, user))) msg = _("contains the user name in some form"); free(usermono); if (newmono) { memset(newmono, 0, strlen(newmono)); free(newmono); } if (oldmono) { memset(oldmono, 0, strlen(oldmono)); free(oldmono); } if (wrapped) { memset(wrapped, 0, strlen(wrapped)); free(wrapped); } return msg; } ukui-control-center/panels/user-accounts/run-passwd.c0000664000175000017500000007276413253611051021752 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* run-passwd.h: this file is part of users-admin, a gnome-system-tools frontend * for user administration. * * Copyright (C) 2010 Milan Bouchet-Valat * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * Authors: Milan Bouchet-Valat */ #include #include #include #include #include #include #include #include "run-passwd.h" /* Passwd states */ typedef enum { PASSWD_STATE_NONE, /* Passwd is not asking for anything */ PASSWD_STATE_AUTH, /* Passwd is asking for our current password */ PASSWD_STATE_NEW, /* Passwd is asking for our new password */ PASSWD_STATE_RETYPE, /* Passwd is asking for our retyped new password */ PASSWD_STATE_ERR /* Passwd reported an error but has not yet exited */ } PasswdState; struct PasswdHandler { // GtkBuilder *ui; const char *current_password; const char *new_password; const char *retyped_password; /* Communication with the passwd program */ GPid backend_pid; GIOChannel *backend_stdin; GIOChannel *backend_stdout; GQueue *backend_stdin_queue; /* Write queue to backend_stdin */ /* GMainLoop IDs */ guint backend_child_watch_id; /* g_child_watch_add (PID) */ guint backend_stdout_watch_id; /* g_io_add_watch (stdout) */ /* State of the passwd program */ PasswdState backend_state; gboolean changing_password; PasswdCallback auth_cb; gpointer auth_cb_data; PasswdCallback chpasswd_cb; gpointer chpasswd_cb_data; }; /* Buffer size for backend output */ #define BUFSIZE 64 static GQuark passwd_error_quark (void) { static GQuark q = 0; if (q == 0) { q = g_quark_from_static_string("passwd_error"); } return q; } /* Error handling */ #define PASSWD_ERROR (passwd_error_quark ()) static void stop_passwd (PasswdHandler *passwd_handler); static void free_passwd_resources (PasswdHandler *passwd_handler); static gboolean io_watch_stdout (GIOChannel *source, GIOCondition condition, PasswdHandler *passwd_handler); /* Child watcher */ static void child_watch_cb (GPid pid, gint status, PasswdHandler *passwd_handler) { if (WIFEXITED (status)) { if (WEXITSTATUS (status) >= 255) { g_warning ("Child exited unexpectedly"); } } free_passwd_resources (passwd_handler); } /* Write the first element of queue through channel */ static void io_queue_pop (GQueue *queue, GIOChannel *channel) { gchar *buf; gsize bytes_written; GError *error = NULL; buf = g_queue_pop_head (queue); if (buf != NULL) { if (g_io_channel_write_chars (channel, buf, -1, &bytes_written, &error) != G_IO_STATUS_NORMAL) { g_warning ("Could not write queue element \"%s\" to channel: %s", buf, error->message); g_error_free (error); } /* Ensure passwords are cleared from memory */ memset (buf, 0, strlen (buf)); g_free (buf); } } /* Goes through the argument list, checking if one of them occurs in str * Returns: TRUE as soon as an element is found to match, FALSE otherwise */ static gboolean is_string_complete (gchar *str, ...) { va_list ap; gchar *arg; if (strlen (str) == 0) { return FALSE; } va_start (ap, str); while ((arg = va_arg (ap, char *)) != NULL) { if (g_strrstr (str, arg) != NULL) { va_end (ap); return TRUE; } } va_end (ap); return FALSE; } /* * IO watcher for stdout, called whenever there is data to read from the backend. * This is where most of the actual IO handling happens. */ static gboolean io_watch_stdout (GIOChannel *source, GIOCondition condition, PasswdHandler *passwd_handler) { static GString *str = NULL; /* Persistent buffer */ gchar buf[BUFSIZE]; /* Temporary buffer */ gsize bytes_read; GError *gio_error = NULL; /* Error returned by functions */ GError *error = NULL; /* Error sent to callbacks */ //GtkBuilder *dialog; gboolean reinit = FALSE; /* Initialize buffer */ if (str == NULL) { str = g_string_new (""); } //dialog = passwd_handler->ui; if (g_io_channel_read_chars (source, buf, BUFSIZE, &bytes_read, &gio_error) != G_IO_STATUS_NORMAL) { g_warning ("IO Channel read error: %s", gio_error->message); g_error_free (gio_error); return TRUE; } str = g_string_append_len (str, buf, bytes_read); /* In which state is the backend? */ switch (passwd_handler->backend_state) { case PASSWD_STATE_AUTH: /* Passwd is asking for our current password */ if (is_string_complete (str->str, "assword: ", "failure", "wrong", "error", NULL)) { if (g_strrstr (str->str, "assword: ") != NULL) { /* Authentication successful */ passwd_handler->backend_state = PASSWD_STATE_NEW; /* Trigger callback to update authentication status */ if (passwd_handler->auth_cb) passwd_handler->auth_cb (passwd_handler, NULL, passwd_handler->auth_cb_data); } else { /* Authentication failed */ error = g_error_new_literal (PASSWD_ERROR, PASSWD_ERROR_AUTH_FAILED, _("Authentication failure!")); passwd_handler->changing_password = FALSE; /* This error can happen both while authenticating or while changing password: * if chpasswd_cb is set, this means we're already changing password */ if (passwd_handler->chpasswd_cb) passwd_handler->chpasswd_cb (passwd_handler, error, passwd_handler->auth_cb_data); else if (passwd_handler->auth_cb) passwd_handler->auth_cb (passwd_handler, error, passwd_handler->auth_cb_data); g_error_free (error); } reinit = TRUE; } break; case PASSWD_STATE_NEW: /* Passwd is asking for our new password */ if (is_string_complete (str->str, "assword: ", NULL)) { /* Advance to next state */ passwd_handler->backend_state = PASSWD_STATE_RETYPE; /* Pop retyped password from queue and into IO channel */ io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin); reinit = TRUE; } break; case PASSWD_STATE_RETYPE: /* Passwd is asking for our retyped new password */ if (is_string_complete (str->str, "successfully", "short", "longer", "palindrome", "dictionary", "simple", "simplistic", "similar", "different", "case", "wrapped", "recovered", "recent", "unchanged", "match", "1 numeric or special", "failure", NULL)) { if (g_strrstr (str->str, "successfully") != NULL) { /* Hooray! */ /* Trigger callback to update status */ if (passwd_handler->chpasswd_cb) passwd_handler->chpasswd_cb (passwd_handler, NULL, passwd_handler->chpasswd_cb_data); } else { /* Ohnoes! */ if (g_strrstr (str->str, "recovered") != NULL) { /* What does this indicate? * "Authentication information cannot be recovered?" from libpam? */ error = g_error_new_literal (PASSWD_ERROR, PASSWD_ERROR_UNKNOWN, str->str); } else if (g_strrstr (str->str, "short") != NULL || g_strrstr (str->str, "longer") != NULL) { error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, _("New password length is too short!")); } else if (g_strrstr (str->str, "palindrome") != NULL || g_strrstr (str->str, "simple") != NULL || g_strrstr (str->str, "simplistic") != NULL || g_strrstr (str->str, "dictionary") != NULL) { error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, _("The new password is too simple!")); } else if (g_strrstr (str->str, "similar") != NULL || g_strrstr (str->str, "different") != NULL || g_strrstr (str->str, "case") != NULL || g_strrstr (str->str, "wrapped") != NULL) { error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, _("The new password is too similar to the old one!")); } else if (g_strrstr (str->str, "1 numeric or special") != NULL) { error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, _("The new password must contain numbers or special characters!")); } else if (g_strrstr (str->str, "unchanged") != NULL || g_strrstr (str->str, "match") != NULL) { error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, _("The new password is the same as the old one!")); } else if (g_strrstr (str->str, "recent") != NULL) { error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, _("The new password has been used recently!")); } else if (g_strrstr (str->str, "failure") != NULL) { /* Authentication failure */ error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_AUTH_FAILED, _("Your password has been changed after you verify!")); } else { error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_UNKNOWN, "Unknown error"); } /* At this point, passwd might have exited, in which case * child_watch_cb should clean up for us and remove this watcher. * On some error conditions though, passwd just re-prompts us * for our new password. */ passwd_handler->backend_state = PASSWD_STATE_ERR; passwd_handler->changing_password = FALSE; /* Trigger callback to update status */ if (passwd_handler->chpasswd_cb) passwd_handler->chpasswd_cb (passwd_handler, error, passwd_handler->chpasswd_cb_data); g_error_free (error); } reinit = TRUE; /* child_watch_cb should clean up for us now */ } break; case PASSWD_STATE_NONE: /* Passwd is not asking for anything yet */ if (is_string_complete (str->str, "assword: ", NULL)) { /* If the user does not have a password set, * passwd will immediately ask for the new password, * so skip the AUTH phase */ if (is_string_complete (str->str, "new", "New", NULL)) { gchar *pw; passwd_handler->backend_state = PASSWD_STATE_NEW; /* since passwd didn't ask for our old password * in this case, simply remove it from the queue */ pw = g_queue_pop_head (passwd_handler->backend_stdin_queue); g_free (pw); /* Pop the IO queue, i.e. send new password */ io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin); } else { passwd_handler->backend_state = PASSWD_STATE_AUTH; /* Pop the IO queue, i.e. send current password */ io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin); } reinit = TRUE; } break; default: /* Passwd has returned an error */ reinit = TRUE; break; } if (reinit) { g_string_free (str, TRUE); str = NULL; } /* Continue calling us */ return TRUE; } static void free_passwd_resources (PasswdHandler *passwd_handler) { GError *error = NULL; /* Remove the child watcher */ if (passwd_handler->backend_child_watch_id != 0) { g_source_remove (passwd_handler->backend_child_watch_id); passwd_handler->backend_child_watch_id = 0; } /* Close IO channels (internal file descriptors are automatically closed) */ if (passwd_handler->backend_stdin != NULL) { if (g_io_channel_shutdown (passwd_handler->backend_stdin, TRUE, &error) != G_IO_STATUS_NORMAL) { g_warning ("Could not shutdown backend_stdin IO channel: %s", error->message); g_error_free (error); error = NULL; } g_io_channel_unref (passwd_handler->backend_stdin); passwd_handler->backend_stdin = NULL; } if (passwd_handler->backend_stdout != NULL) { if (g_io_channel_shutdown (passwd_handler->backend_stdout, TRUE, &error) != G_IO_STATUS_NORMAL) { g_warning ("Could not shutdown backend_stdout IO channel: %s", error->message); g_error_free (error); error = NULL; } g_io_channel_unref (passwd_handler->backend_stdout); passwd_handler->backend_stdout = NULL; } /* Remove IO watcher */ if (passwd_handler->backend_stdout_watch_id != 0) { g_source_remove (passwd_handler->backend_stdout_watch_id); passwd_handler->backend_stdout_watch_id = 0; } /* Close PID */ if (passwd_handler->backend_pid != -1) { g_spawn_close_pid (passwd_handler->backend_pid); passwd_handler->backend_pid = -1; } /* Clear backend state */ passwd_handler->backend_state = PASSWD_STATE_NONE; } /* Adds the current password to the IO queue */ static void authenticate (PasswdHandler *passwd_handler) { gchar *s; s = g_strdup_printf ("%s\n", passwd_handler->current_password); g_queue_push_tail (passwd_handler->backend_stdin_queue, s); } /* Adds the new password twice to the IO queue */ static void update_password (PasswdHandler *passwd_handler) { gchar *s; s = g_strdup_printf ("%s\n", passwd_handler->new_password); g_queue_push_tail (passwd_handler->backend_stdin_queue, s); /* We need to allocate new space because io_queue_pop() g_free()s * every element of the queue after it's done */ g_queue_push_tail (passwd_handler->backend_stdin_queue, g_strdup (s)); } /* Spawn passwd backend * Returns: TRUE on success, FALSE otherwise and sets error appropriately */ static gboolean spawn_passwd (PasswdHandler *passwd_handler, GError **error) { gchar *argv[2]; gchar *envp[1]; gint my_stdin, my_stdout, my_stderr; argv[0] = "/usr/bin/passwd"; /* Is it safe to rely on a hard-coded path? */ argv[1] = NULL; envp[0] = NULL; /* If we pass an empty array as the environment, * will the childs environment be empty, and the * locales set to the C default? From the manual: * "If envp is NULL, the child inherits its * parent'senvironment." * If I'm wrong here, we somehow have to set * the locales here. */ if (!g_spawn_async_with_pipes (NULL, /* Working directory */ argv, /* Argument vector */ envp, /* Environment */ G_SPAWN_DO_NOT_REAP_CHILD, /* Flags */ NULL, /* Child setup */ NULL, /* Data to child setup */ &passwd_handler->backend_pid, /* PID */ &my_stdin, /* Stdin */ &my_stdout, /* Stdout */ &my_stderr, /* Stderr */ error)) { /* GError */ /* An error occurred */ free_passwd_resources (passwd_handler); return FALSE; } /* 2>&1 */ if (dup2 (my_stderr, my_stdout) == -1) { /* Failed! */ g_set_error_literal (error, PASSWD_ERROR, PASSWD_ERROR_BACKEND, strerror (errno)); /* Clean up */ stop_passwd (passwd_handler); return FALSE; } /* Open IO Channels */ passwd_handler->backend_stdin = g_io_channel_unix_new (my_stdin); passwd_handler->backend_stdout = g_io_channel_unix_new (my_stdout); /* Set raw encoding */ /* Set nonblocking mode */ if (g_io_channel_set_encoding (passwd_handler->backend_stdin, NULL, error) != G_IO_STATUS_NORMAL || g_io_channel_set_encoding (passwd_handler->backend_stdout, NULL, error) != G_IO_STATUS_NORMAL || g_io_channel_set_flags (passwd_handler->backend_stdin, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL || g_io_channel_set_flags (passwd_handler->backend_stdout, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ) { /* Clean up */ stop_passwd (passwd_handler); return FALSE; } /* Turn off buffering */ g_io_channel_set_buffered (passwd_handler->backend_stdin, FALSE); g_io_channel_set_buffered (passwd_handler->backend_stdout, FALSE); /* Add IO Channel watcher */ passwd_handler->backend_stdout_watch_id = g_io_add_watch (passwd_handler->backend_stdout, G_IO_IN | G_IO_PRI, (GIOFunc) io_watch_stdout, passwd_handler); /* Add child watcher */ passwd_handler->backend_child_watch_id = g_child_watch_add (passwd_handler->backend_pid, (GChildWatchFunc) child_watch_cb, passwd_handler); /* Success! */ return TRUE; } /* Stop passwd backend */ static void stop_passwd (PasswdHandler *passwd_handler) { /* This is the standard way of returning from the dialog with passwd. * If we return this way we can safely kill passwd as it has completed * its task. */ if (passwd_handler->backend_pid != -1) { kill (passwd_handler->backend_pid, 9); } /* We must run free_passwd_resources here and not let our child * watcher do it, since it will access invalid memory after the * dialog has been closed and cleaned up. * * If we had more than a single thread we'd need to remove * the child watch before trying to kill the child. */ free_passwd_resources (passwd_handler); } PasswdHandler * passwd_init () { PasswdHandler *passwd_handler; passwd_handler = g_new0 (PasswdHandler, 1); /* Initialize backend_pid. -1 means the backend is not running */ passwd_handler->backend_pid = -1; /* Initialize IO Channels */ passwd_handler->backend_stdin = NULL; passwd_handler->backend_stdout = NULL; /* Initialize write queue */ passwd_handler->backend_stdin_queue = g_queue_new (); /* Initialize watchers */ passwd_handler->backend_child_watch_id = 0; passwd_handler->backend_stdout_watch_id = 0; /* Initialize backend state */ passwd_handler->backend_state = PASSWD_STATE_NONE; passwd_handler->changing_password = FALSE; return passwd_handler; } void passwd_authenticate (PasswdHandler *passwd_handler, const char *current_password, PasswdCallback cb, const gpointer user_data) { GError *error = NULL; /* Don't stop if we've already started chaging password */ if (passwd_handler->changing_password) return; /* Clear data from possible previous attempts to change password */ passwd_handler->new_password = NULL; passwd_handler->chpasswd_cb = NULL; passwd_handler->chpasswd_cb_data = NULL; g_queue_foreach (passwd_handler->backend_stdin_queue, (GFunc) g_free, NULL); g_queue_clear (passwd_handler->backend_stdin_queue); passwd_handler->current_password = current_password; passwd_handler->auth_cb = cb; passwd_handler->auth_cb_data = user_data; /* Spawn backend */ stop_passwd (passwd_handler); if (!spawn_passwd (passwd_handler, &error)) { g_warning ("%s", error->message); g_error_free (error); return; } authenticate (passwd_handler); /* Our IO watcher should now handle the rest */ } void passwd_destroy (PasswdHandler *passwd_handler) { g_queue_free (passwd_handler->backend_stdin_queue); stop_passwd (passwd_handler); g_free (passwd_handler); } gboolean passwd_change_password (PasswdHandler *passwd_handler, const char *new_password, PasswdCallback cb, const gpointer user_data) { GError *error = NULL; passwd_handler->changing_password = TRUE; passwd_handler->new_password = new_password; passwd_handler->chpasswd_cb = cb; passwd_handler->chpasswd_cb_data = user_data; /* Stop passwd if an error occurred and it is still running */ if (passwd_handler->backend_state == PASSWD_STATE_ERR) { /* Stop passwd, free resources */ stop_passwd (passwd_handler); } /* Check that the backend is still running, or that an error * has occurred but it has not yet exited */ if (passwd_handler->backend_pid == -1) { /* If it is not, re-run authentication */ /* Spawn backend */ stop_passwd (passwd_handler); if (!spawn_passwd (passwd_handler, &error)) { g_warning ("%s", error->message); g_error_free (error); return FALSE; } /* Add current and new passwords to queue */ authenticate (passwd_handler); update_password (passwd_handler); } else { /* Only add new passwords to queue */ update_password (passwd_handler); } /* Pop new password through the backend. If user has no password, popping the queue would output current password, while 'passwd' is waiting for the new one. So wait for io_watch_stdout() to remove current password from the queue, and output the new one for us.*/ if (passwd_handler->current_password) { io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin); } /* Our IO watcher should now handle the rest */ return TRUE; } ukui-control-center/panels/user-accounts/run-passwd.h0000664000175000017500000000436313057175444021762 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* run-passwd.h: this file is part of users-admin, a gnome-system-tools frontend * for user administration. * * Copyright (C) 2010 Milan Bouchet-Valat * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * Authors: Milan Bouchet-Valat */ #ifndef _RUN_PASSWD_H #define _RUN_PASSWD_H struct PasswdHandler; typedef struct PasswdHandler PasswdHandler; typedef void (*PasswdCallback) (PasswdHandler *passwd_handler, GError *error, const gpointer user_data); /* Error codes */ typedef enum { PASSWD_ERROR_REJECTED, /* New password is not secure enough */ PASSWD_ERROR_AUTH_FAILED, /* Wrong old password, or PAM failure */ PASSWD_ERROR_REAUTH_FAILED, /* Password has changed since first authentication */ PASSWD_ERROR_BACKEND, /* Backend error */ PASSWD_ERROR_UNKNOWN /* General error */ } PasswdError; PasswdHandler *passwd_init (); void passwd_destroy (PasswdHandler *passwd_handler); void passwd_authenticate (PasswdHandler *passwd_handler, const char *current_password, PasswdCallback cb, gpointer user_data); gboolean passwd_change_password (PasswdHandler *passwd_handler, const char *new_password, PasswdCallback cb, const gpointer user_data); #endif /* _RUN_PASSWD_H */ ukui-control-center/panels/user-accounts/change-name.ui0000664000175000017500000002376013245450076022206 0ustar fengfeng 465 295 False 5 Change Name True dialog True True True False vertical 2 True False end Cancel True True True False False 0 Ok True True True False False 1 False False 10 end 0 True False vertical 15 True False 8 90 80 True False gtk-missing-image False False 10 0 233 True False vertical True True False label False True 0 True False label False True 1 True False label False True 2 True True 1 True True 0 50 True False none True False 315 True False vertical True True False False True True 0 True False True True 1 10 True True 1 True True 1 buttoncancel buttonok ukui-control-center/panels/display/0000775000175000017500000000000013263647163016353 5ustar fengfengukui-control-center/panels/display/scrollarea.c0000664000175000017500000011526613057175444020660 0ustar fengfeng/* Copyright 2006, 2007, 2008, Soren Sandmann * Copyright (C) 2016,Tianjin KYLIN Information Technology Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include /* For GDK_PARENT_RELATIVE_BG */ #include "scrollarea.h" #include "foo-marshal.h" G_DEFINE_TYPE_WITH_CODE (FooScrollArea, foo_scroll_area, GTK_TYPE_CONTAINER, G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL)); static GtkWidgetClass *parent_class; typedef struct BackingStore BackingStore; typedef void (* ExposeFunc) (cairo_t *cr, cairo_region_t *region, gpointer data); typedef struct InputPath InputPath; typedef struct InputRegion InputRegion; typedef struct AutoScrollInfo AutoScrollInfo; struct InputPath { gboolean is_stroke; cairo_fill_rule_t fill_rule; double line_width; cairo_path_t *path; /* In canvas coordinates */ FooScrollAreaEventFunc func; gpointer data; InputPath *next; }; /* InputRegions are mutually disjoint */ struct InputRegion { cairo_region_t *region; /* the boundary of this area in canvas coordinates */ InputPath *paths; }; struct AutoScrollInfo { int dx; int dy; int timeout_id; int begin_x; int begin_y; double res_x; double res_y; GTimer *timer; }; struct FooScrollAreaPrivate { GdkWindow *input_window; int width; int height; GtkAdjustment *hadj; GtkAdjustment *vadj; GtkScrollablePolicy hscroll_policy; GtkScrollablePolicy vscroll_policy; int x_offset; int y_offset; int min_width; int min_height; GPtrArray *input_regions; AutoScrollInfo *auto_scroll_info; InputRegion *current_input; gboolean grabbed; FooScrollAreaEventFunc grab_func; gpointer grab_data; cairo_surface_t *surface; cairo_region_t *update_region; /* In canvas coordinates */ }; enum { VIEWPORT_CHANGED, PAINT, INPUT, LAST_SIGNAL, }; enum { PROP_0, PROP_VADJUSTMENT, PROP_HADJUSTMENT, PROP_HSCROLL_POLICY, PROP_VSCROLL_POLICY }; static guint signals [LAST_SIGNAL] = { 0 }; static void foo_scroll_area_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural); static void foo_scroll_area_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural); static gboolean foo_scroll_area_draw (GtkWidget *widget, cairo_t *cr); static void foo_scroll_area_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static void foo_scroll_area_set_hadjustment (FooScrollArea *scroll_area, GtkAdjustment *hadjustment); static void foo_scroll_area_set_vadjustment (FooScrollArea *scroll_area, GtkAdjustment *vadjustment); static void foo_scroll_area_realize (GtkWidget *widget); static void foo_scroll_area_unrealize (GtkWidget *widget); static void foo_scroll_area_map (GtkWidget *widget); static void foo_scroll_area_unmap (GtkWidget *widget); static gboolean foo_scroll_area_button_press (GtkWidget *widget, GdkEventButton *event); static gboolean foo_scroll_area_button_release (GtkWidget *widget, GdkEventButton *event); static gboolean foo_scroll_area_motion (GtkWidget *widget, GdkEventMotion *event); static void foo_scroll_area_map (GtkWidget *widget) { FooScrollArea *area = FOO_SCROLL_AREA (widget); GTK_WIDGET_CLASS (parent_class)->map (widget); if (area->priv->input_window) gdk_window_show (area->priv->input_window); } static void foo_scroll_area_unmap (GtkWidget *widget) { FooScrollArea *area = FOO_SCROLL_AREA (widget); if (area->priv->input_window) gdk_window_hide (area->priv->input_window); GTK_WIDGET_CLASS (parent_class)->unmap (widget); } static void foo_scroll_area_finalize (GObject *object) { FooScrollArea *scroll_area = FOO_SCROLL_AREA (object); g_object_unref (scroll_area->priv->hadj); g_object_unref (scroll_area->priv->vadj); g_ptr_array_free (scroll_area->priv->input_regions, TRUE); g_free (scroll_area->priv); G_OBJECT_CLASS (foo_scroll_area_parent_class)->finalize (object); } static void foo_scroll_area_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { FooScrollArea *scroll_area = FOO_SCROLL_AREA (object); switch (property_id) { case PROP_VADJUSTMENT: g_value_set_object (value, &scroll_area->priv->vadj); break; case PROP_HADJUSTMENT: g_value_set_object (value, &scroll_area->priv->hadj); break; case PROP_HSCROLL_POLICY: g_value_set_enum (value, scroll_area->priv->hscroll_policy); break; case PROP_VSCROLL_POLICY: g_value_set_enum (value, scroll_area->priv->vscroll_policy); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void foo_scroll_area_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { FooScrollArea *scroll_area = FOO_SCROLL_AREA (object); switch (property_id) { case PROP_VADJUSTMENT: foo_scroll_area_set_vadjustment (FOO_SCROLL_AREA (object), g_value_get_object (value)); break; case PROP_HADJUSTMENT: foo_scroll_area_set_hadjustment (FOO_SCROLL_AREA (object), g_value_get_object (value)); break; case PROP_HSCROLL_POLICY: scroll_area->priv->hscroll_policy = g_value_get_enum (value); break; case PROP_VSCROLL_POLICY: scroll_area->priv->vscroll_policy = g_value_get_enum (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void foo_scroll_area_class_init (FooScrollAreaClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); object_class->finalize = foo_scroll_area_finalize; object_class->set_property = foo_scroll_area_set_property; object_class->get_property = foo_scroll_area_get_property; widget_class->draw = foo_scroll_area_draw; widget_class->get_preferred_width = foo_scroll_area_get_preferred_width; widget_class->get_preferred_height = foo_scroll_area_get_preferred_height; widget_class->size_allocate = foo_scroll_area_size_allocate; widget_class->realize = foo_scroll_area_realize; widget_class->unrealize = foo_scroll_area_unrealize; widget_class->button_press_event = foo_scroll_area_button_press; widget_class->button_release_event = foo_scroll_area_button_release; widget_class->motion_notify_event = foo_scroll_area_motion; widget_class->map = foo_scroll_area_map; widget_class->unmap = foo_scroll_area_unmap; parent_class = g_type_class_peek_parent (class); /* Scrollable interface properties */ g_object_class_override_property (object_class, PROP_HADJUSTMENT, "hadjustment"); g_object_class_override_property (object_class, PROP_VADJUSTMENT, "vadjustment"); g_object_class_override_property (object_class, PROP_HSCROLL_POLICY, "hscroll-policy"); g_object_class_override_property (object_class, PROP_VSCROLL_POLICY, "vscroll-policy"); signals[VIEWPORT_CHANGED] = g_signal_new ("viewport_changed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (FooScrollAreaClass, viewport_changed), NULL, NULL, foo_marshal_VOID__BOXED_BOXED, G_TYPE_NONE, 2, GDK_TYPE_RECTANGLE, GDK_TYPE_RECTANGLE); signals[PAINT] = g_signal_new ("paint", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (FooScrollAreaClass, paint), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); } static GtkAdjustment * new_adjustment (void) { return GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); } static void foo_scroll_area_init (FooScrollArea *scroll_area) { GtkWidget *widget; widget = GTK_WIDGET (scroll_area); gtk_widget_set_has_window (widget, FALSE); gtk_widget_set_redraw_on_allocate (widget, FALSE); scroll_area->priv = g_new0 (FooScrollAreaPrivate, 1); scroll_area->priv->width = 0; scroll_area->priv->height = 0; scroll_area->priv->hadj = g_object_ref_sink (new_adjustment()); scroll_area->priv->vadj = g_object_ref_sink (new_adjustment()); scroll_area->priv->x_offset = 0.0; scroll_area->priv->y_offset = 0.0; scroll_area->priv->min_width = 0; scroll_area->priv->min_height = 0; scroll_area->priv->auto_scroll_info = NULL; scroll_area->priv->input_regions = g_ptr_array_new (); scroll_area->priv->surface = NULL; scroll_area->priv->update_region = cairo_region_create (); } typedef void (* PathForeachFunc) (double *x, double *y, gpointer data); static void path_foreach_point (cairo_path_t *path, PathForeachFunc func, gpointer user_data) { int i; for (i = 0; i < path->num_data; i += path->data[i].header.length) { cairo_path_data_t *data = &(path->data[i]); switch (data->header.type) { case CAIRO_PATH_MOVE_TO: case CAIRO_PATH_LINE_TO: func (&(data[1].point.x), &(data[1].point.y), user_data); break; case CAIRO_PATH_CURVE_TO: func (&(data[1].point.x), &(data[1].point.y), user_data); func (&(data[2].point.x), &(data[2].point.y), user_data); func (&(data[3].point.x), &(data[3].point.y), user_data); break; case CAIRO_PATH_CLOSE_PATH: break; } } } typedef struct { double x1, y1, x2, y2; } Box; static void input_path_free_list (InputPath *paths) { if (!paths) return; input_path_free_list (paths->next); cairo_path_destroy (paths->path); g_free (paths); } static void input_region_free (InputRegion *region) { input_path_free_list (region->paths); cairo_region_destroy (region->region); g_free (region); } static void get_viewport (FooScrollArea *scroll_area, GdkRectangle *viewport) { GtkAllocation allocation; GtkWidget *widget = GTK_WIDGET (scroll_area); gtk_widget_get_allocation (widget, &allocation); viewport->x = scroll_area->priv->x_offset; viewport->y = scroll_area->priv->y_offset; viewport->width = allocation.width; viewport->height = allocation.height; } static void allocation_to_canvas (FooScrollArea *area, int *x, int *y) { *x += area->priv->x_offset; *y += area->priv->y_offset; } static void clear_exposed_input_region (FooScrollArea *area, cairo_region_t *exposed) /* in canvas coordinates */ { int i; cairo_region_t *viewport; GdkRectangle allocation; gtk_widget_get_allocation (GTK_WIDGET (area), &allocation); allocation.x = 0; allocation.y = 0; allocation_to_canvas (area, &allocation.x, &allocation.y); viewport = cairo_region_create_rectangle (&allocation); cairo_region_subtract (viewport, exposed); for (i = 0; i < area->priv->input_regions->len; ++i) { InputRegion *region = area->priv->input_regions->pdata[i]; cairo_region_intersect (region->region, viewport); if (cairo_region_is_empty (region->region)) { input_region_free (region); g_ptr_array_remove_index_fast (area->priv->input_regions, i--); } } cairo_region_destroy (viewport); } static void setup_background_cr (GdkWindow *window, cairo_t *cr, int x_offset, int y_offset) { GdkWindow *parent = gdk_window_get_parent (window); cairo_pattern_t *bg_pattern; bg_pattern = gdk_window_get_background_pattern (window); if (bg_pattern == NULL && parent) { gint window_x, window_y; gdk_window_get_position (window, &window_x, &window_y); setup_background_cr (parent, cr, x_offset + window_x, y_offset + window_y); } else if (bg_pattern) { cairo_translate (cr, - x_offset, - y_offset); cairo_set_source (cr, bg_pattern); cairo_translate (cr, x_offset, y_offset); } } static void initialize_background (GtkWidget *widget, cairo_t *cr) { setup_background_cr (gtk_widget_get_window (widget), cr, 0, 0); cairo_paint (cr); } static gboolean foo_scroll_area_draw (GtkWidget *widget, cairo_t *widget_cr) { FooScrollArea *scroll_area = FOO_SCROLL_AREA (widget); cairo_t *cr; cairo_region_t *region; GtkAllocation widget_allocation; /* Setup input areas */ clear_exposed_input_region (scroll_area, scroll_area->priv->update_region); scroll_area->priv->current_input = g_new0 (InputRegion, 1); scroll_area->priv->current_input->region = cairo_region_copy (scroll_area->priv->update_region); scroll_area->priv->current_input->paths = NULL; g_ptr_array_add (scroll_area->priv->input_regions, scroll_area->priv->current_input); region = scroll_area->priv->update_region; scroll_area->priv->update_region = cairo_region_create (); /* Create cairo context */ cr = cairo_create (scroll_area->priv->surface); initialize_background (widget, cr); g_signal_emit (widget, signals[PAINT], 0, cr); /* Destroy stuff */ cairo_destroy (cr); scroll_area->priv->current_input = NULL; /* Finally draw the backing pixmap */ cairo_set_source_surface (widget_cr, scroll_area->priv->surface, widget_allocation.x, widget_allocation.y); cairo_paint (widget_cr); cairo_region_destroy (region); return TRUE; } void foo_scroll_area_get_viewport (FooScrollArea *scroll_area, GdkRectangle *viewport) { g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area)); if (!viewport) return; get_viewport (scroll_area, viewport); } static void process_event (FooScrollArea *scroll_area, FooScrollAreaEventType input_type, int x, int y); static void emit_viewport_changed (FooScrollArea *scroll_area, GdkRectangle *new_viewport, GdkRectangle *old_viewport) { int px, py; g_signal_emit (scroll_area, signals[VIEWPORT_CHANGED], 0, new_viewport, old_viewport); if (scroll_area->priv->input_window == NULL) return; gdk_window_get_pointer (scroll_area->priv->input_window, &px, &py, NULL); process_event (scroll_area, FOO_MOTION, px, py); } static void clamp_adjustment (GtkAdjustment *adj) { if (gtk_adjustment_get_upper (adj) >= gtk_adjustment_get_page_size (adj)) gtk_adjustment_set_value (adj, CLAMP (gtk_adjustment_get_value (adj), 0.0, gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj))); else gtk_adjustment_set_value (adj, 0.0); gtk_adjustment_changed (adj); } static gboolean set_adjustment_values (FooScrollArea *scroll_area) { GtkAllocation allocation; GtkAdjustment *hadj = scroll_area->priv->hadj; GtkAdjustment *vadj = scroll_area->priv->vadj; /* Horizontal */ gtk_widget_get_allocation (GTK_WIDGET (scroll_area), &allocation); g_object_freeze_notify (G_OBJECT (hadj)); gtk_adjustment_set_page_size (hadj, allocation.width); gtk_adjustment_set_step_increment (hadj, 0.1 * allocation.width); gtk_adjustment_set_page_increment (hadj, 0.9 * allocation.width); gtk_adjustment_set_lower (hadj, 0.0); gtk_adjustment_set_upper (hadj, scroll_area->priv->width); g_object_thaw_notify (G_OBJECT (hadj)); /* Vertical */ g_object_freeze_notify (G_OBJECT (vadj)); gtk_adjustment_set_page_size (vadj, allocation.height); gtk_adjustment_set_step_increment (vadj, 0.1 * allocation.height); gtk_adjustment_set_page_increment (vadj, 0.9 * allocation.height); gtk_adjustment_set_lower (vadj, 0.0); gtk_adjustment_set_upper (vadj, scroll_area->priv->height); g_object_thaw_notify (G_OBJECT (vadj)); clamp_adjustment (hadj); clamp_adjustment (vadj); return TRUE; } static void foo_scroll_area_realize (GtkWidget *widget) { FooScrollArea *area = FOO_SCROLL_AREA (widget); GdkWindowAttr attributes; GtkAllocation widget_allocation; GdkWindow *window; gint attributes_mask; cairo_t *cr; gtk_widget_get_allocation (widget, &widget_allocation); gtk_widget_set_realized (widget, TRUE); attributes.window_type = GDK_WINDOW_CHILD; attributes.x = widget_allocation.x; attributes.y = widget_allocation.y; attributes.width = widget_allocation.width; attributes.height = widget_allocation.height; attributes.wclass = GDK_INPUT_ONLY; attributes.event_mask = gtk_widget_get_events (widget); attributes.event_mask |= (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); attributes_mask = GDK_WA_X | GDK_WA_Y; window = gtk_widget_get_parent_window (widget); gtk_widget_set_window (widget, window); g_object_ref (window); area->priv->input_window = gdk_window_new (window, &attributes, attributes_mask); cr = gdk_cairo_create (gtk_widget_get_window (widget)); area->priv->surface = cairo_surface_create_similar (cairo_get_target (cr), CAIRO_CONTENT_COLOR, widget_allocation.width, widget_allocation.height); cairo_destroy (cr); gdk_window_set_user_data (area->priv->input_window, area); gtk_widget_style_attach (widget); } static void foo_scroll_area_unrealize (GtkWidget *widget) { FooScrollArea *area = FOO_SCROLL_AREA (widget); if (area->priv->input_window) { gdk_window_set_user_data (area->priv->input_window, NULL); gdk_window_destroy (area->priv->input_window); area->priv->input_window = NULL; } GTK_WIDGET_CLASS (parent_class)->unrealize (widget); } static cairo_surface_t * create_new_surface (GtkWidget *widget, cairo_surface_t *old) { GtkAllocation widget_allocation; cairo_t *cr; cairo_surface_t *new; gtk_widget_get_allocation (widget, &widget_allocation); cr = gdk_cairo_create (gtk_widget_get_window (widget)); new = cairo_surface_create_similar (cairo_get_target (cr), CAIRO_CONTENT_COLOR, widget_allocation.width, widget_allocation.height); cairo_destroy (cr); /* Unfortunately we don't know in which direction we were resized, * so we just assume we were dragged from the south-east corner. * * Although, maybe we could get the root coordinates of the input-window? * That might just work, actually. We need to make sure marco uses * static gravity for the window before this will be useful. */ cr = cairo_create (new); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_surface (cr, old, 0, 0); cairo_paint (cr); cairo_destroy (cr); return new; } static void allocation_to_canvas_region (FooScrollArea *area, cairo_region_t *region) { cairo_region_translate (region, area->priv->x_offset, area->priv->y_offset); } static void _cairo_region_xor (cairo_region_t *dst, const cairo_region_t *src) { cairo_region_t *trb; trb = cairo_region_copy (src); cairo_region_subtract (trb, dst); cairo_region_subtract (dst, src); cairo_region_union (dst, trb); cairo_region_destroy (trb); } static void foo_scroll_area_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { FooScrollArea *scroll_area = FOO_SCROLL_AREA (widget); GdkRectangle new_viewport; GdkRectangle old_viewport; cairo_region_t *old_allocation; cairo_region_t *invalid; GtkAllocation widget_allocation; get_viewport (scroll_area, &old_viewport); gtk_widget_get_allocation (widget, &widget_allocation); old_allocation = cairo_region_create_rectangle (&widget_allocation); cairo_region_translate (old_allocation, -widget_allocation.x, -widget_allocation.y); invalid = cairo_region_create_rectangle (allocation); cairo_region_translate (invalid, -allocation->x, -allocation->y); _cairo_region_xor (invalid, old_allocation); allocation_to_canvas_region (scroll_area, invalid); foo_scroll_area_invalidate_region (scroll_area, invalid); cairo_region_destroy (old_allocation); cairo_region_destroy (invalid); gtk_widget_set_allocation (widget, allocation); if (scroll_area->priv->input_window) { cairo_surface_t *new_surface; gdk_window_move_resize (scroll_area->priv->input_window, allocation->x, allocation->y, allocation->width, allocation->height); new_surface = create_new_surface (widget, scroll_area->priv->surface); cairo_surface_destroy (scroll_area->priv->surface); scroll_area->priv->surface = new_surface; } get_viewport (scroll_area, &new_viewport); emit_viewport_changed (scroll_area, &new_viewport, &old_viewport); } static void emit_input (FooScrollArea *scroll_area, FooScrollAreaEventType type, int x, int y, FooScrollAreaEventFunc func, gpointer data) { FooScrollAreaEvent event; if (!func) return; if (type != FOO_MOTION) emit_input (scroll_area, FOO_MOTION, x, y, func, data); event.type = type; event.x = x; event.y = y; func (scroll_area, &event, data); } static void process_event (FooScrollArea *scroll_area, FooScrollAreaEventType input_type, int x, int y) { GtkWidget *widget = GTK_WIDGET (scroll_area); int i; allocation_to_canvas (scroll_area, &x, &y); if (scroll_area->priv->grabbed) { emit_input (scroll_area, input_type, x, y, scroll_area->priv->grab_func, scroll_area->priv->grab_data); return; } for (i = 0; i < scroll_area->priv->input_regions->len; ++i) { InputRegion *region = scroll_area->priv->input_regions->pdata[i]; if (cairo_region_contains_point (region->region, x, y)) { InputPath *path; path = region->paths; while (path) { cairo_t *cr; gboolean inside; cr = gdk_cairo_create (gtk_widget_get_window (widget)); cairo_set_fill_rule (cr, path->fill_rule); cairo_set_line_width (cr, path->line_width); cairo_append_path (cr, path->path); if (path->is_stroke) inside = cairo_in_stroke (cr, x, y); else inside = cairo_in_fill (cr, x, y); cairo_destroy (cr); if (inside) { emit_input (scroll_area, input_type, x, y, path->func, path->data); return; } path = path->next; } /* Since the regions are all disjoint, no other region * can match. Of course we could be clever and try and * sort the regions, but so far I have been unable to * make this loop show up on a profile. */ return; } } } static void process_gdk_event (FooScrollArea *scroll_area, int x, int y, GdkEvent *event) { FooScrollAreaEventType input_type; if (event->type == GDK_BUTTON_PRESS) input_type = FOO_BUTTON_PRESS; else if (event->type == GDK_BUTTON_RELEASE) input_type = FOO_BUTTON_RELEASE; else if (event->type == GDK_MOTION_NOTIFY) input_type = FOO_MOTION; else return; process_event (scroll_area, input_type, x, y); } static gboolean foo_scroll_area_button_press (GtkWidget *widget, GdkEventButton *event) { FooScrollArea *area = FOO_SCROLL_AREA (widget); process_gdk_event (area, event->x, event->y, (GdkEvent *)event); return TRUE; } static gboolean foo_scroll_area_button_release (GtkWidget *widget, GdkEventButton *event) { FooScrollArea *area = FOO_SCROLL_AREA (widget); process_gdk_event (area, event->x, event->y, (GdkEvent *)event); return FALSE; } static gboolean foo_scroll_area_motion (GtkWidget *widget, GdkEventMotion *event) { FooScrollArea *area = FOO_SCROLL_AREA (widget); process_gdk_event (area, event->x, event->y, (GdkEvent *)event); return TRUE; } void foo_scroll_area_set_size_fixed_y (FooScrollArea *scroll_area, int width, int height, int old_y, int new_y) { scroll_area->priv->width = width; scroll_area->priv->height = height; g_object_thaw_notify (G_OBJECT (scroll_area->priv->vadj)); gtk_adjustment_set_value (scroll_area->priv->vadj, new_y); set_adjustment_values (scroll_area); g_object_thaw_notify (G_OBJECT (scroll_area->priv->vadj)); } void foo_scroll_area_set_size (FooScrollArea *scroll_area, int width, int height) { g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area)); /* FIXME: Default scroll algorithm should probably be to * keep the same *area* outside the screen as before. * * For wrapper widgets that will do something roughly * right. For widgets that don't change size, it * will do the right thing. Except for idle-layouting * widgets. * * Maybe there should be some generic support for those * widgets. Can that even be done? * * Should we have a version of this function using * fixed points? */ scroll_area->priv->width = width; scroll_area->priv->height = height; set_adjustment_values (scroll_area); } static void foo_scroll_area_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural) { FooScrollArea *scroll_area = FOO_SCROLL_AREA (widget); if (minimum != NULL) { *minimum = scroll_area->priv->min_width; } if (natural != NULL) { *natural = scroll_area->priv->min_width; } } static void foo_scroll_area_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural) { FooScrollArea *scroll_area = FOO_SCROLL_AREA (widget); if (minimum != NULL) { *minimum = scroll_area->priv->min_height; } if (natural != NULL) { *natural = scroll_area->priv->min_height; } } static void foo_scroll_area_scroll (FooScrollArea *area, gint dx, gint dy) { GdkRectangle allocation; GdkRectangle src_area; GdkRectangle move_area; cairo_region_t *invalid_region; gtk_widget_get_allocation (GTK_WIDGET (area), &allocation); allocation.x = 0; allocation.y = 0; src_area = allocation; src_area.x -= dx; src_area.y -= dy; invalid_region = cairo_region_create_rectangle (&allocation); if (gdk_rectangle_intersect (&allocation, &src_area, &move_area)) { cairo_region_t *move_region; cairo_t *cr; cr = cairo_create (area->priv->surface); /* Cairo doesn't allow self-copies, so we do this little trick instead: * 1) Clip so the group size is small. * 2) Call push_group() which creates a temporary pixmap as a workaround */ gdk_cairo_rectangle (cr, &move_area); cairo_clip (cr); cairo_push_group (cr); cairo_set_source_surface (cr, area->priv->surface, dx, dy); gdk_cairo_rectangle (cr, &move_area); cairo_fill (cr); cairo_pop_group_to_source (cr); cairo_paint (cr); cairo_destroy (cr); gtk_widget_queue_draw (GTK_WIDGET (area)); move_region = cairo_region_create_rectangle (&move_area); cairo_region_translate (move_region, dx, dy); cairo_region_subtract (invalid_region, move_region); cairo_region_destroy (move_region); } allocation_to_canvas_region (area, invalid_region); foo_scroll_area_invalidate_region (area, invalid_region); cairo_region_destroy (invalid_region); } static void foo_scrollbar_adjustment_changed (GtkAdjustment *adj, FooScrollArea *scroll_area) { GtkWidget *widget = GTK_WIDGET (scroll_area); gint dx = 0; gint dy = 0; GdkRectangle old_viewport, new_viewport; get_viewport (scroll_area, &old_viewport); if (adj == scroll_area->priv->hadj) { /* FIXME: do we treat the offset as int or double, and, * if int, how do we round? */ dx = (int)gtk_adjustment_get_value (adj) - scroll_area->priv->x_offset; scroll_area->priv->x_offset = gtk_adjustment_get_value (adj); } else if (adj == scroll_area->priv->vadj) { dy = (int)gtk_adjustment_get_value (adj) - scroll_area->priv->y_offset; scroll_area->priv->y_offset = gtk_adjustment_get_value (adj); } else { g_assert_not_reached (); } if (gtk_widget_get_realized (widget)) { foo_scroll_area_scroll (scroll_area, -dx, -dy); } get_viewport (scroll_area, &new_viewport); emit_viewport_changed (scroll_area, &new_viewport, &old_viewport); } static void set_one_adjustment (FooScrollArea *scroll_area, GtkAdjustment *adjustment, GtkAdjustment **location) { g_return_if_fail (location != NULL); if (adjustment == *location) return; if (!adjustment) adjustment = new_adjustment (); g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); if (*location) { g_signal_handlers_disconnect_by_func ( *location, foo_scrollbar_adjustment_changed, scroll_area); g_object_unref (*location); } *location = adjustment; g_object_ref_sink (*location); g_signal_connect (*location, "value_changed", G_CALLBACK (foo_scrollbar_adjustment_changed), scroll_area); } static void foo_scroll_area_set_hadjustment (FooScrollArea *scroll_area, GtkAdjustment *hadjustment) { set_one_adjustment (scroll_area, hadjustment, &scroll_area->priv->hadj); set_adjustment_values (scroll_area); } static void foo_scroll_area_set_vadjustment (FooScrollArea *scroll_area, GtkAdjustment *vadjustment) { set_one_adjustment (scroll_area, vadjustment, &scroll_area->priv->vadj); set_adjustment_values (scroll_area); } FooScrollArea * foo_scroll_area_new (void) { return g_object_new (FOO_TYPE_SCROLL_AREA, NULL); } void foo_scroll_area_set_min_size (FooScrollArea *scroll_area, int min_width, int min_height) { scroll_area->priv->min_width = min_width; scroll_area->priv->min_height = min_height; /* FIXME: think through invalidation. * * Goals: - no repainting everything on size_allocate(), * - make sure input boxes are invalidated when * needed */ gtk_widget_queue_resize (GTK_WIDGET (scroll_area)); } static void user_to_device (double *x, double *y, gpointer data) { cairo_t *cr = data; cairo_user_to_device (cr, x, y); } static InputPath * make_path (FooScrollArea *area, cairo_t *cr, gboolean is_stroke, FooScrollAreaEventFunc func, gpointer data) { InputPath *path = g_new0 (InputPath, 1); path->is_stroke = is_stroke; path->fill_rule = cairo_get_fill_rule (cr); path->line_width = cairo_get_line_width (cr); path->path = cairo_copy_path (cr); path_foreach_point (path->path, user_to_device, cr); path->func = func; path->data = data; path->next = area->priv->current_input->paths; area->priv->current_input->paths = path; return path; } /* FIXME: we probably really want a * * foo_scroll_area_add_input_from_fill (area, cr, ...); * and * foo_scroll_area_add_input_from_stroke (area, cr, ...); * as well. */ void foo_scroll_area_add_input_from_fill (FooScrollArea *scroll_area, cairo_t *cr, FooScrollAreaEventFunc func, gpointer data) { g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area)); g_return_if_fail (cr != NULL); g_return_if_fail (scroll_area->priv->current_input); make_path (scroll_area, cr, FALSE, func, data); } void foo_scroll_area_add_input_from_stroke (FooScrollArea *scroll_area, cairo_t *cr, FooScrollAreaEventFunc func, gpointer data) { g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area)); g_return_if_fail (cr != NULL); g_return_if_fail (scroll_area->priv->current_input); make_path (scroll_area, cr, TRUE, func, data); } void foo_scroll_area_invalidate (FooScrollArea *scroll_area) { GtkAllocation allocation; GtkWidget *widget = GTK_WIDGET (scroll_area); gtk_widget_get_allocation (widget, &allocation); foo_scroll_area_invalidate_rect (scroll_area, scroll_area->priv->x_offset, scroll_area->priv->y_offset, allocation.width, allocation.height); } static void canvas_to_window (FooScrollArea *area, cairo_region_t *region) { GtkAllocation allocation; GtkWidget *widget = GTK_WIDGET (area); gtk_widget_get_allocation (widget, &allocation); cairo_region_translate (region, -area->priv->x_offset + allocation.x, -area->priv->y_offset + allocation.y); } static void window_to_canvas (FooScrollArea *area, cairo_region_t *region) { GtkAllocation allocation; GtkWidget *widget = GTK_WIDGET (area); gtk_widget_get_allocation (widget, &allocation); cairo_region_translate (region, area->priv->x_offset - allocation.x, area->priv->y_offset - allocation.y); } void foo_scroll_area_invalidate_region (FooScrollArea *area, cairo_region_t *region) { GtkWidget *widget; g_return_if_fail (FOO_IS_SCROLL_AREA (area)); widget = GTK_WIDGET (area); cairo_region_union (area->priv->update_region, region); if (gtk_widget_get_realized (widget)) { canvas_to_window (area, region); gdk_window_invalidate_region (gtk_widget_get_window (widget), region, TRUE); window_to_canvas (area, region); } } void foo_scroll_area_invalidate_rect (FooScrollArea *scroll_area, int x, int y, int width, int height) { GdkRectangle rect = { x, y, width, height }; cairo_region_t *region; g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area)); region = cairo_region_create_rectangle (&rect); foo_scroll_area_invalidate_region (scroll_area, region); cairo_region_destroy (region); } void foo_scroll_area_begin_grab (FooScrollArea *scroll_area, FooScrollAreaEventFunc func, gpointer input_data) { g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area)); g_return_if_fail (!scroll_area->priv->grabbed); scroll_area->priv->grabbed = TRUE; scroll_area->priv->grab_func = func; scroll_area->priv->grab_data = input_data; /* FIXME: we should probably take a server grab */ /* Also, maybe there should be support for setting the grab cursor */ } void foo_scroll_area_end_grab (FooScrollArea *scroll_area) { g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area)); scroll_area->priv->grabbed = FALSE; scroll_area->priv->grab_func = NULL; scroll_area->priv->grab_data = NULL; } gboolean foo_scroll_area_is_grabbed (FooScrollArea *scroll_area) { return scroll_area->priv->grabbed; } void foo_scroll_area_set_viewport_pos (FooScrollArea *scroll_area, int x, int y) { g_object_freeze_notify (G_OBJECT (scroll_area->priv->hadj)); g_object_freeze_notify (G_OBJECT (scroll_area->priv->vadj)); gtk_adjustment_set_value (scroll_area->priv->hadj, x); gtk_adjustment_set_value (scroll_area->priv->vadj, y); set_adjustment_values (scroll_area); g_object_thaw_notify (G_OBJECT (scroll_area->priv->hadj)); g_object_thaw_notify (G_OBJECT (scroll_area->priv->vadj)); } static gboolean rect_contains (const GdkRectangle *rect, int x, int y) { return (x >= rect->x && y >= rect->y && x < rect->x + rect->width && y < rect->y + rect->height); } static void stop_scrolling (FooScrollArea *area) { if (area->priv->auto_scroll_info) { g_source_remove (area->priv->auto_scroll_info->timeout_id); g_timer_destroy (area->priv->auto_scroll_info->timer); g_free (area->priv->auto_scroll_info); area->priv->auto_scroll_info = NULL; } } static gboolean scroll_idle (gpointer data) { GdkRectangle viewport, new_viewport; FooScrollArea *area = data; AutoScrollInfo *info = area->priv->auto_scroll_info; int new_x, new_y; double elapsed; get_viewport (area, &viewport); elapsed = g_timer_elapsed (info->timer, NULL); info->res_x = elapsed * info->dx / 0.2; info->res_y = elapsed * info->dy / 0.2; new_x = viewport.x + info->res_x; new_y = viewport.y + info->res_y; foo_scroll_area_set_viewport_pos (area, new_x, new_y); get_viewport (area, &new_viewport); if (viewport.x == new_viewport.x && viewport.y == new_viewport.y && (info->res_x > 1.0 || info->res_y > 1.0 || info->res_x < -1.0 || info->res_y < -1.0)) { stop_scrolling (area); /* stop scrolling if it didn't have an effect */ return FALSE; } return TRUE; } static void ensure_scrolling (FooScrollArea *area, int dx, int dy) { if (!area->priv->auto_scroll_info) { area->priv->auto_scroll_info = g_new0 (AutoScrollInfo, 1); area->priv->auto_scroll_info->timeout_id = g_idle_add (scroll_idle, area); area->priv->auto_scroll_info->timer = g_timer_new (); } area->priv->auto_scroll_info->dx = dx; area->priv->auto_scroll_info->dy = dy; } void foo_scroll_area_auto_scroll (FooScrollArea *scroll_area, FooScrollAreaEvent *event) { GdkRectangle viewport; get_viewport (scroll_area, &viewport); if (rect_contains (&viewport, event->x, event->y)) { stop_scrolling (scroll_area); } else { int dx, dy; dx = dy = 0; if (event->y < viewport.y) { dy = event->y - viewport.y; dy = MIN (dy + 2, 0); } else if (event->y >= viewport.y + viewport.height) { dy = event->y - (viewport.y + viewport.height - 1); dy = MAX (dy - 2, 0); } if (event->x < viewport.x) { dx = event->x - viewport.x; dx = MIN (dx + 2, 0); } else if (event->x >= viewport.x + viewport.width) { dx = event->x - (viewport.x + viewport.width - 1); dx = MAX (dx - 2, 0); } ensure_scrolling (scroll_area, dx, dy); } } void foo_scroll_area_begin_auto_scroll (FooScrollArea *scroll_area) { /* noop for now */ } void foo_scroll_area_end_auto_scroll (FooScrollArea *scroll_area) { stop_scrolling (scroll_area); } ukui-control-center/panels/display/Makefile.am0000664000175000017500000000264413253611037020403 0ustar fengfengcappletname=display_app noinst_LTLIBRARIES=libdisplayapp.la AUTOMAKE_OPTIONS=foreign #INCLUDES=`pkg-config --cflags gtk+-2.0 glib-2.0 dbus-glib-1 gio-2.0 ukui-settings-daemon mate-desktop-2.0` #LIBS=`pkg-config --libs gtk+-2.0 glib-2.0 dbus-glib-1 gio-2.0 ukui-settings-daemon mate-desktop-2.0` sbin_PROGRAMS = ukui-display-properties-install-systemwide ukui_display_properties_install_systemwide_SOURCES = \ ukui-display-properties-install-systemwide.c ukui_display_properties_install_systemwide_LDADD = \ $(GLIB_LIBS) polkit_policydir = $(datadir)/polkit-1/actions dist_polkit_policy_DATA = \ org.ukuicc.randr.policy @INTLTOOL_POLICY_RULE@ AM_CPPFLAGS = $(DISPLAY_CAPPLET_CFLAGS) \ $(MATECC_CAPPLETS_CFLAGS) \ -DSBINDIR="\"$(sbindir)\"" \ -DUIDIR="\"$(uidir)\"" \ -DMATELOCALEDIR="\"$(datadir)/locale\"" \ -DMATECC_DATA_DIR="\"$(pkgdatadir)\"" \ $(GTK_CFLAGS) \ $(GLIB_CFLAGS) \ $(DBUS_LIB_CFLAGS) \ $(UKUI_SD_CFLAGS) \ $(MATE_DESKTOP_CFLAGS) \ $(NULL) libdisplayapp_la_LIBADD = \ $(GTK_LIBS) \ $(GLIB_LIBS) \ $(DBUS_LIB_LIBS) \ $(UKUI_SD_LIBS) \ $(MATE_DESKTOP_LIBS) \ $(NULL) libdisplayapp_la_SOURCES=\ foo-marshal.c \ foo-marshal.h \ scrollarea.c \ scrollarea.h \ xrandr-capplet.c \ xrandr-capplet.h EXTRA_DIST = org.ukuicc.randr.policy.in DISTCLEANFILES = org.ukuicc.randr.policy -include $(top_srcdir)/git.mk clean-local : rm -f *~ Makefile.in Makefile ukui-control-center/panels/display/xrandr-capplet.c0000664000175000017500000021470413253611050021434 0ustar fengfeng/* Monitor Settings. A preference panel for configuring monitors * * Copyright (C) 2007, 2008 Red Hat, Inc. * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301 USA * * Author: Soren Sandmann */ #include #include #include #include #include #include "scrollarea.h" #define MATE_DESKTOP_USE_UNSTABLE_API #include #include #include #include #include #include #include #include #include #include #include #if GTK_CHECK_VERSION (3, 0, 0) #define GdkRegion cairo_region_t #endif typedef struct App App; typedef struct GrabInfo GrabInfo; time_t backup_timestamp=0; struct App { MateRRScreen *screen; MateRRConfig *current_configuration; MateRRLabeler *labeler; MateRROutputInfo *current_output; GtkWidget *dialog; GtkWidget *current_monitor_event_box; GtkWidget *current_monitor_label; GtkWidget *monitor_on_radio; GtkWidget *monitor_off_radio; GtkWidget *dispaly_combo; GtkListStore *resolution_store; GtkWidget *resolution_combo; GtkWidget *refresh_combo; GtkWidget *rotation_combo; GtkWidget *panel_checkbox; GtkWidget *clone_checkbox; GtkWidget *show_icon_checkbox; GtkWidget *primary_button; /* We store the event timestamp when the Apply button is clicked */ GtkWidget *apply_button; guint32 apply_button_clicked_timestamp; GtkWidget *area; gboolean ignore_gui_changes; GSettings *settings; /* These are used while we are waiting for the ApplyConfiguration method to be executed over D-bus */ DBusGConnection *connection; DBusGProxy *proxy; DBusGProxyCall *proxy_call; enum { APPLYING_VERSION_1, APPLYING_VERSION_2 } apply_configuration_state; }; /* Response codes for custom buttons in the main dialog */ enum { RESPONSE_MAKE_DEFAULT = 1 }; static void rebuild_gui (App *app); static void on_clone_changed (GtkWidget *box, gpointer data); static void on_rate_changed (GtkComboBox *box, gpointer data); static gboolean output_overlaps (MateRROutputInfo *output, MateRRConfig *config); static void select_current_output_from_dialog_position (App *app); static void monitor_on_off_toggled_cb (GtkToggleButton *toggle, gpointer data); static void get_geometry (MateRROutputInfo *output, int *w, int *h); static void apply_configuration_returned_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, void *data); static gboolean get_clone_size (MateRRScreen *screen, int *width, int *height); static gboolean output_info_supports_mode (App *app, MateRROutputInfo *info, int width, int height); static void error_message (App *app, const char *primary_text, const char *secondary_text) { GtkWidget *dialog; dialog = gtk_message_dialog_new ((app && app->dialog) ? GTK_WINDOW (app->dialog) : NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", primary_text); if (secondary_text) gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", secondary_text); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } static gboolean do_free (gpointer data) { g_free (data); return FALSE; } static gchar * idle_free (gchar *s) { g_idle_add (do_free, s); return s; } static void on_screen_changed (MateRRScreen *scr, gpointer data) { MateRRConfig *current; App *app = data; current = mate_rr_config_new_current (app->screen, NULL); if (app->current_configuration) g_object_unref (app->current_configuration); app->current_configuration = current; app->current_output = NULL; if (app->labeler) { mate_rr_labeler_hide (app->labeler); g_object_unref (app->labeler); } app->labeler = mate_rr_labeler_new (app->current_configuration); mate_rr_labeler_hide (app->labeler); select_current_output_from_dialog_position (app); } static void on_viewport_changed (FooScrollArea *scroll_area, GdkRectangle *old_viewport, GdkRectangle *new_viewport) { foo_scroll_area_set_size (scroll_area, new_viewport->width, new_viewport->height); foo_scroll_area_invalidate (scroll_area); } static void layout_set_font (PangoLayout *layout, const char *font) { PangoFontDescription *desc = pango_font_description_from_string (font); if (desc) { pango_layout_set_font_description (layout, desc); pango_font_description_free (desc); } } static void clear_combo (GtkWidget *widget) { GtkComboBox *box = GTK_COMBO_BOX (widget); GtkTreeModel *model = gtk_combo_box_get_model (box); GtkListStore *store = GTK_LIST_STORE (model); gtk_list_store_clear (store); } typedef struct { const char *text; gboolean found; GtkTreeIter iter; } ForeachInfo; static gboolean foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { ForeachInfo *info = data; char *text = NULL; gtk_tree_model_get (model, iter, 0, &text, -1); g_assert (text != NULL); if (strcmp (info->text, text) == 0) { info->found = TRUE; info->iter = *iter; return TRUE; } return FALSE; } static void add_key (GtkWidget *widget, const char *text,MateRROutputInfo *output, int width, int height, int rate, MateRRRotation rotation) { ForeachInfo info; GtkComboBox *box = GTK_COMBO_BOX (widget); GtkTreeModel *model = gtk_combo_box_get_model (box); GtkListStore *store = GTK_LIST_STORE (model); info.text = text; info.found = FALSE; gtk_tree_model_foreach (model, foreach, &info); if (!info.found) { GtkTreeIter iter; gtk_list_store_insert_with_values (store, &iter,-1, 0, text, 1,output, 2, width, 3, height, 4, rate, 5, width * height, 6, rotation, -1); } } static gboolean combo_select (GtkWidget *widget, const char *text) { GtkComboBox *box = GTK_COMBO_BOX (widget); GtkTreeModel *model = gtk_combo_box_get_model (box); ForeachInfo info; info.text = text; info.found = FALSE; gtk_tree_model_foreach (model, foreach, &info); if (!info.found) return FALSE; gtk_combo_box_set_active_iter (box, &info.iter); return TRUE; } static MateRRMode ** get_current_modes (App *app) { MateRROutput *output; if (mate_rr_config_get_clone (app->current_configuration)) { return mate_rr_screen_list_clone_modes (app->screen); } else { if (!app->current_output) return NULL; output = mate_rr_screen_get_output_by_name (app->screen, mate_rr_output_info_get_name (app->current_output)); if (!output) return NULL; return mate_rr_output_list_modes (output); } } static void rebuild_rotation_combo (App *app) { typedef struct { MateRRRotation rotation; const char * name; } RotationInfo; static const RotationInfo rotations[] = { { MATE_RR_ROTATION_0, N_("Normal") }, { MATE_RR_ROTATION_90, N_("Left") }, { MATE_RR_ROTATION_270, N_("Right") }, { MATE_RR_ROTATION_180, N_("Upside-down") }, }; const char *selection; MateRRRotation current; int i; clear_combo (app->rotation_combo); gtk_widget_set_sensitive (app->rotation_combo, app->current_output && mate_rr_output_info_is_active (app->current_output)); if (!app->current_output) return; current = mate_rr_output_info_get_rotation (app->current_output); selection = NULL; for (i = 0; i < G_N_ELEMENTS (rotations); ++i) { const RotationInfo *info = &(rotations[i]); mate_rr_output_info_set_rotation (app->current_output, info->rotation); /* NULL-GError --- FIXME: we should say why this rotation is not available! */ if (mate_rr_config_applicable (app->current_configuration, app->screen, NULL)) { add_key (app->rotation_combo, _(info->name),NULL, 0, 0, 0, info->rotation); if (info->rotation == current) selection = _(info->name); } } mate_rr_output_info_set_rotation (app->current_output, current); if (!(selection && combo_select (app->rotation_combo, selection))) combo_select (app->rotation_combo, _("Normal")); } static char * make_rate_string (int hz) { return g_strdup_printf (_("%d Hz"), hz); } /* static void rebuild_rate_combo (App *app) { MateRRMode **modes; int best; int i; clear_combo (app->refresh_combo); gtk_widget_set_sensitive ( app->refresh_combo, app->current_output && mate_rr_output_info_is_active (app->current_output)); if (!app->current_output || !(modes = get_current_modes (app))) return; best = -1; for (i = 0; modes[i] != NULL; ++i) { MateRRMode *mode = modes[i]; int width, height, rate; int output_width, output_height; mate_rr_output_info_get_geometry (app->current_output, NULL, NULL, &output_width, &output_height); width = mate_rr_mode_get_width (mode); height = mate_rr_mode_get_height (mode); rate = mate_rr_mode_get_freq (mode); if (width == output_width && height == output_height) { add_key (app->refresh_combo, idle_free (make_rate_string (rate)), NULL,0, 0, rate, -1); if (rate > best) best = rate; } } if (!combo_select (app->refresh_combo, idle_free (make_rate_string (mate_rr_output_info_get_refresh_rate (app->current_output))))) combo_select (app->refresh_combo, idle_free (make_rate_string (best))); } */ static int count_active_outputs (App *app) { int i, count = 0; MateRROutputInfo **outputs = mate_rr_config_get_outputs (app->current_configuration); for (i = 0; outputs[i] != NULL; ++i) { if (mate_rr_output_info_is_active (outputs[i])) count++; } return count; } /* Computes whether "Mirror Screens" (clone mode) is supported based on these criteria: * * 1. There is an available size for cloning. * * 2. There are 2 or more connected outputs that support that size. */ static gboolean mirror_screens_is_supported (App *app) { int clone_width, clone_height; gboolean have_clone_size; gboolean mirror_is_supported; mirror_is_supported = FALSE; have_clone_size = get_clone_size (app->screen, &clone_width, &clone_height); if (have_clone_size) { int i; int num_outputs_with_clone_size; MateRROutputInfo **outputs = mate_rr_config_get_outputs (app->current_configuration); num_outputs_with_clone_size = 0; for (i = 0; outputs[i] != NULL; i++) { /* We count the connected outputs that support the clone size. It * doesn't matter if those outputs aren't actually On currently; we * will turn them on in on_clone_changed(). */ if (mate_rr_output_info_is_connected (outputs[i]) && output_info_supports_mode (app, outputs[i], clone_width, clone_height)) num_outputs_with_clone_size++; } if (num_outputs_with_clone_size >= 2) mirror_is_supported = TRUE; } return mirror_is_supported; } static void rebuild_mirror_screens (App *app) { gboolean mirror_is_active; gboolean mirror_is_supported; g_signal_handlers_block_by_func (app->clone_checkbox, G_CALLBACK (on_clone_changed), app); mirror_is_active = app->current_configuration && mate_rr_config_get_clone (app->current_configuration); /* If mirror_is_active, then it *must* be possible to turn mirroring off */ mirror_is_supported = mirror_is_active || mirror_screens_is_supported (app); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->clone_checkbox), mirror_is_active); gtk_widget_set_sensitive (app->clone_checkbox, mirror_is_supported); g_signal_handlers_unblock_by_func (app->clone_checkbox, G_CALLBACK (on_clone_changed), app); } static void rebuild_current_monitor_label (App *app) { char *str, *tmp; #if GTK_CHECK_VERSION (3, 0, 0) GdkRGBA color; #else GdkColor color; #endif gboolean use_color; if (app->current_output) { if (mate_rr_config_get_clone (app->current_configuration)) tmp = g_strdup (_("Mirror Screens")); else tmp = g_strdup_printf (_("Monitor: %s"), mate_rr_output_info_get_display_name (app->current_output)); str = g_strdup_printf ("%s", tmp); #if GTK_CHECK_VERSION (3, 0, 0) mate_rr_labeler_get_rgba_for_output (app->labeler, app->current_output, &color); #else //mate_rr_labeler_get_color_for_output (app->labeler, app->current_output, &color); color.red = 4420; color.green = 39219; color.blue = 56661; #endif use_color = TRUE; g_free (tmp); } else { str = g_strdup_printf ("%s", _("Monitor")); use_color = FALSE; } gtk_label_set_markup (GTK_LABEL (app->current_monitor_label), str); g_free (str); gtk_label_set_text(GTK_LABEL (app->current_monitor_label), "11111111111111"); if (use_color) { #if GTK_CHECK_VERSION (3, 0, 0) GdkRGBA black = { 0, 0, 0, 1.0 }; gtk_widget_override_background_color (app->current_monitor_event_box, gtk_widget_get_state_flags (app->current_monitor_event_box), &color); /* Make the label explicitly black. We don't want it to follow the * theme's colors, since the label is always shown against a light * pastel background. See bgo#556050 */ gtk_widget_override_color (app->current_monitor_label, gtk_widget_get_state_flags (app->current_monitor_label), &black); #else GdkColor black = { 0, 0, 0, 0 }; gtk_widget_modify_bg (app->current_monitor_event_box, gtk_widget_get_state (app->current_monitor_event_box), &color); /* Make the label explicitly black. We don't want it to follow the * theme's colors, since the label is always shown against a light * pastel background. See bgo#556050 */ gtk_widget_modify_fg (app->current_monitor_label, gtk_widget_get_state (app->current_monitor_label), &black); #endif } #if !GTK_CHECK_VERSION (3, 0, 0) else { /* Remove any modifications we did on the label's color */ GtkRcStyle *reset_rc_style; reset_rc_style = gtk_rc_style_new (); gtk_widget_modify_style (app->current_monitor_label, reset_rc_style); /* takes ownership of, and destroys, the rc style */ } #endif gtk_event_box_set_visible_window (GTK_EVENT_BOX (app->current_monitor_event_box), use_color); } static void rebuild_display_combo (App *app) { int i; int monitor_num=0; char *current_display_name; clear_combo (app->dispaly_combo); MateRROutputInfo **outputs; outputs = mate_rr_config_get_outputs (app->current_configuration); for (i = 0; outputs[i] != NULL; ++i) { MateRROutputInfo *output = outputs[i]; if (mate_rr_output_info_is_connected(output)) { // g_printerr("-----------display_name=%s\n",g_strdup_printf ("%s\n%s", mate_rr_output_info_get_display_name (output), mate_rr_output_info_get_name (output))); add_key (app->dispaly_combo,g_strdup_printf ("%s<%s>", mate_rr_output_info_get_display_name (output), mate_rr_output_info_get_name (output)),output, 0, 0, 0, -1); monitor_num++; } } if (app->current_output) { current_display_name= g_strdup_printf ("%s<%s>", mate_rr_output_info_get_display_name (app->current_output), mate_rr_output_info_get_name (app->current_output)); combo_select (app->dispaly_combo, current_display_name); } if (monitor_num > 1) gtk_widget_set_sensitive (app->dispaly_combo, TRUE); else gtk_widget_set_sensitive (app->dispaly_combo, FALSE); } static void rebuild_on_off_radios (App *app) { gboolean sensitive; gboolean on_active; gboolean off_active; g_signal_handlers_block_by_func (app->monitor_on_radio, G_CALLBACK (monitor_on_off_toggled_cb), app); g_signal_handlers_block_by_func (app->monitor_off_radio, G_CALLBACK (monitor_on_off_toggled_cb), app); sensitive = FALSE; on_active = FALSE; off_active = FALSE; if (!mate_rr_config_get_clone (app->current_configuration) && app->current_output) { if (count_active_outputs (app) > 1 || !mate_rr_output_info_is_active (app->current_output)) sensitive = TRUE; else sensitive = FALSE; on_active = mate_rr_output_info_is_active (app->current_output); off_active = !on_active; } gtk_widget_set_sensitive (app->monitor_on_radio, sensitive); gtk_widget_set_sensitive (app->monitor_off_radio, sensitive); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->monitor_on_radio), on_active); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->monitor_off_radio), off_active); g_signal_handlers_unblock_by_func (app->monitor_on_radio, G_CALLBACK (monitor_on_off_toggled_cb), app); g_signal_handlers_unblock_by_func (app->monitor_off_radio, G_CALLBACK (monitor_on_off_toggled_cb), app); } static char * make_resolution_string (int width, int height) { return g_strdup_printf (_("%d x %d"), width, height); } static void find_best_mode (MateRRMode **modes, int *out_width, int *out_height) { int i; *out_width = 0; *out_height = 0; for (i = 0; modes[i] != NULL; i++) { int w, h; w = mate_rr_mode_get_width (modes[i]); h = mate_rr_mode_get_height (modes[i]); if (w * h > *out_width * *out_height) { *out_width = w; *out_height = h; } } } static void rebuild_resolution_combo (App *app) { int i; MateRRMode **modes; const char *current; int output_width, output_height; if (!(modes = get_current_modes (app)) || !app->current_output || !mate_rr_output_info_is_active (app->current_output)) { gtk_widget_set_sensitive (app->resolution_combo, FALSE); return; } clear_combo (app->resolution_combo); g_assert (app->current_output != NULL); mate_rr_output_info_get_geometry (app->current_output, NULL, NULL, &output_width, &output_height); g_assert (output_width != 0 && output_height != 0); gtk_widget_set_sensitive (app->resolution_combo, TRUE); for (i = 0; modes[i] != NULL; ++i) { int width, height; width = mate_rr_mode_get_width (modes[i]); height = mate_rr_mode_get_height (modes[i]); if(width <= 800 || height <= 600) continue; add_key (app->resolution_combo, idle_free (make_resolution_string (width, height)),app->current_output, width, height, 0, -1); } current = idle_free (make_resolution_string (output_width, output_height)); if (!combo_select (app->resolution_combo, current)) { int best_w, best_h; find_best_mode (modes, &best_w, &best_h); combo_select (app->resolution_combo, idle_free (make_resolution_string (best_w, best_h))); } } static void rebuild_gui (App *app) { gboolean sensitive; /* We would break spectacularly if we recursed, so * just assert if that happens */ g_assert (app->ignore_gui_changes == FALSE); app->ignore_gui_changes = TRUE; sensitive = app->current_output ? TRUE : FALSE; #if 0 g_debug ("rebuild gui, is on: %d", mate_rr_output_info_is_active (app->current_output)); #endif rebuild_mirror_screens (app); // rebuild_current_monitor_label (app); rebuild_on_off_radios (app); rebuild_resolution_combo (app); rebuild_display_combo(app); // rebuild_rate_combo (app); rebuild_rotation_combo (app); #if 0 g_debug ("sensitive: %d, on: %d", sensitive, mate_rr_output_info_is_active (app->current_output)); #endif // gtk_widget_set_sensitive (app->panel_checkbox, sensitive); gtk_widget_set_sensitive (app->primary_button, app->current_output && !mate_rr_output_info_get_primary(app->current_output)); app->ignore_gui_changes = FALSE; } static gboolean get_mode (GtkWidget *widget, char** text,MateRROutputInfo **output,int *width, int *height, int *freq, MateRRRotation *rot) { GtkTreeIter iter; GtkTreeModel *model; GtkComboBox *box = GTK_COMBO_BOX (widget); int dummy; char * dummy_char; MateRROutputInfo *dummy_output; if (!gtk_combo_box_get_active_iter (box, &iter)) return FALSE; if (!text) text = &dummy_char; if(!output) output = &dummy_output; if (!width) width = &dummy; if (!height) height = &dummy; if (!freq) freq = &dummy; if (!rot) rot = (MateRRRotation *)&dummy; model = gtk_combo_box_get_model (box); gtk_tree_model_get (model, &iter, 0,text, 1,output, 2, width, 3, height, 4, freq, 6, rot, -1); return TRUE; } static void on_rotation_changed (GtkComboBox *box, gpointer data) { App *app = data; MateRRRotation rotation; if (!app->current_output) return; if (get_mode (app->rotation_combo, NULL,NULL,NULL, NULL, NULL, &rotation)) mate_rr_output_info_set_rotation (app->current_output, rotation); foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area)); } /* static void on_rate_changed (GtkComboBox *box, gpointer data) { App *app = data; int rate; if (!app->current_output) return; if (get_mode (app->refresh_combo, NULL, NULL, &rate, NULL)) mate_rr_output_info_set_refresh_rate (app->current_output, rate); foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area)); } */ static void on_display_changed (GtkComboBox *box, gpointer data) { App *app = data; char* display_name; MateRROutputInfo *output=NULL; if (!app->current_output) return; if (get_mode (app->dispaly_combo, &display_name,&output, NULL, NULL,NULL,NULL)) if(output) { app->current_output = output; rebuild_resolution_combo(app); rebuild_rotation_combo(app); foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area)); } } static void select_resolution_for_current_output (App *app) { MateRRMode **modes; int width, height; int x, y; mate_rr_output_info_get_geometry (app->current_output, &x, &y, NULL, NULL); width = mate_rr_output_info_get_preferred_width (app->current_output); height = mate_rr_output_info_get_preferred_height (app->current_output); if (width != 0 && height != 0) { mate_rr_output_info_set_geometry (app->current_output, x, y, width, height); return; } modes = get_current_modes (app); if (!modes) return; find_best_mode (modes, &width, &height); mate_rr_output_info_set_geometry (app->current_output, x, y, width, height); } static void monitor_on_off_toggled_cb (GtkToggleButton *toggle, gpointer data) { App *app = data; gboolean is_on; if (!app->current_output) return; if (!gtk_toggle_button_get_active (toggle)) return; if (GTK_WIDGET (toggle) == app->monitor_on_radio) is_on = TRUE; else if (GTK_WIDGET (toggle) == app->monitor_off_radio) is_on = FALSE; else { g_assert_not_reached (); return; } mate_rr_output_info_set_active (app->current_output, is_on); if (is_on) select_resolution_for_current_output (app); /* The refresh rate will be picked in rebuild_rate_combo() */ rebuild_gui (app); foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area)); } static void realign_outputs_after_resolution_change (App *app, MateRROutputInfo *output_that_changed, int old_width, int old_height) { /* We find the outputs that were below or to the right of the output that * changed, and realign them; we also do that for outputs that shared the * right/bottom edges with the output that changed. The outputs that are * above or to the left of that output don't need to change. */ int i; int old_right_edge, old_bottom_edge; int dx, dy; int x, y, width, height; MateRROutputInfo **outputs; g_assert (app->current_configuration != NULL); mate_rr_output_info_get_geometry (output_that_changed, &x, &y, &width, &height); if (width == old_width && height == old_height) return; old_right_edge = x + old_width; old_bottom_edge = y + old_height; dx = width - old_width; dy = height - old_height; outputs = mate_rr_config_get_outputs (app->current_configuration); for (i = 0; outputs[i] != NULL; i++) { int output_x, output_y; int output_width, output_height; if (outputs[i] == output_that_changed || mate_rr_output_info_is_connected (outputs[i])) continue; mate_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height); if (output_x >= old_right_edge) output_x += dx; else if (output_x + output_width == old_right_edge) output_x = x + width - output_width; if (output_y >= old_bottom_edge) output_y += dy; else if (output_y + output_height == old_bottom_edge) output_y = y + height - output_height; mate_rr_output_info_set_geometry (outputs[i], output_x, output_y, output_width, output_height); } } static void on_resolution_changed (GtkComboBox *box, gpointer data) { App *app = data; int old_width, old_height; int x, y; int width; int height; if (!app->current_output) return; mate_rr_output_info_get_geometry (app->current_output, &x, &y, &old_width, &old_height); if (get_mode (app->resolution_combo,NULL,NULL, &width, &height, NULL, NULL)) { mate_rr_output_info_set_geometry (app->current_output, x, y, width, height); if (width == 0 || height == 0) mate_rr_output_info_set_active (app->current_output, FALSE); else mate_rr_output_info_set_active (app->current_output, TRUE); } realign_outputs_after_resolution_change (app, app->current_output, old_width, old_height); // rebuild_rate_combo (app); rebuild_rotation_combo (app); foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area)); } static void lay_out_outputs_horizontally (App *app) { int i; int x; MateRROutputInfo **outputs; /* Lay out all the monitors horizontally when "mirror screens" is turned * off, to avoid having all of them overlapped initially. We put the * outputs turned off on the right-hand side. */ x = 0; /* First pass, all "on" outputs */ outputs = mate_rr_config_get_outputs (app->current_configuration); for (i = 0; outputs[i]; ++i) { int width, height; if (mate_rr_output_info_is_connected (outputs[i]) &&mate_rr_output_info_is_active (outputs[i])) { mate_rr_output_info_get_geometry (outputs[i], NULL, NULL, &width, &height); mate_rr_output_info_set_geometry (outputs[i], x, 0, width, height); x += width; } } /* Second pass, all the black screens */ for (i = 0; outputs[i]; ++i) { int width, height; if (!(mate_rr_output_info_is_connected (outputs[i]) && mate_rr_output_info_is_active (outputs[i]))) { mate_rr_output_info_get_geometry (outputs[i], NULL, NULL, &width, &height); mate_rr_output_info_set_geometry (outputs[i], x, 0, width, height); x += width; } } } /* FIXME: this function is copied from mate-settings-daemon/plugins/xrandr/gsd-xrandr-manager.c. * Do we need to put this function in mate-desktop for public use? */ static gboolean get_clone_size (MateRRScreen *screen, int *width, int *height) { MateRRMode **modes = mate_rr_screen_list_clone_modes (screen); int best_w, best_h; int i; best_w = 0; best_h = 0; for (i = 0; modes[i] != NULL; ++i) { MateRRMode *mode = modes[i]; int w, h; w = mate_rr_mode_get_width (mode); h = mate_rr_mode_get_height (mode); if (w * h > best_w * best_h) { best_w = w; best_h = h; } } if (best_w > 0 && best_h > 0) { if (width) *width = best_w; if (height) *height = best_h; return TRUE; } return FALSE; } static gboolean output_info_supports_mode (App *app, MateRROutputInfo *info, int width, int height) { MateRROutput *output; MateRRMode **modes; int i; if (!mate_rr_output_info_is_connected (info)) return FALSE; output = mate_rr_screen_get_output_by_name (app->screen, mate_rr_output_info_get_name (info)); if (!output) return FALSE; modes = mate_rr_output_list_modes (output); for (i = 0; modes[i]; i++) { if (mate_rr_mode_get_width (modes[i]) == width && mate_rr_mode_get_height (modes[i]) == height) return TRUE; } return FALSE; } static void on_clone_changed (GtkWidget *box, gpointer data) { App *app = data; mate_rr_config_set_clone (app->current_configuration, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (app->clone_checkbox))); if (mate_rr_config_get_clone (app->current_configuration)) { int i; int width, height; MateRROutputInfo **outputs = mate_rr_config_get_outputs (app->current_configuration); for (i = 0; outputs[i]; ++i) { if (mate_rr_output_info_is_connected(outputs[i])) { app->current_output = outputs[i]; break; } } /* Turn on all the connected screens that support the best clone mode. * The user may hit "Mirror Screens", but he shouldn't have to turn on * all the required outputs as well. */ get_clone_size (app->screen, &width, &height); for (i = 0; outputs[i]; i++) { int x, y; if (output_info_supports_mode (app, outputs[i], width, height)) { mate_rr_output_info_set_active (outputs[i], TRUE); mate_rr_output_info_get_geometry (outputs[i], &x, &y, NULL, NULL); mate_rr_output_info_set_geometry (outputs[i], x, y, width, height); } } } else { if (output_overlaps (app->current_output, app->current_configuration)) lay_out_outputs_horizontally (app); } rebuild_gui (app); } static void get_geometry (MateRROutputInfo *output, int *w, int *h) { MateRRRotation rotation; if (mate_rr_output_info_is_active (output)) { mate_rr_output_info_get_geometry (output, NULL, NULL, w, h); } else { *h = mate_rr_output_info_get_preferred_height (output); *w = mate_rr_output_info_get_preferred_width (output); } rotation = mate_rr_output_info_get_rotation (output); if ((rotation & MATE_RR_ROTATION_90) || (rotation & MATE_RR_ROTATION_270)) { int tmp; tmp = *h; *h = *w; *w = tmp; } } #define SPACE 15 #define MARGIN 15 static GList * list_connected_outputs (App *app, int *total_w, int *total_h) { int i, dummy; GList *result = NULL; MateRROutputInfo **outputs; if (!total_w) total_w = &dummy; if (!total_h) total_h = &dummy; *total_w = 0; *total_h = 0; outputs = mate_rr_config_get_outputs(app->current_configuration); for (i = 0; outputs[i] != NULL; ++i) { if (mate_rr_output_info_is_connected (outputs[i])) { int w, h; result = g_list_prepend (result, outputs[i]); get_geometry (outputs[i], &w, &h); *total_w += w; *total_h += h; } } return g_list_reverse (result); } static int get_n_connected (App *app) { GList *connected_outputs = list_connected_outputs (app, NULL, NULL); int n = g_list_length (connected_outputs); g_list_free (connected_outputs); return n; } static double compute_scale (App *app) { int available_w, available_h; int total_w, total_h; int n_monitors; GdkRectangle viewport; GList *connected_outputs; foo_scroll_area_get_viewport (FOO_SCROLL_AREA (app->area), &viewport); connected_outputs = list_connected_outputs (app, &total_w, &total_h); n_monitors = g_list_length (connected_outputs); g_list_free (connected_outputs); available_w = viewport.width - 2 * MARGIN - (n_monitors - 1) * SPACE; available_h = viewport.height - 2 * MARGIN - (n_monitors - 1) * SPACE; return MIN ((double)available_w / total_w, (double)available_h / total_h); } typedef struct Edge { MateRROutputInfo *output; int x1, y1; int x2, y2; } Edge; typedef struct Snap { Edge *snapper; /* Edge that should be snapped */ Edge *snappee; int dy, dx; } Snap; static void add_edge (MateRROutputInfo *output, int x1, int y1, int x2, int y2, GArray *edges) { Edge e; e.x1 = x1; e.x2 = x2; e.y1 = y1; e.y2 = y2; e.output = output; g_array_append_val (edges, e); } static void list_edges_for_output (MateRROutputInfo *output, GArray *edges) { int x, y, w, h; mate_rr_output_info_get_geometry (output, &x, &y, &w, &h); /* Top, Bottom, Left, Right */ add_edge (output, x, y, x + w, y, edges); add_edge (output, x, y + h, x + w, y + h, edges); add_edge (output, x, y, x, y + h, edges); add_edge (output, x + w, y, x + w, y + h, edges); } static void list_edges (MateRRConfig *config, GArray *edges) { int i; MateRROutputInfo **outputs = mate_rr_config_get_outputs (config); for (i = 0; outputs[i]; ++i) { if (mate_rr_output_info_is_connected (outputs[i])) list_edges_for_output (outputs[i], edges); } } static gboolean overlap (int s1, int e1, int s2, int e2) { return (!(e1 < s2 || s1 >= e2)); } static gboolean horizontal_overlap (Edge *snapper, Edge *snappee) { if (snapper->y1 != snapper->y2 || snappee->y1 != snappee->y2) return FALSE; return overlap (snapper->x1, snapper->x2, snappee->x1, snappee->x2); } static gboolean vertical_overlap (Edge *snapper, Edge *snappee) { if (snapper->x1 != snapper->x2 || snappee->x1 != snappee->x2) return FALSE; return overlap (snapper->y1, snapper->y2, snappee->y1, snappee->y2); } static void add_snap (GArray *snaps, Snap snap) { if (ABS (snap.dx) <= 200 || ABS (snap.dy) <= 200) g_array_append_val (snaps, snap); } static void add_edge_snaps (Edge *snapper, Edge *snappee, GArray *snaps) { Snap snap; snap.snapper = snapper; snap.snappee = snappee; if (horizontal_overlap (snapper, snappee)) { snap.dx = 0; snap.dy = snappee->y1 - snapper->y1; add_snap (snaps, snap); } else if (vertical_overlap (snapper, snappee)) { snap.dy = 0; snap.dx = snappee->x1 - snapper->x1; add_snap (snaps, snap); } /* Corner snaps */ /* 1->1 */ snap.dx = snappee->x1 - snapper->x1; snap.dy = snappee->y1 - snapper->y1; add_snap (snaps, snap); /* 1->2 */ snap.dx = snappee->x2 - snapper->x1; snap.dy = snappee->y2 - snapper->y1; add_snap (snaps, snap); /* 2->2 */ snap.dx = snappee->x2 - snapper->x2; snap.dy = snappee->y2 - snapper->y2; add_snap (snaps, snap); /* 2->1 */ snap.dx = snappee->x1 - snapper->x2; snap.dy = snappee->y1 - snapper->y2; add_snap (snaps, snap); } static void list_snaps (MateRROutputInfo *output, GArray *edges, GArray *snaps) { int i; for (i = 0; i < edges->len; ++i) { Edge *output_edge = &(g_array_index (edges, Edge, i)); if (output_edge->output == output) { int j; for (j = 0; j < edges->len; ++j) { Edge *edge = &(g_array_index (edges, Edge, j)); if (edge->output != output) add_edge_snaps (output_edge, edge, snaps); } } } } #if 0 static void print_edge (Edge *edge) { g_debug ("(%d %d %d %d)", edge->x1, edge->y1, edge->x2, edge->y2); } #endif static gboolean corner_on_edge (int x, int y, Edge *e) { if (x == e->x1 && x == e->x2 && y >= e->y1 && y <= e->y2) return TRUE; if (y == e->y1 && y == e->y2 && x >= e->x1 && x <= e->x2) return TRUE; return FALSE; } static gboolean edges_align (Edge *e1, Edge *e2) { if (corner_on_edge (e1->x1, e1->y1, e2)) return TRUE; if (corner_on_edge (e2->x1, e2->y1, e1)) return TRUE; return FALSE; } static gboolean output_is_aligned (MateRROutputInfo *output, GArray *edges) { gboolean result = FALSE; int i; for (i = 0; i < edges->len; ++i) { Edge *output_edge = &(g_array_index (edges, Edge, i)); if (output_edge->output == output) { int j; for (j = 0; j < edges->len; ++j) { Edge *edge = &(g_array_index (edges, Edge, j)); /* We are aligned if an output edge matches * an edge of another output */ if (edge->output != output_edge->output) { if (edges_align (output_edge, edge)) { result = TRUE; goto done; } } } } } done: return result; } static void get_output_rect (MateRROutputInfo *output, GdkRectangle *rect) { mate_rr_output_info_get_geometry (output, &rect->x, &rect->y, &rect->width, &rect->height); } static gboolean output_overlaps (MateRROutputInfo *output, MateRRConfig *config) { int i; GdkRectangle output_rect; MateRROutputInfo **outputs; get_output_rect (output, &output_rect); outputs = mate_rr_config_get_outputs (config); for (i = 0; outputs[i]; ++i) { if (outputs[i] != output && mate_rr_output_info_is_connected (outputs[i])) { GdkRectangle other_rect; get_output_rect (outputs[i], &other_rect); if (gdk_rectangle_intersect (&output_rect, &other_rect, NULL)) return TRUE; } } return FALSE; } static gboolean mate_rr_config_is_aligned (MateRRConfig *config, GArray *edges) { int i; gboolean result = TRUE; MateRROutputInfo **outputs; outputs = mate_rr_config_get_outputs(config); for (i = 0; outputs[i]; ++i) { if (mate_rr_output_info_is_connected (outputs[i])) { if (!output_is_aligned (outputs[i], edges)) return FALSE; if (output_overlaps (outputs[i], config)) return FALSE; } } return result; } struct GrabInfo { int grab_x; int grab_y; int output_x; int output_y; }; static gboolean is_corner_snap (const Snap *s) { return s->dx != 0 && s->dy != 0; } static int compare_snaps (gconstpointer v1, gconstpointer v2) { const Snap *s1 = v1; const Snap *s2 = v2; int sv1 = MAX (ABS (s1->dx), ABS (s1->dy)); int sv2 = MAX (ABS (s2->dx), ABS (s2->dy)); int d; d = sv1 - sv2; /* This snapping algorithm is good enough for rock'n'roll, but * this is probably a better: * * First do a horizontal/vertical snap, then * with the new coordinates from that snap, * do a corner snap. * * Right now, it's confusing that corner snapping * depends on the distance in an axis that you can't actually see. * */ if (d == 0) { if (is_corner_snap (s1) && !is_corner_snap (s2)) return -1; else if (is_corner_snap (s2) && !is_corner_snap (s1)) return 1; else return 0; } else { return d; } } /* Sets a mouse cursor for a widget's window. As a hack, you can pass * GDK_BLANK_CURSOR to mean "set the cursor to NULL" (i.e. reset the widget's * window's cursor to its default). */ static void set_cursor (GtkWidget *widget, GdkCursorType type) { GdkCursor *cursor; GdkWindow *window; if (type == GDK_BLANK_CURSOR) cursor = NULL; else cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), type); window = gtk_widget_get_window (widget); if (window) gdk_window_set_cursor (window, cursor); if (cursor) #if GTK_CHECK_VERSION (3, 0, 0) g_object_unref (cursor); #else gdk_cursor_unref (cursor); #endif } static void set_monitors_tooltip (App *app, gboolean is_dragging) { const char *text; if (is_dragging) text = NULL; else text = _("Select a monitor to change its properties; drag it to rearrange its placement."); gtk_widget_set_tooltip_text (app->area, text); } static void on_output_event (FooScrollArea *area, FooScrollAreaEvent *event, gpointer data) { MateRROutputInfo *output = data; App *app = g_object_get_data (G_OBJECT (area), "app"); /* If the mouse is inside the outputs, set the cursor to "you can move me". See * on_canvas_event() for where we reset the cursor to the default if it * exits the outputs' area. */ if (!mate_rr_config_get_clone (app->current_configuration) && get_n_connected (app) > 1) set_cursor (GTK_WIDGET (area), GDK_FLEUR); if (event->type == FOO_BUTTON_PRESS) { GrabInfo *info; app->current_output = output; rebuild_gui (app); set_monitors_tooltip (app, TRUE); if (!mate_rr_config_get_clone (app->current_configuration) && get_n_connected (app) > 1) { int output_x, output_y; mate_rr_output_info_get_geometry (output, &output_x, &output_y, NULL, NULL); foo_scroll_area_begin_grab (area, on_output_event, data); info = g_new0 (GrabInfo, 1); info->grab_x = event->x; info->grab_y = event->y; info->output_x = output_x; info->output_y = output_y; g_object_set_data (G_OBJECT (output), "grab-info", info); } foo_scroll_area_invalidate (area); } else { if (foo_scroll_area_is_grabbed (area)) { GrabInfo *info = g_object_get_data (G_OBJECT (output), "grab-info"); double scale = compute_scale (app); int old_x, old_y; int width, height; int new_x, new_y; int i; GArray *edges, *snaps, *new_edges; mate_rr_output_info_get_geometry (output, &old_x, &old_y, &width, &height); new_x = info->output_x + (event->x - info->grab_x) / scale; new_y = info->output_y + (event->y - info->grab_y) / scale; mate_rr_output_info_set_geometry (output, new_x, new_y, width, height); edges = g_array_new (TRUE, TRUE, sizeof (Edge)); snaps = g_array_new (TRUE, TRUE, sizeof (Snap)); new_edges = g_array_new (TRUE, TRUE, sizeof (Edge)); list_edges (app->current_configuration, edges); list_snaps (output, edges, snaps); g_array_sort (snaps, compare_snaps); mate_rr_output_info_set_geometry (output, new_x, new_y, width, height); for (i = 0; i < snaps->len; ++i) { Snap *snap = &(g_array_index (snaps, Snap, i)); GArray *new_edges = g_array_new (TRUE, TRUE, sizeof (Edge)); mate_rr_output_info_set_geometry (output, new_x + snap->dx, new_y + snap->dy, width, height); g_array_set_size (new_edges, 0); list_edges (app->current_configuration, new_edges); if (mate_rr_config_is_aligned (app->current_configuration, new_edges)) { g_array_free (new_edges, TRUE); break; } else { mate_rr_output_info_set_geometry (output, info->output_x, info->output_y, width, height); } } g_array_free (new_edges, TRUE); g_array_free (snaps, TRUE); g_array_free (edges, TRUE); if (event->type == FOO_BUTTON_RELEASE) { foo_scroll_area_end_grab (area); set_monitors_tooltip (app, FALSE); g_free (g_object_get_data (G_OBJECT (output), "grab-info")); g_object_set_data (G_OBJECT (output), "grab-info", NULL); #if 0 g_debug ("new position: %d %d %d %d", output->x, output->y, output->width, output->height); #endif } foo_scroll_area_invalidate (area); } } } static void on_canvas_event (FooScrollArea *area, FooScrollAreaEvent *event, gpointer data) { /* If the mouse exits the outputs, reset the cursor to the default. See * on_output_event() for where we set the cursor to the movement cursor if * it is over one of the outputs. */ set_cursor (GTK_WIDGET (area), GDK_BLANK_CURSOR); } static PangoLayout * get_display_name (App *app, MateRROutputInfo *output) { char *text; PangoLayout * layout; if (mate_rr_config_get_clone (app->current_configuration)) { /* Translators: this is the feature where what you see on your laptop's * screen is the same as your external monitor. Here, "Mirror" is being * used as an adjective, not as a verb. For example, the Spanish * translation could be "Pantallas en Espejo", *not* "Espejar Pantallas". */ text = g_strdup_printf (_("Mirror Screens")); } else { text = g_strdup_printf ("%s\n%s", mate_rr_output_info_get_display_name (output), mate_rr_output_info_get_name (output)); } layout = gtk_widget_create_pango_layout (GTK_WIDGET (app->area), text); pango_layout_set_markup (layout, text, -1); g_free (text); pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); return layout; } static void paint_background (FooScrollArea *area, cairo_t *cr) { GdkRectangle viewport; GtkWidget *widget; GtkStyleContext *widget_style; GdkRGBA *base_color = NULL; GdkRGBA dark_color; widget = GTK_WIDGET (area); foo_scroll_area_get_viewport (area, &viewport); widget_style = gtk_widget_get_style_context (widget); gtk_style_context_save (widget_style); gtk_style_context_set_state (widget_style, GTK_STATE_FLAG_SELECTED); gtk_style_context_get (widget_style, gtk_style_context_get_state (widget_style), GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &base_color, NULL); gtk_style_context_restore (widget_style); gdk_cairo_set_source_rgba(cr, base_color); gdk_rgba_free (base_color); cairo_rectangle (cr, viewport.x, viewport.y, viewport.width, viewport.height); cairo_fill_preserve (cr); foo_scroll_area_add_input_from_fill (area, cr, on_canvas_event, NULL); gtk_style_context_save (widget_style); gtk_style_context_set_state (widget_style, GTK_STATE_FLAG_SELECTED); mate_desktop_gtk_style_get_dark_color (widget_style, gtk_style_context_get_state (widget_style), &dark_color); gtk_style_context_restore (widget_style); gdk_cairo_set_source_rgba (cr, &dark_color); cairo_stroke (cr); } static void paint_output (App *app, cairo_t *cr, int i) { int w, h; double scale = compute_scale (app); double x, y; int output_x, output_y; MateRRRotation rotation; int total_w, total_h; GList *connected_outputs = list_connected_outputs (app, &total_w, &total_h); MateRROutputInfo *output = g_list_nth_data (connected_outputs, i); PangoLayout *layout = get_display_name (app, output); PangoRectangle ink_extent, log_extent; GdkRectangle viewport; #if GTK_CHECK_VERSION (3, 0, 0) GdkRGBA output_color; #else GdkColor output_color; #endif double r, g, b; double available_w; double factor; cairo_save (cr); foo_scroll_area_get_viewport (FOO_SCROLL_AREA (app->area), &viewport); get_geometry (output, &w, &h); #if 0 g_debug ("%s (%p) geometry %d %d %d", output->name, output, w, h, output->rate); #endif viewport.height -= 2 * MARGIN; viewport.width -= 2 * MARGIN; mate_rr_output_info_get_geometry (output, &output_x, &output_y, NULL, NULL); x = output_x * scale + MARGIN + (viewport.width - total_w * scale) / 2.0; y = output_y * scale + MARGIN + (viewport.height - total_h * scale) / 2.0; #if 0 g_debug ("scaled: %f %f", x, y); g_debug ("scale: %f", scale); g_debug ("%f %f %f %f", x, y, w * scale + 0.5, h * scale + 0.5); #endif cairo_translate (cr, x + (w * scale + 0.5) / 2, y + (h * scale + 0.5) / 2); /* rotation is already applied in get_geometry */ rotation = mate_rr_output_info_get_rotation (output); if (rotation & MATE_RR_REFLECT_X) cairo_scale (cr, -1, 1); if (rotation & MATE_RR_REFLECT_Y) cairo_scale (cr, 1, -1); cairo_translate (cr, - x - (w * scale + 0.5) / 2, - y - (h * scale + 0.5) / 2); cairo_rectangle (cr, x, y, w * scale + 0.5, h * scale + 0.5); cairo_clip_preserve (cr); #if GTK_CHECK_VERSION (3, 0, 0) mate_rr_labeler_get_rgba_for_output (app->labeler, output, &output_color); r = output_color.red; g = output_color.green; b = output_color.blue; #else // mate_rr_labeler_get_color_for_output (app->labeler, output, &output_color); output_color.red = 4420; output_color.green = 39219; output_color.blue = 56661; r = output_color.red / 65535.0; g = output_color.green / 65535.0; b = output_color.blue / 65535.0; #endif if (!mate_rr_output_info_is_active (output)) { /* If the output is turned off, just darken the selected color */ r *= 0.2; g *= 0.2; b *= 0.2; } cairo_set_source_rgba (cr, r, g, b, 1.0); foo_scroll_area_add_input_from_fill (FOO_SCROLL_AREA (app->area), cr, on_output_event, output); cairo_fill (cr); if (output == app->current_output) { cairo_rectangle (cr, x + 2, y + 2, w * scale + 0.5 - 4, h * scale + 0.5 - 4); cairo_set_line_width (cr, 4); cairo_set_source_rgba (cr, 0.33, 0.43, 0.57, 1.0); cairo_stroke (cr); } cairo_rectangle (cr, x + 0.5, y + 0.5, w * scale + 0.5 - 1, h * scale + 0.5 - 1); cairo_set_line_width (cr, 1); cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0); cairo_stroke (cr); cairo_set_line_width (cr, 2); layout_set_font (layout, "Sans 12"); pango_layout_get_pixel_extents (layout, &ink_extent, &log_extent); available_w = w * scale + 0.5 - 6; /* Same as the inner rectangle's width, minus 1 pixel of padding on each side */ if (available_w < ink_extent.width) factor = available_w / ink_extent.width; else factor = 1.0; cairo_move_to (cr, x + ((w * scale + 0.5) - factor * log_extent.width) / 2, y + ((h * scale + 0.5) - factor * log_extent.height) / 2); cairo_scale (cr, factor, factor); if (mate_rr_output_info_is_active (output)) cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); else cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); pango_cairo_show_layout (cr, layout); cairo_restore (cr); g_object_unref (layout); } #if GTK_CHECK_VERSION (3, 0, 0) static void on_area_paint (FooScrollArea *area, cairo_t *cr, gpointer data) #else static void on_area_paint (FooScrollArea *area, cairo_t *cr, GdkRectangle *extent, GdkRegion *region, gpointer data) #endif { App *app = data; double scale; GList *connected_outputs = NULL; GList *list; paint_background (area, cr); if (!app->current_configuration) return; scale = compute_scale (app); connected_outputs = list_connected_outputs (app, NULL, NULL); #if 0 g_debug ("scale: %f", scale); #endif for (list = connected_outputs; list != NULL; list = list->next) { paint_output (app, cr, g_list_position (connected_outputs, list)); if (mate_rr_config_get_clone (app->current_configuration)) break; } } static void make_text_combo (GtkWidget *widget, int sort_column) { GtkComboBox *box = GTK_COMBO_BOX (widget); GtkListStore *store = gtk_list_store_new ( 7, G_TYPE_STRING, /* Text */ G_TYPE_POINTER, G_TYPE_INT, /* Width */ G_TYPE_INT, /* Height */ G_TYPE_INT, /* Frequency */ G_TYPE_INT, /* Width * Height */ G_TYPE_INT); /* Rotation */ GtkCellRenderer *cell; gtk_cell_layout_clear (GTK_CELL_LAYOUT (widget)); gtk_combo_box_set_model (box, GTK_TREE_MODEL (store)); cell = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (box), cell, TRUE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (box), cell, "text", 0, NULL); if (sort_column != -1) { gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), sort_column, GTK_SORT_DESCENDING); } } static void compute_virtual_size_for_configuration (MateRRConfig *config, int *ret_width, int *ret_height) { int i; int width, height; int output_x, output_y, output_width, output_height; MateRROutputInfo **outputs; width = height = 0; outputs = mate_rr_config_get_outputs (config); for (i = 0; outputs[i] != NULL; i++) { if (mate_rr_output_info_is_active (outputs[i])) { mate_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height); width = MAX (width, output_x + output_width); height = MAX (height, output_y + output_height); } } *ret_width = width; *ret_height = height; } static void check_required_virtual_size (App *app) { int req_width, req_height; int min_width, max_width; int min_height, max_height; compute_virtual_size_for_configuration (app->current_configuration, &req_width, &req_height); mate_rr_screen_get_ranges (app->screen, &min_width, &max_width, &min_height, &max_height); #if 0 g_debug ("X Server supports:"); g_debug ("min_width = %d, max_width = %d", min_width, max_width); g_debug ("min_height = %d, max_height = %d", min_height, max_height); g_debug ("Requesting size of %dx%d", req_width, req_height); #endif if (!(min_width <= req_width && req_width <= max_width && min_height <= req_height && req_height <= max_height)) { /* FIXME: present a useful dialog, maybe even before the user tries to Apply */ #if 0 g_debug ("Your X server needs a larger Virtual size!"); #endif } } static void begin_version2_apply_configuration (App *app, GdkWindow *parent_window, guint32 timestamp) { XID parent_window_xid; parent_window_xid = GDK_WINDOW_XID (parent_window); app->proxy = dbus_g_proxy_new_for_name (app->connection, "org.ukui.SettingsDaemon", "/org/ukui/SettingsDaemon/XRANDR", "org.ukui.SettingsDaemon.XRANDR_2"); g_assert (app->proxy != NULL); /* that call does not fail unless we pass bogus names */ app->apply_configuration_state = APPLYING_VERSION_2; app->proxy_call = dbus_g_proxy_begin_call (app->proxy, "ApplyConfiguration", apply_configuration_returned_cb, app, NULL, G_TYPE_INT64, (gint64) parent_window_xid, G_TYPE_INT64, (gint64) timestamp, G_TYPE_INVALID, G_TYPE_INVALID); /* FIXME: we don't check for app->proxy_call == NULL, which could happen if * the connection was disconnected. This is left as an exercise for the * reader. */ } static void begin_version1_apply_configuration (App *app) { app->proxy = dbus_g_proxy_new_for_name (app->connection, "org.ukui.SettingsDaemon", "/org/ukui/SettingsDaemon/XRANDR", "org.ukui.SettingsDaemon.XRANDR"); g_assert (app->proxy != NULL); /* that call does not fail unless we pass bogus names */ app->apply_configuration_state = APPLYING_VERSION_1; app->proxy_call = dbus_g_proxy_begin_call (app->proxy, "ApplyConfiguration", apply_configuration_returned_cb, app, NULL, G_TYPE_INVALID, G_TYPE_INVALID); /* FIXME: we don't check for app->proxy_call == NULL, which could happen if * the connection was disconnected. This is left as an exercise for the * reader. */ } static void ensure_current_configuration_is_saved (void) { MateRRScreen *rr_screen; MateRRConfig *rr_config; /* Normally, mate_rr_config_save() creates a backup file based on the * old monitors.xml. However, if *that* file didn't exist, there is * nothing from which to create a backup. So, here we'll save the * current/unchanged configuration and then let our caller call * mate_rr_config_save() again with the new/changed configuration, so * that there *will* be a backup file in the end. */ rr_screen = mate_rr_screen_new (gdk_screen_get_default (), NULL); /* NULL-GError */ if (!rr_screen) return; rr_config = mate_rr_config_new_current (rr_screen, NULL); mate_rr_config_save (rr_config, NULL); /* NULL-GError */ g_object_unref (rr_config); g_object_unref (rr_screen); } /* Callback for dbus_g_proxy_begin_call() */ static void apply_configuration_returned_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, void *data) { App *app = data; gboolean success; GError *error; g_assert (call_id == app->proxy_call); error = NULL; success = dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID); if (!success) { if (app->apply_configuration_state == APPLYING_VERSION_2 && g_error_matches (error, DBUS_GERROR, DBUS_GERROR_UNKNOWN_METHOD)) { g_error_free (error); g_object_unref (app->proxy); app->proxy = NULL; begin_version1_apply_configuration (app); return; } else { /* We don't pop up an error message; mate-settings-daemon already does that * in case the selected RANDR configuration could not be applied. */ g_error_free (error); } } g_object_unref (app->proxy); app->proxy = NULL; dbus_g_connection_unref (app->connection); app->connection = NULL; app->proxy_call = NULL; gtk_widget_set_sensitive (app->dialog, TRUE); } static gboolean sanitize_and_save_configuration (App *app) { GError *error; mate_rr_config_sanitize (app->current_configuration); check_required_virtual_size (app); foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area)); ensure_current_configuration_is_saved (); error = NULL; if (!mate_rr_config_save (app->current_configuration, &error)) { error_message (app, _("Could not save the monitor configuration"), error->message); g_error_free (error); return FALSE; } return TRUE; } static void apply (App *app) { GError *error = NULL; if (!sanitize_and_save_configuration (app)) return; g_assert (app->connection == NULL); g_assert (app->proxy == NULL); g_assert (app->proxy_call == NULL); app->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (app->connection == NULL) { error_message (app, _("Could not get session bus while applying display configuration"), error->message); g_error_free (error); return; } gtk_widget_set_sensitive (app->dialog, FALSE); begin_version2_apply_configuration (app, gtk_widget_get_window (app->dialog), app->apply_button_clicked_timestamp); } static void on_detect_displays (GtkWidget *widget, gpointer data) { App *app = data; GError *error; error = NULL; if (!mate_rr_screen_refresh (app->screen, &error)) { if (error) { error_message (app, _("Could not detect displays"), error->message); g_error_free (error); } } } static void set_primary (GtkWidget *widget, gpointer data) { App *app = data; int i; MateRROutputInfo **outputs; if (!app->current_output) return; outputs = mate_rr_config_get_outputs (app->current_configuration); for (i=0; outputs[i]!=NULL; i++) { mate_rr_output_info_set_primary (outputs[i], outputs[i] == app->current_output); } gtk_widget_set_sensitive (app->primary_button, !mate_rr_output_info_get_primary(app->current_output)); } #define MSD_XRANDR_SCHEMA "org.ukui.SettingsDaemon.plugins.xrandr" #define SHOW_ICON_KEY "show-notification-icon" #define DEFAULT_CONFIGURATION_FILE_KEY "default-configuration-file" static void on_show_icon_toggled (GtkWidget *widget, gpointer data) { GtkToggleButton *tb = GTK_TOGGLE_BUTTON (widget); App *app = data; g_settings_set_boolean (app->settings, SHOW_ICON_KEY, gtk_toggle_button_get_active (tb)); } static MateRROutputInfo * get_nearest_output (MateRRConfig *configuration, int x, int y) { int i; int nearest_index; int nearest_dist; MateRROutputInfo **outputs; nearest_index = -1; nearest_dist = G_MAXINT; outputs = mate_rr_config_get_outputs (configuration); for (i = 0; outputs[i] != NULL; i++) { int dist_x, dist_y; int output_x, output_y, output_width, output_height; if (!(mate_rr_output_info_is_connected(outputs[i]) && mate_rr_output_info_is_active (outputs[i]))) continue; mate_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height); if (x < output_x) dist_x = output_x - x; else if (x >= output_x + output_width) dist_x = x - (output_x + output_width) + 1; else dist_x = 0; if (y < output_y) dist_y = output_y - y; else if (y >= output_y + output_height) dist_y = y - (output_y + output_height) + 1; else dist_y = 0; if (MIN (dist_x, dist_y) < nearest_dist) { nearest_dist = MIN (dist_x, dist_y); nearest_index = i; } } if (nearest_index != -1) return outputs[nearest_index]; else return NULL; } /* Gets the output that contains the largest intersection with the window. * Logic stolen from gdk_screen_get_monitor_at_window(). */ static MateRROutputInfo * get_output_for_window (MateRRConfig *configuration, GdkWindow *window) { GdkRectangle win_rect; int i; int largest_area; int largest_index; MateRROutputInfo **outputs; #if GTK_CHECK_VERSION (3, 0, 0) gdk_window_get_geometry (window, &win_rect.x, &win_rect.y, &win_rect.width, &win_rect.height); #else gdk_window_get_geometry (window, &win_rect.x, &win_rect.y, &win_rect.width, &win_rect.height, NULL); #endif gdk_window_get_origin (window, &win_rect.x, &win_rect.y); largest_area = 0; largest_index = -1; outputs = mate_rr_config_get_outputs (configuration); for (i = 0; outputs[i] != NULL; i++) { GdkRectangle output_rect, intersection; mate_rr_output_info_get_geometry (outputs[i], &output_rect.x, &output_rect.y, &output_rect.width, &output_rect.height); if (mate_rr_output_info_is_connected (outputs[i]) && gdk_rectangle_intersect (&win_rect, &output_rect, &intersection)) { int area; area = intersection.width * intersection.height; if (area > largest_area) { largest_area = area; largest_index = i; } } } if (largest_index != -1) return outputs[largest_index]; else return get_nearest_output (configuration, win_rect.x + win_rect.width / 2, win_rect.y + win_rect.height / 2); } /* We select the current output, i.e. select the one being edited, based on * which output is showing the configuration dialog. */ static void select_current_output_from_dialog_position (App *app) { if (gtk_widget_get_realized (app->dialog)) { app->current_output = get_output_for_window (app->current_configuration, gtk_widget_get_window (app->dialog)); } else app->current_output = NULL; rebuild_gui (app); } /* This is a GtkWidget::map-event handler. We wait for the display-properties * dialog to be mapped, and then we select the output which corresponds to the * monitor on which the dialog is being shown. */ static gboolean dialog_map_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer data) { App *app = data; select_current_output_from_dialog_position (app); return FALSE; } static gboolean dialog_realize_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer data) { App *app = data; gtk_widget_grab_focus(widget); select_current_output_from_dialog_position (app); return FALSE; } /*static void hide_help_button (App *app) { GtkWidget *action_area; GList *children; GList *l; action_area = gtk_dialog_get_action_area (GTK_DIALOG (app->dialog)); children = gtk_container_get_children (GTK_CONTAINER (action_area)); for (l = children; l; l = l->next) { GtkWidget *child; int response; child = GTK_WIDGET (l->data); response = gtk_dialog_get_response_for_widget (GTK_DIALOG (app->dialog), child); if (response == GTK_RESPONSE_HELP) { gtk_widget_hide (child); return; } } }*/ static void apply_button_clicked_cb (GtkButton *button, gpointer data) { App *app = data; time_t rawtime; /* We simply store the timestamp at which the Apply button was clicked. * We'll just wait for the dialog to return from gtk_dialog_run(), and * *then* use the timestamp when applying the RANDR configuration. */ rawtime = time ( NULL ); if(abs(backup_timestamp-rawtime)>=7)//7s内连续点击无效 { backup_timestamp = rawtime; app->apply_button_clicked_timestamp = gtk_get_current_event_time (); apply (app); } } static void success_dialog_for_make_default (App *app) { GtkWidget *dialog; dialog = gtk_message_dialog_new (GTK_WINDOW (app->dialog), GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, _("The monitor configuration has been saved")); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), _("This configuration will be used the next time someone logs in.")); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } static void error_dialog_for_make_default (App *app, const char *error_text) { error_message (app, _("Could not set the default configuration for monitors"), error_text); } static void make_default (App *app) { char *command_line; char *source_filename; char *dest_filename; char *dest_basename; char *std_error; gint exit_status; GError *error; if (!sanitize_and_save_configuration (app)) return; dest_filename = g_settings_get_string (app->settings, DEFAULT_CONFIGURATION_FILE_KEY); if (!dest_filename) return; /* FIXME: present an error? */ dest_basename = g_path_get_basename (dest_filename); source_filename = mate_rr_config_get_intended_filename (); command_line = g_strdup_printf ("pkexec %s/ukui-display-properties-install-systemwide %s %s", SBINDIR, source_filename, dest_basename); error = NULL; if (!g_spawn_command_line_sync (command_line, NULL, &std_error, &exit_status, &error)) { error_dialog_for_make_default (app, error->message); g_error_free (error); } else if (!WIFEXITED (exit_status) || WEXITSTATUS (exit_status) != 0) { error_dialog_for_make_default (app, std_error); } else { success_dialog_for_make_default (app); } g_free (std_error); g_free (dest_filename); g_free (dest_basename); g_free (source_filename); g_free (command_line); } static GtkWidget* _gtk_builder_get_widget (GtkBuilder *builder, const gchar *name) { return GTK_WIDGET (gtk_builder_get_object (builder, name)); } static int run_application (App *app, GtkBuilder *builder) { GtkWidget *align; GError *error; error = NULL; app->screen = mate_rr_screen_new (gdk_screen_get_default (), &error); g_signal_connect (app->screen, "changed", G_CALLBACK (on_screen_changed), app); if (!app->screen) { error_message (NULL, _("Could not get screen information"), error->message); g_error_free (error); return 0; } app->settings = g_settings_new (MSD_XRANDR_SCHEMA); app->dialog = _gtk_builder_get_widget (builder, "window1"); g_signal_connect_after (app->dialog, "map-event", G_CALLBACK (dialog_map_event_cb), app); /*g_signal_connect (app->dialog, "realize", G_CALLBACK (dialog_realize_event_cb), app);*/ app->current_monitor_event_box = _gtk_builder_get_widget (builder, "current_monitor_event_box"); app->current_monitor_label = _gtk_builder_get_widget (builder, "current_monitor_label"); app->monitor_on_radio = _gtk_builder_get_widget (builder, "radiobutton_display_on"); app->monitor_off_radio = _gtk_builder_get_widget (builder, "radiobutton_display_off"); g_signal_connect (app->monitor_on_radio, "toggled", G_CALLBACK (monitor_on_off_toggled_cb), app); g_signal_connect (app->monitor_off_radio, "toggled", G_CALLBACK (monitor_on_off_toggled_cb), app); app->dispaly_combo = _gtk_builder_get_widget(builder,"combobox_display"); g_signal_connect (app->dispaly_combo, "changed", G_CALLBACK (on_display_changed), app); app->resolution_combo = _gtk_builder_get_widget (builder, "resolution_combo"); g_signal_connect (app->resolution_combo, "changed", G_CALLBACK (on_resolution_changed), app); GtkWidget *label_display = _gtk_builder_get_widget (builder, "label55"); gtk_label_set_xalign(GTK_LABEL(label_display), 0.0); // app->refresh_combo = _gtk_builder_get_widget (builder, "refresh_combo"); // g_signal_connect (app->refresh_combo, "changed", // G_CALLBACK (on_rate_changed), app); app->rotation_combo = _gtk_builder_get_widget (builder, "rotation_combo"); g_signal_connect (app->rotation_combo, "changed", G_CALLBACK (on_rotation_changed), app); app->clone_checkbox = _gtk_builder_get_widget (builder, "checkbutton_display_clone"); g_signal_connect (app->clone_checkbox, "toggled", G_CALLBACK (on_clone_changed), app); // g_signal_connect (_gtk_builder_get_widget (builder, "detect_displays_button"), // "clicked", G_CALLBACK (on_detect_displays), app); app->primary_button = _gtk_builder_get_widget (builder, "primary_button"); g_signal_connect (app->primary_button, "clicked", G_CALLBACK (set_primary), app); // app->show_icon_checkbox = _gtk_builder_get_widget (builder, // "show_notification_icon"); // gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->show_icon_checkbox), // g_settings_get_boolean (app->settings, SHOW_ICON_KEY)); // g_signal_connect (app->show_icon_checkbox, "toggled", G_CALLBACK (on_show_icon_toggled), app); // app->panel_checkbox = _gtk_builder_get_widget (builder, "panel_checkbox"); make_text_combo (app->resolution_combo, 4); // make_text_combo (app->refresh_combo, 3); make_text_combo (app->rotation_combo, -1); make_text_combo (app->dispaly_combo, 2); // g_assert (app->panel_checkbox); /* Scroll Area */ app->area = (GtkWidget *)foo_scroll_area_new (); g_object_set_data (G_OBJECT (app->area), "app", app); set_monitors_tooltip (app, FALSE); /* FIXME: this should be computed dynamically */ foo_scroll_area_set_min_size (FOO_SCROLL_AREA (app->area), -1, 200); gtk_widget_show (app->area); g_signal_connect (app->area, "paint", G_CALLBACK (on_area_paint), app); g_signal_connect (app->area, "viewport_changed", G_CALLBACK (on_viewport_changed), app); align = _gtk_builder_get_widget (builder, "alignment_display"); gtk_container_add (GTK_CONTAINER (align), app->area); /* Until we have help to show, we'll just hide the Help button */ //hide_help_button (app); app->apply_button = _gtk_builder_get_widget (builder, "button_keep_dispaly_setting"); g_signal_connect (app->apply_button, "clicked", G_CALLBACK (apply_button_clicked_cb), app); on_screen_changed (app->screen, app); return 1; } int add_display_app (GtkBuilder * builder) { g_debug("display"); App *app; app = g_new0 (App, 1); return run_application (app, builder); } ukui-control-center/panels/display/org.ukuicc.randr.policy.in0000664000175000017500000000210213253611037023340 0ustar fengfeng UKUI Monitor Preferences http://live.gnome.org/RandR mate-display-properties <_description>Install multi-monitor settings for the whole system <_message>Authentication is required to install multi-monitor settings for all users mate-display-properties no no auth_admin_keep /usr/sbin/ukui-display-properties-install-systemwide ukui-control-center/panels/display/xrandr-capplet.h0000664000175000017500000000165013057175444021451 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute 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 St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include int add_display_app(GtkBuilder * builder); ukui-control-center/panels/display/foo-marshal.c0000664000175000017500000002646613057175444020744 0ustar fengfeng #include #ifdef G_ENABLE_DEBUG #define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) #define g_marshal_value_peek_char(v) g_value_get_char (v) #define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) #define g_marshal_value_peek_int(v) g_value_get_int (v) #define g_marshal_value_peek_uint(v) g_value_get_uint (v) #define g_marshal_value_peek_long(v) g_value_get_long (v) #define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) #define g_marshal_value_peek_int64(v) g_value_get_int64 (v) #define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) #define g_marshal_value_peek_enum(v) g_value_get_enum (v) #define g_marshal_value_peek_flags(v) g_value_get_flags (v) #define g_marshal_value_peek_float(v) g_value_get_float (v) #define g_marshal_value_peek_double(v) g_value_get_double (v) #define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) #define g_marshal_value_peek_param(v) g_value_get_param (v) #define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) #define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) #define g_marshal_value_peek_object(v) g_value_get_object (v) #else /* !G_ENABLE_DEBUG */ /* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. * Do not access GValues directly in your code. Instead, use the * g_value_get_*() functions */ #define g_marshal_value_peek_boolean(v) (v)->data[0].v_int #define g_marshal_value_peek_char(v) (v)->data[0].v_int #define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint #define g_marshal_value_peek_int(v) (v)->data[0].v_int #define g_marshal_value_peek_uint(v) (v)->data[0].v_uint #define g_marshal_value_peek_long(v) (v)->data[0].v_long #define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong #define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 #define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 #define g_marshal_value_peek_enum(v) (v)->data[0].v_long #define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong #define g_marshal_value_peek_float(v) (v)->data[0].v_float #define g_marshal_value_peek_double(v) (v)->data[0].v_double #define g_marshal_value_peek_string(v) (v)->data[0].v_pointer #define g_marshal_value_peek_param(v) (v)->data[0].v_pointer #define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer #define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer #define g_marshal_value_peek_object(v) (v)->data[0].v_pointer #endif /* !G_ENABLE_DEBUG */ /* VOID:OBJECT,OBJECT (marshal.list:1) */ void foo_marshal_VOID__OBJECT_OBJECT (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef void (*GMarshalFunc_VOID__OBJECT_OBJECT) (gpointer data1, gpointer arg_1, gpointer arg_2, gpointer data2); register GMarshalFunc_VOID__OBJECT_OBJECT callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; g_return_if_fail (n_param_values == 3); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_VOID__OBJECT_OBJECT) (marshal_data ? marshal_data : cc->callback); callback (data1, g_marshal_value_peek_object (param_values + 1), g_marshal_value_peek_object (param_values + 2), data2); } /* VOID:UINT,UINT,UINT,UINT (marshal.list:2) */ void foo_marshal_VOID__UINT_UINT_UINT_UINT (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef void (*GMarshalFunc_VOID__UINT_UINT_UINT_UINT) (gpointer data1, guint arg_1, guint arg_2, guint arg_3, guint arg_4, gpointer data2); register GMarshalFunc_VOID__UINT_UINT_UINT_UINT callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; g_return_if_fail (n_param_values == 5); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_VOID__UINT_UINT_UINT_UINT) (marshal_data ? marshal_data : cc->callback); callback (data1, g_marshal_value_peek_uint (param_values + 1), g_marshal_value_peek_uint (param_values + 2), g_marshal_value_peek_uint (param_values + 3), g_marshal_value_peek_uint (param_values + 4), data2); } /* VOID:UINT,UINT (marshal.list:3) */ void foo_marshal_VOID__UINT_UINT (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef void (*GMarshalFunc_VOID__UINT_UINT) (gpointer data1, guint arg_1, guint arg_2, gpointer data2); register GMarshalFunc_VOID__UINT_UINT callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; g_return_if_fail (n_param_values == 3); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_VOID__UINT_UINT) (marshal_data ? marshal_data : cc->callback); callback (data1, g_marshal_value_peek_uint (param_values + 1), g_marshal_value_peek_uint (param_values + 2), data2); } /* VOID:BOXED (marshal.list:4) */ /* VOID:BOXED,BOXED (marshal.list:5) */ void foo_marshal_VOID__BOXED_BOXED (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef void (*GMarshalFunc_VOID__BOXED_BOXED) (gpointer data1, gpointer arg_1, gpointer arg_2, gpointer data2); register GMarshalFunc_VOID__BOXED_BOXED callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; g_return_if_fail (n_param_values == 3); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_VOID__BOXED_BOXED) (marshal_data ? marshal_data : cc->callback); callback (data1, g_marshal_value_peek_boxed (param_values + 1), g_marshal_value_peek_boxed (param_values + 2), data2); } /* VOID:POINTER,BOXED,POINTER (marshal.list:6) */ void foo_marshal_VOID__POINTER_BOXED_POINTER (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef void (*GMarshalFunc_VOID__POINTER_BOXED_POINTER) (gpointer data1, gpointer arg_1, gpointer arg_2, gpointer arg_3, gpointer data2); register GMarshalFunc_VOID__POINTER_BOXED_POINTER callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; g_return_if_fail (n_param_values == 4); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_VOID__POINTER_BOXED_POINTER) (marshal_data ? marshal_data : cc->callback); callback (data1, g_marshal_value_peek_pointer (param_values + 1), g_marshal_value_peek_boxed (param_values + 2), g_marshal_value_peek_pointer (param_values + 3), data2); } /* VOID:POINTER,POINTER (marshal.list:7) */ void foo_marshal_VOID__POINTER_POINTER (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef void (*GMarshalFunc_VOID__POINTER_POINTER) (gpointer data1, gpointer arg_1, gpointer arg_2, gpointer data2); register GMarshalFunc_VOID__POINTER_POINTER callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; g_return_if_fail (n_param_values == 3); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_VOID__POINTER_POINTER) (marshal_data ? marshal_data : cc->callback); callback (data1, g_marshal_value_peek_pointer (param_values + 1), g_marshal_value_peek_pointer (param_values + 2), data2); } ukui-control-center/panels/display/scrollarea.h0000664000175000017500000001100113057175444020643 0ustar fengfeng/* Copyright 2006, 2007, 2008, Soren Sandmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #define FOO_TYPE_SCROLL_AREA (foo_scroll_area_get_type ()) #define FOO_SCROLL_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FOO_TYPE_SCROLL_AREA, FooScrollArea)) #define FOO_SCROLL_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), FOO_TYPE_SCROLL_AREA, FooScrollAreaClass)) #define FOO_IS_SCROLL_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FOO_TYPE_SCROLL_AREA)) #define FOO_IS_SCROLL_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FOO_TYPE_SCROLL_AREA)) #define FOO_SCROLL_AREA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), FOO_TYPE_SCROLL_AREA, FooScrollAreaClass)) typedef struct FooScrollArea FooScrollArea; typedef struct FooScrollAreaClass FooScrollAreaClass; typedef struct FooScrollAreaPrivate FooScrollAreaPrivate; typedef struct FooScrollAreaEvent FooScrollAreaEvent; typedef enum { FOO_BUTTON_PRESS, FOO_BUTTON_RELEASE, FOO_MOTION } FooScrollAreaEventType; struct FooScrollAreaEvent { FooScrollAreaEventType type; int x; int y; }; typedef void (* FooScrollAreaEventFunc) (FooScrollArea *area, FooScrollAreaEvent *event, gpointer data); struct FooScrollArea { GtkContainer parent_instance; FooScrollAreaPrivate *priv; }; struct FooScrollAreaClass { GtkContainerClass parent_class; void (*set_scroll_adjustments) (FooScrollArea *scroll_area, GtkAdjustment *hadjustment, GtkAdjustment *vadjustment); void (*viewport_changed) (FooScrollArea *scroll_area, GdkRectangle *old_viewport, GdkRectangle *new_viewport); void (*paint) (FooScrollArea *scroll_area, cairo_t *cr, GdkRectangle *extents, cairo_region_t *region); }; GType foo_scroll_area_get_type (void); FooScrollArea *foo_scroll_area_new (void); /* Set the requisition for the widget. */ void foo_scroll_area_set_min_size (FooScrollArea *scroll_area, int min_width, int min_height); /* Set how much of the canvas can be scrolled into view */ void foo_scroll_area_set_size (FooScrollArea *scroll_area, int width, int height); void foo_scroll_area_set_size_fixed_y (FooScrollArea *scroll_area, int width, int height, int old_y, int new_y); void foo_scroll_area_set_viewport_pos (FooScrollArea *scroll_area, int x, int y); void foo_scroll_area_get_viewport (FooScrollArea *scroll_area, GdkRectangle *viewport); void foo_scroll_area_add_input_from_stroke (FooScrollArea *scroll_area, cairo_t *cr, FooScrollAreaEventFunc func, gpointer data); void foo_scroll_area_add_input_from_fill (FooScrollArea *scroll_area, cairo_t *cr, FooScrollAreaEventFunc func, gpointer data); void foo_scroll_area_invalidate_region (FooScrollArea *area, cairo_region_t *region); void foo_scroll_area_invalidate (FooScrollArea *scroll_area); void foo_scroll_area_invalidate_rect (FooScrollArea *scroll_area, int x, int y, int width, int height); void foo_scroll_area_begin_grab (FooScrollArea *scroll_area, FooScrollAreaEventFunc func, gpointer input_data); void foo_scroll_area_end_grab (FooScrollArea *scroll_area); gboolean foo_scroll_area_is_grabbed (FooScrollArea *scroll_area); void foo_scroll_area_begin_auto_scroll (FooScrollArea *scroll_area); void foo_scroll_area_auto_scroll (FooScrollArea *scroll_area, FooScrollAreaEvent *event); void foo_scroll_area_end_auto_scroll (FooScrollArea *scroll_area); ukui-control-center/panels/display/TODO0000664000175000017500000006272613057175444017057 0ustar fengfengHighlevel overview: Tablet rotation things only when there is a tablet attached. Here is the OS X Display menu: Detect Displays Turn on mirroring -------------------------- SyncMaster - 1280 x 1024, 60 Hz, Millions - 1344 x ... -------------------------------- Color LCD - 1024 x 1024 ... -------------------------- Displays Preferences Color LCD means "laptop panel". - GTK+ work. Allow applications to be notified whenever monitors are added or removed. Allow applications to get more detailed information about the connected monitors. The main complication is that XRRGetScreenResources() is very slow. We could call it only when the X server sends an event, but it's not desirable to have every application freeze for half a second. And certainly not desirable to have the X server block for n * 0.5 seconds. With the X server work below we should be fine just calling XRRGetScreenResources on startup and in response to events. - X server work: X server needs to poll for whether a monitor is plugged in. Whenever it detects a change, it should do an EDID query, and cache the resulting information. That way XRRGetScreenResources() can be the speed of a normal roundtrip. It's desirable that normal client requests can still be processed during the EDID querying, but only a nice-to-have. Drivers need to work reliably. There could be substantial work here. For F9, possibly only the Intel driver can be made to work. Interrupts and events must be generated whenever something changes about the outputs, if necessary by polling. Events must be emitted whenever something changes, including when the reason for the change is a manual change. The maximum framebuffer must be dynamically changable. - Control panel work: Capplet needs to be written. The main complications: - It needs to pay attention to events from the X server and update itself, ie., add show new monitors if they become available when the applet is shown. - It needs to store information under a key computed from a monitor identifier. The complication here is that it's not completely clear how to do this in MateConf. - Would probably be worthwhile to drop libmate/libmateui from the craplets. - Marco work: - Marco is already Xinerama aware, but it needs to update itself when monitors come and go. - MATE panel work: - Is already Xinerama aware, but needs to listen and update itself when monitors change. - Evince work: - Make sure it deals sensibly with multiple monitors - OpenOffice work: - Make sure it deals sensibly with multiple monitors - An Xlib call to just return all the available information would be useful. At the moment we have to do a bunch of roundtrips to get the information. This is a would-be-nice though. - A dbus service could be written that pops up the applet whenever a monitor. It should only pop up if the new monitor is unknown. This is at best a nice-to-have, and low priority in my opinion. ******************* Marco Havoc: > I was just talking to bryan about this and "helping" him design it ;-) > But I wanted to be sure and lobby for a fix window managers > need. Basically right now the WM can't tell "physical" from > "logical" monitors. > A "logical" monitor is a desktop; it has its own panel, windows > maximize to it, etc. > A "physical" monitor is a piece of hardware. > Sometimes people want to combine physical monitors into a video wall > or just two monitors treated as one. Or at least a couple of noisy > people in bugzilla want to do this. > When people talk about a "Xinerama aware" app or WM they usually > mean that all physical monitors are treated as logical monitors, > while lack of Xinerama-aware means treating the entire X screen (all > physical monitors) as one logical monitor. > The problem is that the setting for "ignore Xinerama" or "don't be > Xinerama aware" should be global to the desktop (GTK, all apps, WM) > and should not be a window manager setting. > Bryan thought people who wanted non-Xinerama-aware should just use > fvwm, which may be right, but what I'd say is that if there is any > setting for this, it should be desktop-global and in this monitor > config dialog. > It should not be a marco or Compiz option, but in some way an X > option in short. The implementation could be either an X server > feature or an EWMH hint or whatever, but it should be controlled by > the monitor config dialog and used by apps, GTK, etc. in addition to > used by the WM. > People tend to insist this should be a WM option, but that's just > busted, since GTK and apps also have Xinerama-awareness features. ******************* EDID edid-decode enhancements: - Rejects years <= 0x0f for all versions, but this should only be done for monitors claiming conformance to 1.4 (since 1.4 was released in 2006). A monitor produced in 2005 should have 0x0f - it's the only reasonable thing to do. - Uses 0x80 as the conformance mask for 1.4, should be 0 - Should read from stdin - Should parse xrandr -verbose output more robustly - Color depth computation is wrong. It uses the formula (edid[0x14] >> 3) + 2 The correct formula to use is (edid[0x14] & 0x70) >> 3 + 4 - -=-=-=- Computing a display name from EDID information: vendor = lookup_vendor (code); if (dsc_product && !is_gobbledigook (dsc_product)) { if (vendor && !fuzzy_string_search (vendor, dsc_product)) prepend (vendor); } else { if (vendor) append (vendor); else append ("Unknown"); } if (has size) { convert_to_inches() append (" %d\"", inches) } (Does this internationalize at all)? We also need the ability to get laptop names. The laptop panel may report a manufacturer that has nothing to do with the laptop manufacturer. Needed XRandr output properties: - Modes that the monitor supports, or enough information that the client can go throught the list of modes for the relevant CRTC/Outputs and filter those out that the monitor can't support. - The preferred mode, if any. Also useful if we could get a "strongly preferred" indication if it's an LCD with a fixed resolution. - Sufficient information that a fairly specific identifier can be computed. The algorithm the client should use is: 1 Have we seen exactly this monitor before? If yes, use settings for that. 2 Have we seen a monitor with similar specs before? If yes, use settings for that. (But don't save, unless the user changes the settings). 3 Otherwise, use some reasonable default for the monitor and save it. A setting should only be used if the CRTC/Output allows it. Ie,. if a user has installed a new video card, then previously-used settings may no longer apply, so this must be checked every time. (1) Implies that we really need a globally unique identifier for monitors. (2) is useful in an enterprise setting, but not absolutely critical, since (3) would still handle the majority of cases. There is a question here: Where are machine specific preferences stored? Havoc mentions three possibilities here: http://mail.gnome.org/archives/matecc-list/2001-October/msg00023.html I'm not sure if any of them are implementable at this point. Also (1) may mostly take care of the problem. Usecases: 1. Fixed setup with some number of monitors. - They should be set to the correct mode on login. Note that this involves setting the right position in the framebuffer too. What if someone swaps two monitors? Users are going to expect that the images will switch position. 2. Laptop being moved between home and work - Setups should be detected and the correct mode set, at least on login, but ideally when you put the laptop into the docking station. 3. Laptop gets projector plugged in. Note the same model monitor can be used in two different ways. Ie., at home, it's being used at one resolution, at work the same type of monitor is used at a different resolution. Simple solution: - The on-disk database is just a list of monitors. Each monitor has an associated mode. This has these problems: - If someone uses the same monitor model in two different ways. - If someone swaps the monitors around Better solution - The on-disk database is a list of configurations, where a configuration is a list of monitors and what outputs they are connected to, and the position in the framebuffer. - Picking a default configuration is then a matter of selecting the closest existing configuration from the database. - If the stored configuration is a subset of the existing, then use that - then pick the best mode available for the rest of the monitors - If the stored configuration is a superset of the existing, then use the projection of the configuration onto the monitors. - Pick the configuration with the most overlap in monitors. Although, if a configuration differs only in what outputs they are connected to, then those outputs should probably get their original modes set. - Or maybe simply: - If there is an exact match, use it, if not, pick a default. - Picking a new default must never change the mode of any existing output. ******************* Capplet Somehow the applet will find out that a new monitor is plugged in (either through notification, or through a refresh button). When this happens, this monitor is looked up in a database and if it is found, some suitable mode is set. Restrictions on the modes: - Monitors that are already plugged in should not get their mode changed just because a new monitor is plugged in. - If the exact configuration of monitors is known, and all the old monitors have the same mode as the known configuration, then just use the known configuration. Also do this, if the configuration is a subset of something known. - Otherwise, if the configuration is a subset of a known configuration where the only difference is that existing monitors have different modes, then try and convert that mode to something we can know about. Maybe configurations should be stored in terms of edges that line up. - Otherwise, just pick some good default for the mode, probably based on the EDID prferred mode if possible. By default cloning is probably best. - How do virtual desktops interact with this? g-s-d: - On startup - It reads the configuration file into memory capplet --configure - It gathers the existing configuration from randr - If the existing config is in the file, set that mode - On changes, including changes to the config file [this is crack] - Reread configuration file - Compare new configuration to database, if it is there, set the mode as appropriate - If a monitor was added, pop up a bubble capplet --show-bubble capplet --set-mode capplet - On changes - Update GUI - When user changes something, - Write configuration to file - Signal gsd somehow Schemes: - configuration file changes - randr code will have to be shared between gcc and gsd - binary installed by gcc - something will still have to listen for changes to pop up the notification bubble. Structure of capplet: - There is a database on disk with monitors and their corresponding settings. - On startup, this database is read into memory. When the user accepts new settings, it is written back to disk. - When something changes about the settings - If new configuration is in the database, use that mode - Else, find all outputs that are now connected but weren't before, and set a default mode for them. - If GUI is running, update graphics. - Notification thing: - if - if the new configuration is found in the database, use it and added if they are not already there. Initial settings are 1 what the output is already doing, if anything 2 based on an existing sufficiently similar monitor, if possible 3 some reasonable default. - When the user changes settings in the GUI, the corresponding monitor in the database is updated. - Whenever the GUI settings change, for all displayed monitors the possible modes are recomputed. - Whenever a new monitor is selected in the GUI, it first gets all its possible modes computed based on the selections on other outputs. Then, if the possible modes include the existing choice of resolution, that is selected. Actually, - initially, the settings are copied from the current settings - whenever a gui setting changes for a monitor, all the other monitors get their list of choices set to whatever is possible given the chocie for the current monitor. A 'desired mode' is maintained, and the closest choice to that is displayed. Whenever the user actively selects something, that becomes the desired mode for that monitor. - Required - Generate all outputs that are newly connected foreach_newly_connected (Configuration *before, Configuration *after, OutputFunc); - A way to generate the best mode for a connected output existing best_mode() can probably be used - Given a list of modes, pick the one closest to a given mode. (a possibility here is: pick an exact match, if that's impossible, then pick the best one with the same width/height, if that's impossible, then just pick the best mode on the list). - For a configuation, fix the mode for a subset of the outputs, then list the combinations for the rest of the outputs. An obvious possibility here is to simply list all possibilities, then weed out those that don't work. Is this too expensive? It might be. Structure of login time program: - The configuration database is read - The current hardware configuration is generated - If the current configuration is found in the database, that mode is set. - If it isn't found, then nothing changes. This could just be mate-screen-resolution-capplet --reset ******************* Things that need to be done to the xrandr.patch: === XRRGetScreenResources() is a roundtrip and very slow (~0.5 s). GTK+ needs to keep information up-to-date by tracking events rather than calling this function. In fact we probably can't call it at all unless its performance improves significantly. If EDID processing really has to be this slow, and we can't get interrupts when monitors are plugged in, then we have a problem, because we can't do anything this expensive once per second. Detailed notes (but most of the patch should be rewritten): === FIXME in gdkscreen-x11.c in get_width_mm() /* monitor pixel width / screen pixel width * screen_physical width */ === Check for 1.2 library The patch should check that the 1.2 version of the XRandR library is available before using the functions. A possibility is to not use any RandR unless 1.2 is available, another is to conditionalize the code. The most sane thing is probably to just require 1.2. On the other hand, installing a newer gtk+ on a system with older X is probably not that unusual, so maybe it's better to do the full 1.0, vs. 1.1 vs 1.2 check. For now it just requires 1.2. Actually, this might be fine because the only place where we make use of a 1.1 library is in the _gdk_x11_screen_size_changed() function, but there we have a fallback that just updates the variables in the Screen struct itself. So, only defining HAVE_RANDR if we detect 1.2 should be ok. === Monitor information available - Subpixel information. This should be set automatically for the fonts and store under the name of the monitor. If the user changes the font configuration, that change should also be stored under the monitor name. - When a monitor we don't know about is plugged in, a configuration should be generated: - Screen size, computed based on the location of the screens - RGBA information - Whether the screen has a panel on it - If there is a conflict between stored information and EDID, the stored information wins New API so far: (* monitors_changed) signal gdk_screen_get_monitor_width_mm() gdk_screen_get_monitor_height_mm() gdk_screen_get_monitor_name() => Note this is the output (eg. "DVI-0") We should probably also have get_manufacturer() get_serial() get_resolutions() etc. Should there be a GdkMonitor object that would correspond to an output? Or maybe GdkOutput? screen_list_monitors() *************************** Issues XRandR/Xserver - We need polling in the X server, whenever something changes, X must recompute the information and cache it, then send an event. Note the situation where the user disconnects and reconnects a monitor within the polling interval. The event could missed in that case since the polling cannot do a full EDID query. Difficult to see a way around this. Actually, DDC allows random access, so it should be possible to just read theq vendor id and manufacturer codes. This can be done once a second without a problem. The polling should be turned off in power saving mode anyway. - Driver work: - Intel driver: - EDID information is not reported for VGA when the output is not turned on (i945 laptop). - Screen size must be dynamically changable. (No xorg.conf changes should be required). - Make use of ACPI information when possible. Adam has code on his freedesktop page. - i830 laptop can be put in a state where XRandr reports that no outputs are connected to a CRTC, but the panel is on. - Plug in VGA - xrandr --auto - xrandr --output VGA --off - run chk - xrandr --verbose will now not report any outputs as turned on - run chk again - all screens will be turned off - Small Sun monitor - an 1152x921 mode is generated, but the monitor doesn't handle that. The monitor itself only claims to handle 1152x920. It doesn't look to me like there is anything in the EDID information that would indicate that it could handle 1152x921. This happens with a radeon as wellso it may be a bug in the generic X server EDID parsing. The X server apparently interpretes the standard timing 1152x920 as 1152x921. This happens because the X server uses hsize * 4 / 5 which gives 921 for 1152. By using (hsize / 5) * 4 you get 920. The 66 Hz version can bet set, the 76 Hz mode gets sync out of range. (Would be interesting to find out whether the 1152x920 ModeLine would allow the 76 Hz version to be set). This is for the ATI driver as shipped in F8: - XRRGetScreenResources() takes half a second. - Adam has now removed a workaround that caused some of the slowdown. - If a DVI monitor is disconnected, you get "Unknown" for connection status. - If a VGA monitor is plugged in, then EDID information is not available, even after running xrandr --verbose. The monitor has to be plugged in at driver startup time, apparently. - Logging out and logging back in often results in some random mode being set. We need mode selection to not be completely screwed up. Currently it is. - The set up at server startup needs to be fixed. *If* randr actually works, then we might be able to do something sensible. - We need to revisit the idea that many monitors have broken EDID data. This may be less widespread than previously believed. - It may be useful to return the connector names as identifiers instead of relying on UTF-8 strings. Ie., have an enum { UNKNOWN, OTHER, DVI, VGA, HDMI, ..., } in addition to the string. The difference between UNKNOWN and OTHER is that UNKNOWN means the driver doesn't know, whereas OTHER means it is something not listed in the enum (which could be listed in a later version). - Mouse cursor should be confined to the visible area. (It is already, I think) - It looks like EDID information is only available for one output even though it is actually read according to the log file. (nv, intel drivers) ********************************* DONE: Server work: - i830 laptop incorrectly reports BadMatch when you configure the CRTC to drive both VGA and LVDS with the 1024x768 mode that both outputs can handle. (It should return 'failed' if it can't do that). Same for i945 laptop. It seems as if the same CRTC can't drive more than one output at the same time on Intel. This was a client bug, but the documentation for SetCrtcConfig should say that BadMatch will be returned if the outputs aren't clones. GTK+ patch is in now. === Add helper function + if (screen_x11->randr12) + { + XRRScreenResources *sr; + XRROutputInfo *output; + gchar *retval; + + sr = XRRGetScreenResources ( screen_x11->xdisplay, + screen_x11->xroot_window ); + + output = XRRGetOutputInfo ( screen_x11->xdisplay, + sr, + (RROutput)screen_x11->act_outputs[monitor_num] ); Might be worthwhile to factor this out into a gdk_screen_get_output_info (screen, monitor_num) helper function ? Instead of cutting and pasting all over creation * Calling XRRGetScreenResources all the time is not going to fly. It takes hundreds of milliseconds ... Even if it didn't, it wouldn't be acceptable to do all those roundtrips. === Some g_prints left === Version check Should be (maj > 1) || (maj == 1 && min >= 2) === Grep for TODO === Setup XRRSelectInput() You should call XRRSelectInput() at the same place where you are calling XSelectInput() right now. The right place to handle the XRandr events is the huge switch in gdkevents-x11.c:gdk_event_translate Check out how other extension events are handled there, like XKB, or XFixes. === Lots of variable naming issues, such as act_output and noutput === Needs to select the input, and hook it up to the signal === Add version markers to API === API to turn monitors on and off? - DPMS not exposed through randr, maybe should be - DPMS is presumably a property of either an output or a CRTC. Logically it's an output. - Need events when DPMS happens. Exposing the "screen saving on" on dbus may not be good enough. === Why does init_multihead_support() start by freeing monitors and outputs? === Do we disable Xinerama support entirely when 1.2 is in use? === We should expose information about what parts of the screen monitors are viewing. === Make use of the EDID information? -- details for X server -- In nv driver SorSetOutputProperty should return TRUE for unknown properties. (Like the Intel driver does). Detecting plugged in - Periodically poll - - One ddc probe takes 5 ms, according to a comment in the intel driver. Running this twice a second would mean spending 1% of overall time doing ddc polling, which is almost certainly not acceptable. 1) Async I2C: void I2CProbeAsync(..., callback, data); Bool I2CPending() void I2CUpdate() In Dispatch, call I2CUpdate() Before going idle, do while (I2CPending()) I2CUpdate() Would need RegisterDispatchFunction() (Is this called Wakeup?) RegisterIdleFunction() Note the idle function should have the option of saying: "check if something else happened; if not, call me again" and "ok, I'm done - go idle". Otherwise, we would be blocking for 5 ms whenever the X server went idle. So actually the idle function should be if (I2CPending()) { I2CUpdate(); return TRUE; /* call me again */ } else { return FALSE; /* I'm done */ } What happens if another I2C requests come in while an async one is pending? Most likely we simply finish whatever is going on, then process the new request. What happens if an X request takes so long that we get timeouts on the i2c bus? Good question. Need to read the VESA ddc spec. 2) Run the polling in a separate thread. Probably crack. 3) Run the polling less, maybe once every three seconds. -- details for control panel -- Screen changes - Currently it is polling via rw_screen_refresh(), which will always emit a screen-changed event. In reponse to this event the capplet currently checks whether anything changed physically about the setup. This means the capplet can't react to external changes to modes. On the other hand if it didn't Disallow combinations that would exceed the screen ranges. - Note rotations Give rw objects stable positions in memory so that they can be cached across screen_changed events. Add Clone Mode Drag and drop for the monitors - 2 dimensional layout Store make and model in monitors.xml, then if serial numbers don't match, fall back to a make and model match. Users with an nfs mounted home directory should not have to reconfigure for each new system they log in to. Make sure text is scaled correctly Need to sanitize naming RWOutput vs Output - should probably be OutputInfo rate vs. freq - decide on one Should probably reconsider the use of null terminated arrays. Maybe lists would be better. Pick a fixed scale, so that two 1024x768 don't look like two 6x4. - An alternative would be to draw a checkerboard pattern below the monitors. done: Add rotation Disable panel checkbox for now Patch into mate-desktop Find out how to share code between gcc and gsd Make it assign coordinates correctly - including computing correct screen size ukui-control-center/panels/display/ukui-display-properties-install-systemwide.c0000664000175000017500000001621113253611037027157 0ustar fengfeng/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * ukui-display-properties-install-systemwide - Install a RANDR profile for the whole system * * Copyright (C) 2010 Novell, Inc. * Copyright (C) 2016 Tianjin KYLIN Information Technology Co., Ltd. * * Authors: Federico Mena Quintero * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute 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. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #define SYSTEM_RANDR_PATH "/etc/ukui-settings-daemon/xrandr" static void usage (const char *program_name) { g_print (_("Usage: %s SOURCE_FILE DEST_NAME\n" "\n" "This program installs a RANDR profile for multi-monitor setups into\n" "a systemwide location. The resulting profile will get used when\n" "the RANDR plug-in gets run in ukui-settings-daemon.\n" "\n" "SOURCE_FILE - a full pathname, typically /home/username/.config/monitors.xml\n" "\n" "DEST_NAME - relative name for the installed file. This will get put in\n" " the systemwide directory for RANDR configurations,\n" " so the result will typically be %s/DEST_NAME\n"), program_name, SYSTEM_RANDR_PATH); } static gboolean is_basename (const char *filename) { if (*filename == '\0') return FALSE; /* no empty strings, please */ for (; *filename; filename++) if (G_IS_DIR_SEPARATOR (*filename)) return FALSE; return TRUE; } static gboolean copy_file (int source_fd, int dest_fd) { char buf[1024]; int num_read; int num_written; while (TRUE) { char *p; num_read = read (source_fd, buf, sizeof (buf)); if (num_read == 0) break; if (num_read == -1) { if (errno == EINTR) continue; else return FALSE; } p = buf; while (num_read > 0) { num_written = write (dest_fd, p, num_read); if (num_written == -1) { if (errno == EINTR) continue; else return FALSE; } num_read -= num_written; p += num_written; } } return TRUE; } /* This is essentially a "please copy a file to a privileged location" program. * We try to be paranoid in the following ways: * * - We copy only regular files, owned by the user who called pkexec(1), to * avoid attacks like "copy a file that I'm not allowed to read into a * world-readable location". * * - We copy only to a well-known directory. * * - We try to avoid race conditions. We only fstat() files that we have open * to avoid files moving under our feet. We only create files in directories * that we have open. * * - We replace the destination file atomically. */ int main (int argc, char **argv) { uid_t uid, euid; const char *source_filename; const char *dest_name; const char *pkexec_uid_str; int pkexec_uid; struct stat statbuf; int err; int source_fd; int dest_fd; char template[100]; setlocale (LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); /* We only run as root */ uid = getuid (); euid = geteuid (); if (uid != 0 || euid != 0) { /* Translators: only able to install RANDR profiles as root */ g_print ("%s\n", _("This program can only be used by the root user")); return EXIT_FAILURE; } /* Usage: gsd-xrandr-install-systemwide SOURCE_FILE DEST_NAME */ if (argc != 3) { usage (argv[0]); return EXIT_FAILURE; } source_filename = argv[1]; dest_name = argv[2]; /* Absolute source filenames only, please */ if (!g_path_is_absolute (source_filename)) { g_print ("%s\n", _("The source filename must be absolute")); return EXIT_FAILURE; } /* We only copy regular files */ source_fd = open (source_filename, O_RDONLY); if (source_fd == -1) { err = errno; /* Translators: first %s is a filename; second %s is an error message */ g_print (_("Could not open %s: %s\n"), source_filename, g_strerror (err)); return EXIT_FAILURE; } if (fstat (source_fd, &statbuf) != 0) { err = errno; /* Translators: first %s is a filename; second %s is an error message */ g_print (_("Could not get information for %s: %s\n"), source_filename, g_strerror (err)); return EXIT_FAILURE; } if (!S_ISREG (statbuf.st_mode)) { g_print (_("%s must be a regular file\n"), source_filename); return EXIT_FAILURE; } /* We only copy files that are really owned by the calling user */ pkexec_uid_str = g_getenv ("PKEXEC_UID"); if (pkexec_uid_str == NULL) { g_print ("%s\n", _("This program must only be run through pkexec(1)")); return EXIT_FAILURE; } if (sscanf (pkexec_uid_str, "%d", &pkexec_uid) != 1) { g_print ("%s\n", _("PKEXEC_UID must be set to an integer value")); return EXIT_FAILURE; } if (statbuf.st_uid != pkexec_uid) { /* Translators: we are complaining that a file must be really owned by the user who called this program */ g_print (_("%s must be owned by you\n"), source_filename); return EXIT_FAILURE; } /* We only accept basenames for the destination */ if (!is_basename (dest_name)) { /* Translators: here we are saying that a plain filename must look like "filename", not like "some_dir/filename" */ g_print (_("%s must not have any directory components\n"), dest_name); return EXIT_FAILURE; } /* Chdir to the destination directory to keep it open... */ if (chdir (SYSTEM_RANDR_PATH) != 0) { g_print (_("%s must be a directory\n"), SYSTEM_RANDR_PATH); return EXIT_FAILURE; } /* ... and open our temporary destination file right there */ strcpy (template, "gsd-XXXXXX"); dest_fd = g_mkstemp_full (template, O_WRONLY, 0644); if (dest_fd == -1) { err = errno; /* Translators: the first %s/%s is a directory/filename; the last %s is an error message */ g_print (_("Could not open %s/%s: %s\n"), SYSTEM_RANDR_PATH, template, g_strerror (err)); return EXIT_FAILURE; } /* Do the copy */ if (!copy_file (source_fd, dest_fd)) { /* If something went wrong, remove the destination file to avoid leaving trash around */ unlink (template); return EXIT_FAILURE; } /* Rename to the final filename */ if (rename (template, dest_name) != 0) { err = errno; unlink (template); g_print (_("Could not rename %s to %s: %s\n"), template, dest_name, g_strerror (err)); return EXIT_FAILURE; } /* Whew! We'll leave the final closing of the files to the almighty kernel. */ return EXIT_SUCCESS; } ukui-control-center/panels/display/foo-marshal.h0000664000175000017500000000630113057175444020733 0ustar fengfeng #ifndef __foo_marshal_MARSHAL_H__ #define __foo_marshal_MARSHAL_H__ #include #ifdef __cplusplus extern "C" { #endif /* VOID:OBJECT,OBJECT (marshal.list:1) */ extern void foo_marshal_VOID__OBJECT_OBJECT (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); /* VOID:UINT,UINT,UINT,UINT (marshal.list:2) */ extern void foo_marshal_VOID__UINT_UINT_UINT_UINT (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); /* VOID:UINT,UINT (marshal.list:3) */ extern void foo_marshal_VOID__UINT_UINT (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); /* VOID:BOXED (marshal.list:4) */ #define foo_marshal_VOID__BOXED g_cclosure_marshal_VOID__BOXED /* VOID:BOXED,BOXED (marshal.list:5) */ extern void foo_marshal_VOID__BOXED_BOXED (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); /* VOID:POINTER,BOXED,POINTER (marshal.list:6) */ extern void foo_marshal_VOID__POINTER_BOXED_POINTER (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); /* VOID:POINTER,POINTER (marshal.list:7) */ extern void foo_marshal_VOID__POINTER_POINTER (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); #ifdef __cplusplus } #endif #endif /* __foo_marshal_MARSHAL_H__ */ ukui-control-center/man/0000775000175000017500000000000013263647163014177 5ustar fengfengukui-control-center/man/ukui-display-properties-install-systemwide.10000664000175000017500000000365413253611037024730 0ustar fengfeng.\" Copyright (C) 2014 Mike Gabriel .\" .\" This is free software; you may redistribute it and/or modify .\" it under the terms of the GNU General Public License as .\" published by the Free Software Foundation; either version 2, .\" or (at your option) any later version. .\" .\" This is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 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. .TH ukui-display-properties-install-systemwide 1 "2017\-03\-06" "UKUI" .\" .SH "NAME" ukui-display-properties-install-systemwide \- customize UKUI display behavor .SH "SYNOPSIS" .B ukui-display-properties-install-systemwide \fI \fR .SH "DESCRIPTION" This executable is part of the package 'ukui\-control\-center': The UKUI Control Center. .PP This command line tool installs a RANDR profile for multi-monitor setups into a systemwide location. The resulting profile will get used when the RANDR plug-in gets run in \fBukui-settings-daemon\fR. .TP \fI\fR a full pathname, typically /home/username/.config/monitors.xml .TP \fI\fR relative name for the installed file. This will get put in the systemwide directory for RANDR configurations, so the result will typically be /etc/ukui-settings-daemon/xrandr/DEST_NAME .SH AUTHORS This manual page was writtenby Mike Gabriel for the Debian project (but may be used by others). .SH "SEE ALSO" .PP Latest version of the UKUI Desktop User Guide for your platform. .PP .BR "ukui-control-center" (1), .BR "ukui-display-properties" (1), .BR "ukui-settings-daemon" (1), ukui-control-center/man/Makefile.am0000664000175000017500000000022313057446637016234 0ustar fengfengman_MANS = \ ukui-control-center.1 \ ukui-display-properties-install-systemwide.1 EXTRA_DIST = $(man_MANS) -include $(top_srcdir)/git.mk ukui-control-center/man/ukui-control-center.10000664000175000017500000000545013057446637020202 0ustar fengfeng.\" Copyright (C) 2014 Vangelis Mouhtsis .\" .\" This is free software; you may redistribute it and/or modify .\" it under the terms of the GNU General Public License as .\" published by the Free Software Foundation; either version 2, .\" or (at your option) any later version. .\" .\" This is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 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. .TH ukui-control-center 1 "2014\-05\-02" "UKUI" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/734663 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" ukui-control-center \- Configure UKUI settings .SH "SYNOPSIS" .B ukui-control-center .RI [ OPTION... ] .SH "DESCRIPTION" .PP \fBukui\-control\-center\fR is a graphical user interface to configure various aspects of UKUI. .PP When run without arguments, the shell displays the control center overview, which shows all available configuration panels\&. The overview allows one to open individual panels by clicking on them\&. It also has a search entry to find panels by searching keywords\&. .SH "OPTIONS" .TP \fB\-?\fR, \fB\-\-help\fR Print the application's help options and exit. .TP \fB\-\-help-gtk\fR Print GTK help options and exit. .TP \fB\-\-help-all\fR Print application and GTK help options and exit. .TP \fB\-\-hide\fR Hide on start (useful for preloading the shell). .TP \fB\-\-display=DISPLAY\fR X display to use. .PP This program additionally accepts the standard UKUI and GTK options (as listed with \fI\-\-help\-gtk\fR). .SH "EXIT STATUS" .PP On success 0 is returned, a non\-zero failure code otherwise\&. .SH "AUTHORS" .PP This manual page has been adopted for UKUI Desktop Environment by xiaoyiwu \&. ukui-control-center/data/0000775000175000017500000000000013263647163014335 5ustar fengfengukui-control-center/data/网络代理.png0000664000175000017500000000221713245450075021400 0ustar fengfengPNG  IHDR@@iqtEXtSoftwareAdobe ImageReadyqe<1IDATx[[kA>n٘k6 V-Z"'hAIARAEjM-^V5IceǙieӰlnv&g\SEѷ(YٴcWhYpW4}2JxZNmvο^ >|,*՞JXSׄlQeSiٮ "!MB @֮"ЎIl/$wꢏ˪eloݦ GT g39EUͬ}r̔YNd6d?{*f>B(ºի@l"˔$ &y%H 3$R8S8Hc? 0r/<pt]LP|^h|uczzCB>޼/R$$H \X7aQ9.-4|Ȥ_UYr֡4y۴ީ8~BWW>DbNo\x>m^ĥNqfKyupym; bJ"j fs@IRy^J5Mh$)H(h$hn#񨌩|Y^znH.-T00%EvIENDB`ukui-control-center/data/个性化.png0000664000175000017500000000764213245450075020257 0ustar fengfengPNG  IHDR@@iqtEXtSoftwareAdobe ImageReadyqe<DIDATx[ TTfx* %߆Mݫhꪋo-rm}ZfVr,[]Q!C, ̋sFyE_ks89~K¹P;0d޽[Zm.h20cƌk.I%ɍ {h/_:{*;z(m[mPUU{t1Ol6K+<۫ g{  +>$D[ 7SbbPn$I]zǏ yGn߾\:m:.m7P$⢣ /^\%TTvgqw:^6KZyp5gΜ'G1СC꫻ho6I1Iͽ |gU=x2rZUlu~ ?jԨvy~'G+֬Y0hРeX:( @+Ϯ]z衩A.w#mAcǎMQQW0@!!!0aBMxt:$D3dm}٧ 5YY{ Ց*QYwz2D][qC{x,?=$QduG}J<`mfnZqնfs,\p9[R˰;"Pkk]hrם&d4)pرoRRR~C[G0Ţv޼ EaUh2w'kSj}\Js5e2򨪬/E@llYf!-p8E˗{@{(}c ׮]ݻ/%&.e rLTF76nBJ4NӧOJ %R(Զ; ܳމ'2%3SaÆ3gΜEe*+䟕+WƳx:˄gR%Pg$"Oڻw ,X5`35gaq0?4ysBPP 'wէ` Y@cKp1!VuHI3J{CfP ǮUqsl..1uaP<~ɒ%"eYP_^ ZQM(|Ӊleؼy~ 2m4<[ũs)/".&EPw$(4ȳyut?Ga.Y1Vy<\x֭[ߢzF>.CA^BsLÞ s͛?)-ָJnC@ի{n+WnB}9Q8, CՃHr& > GoOM{RrA%WA.!22`xO1I;"ֈKϰ\K,jBَ2\'畜S|>:5qRX3an- "^()(_|bŊ|AsEn=23.Q[RLH{,؜ٞs40P7NJӛ9Ut?t :BՍ*|MRZuo7KMkHh  Xf_~r79 wW:&>肳5RW | n=^3H_j|W%dPQqM^ѩӽg}Cm \B#bPؓ8vر?!!!JiHTLnu%xAOAS>e)pC`?Om|  Xo]I1%f&a3 8́,HIe]g L}jiޛ{7 ;LLb#s"g/Nnj4Y g~!k׮qJNQZZZvZ8I *Ϲ` Jb0XG$"ؿ H_ك[}Z9Cfcz"Ν۷/woOC=zKop 3,dҲ/M7=vϻ4iҋ xtߕ+WӧHH-(N,[lӝ8H@9Uía8xK _zewN  ˣ$IENDB`ukui-control-center/data/stock_person.png0000664000175000017500000000350613057175444017557 0ustar fengfengPNG  IHDR@@% tEXtSoftwareAdobe ImageReadyqe<!iTXtXML:com.adobe.xmp S_IDATxOQg@[-S `XF-0ڨ,Q*F㋾cHb4(`\hhB`% ʹCLxsi{{~̽wΝVŸ#\pJQ,>W$ɓTLDI٥!beyp$ƃ,%FvPSp<#]ƹiǂuwZ V))ѢhUAN>qn.]|ldRF);p*8CE2TTɜMSz`H'|L.wt]Rz5Wy0_pu{6O8k`4-MIENDB`ukui-control-center/data/声音.png0000664000175000017500000001106313245450075017300 0ustar fengfengPNG  IHDR@@iqtEXtSoftwareAdobe ImageReadyqe<IDATx; p[uO 7DBݲ%U|8c$%%#m7:%uةWV-[ӪRAJFC |k=k??~|ՎvV PܳϾ$&@oj Mnem*J@̾ss*Cs;vg&A#&zJ<|s/HBC$_A >wm=7f3W\b$&T"1@Q-IЍy\H|l()W־И QQQCB\]Ax7 '8p nB\wa}Rb5uLd{~Nrc!'̌ 8Ȫ4dmyFHKp[߄<d4as.9'B8QqJ wǗ%7; k0S#c;6`XMzI&[ 0dΩ(/53;+r1c "'`qqQś>phoz=npØA!5# *FZ"^$L8o!3 %A U ۜt] YxͷԘr0!8ڴi< bjB[[\|rc0a3ET*Dgz<诈aLi!vîP}^ƀ#l4#IC=,Ωɠ3D3Xbl6@ ط<5*׾aXvyp4vDmPq :L%$Efw®-5$$@_Q]sl}c8z; r<rO>{^'88_it MZBc b Ulr˺F3Gs"'޲ˁD+/‸x Aecm 1Bf> {91򌌀o@xzqN5=)."8"HGOIA^Rw !TXͤ>P@4ג𡇉o_{ 7<=H[158o RK4cr2txN>!)؅E,>C"ǎBKUh4ؼus7$*=Q6+e┢ -]$& AX,d@bnVfPd맺vLZ_l2xaf&4c:q~gaYm'j`8%k M:- )B5D3㼈!IxqX ;s嬉{sx Nbz aV^Ǽkxu:%_rN" l2}HM$EsħĽ9<&Q*%D AKORcxW"I(ZX udx3WFO_z2FWr2#W vr1||F';t9e'B8W9tZjLE(G%P$d]wI$+5AD*?ըj ^jsx$+롮v@g{+ݓqqGx{mjT3BN 56 [6h%z_q[N~oZf.E {dWP"Txb mt:xcfz" S!I)"$/G&| $=qo#e<M׺j#؊vryI6 /4Yż(^$bůp-*88#7'^`0 c~922: Zl.LKAZ86җg7 rz9kᚸ6OF^a'"Bz& ,vIXcW(;<$iiJ]e~BDO:pq/})|#"BvsK z 54 5۶@ݕFhhlnG7_ۧ`㎝p M_Q682䆓G?_}vh _MUTVM_pZa54 ,H^}'!`}w6? 8lAE`P\IJ5kкcگ7+%A( W(,yM6j 8]0^*ۭ1`*M$:]#~:A>Aq +ZXo #]$l/!{E)fQF(]E41l]D}-kEQk/%&P71oX-wALOUUپHDJ/o~^63 Jbt]x2DtxM0IR %MG W-]O$J>xwFK9T=lAaW_31t-!3p?y0ϏghhsB !Y O\6o%xbS63\(Mn|UJxD(r/<[PsT.}6QNp]~V1>l9ܹd OW7MCkuc" )ä1+aM:5ݵcIxTW믽 ?;OVII pPK/GEf}c4޷nQW6m5Q"eM&Cw^f["d4j* ZI0sjigo^@l]_y37l)*Xk'D?xAB(D dDo0 ^'Ap k7 D;WU'[|'F'a56cmQQymѬS@͈;e$jڄiAn촠Gt~&cBNc& ؁M؇LIKS M9߸6m.ou8H,"YXz֐\ U8AߎcF<,e=-2VP:8"w)w;4tZY>?!Mvª/{a%Ǥ(&%'Ryyt^KhCD:L)ڱjxJ΂ 2؜eDpT& ~]Q؍ ' *9 Рv|vX؞'hKfIgq*y#|tv%*\ #nTW:G*gNns>IENDB`ukui-control-center/data/日期和时间.png0000664000175000017500000001064013245450075022372 0ustar fengfengPNG  IHDR@@iqtEXtSoftwareAdobe ImageReadyqe<BIDATx[ TWUEB" 슈 .(4b:c$QϜ8[LĜN:c4'&qQ\((DPDکe{EVQvϙu.omɫ 52ďpja !ӤB(czʗn߳[|b1^Hv!ˮ3jaΌ, V,CT t=շK/3a#'^AÅxY7P5(G8ebYbX7*:=O텴$uD%T5b\@f*Ёm)9f 4KzĒ4Gu$15G*_} >>5.^-?lۉD@ĈPg iɉD6Թf|LR|_Բ'X8\<A@M@ZL-yw_'fXV 7&F}O1 _4 bo~,5}5k$ٜ2ҭQꗖ߆&3s45?fԴI u] GO˜xxne%l@ALjԴgmlB V&%)xEV͓#{?;{Մ T]͞if\7w.Xݘ^ #szh@|V33R Y W= ! 9-ep&Ԩ٧g JGz&|fN<J,MrzoYfp0 "-F;:,bEWfD>v=HIkL I IU37&wk5#gR?wOx? tFISQ`o|8,oQ2_/pǚBEU-e )bL̻9toIx.OlU.ZА- ȱzѨ^ sl(| Mt~p-;s:DGF`b&mXg ;rŻʎDjc# 2(.zxfVOoFSY0cS;v_`i~Tݝ "^9L_Q؍ [\zDp=>>!dׯys)'d%(wQ@d;La՝xT`8#ΚݕOƍ\LGgJhX(4li+ ))/ }B,RHى(xIY9A_ 8Hty_KD &K3X! G͙N?F`C"ߋGMޥy}EPcGD&B㠂޿`><":ZC+겭oArW#' sKbf\v#a2V+lߒU*,e2A  D4<hR[~Nh[@c 0%N~ⵯAl_& A XA$nn\sFV H%׾dpvӅEP@ā,JyPDIGGtl=T=kt˝h T~Q)LTr/VBSJN BL̶--lpV\Vt0fO⅔ڃ0N(04^Xfi6hhcu##l޾V: >yH@lMmdAU Y:>gե> BWookz=5$lh : {Uit>e ?r]XX P*]op OG0{ x6-׆S]m]vNM <2#ēIybrD"u9^@OXڵtfb,|r >]K~%2^;96]B+$pEnO65Ӝ8x 6^=PQʗ>yIg4[aNܩP ~[CYy%0ČNJXPRZ+-{̀B[B{GǕR@#:TkWzXUQ`p7'̊: ԯ(|{G'Io.TEAz]&>p" 4!)upj!&휱-ퟬFMcr-d3, 3}Gt:0M@pt?X"؄qA 9L¿og+[E~S2?5ЬtWeNđʨap8?L2A_NIl?G%АVAj6i_X:;)q1Eݣ4%6Ӯlj~j殦p>J譩^{Ϭp\sW|Ίf PĖ]fXs.\#D8: QYA-Ouvo1Z:V>a U,]jŸ6@Zd ŧIMZϙXODz ~QfŶMwK'mr̬Vf_~aj$);˶~Ie?m^2ؾe;DM7oh2qSR,(ncRwh~W@& N=BHt+¡6{hѪU?`9>B*SsKW}P٣UTwCcs j y hru-.6L&`Fs]mcn7JyST‹M#Z~U6$7^oOQfZ6aT9,׿>2ѱ ՞ì5cEᵏI^kg{*I+l 0ÉP S&PR [WB٭0}w9 5 Q=)3kWGofK,pa'F$N)@ h5GdI [އ*`ۗ#Pt nOu vAh1+;qJPh*z8vHoDr`rv}0Qgf5I&DZUXk.<=ƨ{3agzIEddr~(CECEmEֺ"˗1CnmpF+˳8 )Y ѫC7&_wUEpR\8}Z`Up&MFvSsŗՌF >8D+H3`=DvBid00pYp$ `;&IENDB`ukui-control-center/data/Makefile.am0000664000175000017500000000124513253611050016354 0ustar fengfengrcdir = $(datadir)/themes/ukui-theme/gtk-2.0/apps zonedir = $(datadir)/zoneinfo saversdir = $(datadir)/applications/screensavers rc_DATA = ukuicc.rc zone_DATA = zone_utc savers_DATA = savers-desktop/* icondir = $(pkgdatadir)/icons facedir = $(datadir)/pixmaps/faces icon_DATA = 打印机.png 电源管理.png 个性化.png 键盘.png 开机启动.png 默认应用程序.png 日期和时间.png 声音.png 鼠标.png 网络代理.png 网络连接.png 显示器.png 用户账号.png 系统检测.png AC.png battery.png face_DATA = stock_person.png SUBDIRS = color EXTRA_DIST = $(rc_DATA) $(zone_DATA) $(icon_DATA) $(face_DATA) $(savers_DATA) clean-local: rm -rf Makefile.in ukui-control-center/data/zone_utc0000664000175000017500000001561613245450075016111 0ustar fengfengAfrica/Banjul (UTC-12:00) 国际日期变更线西 Pacific/Midway (UTC-11:00) 协调世界时-11 America/Adak (UTC-10:00) 阿留申群岛 Pacific/Honolulu (UTC-10:00) 夏威夷 Pacific/Marquesas (UTC-09:30) 马克萨斯群岛 America/Anchorage (UTC-09:00) 阿拉斯加 Pacific/Gambier (UTC-09:00) 协调世界时-09 America/Sitka (UTC-08:00) 太平洋时间(美国和加拿大) America/Juneau (UTC-08:00) 下加利福尼亚州 America/Metlakatla (UTC-08:00) 协调世界时-08 America/Chihuahua America/La_Paz America/Mazatlan (UTC-07:00) 奇瓦瓦,拉巴斯,马萨特兰 America/Creston America/Dawson_Creek America/Fort_Nelson America/Phoenix (UTC-07:00) 山地时间(美国和加拿大) America/Phoenix (UTC-07:00) 亚利桑那 Pacific/Easter (UTC-06:00) 复活节岛 America/Mexico_City America/Monterrey (UTC-06:00) 瓜达拉哈拉,墨西哥城,蒙特雷 America/Swift_Current (UTC-06:00) 萨斯喀彻温 America/Regina America/Swift_Current (UTC-06:00) 中部时间(美国和加拿大) America/Costa_Rica (UTC-06:00) 中美洲 America/Bogota America/Lima America/Rio_Branco (UTC-05:00) 波哥大,利马,基多,里奥布朗库 America/Atikokan (UTC-05:00) 东部时间(美国和加拿大) America/Havana (UTC-05:00) 哈瓦那 America/Port-au-Prince (UTC-05:00) 海地 America/Cancun (UTC-05:00) 切图马尔 America/Indiana/Indianapolis America/Indiana/Vincennes America/Indiana/Winamac America/Indiana/Marengo (UTC-05:00) 印第安纳州(东部) America/Tortola (UTC-04:00) 大西洋时间(加拿大) America/Caracas (UTC-04:00) 加拉加斯 America/Cuiaba (UTC-04:00) 库亚巴 America/La_Paz America/Manaus America/Argentina/San_Juan (UTC-04:00) 乔治敦,拉巴斯,玛瑙斯,圣胡安 America/Santiago (UTC-04:00) 圣地亚哥 America/Antigua (UTC-04:00) 特克斯和凯科斯群岛 America/Asuncion (UTC-04:00) 亚松森 America/St_Johns (UTC-03:30) 纽芬兰 America/Araguaina (UTC-03:00) 阿拉瓜伊纳 America/Godthab (UTC-03:00) 格陵兰 America/Cayenne America/Fortaleza (UTC-03:00) 卡宴,福塔雷萨 America/Montevideo (UTC-03:00) 蒙得维的亚 America/El_Salvador (UTC-03:00) 萨尔瓦多 America/Miquelon (UTC-03:00) 圣皮埃尔和密克隆群岛 Atlantic/South_Georgia (UTC-02:00) 协调世界时-02 Atlantic/Cape_Verde (UTC-01:00) 佛得角群岛 Atlantic/Azores (UTC-01:00) 亚速尔群岛 Europe/Lisbon (UTC) 协调世界时 Europe/Dublin Europe/Lisbon Europe/London (UTC+00:00) 都柏林,爱丁堡,里斯本,伦敦 Africa/Casablanca (UTC+00:00) 卡萨布兰卡 Africa/Monrovia Atlantic/Reykjavik (UTC+00:00) 蒙罗维亚,雷克雅未克 Europe/Amsterdam Europe/Berlin Europe/Rome Europe/Stockholm Europe/Vienna (UTC+01:00) 阿姆斯特丹,柏林,伯尔尼,罗马,斯德哥尔摩,维也纳 Europe/Belgrade Europe/Bratislava Europe/Budapest Europe/Ljubljana Europe/Prague (UTC+01:00) 贝尔格莱德,布拉迪斯拉发,布达佩斯,卢布尔雅那,布拉格 Europe/Brussels Europe/Copenhagen Europe/Madrid Europe/Paris (UTC+01:00) 布鲁塞尔,哥本哈根,马德里,巴黎 Europe/Sarajevo Europe/Skopje Europe/Warsaw Europe/Zagreb (UTC+01:00) 萨拉热窝,斯科普里,华沙,萨格勒布 Africa/Windhoek (UTC+01:00) 温得和克 Africa/Kinshasa (UTC+01:00) 中非西部 Asia/Amman (UTC+02:00) 安曼 Asia/Beirut (UTC+02:00) 贝鲁特 Asia/Damascus (UTC+02:00) 大马士革 Africa/Tripoli (UTC+02:00) 的黎波里 Africa/Harare (UTC+02:00) 哈拉雷,比勒陀利亚 Europe/Helsinki Europe/Kiev Europe/Riga Europe/Sofia Europe/Tallinn Europe/Vilnius (UTC+02:00) 赫尔辛基,基辅,里加,索菲亚,塔林,维尔纽斯 Europe/Chisinau (UTC+02:00) 基希讷乌 Europe/Kaliningrad (UTC+02:00) 加里宁格勒 Asia/Gaza Asia/Hebron (UTC+02:00) 加沙,希伯伦 Africa/Cairo (UTC+02:00) 开罗 Europe/Athens Europe/Bucharest (UTC+02:00) 雅典,布加勒斯特 Asia/Jerusalem (UTC+02:00) 耶路撒冷 Asia/Baghdad (UTC+03:00) 巴格达 Asia/Kuwait Asia/Riyadh (UTC+03:00) 科威特,利雅得 Europe/Minsk (UTC+03:00) 明斯克 Europe/Moscow Europe/Volgograd (UTC+03:00) 莫斯科,圣彼得堡,伏尔加格勒 Africa/Nairobi (UTC+03:00) 内罗毕 Europe/Istanbul (UTC+03:00) 伊斯坦布尔 Asia/Tehran (UTC+03:30) 德黑兰 Asia/Muscat (UTC+04:00) 阿布扎比,马斯科特 Europe/Astrakhan Europe/Ulyanovsk (UTC+04:00) 阿斯特拉罕,乌里扬诺夫斯克 Asia/Yerevan (UTC+04:00) 埃里温 Asia/Baku (UTC+04:00) 巴库 Asia/Tbilisi (UTC+04:00) 第比利斯 Indian/Mauritius (UTC+04:00) 路易港 Europe/Volgograd (UTC+04:00) 萨拉托夫 Europe/Samara (UTC+04:00) 伊热夫斯克,萨马拉 Asia/Kabul (UTC+04:30) 喀布尔 Asia/Ashgabat Asia/Tashkent (UTC+05:00) 阿什哈巴德,塔什干 Asia/Yekaterinburg (UTC+05:00) 叶卡捷琳堡 Asia/Karachi (UTC+05:00) 伊斯兰堡,卡拉奇 Asia/Kolkata (UTC+05:30) 钦奈,加尔各答,孟买,新德里 Asia/Kathmandu (UTC+05:45) 加德满都 Asia/Almaty (UTC+06:00) 阿斯塔纳 Asia/Dhaka (UTC+06:00) 达卡 Asia/Omsk (UTC+06:00) 鄂木斯克 Asia/Rangoon (UTC+06:30) 仰光 Asia/Barnaul (UTC+07:00) 巴尔瑙尔,戈尔诺-阿尔泰斯克 Asia/Hovd (UTC+07:00) 科布多 Asia/Krasnoyarsk (UTC+07:00) 克拉斯诺亚尔斯克 Asia/Bangkok Asia/Jakarta (UTC+07:00) 曼谷,河内,雅加达 Asia/Tomsk (UTC+07:00) 托木斯克 Asia/Jakarta Asia/Novosibirsk (UTC+07:00) 新西伯利亚 Asia/Shanghai Asia/Hong_Kong Asia/Urumqi Asia/Chongqing (UTC+08:00) 北京,重庆,香港特别行政区,乌鲁木齐 Asia/Kuala_Lumpur Asia/Singapore (UTC+08:00) 吉隆坡,新加坡 Australia/Perth (UTC+08:00) 珀斯 Asia/Urumqi (UTC+08:00) 台北 Asia/Taipei Asia/Ulaanbaatar (UTC+08:00) 乌兰巴托 Asia/Irkutsk (UTC+08:00) 伊尔库兹克 Asia/Pyongyang (UTC+08:30) 平壤 Australia/Eucla (UTC+08:45) 尤克拉 Asia/Chita (UTC+09:00) 赤塔市 Asia/Tokyo (UTC+09:00) 大阪,札幌,东京 Asia/Seoul (UTC+09:00) 首尔 Asia/Yakutsk (UTC+09:00) 雅库兹克 Australia/Adelaide (UTC+09:30) 阿德莱德 Australia/Darwin (UTC+09:30) 达尔文 Australia/Brisbane (UTC+10:00) 布里班斯 Asia/Vladivostok (UTC+10:00) 符拉迪沃斯托克 Pacific/Guam Pacific/Port_Moresby (UTC+10:00) 关岛,莫尔兹比港 Australia/Hobart (UTC+10:00) 霍巴特 Australia/Melbourne Australia/Sydney (UTC+10:00) 堪培拉,墨尔本,悉尼 Australia/Lord_Howe (UTC+10:30) 豪勋爵岛 Pacific/Bougainville (UTC+11:00) 布干维尔岛 Asia/Magadan (UTC+11:00) 马加丹 Pacific/Norfolk (UTC+11:00) 诺福克岛 Pacific/Efate (UTC+11:00) 乔库尔达赫 Asia/Sakhalin (UTC+11:00) 萨哈林 Pacific/Guadalcanal (UTC+11:00) 所罗门群岛,新喀里多尼亚 Asia/Anadyr (UTC+12:00) 阿纳德尔,勘察加彼得罗巴甫洛夫斯克 Pacific/Auckland (UTC+12:00) 奥克兰,惠灵顿 Pacific/Fiji (UTC+12:00) 斐济 Pacific/Wake (UTC+12:00) 协调世界时+12 Pacific/Chatham (UTC+12:45) 查塔姆群岛 Pacific/Tongatapu (UTC+13:00) 努库阿洛法 Pacific/Apia (UTC+13:00) 萨摩亚群岛 Pacific/Enderbury (UTC+13:00) 协调世界时+13 Pacific/Kiritimati Indian/Christmas (UTC+14:00) 圣诞岛 ukui-control-center/data/显示器.png0000664000175000017500000000466213245450075020373 0ustar fengfengPNG  IHDR@@iqtEXtSoftwareAdobe ImageReadyqe< TIDATxZoWٝןId'npQ }@@U! //E!J?7TBڊB@B[jRWb]ν{wdz}Wwgvν;NI9)ǹ1}A#~vfdq~1i  ߟ!K>ǭ4*@(?:~ 1u&Rɦ2 T~H$2Iuܟ;X( npXd )!+/m>Q("V,T3= rtc< S "@W9L5՗D( ۿ'‹|>UƦN,]pbB2^QkQS4,aTY՞ L7}(K ۿT,P- H~J5a1cbݓqcٟ;!H(ڛ*9 OAM-# n+r{C3A' -:-X-<1&]Å%TjelgJZ[P_0UyU|@CT|ݜW05x Y[$0E :SP\E7v[q/ 7ⲿjK./2U PJ\h땜5?\JJ7I9R@\xJ2>|=r}Er~\@#@(>B[g@z6*duV޵rwrLIV mty %DR {VoPPVstYg)&n⑥ 5 G<Pɐ..֥j)D8+Ӟ} X (ເ`490Sm4eWwO܏-'7 kH8O\[)\$nKh `rd=-7p[bQfkTI%h +k+{Ff ROBvjenK,r*uT0|J$755Z{t޼ZNx . '|15=w`S~3m+b(򵀛u|KC3/;裼<:۶!] 48E^u˔lB^B`4gNbroGc5(RUQ v R7r7xyZ|-y/וƠ}+ص9&LPG@^`2y{A:1, j(%?x\)+1d=OIJ:Bqv ,(KŻx/tWP Y*dLyԍw NJ1!_g٢{uczsVP%1⸓@u|L}P U܌ovX !b*50˺ \w{FHŎ`rTKZhZ%vF=v"Ԯ0#ҊqdrO2]1eERlVHn9CX*?X7]ހ|"T3,է:84:J;w0bm#dF,rXꃅ=dR vPa8j"?tu+Œ.Urh$SR\mרCpy.y5z93&,QB Il.syxcku͕emTA/ B)`?C3G3eA>sKI+N,cCT:!1jqZ8PυBµw^^< WJ˔"pS# TGd;"p\aս1䜣xKTI Y+l7jrRtd'Ln#$NIENDB`ukui-control-center/data/savers-desktop/0000775000175000017500000000000013253611050017270 5ustar fengfengukui-control-center/data/savers-desktop/ukui-ripples.desktop0000664000175000017500000000062313253611050023315 0ustar fengfeng [Desktop Entry] Name=Ripples Exec=/usr/lib/xscreensaver/ripples -root TryExec=/usr/lib/xscreensaver/ripples Comment=This draws rippling interference patterns like splashing water. With the -water option, it manipulates your desktop image to look like something is dripping into it. Written by Tom Hammersley. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/savers-desktop/ukui-abstractile.desktop0000664000175000017500000000045313253611050024135 0ustar fengfeng [Desktop Entry] Name=Abstractile Exec=/usr/lib/xscreensaver/abstractile -root TryExec=/usr/lib/xscreensaver/abstractile Comment=Generates mosaic patterns of interlocking tiles. Written by Steve Sundstrom. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/savers-desktop/ukui-fiberlamp.desktop0000664000175000017500000000043313253611050023577 0ustar fengfeng [Desktop Entry] Name=Fiberlamp Exec=/usr/lib/xscreensaver/fiberlamp -root TryExec=/usr/lib/xscreensaver/fiberlamp Comment=Draws a groovy rotating fiber optic lamp. Written by Tim Auckland. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/savers-desktop/ukui-fuzzyflakes.desktop0000664000175000017500000000044013253611050024211 0ustar fengfeng [Desktop Entry] Name=FuzzyFlakes Exec=/usr/lib/xscreensaver/fuzzyflakes -root TryExec=/usr/lib/xscreensaver/fuzzyflakes Comment=Falling colored snowflake/flower shapes. Written by Barry Dmytro. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/savers-desktop/ukui-xlyap.desktop0000664000175000017500000000052413253611050022774 0ustar fengfeng [Desktop Entry] Name=XLyap Exec=/usr/lib/xscreensaver/xlyap -root TryExec=/usr/lib/xscreensaver/xlyap Comment=This generates pretty fractal pictures via the Lyapunov exponent. http://en.wikipedia.org/wiki/Lyapunov_exponent Written by Ron Record. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/savers-desktop/ukui-cwaves.desktop0000664000175000017500000000046413253611050023132 0ustar fengfeng [Desktop Entry] Name=CWaves Exec=/usr/lib/xscreensaver/cwaves -root TryExec=/usr/lib/xscreensaver/cwaves Comment=This generates a languidly-scrolling vertical field of sinusoidal colors. Written by Jamie Zawinski. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/savers-desktop/ukui-m6502.desktop0000664000175000017500000000117513253611050022413 0ustar fengfeng [Desktop Entry] Name=m6502 Exec=/usr/lib/xscreensaver/m6502 -root TryExec=/usr/lib/xscreensaver/m6502 Comment=This emulates a 6502 microprocessor. The family of 6502 chips were used throughout the 70's and 80's in machines such as the Atari 2600, Commodore PET, VIC20 and C64, Apple ][, and the NES. Some example programs are included, and it can also read in an assembly file as input. Original JavaScript Version by Stian Soreng: http://www.6502asm.com/. Ported to XScreenSaver by Jeremy English. Written by Stian Soreng and Jeremy English. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/savers-desktop/ukui-metaballs.desktop0000664000175000017500000000055513253611050023607 0ustar fengfeng [Desktop Entry] Name=MetaBalls Exec=/usr/lib/xscreensaver/metaballs -root TryExec=/usr/lib/xscreensaver/metaballs Comment=Draws two dimensional metaballs: overlapping and merging balls with fuzzy edges. http://en.wikipedia.org/wiki/Metaballs Written by W.P. van Paassen. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/savers-desktop/ukui-shadebobs.desktop0000664000175000017500000000053113253611050023567 0ustar fengfeng [Desktop Entry] Name=ShadeBobs Exec=/usr/lib/xscreensaver/shadebobs -root TryExec=/usr/lib/xscreensaver/shadebobs Comment=This draws smoothly-shaded oscillating oval patterns that look something like vapor trails or neon tubes. Written by Shane Smit. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/savers-desktop/ukui-deco.desktop0000664000175000017500000000064213253611050022552 0ustar fengfeng [Desktop Entry] Name=Deco Exec=/usr/lib/xscreensaver/deco -root TryExec=/usr/lib/xscreensaver/deco Comment=Subdivides and colors rectangles randomly. It looks kind of like Brady-Bunch-era rec-room wall paneling. http://en.wikipedia.org/wiki/Piet_Mondrian#Paris_1919.E2.80.931938 Written by Jamie Zawinski and Michael Bayne. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/savers-desktop/ukui-swirl.desktop0000664000175000017500000000041113253611050022772 0ustar fengfeng [Desktop Entry] Name=Swirl Exec=/usr/lib/xscreensaver/swirl -root TryExec=/usr/lib/xscreensaver/swirl Comment=Flowing, swirly patterns. Written by M. Dobie and R. Taylor. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/savers-desktop/ukui-binaryring.desktop0000664000175000017500000000060113253611050023777 0ustar fengfeng [Desktop Entry] Name=BinaryRing Exec=/usr/lib/xscreensaver/binaryring -root TryExec=/usr/lib/xscreensaver/binaryring Comment=A system of path tracing particles evolves continuously from an initial creation, alternating dark and light colors. Written by J. Tarbell and Emilio Del Tessandoro. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/savers-desktop/ukui-hexadrop.desktop0000664000175000017500000000054513253611050023454 0ustar fengfeng [Desktop Entry] Name=Hexadrop Exec=/usr/lib/xscreensaver/hexadrop -root TryExec=/usr/lib/xscreensaver/hexadrop Comment=Draws a grid of hexagons or other shapes and drops them out. http://en.wikipedia.org/wiki/Tiling_by_regular_polygons Written by Jamie Zawinski. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/savers-desktop/ukui-slidescreen.desktop0000664000175000017500000000075413253611050024144 0ustar fengfeng [Desktop Entry] Name=SlideScreen Exec=/usr/lib/xscreensaver/slidescreen -root TryExec=/usr/lib/xscreensaver/slidescreen Comment=This takes an image, divides it into a grid, and then randomly shuffles the squares around as if it was one of those "fifteen-puzzle" games where there is a grid of squares, one of which is missing. http://en.wikipedia.org/wiki/Fifteen_puzzle Written by Jamie Zawinski. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/savers-desktop/ukui-tessellimage.desktop0000664000175000017500000000151513253611050024316 0ustar fengfeng [Desktop Entry] Name=Tessellimage Exec=/usr/lib/xscreensaver/tessellimage -root TryExec=/usr/lib/xscreensaver/tessellimage Comment=Converts an image to triangles using Delaunay tessellation, and animates the result at various depths. More triangles are allocated to visually complex parts of the image. This is accomplished by first computing the first derivative of the image: the distance between each pixel and its neighbors (which is essentially edge detection or embossing). Then the Delaunay control points are chosen by selecting those pixels whose distance value is above a certain threshold: those are the pixels that have the largest change in color/brightness. http://en.wikipedia.org/wiki/Delaunay_triangulation Written by Jamie Zawinski. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/savers-desktop/ukui-distort.desktop0000664000175000017500000000054713253611050023334 0ustar fengfeng [Desktop Entry] Name=Distort Exec=/usr/lib/xscreensaver/distort -root TryExec=/usr/lib/xscreensaver/distort Comment=Grabs an image of the screen, and then lets a transparent lens wander around the screen, magnifying whatever is underneath. Written by Jonas Munsin. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/savers-desktop/ukui-galaxy.desktop0000664000175000017500000000057113253611050023126 0ustar fengfeng [Desktop Entry] Name=Galaxy Exec=/usr/lib/xscreensaver/galaxy -root TryExec=/usr/lib/xscreensaver/galaxy Comment=This draws spinning galaxies, which then collide and scatter their stars to the, uh, four winds or something. Written by Uli Siegmund, Harald Backert, and Hubert Feyrer. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/savers-desktop/ukui-penrose.desktop0000664000175000017500000000205613253611050023314 0ustar fengfeng [Desktop Entry] Name=Penrose Exec=/usr/lib/xscreensaver/penrose -root TryExec=/usr/lib/xscreensaver/penrose Comment=Draws quasiperiodic tilings; think of the implications on modern formica technology. In April 1997, Sir Roger Penrose, a British math professor who has worked with Stephen Hawking on such topics as relativity, black holes, and whether time has a beginning, filed a copyright-infringement lawsuit against the Kimberly-Clark Corporation, which Penrose said copied a pattern he created (a pattern demonstrating that "a nonrepeating pattern could exist in nature") for its Kleenex quilted toilet paper. Penrose said he doesn't like litigation but, "When it comes to the population of Great Britain being invited by a multinational to wipe their bottoms on what appears to be the work of a Knight of the Realm, then a last stand must be taken." As reported by News of the Weird #491, 4-Jul-1997. http://en.wikipedia.org/wiki/Penrose_tiling Written by Timo Korvola. StartupNotify=false Terminal=false Type=Application Categories=Screensaver; OnlyShowIn=UKUI; ukui-control-center/data/鼠标.png0000664000175000017500000000554013245450075017242 0ustar fengfengPNG  IHDR@@iqtEXtSoftwareAdobe ImageReadyqe< IDATx[[W>\ﻶ:qN%!AQAU R3R%D%$^x@*h_JIIrMs=qlv{=u(#{/B}7n=rLtAմadd4J!ξ䗃Ե5R@hSS/k﫫4 ZO%|į梙/g|*W A+zi 2/+dezڿ*/.2@GGnIJ_A'Kds ^ &$hD)1L9`E @b3DΝVPq8TPy4:< sp x&s>y۲ T>slLJ?z~yHlS'zs$D(i2S: n90wx*}b[&F}C"^+$R0t0Zڸ@@wpP>g 廂׊W+O[FE7^U[S>g9ۍmv/SN-}p9gXˆ %CW:%mvJ4XVX{ M^U6HaEarfeDymtt qZ*> hPэ j@HqycR  L9X*M#>Z~6d20&%"#iZڏ~| /216*=c& $O2_ !MC:uhb0>l/(»n- l4V:y_UspN:}侮g,֤p$ˋbmFrpzU5f}2R\AoR vSySm\Z{/#hC;`?\ FԮ Q  U&/ʼ_)CڨOWo\9Sd,SwЃ{b -IK2f v/^ZWH+LNvNlb$0MO,<^(T^^h8@.] IYʎK XWZ5AJ_XaSb[LqY9lGK #Ne+WEeJ5X#`" n۰꺖T|WcJwll8׏# 0, ~$IENDB`ukui-control-center/data/battery.png0000664000175000017500000000126113245450075016507 0ustar fengfengPNG  IHDR szzxIDATXKOaδ4(Pݰ$1^Hʕn\`ʥ\11PZhZZzN\8Q6}/ef3Oef`Y!?7=xtz{wNOE|b^.}O_RQr,/?cO5`Td8 DkD=Kuڞ@+|Sxԡ\ۦpkJ*Mc'JSb5@"4m QlcPB(QF (c@'?rmI3d;\_bp;+/L@/Nxj9D\3{]߰2`AD Rr3}*Z 6E'@i1hO:)A?NНae>xljxˀexF*N&f=O}= pݹ(8eTTR .CIDATxA0 ]9 JkdMU/ Dc/CIDATxA0 ]-^kdU/ |N8IENDB`ukui-control-center/data/color/ukui-yellow.png0000664000175000017500000000171713057175444020454 0ustar fengfengPNG  IHDR44JtEXtSoftwareAdobe ImageReadyqe<!iTXtXML:com.adobe.xmp 8DIDATx1 002X\VAs zmBIENDB`ukui-control-center/data/color/ukui-orange.png0000664000175000017500000000171513057175444020412 0ustar fengfengPNG  IHDR44JtEXtSoftwareAdobe ImageReadyqe<!iTXtXML:com.adobe.xmp 5BIDATxA0 ]Cѵ|@r Cg IENDB`ukui-control-center/data/color/ukui-gray.png0000664000175000017500000000171413057175444020100 0ustar fengfengPNG  IHDR44JtEXtSoftwareAdobe ImageReadyqe<!iTXtXML:com.adobe.xmp ]AIDATx1 5` IꫩnQOIENDB`ukui-control-center/data/color/ukui-purple.png0000664000175000017500000000171513057175444020446 0ustar fengfengPNG  IHDR44JtEXtSoftwareAdobe ImageReadyqe<!iTXtXML:com.adobe.xmp XQBIDATxA0V(-ǖ`9=UcrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrV"feXIENDB`ukui-control-center/data/color/ukui-green-jun.png0000664000175000017500000000222513057175444021026 0ustar fengfengPNG  IHDR66'tEXtSoftwareAdobe ImageReadyqe<iTXtXML:com.adobe.xmp ?ܛVEIDATx 0 } [֯$ k:v{`;hgySIENDB`ukui-control-center/data/color/ukui-red.png0000664000175000017500000000171313057175444017707 0ustar fengfengPNG  IHDR44JtEXtSoftwareAdobe ImageReadyqe<!iTXtXML:com.adobe.xmp 5@IDATxA0E %XNw|U񘜜ܭ`E!iIENDB`ukui-control-center/data/color/ukui-light-blue.png0000664000175000017500000000171513057175444021173 0ustar fengfengPNG  IHDR44JtEXtSoftwareAdobe ImageReadyqe<!iTXtXML:com.adobe.xmp &BIDATx10 \䪗Z3:IENDB`ukui-control-center/data/默认应用程序.png0000664000175000017500000000423213245450075023541 0ustar fengfengPNG  IHDR@@iqtEXtSoftwareAdobe ImageReadyqe<"g<|GNPqGnM{mRoV,2M~}1ݕsB*U A) 1EAZE8Mj #`m&Io u\kmfETPl6k*LH$X,Qklu>~tw[]2.8@ɓ%B˒`M e.qE"!*|xn8w҅v^k\b @e8Sccgi}6k!9b[(W(m-,tC 1e$ȌqftڪNqr kI%jS>SϴPhp}R0#m3KEQ^ԧ4hGx,n^)lbFPh%$#k!24u&U.qF4w<0@,4hшyIeHڹb0P4O(PX%t.'::1s\ܢYo?&[ E"ϖ])+Tg&?2t{w Y~px$A {m_K/3&ګ<46,Ko@ {VFuoPwA VvF*s^6 X~t76ӨeR^6\hI4=;fa겶yɅ۳t L4xSc|Q >VW'Pa»H+?Da#ګxdc>Ibwo޵;$r.Ǟ̅92x(tHz~,,ɕ9Z~$L_pBQ[Iƚ=F| Z +qĊ2 ɷ wrUmIENDB`ukui-control-center/data/ukuicc.rc0000664000175000017500000000045613057175444016152 0ustar fengfeng# ============================================================================== # Kylin control center settings # ============================================================================== style "default" { font_name = "Ubuntu 10" } widget "*ukuicc*" style "default" gtk-font-name = "Ubuntu 10" ukui-control-center/data/网络连接.png0000664000175000017500000001075513245450075021445 0ustar fengfengPNG  IHDR@@iqtEXtSoftwareAdobe ImageReadyqe<IDATx[ p[Uz,m˲-Ɏv;y8$dCx$$K;t[,%݁e[v2t v-А& 8ߑIzKdYd6]:G{u{}0c(Hr߯CÝ*T_r2 7}ĝ׫Qfy֩*,E?NX]pzM։e{0i @I>jKq ҋ9808Pz;NM9!jNL](b7pUY^}%8<uj$qp {ͧ ktXr=}c{]rY%Kolcףkժ eqcًPHׇfT~ 5ABfoƖ3PZԯnRawNeB0{+oR,\||(לZ6S+]{ ݦh,5JsN.jN"$ JeU+[vq 3WB+o^ܣ?]W+]>M,DyĤWԼ5#PId31EgW%pB?60_)n>&.Pvj lXR/gx$YvtE.d]*"ӄ g|DNAf#Wx+ak)DHِ8 B9;[)VK6ZUrRA^U[ ~؝Gz^z+ ;* ' ~E!¹N|Y싸v Os?i7O~I$SeDˏ/ُX>=A6V&4N+x:EbE-Hqq N:ʢX\D3r%Evohwok) X0̮|KsO}XY>~ЀqMK2L(U+%?w@GM\cr1P4ꨍ^% Ux'׹jIݵJuxdܼ쩔)8y0. Man?ViߦK3|Y.6aYClP)7 7cғ5t T[㙰hTrwOF!%owyiOR75ڷx9 w!G6l.HjDlÕ g4źa'ʟ`e)("cg+\bWh؋G ko0ߤxgR|NjN\6o]||9)/s hdmb+qtUyvjx J+6>M"HZ pࣁaG;J"WR2;#e􇑕iAǶ<ҶyCX31 W?m5lhtеR.ފ }\`IfrZ u0GKsᵮZ͔Pf .t 0 P|x4-x9>؇r?мgN&s&]H߃Rtq~6ꓣQw &6lО9&ܱC||ߟQe+<+a;/ƻrt!`i#*Fb{TaOzδ c@3?,0Lՠٴ9Eٔ,m'>4 'O< n ?pL Fwg907[--]ujg_XW8DN`%wccfmZ^oFj[;#g{)5o$r ta,Saj#$M\}MtSv=,iTа +20A3yBLҀ8DLwWUNUY]ȥ8a!mck/$ʜxdSܿ Yީ8`%C (&o-=ȏ3,pRvHle1dU]w/zVIjUm0@W,&=<:ZȄ-Ԩ=Jq&msܱd8'L}Y%B0@$#n=A|tM(#]OI_o@wlt־dDᾔ{9'阳G( ?m/O15Ӝ ,4{l 37_ƶ&,}T\|[ޣ PճVG 4m3n\ L`XcyN+$& nfwοeqQZml=Z׼$LYҧiSݡDW{(j ]}$ lɢNw>u@INHXR) &XFsQc|G0hJ9p6՝A[%ݫ!iy%6O1qx=%)dqcV1 ^6xq^H~*ly5Jzy% 9BE)஺Wjl@NYvEx&?"8YW⃫{ɤn분}Qlh^fȻ78;/龝Tf$(fv$쿣 lˡBE6;{j1k9N$ iYe\h5n4 fxoLh= #e}Ă80L}h148~+ ʻ/GbqOmfMi4-Oڵ zdޡz\輝bT#w|+o ɎYP>Ѝ-.A2!͉3<(]=[18vӢ%Ymdyr g/Na{W8 iY:F"L_2O=}^o2)P4pӯ|d#Rl 4kj9 T_/$97MŅ bW%('S(j4 +?CM=t| Tq!B`&!( E ~qʦ~oC'$Uxaw~UL\#?9@pL4n1ZEJP)M0+Yi3p7?ϻRQ{=rG?42hSuݰX Iie}g}e0"K՘\؁1dF-n]ۗ Y 9ŭ#͸v0v褠0ں9'ZhJ;"du Qhy0eMJn#W`jaAa齂⹔LGSǔ6TC)Ls1mb ;L~o xڿ6N;d}8¯Dx!1Iϐr}᝝>|?Mvd "Ɯ1D 竺`~-uhBIENDB`ukui-control-center/data/电源管理.png0000664000175000017500000000254613245450075021346 0ustar fengfengPNG  IHDR@@iqtEXtSoftwareAdobe ImageReadyqe<IDATx[IE܋'C& v qAAp ď@7 EBH '\XD!J !5 ==vnwmwJ][}ޫZ~@;yˏeY}Yar W~㋯q) 0 B b=ku2o7 +"~w?~uS6,o\6NЙPd Dže›eVCQ)|,-*HXɳ9s[|}I{$!?@52 ߲>|2sR+quQx})HDQ UdH`:mA0&D2d"!Z ג\.\%f~ {O+."̴kQa!amV;%b >0^Z~8%dr;wms)`r>joh g=EQB^Ҏ:۹~Nv |0<Hᛈ,e2-ӶM] B o-gaDXgvJ1L4;v-ܬ9rlm{9^WMˆf y^g4azL`ZuYtz 9ET:nj i@_8zk1 tJOG 9cdZM?V'͵/*Ll~at< t?y_[J^/5ߺFPۨ}_}S#ش>x tp^sL18[A$()؟;y '<>KPwo|āhTxixtp k }w4&Nx4`JØ DfP) 02& 0T:Y * ;d0s*LYRI9xM0/BRa80%kK, `n+*FI i*ruQmC|LHC{v4O G`=2^y|útD}ɌjFxt7#F=WTȁw;Jzw`o_ĿgL:;+d*x,}5nRھUZohK/[TsJ&t5|;9) V@hGkNm_K^ IENDB`ukui-control-center/data/键盘.png0000664000175000017500000001025013245450075017217 0ustar fengfengPNG  IHDR@@iqtEXtSoftwareAdobe ImageReadyqe<JIDATx[gpT>ZiWҮ@ !$ vi׉%88q .񘉝I<Ό`0c\)2MHH $P[iҪly%w۷o1g+y{]srN99'^I{,_ŏX̧Nj%4 ci҃e(J M1鼜ed, wwkk^J3x'kN46*#k)SnlU#AMmmMu@W8XRli^^gNC^D$$jM.>ANu_zqtla^$OiuyBxTg7qڵko:5Waz0ѻ\rzvACS{ٚ5FX\);p܊5VSں{bN $:x:Wޠ,=o*S:8.=cgس2dP}Io93ϳ-X8ȍ: `6%(iL~9EP^>i Ռ61@ 6,-?7_q#?~55fMA`tz:?|vσdf, Pgƭ'}TXRu))HcH+m]|07y;o#_q3GjJ w14lŢy:1)QѣCPdsDw$'a`炾 4(.ht:Ͼ|5ۃC}-.Jojic |COyjص{_!I,7@[Glxg3:ސgzCZN%s/_W,5M?BVv˽Uvnw8`2% +p|1M5t<0RSt߃EjJ > GdlQ!){i'xHdC2Xi%'§{*`m;ajyY# qz`'_9 '+>߷ZN4.KD1'R>~qHAWT,^wC]>A>{xV΋耂 =,Qxܘ:KabHb*j}Յ_Ws%bBPiܶsWhdYV♞I}j`CȣWbFV1pG٦mV)p~zqCWG[ Vߚj0iʗY6vW{| 3H $.!Azd)'DPEY랇EAi?YtSqhK.{;ng=N *0)=ay3$'t`o/_v0,ʊ9A!OzRm6+dd .v"M34u&Ie,,?IC=ٙN:h?ټaDcA}>lMM3%grCĸatdP)2X< >"lmGv+FڶkX4fK!Jr޾~rP&i?5⇈!!EqIy'iTB4n,aߎ]eAc X¢?Up;B蚝a: Dw}KK^|ѰH *NaXH2=Xz膌  @ *.G,zz En|0 lHqƈm}`tvy5@rĨ󤖶6 JOBY!B @v\aa 9._P f5gnJP$Rl!8wDH҅B_? 1A1 c6bF88 0X[=RxJOA3a pzԐp!Ve-s/ z7}Awxhjk aQTCF 5 MN*(#(MMqcǮXZFmu#̂K?*;HtEs1p>, G_oI8??@\"6 "1Q񪾁A=u N6ֽ?|vv47C`;l\ ob`S( &" Da6 9;; aƌpɬ Q0{4=>/쯮EK.={~ oAdini˔dQ$b|t*?d,3Pifƹ j+)))*NE=8 N} DJmc[&jDvǐW4\SWE1!2jnFv/b g8OkDl׍l}76YC4F`uHM=7_pCx=,]UJrFj?61\%XUx{aq:A<;HM22` 4Uv"'ا';Sn#õALX`^2ӡ|hǔ1Ai,]4\~YнE]6B:{@$#<}pg3;=1dyDA5G}ut6-ϝ};v=dw@7 Q yƳ­^QDH]w#Beyi 34M*[uZ$b1"]ꅦ︙@5&H(2Nq4iֳx#6>1H挆@N(V"K$aA"26FsuE8NOló G-dn0fn%rK|c۲)sQ}Bwrt 1-}+ Ѷ[b@~}Q >uU@l:'kD 15zZq"aYyťO*/-?/?7j§/eu$<,Shkmyg:yj?w['Pt0ז<[k狰<1q3^O,rHB@?'ԷvO9 4ω pރ/(P; uAM}ToAaS'09N-܉~UP {;Fow/(&e2S$fuj5wk5e(%hhQZY:8}oшJ{O#<0FxP0JZĭf,Q+J!q5g0snWWϝ~&tjzv{k/8'~/AVx QH)qQ&Si~7|L9{y"Čd^15`tP?*|?{&n'1x^wdw&xO"iT!ɱ_-R/=?{ YCi|}{lwAJF3n#[:sBKKCKe';r%#0;Ea`}QR|bT{W:S962XA}Pn@8ZF<# BVvwQd?сbf2|PR$zF0I8KM h:fR&#Ol= ?aNƒGPP.ߝRjrc6vM' 8#9~K.JP|Bgmv3q/UDPD2{*5V|}c>E):.#c00oScD$N 1%E1`z!N|'$?2/!))&^jLs\Ks0t9房LRzwXmf B߾/bv _CV 1ԁGVc8-MjwmJ?wЅ $CuӀDe<>x7<~U0h2'w}1J҉eS8BRmPk8DIC,X xo#L#d+9O g{'WQ;DflC[:=#$|uNw@hx`"K fLl=~\bj*('{=IXέw96P!k)Lf+Tp81yUp(`xGN|d39àu i ੆pE/əsp%頦&ڜ_<'pau-j ǂ6PW۴pےGFD©~9:̶J>-\_,:U4m!'' OOz2Ap%Uscد: }``c%1$a@ ̋Wπ/E89N=00 zFRmY7 F@J& 9*\sud)o/CZQ\@MVyʦk6-KE[1Yg|X]$bxL7Jρv:Q'n:zO۪CiYPb(>k+Z!GB{X+6p*Qjՙr4pa [.)sM ٨amlf6^n'+ftBB?uW L>H굃f8J5D{RL p?fqߖ58,rDAwU.mpfXIbiC q>[Uׅ6OZ6=mjb CBJWH'itK ݉6UUOo4ۨ3t0PVA{? })+⺁6mwhA!QCz+_"]sq-JiQUmrv0~ lBoNm0^|~c[{EjN>p":J`RYsc=Žz[{ڊV ɈE2BC57׫hѦЁ }}*=+[]W@ّl *A[*@XRcU+Ȟboxk}?[.awm'+˫5zPbsRz ͠b r 2btȔOKmq)y\[4=y )O"w0]~f֠~mZ2Xr$!8ڥa]iȣ$J,ձVrdoG=9t~Xc^bv<=$!'Eu:*%6 <7;m &:'Sa8m5cw/n h:c e8|5, L6@ྠ5B&4Ϡ/P ‰W >" ;v[̌~jFWޅzA"Sz"#TPTuwgC}>jȵl,.@M7G 'aoI/]<'j8 hgWƾ&fg@Ah Qp'nLwfc z!*: C_z yΕ/߸ v1Йuj N=K=/Q0nds_wt?WK1= 5+!r[Oc];W@5 x׊\V)ohnӋޯ:gBYWfZ0F J<4e!3~s'5xV<) >E\:}V4u%Q;M) 0T*IENDB`ukui-control-center/data/系统检测.png0000664000175000017500000000312413245450075021421 0ustar fengfengPNG  IHDR@@iqtEXtSoftwareAdobe ImageReadyqe<IDATxZioE~fw]Hb;-i^ MRT TC77N%$~_(*BT$)--im(=n\n\q{w@Gkyggk "D!*Ȋ7Ͽ۔)QPY,\>y]E|g "@yC<\tȒ$l^RJ쭧 ;r@> khu$oP ds~b_6 f7x19/8r 7C~TXAHQIrQJ¹<=uW_4v.VE]5߶W (\.)yQ;ӎ?0KsHfh>2Y͞cĜ{ḟ p]}FV0?>#*+ӎ(UDx Z_.տGfV\+JۈԈ>D1VUT́˓ WѵOulWX`9N '<ӁK?6VeC}FbX;AvA T󽩧 w~a+RXL ]*;Ĥ ^VMkX3^.p;f{>AkٜCk3/, Pi0t£ݽǓUmo_@lb,;M0GHBI`g?C~py̞ ^'` ~-2p `eN oBLhuu4y]I@Wȷ"D!` TIENDB`ukui-control-center/data/用户账号.png0000664000175000017500000000714713245450075021412 0ustar fengfengPNG  IHDR@@iqtEXtSoftwareAdobe ImageReadyqe< IDATx[ tTm3o}LVBB$H"&,".E悭HڪHumbvqC 4Vd%$Lfy^@̛Zowe|?Cv͇DЊ` 4 B<5?-qU% B2t*0 )ZG[zB7pdҨ ǥܬe!St;|_54CV GyV)h򘄍,M"k0 $,vԪSkZܜh?LfIw} GJ8p$[ ř0Շ&LVZEO.&d&?IDrLf(@r;R#q7%.cH"WxͺHA2A@LN5G ?;ƧPRDT$&!{6u KE •@s[ vIl( .9Nbpy*'< Mׂ T W,Md C`T2b?3-IYc3aҟH8 DBhDDbcѕ SKKݦW 6-kiƕC$#]Y7aFciiir\hhhhiF_$j@vzְBgNO448̇YNHNW%P#{BJJ 幜N8C=6sZcޯe_C<4"p,((`0,Uw_M~JQ{.d,&KwIv'w [^ 񂣏q|nQQHa oN w9Q %>%];ܧ CqHV)8$\a gR1:NxE,]锢NL-5/Ga1UǏa}?oD9 zo\8eVؾgwX$ۓᖅWx}I1Bm)oBݥ}a]0.!+X"_9;{Ǿ}wnH!@e& tV><\ʫmjn7h>s^᪪MTy.V=EQ}5EP0.cЉOt KJkj$Yw~)_1.){RPSy:L̂ @p}A9O Qkв?m*bʂ,7*5Uܩ . r+o?HPޱ폛[}_WhEAN \i9Stۢ_8_$A2-窢i 'MXf\5>VTMY ʍ˪aU=F?.ּY*X4"8JH5 qP8xOƚ̙EEk^/ Q7n$x 5n~g(dJX)Ѵ`zG˵\xG,}xf{Ӷ˛={Z^^IL8rD )POBWZ U@GgP[ uuuY8v dĨ,'W0Zm||?tR EZ]qgkc2*.V 9&Ǿ*>GyM:u hd =G>R$NkU؀q˶|S6JXÁ9!x~(p^g]AYLtq^vM?1;1rtgu@e~@ζT.Vi.C‚єRCoڶm۲+W>N$jNln [D-:^7m&+D3^;z@Pzz¹/ϙ3B. Du-@ O GxI6YO8!8_b\LS,\K\(42H82UFx:kn4i"=ypk{$x[s˶J3SYJ̹ZuV~uw ޲J?5fb-Zh̶A$PڀG2;(ap&=zʗ2Yu슝@ ,xLJfQaG@dϱO⩌FYTNhcZA[&A@@LJ?qۭa@ASAYJ &vVAq?VnzT2>j -z@i0\=W~u\AQ0Hp)T=hOo?oYzaPXXYYYOS@AZ%lz == ^!䨥rx^nFIdFΕՎN{oPyBs?ҥ`XVHm4uHKG}Qf! 4C*:&Ivs˄PԷ%pf)tķ)L5{/ Rh;HQQ!);ZPQxǣ ({Ƨr˴JyPa< v;,HPa(7$7rC3 mh7R7EynJ~zU.F}Z z"'HǏrI|]^LP`?y–a7j`FKp]dҮdB2DŖ–A$Tv 7)Ee:M/ҫ؈5+I`AD21Lj%LQ(J8M.VLqIQNCY#a$VQB1<0U U U`ҒCEmNelj@G 3A=}@}=hLqiC ;P}JB%&Hf`b;d=AC7xGe{=V@57c3p (Ψ2}Fy&FtE1 Aj&:_ 0ɹ|r IENDB`ukui-control-center/data/打印机.png0000664000175000017500000000225013245450075020253 0ustar fengfengPNG  IHDR@@iqtEXtSoftwareAdobe ImageReadyqe<JIDATx[MLA~ݶlbP @hb8@x1s/r⁛@BH"g/&D("'T--mIeZn}yvrFp8=@ ~N=!}&syߙnL`Zkz{{'&&fS$2[zzzޡIh@ⲘH$Vn7@` ?O"8 0ЧQC8"x|3C6{|1O ך a?6g9rn~_ѓ`<^.{k9wϲ6ݮ@RZaZ'`<ԗI)_-ѠIENDB`ukui-control-center/data/AC.png0000664000175000017500000000247013245450075015323 0ustar fengfengPNG  IHDR szzIDATX]Le?΁s#`R:Dr^eMkk9˚-GKZ .q.Md6lKrR8tԶBjnw]ny<= h+ cԘV&?t8R0dll Ffa6III`fjSN[/xt>w\.$Ib… IOO'//Gx=22رc^EAMeǃlB x͆VE%\`޻wBFF@H$H!^h4ѣX,F#999w%x ,k9rD?"//Sǃ-5ÁU,LOGHIޖpIIIb&!,X.IҲ k.^hv!s(..p`HxiF#OEף j26d޼y7 HLΌ[p崽Φ5[sqgO%wOD1 dggsYA gܹ F)gb͛7( L( $ϟh$j'8ߏ,ˤ͙( |2D(JPh)ŕąD4q4BDYYF[q*F%=#233xG?$ی{gwܥL~nX>::Jq &''ٷ 6mEJfEEcc#7󐑑ĄqR Un|B~.+voyww7/"99ƯXjr\N7p:ttޠ9n 2;χngڵTUmv͚*$3t>ԩS+rS)//g=tuuF,W1Ț^τǏj֭L&Ǐ*--2%H'MMM-߰sN-_Buu5YΜ9C,.(K455z,{͍>'ʆ $''}DaR(OP[[˒BD4՞.128ȁ鲝;v03qISn WM"ͱ]yX!]L}B[DE3*G 5Z-137 Ud Uh