ukui-settings-daemon/0000755000175000017500000000000014205117202013544 5ustar fengfengukui-settings-daemon/plugins/0000755000175000017500000000000014205117202015225 5ustar fengfengukui-settings-daemon/plugins/xsettings/0000755000175000017500000000000014205117202017255 5ustar fengfengukui-settings-daemon/plugins/xsettings/ukui-xsettings-manager.h0000644000175000017500000000302114205117202024035 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UKUIXSETTINGSMANAGER_H #define UKUIXSETTINGSMANAGER_H #include #include #include #include #include #include #include //#include "ixsettings-manager.h" #include "xsettings-manager.h" #include "fontconfig-monitor.h" class ukuiXSettingsManager { public: ukuiXSettingsManager(); ~ukuiXSettingsManager(); bool start(); int stop(); void sendSessionDbus(); //gboolean setup_xsettings_managers (ukuiXSettingsManager *manager); XsettingsManager **pManagers; GHashTable *gsettings; GSettings *gsettings_font; //GSettings *plugin_settings; fontconfig_monitor_handle_t *fontconfig_handle; }; #endif // UKUIXSETTINGSMANAGER_H ukui-settings-daemon/plugins/xsettings/xsettings-common.c0000644000175000017500000001421714205117202022744 0ustar fengfeng/* * Copyright © 2001 Red Hat, Inc. * * 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, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Owen Taylor, Red Hat, Inc. */ #include "string.h" #include "stdlib.h" #include #include /* For CARD32 */ #include "xsettings-common.h" XSettingsSetting * xsettings_setting_copy (XSettingsSetting *setting) { XSettingsSetting *result; size_t str_len; result = malloc (sizeof *result); if (!result) return NULL; str_len = strlen (setting->name); result->name = malloc (str_len + 1); if (!result->name) goto err; memcpy (result->name, setting->name, str_len + 1); result->type = setting->type; switch (setting->type) { case XSETTINGS_TYPE_INT: result->data.v_int = setting->data.v_int; break; case XSETTINGS_TYPE_COLOR: result->data.v_color = setting->data.v_color; break; case XSETTINGS_TYPE_STRING: str_len = strlen (setting->data.v_string); result->data.v_string = malloc (str_len + 1); if (!result->data.v_string) goto err; memcpy (result->data.v_string, setting->data.v_string, str_len + 1); break; } result->last_change_serial = setting->last_change_serial; return result; err: if (result->name) free (result->name); free (result); return NULL; } XSettingsList * xsettings_list_copy (XSettingsList *list) { XSettingsList *new = NULL; XSettingsList *old_iter = list; XSettingsList *new_iter = NULL; while (old_iter) { XSettingsList *new_node; new_node = malloc (sizeof *new_node); if (!new_node) goto error; new_node->setting = xsettings_setting_copy (old_iter->setting); if (!new_node->setting) { free (new_node); goto error; } if (new_iter) new_iter->next = new_node; else new = new_node; new_iter = new_node; old_iter = old_iter->next; } return new; error: xsettings_list_free (new); return NULL; } int xsettings_setting_equal (XSettingsSetting *setting_a, XSettingsSetting *setting_b) { if (setting_a->type != setting_b->type) return 0; if (strcmp (setting_a->name, setting_b->name) != 0) return 0; switch (setting_a->type) { case XSETTINGS_TYPE_INT: return setting_a->data.v_int == setting_b->data.v_int; case XSETTINGS_TYPE_COLOR: return (setting_a->data.v_color.red == setting_b->data.v_color.red && setting_a->data.v_color.green == setting_b->data.v_color.green && setting_a->data.v_color.blue == setting_b->data.v_color.blue && setting_a->data.v_color.alpha == setting_b->data.v_color.alpha); case XSETTINGS_TYPE_STRING: return strcmp (setting_a->data.v_string, setting_b->data.v_string) == 0; } return 0; } void xsettings_setting_free (XSettingsSetting *setting) { if (setting->type == XSETTINGS_TYPE_STRING) free (setting->data.v_string); if (setting->name) free (setting->name); free (setting); } void xsettings_list_free (XSettingsList *list) { while (list) { XSettingsList *next = list->next; xsettings_setting_free (list->setting); free (list); list = next; } } XSettingsResult xsettings_list_insert (XSettingsList **list, XSettingsSetting *setting) { XSettingsList *node; XSettingsList *iter; XSettingsList *last = NULL; node = malloc (sizeof *node); if (!node) return XSETTINGS_NO_MEM; node->setting = setting; iter = *list; while (iter) { int cmp = strcmp (setting->name, iter->setting->name); if (cmp < 0) break; else if (cmp == 0) { free (node); return XSETTINGS_DUPLICATE_ENTRY; } last = iter; iter = iter->next; } if (last) last->next = node; else *list = node; node->next = iter; return XSETTINGS_SUCCESS; } XSettingsResult xsettings_list_delete (XSettingsList **list, const char *name) { XSettingsList *iter; XSettingsList *last = NULL; iter = *list; while (iter) { if (strcmp (name, iter->setting->name) == 0) { if (last) last->next = iter->next; else *list = iter->next; xsettings_setting_free (iter->setting); free (iter); return XSETTINGS_SUCCESS; } last = iter; iter = iter->next; } return XSETTINGS_FAILED; } XSettingsSetting * xsettings_list_lookup (XSettingsList *list, const char *name) { XSettingsList *iter; iter = list; while (iter) { if (strcmp (name, iter->setting->name) == 0) { return iter->setting; } iter = iter->next; } return NULL; } char xsettings_byte_order (void) { CARD32 myint = 0x01020304; return (*(char *)&myint == 1) ? MSBFirst : LSBFirst; } ukui-settings-daemon/plugins/xsettings/xsettings-const.h0000644000175000017500000000452514205117202022610 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XSETTINGSCOMMON_H #define XSETTINGSCOMMON_H #define MOUSE_SCHEMA "org.ukui.peripherals-mouse" #define INTERFACE_SCHEMA "org.mate.interface" #define SOUND_SCHEMA "org.mate.sound" #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" #define XSETTINGS_PLUGIN_SCHEMA "org.ukui.SettingsDaemon.plugins.xsettings" #define SCALING_FACTOR_KEY "scaling-factor" /* X servers sometimes lie about the screen's physical dimensions, so we cannot * compute an accurate DPI value. When this happens, the user gets fonts that * are too huge or too tiny. So, we see what the server returns: if it reports * something outside of the range [DPI_LOW_REASONABLE_VALUE, * DPI_HIGH_REASONABLE_VALUE], then we assume that it is lying and we use * DPI_FALLBACK instead. * * See get_dpi_from_gsettings_or_server() below, and also * https://bugzilla.novell.com/show_bug.cgi?id=217790 */ #define DPI_FALLBACK 96 #define DPI_LOW_REASONABLE_VALUE 50 #define DPI_HIGH_REASONABLE_VALUE 500 /* The minimum resolution at which we turn on a window-scale of 2 */ #define HIDPI_LIMIT (DPI_FALLBACK * 2) /* The minimum screen height at which we turn on a window-scale of 2; * below this there just isn't enough vertical real estate for GNOME * apps to work, and it's better to just be tiny */ #define HIDPI_MIN_HEIGHT 1500 #endif // XSETTINGSCOMMON_H ukui-settings-daemon/plugins/xsettings/fontconfig-monitor.c0000644000175000017500000001056114205117202023245 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. * * Author: Behdad Esfahbod, Red Hat, Inc. */ #include "fontconfig-monitor.h" #include #include #define TIMEOUT_SECONDS 2 static void stuff_changed (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, gpointer handle); void fontconfig_cache_init (void) { FcInit (); } gboolean fontconfig_cache_update (void) { return !FcConfigUptoDate (NULL) && FcInitReinitialize (); } static void monitor_files (GPtrArray *monitors, FcStrList *list, gpointer data) { const char *str; while ((str = (const char *) FcStrListNext (list))) { GFile *file; GFileMonitor *monitor; file = g_file_new_for_path (str); monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, NULL); g_object_unref (file); if (!monitor) continue; g_signal_connect (monitor, "changed", G_CALLBACK (stuff_changed), data); g_ptr_array_add (monitors, monitor); } FcStrListDone (list); } struct _fontconfig_monitor_handle { GPtrArray *monitors; guint timeout; GFunc notify_callback; gpointer notify_data; }; static GPtrArray * monitors_create (gpointer data) { GPtrArray *monitors = g_ptr_array_new (); monitor_files (monitors, FcConfigGetConfigFiles (NULL), data); monitor_files (monitors, FcConfigGetFontDirs (NULL), data); return monitors; } static void monitors_free (GPtrArray *monitors) { if (!monitors) return; g_ptr_array_foreach (monitors, (GFunc) g_object_unref, NULL); g_ptr_array_free (monitors, TRUE); } static gboolean update (gpointer data) { fontconfig_monitor_handle_t *handle = data; gboolean notify = FALSE; handle->timeout = 0; if (fontconfig_cache_update ()) { notify = TRUE; monitors_free (handle->monitors); handle->monitors = monitors_create (data); } /* we finish modifying handle before calling the notify callback, * allowing the callback to free the monitor if it decides to. */ if (notify && handle->notify_callback) handle->notify_callback (data, handle->notify_data); return FALSE; } static void stuff_changed (GFileMonitor *monitor G_GNUC_UNUSED, GFile *file G_GNUC_UNUSED, GFile *other_file G_GNUC_UNUSED, GFileMonitorEvent event_type G_GNUC_UNUSED, gpointer data) { fontconfig_monitor_handle_t *handle = data; /* wait for quiescence */ if (handle->timeout) g_source_remove (handle->timeout); handle->timeout = g_timeout_add_seconds (TIMEOUT_SECONDS, update, data); } fontconfig_monitor_handle_t * fontconfig_monitor_start (GFunc notify_callback, gpointer notify_data) { fontconfig_monitor_handle_t *handle = g_slice_new0 (fontconfig_monitor_handle_t); handle->notify_callback = notify_callback; handle->notify_data = notify_data; handle->monitors = monitors_create (handle); return handle; } void fontconfig_monitor_stop (fontconfig_monitor_handle_t *handle) { if (handle->timeout) g_source_remove (handle->timeout); handle->timeout = 0; monitors_free (handle->monitors); handle->monitors = NULL; } #ifdef FONTCONFIG_MONITOR_TEST static void yay (void) { g_message ("yay"); } int main (void) { GMainLoop *loop; fontconfig_monitor_start ((GFunc) yay, NULL); loop = g_main_loop_new (NULL, TRUE); g_main_loop_run (loop); return 0; } #endif ukui-settings-daemon/plugins/xsettings/xsettings.pro0000644000175000017500000000205414205117202022030 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-05-30T09:30:00 # #------------------------------------------------- QT += gui QT += core widgets x11extras dbus CONFIG += c++11 no_keywords link_pkgconfig plugin CONFIG += app_bunale DEFINES += QT_DEPRECATED_WARNINGS TEMPLATE = lib TARGET = xsettings DEFINES += QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"xsettings\\\" include($$PWD/../../common/common.pri) PKGCONFIG +=\ glib-2.0 \ gio-2.0 \ gdk-3.0 \ atk \ fontconfig \ xcursor \ xfixes SOURCES += \ ukui-xsettings-plugin.cpp \ xsettings-manager.cpp \ ukui-xsettings-manager.cpp \ ukui-xft-settings.cpp \ xsettings-common.c \ fontconfig-monitor.c HEADERS += \ ukui-xsettings-plugin.h \ xsettings-manager.h \ ukui-xsettings-manager.h \ ukui-xft-settings.h \ xsettings-const.h \ xsettings-common.h \ fontconfig-monitor.h xsettings_lib.path = $${PLUGIN_INSTALL_DIRS} xsettings_lib.files += $$OUT_PWD/libxsettings.so INSTALLS += xsettings_lib ukui-settings-daemon/plugins/xsettings/ukui-xft-settings.cpp0000644000175000017500000003556014205117202023404 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "xsettings-const.h" #include "ukui-xft-settings.h" #include "ukui-xsettings-manager.h" #ifdef __cplusplus extern "C" { #endif #include #include #include #ifdef __cplusplus } #endif static const char *rgba_types[] = { "rgb", "bgr", "vbgr", "vrgb" }; static void update_property (GString *props, const gchar* key, const gchar* value) { gchar* needle; size_t needle_len; gchar* found = NULL; /* update an existing property */ needle = g_strconcat (key, ":", NULL); needle_len = strlen (needle); if (g_str_has_prefix (props->str, needle)) found = props->str; else found = strstr (props->str, needle); if (found) { size_t value_index; gchar* end; end = strchr (found, '\n'); value_index = (found - props->str) + needle_len + 1; g_string_erase (props, value_index, end ? (end - found - needle_len) : -1); g_string_insert (props, value_index, "\n"); g_string_insert (props, value_index, value); } else { g_string_append_printf (props, "%s:\t%s\n", key, value); } g_free (needle); } static double dpi_from_pixels_and_mm (int pixels, int mm) { double dpi; if (mm >= 1) dpi = pixels / (mm / 25.4); else dpi = 0; return dpi; } static double get_dpi_from_x_server (void) { GdkScreen *screen; double dpi; screen = gdk_screen_get_default (); if (screen != NULL) { double width_dpi, height_dpi; Screen *xscreen = gdk_x11_screen_get_xscreen (screen); width_dpi = dpi_from_pixels_and_mm (WidthOfScreen (xscreen), WidthMMOfScreen (xscreen)); height_dpi = dpi_from_pixels_and_mm (HeightOfScreen (xscreen), HeightMMOfScreen (xscreen)); if (width_dpi < DPI_LOW_REASONABLE_VALUE || width_dpi > DPI_HIGH_REASONABLE_VALUE || height_dpi < DPI_LOW_REASONABLE_VALUE || height_dpi > DPI_HIGH_REASONABLE_VALUE) { dpi = DPI_FALLBACK; } else { dpi = (width_dpi + height_dpi) / 2.0; } } else { /* Huh!? No screen? */ dpi = DPI_FALLBACK; } return dpi; } static double get_dpi_from_gsettings_or_x_server (GSettings *gsettings) { double value; double dpi; value = g_settings_get_double (gsettings, FONT_DPI_KEY); /* If the user has ever set the DPI preference in GSettings, we use that. * Otherwise, we see if the X server reports a reasonable DPI value: some X * servers report completely bogus values, and the user gets huge or tiny * fonts which are unusable. */ if (value != 0) { dpi = value; } else { dpi = DPI_FALLBACK;//get_dpi_from_x_server (); } return dpi; } /* Auto-detect the most appropriate scale factor for the primary monitor. * A lot of this code is copied and adapted from Linux Mint/Cinnamon. * 如果设置缩放为0,通过获取物理显示器的分辨率大小进行设置合适的DPI缩放 */ static int get_window_scale_auto () { GdkDisplay *display; GdkMonitor *monitor; GdkRectangle rect; int width_mm, height_mm; int monitor_scale, window_scale; display = gdk_display_get_default (); monitor = gdk_display_get_primary_monitor (display); /* Use current value as the default */ window_scale = 1; gdk_monitor_get_geometry (monitor, &rect); width_mm = gdk_monitor_get_width_mm (monitor); height_mm = gdk_monitor_get_height_mm (monitor); monitor_scale = gdk_monitor_get_scale_factor (monitor); if (rect.height * monitor_scale < HIDPI_MIN_HEIGHT) return 1; /* Some monitors/TV encode the aspect ratio (16/9 or 16/10) instead of the physical size */ if ((width_mm == 160 && height_mm == 90) || (width_mm == 160 && height_mm == 100) || (width_mm == 16 && height_mm == 9) || (width_mm == 16 && height_mm == 10)) return 1; if (width_mm > 0 && height_mm > 0) { double dpi_x, dpi_y; dpi_x = (double)rect.width * monitor_scale / (width_mm / 25.4); dpi_y = (double)rect.height * monitor_scale / (height_mm / 25.4); /* We don't completely trust these values so both must be high, and never pick * higher ratio than 2 automatically */ if (dpi_x > HIDPI_LIMIT && dpi_y > HIDPI_LIMIT) window_scale = 2; } return window_scale; } /* Get the key value to set the zoom * 获取要设置缩放的键值 */ static double get_window_scale (ukuiXSettingsManager *manager) { GSettings *gsettings; double scale; gsettings = (GSettings *)g_hash_table_lookup(manager->gsettings,XSETTINGS_PLUGIN_SCHEMA); scale = g_settings_get_double (gsettings, SCALING_FACTOR_KEY); /* Auto-detect */ if (scale == 0) scale = get_window_scale_auto (); return scale; } void UkuiXftSettings::xft_settings_set_xsettings (ukuiXSettingsManager *manager) { int i; double scale = get_window_scale (manager); if(scale >= 2.0) scale = scale - 1.0; if(scale >= 3.0) scale = scale - 2.0; for (i = 0; manager->pManagers [i]; i++) { manager->pManagers [i]->set_int ("Xft/Antialias", antialias); manager->pManagers [i]->set_int ("Xft/Hinting", hinting); manager->pManagers [i]->set_string ("Xft/HintStyle", hintstyle); manager->pManagers [i]->set_int ( "Gdk/WindowScalingFactor",window_scale); manager->pManagers [i]->set_int ("Gdk/UnscaledDPI",(double)dpi * scale); manager->pManagers [i]->set_int ("Xft/DPI", scaled_dpi); manager->pManagers [i]->set_string ("Xft/RGBA", rgba); manager->pManagers [i]->set_string ("Xft/lcdfilter", g_str_equal (rgba, "rgb") ? "lcddefault" : "none"); manager->pManagers [i]->set_int ("Gtk/CursorThemeSize", cursor_size); manager->pManagers [i]->set_string ("Gtk/CursorThemeName", cursor_theme); GdkCursor *cursor = gdk_cursor_new_for_display(gdk_display_get_default(), GDK_LEFT_PTR); gdk_window_set_cursor(gdk_get_default_root_window(), cursor); g_object_unref(G_OBJECT(cursor)); } } void UkuiXftSettings::xft_settings_get (ukuiXSettingsManager *manager) { GSettings *mouse_gsettings; char *antialiasing; char *hinting; char *rgba_order; double dpi; double scale; mouse_gsettings = (GSettings *)g_hash_table_lookup (manager->gsettings, (void*)MOUSE_SCHEMA); antialiasing = g_settings_get_string (manager->gsettings_font, FONT_ANTIALIASING_KEY); hinting = g_settings_get_string (manager->gsettings_font, FONT_HINTING_KEY); rgba_order = g_settings_get_string (manager->gsettings_font, FONT_RGBA_ORDER_KEY); dpi = get_dpi_from_gsettings_or_x_server (manager->gsettings_font); scale = get_window_scale (manager); antialias = TRUE; this->hinting = TRUE; hintstyle = "hintslight"; if (scale >= 0 && scale <= 1.5) { this->window_scale = 1; } else if (scale >= 1.75 && scale <= 2.5) { this->window_scale = 2; } else if (scale >= 2.75) { this->window_scale = 3; } this->dpi = dpi * 1024; /* Xft wants 1/1024ths of an inch */ this->scaled_dpi = dpi * scale * 1024; cursor_theme = g_settings_get_string (mouse_gsettings, CURSOR_THEME_KEY); cursor_size = g_settings_get_int (mouse_gsettings, CURSOR_SIZE_KEY); rgba = "rgb"; if (rgba_order) { int i; gboolean found = FALSE; for (i = 0; i < (int)G_N_ELEMENTS (rgba_types) && !found; i++) { if (strcmp (rgba_order, rgba_types[i]) == 0) { rgba = rgba_types[i]; found = TRUE; } } if (!found) { g_warning ("Invalid value for " FONT_RGBA_ORDER_KEY ": '%s'", rgba_order); } } if (hinting) { if (strcmp (hinting, "none") == 0) { this->hinting = 0; hintstyle = "hintnone"; } else if (strcmp (hinting, "slight") == 0) { this->hinting = 1; hintstyle = "hintslight"; } else if (strcmp (hinting, "medium") == 0) { this->hinting = 1; hintstyle = "hintmedium"; } else if (strcmp (hinting, "full") == 0) { this->hinting = 1; hintstyle = "hintfull"; } else { g_warning ("Invalid value for " FONT_HINTING_KEY ": '%s'", hinting); } } if (antialiasing) { gboolean use_rgba = FALSE; if (strcmp (antialiasing, "none") == 0) { antialias = 0; } else if (strcmp (antialiasing, "grayscale") == 0) { antialias = 1; } else if (strcmp (antialiasing, "rgba") == 0) { antialias = 1; use_rgba = TRUE; } else { g_warning ("Invalid value for " FONT_ANTIALIASING_KEY " : '%s'", antialiasing); } if (!use_rgba) { rgba = "none"; } } g_free (rgba_order); g_free (hinting); g_free (antialiasing); } void UkuiXftSettings::xft_settings_set_xresources () { GString *add_string; char dpibuf[G_ASCII_DTOSTR_BUF_SIZE]; Display *dpy; /* get existing properties */ dpy = XOpenDisplay (NULL); g_return_if_fail (dpy != NULL); add_string = g_string_new (XResourceManagerString (dpy)); g_debug("xft_settings_set_xresources: orig res '%s'", add_string->str); char tmpCursorTheme[255] = {'\0'}; int tmpCursorSize = 0; if (strlen (this->cursor_theme) > 0) { strncpy(tmpCursorTheme, this->cursor_theme, 255); } else { // unset, use default strncpy(tmpCursorTheme, "DMZ-Black", 255); } if (this->cursor_size > 0) { tmpCursorSize = this->cursor_size; } else { tmpCursorSize = XcursorGetDefaultSize(dpy); } QDir dir; QString FilePath = dir.homePath() + "/.xresources"; QFile file; QString date = QString("Xcursor.size:%1\n" "Xcursor.theme:%2").arg(cursor_size).arg(cursor_theme); file.setFileName(FilePath); if(file.open(QIODevice::WriteOnly | QIODevice::Text)){ file.write(date.toLatin1().data()); } file.close(); update_property (add_string, "Xft.dpi", g_ascii_dtostr (dpibuf, sizeof (dpibuf), (double) this->scaled_dpi / 1024.0)); update_property (add_string, "Xft.antialias", this->antialias ? "1" : "0"); update_property (add_string, "Xft.hinting", this->hinting ? "1" : "0"); update_property (add_string, "Xft.hintstyle", this->hintstyle); update_property (add_string, "Xft.rgba", this->rgba); update_property (add_string, "Xft.lcdfilter", g_str_equal (this->rgba, "rgb") ? "lcddefault" : "none"); update_property (add_string, "Xcursor.theme", this->cursor_theme); update_property (add_string, "Xcursor.size", g_ascii_dtostr (dpibuf, sizeof (dpibuf), (double) this->cursor_size)); g_debug("xft_settings_set_xresources: new res '%s'", add_string->str); /* Set the new X property */ XChangeProperty(dpy, RootWindow (dpy, 0), XA_RESOURCE_MANAGER, XA_STRING, 8, PropModeReplace, (unsigned char *) add_string->str, add_string->len); // begin add:for qt adjust cursor size&theme. add by liutong const char *CursorsNames[] = { "X_cursor" , "arrow" , "bottom_side" , "bottom_tee" , "bd_double_arrow", "bottom_left_corner", "bottom_right_corner", "color-picker", "cross" , "cross_reverse" , "copy" , "circle" , "crossed_circle", "dnd-ask" , "dnd-copy" , "dnd-link" , "dnd-move" , "dnd-none" , "dot_box_mask" , "fd_double_arrow", "crosshair" , "diamond_cross" , "dotbox" , "draped_box" , "double_arrow" , "draft_large" , "draft_small" , "fleur" , "grabbing" , "help" , "hand", "hand1" , "hand2" , "icon" , "left_ptr" , "left_side" , "left_tee" , "left_ptr_watch", "ll_angle" , "lr_angle" , "link" , "move" , "pencil" , "pirate" , "plus" , "question_arrow", "right_ptr" , "right_side" , "right_tee" , "sb_down_arrow" , "sb_h_double_arrow", "sb_left_arrow" , "sb_right_arrow" , "sb_up_arrow" , "sb_v_double_arrow", "target" , "tcross" , "top_left_arrow", "top_left_corner" , "top_right_corner", "top_side" , "top_tee" , "ul_angle" , "ur_angle" , "watch" , "xterm" , "h_double_arrow" , "v_double_arrow" , "left_ptr_help", NULL}; if (strlen (tmpCursorTheme) > 0 ) { int len = sizeof(CursorsNames)/sizeof(*CursorsNames); for (int i = 0; i < len-1; i++) { XcursorImages *images = XcursorLibraryLoadImages(CursorsNames[i], tmpCursorTheme, tmpCursorSize); if (!images) { g_debug("xcursorlibrary load images :null image, theme name=%s", tmpCursorTheme); continue; } Cursor handle = XcursorImagesLoadCursor(dpy, images); int event_base, error_base; if (XFixesQueryExtension(dpy, &event_base, &error_base)) { int major, minor; XFixesQueryVersion(dpy, &major, &minor); if (major >= 2) { g_debug("set CursorNmae=%s", CursorsNames[i]); XFixesSetCursorName(dpy, handle, CursorsNames[i]); } } XFixesChangeCursorByName(dpy, handle, CursorsNames[i]); XcursorImagesDestroy(images); } } // end add XCloseDisplay (dpy); g_string_free (add_string, TRUE); } ukui-settings-daemon/plugins/xsettings/xsettings-manager.cpp0000644000175000017500000002470114205117202023425 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "xsettings-manager.h" #include "xsettings-const.h" #include #include #include #include #include #include #include static Time get_server_time (Display *display, Window window); static XSettingsList *Settings; XsettingsManager::XsettingsManager(Display *display, int screen, XSettingsTerminateFunc terminate, int *cb_data) { XClientMessageEvent xev; this->display = display; this->screen = screen; char buffer[256]; sprintf(buffer, "_XSETTINGS_S%d", this->screen); this->selection_atom = XInternAtom (display, buffer, False); this->xsettings_atom = XInternAtom (display, "_XSETTINGS_SETTINGS", False); this->manager_atom = XInternAtom (display, "MANAGER", False); this->terminate = terminate; this->cb_data = cb_data; this->settings = NULL; this->serial = 0; this->window = XCreateSimpleWindow (display, RootWindow (display, screen), 0, 0, 10, 10, 0, WhitePixel (display, screen), WhitePixel (display, screen)); XSelectInput (display, this->window, PropertyChangeMask); Time timestamp; timestamp = get_server_time (display, this->window); XSetSelectionOwner (display, this->selection_atom, this->window, timestamp); /* Check to see if we managed to claim the selection. If not, * we treat it as if we got it then immediately lost it */ if (XGetSelectionOwner (display, this->selection_atom) == this->window) { xev.type = ClientMessage; xev.window = RootWindow (display, screen); xev.message_type = this->manager_atom; xev.format = 32; xev.data.l[0] = timestamp; xev.data.l[1] = this->selection_atom; xev.data.l[2] = this->window; xev.data.l[3] = 0; /* manager specific data */ xev.data.l[4] = 0; /* manager specific data */ XSendEvent (display, RootWindow (display, screen), False, StructureNotifyMask, (XEvent *)&xev); } else { this->terminate ((int*)this->cb_data); } } XsettingsManager::~XsettingsManager() { XDestroyWindow (display, window); xsettings_list_free (settings); } /** * get_server_time: * @display: display from which to get the time * @window: a #Window, used for communication with the server. * The window must have PropertyChangeMask in its * events mask or a hang will result. * * Routine to get the current X server time stamp. * * Return value: the time stamp. **/ typedef struct { Window window; Atom timestamp_prop_atom; } TimeStampInfo; static Bool timestamp_predicate (Display *display, XEvent *xevent, XPointer arg) { TimeStampInfo *info = (TimeStampInfo *)arg; if (xevent->type == PropertyNotify && xevent->xproperty.window == info->window && xevent->xproperty.atom == info->timestamp_prop_atom) return True; return False; } static Time get_server_time (Display *display, Window window) { unsigned char c = 'a'; XEvent xevent; TimeStampInfo info; info.timestamp_prop_atom = XInternAtom (display, "_TIMESTAMP_PROP", False); info.window = window; XChangeProperty (display, window, info.timestamp_prop_atom, info.timestamp_prop_atom, 8, PropModeReplace, &c, 1); XIfEvent (display, &xevent, timestamp_predicate, (XPointer)&info); return xevent.xproperty.time; } Window XsettingsManager::get_window() { return window; } Bool XsettingsManager::process_event (XEvent *xev) { if (xev->xany.window == this->window && xev->xany.type == SelectionClear && xev->xselectionclear.selection == this->selection_atom) { this->terminate ((int *)this->cb_data); return True; } return False; } XSettingsResult XsettingsManager::delete_setting (const char *name) { return xsettings_list_delete (&Settings, name); } XSettingsResult XsettingsManager::set_setting (XSettingsSetting *setting) { XSettingsSetting *old_setting = xsettings_list_lookup (Settings, setting->name); XSettingsSetting *new_setting; XSettingsResult result; if (old_setting) { if (xsettings_setting_equal (old_setting, setting)) return XSETTINGS_SUCCESS; xsettings_list_delete (&Settings, setting->name); } new_setting = xsettings_setting_copy (setting); if (!new_setting) return XSETTINGS_NO_MEM; new_setting->last_change_serial = this->serial; result = xsettings_list_insert (&Settings, new_setting); if (result != XSETTINGS_SUCCESS) xsettings_setting_free (new_setting); return result; } XSettingsResult XsettingsManager::set_int (const char *name, int value) { XSettingsSetting setting; setting.name = (char *)name; setting.type = XSETTINGS_TYPE_INT; setting.data.v_int = value; return set_setting (&setting); } XSettingsResult XsettingsManager::set_string (const char *name, const char *value) { XSettingsSetting setting; setting.name = (char *)name; setting.type = XSETTINGS_TYPE_STRING; setting.data.v_string = (char *)value; return set_setting (&setting); } XSettingsResult XsettingsManager::set_color (const char *name, XSettingsColor *value) { XSettingsSetting setting; setting.name = (char *)name; setting.type = XSETTINGS_TYPE_COLOR; setting.data.v_color = *value; return set_setting (&setting); } static size_t setting_length (XSettingsSetting *setting) { size_t length = 8; /* type + pad + name-len + last-change-serial */ length += XSETTINGS_PAD (strlen (setting->name), 4); switch (setting->type) { case XSETTINGS_TYPE_INT: length += 4; break; case XSETTINGS_TYPE_STRING: length += 4 + XSETTINGS_PAD (strlen (setting->data.v_string), 4); break; case XSETTINGS_TYPE_COLOR: length += 8; break; } return length; } Bool xsettings_manager_check_running (Display *display, int screen) { char buffer[256]; Atom selection_atom; sprintf(buffer, "_XSETTINGS_S%d", screen); selection_atom = XInternAtom (display, buffer, False); gdk_x11_display_error_trap_push (gdk_display_get_default()); if (XGetSelectionOwner (display, selection_atom)){ gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default()); return True; } else return False; } void XsettingsManager::setting_store (XSettingsSetting *setting, XSettingsBuffer *buffer) { size_t string_len; size_t length; *(buffer->pos++) = setting->type; *(buffer->pos++) = 0; string_len = strlen (setting->name); *(CARD16 *)(buffer->pos) = string_len; buffer->pos += 2; length = XSETTINGS_PAD (string_len, 4); memcpy (buffer->pos, setting->name, string_len); length -= string_len; buffer->pos += string_len; while (length > 0) { *(buffer->pos++) = 0; length--; } *(CARD32 *)(buffer->pos) = setting->last_change_serial; buffer->pos += 4; switch (setting->type) { case XSETTINGS_TYPE_INT: *(CARD32 *)(buffer->pos) = setting->data.v_int; buffer->pos += 4; break; case XSETTINGS_TYPE_STRING: string_len = strlen (setting->data.v_string); *(CARD32 *)(buffer->pos) = string_len; buffer->pos += 4; length = XSETTINGS_PAD (string_len, 4); memcpy (buffer->pos, setting->data.v_string, string_len); length -= string_len; buffer->pos += string_len; while (length > 0) { *(buffer->pos++) = 0; length--; } break; case XSETTINGS_TYPE_COLOR: *(CARD16 *)(buffer->pos) = setting->data.v_color.red; *(CARD16 *)(buffer->pos + 2) = setting->data.v_color.green; *(CARD16 *)(buffer->pos + 4) = setting->data.v_color.blue; *(CARD16 *)(buffer->pos + 6) = setting->data.v_color.alpha; buffer->pos += 8; break; } } XSettingsResult XsettingsManager::notify() { XSettingsBuffer buffer; XSettingsList *iter; int n_settings = 0; buffer.len = 12; /* byte-order + pad + SERIAL + N_SETTINGS */ iter = Settings; while (iter) { buffer.len += setting_length (iter->setting); n_settings++; iter = iter->next; } buffer.data = buffer.pos = new unsigned char[buffer.len]; if (!buffer.data) return XSETTINGS_NO_MEM; *buffer.pos = xsettings_byte_order (); buffer.pos += 4; *(CARD32 *)buffer.pos = this->serial++; buffer.pos += 4; *(CARD32 *)buffer.pos = n_settings; buffer.pos += 4; iter = Settings; while (iter) { setting_store (iter->setting, &buffer); iter = iter->next; } XChangeProperty (this->display, this->window, this->xsettings_atom, this->xsettings_atom, 8, PropModeReplace, buffer.data, buffer.len); free (buffer.data); return XSETTINGS_SUCCESS; } ukui-settings-daemon/plugins/xsettings/ukui-xsettings-plugin.cpp0000644000175000017500000000351714205117202024266 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "ukui-xsettings-plugin.h" #include "clib-syslog.h" PluginInterface *XSettingsPlugin::mInstance =nullptr; ukuiXSettingsManager *XSettingsPlugin::m_pukuiXsettingManager = nullptr; XSettingsPlugin::XSettingsPlugin() { if(nullptr == m_pukuiXsettingManager) m_pukuiXsettingManager = new ukuiXSettingsManager(); } XSettingsPlugin::~XSettingsPlugin() { if (m_pukuiXsettingManager) { delete m_pukuiXsettingManager; m_pukuiXsettingManager = nullptr; } } void XSettingsPlugin::activate() { bool res; res = m_pukuiXsettingManager->start(); if (!res) { qWarning ("Unable to start XSettingsPlugin manager"); } USD_LOG (LOG_DEBUG, "Activating %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); } void XSettingsPlugin::deactivate() { m_pukuiXsettingManager->stop(); } PluginInterface *XSettingsPlugin::getInstance() { if(nullptr == mInstance) mInstance = new XSettingsPlugin(); return mInstance; } PluginInterface* createSettingsPlugin() { return XSettingsPlugin::getInstance(); } ukui-settings-daemon/plugins/xsettings/ukui-xsettings-manager.cpp0000644000175000017500000004370214205117202024402 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "ukui-xsettings-manager.h" #include "xsettings-manager.h" #include "fontconfig-monitor.h" #include "ukui-xft-settings.h" #include "xsettings-const.h" #include #include #include "clib-syslog.h" #include #include #include #define MOUSE_SCHEMA "org.ukui.peripherals-mouse" #define INTERFACE_SCHEMA "org.mate.interface" #define SOUND_SCHEMA "org.mate.sound" #define CURSOR_THEME_KEY "cursor-theme" #define CURSOR_SIZE_KEY "cursor-size" /* X servers sometimes lie about the screen's physical dimensions, so we cannot * compute an accurate DPI value. When this happens, the user gets fonts that * are too huge or too tiny. So, we see what the server returns: if it reports * something outside of the range [DPI_LOW_REASONABLE_VALUE, * DPI_HIGH_REASONABLE_VALUE], then we assume that it is lying and we use * DPI_FALLBACK instead. * * See get_dpi_from_gsettings_or_server() below, and also * https://bugzilla.novell.com/show_bug.cgi?id=217790 */ #define DPI_FALLBACK 96 #define DPI_LOW_REASONABLE_VALUE 50 #define DPI_HIGH_REASONABLE_VALUE 500 typedef struct _TranslationEntry TranslationEntry; typedef void (* TranslationFunc) (ukuiXSettingsManager *manager, TranslationEntry *trans, GVariant *value); struct _TranslationEntry { const char *gsettings_schema; const char *gsettings_key; const char *xsetting_name; TranslationFunc translate; }; struct ukuiXSettingsManagerPrivate { XsettingsManager **pManagers; GHashTable *gsettings; GSettings *gsettings_font; // fontconfig_monitor_handle_t *fontconfig_handle; }; #define USD_XSETTINGS_ERROR usd_xsettings_error_quark () enum { USD_XSETTINGS_ERROR_INIT }; static void fontconfig_callback (fontconfig_monitor_handle_t *handle, ukuiXSettingsManager *manager); static void xft_callback (GSettings *gsettings, const gchar *key, ukuiXSettingsManager *manager); static GQuark usd_xsettings_error_quark (void) { return g_quark_from_static_string ("usd-xsettings-error-quark"); } static void translate_bool_int (ukuiXSettingsManager *manager, TranslationEntry *trans, GVariant *value) { int i; for (i = 0; manager->pManagers [i]; i++) { manager->pManagers [i]->set_int (trans->xsetting_name, g_variant_get_boolean (value)); } } static void translate_int_int (ukuiXSettingsManager *manager, TranslationEntry *trans, GVariant *value) { int i; for (i = 0; manager-> pManagers [i]; i++) { manager-> pManagers [i]->set_int (trans->xsetting_name, g_variant_get_int32 (value)); } } static void translate_string_string (ukuiXSettingsManager *manager, TranslationEntry *trans, GVariant *value) { int i; for (i = 0; manager-> pManagers [i]; i++) { manager-> pManagers [i]->set_string (trans->xsetting_name, g_variant_get_string (value, NULL)); } } static void translate_string_string_toolbar (ukuiXSettingsManager *manager, TranslationEntry *trans, GVariant *value) { int i; const char *tmp; /* This is kind of a workaround since GNOME expects the key value to be * "both_horiz" and gtk+ wants the XSetting to be "both-horiz". */ tmp = g_variant_get_string (value, NULL); if (tmp && strcmp (tmp, "both_horiz") == 0) { tmp = "both-horiz"; } for (i = 0; manager-> pManagers [i]; i++) { manager-> pManagers [i]->set_string (trans->xsetting_name, tmp); } } static TranslationEntry translations [] = { { MOUSE_SCHEMA, "double-click", "Net/DoubleClickTime", translate_int_int }, { MOUSE_SCHEMA, "drag-threshold", "Net/DndDragThreshold", translate_int_int }, { MOUSE_SCHEMA, "cursor-theme", "Gtk/CursorThemeName", translate_string_string }, { MOUSE_SCHEMA, "cursor-size", "Gtk/CursorThemeSize", translate_int_int }, { INTERFACE_SCHEMA, "font-name", "Gtk/FontName", translate_string_string }, { INTERFACE_SCHEMA, "gtk-key-theme", "Gtk/KeyThemeName", translate_string_string }, { INTERFACE_SCHEMA, "toolbar-style", "Gtk/ToolbarStyle", translate_string_string_toolbar }, { INTERFACE_SCHEMA, "toolbar-icons-size", "Gtk/ToolbarIconSize", translate_string_string }, { INTERFACE_SCHEMA, "cursor-blink", "Net/CursorBlink", translate_bool_int }, { INTERFACE_SCHEMA, "cursor-blink-time", "Net/CursorBlinkTime", translate_int_int }, { INTERFACE_SCHEMA, "gtk-theme", "Net/ThemeName", translate_string_string }, { INTERFACE_SCHEMA, "gtk-color-scheme", "Gtk/ColorScheme", translate_string_string }, { INTERFACE_SCHEMA, "gtk-im-preedit-style", "Gtk/IMPreeditStyle", translate_string_string }, { INTERFACE_SCHEMA, "gtk-im-status-style", "Gtk/IMStatusStyle", translate_string_string }, { INTERFACE_SCHEMA, "gtk-im-module", "Gtk/IMModule", translate_string_string }, { INTERFACE_SCHEMA, "icon-theme", "Net/IconThemeName", translate_string_string }, { INTERFACE_SCHEMA, "file-chooser-backend", "Gtk/FileChooserBackend", translate_string_string }, { INTERFACE_SCHEMA, "gtk-decoration-layout", "Gtk/DecorationLayout", translate_string_string }, { INTERFACE_SCHEMA, "gtk-shell-shows-app-menu","Gtk/ShellShowsAppMenu", translate_bool_int }, { INTERFACE_SCHEMA, "gtk-shell-shows-menubar","Gtk/ShellShowsMenubar", translate_bool_int }, { INTERFACE_SCHEMA, "menus-have-icons", "Gtk/MenuImages", translate_bool_int }, { INTERFACE_SCHEMA, "buttons-have-icons", "Gtk/ButtonImages", translate_bool_int }, { INTERFACE_SCHEMA, "menubar-accel", "Gtk/MenuBarAccel", translate_string_string }, { INTERFACE_SCHEMA, "show-input-method-menu", "Gtk/ShowInputMethodMenu", translate_bool_int }, { INTERFACE_SCHEMA, "show-unicode-menu", "Gtk/ShowUnicodeMenu", translate_bool_int }, { INTERFACE_SCHEMA, "automatic-mnemonics", "Gtk/AutoMnemonics", translate_bool_int }, { INTERFACE_SCHEMA, "gtk-enable-animations", "Gtk/EnableAnimations", translate_bool_int }, { INTERFACE_SCHEMA, "gtk-dialogs-use-header", "Gtk/DialogsUseHeader", translate_bool_int }, { SOUND_SCHEMA, "theme-name", "Net/SoundThemeName", translate_string_string }, { SOUND_SCHEMA, "event-sounds", "Net/EnableEventSounds" , translate_bool_int }, { SOUND_SCHEMA, "input-feedback-sounds", "Net/EnableInputFeedbackSounds", translate_bool_int } }; static gboolean start_fontconfig_monitor_idle_cb (ukuiXSettingsManager *manager) { manager-> fontconfig_handle = fontconfig_monitor_start ((GFunc) fontconfig_callback, manager); return FALSE; } static void start_fontconfig_monitor (ukuiXSettingsManager *manager) { fontconfig_cache_init (); g_idle_add ((GSourceFunc) start_fontconfig_monitor_idle_cb, manager); } static void stop_fontconfig_monitor (ukuiXSettingsManager *manager) { if (manager->fontconfig_handle) { fontconfig_monitor_stop (manager->fontconfig_handle); manager->fontconfig_handle = NULL; } } static void process_value (ukuiXSettingsManager *manager, TranslationEntry *trans, GVariant *value) { (* trans->translate) (manager, trans, value); } static void terminate_cb (void *data) { gboolean *terminated = reinterpret_cast(data); if (*terminated) { return; } *terminated = TRUE; USD_LOG(LOG_DEBUG,"terminate self....."); exit(15);//gtk_main_quit (); } void setScreenScale() { GSettings *gsettings; double scale; gsettings =g_settings_new(XSETTINGS_PLUGIN_SCHEMA); scale = g_settings_get_double (gsettings, SCALING_FACTOR_KEY); if(scale > 1.25) { bool state = false; for(QScreen *screen : QGuiApplication::screens()) { if (screen->geometry().width() < 1920 && screen->geometry().height() < 1080){ state = true; } else if ((screen->geometry().width() == 1920) && (screen->geometry().height() == 1080) && (scale > 1.5)) { state = true; } else state = false; } if (state){ GSettings *mGsettings; mGsettings = g_settings_new(MOUSE_SCHEMA); g_settings_set_int (mGsettings, CURSOR_SIZE_KEY, 24); g_settings_set_double (gsettings, SCALING_FACTOR_KEY, 1.0); g_object_unref(mGsettings); } } g_object_unref(gsettings); } ukuiXSettingsManager::ukuiXSettingsManager() { gdk_init(NULL,NULL); pManagers=nullptr; gsettings=nullptr; gsettings_font=nullptr; fontconfig_handle=nullptr; } ukuiXSettingsManager::~ukuiXSettingsManager() { } static TranslationEntry * find_translation_entry (GSettings *gsettings, const char *key) { guint i; char *schema; g_object_get (gsettings, "schema", &schema, NULL); for (i = 0; i < G_N_ELEMENTS (translations); i++) { if (g_str_equal (schema, translations[i].gsettings_schema) && g_str_equal (key, translations[i].gsettings_key)) { g_free (schema); return &translations[i]; } } g_free (schema); return NULL; } static void setKwinMouseSize(int size) { QString filename = QDir::homePath() + "/.config/kcminputrc"; QSettings *mouseSettings = new QSettings(filename, QSettings::IniFormat); mouseSettings->beginGroup("Mouse"); mouseSettings->setValue("cursorSize", size); mouseSettings->endGroup(); mouseSettings->sync(); mouseSettings->deleteLater(); QDBusMessage message = QDBusMessage::createSignal("/KGlobalSettings", "org.kde.KGlobalSettings", "notifyChange"); QList args; args.append(5);//cursor size change signal args.append(0);//The sceond param unuse.. message.setArguments(args); QDBusConnection::sessionBus().send(message); } static void xsettings_callback (GSettings *gsettings, const char *key, ukuiXSettingsManager *manager) { TranslationEntry *trans; int i; GVariant *value; // USD_LOG(LOG_DEBUG,"key:%s",key); if (g_str_equal (key, CURSOR_THEME_KEY)|| g_str_equal (key, CURSOR_SIZE_KEY )) { xft_callback (NULL, key, manager); USD_LOG(LOG_ERR," key=%s",key); if (g_str_equal (key, CURSOR_SIZE_KEY)) { setKwinMouseSize(g_settings_get_int (gsettings, key)); USD_LOG_SHOW_PARAM1(g_settings_get_int (gsettings, key)); } return; } trans = find_translation_entry (gsettings, key); if (trans == NULL) { USD_LOG(LOG_ERR,"can't find key:%s",key); return; } value = g_settings_get_value (gsettings, key); process_value (manager, trans, value); g_variant_unref (value); for (i = 0; manager->pManagers [i]; i++) { manager->pManagers [i]->set_string ("Net/FallbackIconTheme", "ukui"); } for (i = 0; manager->pManagers [i]; i++) { manager->pManagers [i]->notify (); } } static gboolean setup_xsettings_managers (ukuiXSettingsManager *manager) { GdkDisplay *display; gboolean res; gboolean terminated; display = gdk_display_get_default (); res = xsettings_manager_check_running (gdk_x11_display_get_xdisplay (display),0); if (res) { g_warning ("You can only run one xsettings manager at a time; exiting"); return FALSE; } if(!manager->pManagers) manager->pManagers = new XsettingsManager*[2]; for(int i=0;manager->pManagers[i];i++) manager->pManagers [i] = nullptr; terminated = FALSE; if(!manager->pManagers [0]) manager->pManagers [0] = new XsettingsManager (gdk_x11_display_get_xdisplay (display), 0, (XSettingsTerminateFunc)terminate_cb, &terminated); if (! manager->pManagers [0]) { g_warning ("Could not create xsettings manager for screen!"); return FALSE; } return TRUE; } void update_xft_settings (ukuiXSettingsManager *manager) { UkuiXftSettings settings; settings.xft_settings_get (manager); settings.xft_settings_set_xsettings (manager); settings.xft_settings_set_xresources (); } static void xft_callback (GSettings *gsettings, const gchar *key, ukuiXSettingsManager *manager) { int i; update_xft_settings (manager); for (i = 0; manager->pManagers [i]; i++) { manager->pManagers [i]->notify (); } } static void fontconfig_callback (fontconfig_monitor_handle_t *handle, ukuiXSettingsManager *manager) { int i; int timestamp = time (NULL); for (i = 0; manager-> pManagers [i]; i++) { manager-> pManagers [i]->set_int ("Fontconfig/Timestamp", timestamp); manager-> pManagers [i]->notify (); } } void ukuiXSettingsManager::sendSessionDbus() { QDBusMessage message = QDBusMessage::createMethodCall("org.gnome.SessionManager", "/org/gnome/SessionManager", "org.gnome.SessionManager", "startupfinished"); QList args; args.append("ukui-settings-daemon"); args.append("startupfinished"); message.setArguments(args); QDBusConnection::sessionBus().send(message); } bool ukuiXSettingsManager::start() { guint i; GList *list, *l; if (!setup_xsettings_managers (this)) { USD_XSETTINGS_ERROR; return false; } gsettings = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) g_object_unref); g_hash_table_insert ( gsettings,(void*)MOUSE_SCHEMA, g_settings_new (MOUSE_SCHEMA)); g_hash_table_insert ( gsettings,(void*)INTERFACE_SCHEMA, g_settings_new (INTERFACE_SCHEMA)); g_hash_table_insert ( gsettings,(void*)SOUND_SCHEMA, g_settings_new (SOUND_SCHEMA)); g_hash_table_insert (gsettings,(void*)XSETTINGS_PLUGIN_SCHEMA, g_settings_new (XSETTINGS_PLUGIN_SCHEMA)); list = g_hash_table_get_values ( gsettings); for (l = list; l != NULL; l = l->next) { g_signal_connect (G_OBJECT (l->data), "changed", G_CALLBACK (xsettings_callback), this); } g_list_free (list); for (i = 0; i < G_N_ELEMENTS (translations); i++) { GVariant *val; GSettings *gsettings; gsettings = (GSettings *)g_hash_table_lookup ( this->gsettings, translations[i].gsettings_schema); if (gsettings == NULL) { USD_LOG(LOG_DEBUG,"Schemas '%s' has not been setup", translations[i].gsettings_schema); continue; } val = g_settings_get_value (gsettings, translations[i].gsettings_key); process_value (this, &translations[i], val); g_variant_unref (val); } this->gsettings_font = g_settings_new (FONT_RENDER_SCHEMA); g_signal_connect (this->gsettings_font, "changed", G_CALLBACK (xft_callback), this); update_xft_settings (this); start_fontconfig_monitor (this); sendSessionDbus(); for (i = 0; pManagers [i]; i++){ pManagers [i]->set_string ( "Net/FallbackIconTheme", "ukui"); } for (i = 0; pManagers [i]; i++) { pManagers [i]->notify ( ); } return true; } int ukuiXSettingsManager::stop() { int i; if (pManagers != NULL) { for (i = 0; pManagers [i]; ++i) { delete (pManagers[i]); pManagers[i] = NULL; } } if (gsettings != NULL) { g_hash_table_destroy (gsettings); gsettings = NULL; } if (gsettings_font != NULL) { g_object_unref (gsettings_font); gsettings_font = NULL; } stop_fontconfig_monitor (this); return 1; } ukui-settings-daemon/plugins/xsettings/ukui-xsettings-plugin.h0000644000175000017500000000253014205117202023725 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XSETTINGS_H #define XSETTINGS_H #include "plugin-interface.h" #include "ukui-xsettings-manager.h" #include class XSettingsPlugin: public PluginInterface { private: XSettingsPlugin(); XSettingsPlugin(XSettingsPlugin&) = delete; public: ~XSettingsPlugin(); static PluginInterface *getInstance(); virtual void activate(); virtual void deactivate(); private: static ukuiXSettingsManager *m_pukuiXsettingManager; static PluginInterface *mInstance; }; extern "C" Q_DECL_EXPORT PluginInterface* createSettingsPlugin(); #endif // XSETTINGS_H ukui-settings-daemon/plugins/xsettings/ukui-xft-settings.h0000644000175000017500000000256114205117202023044 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UKUIXFTSETTINGS_H #define UKUIXFTSETTINGS_H #include class ukuiXSettingsManager; class UkuiXftSettings { private: gboolean antialias; gboolean hinting; int dpi; int scaled_dpi; double window_scale; char *cursor_theme; int cursor_size; const char *rgba; const char *hintstyle; public: void xft_settings_get (ukuiXSettingsManager *manager); void xft_settings_set_xsettings (ukuiXSettingsManager *manager); void xft_settings_set_xresources (); }; #endif // UKUIXFTSETTINGS_H ukui-settings-daemon/plugins/xsettings/fontconfig-monitor.h0000644000175000017500000000261214205117202023250 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. * * Author: Behdad Esfahbod, Red Hat, Inc. */ #ifndef __FONTCONFIG_MONITOR_H #define __FONTCONFIG_MONITOR_H #include #ifdef __cplusplus extern "C" { #endif void fontconfig_cache_init (void); gboolean fontconfig_cache_update (void); typedef struct _fontconfig_monitor_handle fontconfig_monitor_handle_t; fontconfig_monitor_handle_t * fontconfig_monitor_start (GFunc notify_callback, gpointer notify_data); void fontconfig_monitor_stop (fontconfig_monitor_handle_t *handle); #ifdef __cplusplus } #endif #endif /* __FONTCONFIG_MONITOR_H */ ukui-settings-daemon/plugins/xsettings/xsettings-common.h0000644000175000017500000000661114205117202022750 0ustar fengfeng/* * Copyright © 2001 Red Hat, Inc. * * 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, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Owen Taylor, Red Hat, Inc. */ #ifndef XSETTINGS_COMMON_H #define XSETTINGS_COMMON_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ typedef struct _XSettingsBuffer XSettingsBuffer; typedef struct _XSettingsColor XSettingsColor; typedef struct _XSettingsList XSettingsList; typedef struct _XSettingsSetting XSettingsSetting; /* Types of settings possible. Enum values correspond to * protocol values. */ typedef enum { XSETTINGS_TYPE_INT = 0, XSETTINGS_TYPE_STRING = 1, XSETTINGS_TYPE_COLOR = 2 } XSettingsType; typedef enum { XSETTINGS_SUCCESS, XSETTINGS_NO_MEM, XSETTINGS_ACCESS, XSETTINGS_FAILED, XSETTINGS_NO_ENTRY, XSETTINGS_DUPLICATE_ENTRY } XSettingsResult; struct _XSettingsBuffer { char byte_order; size_t len; unsigned char *data; unsigned char *pos; }; struct _XSettingsColor { unsigned short red, green, blue, alpha; }; struct _XSettingsList { XSettingsSetting *setting; XSettingsList *next; }; struct _XSettingsSetting { char *name; XSettingsType type; union { int v_int; char *v_string; XSettingsColor v_color; } data; unsigned long last_change_serial; }; XSettingsSetting *xsettings_setting_copy (XSettingsSetting *setting); void xsettings_setting_free (XSettingsSetting *setting); int xsettings_setting_equal (XSettingsSetting *setting_a, XSettingsSetting *setting_b); void xsettings_list_free (XSettingsList *list); XSettingsList *xsettings_list_copy (XSettingsList *list); XSettingsResult xsettings_list_insert (XSettingsList **list, XSettingsSetting *setting); XSettingsSetting *xsettings_list_lookup (XSettingsList *list, const char *name); XSettingsResult xsettings_list_delete (XSettingsList **list, const char *name); char xsettings_byte_order (void); #define XSETTINGS_PAD(n,m) ((n + m - 1) & (~(m-1))) #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* XSETTINGS_COMMON_H */ ukui-settings-daemon/plugins/xsettings/xsettings-manager.h0000644000175000017500000000444614205117202023076 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XSETTINGSMANAGER_H #define XSETTINGSMANAGER_H #include #include "xsettings-common.h" typedef void (*XSettingsTerminateFunc) (int *cb_data); #if defined __cplusplus class XsettingsManager { public: XsettingsManager(Display *display, int screen, XSettingsTerminateFunc terminate, int *cb_data); ~XsettingsManager(); Window get_window (); Bool process_event (XEvent *xev); XSettingsResult delete_setting (const char *name); XSettingsResult set_setting (XSettingsSetting *setting); XSettingsResult set_int (const char *name, int value); XSettingsResult set_string (const char *name, const char *value); XSettingsResult set_color (const char *name, XSettingsColor *value); void setting_store (XSettingsSetting *setting, XSettingsBuffer *buffer); XSettingsResult notify (); private: Display *display; int screen; Window window; Atom manager_atom; Atom selection_atom; Atom xsettings_atom; XSettingsTerminateFunc terminate; void *cb_data; XSettingsList *settings; unsigned long serial; }; #endif Bool xsettings_manager_check_running (Display *display, int screen); #endif // XSETTINGSMANAGER_H ukui-settings-daemon/plugins/keybindings/0000755000175000017500000000000014205117202017533 5ustar fengfengukui-settings-daemon/plugins/keybindings/keybindings.pro0000644000175000017500000000157214205117202022570 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-05-24T09:30:00 # #------------------------------------------------- QT -= gui QT += core widgets x11extras TARGET = keybindings TEMPLATE = lib DEFINES += KEYBINDINGS_LIBRARY CONFIG += c++11 no_keywords link_pkgconfig plugin DEFINES += QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"keybindings\\\" include($$PWD/../../common/common.pri) PKGCONFIG += \ gtk+-3.0 \ glib-2.0 \ gobject-2.0 \ gio-2.0 \ cairo \ gsettings-qt\ dconf SOURCES += \ dconf-util.c \ keybindings-manager.cpp \ keybindings-plugin.cpp HEADERS += \ dconf-util.h \ keybindings-manager.h \ keybindings-plugin.h keybindings_lib.path = $${PLUGIN_INSTALL_DIRS} keybindings_lib.files = $$OUT_PWD/libkeybindings.so INSTALLS += keybindings_lib ukui-settings-daemon/plugins/keybindings/keybindings-plugin.cpp0000644000175000017500000000370614205117202024047 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "keybindings-plugin.h" #include "clib-syslog.h" PluginInterface *KeybindingsPlugin::mInstance=nullptr; KeybindingsManager *KeybindingsPlugin::mKeyManager=nullptr; KeybindingsPlugin::KeybindingsPlugin() { USD_LOG(LOG_DEBUG,"KeybindingsPlugin initializing"); if(nullptr == mKeyManager) mKeyManager = KeybindingsManager::KeybindingsManagerNew(); } KeybindingsPlugin::~KeybindingsPlugin() { USD_LOG(LOG_DEBUG,"KeybindingsPlugin free"); if(mKeyManager){ delete mKeyManager; mKeyManager = nullptr; } } void KeybindingsPlugin::activate() { bool res; USD_LOG (LOG_DEBUG, "Activating %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); res = mKeyManager->KeybindingsManagerStart(); if(!res) USD_LOG(LOG_ERR,"Unable to start Keybindings manager"); } PluginInterface *KeybindingsPlugin::getInstance() { if(nullptr == mInstance) mInstance = new KeybindingsPlugin(); return mInstance; } void KeybindingsPlugin::deactivate() { USD_LOG(LOG_DEBUG,"Dectivating Keybindings Plugin"); mKeyManager->KeybindingsManagerStop(); } PluginInterface *createSettingsPlugin() { return KeybindingsPlugin::getInstance(); } ukui-settings-daemon/plugins/keybindings/dconf-util.h0000755000175000017500000000264014205117202021755 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., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, 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-settings-daemon/plugins/keybindings/keybindings-manager.h0000644000175000017500000000600714205117202023625 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef KEYBINDINGSMANAGER_H #define KEYBINDINGSMANAGER_H #include #include #include #include #include #include #include #include #include #include #include #include #include extern "C"{ #include "ukui-keygrab.h" #include "eggaccelerators.h" #include "dconf-util.h" #include #include #include #include #include #include #include #include #include } typedef struct { char *binding_str; char *action; char *settings_path; Key key; Key previous_key; } Binding; class KeybindingsManager : public QObject { Q_OBJECT private: KeybindingsManager(); KeybindingsManager(KeybindingsManager&)=delete; public: ~KeybindingsManager(); static KeybindingsManager *KeybindingsManagerNew(); bool KeybindingsManagerStart(); void KeybindingsManagerStop(); void get_screens_list(); public: static void bindings_callback (DConfClient *client, gchar *prefix, const gchar **changes, gchar *tag, KeybindingsManager *manager); static bool key_already_used (KeybindingsManager *manager,Binding *binding); static void binding_register_keys (KeybindingsManager *manager); static void binding_unregister_keys (KeybindingsManager *manager); static void bindings_clear(KeybindingsManager *manager); static void bindings_get_entries(KeybindingsManager *manager); static bool bindings_get_entry (KeybindingsManager *manager,const char *settings_path); friend GdkFilterReturn keybindings_filter (GdkXEvent *gdk_xevent, GdkEvent *event, KeybindingsManager *manager); private: static KeybindingsManager *mKeybinding; DConfClient *client; GSList *binding_list; QList *screens; QGSettings *dconfSet; GMainLoop *loop; }; #endif // KEYBINDINGSMANAGER_H ukui-settings-daemon/plugins/keybindings/keybindings-plugin.h0000644000175000017500000000251514205117202023511 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef KEYBINDINGSPLUGIN_H #define KEYBINDINGSPLUGIN_H #include "keybindings-manager.h" #include "plugin-interface.h" class KeybindingsPlugin : public PluginInterface { public: ~KeybindingsPlugin(); static PluginInterface *getInstance(); virtual void activate(); virtual void deactivate(); private: KeybindingsPlugin(); KeybindingsPlugin(KeybindingsPlugin&)=delete; private: static KeybindingsManager *mKeyManager; static PluginInterface *mInstance; }; extern "C" Q_DECL_EXPORT PluginInterface * createSettingsPlugin(); #endif // KEYBINDINGSPLUGIN_H ukui-settings-daemon/plugins/keybindings/dconf-util.c0000755000175000017500000000475714205117202021763 0ustar fengfeng/* * dconf-util.c: 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., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * Authors: * Stefano Karapetsas * Vincent Untz */ #ifdef HAVE_CONFIG_H #include #endif #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-settings-daemon/plugins/keybindings/keybindings-manager.cpp0000644000175000017500000004411714205117202024164 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "keybindings-manager.h" #include "config.h" #include "clib-syslog.h" #include #include #include #define DESKTOP_APP_DIR "/usr/share/applications/" //#define GSETTINGS_KEYBINDINGS_DIR "/org/ukui/desktop/session/" #define GSETTINGS_KEYBINDINGS_DIR "/org/ukui/desktop/keybindings/" #define CUSTOM_KEYBINDING_SCHEMA "org.ukui.control-center.keybinding" KeybindingsManager *KeybindingsManager::mKeybinding = nullptr; KeybindingsManager::KeybindingsManager() { } KeybindingsManager::~KeybindingsManager() { } KeybindingsManager *KeybindingsManager::KeybindingsManagerNew() { if(nullptr == mKeybinding) mKeybinding = new KeybindingsManager(); return mKeybinding; } /** * @brief parse_binding * Whether the binding exists * 获取此绑定的条目 * @return */ static bool parse_binding (Binding *binding) { gboolean success; if(!binding) return false; binding->key.keysym = 0; binding->key.state = 0; g_free (binding->key.keycodes); binding->key.keycodes = NULL; if (binding->binding_str == NULL || binding->binding_str[0] == '\0' || g_strcmp0 (binding->binding_str, "Disabled") == 0 || g_strcmp0 (binding->binding_str, "disabled") == 0 ) { return false; } success = egg_accelerator_parse_virtual (binding->binding_str, &binding->key.keysym, &binding->key.keycodes, (EggVirtualModifierType *)&binding->key.state); if (!success) USD_LOG(LOG_DEBUG,"Key binding (%s) is invalid", binding->settings_path); return success; } static gint compare_bindings (gconstpointer a, gconstpointer b) { Binding *key_a = (Binding *) a; char *key_b = (char *) b; return g_strcmp0 (key_b, key_a->settings_path); } /** * @brief KeybindingsManager::bindings_get_entry * Gets binding shortcut data * 获取绑定快捷键数据 * @return */ bool KeybindingsManager::bindings_get_entry (KeybindingsManager *manager,const char *settings_path) { GSettings *settings; Binding *new_binding; GSList *tmp_elem; char *action = nullptr; char *key = nullptr; if (!settings_path) { return false; } /* Get entries for this binding * 获取此绑定的条目 */ settings = g_settings_new_with_path (CUSTOM_KEYBINDING_SCHEMA, settings_path); action = g_settings_get_string (settings, "action"); key = g_settings_get_string (settings, "binding"); g_object_unref (settings); if (action==nullptr || key==nullptr) { USD_LOG(LOG_DEBUG,"Key binding (%s) is incomplete", settings_path); return false; } tmp_elem = g_slist_find_custom (manager->binding_list, settings_path, compare_bindings); if (!tmp_elem) { new_binding = g_new0 (Binding, 1); } else { new_binding = (Binding *) tmp_elem->data; g_free (new_binding->binding_str); g_free (new_binding->action); g_free (new_binding->settings_path); new_binding->previous_key.keysym = new_binding->key.keysym; new_binding->previous_key.state = new_binding->key.state; new_binding->previous_key.keycodes = new_binding->key.keycodes; new_binding->key.keycodes = NULL; } new_binding->binding_str = key; new_binding->action = action; new_binding->settings_path = g_strdup (settings_path); if (parse_binding (new_binding)) { if (!tmp_elem) manager->binding_list = g_slist_prepend (manager->binding_list, new_binding); } else { g_free (new_binding->binding_str); g_free (new_binding->action); g_free (new_binding->settings_path); g_free (new_binding->previous_key.keycodes); g_free (new_binding); if (tmp_elem) manager->binding_list = g_slist_delete_link (manager->binding_list, tmp_elem); return false; } return true; } /** * @brief KeybindingsManager::bindings_clear * Clear binding cache * 清除绑定缓存 */ void KeybindingsManager::bindings_clear (KeybindingsManager *manager) { GSList *l; if (manager->binding_list != NULL) { for (l = manager->binding_list; l; l = l->next) { Binding *b = (Binding *)l->data; g_free (b->binding_str); g_free (b->action); g_free (b->settings_path); g_free (b->previous_key.keycodes); g_free (b->key.keycodes); g_free (b); } g_slist_free (manager->binding_list); manager->binding_list = NULL; } } void KeybindingsManager::bindings_get_entries (KeybindingsManager *manager) { gchar **custom_list = NULL; gint i; bindings_clear(manager); custom_list = dconf_util_list_subdirs (GSETTINGS_KEYBINDINGS_DIR, FALSE); if (custom_list != NULL) { for (i = 0; custom_list[i] != NULL; i++) { gchar *settings_path; settings_path = g_strdup_printf("%s%s", GSETTINGS_KEYBINDINGS_DIR, custom_list[i]); bindings_get_entry (manager,settings_path); g_free (settings_path); } g_strfreev (custom_list); } } /** * @brief same_keycode * Is it the same key code * 是否为相同的键码 * @return */ static bool same_keycode (const Key *key, const Key *other) { if (key->keycodes != NULL && other->keycodes != NULL) { unsigned int *c; for (c = key->keycodes; *c; ++c) { if (key_uses_keycode (other, *c)) return true; } } return false; } /** * @brief same_key * Compare whether the keys are shortcuts * 对比按键是否为快捷键 * @return */ static bool same_key (const Key *key, const Key *other) { if (key->state == other->state) { if (key->keycodes != NULL && other->keycodes != NULL) { unsigned int *c1, *c2; for (c1 = key->keycodes, c2 = other->keycodes; *c1 || *c2; ++c1, ++c2) { if (*c1 != *c2) return false; } } else if (key->keycodes != NULL || other->keycodes != NULL) return false; return true; } return false; } /** * @brief KeybindingsManager::key_already_used * @English Compare the shortcuts already used * @简体 已经使用的快捷键 进行比对 * @return */ bool KeybindingsManager::key_already_used (KeybindingsManager*manager,Binding *binding) { GSList *li; for (li = manager->binding_list; li != NULL; li = li->next) { Binding *tmp_binding = (Binding*) li->data; if (tmp_binding != binding && same_keycode (&tmp_binding->key, &binding->key) && tmp_binding->key.state == binding->key.state) { return true; } } return false; } /** * @brief KeybindingsManager::binding_unregister_keys * Unbind key * 注销绑定按键 */ void KeybindingsManager::binding_unregister_keys (KeybindingsManager *manager) { GSList *li; bool need_flush = FALSE; USD_LOG(LOG_DEBUG,"run here..."); gdk_x11_display_error_trap_push (gdk_display_get_default()); try { for (li = manager->binding_list; li != NULL; li = li->next) { Binding *binding = (Binding *) li->data; USD_LOG(LOG_DEBUG,"run here..."); if (binding->key.keycodes) { need_flush = TRUE; grab_key_unsafe (&binding->key, FALSE, manager->screens); } } if (need_flush) gdk_display_flush(gdk_display_get_default()); } catch (...) { } gdk_x11_display_error_trap_pop_ignored(gdk_display_get_default()); } /** * @brief KeybindingsManager::binding_register_keys * Bind register key * 绑定寄存器按键 */ void KeybindingsManager::binding_register_keys (KeybindingsManager *manager) { GSList *li; bool need_flush = false; gdk_x11_display_error_trap_push (gdk_display_get_default()); /* Now check for changes and grab new key if not already used * 现在检查更改并获取新密钥(如果尚未使用) */ for (li = manager->binding_list; li != NULL; li = li->next) { Binding *binding = (Binding *) li->data; if (!same_key (&binding->previous_key, &binding->key)) { /* Ungrab key if it changed and not clashing with previously set binding */ if (!key_already_used (manager,binding)) { gint i; need_flush = true; if (binding->previous_key.keycodes) { grab_key_unsafe (&binding->previous_key, FALSE, manager->screens); } grab_key_unsafe (&binding->key, TRUE, manager->screens); binding->previous_key.keysym = binding->key.keysym; binding->previous_key.state = binding->key.state; g_free (binding->previous_key.keycodes); for (i = 0; binding->key.keycodes&&binding->key.keycodes[i]; ++i); binding->previous_key.keycodes = g_new0 (guint, i); for (i = 0; binding->key.keycodes&&binding->key.keycodes[i]; ++i) binding->previous_key.keycodes[i] = binding->key.keycodes[i]; } else USD_LOG(LOG_DEBUG,"Key binding (%s) is already in use", binding->binding_str); } } if (need_flush) gdk_display_flush (gdk_display_get_default()); if(gdk_x11_display_error_trap_pop (gdk_display_get_default())) USD_LOG(LOG_DEBUG,"Grab failed for some keys, another application may already have access the them."); } /** * @brief keybindings_filter 键盘事件回调函数 * @param gdk_xevent GDK XEvent事件 * @param event GDK Event事件 * @param manager 类 * @return 未处理事件,请继续处理 */ GdkFilterReturn keybindings_filter (GdkXEvent *gdk_xevent, GdkEvent *event, KeybindingsManager *manager) { XEvent *xevent = (XEvent *) gdk_xevent; GSList *li; // USD_LOG(LOG_DEBUG,"had event :%d",xevent->type); if (xevent->type != KeyPress) { return GDK_FILTER_CONTINUE; } for (li = manager->binding_list; li != NULL; li = li->next) { Binding *binding = (Binding *) li->data; if (match_key (&binding->key, xevent)) { GError *error = NULL; gboolean retval; gchar **argv = NULL; if (binding->action == NULL) return GDK_FILTER_CONTINUE; if (!g_shell_parse_argv (binding->action, NULL, &argv, &error)) { return GDK_FILTER_CONTINUE; } GDesktopAppInfo *info = g_desktop_app_info_new_from_filename(binding->action); retval = g_app_info_launch_uris((GAppInfo *)info, NULL, NULL, NULL); g_strfreev (argv); /* Run failed popup * 运行失败弹窗 */ if (!retval) { QString strs = QObject::tr("Error while trying to run \"%1\";\n which is linked to the key \"%2\""). arg(binding->action).arg(binding->binding_str); QMessageBox *msgbox = new QMessageBox(); msgbox->setWindowTitle(QObject::tr("Shortcut message box")); msgbox->setText(strs); msgbox->setStandardButtons(QMessageBox::Yes); msgbox->setButtonText(QMessageBox::Yes,QObject::tr("Yes")); msgbox->exec(); delete msgbox; } return GDK_FILTER_REMOVE; } } return GDK_FILTER_CONTINUE; } static void show_path (DConfClient *client, const gchar *path) { if (dconf_is_key (path, NULL)) { g_autoptr(GVariant) value = NULL; g_autofree gchar *value_str = NULL; value = dconf_client_read (client, path); if (value != NULL) value_str = g_variant_print (value, TRUE); USD_LOG(LOG_DEBUG," %s\n", value_str != NULL ? value_str : "unset"); } } /** * @brief KeybindingsManager::bindings_callback dconf监听快捷键改变回调函数 * @param client * @param prefix * @param changes * @param tag * @param manager 类 */ void KeybindingsManager::bindings_callback (DConfClient *client, gchar *prefix, const gchar **changes, gchar *tag, KeybindingsManager *manager) { Q_UNUSED(client); Q_UNUSED(changes); if (strncmp(GSETTINGS_KEYBINDINGS_DIR,prefix,strlen(GSETTINGS_KEYBINDINGS_DIR))) { return; } USD_LOG(LOG_DEBUG,"keybindings: received 'changed' signal from dconf. gchar:%s changes:%s tag:%s ",prefix, changes[0], tag); for (const gchar **item = changes; *changes; ++changes) { g_autofree gchar *full = NULL; full = g_strconcat (prefix, *item, NULL); USD_LOG (LOG_DEBUG,"prefix%s full%s\n", prefix, full); show_path (client, full); } binding_unregister_keys (manager); bindings_get_entries (manager); binding_register_keys (manager); } /** * @brief get_screens_list 获取gdkscreen屏幕并存放链表 * @return 返回列表 */ void KeybindingsManager::get_screens_list (void) { GdkScreen *screen = gdk_screen_get_default (); screens->append(screen); } bool KeybindingsManager::KeybindingsManagerStart() { USD_LOG(LOG_DEBUG,"-- Keybindings Manager Start --"); QList::iterator l, begin, end; GdkDisplay *dpy; GdkScreen *screen; GdkWindow *window; Display *xdpy; Window xwindow; XWindowAttributes atts; gdk_init(NULL,NULL); dpy = gdk_display_get_default (); // xdpy = GDK_DISPLAY_XDISPLAY (dpy); xdpy = QX11Info::display(); screen = gdk_display_get_default_screen(dpy); window = gdk_screen_get_root_window (screen); xwindow = GDK_WINDOW_XID (window); /* Monitor keyboard events * 监听键盘事件 */ gdk_window_add_filter (window, (GdkFilterFunc) keybindings_filter, this); try { /* Add KeyPressMask to the currently reportable event masks * 将KeyPressMask添加到当前可报告的事件掩码 */ gdk_x11_display_error_trap_push (gdk_display_get_default()); XGetWindowAttributes (xdpy, xwindow, &atts); XSelectInput (xdpy, xwindow, atts.your_event_mask | KeyPressMask); gdk_x11_display_error_trap_pop_ignored(gdk_display_get_default()); } catch (int) { USD_LOG(LOG_DEBUG,"had a error in here..."); } screens = new QList(); get_screens_list (); binding_list = NULL; bindings_get_entries (this); binding_register_keys(this); /* Link to dconf, receive a shortcut key change signal from dconf * 链接dconf, 从dconf收到更改快捷键信号 */ { char ** childs; int len; QList vals; client = dconf_client_new (); dconf_client_watch_fast (client, GSETTINGS_KEYBINDINGS_DIR); dconf_client_watch_sync (client, GSETTINGS_KEYBINDINGS_DIR); g_signal_connect (client, "changed", G_CALLBACK (bindings_callback), this); #if 0 //无效,无法使用gsetings的方法监控dconf childs = dconf_client_list (client, GSETTINGS_KEYBINDINGS_DIR, &len); for (int i = 0; childs[i] != NULL; i++){ USD_LOG(LOG_DEBUG,"val:%s",childs[i]); if (dconf_is_rel_dir (childs[i], NULL)) { USD_LOG(LOG_DEBUG,"val:"); char * val = g_strdup (childs[i]); vals.append(val); USD_LOG(LOG_DEBUG,"val:%s",val); } } USD_LOG(LOG_DEBUG,"len:%d",len); for (char * path : vals){ USD_LOG(LOG_DEBUG,"val:%s",path); char tempbuf[128]=""; memcpy(tempbuf, GSETTINGS_KEYBINDINGS_DIR, strlen(GSETTINGS_KEYBINDINGS_DIR)); strcat(tempbuf, path); USD_LOG(LOG_DEBUG,"path:%s, tempbuf%s",path, tempbuf); const QByteArray ba(GSETTINGS_KEYBINDINGS_DIR,strlen(GSETTINGS_KEYBINDINGS_DIR)); const QByteArray bba(tempbuf,strlen(tempbuf)); USD_LOG(LOG_DEBUG,"ba[%s] bba[%s]",ba.data(),bba.data()); QGSettings * settings = new QGSettings(ba, bba); connect(settings, &QGSettings::changed, this, [=] (const QString &key){ USD_LOG(LOG_DEBUG,"key=%s",key.toLatin1().data()); }); } #endif } return true; } void KeybindingsManager::KeybindingsManagerStop() { USD_LOG(LOG_DEBUG,"Stopping keybindings manager"); if (client != NULL) { g_object_unref (client); client = NULL; } QList::iterator l,end; l = screens->begin(); GdkScreen *screen = *l; gdk_window_remove_filter (gdk_screen_get_root_window (screen), (GdkFilterFunc) keybindings_filter, this); binding_unregister_keys (this); bindings_clear (this); screens->clear(); delete screens; screens = NULL; } ukui-settings-daemon/plugins/authority/0000755000175000017500000000000014205117202017255 5ustar fengfengukui-settings-daemon/plugins/authority/authorityservice.h0000644000175000017500000000254614205117202023046 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef AUTHORITYSERVICE_H #define AUTHORITYSERVICE_H #include #include #include #include class AuthorityService : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.ukui.authority.interface") public: explicit AuthorityService(QObject *parent = nullptr); ~AuthorityService(){} public slots: Q_SCRIPTABLE QString getCameraBusinfo(); Q_SCRIPTABLE int getCameraDeviceEnable(); Q_SCRIPTABLE QString toggleCameraDevice(QString businfo); Q_SCRIPTABLE int setCameraKeyboardLight(bool lightup); signals: }; #endif // AUTHORITYSERVICE_H ukui-settings-daemon/plugins/authority/authorityservice.cpp0000644000175000017500000001033614205117202023375 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "authorityservice.h" extern "C" { #include #include #include } AuthorityService::AuthorityService(QObject *parent) : QObject(parent) { } QString AuthorityService::getCameraBusinfo() { QString path = QString("/sys/bus/usb/devices/"); QDir dir(path); if (!dir.exists()){ return QString(); } dir.setFilter(QDir::Dirs); dir.setSorting(QDir::Name); QFileInfoList fileinfoList = dir.entryInfoList(); for(QFileInfo fileinfo : fileinfoList){ if (fileinfo.fileName() == "." || fileinfo.fileName() == ".."){ continue; } if (fileinfo.fileName().contains(":")){ continue; } if (fileinfo.fileName().startsWith("usb")){ continue; } QDir subdir(fileinfo.absoluteFilePath()); subdir.setFilter(QDir::Files); QFileInfoList fileinfoList2 = subdir.entryInfoList(); for (QFileInfo fileinfo2 : fileinfoList2){ if (fileinfo2.fileName() == "product"){ QFile pfile(fileinfo2.absoluteFilePath()); if (!pfile.open(QIODevice::ReadOnly | QIODevice::Text)) return QString(); QTextStream pstream(&pfile); QString output = pstream.readAll(); if (output.contains("camera", Qt::CaseInsensitive)){ return fileinfo.fileName(); } } } } return QString(); } int AuthorityService::getCameraDeviceEnable() { QString businfo = getCameraBusinfo(); if (businfo.isEmpty()){ const char cmd[] = "lsusb -t | grep 'Driver=uvcvideo'"; char output[1024] = "\0"; FILE * stream; if ((stream = popen(cmd, "r")) == NULL){ return -1; } int ret; if (fread(output, sizeof(char), 1024, stream) <= 0){ ret = 0; } else { ret = 1; } fclose(stream); return ret; } int isExists = 0; QString path = QString("/sys/bus/usb/drivers/usb/"); QDir dir(path); if (!dir.exists()){ return -1; } dir.setFilter(QDir::Dirs); dir.setSorting(QDir::Name); QFileInfoList fileinfoList = dir.entryInfoList(); for(QFileInfo fileinfo : fileinfoList){ if (fileinfo.fileName() == "." || fileinfo.fileName() == ".."){ continue; } if (fileinfo.fileName().contains(":")){ continue; } if (fileinfo.fileName() == businfo){ isExists = 1; } } return isExists; } QString AuthorityService::toggleCameraDevice(QString businfo) { QString path = QString("/sys/bus/usb/drivers/usb/"); int status = getCameraDeviceEnable(); if (status == -1){ return QString("Camera Device Not Exists!"); } if (status){ QString cmd = QString("echo '%1' > %2/unbind").arg(businfo).arg(path); system(cmd.toLatin1().data()); return QString("unbinded"); } else { QString cmd = QString("echo '%1' > %2/bind").arg(businfo).arg(path); system(cmd.toLatin1().data()); return QString("binded"); } } int AuthorityService::setCameraKeyboardLight(bool lightup) { const char target[] = "/sys/class/leds/platform::cameramute/brightness"; if (access(target, F_OK) == -1){ return -1; } int value = lightup ? 1 : 0; char cmd[256]; sprintf(cmd, "echo %d > %s", value, target); system(cmd); return 1; } ukui-settings-daemon/plugins/authority/conf/0000755000175000017500000000000014205117202020202 5ustar fengfengukui-settings-daemon/plugins/authority/conf/org.ukui.authority.conf0000644000175000017500000000156114205117202024646 0ustar fengfeng ukui-settings-daemon/plugins/authority/conf/org.ukui.authority.service0000644000175000017500000000011614205117202025354 0ustar fengfeng[D-BUS Service] Name=org.ukui.authority Exec=/usr/bin/authoritydbus User=root ukui-settings-daemon/plugins/authority/authority.pro0000644000175000017500000000246714205117202022040 0ustar fengfengQT -= gui QT += core dbus CONFIG += c++11 console CONFIG -= app_bundle # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 TEMPLATE = app TARGET = authoritydbus DESTDIR = . target.source += $$TARGET target.path = /usr/bin service.files += conf/org.ukui.authority.service service.path = /usr/share/dbus-1/system-services/ conffile.files += conf/org.ukui.authority.conf conffile.path = /etc/dbus-1/system.d/ INSTALLS += \ target \ service \ conffile SOURCES += \ authorityservice.cpp \ main.cpp # Default rules for deployment. #qnx: target.path = /tmp/$${TARGET}/bin #else: unix:!android: target.path = /opt/$${TARGET}/bin #!isEmpty(target.path): INSTALLS += target HEADERS += \ authorityservice.h ukui-settings-daemon/plugins/authority/main.cpp0000644000175000017500000000251214205117202020705 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include "authorityservice.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); a.setOrganizationName("Kylin Team"); QDBusConnection systemBus = QDBusConnection::systemBus(); if (systemBus.registerService("org.ukui.authority")){ systemBus.registerObject("/", new AuthorityService(), QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals ); } return a.exec(); } ukui-settings-daemon/plugins/auto-brightness/0000755000175000017500000000000014205117202020343 5ustar fengfengukui-settings-daemon/plugins/auto-brightness/auto-brightness.pro0000644000175000017500000000135514205117202024207 0ustar fengfengQT += gui widgets x11extras dbus sensors KConfigCore KConfigGui TEMPLATE = lib CONFIG += c++11 plugin link_pkgconfig DEFINES += TABLETMODE_LIBRARY QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"backGround\\\" include($$PWD/../../common/common.pri) INCLUDEPATH += \ -I $$PWD/../../common/ \ -I ukui-settings-daemon/ \ PKGCONFIG += \ xrandr x11 \ glib-2.0 SOURCES += \ autoBrightness-manager.cpp \ autoBrightness-plugin.cpp \ brightThread.cpp HEADERS += \ autoBrightness-manager.h \ autoBrightness-plugin.h \ brightThread.h auto_brightness_lib.path = $${PLUGIN_INSTALL_DIRS} auto_brightness_lib.files = $$OUT_PWD/libauto-brightness.so INSTALLS += auto_brightness_lib ukui-settings-daemon/plugins/auto-brightness/brightThread.h0000644000175000017500000000240314205117202023122 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BRIGHTTHREAD_H #define BRIGHTTHREAD_H #include #include class QGSettings; class BrightThread : public QThread { Q_OBJECT public: BrightThread(QObject *parent = nullptr, double bright = 100.0); // BrightThread(QObject *parent = nullptr); ~BrightThread(); void stopImmediately(); protected: void run(); private: double brightness; double currentBrightness; QGSettings *mpowerSettings; bool m_isCanRun; QMutex m_lock; }; #endif // BRIGHTTHREAD_H ukui-settings-daemon/plugins/auto-brightness/autoBrightness-plugin.h0000644000175000017500000000264214205117202025015 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef AUTOBRIGHTNESSPLUGIN_H #define AUTOBRIGHTNESSPLUGIN_H #include #include "plugin-interface.h" #include "autoBrightness-manager.h" #include "clib-syslog.h" class AutoBrightnessPlugin : public PluginInterface { private: AutoBrightnessPlugin(); AutoBrightnessPlugin(AutoBrightnessPlugin&)=delete; public: ~AutoBrightnessPlugin(); static PluginInterface *getInstance(); virtual void activate(); virtual void deactivate(); private: static AutoBrightnessManager *mAutoBrightnessManager; static PluginInterface *mInstance; }; extern "C" Q_DECL_EXPORT PluginInterface *createSettingsPlugin(); #endif // AUTOBRIGHTNESSPLUGIN_H ukui-settings-daemon/plugins/auto-brightness/autoBrightness-manager.cpp0000644000175000017500000001135114205117202025461 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include "autoBrightness-manager.h" extern "C"{ #include #include } #define SETTINGS_AUTO_BRIGHTNESS_SCHEMAS "org.ukui.SettingsDaemon.plugins.auto-brightness" #define AUTO_BRIGHTNESS_KEY "auto-brightness" AutoBrightnessManager *AutoBrightnessManager::mAutoBrightnessManager = nullptr; AutoBrightnessManager::AutoBrightnessManager() : mEnabled(false) , m_currentRunLocalThread(NULL) , mPreLux(10.f) { mSensor = new QLightSensor(this); mAutoBrightnessSettings = new QGSettings(SETTINGS_AUTO_BRIGHTNESS_SCHEMAS); } AutoBrightnessManager::~AutoBrightnessManager() { if(mAutoBrightnessManager) delete mAutoBrightnessManager; if(mSensor) delete mSensor; if(mAutoBrightnessSettings) delete mAutoBrightnessSettings; if(m_currentRunLocalThread) { m_currentRunLocalThread->stopImmediately(); m_currentRunLocalThread = NULL; } } AutoBrightnessManager *AutoBrightnessManager::AutoBrightnessManagerNew() { if(nullptr == mAutoBrightnessManager) mAutoBrightnessManager = new AutoBrightnessManager(); return mAutoBrightnessManager; } void AutoBrightnessManager::onLocalThreadDestroy(QObject* obj){ if(qobject_cast(m_currentRunLocalThread) == obj) m_currentRunLocalThread = NULL; } void AutoBrightnessManager::AutoBrightnessUpdateState() { QLightReading * lightReading = mSensor->reading(); qreal lux = lightReading->lux();//获得具体光强 if(qAbs(lux - mPreLux) <= 4.0) // 如果传感器检测到的Lux值和上次值小于4.0Lux,则不进行亮度调整 return; mPreLux = lux; if(m_currentRunLocalThread) // 如果已经存在了一个线程在调节亮度值,就终止该线程 { qDebug() << "已经有线程在运行"; m_currentRunLocalThread->stopImmediately(); m_currentRunLocalThread = NULL; } double brightness_ac = 0; if(lux > 41.0){ brightness_ac = 100.0; } else{ brightness_ac = pow(lux, 1.2) + 13; brightness_ac = round(brightness_ac); } BrightThread* thread = new BrightThread(NULL, brightness_ac); connect(thread, &QThread::finished, thread, &QObject::deleteLater); // 线程结束后调用deleteLater来销毁分配的内存 connect(thread, &QObject::destroyed, this, &AutoBrightnessManager::onLocalThreadDestroy); thread->start(); m_currentRunLocalThread = thread; } void AutoBrightnessManager::AutoBrightnessRefresh() { if(mSensor->isActive()){ AutoBrightnessUpdateState(); } else { } } void AutoBrightnessManager::SetEnabled(bool enabled) { if(mEnabled == enabled) return; mEnabled = enabled; if (mEnabled) { mSensor->start(); AutoBrightnessRefresh(); } else { if(m_currentRunLocalThread) { m_currentRunLocalThread->stopImmediately(); m_currentRunLocalThread = NULL; } mSensor->stop(); mPreLux = -4.f; } } void AutoBrightnessManager::AutoBrightnessSettingsChanged(QString key) { bool autobright; autobright = mAutoBrightnessSettings->get(AUTO_BRIGHTNESS_KEY).toBool(); if (key == AUTO_BRIGHTNESS_KEY) { SetEnabled(autobright); } } bool AutoBrightnessManager::AutoBrightnessManagerStart() { qDebug("AutoBrightnessManager Start"); bool autobright; autobright = mAutoBrightnessSettings->get(AUTO_BRIGHTNESS_KEY).toBool(); connect(mSensor,SIGNAL(readingChanged()),this,SLOT(AutoBrightnessUpdateState())); connect(mSensor,SIGNAL(activeChanged()),this,SLOT(AutoBrightnessRefresh())); connect(mAutoBrightnessSettings,SIGNAL(changed(QString)),this,SLOT(AutoBrightnessSettingsChanged(QString))); SetEnabled(autobright); return true; } void AutoBrightnessManager::AutoBrightnessManagerStop() { SetEnabled(false); qDebug("AutoBrightness Manager stop"); } ukui-settings-daemon/plugins/auto-brightness/autoBrightness-plugin.cpp0000644000175000017500000000372114205117202025347 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "autoBrightness-plugin.h" PluginInterface *AutoBrightnessPlugin::mInstance = nullptr; AutoBrightnessManager *AutoBrightnessPlugin::mAutoBrightnessManager = nullptr; AutoBrightnessPlugin::AutoBrightnessPlugin() { qDebug("AutoBrightness Plugin initializing"); if(nullptr == mAutoBrightnessManager) mAutoBrightnessManager = AutoBrightnessManager::AutoBrightnessManagerNew(); } AutoBrightnessPlugin::~AutoBrightnessPlugin() { if(mAutoBrightnessManager) delete mAutoBrightnessManager; if(mInstance) delete mInstance; } void AutoBrightnessPlugin::activate() { USD_LOG(LOG_DEBUG,"Activating AutoBrightness plugins"); bool res; res = mAutoBrightnessManager->AutoBrightnessManagerStart(); if(!res) USD_LOG(LOG_ERR,"Unable to start AutoBrightness manager"); } PluginInterface *AutoBrightnessPlugin::getInstance() { if(nullptr == mInstance) mInstance = new AutoBrightnessPlugin(); return mInstance; } void AutoBrightnessPlugin::deactivate() { qDebug("Deactivating AutoBrightness plugin"); mAutoBrightnessManager->AutoBrightnessManagerStop(); } PluginInterface *createSettingsPlugin() { return AutoBrightnessPlugin::getInstance(); } ukui-settings-daemon/plugins/auto-brightness/brightThread.cpp0000644000175000017500000000643014205117202023461 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "brightThread.h" #include #include #include #include extern "C"{ #include #include } #define SETTINGS_POWER_MANAGER "org.ukui.power-manager" #define BRIGHTNESS_AC "brightness-ac" BrightThread::BrightThread(QObject *parent, double bright) : QThread(parent), brightness(bright) //BrightThread::BrightThread(QObject *parent) : QThread(parent) { QByteArray id(SETTINGS_POWER_MANAGER); if(QGSettings::isSchemaInstalled(id)) mpowerSettings = new QGSettings(SETTINGS_POWER_MANAGER); currentBrightness = mpowerSettings->get(BRIGHTNESS_AC).toDouble(); } void BrightThread::run(){ m_isCanRun = true; if(qAbs(brightness - currentBrightness) <= 0.01){ mpowerSettings->set(BRIGHTNESS_AC, brightness); return; } if(brightness > currentBrightness){ int interval = round(brightness-currentBrightness); double step = (brightness-currentBrightness)/interval; qDebug("需要调节%d次", interval); for(int i=1; i<=interval; i++){ // qDebug() << "子线程ID:" << QThread::currentThreadId() << "m_isCanEun = " << m_isCanRun; { QMutexLocker locker(&m_lock); if(!m_isCanRun){ // qDebug() << QThread::currentThreadId() << "被终止"; return; } } mpowerSettings->set(BRIGHTNESS_AC, currentBrightness + i * step); usleep(50000); } mpowerSettings->set(BRIGHTNESS_AC, brightness); } else{ int interval = round(currentBrightness-brightness); double step = (currentBrightness-brightness)/interval; qDebug("需要调节%d次", interval); for(int i=1; i<=interval; i++){ // qDebug() << "子线程ID:" << QThread::currentThreadId() << "m_isCanEun = " << m_isCanRun; { QMutexLocker locker(&m_lock); if(!m_isCanRun){ // qDebug() << QThread::currentThreadId() << "被终止"; return; } } mpowerSettings->set(BRIGHTNESS_AC, currentBrightness - i * step); usleep(50000); } mpowerSettings->set(BRIGHTNESS_AC, brightness); } qDebug() << "brightness = " << brightness; } void BrightThread::stopImmediately(){ QMutexLocker locker(&m_lock); m_isCanRun = false; } BrightThread::~BrightThread() { if(mpowerSettings) delete mpowerSettings; } ukui-settings-daemon/plugins/auto-brightness/autoBrightness-manager.h0000644000175000017500000000357214205117202025134 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef AUTOBRIGHTNESSMANAGER_H #define AUTOBRIGHTNESSMANAGER_H #include #include #include #include #include #include "brightThread.h" class AutoBrightnessManager : public QObject { Q_OBJECT private: AutoBrightnessManager(); AutoBrightnessManager(AutoBrightnessManager&)=delete; AutoBrightnessManager&operator=(const AutoBrightnessManager&)=delete; public: ~AutoBrightnessManager(); static AutoBrightnessManager *AutoBrightnessManagerNew(); bool AutoBrightnessManagerStart(); void AutoBrightnessManagerStop(); void SetEnabled(bool enabled); public Q_SLOTS: void AutoBrightnessUpdateState(); void onLocalThreadDestroy(QObject* obj); void AutoBrightnessRefresh(); void AutoBrightnessSettingsChanged(QString); private: bool mEnabled; double mPreLux; QGSettings *mAutoBrightnessSettings; static AutoBrightnessManager *mAutoBrightnessManager; QLightSensor *mSensor; KSharedConfig::Ptr mConfig; BrightThread * m_currentRunLocalThread; }; #endif // AUTOBRIGHTNESSMANAGER_H ukui-settings-daemon/plugins/xinput/0000755000175000017500000000000014205117202016554 5ustar fengfengukui-settings-daemon/plugins/xinput/xinputmanager.h0000644000175000017500000000347414205117202021617 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XINPUTMANAGER_H #define XINPUTMANAGER_H #include #include #include "monitorinputtask.h" extern "C"{ #include "clib-syslog.h" } class QGSettings; class XinputManager : public QObject { Q_OBJECT public: XinputManager(QObject *parent = nullptr); ~XinputManager(); void start(); void stop(); Q_SIGNALS: void sigStartThread(); private: void init(); bool deviceHasProperty(XDevice *device, const char *property_name); private: QThread *m_pManagerThread; QMutex m_runningMutex; MonitorInputTask *m_pMonitorInputTask; QGSettings* m_penSettings = nullptr; private Q_SLOTS: void onSlaveAdded(int device_id); void updateSettings(QString key); /*! * \brief update tablet tool button map * It will refresh when the gsetting updates * or receives an increased signal from the device */ void updateButtonMap(); private: void SetPenRotation(int device_id); QQueue GetPenDevice(); bool initSettings(); }; #endif // XINPUTMANAGER_H ukui-settings-daemon/plugins/xinput/xinputplugin.cpp0000644000175000017500000000276614205117202022041 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "xinputplugin.h" #include #include XinputPlugin* XinputPlugin::_instance = nullptr; XinputPlugin* XinputPlugin::instance() { QMutex mutex; mutex.lock(); if(nullptr == _instance) _instance = new XinputPlugin; mutex.unlock(); return _instance; } XinputPlugin::XinputPlugin(): m_pXinputManager(new XinputManager) { USD_LOG(LOG_ERR, "Loading Xinput plugins"); } XinputPlugin::~XinputPlugin() { } void XinputPlugin::activate() { USD_LOG(LOG_ERR,"activating Xinput plugins"); m_pXinputManager->start(); } void XinputPlugin::deactivate() { m_pXinputManager->stop(); } PluginInterface *createSettingsPlugin() { return dynamic_cast(XinputPlugin::instance()); } ukui-settings-daemon/plugins/xinput/xinputplugin.h0000644000175000017500000000250214205117202021472 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XINPUTPLUGIN_H #define XINPUTPLUGIN_H #include "plugin-interface.h" #include "xinputmanager.h" #include extern "C"{ #include "clib-syslog.h" } class XinputPlugin : public PluginInterface { public: XinputPlugin(); XinputPlugin(XinputPlugin&)=delete; ~XinputPlugin(); static XinputPlugin *instance(); virtual void activate(); virtual void deactivate(); private: XinputManager *m_pXinputManager; static XinputPlugin *_instance; }; extern "C" Q_DECL_EXPORT PluginInterface *createSettingsPlugin(); #endif // XINPUTPLUGIN_H ukui-settings-daemon/plugins/xinput/xinput.pro0000644000175000017500000000131314205117202020623 0ustar fengfengQT += core gui x11extras LIBS += -lXi -lX11 TEMPLATE = lib DEFINES += XINPUT_LIBRARY include($$PWD/../../common/common.pri) CONFIG += c++11 link_pkgconfig x11extras debug CONFIG += plugin PKGCONFIG += x11 DEFINES += QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"xinput\\\" QMAKE_CXXFLAGS += -Wdeprecated-declarations INCLUDEPATH += \ -I $$PWD/../../common/ \ -I ukui-settings-daemon/ SOURCES += \ monitorinputtask.cpp \ xinputmanager.cpp \ xinputplugin.cpp HEADERS += \ monitorinputtask.h \ xinputmanager.h \ xinputplugin.h xinput_lib.path = $${PLUGIN_INSTALL_DIRS} xinput_lib.files = $$OUT_PWD/libxinput.so INSTALLS += xinput_lib ukui-settings-daemon/plugins/xinput/monitorinputtask.h0000644000175000017500000000557114205117202022367 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MONITORINPUTTASK_H #define MONITORINPUTTASK_H #include #include #include #include #include #include #include #include #include #include #include #include #include extern "C"{ #include #include "clib-syslog.h" // #include "KylinDefine.h" } class MonitorInputTask : public QObject { Q_OBJECT public: bool m_running; public: static MonitorInputTask* instance(QObject *parent = nullptr); public Q_SLOTS: void StartManager(); Q_SIGNALS: /*! * \brief slaveAdded 从设备添加 * \param device_id */ void slaveAdded(int device_id); /*! * \brief slaveRemoved 从设备移除 * \param device_id */ void slaveRemoved(int device_id); /*! * \brief masterAdded 主分支添加 * \param device_id */ void masterAdded(int device_id); /*! * \brief masterRemoved 主分支移除 * \param device_id */ void masterRemoved(int device_id); /*! * \brief deviceEnable 设备启用 * \param device_id */ void deviceEnable(int device_id); /*! * \brief deviceDisable 设备禁用 * \param device_id */ void deviceDisable(int device_id); /*! * \brief slaveAttached 从设备附加 * \param device_id */ void slaveAttached(int device_id); /*! * \brief slaveDetached 从设备分离 * \param device_id */ void slaveDetached(int device_id); private: MonitorInputTask(QObject *parent = nullptr); void initConnect(); /*! * \brief ListeningToInputEvent 监听所有输入设备的事件 */ void ListeningToInputEvent(); /*! * \brief EventSift 筛选出发生事件的设备ID * \param event 所有设备的事件信息 * \param flag 当前发生的事件 * \return 查找失败 return -1; 查找成功 return device_id; */ int EventSift(XIHierarchyEvent *event, int flag); }; #endif // MONITORINPUTTASK_H ukui-settings-daemon/plugins/xinput/monitorinputtask.cpp0000644000175000017500000001321514205117202022714 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "monitorinputtask.h" #include "xinputmanager.h" MonitorInputTask* MonitorInputTask::instance(QObject *parent) { static MonitorInputTask *_instance = nullptr; QMutex mutex; mutex.lock(); if(!_instance) _instance = new MonitorInputTask(parent); mutex.unlock(); return _instance; } MonitorInputTask::MonitorInputTask(QObject *parent): QObject(parent), m_running(false) { initConnect(); } void MonitorInputTask::initConnect() { } void MonitorInputTask::StartManager() { USD_LOG(LOG_DEBUG,"info: [MonitorInputTask][StartManager]: thread id =%d",QThread::currentThreadId()); QTimer::singleShot(0, this, &MonitorInputTask::ListeningToInputEvent); } int MonitorInputTask::EventSift(XIHierarchyEvent *event, int flag) { int device_id = -1; int cnt = event->num_info; XIHierarchyInfo *event_list = event->info; for(int i = 0;i < cnt;i++) { if(event_list[i].flags & flag) { device_id = event_list[i].deviceid; } } return device_id; } void MonitorInputTask::ListeningToInputEvent() { USD_LOG(LOG_DEBUG,"Start ListeningToInputEvent!"); Display *display = NULL; // open display // PEEK_XOpenDisplay(display); display = XOpenDisplay(NULL); // display = XOpenDisplay(NULL); // openDisplayOK = true; //QX11Info::display(); USD_LOG(LOG_DEBUG, "choke check pass......"); if (display == NULL) { USD_LOG(LOG_ERR,"OpenDisplay fail...."); return; } XIEventMask mask[2]; XIEventMask *m; Window win; USD_LOG(LOG_DEBUG, "choke check pass......"); win = DefaultRootWindow(display); USD_LOG(LOG_DEBUG, "choke check pass......"); m = &mask[0]; m->deviceid = XIAllDevices; m->mask_len = XIMaskLen(XI_LASTEVENT); m->mask = (unsigned char*)calloc(m->mask_len, sizeof(char)); XISetMask(m->mask, XI_HierarchyChanged); USD_LOG(LOG_DEBUG, "choke check pass......"); m = &mask[1]; m->deviceid = XIAllMasterDevices; m->mask_len = XIMaskLen(XI_LASTEVENT); m->mask = (unsigned char*)calloc(m->mask_len, sizeof(char)); XISelectEvents(display, win, &mask[0], 2); XSync(display, False); USD_LOG(LOG_DEBUG, "choke check pass......"); free(mask[0].mask); free(mask[1].mask); while(true) { XEvent ev; XGenericEventCookie *cookie = (XGenericEventCookie*)&ev.xcookie; USD_LOG(LOG_DEBUG, "choke chdeck pass......cookie->evtype:%d",cookie->evtype); // if (cookie->type != GenericEvent){ // USD_LOG(LOG_DEBUG, "choke chdeck pass......type error:%d is't GenericEvent(%d)",cookie->evtype,GenericEvent); // continue; // } XNextEvent(display, (XEvent*)&ev);//该方法会引起glib崩溃一次.下次出现记录具体的事件类型,该方法是阻塞处理。。。。 USD_LOG(LOG_DEBUG, "choke check pass......event:%d",ev.type); // 判断当前事件监听是否还要继续 // 保证效率 m_running[*bool] 的访问不需要加锁 if(!m_running){ USD_LOG(LOG_DEBUG, "choke check pass......break"); break; } USD_LOG(LOG_DEBUG, "choke check pass......"); if (XGetEventData(display, cookie) && cookie->type == GenericEvent) { USD_LOG(LOG_DEBUG, "choke check pass......"); if(XI_HierarchyChanged == cookie->evtype) { XIHierarchyEvent *hev = (XIHierarchyEvent*)cookie->data; if(hev->flags & XIMasterRemoved) { Q_EMIT masterRemoved(EventSift(hev, XIMasterRemoved)); } else if(hev->flags & XISlaveAdded) { Q_EMIT slaveAdded(EventSift(hev, XISlaveAdded)); } else if(hev->flags & XISlaveRemoved) { Q_EMIT slaveRemoved(EventSift(hev, XISlaveRemoved)); } else if(hev->flags & XISlaveAttached) { Q_EMIT slaveAttached(EventSift(hev, XISlaveAttached)); } else if(hev->flags & XISlaveDetached) { Q_EMIT slaveDetached(EventSift(hev, XISlaveDetached)); } else if(hev->flags & XIDeviceEnabled) { Q_EMIT deviceEnable(EventSift(hev, XIDeviceEnabled)); } else if(hev->flags & XIDeviceDisabled) { Q_EMIT deviceDisable(EventSift(hev, XIDeviceDisabled)); } else if(hev->flags & XIMasterAdded) { Q_EMIT masterAdded(EventSift(hev, XIMasterAdded)); } } } USD_LOG(LOG_DEBUG, "choke check pass......"); XFreeEventData(display, cookie); } XDestroyWindow(display, win); } ukui-settings-daemon/plugins/xinput/xinputmanager.cpp0000644000175000017500000001741614205117202022153 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "xinputmanager.h" #include #include #include #include #include #define UKUI_CONTROL_CENTER_PEN_SCHEMA "org.ukui.control-center.pen" #define RIGHT_CLICK_KEY "right-click" XinputManager::XinputManager(QObject *parent): QObject(parent) { init(); } void XinputManager::init() { // init device monitor m_pMonitorInputTask = MonitorInputTask::instance(); connect(this, &XinputManager::sigStartThread, m_pMonitorInputTask, &MonitorInputTask::StartManager); connect(m_pMonitorInputTask, &MonitorInputTask::slaveAdded, this, &XinputManager::onSlaveAdded); connect(m_pMonitorInputTask, &MonitorInputTask::slaveAdded, this, &XinputManager::updateButtonMap); m_pManagerThread = new QThread(this); m_pMonitorInputTask->moveToThread(m_pManagerThread); // init pen settings if ( false == initSettings()) { return ; } // init settings monitor connect(m_penSettings, SIGNAL(changed(QString)), this, SLOT(updateSettings(QString))); } XinputManager::~XinputManager() { if (m_penSettings) delete m_penSettings; } void XinputManager::start() { USD_LOG(LOG_DEBUG,"info: [XinputManager][StartManager]: thread id =%d",QThread::currentThreadId()); m_runningMutex.lock(); m_pMonitorInputTask->m_running = true; m_runningMutex.unlock(); m_pManagerThread->start(); Q_EMIT sigStartThread(); } void XinputManager::stop() { if(m_pManagerThread->isRunning()) { m_runningMutex.lock(); m_pMonitorInputTask->m_running = false; m_runningMutex.unlock(); m_pManagerThread->quit(); } } void XinputManager::SetPenRotation(int device_id) { // Q_UNUSED(device_id); // 得到触控笔的ID QQueue penDeviceQue; int ndevices = 0; Display *dpy = XOpenDisplay(NULL); XIDeviceInfo *info = XIQueryDevice(dpy, XIAllDevices, &ndevices); for (int i = 0; i < ndevices; i++) { XIDeviceInfo* dev = &info[i]; if(!dev->enabled) continue; if(device_id != dev->deviceid) { continue; } if(dev->use != XISlavePointer) continue; for (int j = 0; j < dev->num_classes; j++) { if (dev->classes[j]->type == XITouchClass) { // 如果当前的设备是绝对坐标映射 则认为该设备需要进行一次屏幕映射 QDBusInterface *xrandDbus = new QDBusInterface(DBUS_XRANDR_NAME,DBUS_XRANDR_PATH,DBUS_XRANDR_INTERFACE,QDBusConnection::sessionBus(),this); if (xrandDbus->isValid()) { //USD_LOG(LOG_DEBUG, ".."); xrandDbus->asyncCall("setScreenMap"); } } } } for (int i = 0; i < ndevices; i++) { XIDeviceInfo* dev = &info[i]; // 判断当前设备是不是触控笔 if(dev->use != XISlavePointer) continue; if(!dev->enabled) continue; for (int j = 0; j < dev->num_classes; j++) { if (dev->classes[j]->type == XIValuatorClass) { XIValuatorClassInfo *t = (XIValuatorClassInfo*)dev->classes[j]; // 如果当前的设备是绝对坐标映射 则认为该设备需要进行一次屏幕映射 if (t->mode == XIModeAbsolute) { penDeviceQue.enqueue(dev->deviceid); break; } } } } if(!penDeviceQue.size()) { // qDebug() << "info: [XrandrManager][SetPenRotation]: Do not neet to pen device map-to-output outDevice!"; //return; goto FREE_DPY; } // 设置map-to-output while(penDeviceQue.size()) { int pen_device_id = penDeviceQue.dequeue(); QString name = "eDP-1"; //针对该项目而言,笔记本内显固定为 eDP-1 QString cmd = QString("xinput map-to-output %1 %2").arg(pen_device_id).arg(name); QProcess::execute(cmd); } FREE_DPY: XIFreeDeviceInfo(info); XCloseDisplay(dpy); } void XinputManager::onSlaveAdded(int device_id) { // qDebug() << "info: [XinputManager][onSlaveAdded]: Slave Device(id =" << device_id << ") Added!"; SetPenRotation(device_id);//新设备不是触控笔就不要处理了! } bool XinputManager::initSettings() { if (!QGSettings::isSchemaInstalled(UKUI_CONTROL_CENTER_PEN_SCHEMA)) { USD_LOG(LOG_DEBUG,"Can not find schema org.ukui.control-center.pen!"); return false; } m_penSettings = new QGSettings(UKUI_CONTROL_CENTER_PEN_SCHEMA); updateButtonMap(); return true; } void XinputManager::updateSettings(QString key) { if (key == RIGHT_CLICK_KEY) { updateButtonMap(); } } void XinputManager::updateButtonMap() { QQueue deviceQue = GetPenDevice(); if (!deviceQue.size()) { return; } QString command; //! \brief The button-map default value is 1234567, //! and the modified mapping is 1334567 //! The numbers in this refer to button 2 being mapped to button 3 while (deviceQue.size()) { if (m_penSettings->get(RIGHT_CLICK_KEY).value()) { command = QString("xinput set-button-map %1 1 3 3").arg(deviceQue.dequeue()); } else { command = QString("xinput set-button-map %1 1 2 3").arg(deviceQue.dequeue()); } QProcess::execute(command); } } QQueue XinputManager::GetPenDevice() { QQueue penDeviceQue; int ndevices = 0; Display* dpy = XOpenDisplay(NULL); XIDeviceInfo* info = XIQueryDevice(dpy, XIAllDevices, &ndevices); for (int i = 0; i < ndevices; i++) { XIDeviceInfo* dev = &info[i]; if(dev->use != XISlavePointer) continue; if(!dev->enabled) continue; XDevice* device = XOpenDevice(dpy, dev->deviceid); /*! * \note Currently only pen devices have this property, * but it is not certain that this property must be pen-only */ if (deviceHasProperty(device, "libinput Tablet Tool Pressurecurve")) { penDeviceQue.enqueue(dev->deviceid); } XCloseDevice(dpy, device); } XIFreeDeviceInfo(info); XCloseDisplay(dpy); return penDeviceQue; } bool XinputManager::deviceHasProperty(XDevice *device, const char *property_name) { Display* dpy = XOpenDisplay(NULL); Atom realtype, prop; int realformat; unsigned long nitems, bytes_after; unsigned char* data; prop = XInternAtom (dpy, property_name, True); if (!prop) { XCloseDisplay(dpy); return false; } try { if ((XGetDeviceProperty(dpy, device, prop, 0, 1, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data) == Success) && (realtype != None)) { XFree (data); XCloseDisplay(dpy); return true; } } catch (int x) { } XCloseDisplay(dpy); return false; } ukui-settings-daemon/plugins/background/0000755000175000017500000000000014205117202017344 5ustar fengfengukui-settings-daemon/plugins/background/background.pro0000644000175000017500000000141414205117202022205 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-04-16T09:30:00 # #------------------------------------------------- QT += core widgets dbus x11extras gui TEMPLATE = lib TARGET = background CONFIG += no_keywords c++11 create_prl plugin link_pkgconfig app_bundle debug DEFINES += MODULE_NAME=\\\"backGround\\\" include($$PWD/../../common/common.pri) PKGCONFIG += \ gio-2.0 \ gtk+-3.0 \ glib-2.0 \ imlib2 SOURCES += \ $$PWD/background-plugin.cpp \ $$PWD/background-manager.cpp HEADERS += \ $$PWD/background-plugin.h \ $$PWD/background-manager.h background_lib.path = $${PLUGIN_INSTALL_DIRS} background_lib.files += $$OUT_PWD/libbackground.so INSTALLS += background_lib ukui-settings-daemon/plugins/background/background-plugin.cpp0000644000175000017500000000331414205117202023464 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "background-plugin.h" #include "clib-syslog.h" PluginInterface* BackgroundPlugin::mInstance = nullptr; BackgroundPlugin::BackgroundPlugin() { return; manager = new BackgroundManager(); return; } BackgroundPlugin::~BackgroundPlugin() { USD_LOG(LOG_DEBUG, "background plugin free..."); if(manager){ delete manager; manager = nullptr; } } PluginInterface *BackgroundPlugin::getInstance() { if (nullptr == mInstance) { mInstance = new BackgroundPlugin(); } return mInstance; } void BackgroundPlugin::activate() { return; USD_LOG (LOG_DEBUG, "Activating %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); manager->BackgroundManagerStart(); } void BackgroundPlugin::deactivate() { USD_LOG (LOG_DEBUG, "Deactivating background plugin"); } PluginInterface* createSettingsPlugin() { return BackgroundPlugin::getInstance(); } ukui-settings-daemon/plugins/background/background-manager.cpp0000644000175000017500000001102414205117202023575 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "background-manager.h" #include #include #define BACKGROUND "org.mate.background" #define PICTURE_FILE_NAME "picture-filename" #define COLOR_FILE_NAME "primary-color" #define CAN_DRAW_BACKGROUND "draw-background" BackgroundManager::BackgroundManager() { m_screen = QApplication::screens().at(0); } BackgroundManager::~BackgroundManager() { if(bSettingOld) delete bSettingOld; } void BackgroundManager::initGSettings(){ bSettingOld = new QGSettings(BACKGROUND); Filename = bSettingOld->get(PICTURE_FILE_NAME).toString(); // QObject::connect(bSettingOld, &QGSettings::changed, this, &BackgroundManager::setup_Background); // QObject::connect(qApp, &QApplication::screenAdded, this, &BackgroundManager::screenAddedProcess); // QObject::connect(qApp, &QApplication::screenRemoved, this, &BackgroundManager::screenRemovedProcess); // QObject::connect(m_screen, &QScreen::virtualGeometryChanged, this, &BackgroundManager::virtualGeometryChangedProcess); connect(bSettingOld, SIGNAL(changed(QString)),this, SLOT(setup_Background(QString))); connect(qApp,SIGNAL(screenAdded(QScreen *)),this, SLOT(screenAddedProcess(QScreen*))); connect(qApp, SLOT(screenRemoved(QScreen *)),this, SLOT(screenRemovedProcess(QScreen *))); connect(m_screen, &QScreen::virtualGeometryChanged, this,&BackgroundManager::virtualGeometryChangedProcess); } void BackgroundManager::SetBackground() { Pixmap pix; Window root; Screen *scn; QScreen *screen; Imlib_Image img; int ScnNum, width = 0,height = 0; dpy = gdk_x11_get_default_xdisplay(); img = imlib_load_image(Filename.toLatin1().data()); if (!img) { USD_LOG(LOG_DEBUG,"%s:Unable to load image\n", Filename.toLatin1().data()); return ; } imlib_context_set_image(img); if (!dpy) return ; ScnNum = QApplication::screens().length(); width = DisplayWidth(dpy, 0); height = DisplayHeight(dpy, 0); scn = DefaultScreenOfDisplay(dpy); root = DefaultRootWindow(dpy); pix = XCreatePixmap(dpy, root, width, height, DefaultDepthOfScreen(scn)); imlib_context_set_display(dpy); imlib_context_set_visual(DefaultVisualOfScreen(scn)); imlib_context_set_colormap(DefaultColormapOfScreen(scn)); imlib_context_set_drawable(pix); ScnNum = QApplication::screens().length(); for(int i = 0; i < ScnNum; i++){ screen = QApplication::screens().at(i); //qDebug()<geometry(); imlib_render_image_on_drawable_at_size(screen->geometry().x() * 2, screen->geometry().y() * 2, screen->geometry().width() *2, screen->geometry().height() * 2); } XSetWindowBackgroundPixmap(dpy, root, pix); XClearWindow(dpy, root); while (XPending(dpy)) { XEvent ev; XNextEvent(dpy, &ev); } XFreePixmap(dpy, pix); imlib_free_image(); } void BackgroundManager::setup_Background(const QString &key) { if(key.compare(QString::fromLocal8Bit(PICTURE_FILE_NAME))==0) Filename = bSettingOld->get(PICTURE_FILE_NAME).toString(); if(key.compare(QString::fromLocal8Bit(COLOR_FILE_NAME))==0) Filename = bSettingOld->get(COLOR_FILE_NAME).toString(); SetBackground(); } void BackgroundManager::screenAddedProcess(QScreen *screen) { SetBackground(); } void BackgroundManager::screenRemovedProcess(QScreen *screen) { SetBackground(); } void BackgroundManager::virtualGeometryChangedProcess(const QRect &geometry) { SetBackground(); } void BackgroundManager::BackgroundManagerStart() { initGSettings(); //SetBackground(); } ukui-settings-daemon/plugins/background/background-plugin.h0000644000175000017500000000254614205117202023137 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BACKGROUNDPLUGIN_H #define BACKGROUNDPLUGIN_H #include "background-manager.h" #include "plugin-interface.h" #include class BackgroundPlugin : public PluginInterface { public: ~BackgroundPlugin(); static PluginInterface* getInstance(); virtual void activate (); virtual void deactivate (); private: BackgroundPlugin(); BackgroundPlugin(BackgroundPlugin&)=delete; private: BackgroundManager *manager; static PluginInterface* mInstance; }; extern "C" Q_DECL_EXPORT PluginInterface* createSettingsPlugin(); #endif // BACKGROUNDPLUGIN_H ukui-settings-daemon/plugins/background/background-manager.h0000644000175000017500000000317614205117202023253 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BACKGROUND_MANAGER_H #define BACKGROUND_MANAGER_H #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif #include "clib-syslog.h" #ifdef __cplusplus } #endif class BackgroundManager : public QObject { Q_OBJECT public: BackgroundManager(); ~BackgroundManager(); public: void BackgroundManagerStart(); void SetBackground(); void initGSettings(); private: void scaleBg(const QRect &geometry); void virtualGeometryChangedProcess(const QRect &geometry); public Q_SLOTS: void setup_Background(const QString &key); void screenAddedProcess(QScreen *screen); void screenRemovedProcess(QScreen *screen); private: QGSettings *bSettingOld; QScreen *m_screen; QString Filename; Display *dpy; }; #endif // BACKGROUND_MANAGER_H ukui-settings-daemon/plugins/media-keys/0000755000175000017500000000000014205117214017260 5ustar fengfengukui-settings-daemon/plugins/media-keys/xEventMonitor.cpp0000644000175000017500000001205014205117202022600 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "xEventMonitor.h" xEventMonitor::xEventMonitor(QObject *parent) : QThread(parent) { isPress = false; start(QThread::LowestPriority); } void xEventMonitor::run() { Display* display = XOpenDisplay(0); if (display == 0) { USD_LOG(LOG_DEBUG, "unable to open display\n"); return; } // Receive from ALL clients, including future clients. XRecordClientSpec clients = XRecordAllClients; XRecordRange* range = XRecordAllocRange(); if (range == 0) { USD_LOG(LOG_DEBUG,"unable to allocate XRecordRange\n"); return; } // Receive KeyPress, KeyRelease, ButtonPress, ButtonRelease and MotionNotify events. memset(range, 0, sizeof(XRecordRange)); range->device_events.first = KeyPress; range->device_events.last = MotionNotify; // And create the XRECORD context. XRecordContext context = XRecordCreateContext(display, 0, &clients, 1, &range, 1); if (context == 0) { USD_LOG(LOG_DEBUG,"XRecordCreateContext failed\n");//fprintf(stderr, "XRecordCreateContext failed\n"); return; } XFree(range); XSync(display, True); Display* display_datalink = XOpenDisplay(0); if (display_datalink == 0) { // fprintf(stderr, "unable to open second display\n"); USD_LOG(LOG_DEBUG,"unable to open second display\n"); return; } if (!XRecordEnableContext(display_datalink, context, callback, (XPointer) this)) { // fprintf(stderr, "XRecordEnableContext() failed\n"); USD_LOG(LOG_DEBUG,"XRecordEnableContext() failed\n"); return; } XCloseDisplay(display); XCloseDisplay(display_datalink); } void xEventMonitor::callback(XPointer ptr, XRecordInterceptData* data) { ((xEventMonitor *) ptr)->handleRecordEvent(data); } bool xEventMonitor::getWinPressStatus() { return winPress; } bool xEventMonitor::getCtrlPressStatus() { return ctrlPress_l | ctrlPress_r; } bool xEventMonitor::getAltPressStatus() { return altPress_l | altPress_r; } bool xEventMonitor::getShiftPressStatus() { return shiftPress_l | shiftPress_r; } void xEventMonitor::handleRecordEvent(XRecordInterceptData* data) { int eventKeysym; static int Bpress = 0; if (data->category == XRecordFromServer) { xEvent * event = (xEvent *)data->data; if (event->u.u.type!=KeyPress && event->u.u.type!=KeyRelease){ goto ERR; } switch (event->u.u.type) { case KeyPress: switch(event->u.u.detail){ case LEFT_SHIFT: shiftPress_l = true; break; case LEFT_CTRL: ctrlPress_l = true; Q_EMIT keyPress(event); break; case LEFT_ALT: altPress_l = true; break; case RIGHT_SHIFT: shiftPress_r = true; break; case RIGHT_ALT: altPress_r = true; break; case RIGHT_CTRL: ctrlPress_r = true; Q_EMIT keyPress(event); break; case MATE_KEY: winPress = true; break; default : Q_EMIT keyPress(event); break; } break; case KeyRelease: switch(event->u.u.detail){ case LEFT_SHIFT: shiftPress_l = false; break; case LEFT_CTRL: ctrlPress_l = false; break; case LEFT_ALT: altPress_l = false; break; case RIGHT_SHIFT: shiftPress_r = false; break; case RIGHT_ALT: altPress_r = false; break; case RIGHT_CTRL: ctrlPress_r = false; break; case MATE_KEY: winPress = false; break; default : Q_EMIT keyRelease(event); break; } break; default: break; } } ERR: XRecordFreeData(data); } bool xEventMonitor::filterWheelEvent(int detail) { return detail != WheelUp && detail != WheelDown && detail != WheelLeft && detail != WheelRight; } ukui-settings-daemon/plugins/media-keys/mediakey-manager.cpp0000644000175000017500000024571214205117202023174 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mediakey-manager.h" #include "eggaccelerators.h" #include #include "clib-syslog.h" #include "rfkillswitch.h" #include "usd_base_class.h" MediaKeysManager* MediaKeysManager::mManager = nullptr; const int VOLUMESTEP = 6; #define midValue(x,low,high) (((x) > (high)) ? (high): (((x) < (low)) ? (low) : (x))) #define TIME_LIMIT 2500 #define MAX_BRIGHTNESS 100 #define STEP_BRIGHTNESS 10 #define UKUI_DAEMON_NAME "ukui-settings-daemon" #define MEDIAKEY_SCHEMA "org.ukui.SettingsDaemon.plugins.media-keys" #define POINTER_SCHEMA "org.ukui.SettingsDaemon.plugins.mouse" #define POINTER_KEY "locate-pointer" #define POWER_SCHEMA "org.ukui.power-manager" #define POWER_BUTTON_KEY "button-power" #define SESSION_SCHEMA "org.ukui.session" #define SESSION_WIN_KEY "win-key-release" #define SHOT_SCHEMA "org.ukui.screenshot" #define SHOT_RUN_KEY "isrunning" #define PANEL_QUICK_OPERATION "org.ukui.quick-operation.panel" #define PANEL_SOUND_STATE "soundstate" #define PANEL_SOUND_VOLUMSIZE "volumesize" #define GPM_SETTINGS_SCHEMA "org.ukui.power-manager" #define GPM_SETTINGS_BRIGHTNESS_AC "brightness-ac" typedef enum { POWER_SUSPEND = 1, POWER_SHUTDOWN = 2, POWER_HIBERNATE = 3, POWER_INTER_ACTIVE = 4 } PowerButton; MediaKeysManager::MediaKeysManager(QObject* parent):QObject(parent) { mTimer = new QTimer(this); mVolumeWindow = new VolumeWindow(); mDeviceWindow = new DeviceWindow(); powerSettings = new QGSettings(POWER_SCHEMA); mSettings = new QGSettings(MEDIAKEY_SCHEMA); pointSettings = new QGSettings(POINTER_SCHEMA); sessionSettings = new QGSettings(SESSION_SCHEMA); gdk_init(NULL,NULL); //session bus 会话总线 QDBusConnection sessionBus = QDBusConnection::sessionBus(); if(sessionBus.registerService("org.ukui.SettingsDaemon")){ sessionBus.registerObject("/org/ukui/SettingsDaemon/MediaKeys",this, QDBusConnection::ExportAllContents); } mXEventMonitor = new xEventMonitor(this); } MediaKeysManager::~MediaKeysManager() { delete mTimer; if (mXEventMonitor) { mXEventMonitor->deleteLater(); } if (mSettings) { delete mSettings; mSettings = nullptr; } if (pointSettings) { delete pointSettings; mSettings = nullptr; } if (sessionSettings) { delete sessionSettings; sessionSettings = nullptr; } if (shotSettings) { delete shotSettings; shotSettings = nullptr; } // if (mExecCmd) // delete mExecCmd; if (mVolumeWindow) { delete mVolumeWindow; mVolumeWindow = nullptr; } if (mDeviceWindow) { delete mDeviceWindow; mDeviceWindow = nullptr; } if (powerSettings) { delete powerSettings; powerSettings = nullptr; } } MediaKeysManager* MediaKeysManager::mediaKeysNew() { if(nullptr == mManager) mManager = new MediaKeysManager(); return mManager; } void MediaKeysManager::sjhKeyTest() { QList args; QString param = QString::fromLocal8Bit("" "[" "{" "\"enabled\": true," " \"id\": \"e3fa3cd9190f27820ab7c30a34b9f1fb\"," " \"metadata\": {" "\"fullname\": \"xrandr-DO NOT USE - RTK-WCS Display\"," "\"name\": \"HDMI-1\"" " }," " \"mode\": {" " \"refresh\": 30," "\"size\": {" " \"height\": 2160," " \"width\": 3840" "}" "}," "\"pos\": {" " \"x\": 0," " \"y\": 0" "}," "\"primary\": false," "\"rotation\": 1," "\"scale\": 1" "}," "{" " \"enabled\": true," " \"id\": \"e2add05191c5c70db7824c9cd76e19f5\"," " \"metadata\": {" " \"fullname\": \"xrandr-Lenovo Group Limited-LEN LI2224A-U5619HB8\"," " \"name\": \"DP-2\"" "}," "\"mode\": {" " \"refresh\": 59.93387985229492," " \"size\": {" " \"height\": 1080," " \"width\": 1920" "}" "}," "\"pos\": {" " \"x\": 3840," " \"y\": 0" "}," "\"primary\": true," "\"rotation\": 1," "\"scale\": 1" "}" "]" ""); QDBusMessage message = QDBusMessage::createMethodCall(DBUS_XRANDR_NAME, DBUS_XRANDR_PATH, DBUS_XRANDR_INTERFACE, "setScreensParam"); args.append(param); args.append(qAppName()); message.setArguments(args); QDBusConnection::sessionBus().send(message); } bool MediaKeysManager::getScreenLockState() { bool res = false; QDBusMessage response = QDBusConnection::sessionBus().call(mDbusScreensaveMessage); if (response.type() == QDBusMessage::ReplyMessage) { if(response.arguments().isEmpty() == false) { bool value = response.arguments().takeFirst().toBool(); res = value; } } else { USD_LOG(LOG_DEBUG, "GetLockState called failed"); } return res; } bool MediaKeysManager::mediaKeysStart(GError*) { // mate_mixer_init(); QList::iterator l,begin,end; if (true == QGSettings::isSchemaInstalled(SHOT_SCHEMA)) { shotSettings = new QGSettings(SHOT_SCHEMA); if (nullptr != shotSettings) { if (shotSettings->keys().contains(SHOT_RUN_KEY)) { if (shotSettings->get(SHOT_RUN_KEY).toBool()) shotSettings->set(SHOT_RUN_KEY, false); } } } mVolumeWindow->initWindowInfo(); mDeviceWindow->initWindowInfo(); initShortcuts(); initXeventMonitor(); mDbusScreensaveMessage = QDBusMessage::createMethodCall("org.ukui.ScreenSaver", "/", "org.ukui.ScreenSaver", "GetLockState"); return true; } int8_t MediaKeysManager::getCurrentMode() { QDBusMessage message = QDBusMessage::createMethodCall(DBUS_STATUSMANAGER_NAME, DBUS_STATUSMANAGER_PATH, DBUS_STATUSMANAGER_NAME, DBUS_STATUSMANAGER_GET_MODE); QDBusMessage response = QDBusConnection::sessionBus().call(message); if (response.type() == QDBusMessage::ReplyMessage) { if(response.arguments().isEmpty() == false) { bool value = response.arguments().takeFirst().toBool(); USD_LOG(LOG_DEBUG, "get mode :%d", value); return value; } } return -1; } void MediaKeysManager::initShortcuts() { /* WebCam */ QAction *webCam= new QAction(this); webCam->setObjectName(QStringLiteral("Toggle WebCam")); webCam->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(webCam, QList{Qt::Key_WebCam}); KGlobalAccel::self()->setShortcut(webCam, QList{Qt::Key_WebCam}); connect(webCam, &QAction::triggered, this, [this]() { doAction(WEBCAM_KEY); }); if (false == UsdBaseClass::isUseXEventAsShutKey()) { /* touchpad */ QAction *touchpad= new QAction(this); touchpad->setObjectName(QStringLiteral("Toggle touchpad")); touchpad->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(touchpad, QList{Qt::Key_TouchpadToggle}); KGlobalAccel::self()->setShortcut(touchpad, QList{Qt::Key_TouchpadToggle}); connect(touchpad, &QAction::triggered, this, [this]() { doAction(TOUCHPAD_KEY); }); /* Brightness Down */ QAction *brightDown= new QAction(this); brightDown->setObjectName(QStringLiteral("Brightness down")); brightDown->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(brightDown, QList{Qt::Key_MonBrightnessDown}); KGlobalAccel::self()->setShortcut(brightDown, QList{Qt::Key_MonBrightnessDown}); connect(brightDown, &QAction::triggered, this, [this]() { USD_LOG(LOG_DEBUG,"Brightness down..............."); doAction(BRIGHT_DOWN_KEY); }); /* Brightness Up */ QAction *brightUp = new QAction(this); brightUp->setObjectName(QStringLiteral("Brightness Up")); brightUp->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(brightUp, QList{Qt::Key_MonBrightnessUp}); KGlobalAccel::self()->setShortcut(brightUp, QList{Qt::Key_MonBrightnessUp}); connect(brightUp, &QAction::triggered, this, [this]() { USD_LOG(LOG_DEBUG,"Brightness Up .................."); doAction(BRIGHT_UP_KEY); }); /* sound mute*/ QAction *volumeMute= new QAction(this); volumeMute->setObjectName(QStringLiteral("Volume mute")); volumeMute->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(volumeMute, QList{Qt::Key_VolumeMute}); KGlobalAccel::self()->setShortcut(volumeMute, QList{Qt::Key_VolumeMute}); connect(volumeMute, &QAction::triggered, this, [this]() { doAction(MUTE_KEY); }); /*sound down*/ QAction *volumeDown= new QAction(this); volumeDown->setObjectName(QStringLiteral("Volume down")); volumeDown->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(volumeDown, QList{Qt::Key_VolumeDown}); KGlobalAccel::self()->setShortcut(volumeDown, QList{Qt::Key_VolumeDown}); connect(volumeDown, &QAction::triggered, this, [this]() { doAction(VOLUME_DOWN_KEY); }); /*sound up*/ QAction *volumeUp= new QAction(this); volumeUp->setObjectName(QStringLiteral("Volume up")); volumeUp->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(volumeUp, QList{Qt::Key_VolumeUp}); KGlobalAccel::self()->setShortcut(volumeUp, QList{Qt::Key_VolumeUp}); connect(volumeUp, &QAction::triggered, this, [this]() { doAction(VOLUME_UP_KEY); }); /*screenshot*/ QAction *screenshot= new QAction(this); screenshot->setObjectName(QStringLiteral("Take a screenshot")); screenshot->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(screenshot, QList{Qt::Key_Print}); KGlobalAccel::self()->setShortcut(screenshot, QList{Qt::Key_Print}); connect(screenshot, &QAction::triggered, this, [this]() { if(!mTimer->isActive()){ mTimer->singleShot(1000, this, [=]() { doAction(SCREENSHOT_KEY); }); } }); /*mic mute*/ QAction *micMute= new QAction(this); micMute->setObjectName(QStringLiteral("Mic mute")); micMute->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(micMute, QList{Qt::Key_MicMute}); KGlobalAccel::self()->setShortcut(micMute, QList{Qt::Key_MicMute}); connect(micMute, &QAction::triggered, this, [this]() { doAction(MIC_MUTE_KEY); }); /*window screenshot*/ QAction *wScreenshot= new QAction(this); wScreenshot->setObjectName(QStringLiteral("Take a screenshot of a window")); wScreenshot->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(wScreenshot, QList{Qt::CTRL + Qt::Key_Print}); KGlobalAccel::self()->setShortcut(wScreenshot, QList{Qt::CTRL + Qt::Key_Print}); connect(wScreenshot, &QAction::triggered, this, [this]() { if(!mTimer->isActive()){ mTimer->singleShot(1000, this, [=]() { doAction(WINDOW_SCREENSHOT_KEY); }); } }); /*area screenshot*/ QAction *aScreenshot= new QAction(this); aScreenshot->setObjectName(QStringLiteral("Take a screenshot of an area")); aScreenshot->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(aScreenshot, QList{Qt::SHIFT + Qt::Key_Print}); KGlobalAccel::self()->setShortcut(aScreenshot, QList{Qt::SHIFT + Qt::Key_Print}); connect(aScreenshot, &QAction::triggered, this, [this]() { if(!mTimer->isActive()){ mTimer->singleShot(1000, this, [=]() { doAction(AREA_SCREENSHOT_KEY); }); } }); /* WLAN */ QAction *wlan= new QAction(this); wlan->setObjectName(QStringLiteral("Toggle wlan")); wlan->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(wlan, QList{Qt::Key_WLAN}); KGlobalAccel::self()->setShortcut(wlan, QList{Qt::Key_WLAN}); connect(wlan, &QAction::triggered, this, [this]() { doAction(WLAN_KEY); }); /* POWEROFF */ QAction *logout2 = new QAction(this); logout2->setObjectName(QStringLiteral("open shutdown interface")); logout2->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(logout2, QList{Qt::Key_PowerOff}); KGlobalAccel::self()->setShortcut(logout2, QList{Qt::Key_PowerOff}); connect(logout2, &QAction::triggered, this, [this]() { doAction(POWER_OFF_KEY); }); } /*shutdown*/ QAction *powerDown= new QAction(this); powerDown->setObjectName(QStringLiteral("Shut down")); powerDown->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(powerDown, QList{Qt::Key_PowerDown}); KGlobalAccel::self()->setShortcut(powerDown, QList{Qt::Key_PowerDown}); connect(powerDown, &QAction::triggered, this, [this]() { USD_LOG(LOG_DEBUG,"press key powerdown !"); doAction(POWER_DOWN_KEY); }); /*TODO eject*/ QAction *eject= new QAction(this); eject->setObjectName(QStringLiteral("Eject")); eject->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(eject, QList{Qt::Key_Eject}); KGlobalAccel::self()->setShortcut(eject, QList{Qt::Key_Eject}); connect(eject, &QAction::triggered, this, [this]() { doAction(EJECT_KEY); }); /*home*/ QAction *home= new QAction(this); home->setObjectName(QStringLiteral("Home folder")); home->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(home, QList{Qt::Key_Explorer}); KGlobalAccel::self()->setShortcut(home, QList{Qt::Key_Explorer}); connect(home, &QAction::triggered, this, [this]() { doAction(HOME_KEY); }); /*media*/ QAction *media= new QAction(this); media->setObjectName(QStringLiteral("Launch media player")); media->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(media, QList{Qt::Key_LaunchMedia}); KGlobalAccel::self()->setShortcut(media, QList{Qt::Key_LaunchMedia}); connect(media, &QAction::triggered, this, [this]() { doAction(MEDIA_KEY); }); /*calculator*/ QAction *cal= new QAction(this); cal->setObjectName(QStringLiteral("Open calculator")); cal->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(cal, QList{Qt::Key_Calculator}); KGlobalAccel::self()->setShortcut(cal, QList{Qt::Key_Calculator}); connect(cal, &QAction::triggered, this, [this]() { doAction(CALCULATOR_KEY); }); /*search*/ QAction *search= new QAction(this); search->setObjectName(QStringLiteral("Open search")); search->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(search, QList{Qt::Key_Search}); KGlobalAccel::self()->setShortcut(search, QList{Qt::Key_Search}); connect(search, &QAction::triggered, this, [this]() { doAction(GLOBAL_SEARCH_KEY); }); /*email*/ QAction *mail= new QAction(this); mail->setObjectName(QStringLiteral("Launch email client")); mail->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(mail, QList{Qt::Key_MailForward}); KGlobalAccel::self()->setShortcut(mail, QList{Qt::Key_MailForward}); connect(mail, &QAction::triggered, this, [this]() { doAction(EMAIL_KEY); }); if (false == UsdBaseClass::isTablet()) { /*screensaver*/ QAction *screensaver= new QAction(this); screensaver->setObjectName(QStringLiteral("Lock screen")); screensaver->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(screensaver, QList{Qt::CTRL + Qt::ALT + Qt::Key_L}); KGlobalAccel::self()->setShortcut(screensaver, QList{Qt::CTRL + Qt::ALT + Qt::Key_L}); connect(screensaver, &QAction::triggered, this, [this]() { doAction(SCREENSAVER_KEY); }); /*peony2*/ QAction *peony2= new QAction(this); peony2->setObjectName(QStringLiteral("Open File manager ")); peony2->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(peony2, QList{Qt::CTRL + Qt::ALT + Qt::Key_E}); KGlobalAccel::self()->setShortcut(peony2, QList{Qt::CTRL + Qt::ALT + Qt::Key_E}); connect(peony2, &QAction::triggered, this, [this]() { doAction(FILE_MANAGER_KEY_2); }); /*terminal*/ QAction *terminal= new QAction(this); terminal->setObjectName(QStringLiteral("Open terminal")); terminal->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(terminal, QList{Qt::CTRL + Qt::ALT + Qt::Key_T}); KGlobalAccel::self()->setShortcut(terminal, QList{Qt::CTRL + Qt::ALT + Qt::Key_T}); connect(terminal, &QAction::triggered, this, [this]() { doAction(TERMINAL_KEY); }); } /*screensaver2*/ QAction *screensaver2= new QAction(this); screensaver2->setObjectName(QStringLiteral("Lock screens")); screensaver2->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(screensaver2, QList{Qt::META + Qt::Key_L}); KGlobalAccel::self()->setShortcut(screensaver2, QList{Qt::META + Qt::Key_L}); connect(screensaver2, &QAction::triggered, this, [this]() { doAction(SCREENSAVER_KEY_2); }); /*ukui-control-center*/ QAction *ukuiControlCenter= new QAction(this); ukuiControlCenter->setObjectName(QStringLiteral("Open system setting")); ukuiControlCenter->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(ukuiControlCenter, QList{Qt::META + Qt::Key_I}); KGlobalAccel::self()->setShortcut(ukuiControlCenter, QList{Qt::META + Qt::Key_I}); connect(ukuiControlCenter, &QAction::triggered, this, [this]() { doAction(SETTINGS_KEY); }); /*ukui-control-center2*/ QAction *ukuiControlCenter2= new QAction(this); ukuiControlCenter2->setObjectName(QStringLiteral("Open system settings")); ukuiControlCenter2->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(ukuiControlCenter2, QList{Qt::Key_Tools}); KGlobalAccel::self()->setShortcut(ukuiControlCenter2, QList{Qt::Key_Tools}); connect(ukuiControlCenter2, &QAction::triggered, this, [this]() { doAction(SETTINGS_KEY_2); }); /*peony*/ QAction *peony= new QAction(this); peony->setObjectName(QStringLiteral("Open file manager")); peony->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(peony, QList{Qt::META + Qt::Key_E}); KGlobalAccel::self()->setShortcut(peony, QList{Qt::META + Qt::Key_E}); connect(peony, &QAction::triggered, this, [this]() { doAction(FILE_MANAGER_KEY); }); /*help*/ QAction *help= new QAction(this); help->setObjectName(QStringLiteral("Launch help browser")); help->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(help, QList{Qt::Key_Help}); KGlobalAccel::self()->setShortcut(help, QList{Qt::Key_Help}); connect(help, &QAction::triggered, this, [this]() { doAction(HELP_KEY); }); /*www*/ QAction *www= new QAction(this); www->setObjectName(QStringLiteral("Launch help browser2")); www->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(www, QList{Qt::Key_WWW}); KGlobalAccel::self()->setShortcut(www, QList{Qt::Key_WWW}); connect(www, &QAction::triggered, this, [this]() { doAction(WWW_KEY); }); /*media play*/ QAction *mediaPlay= new QAction(this); mediaPlay->setObjectName(QStringLiteral("Play/Pause")); mediaPlay->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(mediaPlay, QList{Qt::Key_MediaPlay}); KGlobalAccel::self()->setShortcut(mediaPlay, QList{Qt::Key_MediaPlay}); connect(mediaPlay, &QAction::triggered, this, [this]() { doAction(PLAY_KEY); }); /*media pause*/ QAction *mediaPause= new QAction(this); mediaPause->setObjectName(QStringLiteral("Pause playback")); mediaPause->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(mediaPause, QList{Qt::Key_MediaPause}); KGlobalAccel::self()->setShortcut(mediaPause, QList{Qt::Key_MediaPause}); connect(mediaPause, &QAction::triggered, this, [this]() { doAction(PAUSE_KEY); }); /*media stop*/ QAction *mediaStop= new QAction(this); mediaStop->setObjectName(QStringLiteral("Stop playback")); mediaStop->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(mediaStop, QList{Qt::Key_MediaStop}); KGlobalAccel::self()->setShortcut(mediaStop, QList{Qt::Key_MediaStop}); connect(mediaStop, &QAction::triggered, this, [this]() { USD_LOG(LOG_DEBUG,"stop_key..."); doAction(STOP_KEY); }); /*media preious*/ QAction *mediaPre= new QAction(this); mediaPre->setObjectName(QStringLiteral("Previous track")); mediaPre->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(mediaPre, QList{Qt::Key_MediaPrevious}); KGlobalAccel::self()->setShortcut(mediaPre, QList{Qt::Key_MediaPrevious}); connect(mediaPre, &QAction::triggered, this, [this]() { USD_LOG(LOG_DEBUG,"PREVIOUS_KEY..."); doAction(PREVIOUS_KEY); }); /*media next*/ QAction *mediaNext= new QAction(this); mediaNext->setObjectName(QStringLiteral("Next track")); mediaNext->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(mediaNext, QList{Qt::Key_MediaNext}); KGlobalAccel::self()->setShortcut(mediaNext, QList{Qt::Key_MediaNext}); connect(mediaNext, &QAction::triggered, this, [this]() { doAction(NEXT_KEY); USD_LOG(LOG_DEBUG,"NEXT_KEY..."); }); /*audio Rewind*/ QAction *audioRewind= new QAction(this); audioRewind->setObjectName(QStringLiteral("Audio Rewind")); audioRewind->setProperty("componentName",QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(audioRewind, QList{Qt::Key_AudioRewind}); KGlobalAccel::self()->setShortcut(audioRewind, QList{Qt::Key_AudioRewind}); connect(audioRewind, &QAction::triggered, this, [this]() { doAction(REWIND_KEY); }); /*audio Forward*/ QAction *audioForward= new QAction(this); audioForward->setObjectName(QStringLiteral("Audio Forward")); audioForward->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(audioForward, QList{Qt::Key_AudioForward}); KGlobalAccel::self()->setShortcut(audioForward, QList{Qt::Key_AudioForward}); connect(audioForward, &QAction::triggered, this, [this]() { doAction(FORWARD_KEY); }); /*audio Repeat*/ QAction *audioRepeat= new QAction(this); audioRepeat->setObjectName(QStringLiteral("Audio Repeat")); audioRepeat->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(audioRepeat, QList{Qt::Key_AudioRepeat}); KGlobalAccel::self()->setShortcut(audioRepeat, QList{Qt::Key_AudioRepeat}); connect(audioRepeat, &QAction::triggered, this, [this]() { doAction(REPEAT_KEY); }); /*audio random*/ QAction *audioRandom= new QAction(this); audioRandom->setObjectName(QStringLiteral("Audio Random")); audioRandom->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(audioRandom, QList{Qt::Key_AudioRandomPlay}); KGlobalAccel::self()->setShortcut(audioRandom, QList{Qt::Key_AudioRandomPlay}); connect(audioRandom, &QAction::triggered, this, [this]() { doAction(RANDOM_KEY); }); /*TODO magnifier*/ QAction *magnifier= new QAction(this); magnifier->setObjectName(QStringLiteral("Toggle Magnifier")); magnifier->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(magnifier, QList{}); KGlobalAccel::self()->setShortcut(magnifier, QList{}); connect(magnifier, &QAction::triggered, this, [this]() { doAction(MAGNIFIER_KEY); }); /*TODO screen reader*/ QAction *screenReader= new QAction(this); screenReader->setObjectName(QStringLiteral("Toggle Screen Reader")); screenReader->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(screenReader, QList{}); KGlobalAccel::self()->setShortcut(screenReader, QList{}); connect(screenReader, &QAction::triggered, this, [this]() { doAction(SCREENREADER_KEY); }); /*TODO on-screen keyboard*/ QAction *onScreenKeyboard= new QAction(this); onScreenKeyboard->setObjectName(QStringLiteral("Toggle On-screen Keyboard")); onScreenKeyboard->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(onScreenKeyboard, QList{}); KGlobalAccel::self()->setShortcut(onScreenKeyboard, QList{}); connect(onScreenKeyboard, &QAction::triggered, this, [this]() { doAction(ON_SCREEN_KEYBOARD_KEY); }); /*logout*/ QAction *logout= new QAction(this); logout->setObjectName(QStringLiteral("Open shutdown interface")); logout->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(logout, QList{Qt::CTRL + Qt::ALT + Qt::Key_Delete}); KGlobalAccel::self()->setShortcut(logout, QList{Qt::CTRL + Qt::ALT + Qt::Key_Delete }); connect(logout, &QAction::triggered, this, [this]() { doAction(LOGOUT_KEY); }); QAction *logout1= new QAction(this); logout1->setObjectName(QStringLiteral("Open shutdown Interface ")); logout1->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(logout1, QList{Qt::CTRL + Qt::ALT + Qt::Key_Period}); KGlobalAccel::self()->setShortcut(logout1, QList{Qt::CTRL + Qt::ALT + Qt::Key_Period }); connect(logout1, &QAction::triggered, this, [this]() { doAction(LOGOUT_KEY); }); //sideBar QAction *sideBar= new QAction(this); sideBar->setObjectName(QStringLiteral("Open sideBar ")); sideBar->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(sideBar, QList{Qt::META + Qt::Key_A}); KGlobalAccel::self()->setShortcut(sideBar, QList{Qt::META + Qt::Key_A}); connect(sideBar, &QAction::triggered, this, [this]() { doAction(UKUI_SIDEBAR); }); /*terminal2*/ QAction *terminal2= new QAction(this); terminal2->setObjectName(QStringLiteral("Open Terminal")); terminal2->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(terminal2, QList{Qt::META + Qt::Key_T}); KGlobalAccel::self()->setShortcut(terminal2, QList{Qt::META + Qt::Key_T}); connect(terminal2, &QAction::triggered, this, [this]() { doAction(TERMINAL_KEY); }); /*window switch*/ QAction *wSwitch= new QAction(this); wSwitch->setObjectName(QStringLiteral("open windows switch")); wSwitch->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(wSwitch, QList{Qt::CTRL + Qt::ALT + Qt::Key_W}); KGlobalAccel::self()->setShortcut(wSwitch, QList{Qt::CTRL + Qt::ALT + Qt::Key_W}); connect(wSwitch, &QAction::triggered, this, [this]() { doAction(WINDOWSWITCH_KEY); }); /*window switch2*/ QAction *wSwitch2= new QAction(this); wSwitch2->setObjectName(QStringLiteral("Open Windows switch")); wSwitch2->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(wSwitch2, QList{Qt::META + Qt::Key_W}); KGlobalAccel::self()->setShortcut(wSwitch2, QList{Qt::META + Qt::Key_W}); connect(wSwitch2, &QAction::triggered, this, [this]() { doAction(WINDOWSWITCH_KEY_2); }); /*system monitor*/ QAction *monitor= new QAction(this); monitor->setObjectName(QStringLiteral("Open the system monitor")); monitor->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(monitor, QList{Qt::CTRL + Qt::SHIFT + Qt::Key_Escape}); KGlobalAccel::self()->setShortcut(monitor, QList{Qt::CTRL + Qt::SHIFT + Qt::Key_Escape}); connect(monitor, &QAction::triggered, this, [this]() { doAction(SYSTEM_MONITOR_KEY); }); /*internal edit*/ QAction *editor= new QAction(this); editor->setObjectName(QStringLiteral("Open the internet connectionr")); editor->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(editor, QList{Qt::META + Qt::Key_K}); KGlobalAccel::self()->setShortcut(editor, QList{Qt::META + Qt::Key_K}); connect(editor, &QAction::triggered, this, [this]() { doAction(CONNECTION_EDITOR_KEY); }); /*ukui search*/ QAction *ukuiSearch= new QAction(this); ukuiSearch->setObjectName(QStringLiteral("Open UKUI Search")); ukuiSearch->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(ukuiSearch, QList{Qt::META + Qt::Key_S}); KGlobalAccel::self()->setShortcut(ukuiSearch, QList{Qt::META + Qt::Key_S}); connect(ukuiSearch, &QAction::triggered, this, [this]() { doAction(GLOBAL_SEARCH_KEY); }); /*kylin display switch*/ QAction *dSwitch= new QAction(this); dSwitch->setObjectName(QStringLiteral("Open kylin display switch")); dSwitch->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(dSwitch, QList{Qt::META + Qt::Key_P}); KGlobalAccel::self()->setShortcut(dSwitch, QList{Qt::META + Qt::Key_P}); connect(dSwitch, &QAction::triggered, this, [this]() { if (UsdBaseClass::isTablet()){ if (getCurrentMode()) { return; } } static QTime startTime = QTime::currentTime(); int elapsed = 0; elapsed = startTime.msecsTo(QTime::currentTime()); if (elapsed>0 && elapsed<1200){//避免过快刷屏,必须大于,1200ms执行一次, if (false == CheckProcessAlive("kydisplayswitch")){ return; } } startTime = QTime::currentTime(); doAction(KDS_KEY); }); /*kylin display switch2*/ QAction *dSwitch2= new QAction(this); dSwitch2->setObjectName(QStringLiteral("open kylin display switch")); dSwitch2->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(dSwitch2, QList{Qt::Key_Display}); KGlobalAccel::self()->setShortcut(dSwitch2, QList{Qt::Key_Display}); connect(dSwitch2, &QAction::triggered, this, [this]() { doAction(KDS_KEY2); }); /*kylin eyeCare center*/ QAction *eyeCare= new QAction(this); eyeCare->setObjectName(QStringLiteral("open kylin eyeCare center")); eyeCare->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); KGlobalAccel::self()->setDefaultShortcut(eyeCare, QList{Qt::CTRL + Qt::ALT + Qt::Key_P}); KGlobalAccel::self()->setShortcut(eyeCare, QList{Qt::CTRL + Qt::ALT + Qt::Key_P}); connect(eyeCare, &QAction::triggered, this, [this]() { doAction(UKUI_EYECARE_CENTER); }); //just for test globalshut // QAction *sjhTest= new QAction(this); // sjhTest->setObjectName(QStringLiteral("sjh test")); // sjhTest->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); // KGlobalAccel::self()->setDefaultShortcut(sjhTest, QList{Qt::CTRL + Qt::ALT + Qt::Key_R}); // KGlobalAccel::self()->setShortcut(sjhTest, QList{Qt::CTRL + Qt::ALT + Qt::Key_R}); // connect(sjhTest, &QAction::triggered, this, [this]() { // USD_LOG(LOG_DEBUG,"."); // sjhKeyTest(); // }); /*TODO Ukui Sidebar*/ // QAction *sideBar= new QAction(this); // sideBar->setObjectName(QStringLiteral("Open ukui sidebar")); // sideBar->setProperty("componentName", QStringLiteral(UKUI_DAEMON_NAME)); // KGlobalAccel::self()->setDefaultShortcut(sideBar, QList{}); // KGlobalAccel::self()->setShortcut(sideBar, QList{}); // connect(sideBar, &QAction::triggered, this, [this]() { // //doAction(); // }); } void MediaKeysManager::mediaKeysStop() { QList::iterator l,end; bool needFlush; int i; USD_LOG(LOG_DEBUG, "Stooping media keys manager!"); // XEventMonitor::instance()->exit(); /* gdk_window_remove_filter(gdk_screen_get_root_window(gdk_screen_get_default()), (GdkFilterFunc)acmeFilterEvents, NULL); needFlush = false; gdk_x11_display_error_trap_push(gdk_display_get_default()); for(i = 0; i < HANDLED_KEYS; ++i){ if(keys[i].key){ needFlush = true; grab_key_unsafe(keys[i].key,false,nullptr); g_free(keys[i].key->keycodes); g_free(keys[i].key); keys[i].key = NULL; } } if(needFlush) gdk_display_flush(gdk_display_get_default()); gdk_x11_display_error_trap_pop_ignored(gdk_display_get_default()); */ // if(mStream != NULL) // g_clear_object(&mStream); // if(mControl != NULL) // g_clear_object(&mControl); // if(mInputControl != NULL) // g_clear_object(&mInputControl); // if(mInputStream != NULL) // g_clear_object(&mInputStream); // if(mContext != NULL) // g_clear_object(&mContext); } void MediaKeysManager::XkbEventsRelease(const QString &keyStr) { QString KeyName; static bool ctrlFlag = false; /* if (keyStr.compare("Shift_L+Print") == 0 || keyStr.compare("Shift_R+Print") == 0 ){ executeCommand("kylin-screenshot", " gui"); return; } if (keyStr.compare("Print") == 0){ executeCommand("kylin-screenshot", " full"); return; } if(keyStr.compare("Control_L+Shift_L+Escape") == 0 || keyStr.compare("Shift_L+Control_L+Escape") == 0) { executeCommand("ukui-system-monitor", nullptr); return; } */ if (keyStr.length() >= 10) KeyName = keyStr.left(10); if(KeyName.compare("Control_L+") == 0 || KeyName.compare("Control_R+") == 0 ) ctrlFlag = true; if((ctrlFlag && keyStr.compare("Control_L") == 0 )|| (ctrlFlag && keyStr.compare("Control_R") == 0 )){ ctrlFlag = false; return; } else if((m_ctrlFlag && keyStr.compare("Control_L") == 0 )|| (m_ctrlFlag && keyStr.compare("Control_R") == 0 )) return; if (keyStr.compare("Control_L") == 0 || keyStr.compare("Control_R") == 0) { if (pointSettings) { try { QStringList QGsettingskeys = pointSettings->keys(); if (QGsettingskeys.contains("locate-pointer")){ pointSettings->set("locate-pointer", !pointSettings->get(POINTER_KEY).toBool()); } else { USD_LOG(LOG_DEBUG,"schema contins key..."); } } catch(char *msg){ } } } } void MediaKeysManager::XkbEventsPress(const QString &keyStr) { QString KeyName; if (keyStr.length() >= 10) KeyName = keyStr.left(10); if(KeyName.compare("Control_L+") == 0 || KeyName.compare("Control_R+") == 0 ) m_ctrlFlag = true; if(m_ctrlFlag && keyStr.compare("Control_L") == 0 || m_ctrlFlag && keyStr.compare("Control_R") == 0 ){ m_ctrlFlag = false; return; } } void MediaKeysManager::MMhandleRecordEvent(xEvent* data) { if(UsdBaseClass::isUseXEventAsShutKey()) { Display* display; guint eventKeysym; display = QX11Info::display(); xEvent * event = (xEvent *)data; eventKeysym =XkbKeycodeToKeysym(display, event->u.u.detail, 0, 0); if (eventKeysym == XKB_KEY_XF86AudioMute) { xEventHandle(MUTE_KEY, event); } else if (eventKeysym == XKB_KEY_XF86AudioLowerVolume) { doAction(VOLUME_DOWN_KEY); } else if (eventKeysym == XKB_KEY_XF86AudioRaiseVolume) { doAction(VOLUME_UP_KEY); } else if (eventKeysym == XKB_KEY_XF86MonBrightnessDown) { doAction(BRIGHT_DOWN_KEY); } else if (eventKeysym == XKB_KEY_XF86MonBrightnessUp) { doAction(BRIGHT_UP_KEY); } else if (eventKeysym == XKB_KEY_Print && mXEventMonitor->getShiftPressStatus()) { xEventHandle(AREA_SCREENSHOT_KEY, event); } else if (eventKeysym == XKB_KEY_Print && mXEventMonitor->getCtrlPressStatus()) { xEventHandle(WINDOW_SCREENSHOT_KEY, event); } else if (eventKeysym == XKB_KEY_Print) { xEventHandle(SCREENSHOT_KEY, event); } else if (eventKeysym == XKB_KEY_XF86RFKill) { xEventHandle(RFKILL_KEY, event); } else if(eventKeysym == XKB_KEY_XF86WLAN) { xEventHandle(WLAN_KEY, event); } else if (eventKeysym == XKB_KEY_XF86TouchpadToggle) { xEventHandle(TOUCHPAD_KEY, event); } else if (eventKeysym == XKB_KEY_XF86AudioMicMute) { xEventHandle(MIC_MUTE_KEY, event); } else if (eventKeysym == XKB_KEY_XF86TouchpadOn) { xEventHandle(TOUCHPAD_ON_KEY, event); } else if (eventKeysym == XKB_KEY_XF86TouchpadOff) { xEventHandle(TOUCHPAD_OFF_KEY, event); } else if (eventKeysym == XKB_KEY_XF86ScreenSaver) { xEventHandle(SCREENSAVER_KEY, event); } else if (eventKeysym == XKB_KEY_XF86TaskPane) { xEventHandle(WINDOWSWITCH_KEY, event); } else if (eventKeysym == XKB_KEY_XF86Calculator) { xEventHandle(CALCULATOR_KEY, event); } else if (eventKeysym == XKB_KEY_XF86Battery) { } else if (eventKeysym == XKB_KEY_XF86Bluetooth) { xEventHandle(BLUETOOTH_KEY, event); } else if (eventKeysym == XKB_KEY_XF86PowerOff) { doAction(POWER_OFF_KEY); } else if(true == mXEventMonitor->getCtrlPressStatus()) { if (pointSettings) { QStringList QGsettingskeys = pointSettings->keys(); if (QGsettingskeys.contains("locate-pointer")){ pointSettings->set("locate-pointer", !pointSettings->get(POINTER_KEY).toBool()); } } } } } void MediaKeysManager::MMhandleRecordEventRelease(xEvent* data) { if(UsdBaseClass::isUseXEventAsShutKey()) { Display* display; guint eventKeysym; display = QX11Info::display(); xEvent * event = (xEvent *)data; eventKeysym =XkbKeycodeToKeysym(display, event->u.u.detail, 0, 0); if (eventKeysym == XKB_KEY_XF86AudioMute) { xEventHandleRelease(MUTE_KEY); } else if (eventKeysym == XKB_KEY_Print && mXEventMonitor->getShiftPressStatus()) { xEventHandleRelease(AREA_SCREENSHOT_KEY); } else if (eventKeysym == XKB_KEY_Print && mXEventMonitor->getCtrlPressStatus()) { xEventHandleRelease(WINDOW_SCREENSHOT_KEY); } else if (eventKeysym == XKB_KEY_Print) { xEventHandleRelease(SCREENSHOT_KEY); } else if(eventKeysym == XKB_KEY_XF86RFKill) { xEventHandleRelease(RFKILL_KEY); } else if (eventKeysym == XKB_KEY_XF86WLAN) { xEventHandleRelease(WLAN_KEY); }else if (eventKeysym == XKB_KEY_XF86TouchpadToggle) { xEventHandleRelease(TOUCHPAD_KEY); } else if (eventKeysym == XKB_KEY_XF86AudioMicMute) { xEventHandleRelease(MIC_MUTE_KEY); } else if (eventKeysym == XKB_KEY_XF86TouchpadOn) { xEventHandleRelease(TOUCHPAD_ON_KEY); } else if (eventKeysym == XKB_KEY_XF86TouchpadOff) { xEventHandleRelease(TOUCHPAD_OFF_KEY); } else if (eventKeysym == XKB_KEY_XF86ScreenSaver) { xEventHandleRelease(SCREENSAVER_KEY); } else if (eventKeysym == XKB_KEY_XF86TaskPane) { xEventHandleRelease(WINDOWSWITCH_KEY); } else if (eventKeysym == XKB_KEY_XF86Calculator) { xEventHandleRelease(CALCULATOR_KEY); } else if (eventKeysym == XKB_KEY_XF86Battery) { } else if (eventKeysym == XKB_KEY_XF86Battery) { xEventHandleRelease(BLUETOOTH_KEY); } } } void MediaKeysManager::initXeventMonitor() { // XEventMonitor::instance()->start(); // connect(XEventMonitor::instance(), SIGNAL(keyRelease(QString)),this, SLOT(XkbEventsRelease(QString))); // connect(XEventMonitor::instance(), SIGNAL(keyPress(QString)),this, SLOT(XkbEventsPress(QString))); connect(mXEventMonitor, SIGNAL(keyPress(xEvent*)), this, SLOT(MMhandleRecordEvent(xEvent*)), Qt::QueuedConnection); connect(mXEventMonitor, SIGNAL(keyRelease(xEvent*)), this, SLOT(MMhandleRecordEventRelease(xEvent*)), Qt::QueuedConnection); } void MediaKeysManager::initScreens() { GdkDisplay *display; GdkScreen *screen; display = gdk_display_get_default(); screen = gdk_display_get_default_screen(display); mCurrentScreen = screen; } GdkFilterReturn MediaKeysManager::acmeFilterEvents(GdkXEvent* xevent,GdkEvent* event,void* data) { XEvent *xev = (XEvent *) xevent; XAnyEvent *xany = (XAnyEvent *) xevent; int i; /* verify we have a key event */ if (xev->type != KeyPress && xev->type != KeyRelease) return GDK_FILTER_CONTINUE; for (i = 0; i < HANDLED_KEYS; i++) { if (match_key (keys[i].key, xev)) { switch (keys[i].key_type) { case VOLUME_DOWN_KEY: case VOLUME_UP_KEY: /* auto-repeatable keys */ if (xev->type != KeyPress) return GDK_FILTER_CONTINUE; break; default: if (xev->type != KeyRelease) return GDK_FILTER_CONTINUE; } mManager->mCurrentScreen = mManager->acmeGetScreenFromEvent(xany); if (mManager->doAction(keys[i].key_type) == false) return GDK_FILTER_REMOVE; else return GDK_FILTER_CONTINUE; } } return GDK_FILTER_CONTINUE; } #if 0 //delete libmatemixer void MediaKeysManager::onContextStateNotify(MateMixerContext *context, GParamSpec *pspec, MediaKeysManager *manager) { updateDefaultInput(manager); updateDefaultOutput(manager); } void MediaKeysManager::onContextDefaultInputNotify(MateMixerContext *context, GParamSpec *pspec, MediaKeysManager *manager) { updateDefaultInput(manager); } void MediaKeysManager::onContextDefaultOutputNotify(MateMixerContext *context, GParamSpec *pspec, MediaKeysManager *manager) { updateDefaultOutput(manager); } void MediaKeysManager::onContextStreamRemoved(MateMixerContext *context, char *name, MediaKeysManager *mManager) { if (mManager->mStream != NULL) { MateMixerStream *stream = mate_mixer_context_get_stream (mManager->mContext, name); if (stream == mManager->mStream) { if(mManager->mStream && mManager->mControl){ g_clear_object (&mManager->mStream); g_clear_object (&mManager->mControl); } } } } void MediaKeysManager::updateDefaultInput(MediaKeysManager *mManager) { MateMixerStream *inputStream; MateMixerStreamControl *inputControl = NULL; inputStream = mate_mixer_context_get_default_input_stream (mManager->mContext); if (inputStream != NULL) inputControl = mate_mixer_stream_get_default_control (inputStream); if(inputStream == mManager->mInputStream) return; if(mManager->mInputStream && mManager->mInputControl){ g_clear_object (&mManager->mInputStream); g_clear_object (&mManager->mInputControl); } if (inputControl != NULL) { MateMixerStreamControlFlags flags = mate_mixer_stream_control_get_flags (inputControl); /* Do not use the stream if it is not possible to mute it or * change the volume */ if (!(flags & MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE) && !(flags & MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE)) return; mManager->mInputStream = (MateMixerStream *)g_object_ref(inputStream); mManager->mInputControl = (MateMixerStreamControl *)g_object_ref(inputControl); USD_LOG(LOG_DEBUG, "Default input stream updated to %s", mate_mixer_stream_get_name (inputStream)); } else USD_LOG(LOG_DEBUG, "Default input stream unset"); } void MediaKeysManager::updateDefaultOutput(MediaKeysManager *mManager) { MateMixerStream *stream; MateMixerStreamControl *control = NULL; stream = mate_mixer_context_get_default_output_stream (mManager->mContext); if (stream != NULL) control = mate_mixer_stream_get_default_control (stream); if (stream == mManager->mStream) return; if(mManager->mStream && mManager->mControl){ g_clear_object (&mManager->mStream); g_clear_object (&mManager->mControl); } if (control != NULL) { MateMixerStreamControlFlags flags = mate_mixer_stream_control_get_flags (control); /* Do not use the stream if it is not possible to mute it or * change the volume */ if (!(flags & MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE) && !(flags & MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE)) return; mManager->mStream = (MateMixerStream *)g_object_ref(stream); mManager->mControl = (MateMixerStreamControl *)g_object_ref(control); USD_LOG(LOG_DEBUG, "Default output stream updated to %s", mate_mixer_stream_get_name (stream)); } else USD_LOG(LOG_DEBUG, "Default output stream unset"); g_signal_connect ( G_OBJECT (mManager->mControl), "notify::volume", G_CALLBACK (onStreamControlVolumeNotify), mManager); g_signal_connect ( G_OBJECT (mManager->mControl), "notify::mute", G_CALLBACK (onStreamControlMuteNotify), mManager); } /*! * \brief * \details * 音量值更改 */ void MediaKeysManager::onStreamControlVolumeNotify (MateMixerStreamControl *control,GParamSpec *pspec,MediaKeysManager *mManager) { #if 0 MateMixerStream *stream = mate_mixer_stream_control_get_stream(control); USD_LOG(LOG_DEBUG, "onStreamControlVolumeNotify control name: %s volume: %d", mate_mixer_stream_control_get_name(control) , mate_mixer_stream_control_get_volume (control)); if(!MATE_MIXER_IS_STREAM(stream)){ USD_LOG(LOG_DEBUG,"Add exception handling ---------"); stream = mate_mixer_context_get_stream(mManager->mContext,mate_mixer_stream_control_get_name(control)); //使用命令重新设置音量 int volume = mate_mixer_stream_control_get_volume(control); QString cmd = "pactl set-sink-volume "+ QString(mate_mixer_stream_control_get_name(control)) +" "+ QString::number(volume,10); system(cmd.toLocal8Bit().data()); } #endif } /*! * \brief * \details * 静音通知 */ void MediaKeysManager::onStreamControlMuteNotify (MateMixerStreamControl *control,GParamSpec *pspec,MediaKeysManager *mManager) { #if 0 MateMixerStream *stream = mate_mixer_stream_control_get_stream(control); USD_LOG(LOG_DEBUG, "onStreamControlMuteNotify control name: %s volume: %d", mate_mixer_stream_control_get_name(control) , mate_mixer_stream_control_get_mute (control)); if(!MATE_MIXER_IS_STREAM(stream)){ USD_LOG(LOG_DEBUG,"Add exception handling ---------"); stream = mate_mixer_context_get_stream(mManager->mContext,mate_mixer_stream_control_get_name(control)); //使用命令重新设置音量 bool isMuted = mate_mixer_stream_control_get_mute(control); QString cmd = "pactl set-sink-mute "+ QString(mate_mixer_stream_control_get_name(control)) +" "+ QString::number(isMuted,10); system(cmd.toLocal8Bit().data()); } #endif } #endif //delete matemixer GdkScreen * MediaKeysManager::acmeGetScreenFromEvent (XAnyEvent *xanyev) { GdkWindow *window; window = gdk_screen_get_root_window (gdk_screen_get_default()); if (GDK_WINDOW_XID (window) == xanyev->window) return gdk_screen_get_default(); return NULL; } bool MediaKeysManager::doAction(int type) { static QTime startTime = QTime::currentTime(); int elapsed = 0; static uint lastKeySym = 0x00; // if ((getScreenLockState()) && (type!=MUTE_KEY && type!=VOLUME_DOWN_KEY && type!=VOLUME_UP_KEY)) { // USD_LOG(LOG_DEBUG,"can;t use it.."); // return false; // } //TODO:需要考虑清楚如何过滤掉重复事件, // if (lastKeySym == type){//考虑到一个应用针对多个快捷键,所以不能以按键值进行次数区分必须以序号进行区分,否则第二个以后的快捷键不生效 // elapsed = startTime.msecsTo(QTime::currentTime()); // if (elapsed>=0 && elapsed<50){//避免过快刷屏,必须大于,50ms执行一次, // return false; //goto FREE_DISPLAY; // } // } startTime = QTime::currentTime(); lastKeySym = type; switch(type){ case TOUCHPAD_KEY: doTouchpadAction(STATE_TOGGLE); break; case TOUCHPAD_ON_KEY: doTouchpadAction(STATE_ON); break; case TOUCHPAD_OFF_KEY: doTouchpadAction(STATE_OFF); break; case MUTE_KEY: case VOLUME_DOWN_KEY: case VOLUME_UP_KEY: doSoundActionALSA(type); break; case MIC_MUTE_KEY: doMicSoundAction(); break; case BRIGHT_UP_KEY: case BRIGHT_DOWN_KEY: doBrightAction(type); break; case POWER_DOWN_KEY: doShutdownAction(); break; case POWER_OFF_KEY: doPowerOffAction(); break; case LOGOUT_KEY: doLogoutAction(); break; case EJECT_KEY: break; case HOME_KEY: doOpenHomeDirAction(); break; case SEARCH_KEY: doSearchAction(); break; case EMAIL_KEY: doUrlAction("mailto"); break; case SCREENSAVER_KEY: case SCREENSAVER_KEY_2: doScreensaverAction(); break; case SETTINGS_KEY: case SETTINGS_KEY_2: doSettingsAction(); break; case WINDOWSWITCH_KEY: case WINDOWSWITCH_KEY_2: doWindowSwitchAction(); break; case FILE_MANAGER_KEY: case FILE_MANAGER_KEY_2: doOpenFileManagerAction(); break; case HELP_KEY: doUrlAction("help"); break; case WWW_KEY: doUrlAction("http"); break; case MEDIA_KEY: doMediaAction(); break; case PLAY_KEY: doMultiMediaPlayerAction("Play"); break; case PAUSE_KEY: doMultiMediaPlayerAction("Pause"); break; case STOP_KEY: doMultiMediaPlayerAction("Stop"); break; case PREVIOUS_KEY: doMultiMediaPlayerAction("Previous"); break; case NEXT_KEY: doMultiMediaPlayerAction("Next"); break; case REWIND_KEY: doMultiMediaPlayerAction("Rewind"); break; case FORWARD_KEY: doMultiMediaPlayerAction("FastForward"); break; case REPEAT_KEY: doMultiMediaPlayerAction("Repeat"); break; case RANDOM_KEY: doMultiMediaPlayerAction("Shuffle"); break; case MAGNIFIER_KEY: doMagnifierAction(); break; case SCREENREADER_KEY: doScreensaverAction(); break; case ON_SCREEN_KEYBOARD_KEY: doOnScreenKeyboardAction(); break; case TERMINAL_KEY: case TERMINAL_KEY_2: doOpenTerminalAction(); break; case SCREENSHOT_KEY: doScreenshotAction(" full"); break; case AREA_SCREENSHOT_KEY: doScreenshotAction(" gui"); break; case WINDOW_SCREENSHOT_KEY: doScreenshotAction(" screen"); break; case SYSTEM_MONITOR_KEY: doOpenMonitor(); break; case CONNECTION_EDITOR_KEY: doOpenConnectionEditor(); break; case GLOBAL_SEARCH_KEY: doOpenUkuiSearchAction(); break; case KDS_KEY: case KDS_KEY2: doOpenKdsAction(); break; case WLAN_KEY: doWlanAction(); break; case WEBCAM_KEY: doWebcamAction(); break; case UKUI_SIDEBAR: doSidebarAction(); break; case UKUI_EYECARE_CENTER: doEyeCenterAction(); break; case RFKILL_KEY: doFlightModeAction(); break; case CALCULATOR_KEY: doOpenKylinCalculator(); break; case BLUETOOTH_KEY: doBluetoothAction(); break; default: break; } return false; } bool isValidShortcut (const QString& string) { if (string.isNull() || string.isEmpty()) return false; if (string == "disabled") return false; return true; } void MediaKeysManager::initKbd() { int i; bool needFlush = false; // gdk_x11_display_error_trap_push(gdk_display_get_default()); QObject::connect(mSettings, &QGSettings::changed, this, &MediaKeysManager::updateKbdCallback); connect(mSettings, SIGNAL(changed(QString)), this, SLOT(updateKbdCallback(QString))); for(i = 0; i < HANDLED_KEYS; ++i){ QString tmp,schmeasKey; Key* key; if(NULL != keys[i].settings_key){ schmeasKey = keys[i].settings_key; tmp = mSettings->get(schmeasKey).toString(); }else tmp = keys[i].hard_coded; if(!isValidShortcut(tmp)){ tmp.clear(); continue; } key = g_new0(Key,1); if(!egg_accelerator_parse_virtual(tmp.toLatin1().data(),&key->keysym,&key->keycodes, (EggVirtualModifierType*)&key->state)){ tmp.clear(); g_free(key); continue; } tmp.clear(); keys[i].key = key; needFlush = true; grab_key_unsafe(key,true, nullptr); } // if(needFlush) // gdk_display_flush(gdk_display_get_default()); // if(gdk_x11_display_error_trap_pop(gdk_display_get_default())) // qWarning("Grab failed for some keys,another application may already have access the them."); } void MediaKeysManager::updateKbdCallback(const QString &key) { int i; bool needFlush = true; if(key.isNull()) return; gdk_x11_display_error_trap_push (gdk_display_get_default()); /* Find the key that was modified */ for (i = 0; i < HANDLED_KEYS; i++) { if (0 == key.compare(keys[i].settings_key)) { QString tmp; Key *key; if (NULL != keys[i].key) { needFlush = true; grab_key_unsafe (keys[i].key, false, nullptr); } g_free (keys[i].key); keys[i].key = NULL; /* We can't have a change in a hard-coded key */ if(NULL != keys[i].settings_key){ qWarning("settings key value is NULL,exit!"); //return; } tmp = mSettings->get(keys[i].settings_key).toString(); if (false == isValidShortcut(tmp)) { tmp.clear(); break; } key = g_new0 (Key, 1); if (!egg_accelerator_parse_virtual (tmp.toLatin1().data(), &key->keysym, &key->keycodes, (EggVirtualModifierType*)&key->state)) { tmp.clear(); g_free (key); break; } needFlush = true; grab_key_unsafe (key, true, nullptr); keys[i].key = key; tmp.clear(); break; } } if (needFlush) gdk_display_flush (gdk_display_get_default()); if (gdk_x11_display_error_trap_pop (gdk_display_get_default())) qWarning("Grab failed for some keys, another application may already have access the them."); } void MediaKeysManager::doTouchpadAction(int state) { QGSettings *touchpadSettings; bool touchpadState; touchpadSettings = new QGSettings("org.ukui.peripherals-touchpad"); touchpadState = touchpadSettings->get("touchpad-enabled").toBool(); if(FALSE == touchpad_is_present()){ mDeviceWindow->setAction("touchpad-disabled"); return; } if (STATE_TOGGLE == state) { mDeviceWindow->setAction(!touchpadState ? "ukui-touchpad-on" : "ukui-touchpad-off"); touchpadSettings->set("touchpad-enabled",!touchpadState); } else if (STATE_ON == state) { mDeviceWindow->setAction("ukui-touchpad-on"); touchpadSettings->set("touchpad-enabled",STATE_ON); } else if (STATE_OFF == state) { mDeviceWindow->setAction("ukui-touchpad-off"); touchpadSettings->set("touchpad-enabled",STATE_OFF); } mDeviceWindow->dialogShow(); delete touchpadSettings; } void MediaKeysManager::doMicSoundAction() { bool mute; mpulseAudioManager = new pulseAudioManager(this); mute = !mpulseAudioManager->getMicMute(); mpulseAudioManager->setMicMute(mute); mDeviceWindow->setAction ( mute ? "ukui-microphone-off" : "ukui-microphone-on"); mDeviceWindow->dialogShow(); delete mpulseAudioManager; } void MediaKeysManager::doBrightAction(int type) { int brightValue; QGSettings* settings = new QGSettings(GPM_SETTINGS_SCHEMA); switch (type){ case BRIGHT_UP_KEY: brightValue = settings->get(GPM_SETTINGS_BRIGHTNESS_AC).toInt() + STEP_BRIGHTNESS; if(brightValue >= MAX_BRIGHTNESS){ brightValue = MAX_BRIGHTNESS; } break; case BRIGHT_DOWN_KEY: brightValue = settings->get(GPM_SETTINGS_BRIGHTNESS_AC).toInt() - STEP_BRIGHTNESS; if(brightValue <= STEP_BRIGHTNESS){ brightValue = STEP_BRIGHTNESS; } break; } settings->set(GPM_SETTINGS_BRIGHTNESS_AC,brightValue); mVolumeWindow->setBrightIcon("display-brightness-symbolic"); mVolumeWindow->setBrightValue(brightValue); mVolumeWindow->dialogBrightShow(); delete settings; } void MediaKeysManager::doSoundActionALSA(int keyType) { int last_volume; bool lastmuted; bool soundChanged = false; mpulseAudioManager = new pulseAudioManager(this); int volumeStep = mSettings->get("volume-step").toInt(); int volume = mpulseAudioManager->getVolume(); int muted = mpulseAudioManager->getMute(); USD_LOG(LOG_DEBUG,"getMute muted : %d",muted); int volumeCvStep = mpulseAudioManager->getStepVolume(); int volumeMin = mpulseAudioManager->getMinVolume(); int volumeMax = mpulseAudioManager->getMaxVolume(); volumeStep*=volumeCvStep; last_volume = volume; lastmuted = muted; switch(keyType){ case MUTE_KEY: muted = !muted; break; case VOLUME_DOWN_KEY: if(volume <= (volumeMin + volumeStep)){ volume = volumeMin; muted = true; }else{ volume -= volumeStep; muted = false; } if(volume <= volumeMin){ volume = volumeMin; muted = true; } break; case VOLUME_UP_KEY: if(muted){ muted = false; } volume += volumeStep; if (volume >= volumeMax) { volume = volumeMax; } break; } if (last_volume != volume) { soundChanged = true; } if (volumeMin == volume) { muted = true; } mpulseAudioManager->setVolume(volume); mVolumeWindow->setVolumeRange(volumeMin, volumeMax); mpulseAudioManager->setMute(muted); updateDialogForVolume(volume,muted,soundChanged); delete mpulseAudioManager; } void MediaKeysManager::doSoundAction(int keyType) { #if 0 bool muted,mutedLast,soundChanged; //是否静音,上一次值记录,是否改变 int volume,volumeMin,volumeMax; //当前音量值,最小音量值,最大音量值 uint volumeStep,volumeLast; //音量步长,上一次音量值 if(NULL == mControl) return; volumeMin = mate_mixer_stream_control_get_min_volume(mControl); volumeMax = mate_mixer_stream_control_get_normal_volume(mControl); volumeStep = mSettings->get("volume-step").toInt(); if(volumeStep <= 0 || volumeStep > 100) volumeStep = VOLUMESTEP; volumeStep = (volumeStep * volumeMax) / 100; volume = volumeLast = mate_mixer_stream_control_get_volume(mControl); muted = mutedLast = mate_mixer_stream_control_get_mute(mControl); USD_LOG(LOG_DEBUG,"volumeMin volume%d",volume); switch(keyType){ case MUTE_KEY: // if(volume == volumeMin) //HW需求:音量为0时也支持F4快捷键静音和解除静音 // muted = true; // else muted = !muted; break; case VOLUME_DOWN_KEY: if(volume <= (volumeMin + volumeStep)){ volume = volumeMin; muted = true; USD_LOG(LOG_DEBUG,"volumeMin volume%d",volume); }else{ volume -= volumeStep; USD_LOG(LOG_DEBUG,"volumeMin volume%d",volume); muted = false; } if(volume < 300){ volume = volumeMin; muted = true; } USD_LOG(LOG_DEBUG,"volumeMin volume%d",volume); break; case VOLUME_UP_KEY: if(muted){ muted = false; if(volume <= (volumeMin + volumeStep)) volume = volumeMin + volumeStep; }else volume = midValue(volume + volumeStep, volumeMin, volumeMax); break; } if(muted != mutedLast){ if(mate_mixer_stream_control_set_mute(mControl, muted)) soundChanged = true; else muted = mutedLast; } if(mate_mixer_stream_control_get_volume(mControl) != volume){ if(mate_mixer_stream_control_set_volume(mControl,volume)) { soundChanged = true; USD_LOG(LOG_DEBUG,"setok/// volume:%d",volume); } else { volume = volumeLast; USD_LOG(LOG_DEBUG,"set fail."); } } USD_LOG(LOG_DEBUG,"volumeMin volume%d %d~%d get :%d",volume,volumeMin,volumeMax,mate_mixer_stream_control_get_volume(mControl) ); mVolumeWindow->setVolumeRange(volumeMin, volumeMax); updateDialogForVolume(volume,muted,soundChanged); #endif // usleep(1500); } void MediaKeysManager::updateDialogForVolume(uint volume,bool muted,bool soundChanged) { int v = volume; USD_LOG(LOG_DEBUG, "volume = %d, muted is %d", v, muted); mVolumeWindow->setVolumeMuted(muted); mVolumeWindow->setVolumeLevel(volume); mVolumeWindow->dialogVolumeShow(); } void processAbstractPath(QString& process) { QString tmpPath; QFileInfo fileInfo; tmpPath = "/usr/bin/" + process; fileInfo.setFile(tmpPath); if(fileInfo.exists()){ process = tmpPath; return; } tmpPath.clear(); tmpPath = "/usr/sbin/" + process; fileInfo.setFile(tmpPath); if(fileInfo.exists()){ process = tmpPath; return; } process = ""; } bool binaryFileExists(const QString& binary) { QString tmpPath; QFileInfo fileInfo; tmpPath = "/usr/bin/" + binary; fileInfo.setFile(tmpPath); if(fileInfo.exists()) return true; tmpPath.clear(); tmpPath = "/usr/sbin/" + binary; fileInfo.setFile(tmpPath); if(fileInfo.exists()) return true; return false; } void MediaKeysManager::executeCommand(const QString& command,const QString& paramter){ QString cmd = command + paramter; char **argv; int argc; bool retval; //processAbstractPath(cmd); if(!cmd.isEmpty()){ if (g_shell_parse_argv (cmd.toLatin1().data(), &argc, &argv, NULL)) { retval = g_spawn_async (g_get_home_dir (), argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL); g_strfreev (argv); } //mExecCmd->execute(cmd + paramter);//mExecCmd->start(cmd + paramter); } else qWarning("%s cannot found at system path!",command.toLatin1().data()); } void MediaKeysManager::doShutdownAction() { executeCommand("ukui-session-tools"," --shutdown"); } void MediaKeysManager::doLogoutAction() { executeCommand("ukui-session-tools",""); } void MediaKeysManager::doPowerOffAction() { if (true == UsdBaseClass::isTablet()) { doAction(SCREENSAVER_KEY_2); } else { static QTime startTime = QTime::currentTime(); static int elapsed = -1; elapsed = startTime.msecsTo(QTime::currentTime()); if(elapsed > 0 && elapsed <= TIME_LIMIT){ return; } startTime = QTime::currentTime(); power_state = powerSettings->getEnum(POWER_BUTTON_KEY); switch (power_state) { case POWER_HIBERNATE: executeCommand("ukui-session-tools"," --hibernate"); break; case POWER_INTER_ACTIVE: { if(UsdBaseClass::isPowerOff()) { executeCommand("ukui-session-tools"," --shutdown"); } else { bool session = false; if(sessionSettings->keys().contains(SESSION_WIN_KEY)) { session = sessionSettings->get(SESSION_WIN_KEY).toBool(); if(session) { return; } } executeCommand("ukui-session-tools",""); } break; } case POWER_SHUTDOWN: executeCommand("ukui-session-tools"," --shutdown"); break; case POWER_SUSPEND: executeCommand("ukui-session-tools"," --suspend"); break; } } } void MediaKeysManager::doOpenHomeDirAction() { QString homePath; homePath = QDir::homePath(); executeCommand("peony"," --show-folders " + homePath); } void MediaKeysManager::doSearchAction() { QString tool1,tool2,tool3; tool1 = "beagle-search"; tool2 = "tracker-search-tool"; tool3 = "mate-search-tool"; if(binaryFileExists(tool1)){ executeCommand(tool1,""); }else if(binaryFileExists(tool2)){ executeCommand(tool2,""); }else executeCommand(tool3,""); } void MediaKeysManager::doScreensaverAction() { QString tool1,tool2; tool1 = "ukui-screensaver-command"; tool2 = "xscreensaver-command"; if(binaryFileExists(tool1)) executeCommand(tool1," --lock"); else executeCommand(tool2," --lock"); } void MediaKeysManager::doSettingsAction() { executeCommand("ukui-control-center",""); } void MediaKeysManager::doWindowSwitchAction() { executeCommand("ukui-window-switch"," --show-workspace"); } void MediaKeysManager::doOpenFileManagerAction() { executeCommand("peony",""); } void MediaKeysManager::doMediaAction() { } void MediaKeysManager::doOpenCalcAction() { //其他平台计算器 QString tool1,tool2,tool3; tool1 = "galculator"; tool2 = "mate-calc"; tool3 = "gnome-calculator"; if(binaryFileExists(tool1)){ executeCommand(tool1,""); }else if(binaryFileExists(tool2)){ executeCommand(tool2,""); }else executeCommand(tool3,""); } void MediaKeysManager::doToggleAccessibilityKey(const QString key) { QGSettings* toggleSettings; bool state; toggleSettings = new QGSettings("org.gnome.desktop.a11y.applications"); state = toggleSettings->get(key).toBool(); toggleSettings->set(key,!state); delete toggleSettings; } void MediaKeysManager::doMagnifierAction() { doToggleAccessibilityKey("screen-magnifier-enabled"); } void MediaKeysManager::doScreenreaderAction() { doToggleAccessibilityKey("screen-reader-enabled"); } void MediaKeysManager::doOnScreenKeyboardAction() { doToggleAccessibilityKey("screen-keyboard-enabled"); } void MediaKeysManager::doOpenTerminalAction() { if(UsdBaseClass::isTablet()) { executeCommand("mate-terminal",""); } else { executeCommand("x-terminal-emulator",""); } } void MediaKeysManager::doScreenshotAction(const QString pramater) { executeCommand("kylin-screenshot",pramater); } void MediaKeysManager::doSidebarAction() { executeCommand("ukui-sidebar"," -show"); } void MediaKeysManager::doOpenMonitor() { executeCommand("ukui-system-monitor",""); } void MediaKeysManager::doOpenConnectionEditor() { executeCommand("kylin-nm --sw",""); } void MediaKeysManager::doOpenUkuiSearchAction() { QDBusMessage message = QDBusMessage::createMethodCall("com.ukui.search.service", "/", "org.ukui.search.service", "showWindow"); QDBusMessage response = QDBusConnection::sessionBus().call(message); if (response.type() != QDBusMessage::ReplyMessage){ USD_LOG(LOG_DEBUG, "priScreenChanged called failed"); executeCommand("ukui-search"," -s"); } } void MediaKeysManager::doOpenKdsAction() { executeCommand("ukydisplayswitch",""); } void MediaKeysManager::doWlanAction() { int wlanState = RfkillSwitch::instance()->getCurrentWlanMode(); if(wlanState == -1) { return; } if(wlanState) { mDeviceWindow->setAction("ukui-wifi-on"); RfkillSwitch::instance()->turnWifiOn(); } else { mDeviceWindow->setAction("ukui-wifi-off"); } mDeviceWindow->dialogShow(); } void MediaKeysManager::doFlightModeAction() { int flightState = RfkillSwitch::instance()->getCurrentFlightMode(); if(flightState == -1) { USD_LOG(LOG_ERR,"get flight mode error"); return; } mDeviceWindow->setAction(flightState?"ukui-airplane-on":"ukui-airplane-off"); mDeviceWindow->dialogShow(); } void MediaKeysManager::doBluetoothAction() { int bluetoothState = RfkillSwitch::instance()->getCurrentBluetoothMode(); if(bluetoothState == -1) { USD_LOG(LOG_ERR,"get bluetooth mode error"); return; } mDeviceWindow->setAction(bluetoothState?"ukui-bluetooth-on":"ukui-bluetooth-off"); mDeviceWindow->dialogShow(); } void MediaKeysManager::doOpenKylinCalculator() { executeCommand("kylin-calculator",""); } void MediaKeysManager::doEyeCenterAction() { executeCommand("eye-protection-center",""); } void MediaKeysManager::doUrlAction(const QString scheme) { GError *error = NULL; GAppInfo *appInfo; appInfo = g_app_info_get_default_for_uri_scheme (scheme.toLatin1().data()); if (appInfo != NULL) { if (!g_app_info_launch (appInfo, NULL, NULL, &error)) { qWarning("Could not launch '%s': %s", g_app_info_get_commandline (appInfo), error->message); g_object_unref (appInfo); g_error_free (error); } }else qWarning("Could not find default application for '%s' scheme", scheme.toLatin1().data()); } void MediaKeysManager::doWebcamAction() { QDBusInterface *iface = new QDBusInterface("org.ukui.authority", \ "/", \ "org.ukui.authority.interface", \ QDBusConnection::systemBus()); QDBusReply reply = iface->call("getCameraBusinfo"); if (reply.isValid()){ QString businfo = reply.value(); QDBusReply reply2 = iface->call("toggleCameraDevice", businfo); if (reply2.isValid()){ QString result = reply2.value(); if (result == QString("binded")){ mDeviceWindow->setAction("ukui-camera-on"); iface->call("setCameraKeyboardLight", false); } else if (result == QString("unbinded")){ mDeviceWindow->setAction("ukui-camera-off"); iface->call("setCameraKeyboardLight", true); } else { USD_LOG(LOG_DEBUG,"toggleCameraDevice result %s", result.toLatin1().data()); } mDeviceWindow->dialogShow(); } else { USD_LOG(LOG_ERR,"Toggle Camera device Failed!"); } } else { USD_LOG(LOG_ERR,"Get Camera Businfo Failed!"); } delete iface; } /** * @brief MediaKeysManager::doMultiMediaPlayerAction * for detailed purposes,refer to the definition of MediaPlayerKeyPressed() * 有关该函数的详细用途,请参考MediaPlayerKeyPressed()的声明 * @param operation * @operation can take the following values: Play、Pause、Stop... */ void MediaKeysManager::doMultiMediaPlayerAction(const QString operation) { if(!mediaPlayers.isEmpty()) Q_EMIT MediaPlayerKeyPressed(mediaPlayers.first()->application,operation); } /** * @brief MediaKeysManager::GrabMediaPlayerKeys * this is a dbus method,it will be called follow org.ukui.SettingsDaemon.MediaKeys in mpris plugin * 这是一个dbus method,它将会跟随org.ukui.SettingsDaemon.MediaKeys这个dbus在mpris插件中调用 * @param app * app=="UsdMpris" is true according to the open source. * 按照开源的写法,这个变量的值为"UsdMpris" * @param time */ void MediaKeysManager::GrabMediaPlayerKeys(QString app) { QTime currentTime; uint curTime = 0; //current time(s) 当前时间(秒) bool containApp; currentTime = QTime::currentTime(); curTime = 60*currentTime.minute() + currentTime.second() + currentTime.msec()/1000; //whether @app is inclued in @mediaPlayers @mediaPlayers中是否包含@app containApp = findMediaPlayerByApplication(app); if(true == containApp) removeMediaPlayerByApplication(app,curTime); MediaPlayer* newPlayer = new MediaPlayer; newPlayer->application = app; newPlayer->time = curTime; mediaPlayers.insert(findMediaPlayerByTime(newPlayer),newPlayer); } void MediaKeysManager::mediaKeyForOtherApp(int action,QString appName) { Q_UNUSED(action); Q_UNUSED(appName); // USD_LOG(LOG_DEBUG,"action:%d appName:%s",action, appName.toLatin1().data()); // doAction(action); } /** * @brief MediaKeysManager::ReleaseMediaPlayerKeys * @param app */ void MediaKeysManager::ReleaseMediaPlayerKeys(QString app) { bool containApp; QList::iterator item,end; MediaPlayer* tmp; item = mediaPlayers.begin(); end = mediaPlayers.end(); containApp = findMediaPlayerByApplication(app); if(true == containApp){ for(; item != end; ++item){ tmp = *item; //find @player successfully 在链表中成功找到该元素 if(tmp->application == app){ tmp->application.clear(); delete tmp; mediaPlayers.removeOne(tmp); break; } } } } /** * @brief MediaKeysManager::findMediaPlayerByApplication * @param app app=="UsdMpris" is true at general 一般情况下app=="UsdMpris" * @param player if@app can be founded in @mediaPlayers, @player recored it's position * 如果@app 存在于@mediaPlayers内,则@player 记录它的位置 * @return return true if @app can be founded in @mediaPlayers */ bool MediaKeysManager::findMediaPlayerByApplication(const QString& app) { QList::iterator item,end; MediaPlayer* tmp; item = mediaPlayers.begin(); end = mediaPlayers.end(); for(; item != end; ++item){ tmp = *item; //find @player successfully 在链表中成功找到该元素 if(tmp->application == app){ return true; } } //can not find @player at QList 查找失败 return false; } /** * @brief MediaKeysManager::findMediaPlayerByTime determine insert location at the @mediaPlayers * 确定在@mediaPlayers中的插入位置 * @param player * @return return index. 返回下标 */ uint MediaKeysManager::findMediaPlayerByTime(MediaPlayer* player) { if(mediaPlayers.isEmpty()) return 0; return player->time < mediaPlayers.first()->time; } void MediaKeysManager::removeMediaPlayerByApplication(const QString& app,uint currentTime) { QList::iterator item,end; MediaPlayer* tmp; item = mediaPlayers.begin(); end = mediaPlayers.end(); for(; item != end; ++item){ tmp = *item; //find @player successfully 在链表中成功找到该元素 if(tmp->application == app && tmp->time < currentTime){ tmp->application.clear(); delete tmp; mediaPlayers.removeOne(tmp); break; } } } int MediaKeysManager::getFlightState() { return RfkillSwitch::instance()->getCurrentFlightMode(); } void MediaKeysManager::setFlightState(int value) { RfkillSwitch::instance()->toggleFlightMode(value); } ukui-settings-daemon/plugins/media-keys/mediakey-manager.h0000644000175000017500000001712514205117202022634 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MEDIAKEYSMANAGER_H #define MEDIAKEYSMANAGER_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include "volumewindow.h" #include "devicewindow.h" #include "acme.h" #include "pulseaudiomanager.h" #include "usd_base_class.h" #include "usd_global_define.h" #include "xEventMonitor.h" #ifdef signals #undef signals #endif extern "C"{ #include #include #include #include #include //#include #include #include "ukui-input-helper.h" } /** this value generate from mpris serviceRegisteredSlot(const QString&) * 这个值一般由mpris插件的serviceRegisteredSlot(const QString&)传递 */ typedef struct{ QString application; uint time; }MediaPlayer; class MediaKeysManager:public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface","org.ukui.SettingsDaemon.MediaKeys") public: ~MediaKeysManager(); static MediaKeysManager* mediaKeysNew(); bool mediaKeysStart(GError*); void mediaKeysStop(); private: MediaKeysManager(QObject* parent = nullptr); void initScreens(); void initKbd(); void initXeventMonitor(); bool getScreenLockState(); void sjhKeyTest(); // static void onStreamControlVolumeNotify (MateMixerStreamControl *control,GParamSpec *pspec,MediaKeysManager *mManager); // static void onStreamControlMuteNotify (MateMixerStreamControl *control,GParamSpec *pspec,MediaKeysManager *mManager); static GdkFilterReturn acmeFilterEvents(GdkXEvent*,GdkEvent*,void*); // static void onContextStateNotify(MateMixerContext*,GParamSpec*,MediaKeysManager*); // static void onContextDefaultOutputNotify(MateMixerContext*,GParamSpec*,MediaKeysManager*); // static void onContextDefaultInputNotify(MateMixerContext*,GParamSpec*,MediaKeysManager*); // static void onContextStreamRemoved(MateMixerContext*,char*,MediaKeysManager*); static void updateDefaultOutput(MediaKeysManager *); static void updateDefaultInput(MediaKeysManager *); GdkScreen *acmeGetScreenFromEvent (XAnyEvent*); bool doAction(int); void initShortcuts(); /******************Functional class function(功能类函数)****************/ void doTouchpadAction(int); void doSoundAction(int); void doSoundActionALSA(int); void doMicSoundAction(); void doBrightAction(int); void updateDialogForVolume(uint,bool,bool); void executeCommand(const QString&,const QString&); void doShutdownAction(); void doLogoutAction(); void doPowerOffAction(); void doOpenHomeDirAction(); void doSearchAction(); void doScreensaverAction(); void doSettingsAction(); void doOpenFileManagerAction(); void doMediaAction(); void doOpenCalcAction(); void doToggleAccessibilityKey(const QString key); void doMagnifierAction(); void doScreenreaderAction(); void doOnScreenKeyboardAction(); void doOpenTerminalAction(); void doOpenMonitor(); void doOpenConnectionEditor(); void doScreenshotAction(const QString); void doUrlAction(const QString); void doMultiMediaPlayerAction(const QString); void doSidebarAction(); void doWindowSwitchAction(); void doOpenUkuiSearchAction(); void doOpenKdsAction(); void doWlanAction(); void doWebcamAction(); void doEyeCenterAction(); void doFlightModeAction(); void doOpenKylinCalculator(); void doBluetoothAction(); /******************Function for DBus(DBus相关处理函数)******************************/ bool findMediaPlayerByApplication(const QString&); uint findMediaPlayerByTime(MediaPlayer*); void removeMediaPlayerByApplication(const QString&,uint); int8_t getCurrentMode(); public Q_SLOTS: /** two dbus method, will be called in mpris plugin(mprismanager.cpp MprisManagerStart()) * 两个dbus 方法,将会在mpris插件中被调用(mprismanager.cpp MprisManagerStart()) */ void GrabMediaPlayerKeys(QString application); void ReleaseMediaPlayerKeys(QString application); int getFlightState(); void setFlightState(int value); void mediaKeyForOtherApp(int action,QString appName); private Q_SLOTS: //void timeoutCallback(); void updateKbdCallback(const QString&); void XkbEventsPress(const QString &keyStr); void XkbEventsRelease(const QString &keyStr); void MMhandleRecordEvent(xEvent* data); void MMhandleRecordEventRelease(xEvent* data); Q_SIGNALS: /** media-keys plugin will emit this signal by org.ukui.SettingsDaemon.MediaKeys * when listen some key Pressed(such as XF86AudioPlay 、XF86AudioPause 、XF86AudioForward) * at the same time,mpris plugin will connect this signal * * 当监听到某些按键(XF86AudioRewind、XF86AudioRepeat、XF86AudioRandomPlay)时, * media-keys插件将会通过org.ukui.SettingsDaemon.MediaKeys这个dbus发送这个signal * 同时,mpris插件会connect这个signal */ void MediaPlayerKeyPressed(QString application,QString operation); private: pulseAudioManager *mpulseAudioManager; static MediaKeysManager* mManager; QDBusMessage mDbusScreensaveMessage; QTimer *mTimer; QGSettings *mSettings; QGSettings *pointSettings; QGSettings *sessionSettings; QGSettings *shotSettings; QGSettings *powerSettings; QProcess *mExecCmd; GdkScreen *mCurrentScreen; //current GdkScreen xEventMonitor *mXEventMonitor = nullptr; // MateMixerStream *mStream; // MateMixerContext *mContext; // MateMixerStreamControl *mControl; // MateMixerStream *mInputStream; // MateMixerStreamControl *mInputControl; VolumeWindow *mVolumeWindow; //volume size window 声音大小窗口 DeviceWindow *mDeviceWindow; //other widow,such as touchapad、volume 例如触摸板、磁盘卷设备 QList mediaPlayers; //all opened media player(vlc,audacious) 已经打开的媒体播放器列表(vlc,audacious) int power_state = 4; bool m_ctrlFlag = false; xEventHandleHadRelase(MUTE_KEY); xEventHandleHadRelase(AREA_SCREENSHOT_KEY); xEventHandleHadRelase(WINDOW_SCREENSHOT_KEY); xEventHandleHadRelase(SCREENSHOT_KEY); xEventHandleHadRelase(WLAN_KEY); xEventHandleHadRelase(MIC_MUTE_KEY); xEventHandleHadRelase(RFKILL_KEY); xEventHandleHadRelase(TOUCHPAD_KEY); xEventHandleHadRelase(TOUCHPAD_ON_KEY); xEventHandleHadRelase(TOUCHPAD_OFF_KEY); xEventHandleHadRelase(SCREENSAVER_KEY); xEventHandleHadRelase(WINDOWSWITCH_KEY); xEventHandleHadRelase(CALCULATOR_KEY); xEventHandleHadRelase(BLUETOOTH_KEY); }; #endif // MEDIAKEYSMANAGER_H ukui-settings-daemon/plugins/media-keys/xEventMonitor.h0000644000175000017500000000422614205117202022253 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XEVENTMONITOR_H #define XEVENTMONITOR_H #include #include #include #include #include #include #include #include // Virtual button codes that are not defined by X11. #define Button1 1 #define Button2 2 #define Button3 3 #define WheelUp 4 #define WheelDown 5 #define WheelLeft 6 #define WheelRight 7 #define XButton1 8 #define XButton2 9 extern "C"{ #include "clib-syslog.h" #include "usd_global_define.h" } class xEventMonitor : public QThread { Q_OBJECT public: xEventMonitor(QObject *parent = 0); bool getWinPressStatus(); bool getCtrlPressStatus(); bool getAltPressStatus(); bool getShiftPressStatus(); Q_SIGNALS: void buttonPress(int x, int y); void buttonDrag(int x, int y); void buttonRelease(int x, int y); void keyPress(xEvent *code); void keyRelease(xEvent *code); protected: bool filterWheelEvent(int detail); static void callback(XPointer trash, XRecordInterceptData* data); void handleRecordEvent(XRecordInterceptData *); void run(); private: bool winPress=false; bool ctrlPress_l=false; bool altPress_l=false; bool shiftPress_l = false; bool ctrlPress_r=false; bool altPress_r=false; bool shiftPress_r = false; bool isPress; }; #endif // XEVENTMONITOR_H ukui-settings-daemon/plugins/media-keys/pulseaudiomanager.h0000644000175000017500000000537014205117202023140 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef PLUSEAUDIOMANAGER_H #define PLUSEAUDIOMANAGER_H #include #include #include #include extern "C" { #include "clib-syslog.h" } class pulseAudioManager : public QObject { Q_OBJECT public: pulseAudioManager(QObject *parent = nullptr); ~pulseAudioManager(); void initPulseAudio(); void setMicMute(bool MuteState); void setMute(bool MuteState); void upVolume(int PerVolume); void lowVolume(int PerVolume); void setVolume(int Volume); bool getMute(); bool getMicMute(); int getVolume(); int getMaxVolume(); int getStepVolume(); int getMinVolume(); bool getMuteAndVolume(int *volume, int *mute); void paCvOperationHandle(pa_operation *paOp); bool getSourceMute(); void setSourceMute(bool Mute); // pulseAudioManager* getIntance(); static void PaContextStateCallback(pa_context* pa_ctx, void* userdata); static void getSinkInfoCallback(pa_context *ctx, const pa_sink_info *si, int isLast, void *userdata); static void getServerInfoCallback(pa_context *ctx, const pa_server_info *si, void *userdata); static void getSinkVolumeAndSetCallback(pa_context *ctx, const pa_sink_info *si, int isLast, void *userdata); static void contextDrainComplete(pa_context *ctx, void *userdata); static void completeAction(); static void paActionDoneCallback(pa_context *ctx, int success, void *userdata); static void getSourceInfoCallback(pa_context *ctx, const pa_source_info *si, int isLast, void *userdata); private: enum class PulseAudioContextState { PULSE_CONTEXT_INITIALIZING, PULSE_CONTEXT_READY, PULSE_CONTEXT_FINISHED }; const char *description = "audio recorder"; pa_mainloop* p_PaMl = nullptr; pa_operation* p_PaOp = nullptr; pa_context* p_PaCtx = nullptr; pa_mainloop_api* p_PaMlApi = nullptr; QString mSinkName; pulseAudioManager *mInstance = nullptr; }; #endif // PLUSEAUDIOMANAGER_H ukui-settings-daemon/plugins/media-keys/volumewindow.ui0000644000175000017500000000061514205117202022355 0ustar fengfeng VolumeWindow 0 0 800 600 VolumeWindow ukui-settings-daemon/plugins/media-keys/devicewindow.cpp0000644000175000017500000002127414205117214022461 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "devicewindow.h" #include "ui_devicewindow.h" #include #include #include #include #include #include "clib-syslog.h" #include "usd_base_class.h" #define DBUS_NAME "org.ukui.SettingsDaemon" #define DBUS_PATH "/org/ukui/SettingsDaemon/wayland" #define DBUS_INTERFACE "org.ukui.SettingsDaemon.wayland" #define QT_THEME_SCHEMA "org.ukui.style" #define PANEL_SCHEMA "org.ukui.panel.settings" #define PANEL_SIZE_KEY "panelsize" #define DEFAULT_LOCALE_ICON_NAME ":/ukui_res/ukui/" #define INTEL_LOCALE_ICON_NAME ":/ukui_res/ukui_intel/" const QString allIconName[] = { "gpm-brightness-lcd", "touchpad-disabled-symbolic", "touchpad-enabled-symbolic", "media-eject", nullptr }; DeviceWindow::DeviceWindow(QWidget *parent) : QWidget(parent), ui(new Ui::DeviceWindow) { ui->setupUi(this); mDbusXrandInter = new QDBusInterface(DBUS_NAME, DBUS_PATH, DBUS_INTERFACE, QDBusConnection::sessionBus(), this); if (!mDbusXrandInter->isValid()) { USD_LOG(LOG_DEBUG, "stderr:%s\n",qPrintable(QDBusConnection::sessionBus().lastError().message())); } //监听dbus变化 更改主屏幕时,会进行信号发送 connect(mDbusXrandInter, SIGNAL(screenPrimaryChanged(int,int,int,int)), this, SLOT(priScreenChanged(int,int,int,int))); m_styleSettings = new QGSettings(QT_THEME_SCHEMA); connect(m_styleSettings,SIGNAL(changed(const QString&)), this,SLOT(onStyleChanged(const QString&))); mScale = getScreenGeometry("scale"); if(UsdBaseClass::isTablet()) { m_LocalIconPath = INTEL_LOCALE_ICON_NAME; } else { m_LocalIconPath = DEFAULT_LOCALE_ICON_NAME; } } DeviceWindow::~DeviceWindow() { delete ui; delete mTimer; mTimer = nullptr; } /* 主屏幕变化监听函数 */ void DeviceWindow::priScreenChanged(int x, int y, int Width, int Height) { const QByteArray id(PANEL_SCHEMA); int pSize = 0; if (QGSettings::isSchemaInstalled(id)){ QGSettings * settings = new QGSettings(id); pSize = settings->get(PANEL_SIZE_KEY).toInt(); delete settings; } int ax,ay; ax = x+Width - this->width() - 200; ay = y+Height - this->height() - pSize-4; move(ax,ay); USD_LOG(LOG_DEBUG,"move it at %d,%d",ax,ay); } void DeviceWindow::geometryChangedHandle() { int x=QApplication::primaryScreen()->geometry().x(); int y=QApplication::primaryScreen()->geometry().y(); int width = QApplication::primaryScreen()->size().width(); int height = QApplication::primaryScreen()->size().height(); USD_LOG(LOG_DEBUG,"getchangehandle....%dx%d at(%d,%d)",width,height,x,y); priScreenChanged(x,y,width,height); } int DeviceWindow::getScreenGeometry(QString methodName) { int res = 0; QDBusMessage message = QDBusMessage::createMethodCall(DBUS_NAME, DBUS_PATH, DBUS_INTERFACE, methodName); QDBusMessage response = QDBusConnection::sessionBus().call(message); if (response.type() == QDBusMessage::ReplyMessage) { if(response.arguments().isEmpty() == false) { int value = response.arguments().takeFirst().toInt(); res = value; } } else { USD_LOG(LOG_DEBUG, "%s called failed", methodName.toLatin1().data()); } return res; } void DeviceWindow::initWindowInfo() { mTimer = new QTimer(); connect(mTimer,SIGNAL(timeout()),this,SLOT(timeoutHandle())); m_btnStatus = new QLabel(this); m_btnStatus->setFixedSize(QSize(48,48)); connect(QApplication::primaryScreen(), &QScreen::geometryChanged, this, &DeviceWindow::geometryChangedHandle); connect(static_cast(QCoreApplication::instance()), &QApplication::primaryScreenChanged, this, &DeviceWindow::geometryChangedHandle); setFixedSize(72,72); setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint | Qt::Popup); setAttribute(Qt::WA_TranslucentBackground, true); setAutoFillBackground(true); geometryChangedHandle(); } void DeviceWindow::setAction(const QString icon) { mIconName.clear(); if("media-eject" == icon) mIconName = allIconName[3]; else if("touchpad-enabled" == icon) mIconName = allIconName[2]; else if("touchpad-disabled" == icon) mIconName = allIconName[1]; else mIconName = icon; } void DeviceWindow::dialogShow() { geometryChangedHandle(); repaintWidget(); show(); mTimer->start(2000); } void DeviceWindow::timeoutHandle() { hide(); mTimer->stop(); } QPixmap DeviceWindow::drawLightColoredPixmap(const QPixmap &source, const QString &style) { int value = 255; if(style == "ukui-light") { value = 0; } QColor gray(255,255,255); QColor standard (0,0,0); QImage img = source.toImage(); for (int x = 0; x < img.width(); x++) { for (int y = 0; y < img.height(); y++) { auto color = img.pixelColor(x, y); if (color.alpha() > 0) { if (qAbs(color.red()-gray.red())<20 && qAbs(color.green()-gray.green())<20 && qAbs(color.blue()-gray.blue())<20) { color.setRed(value); color.setGreen(value); color.setBlue(value); img.setPixelColor(x, y, color); } else { color.setRed(value); color.setGreen(value); color.setBlue(value); img.setPixelColor(x, y, color); } } } } return QPixmap::fromImage(img); } void DeviceWindow::repaintWidget() { if(m_styleSettings->get("style-name").toString() == "ukui-light"){ setPalette(QPalette(QColor("#F5F5F5")));//设置窗口背景 } else{ setPalette(QPalette(QColor("#232426")));//设置窗口背景色 } QString m_LocalIconName; m_LocalIconName = m_LocalIconPath + mIconName + QString(".svg"); QPixmap m_pixmap = QIcon::fromTheme(mIconName,QIcon(m_LocalIconName)).pixmap(QSize(48,48)); m_btnStatus->setPixmap(drawLightColoredPixmap(m_pixmap,m_styleSettings->get("style-name").toString())); } void DeviceWindow::onStyleChanged(const QString&) { if(!this->isHidden()) { hide(); repaintWidget(); show(); } } void DeviceWindow::resizeEvent(QResizeEvent* event) { m_btnStatus->move((width() - m_btnStatus->width())/2,(height() - m_btnStatus->height())/2); QWidget::resizeEvent(event); } void DeviceWindow::paintEvent(QPaintEvent *event) { QRect rect = this->rect(); QPainterPath path; QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); // 反锯齿; painter.setPen(Qt::transparent); qreal radius=12; path.moveTo(rect.topRight() - QPointF(radius, 0)); path.lineTo(rect.topLeft() + QPointF(radius, 0)); path.quadTo(rect.topLeft(), rect.topLeft() + QPointF(0, radius)); path.lineTo(rect.bottomLeft() + QPointF(0, -radius)); path.quadTo(rect.bottomLeft(), rect.bottomLeft() + QPointF(radius, 0)); path.lineTo(rect.bottomRight() - QPointF(radius, 0)); path.quadTo(rect.bottomRight(), rect.bottomRight() + QPointF(0, -radius)); path.lineTo(rect.topRight() + QPointF(0, radius)); path.quadTo(rect.topRight(), rect.topRight() + QPointF(-radius, -0)); painter.setBrush(this->palette().base()); painter.setPen(Qt::transparent); painter.setOpacity(0.75); painter.drawPath(path); KWindowEffects::enableBlurBehind(this->winId(), true, QRegion(path.toFillPolygon().toPolygon())); QWidget::paintEvent(event); } ukui-settings-daemon/plugins/media-keys/mediakey-plugin.h0000644000175000017500000000253714205117202022521 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MEDIAKEYPLUGIN_H #define MEDIAKEYPLUGIN_H #include "plugin-interface.h" #include #include "mediakey-manager.h" class MediakeyPlugin : public PluginInterface { public: ~MediakeyPlugin(); static PluginInterface* getInstance(); virtual void activate () override; virtual void deactivate () override; private: MediakeyPlugin(); MediakeyPlugin(MediakeyPlugin&)=delete; private: MediaKeysManager* mManager; static PluginInterface* mInstance; }; extern "C" Q_DECL_EXPORT PluginInterface* createSettingsPlugin(); #endif // MEDIAKEYPLUGIN_H ukui-settings-daemon/plugins/media-keys/devicewindow.h0000644000175000017500000000414114205117202022115 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DEVICEWINDOW_H #define DEVICEWINDOW_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Ui { class DeviceWindow; } class DeviceWindow : public QWidget { Q_OBJECT public: explicit DeviceWindow(QWidget *parent = nullptr); ~DeviceWindow(); void initWindowInfo(); void setAction(const QString); void dialogShow(); int getScreenGeometry (QString methodName); private: QPixmap drawLightColoredPixmap(const QPixmap &source, const QString &style); private Q_SLOTS: void timeoutHandle(); void priScreenChanged(int x, int y, int width, int height); void geometryChangedHandle(); void repaintWidget(); void onStyleChanged(const QString& ); protected: void paintEvent(QPaintEvent *event); void resizeEvent(QResizeEvent* event); private: Ui::DeviceWindow *ui; double mScale = 1; QString mIconName; QString m_LocalIconPath; QLabel *m_btnStatus; QTimer *mTimer; QDBusInterface *mDbusXrandInter; QGSettings *m_styleSettings; }; #endif // DEVICEWINDOW_H ukui-settings-daemon/plugins/media-keys/pulseaudiomanager.cpp0000644000175000017500000002251414205117202023472 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "pulseaudiomanager.h" #include pa_cvolume g_GetPaCV; pa_cvolume g_SetPaCV; pa_channel_map g_sinkMap; int g_mute; int g_volume; float g_balance = 0.0f;//声道平衡,设置之前先计算出先前的声道平衡值,设置时,带入计算即可。。 char g_sinkName[128] = ""; char g_sourceName[128] = ""; bool g_sourceMute = false; pulseAudioManager::pulseAudioManager(QObject *parent) :QObject(parent) { initPulseAudio(); } pulseAudioManager::~pulseAudioManager() { if ( nullptr != p_PaCtx ) { pa_context_set_state_callback(p_PaCtx, NULL, NULL); pa_context_disconnect(p_PaCtx); pa_context_unref(p_PaCtx); } pa_signal_done(); if (nullptr != p_PaMl) { pa_mainloop_free(p_PaMl); } g_balance = 0; memset(&g_GetPaCV,0x00,sizeof(g_GetPaCV)); memset(&g_SetPaCV,0x00,sizeof(g_SetPaCV)); memset(&g_sinkMap,0x00,sizeof(g_sinkMap)); memset(g_sinkName,0x00,sizeof(g_sinkName)); memset(g_sourceName,0x00,sizeof(g_sourceName)); } //pulseAudioManager *pulseAudioManager::getIntance() //{ // if (nullptr == mInstance) { // mInstance = new pulseAudioManager(nullptr); // } // return mInstance; //} void pulseAudioManager::PaContextStateCallback(pa_context* p_PaCtx, void* userdata) { PulseAudioContextState* context_state = (PulseAudioContextState*)userdata; switch (pa_context_get_state(p_PaCtx)) { case PA_CONTEXT_FAILED: case PA_CONTEXT_TERMINATED: case PA_CONTEXT_READY: *context_state = PulseAudioContextState::PULSE_CONTEXT_READY; break; default: break; } } void pulseAudioManager::initPulseAudio() { p_PaMl = pa_mainloop_new(); if (!(p_PaMl)) { return; } p_PaMlApi = pa_mainloop_get_api(p_PaMl); if (!p_PaMlApi) { return ; } p_PaCtx = pa_context_new(p_PaMlApi, description); if (!(p_PaCtx)) { return ; } PulseAudioContextState context_state = PulseAudioContextState::PULSE_CONTEXT_INITIALIZING; pa_signal_init(p_PaMlApi); // pa_disable_sigpipe(); pa_context_set_state_callback(p_PaCtx, PaContextStateCallback, &context_state); if (pa_context_connect(p_PaCtx, nullptr, PA_CONTEXT_NOFLAGS, NULL) < 0) { return ; } while (context_state == PulseAudioContextState::PULSE_CONTEXT_INITIALIZING) { pa_mainloop_iterate(p_PaMl, 1, NULL); } if (context_state == PulseAudioContextState::PULSE_CONTEXT_FINISHED) { return ; } p_PaOp = pa_context_get_server_info(p_PaCtx, getServerInfoCallback, NULL); while (pa_operation_get_state(p_PaOp) == PA_OPERATION_RUNNING) { pa_mainloop_iterate(p_PaMl, 1, nullptr); } } void pulseAudioManager::contextDrainComplete(pa_context *ctx, void *userdata) { Q_UNUSED(userdata); pa_context_disconnect(ctx); } void pulseAudioManager::completeAction( ) { // if (!(o = pa_context_drain(p_PaCtx, contextDrainComplete, NULL))) // pa_context_disconnect(p_PaCtx); // else // pa_operation_unref(o); } void pulseAudioManager::paActionDoneCallback(pa_context *ctx, int success, void *userdata) { Q_UNUSED(userdata); Q_UNUSED(ctx); if (!success) { return; } } void pulseAudioManager::getSourceInfoCallback(pa_context *ctx, const pa_source_info *so, int isLast, void *userdata) { Q_UNUSED(ctx); Q_UNUSED(userdata); if (isLast != 0) { return; } g_sourceMute = so->mute; } void pulseAudioManager:: getServerInfoCallback(pa_context *ctx, const pa_server_info *si, void *userdata) { Q_UNUSED(ctx); Q_UNUSED(userdata); memset(g_sinkName,0x00,sizeof(g_sinkName)); memcpy(g_sinkName,si->default_sink_name,strlen(si->default_sink_name)); memset(g_sourceName,0x00,sizeof(g_sourceName)); memcpy(g_sourceName,si->default_source_name,strlen(si->default_source_name)); } void pulseAudioManager::getSinkInfoCallback(pa_context *ctx, const pa_sink_info *si, int isLast, void *userdata) { Q_UNUSED(ctx); Q_UNUSED(userdata); if (isLast != 0) { return; } g_sinkMap.channels = si->channel_map.channels; for (int i = 0; i < si->channel_map.channels; ++i) { g_sinkMap.map[i] = si->channel_map.map[i]; } g_GetPaCV.channels = si->volume.channels; g_mute = si->mute; for (int k = 0; k < si->volume.channels; k++) { g_GetPaCV.values[k]=si->volume.values[k]; } g_balance = pa_cvolume_get_balance(&g_GetPaCV,&g_sinkMap); } void pulseAudioManager::getSinkVolumeAndSetCallback(pa_context *ctx, const pa_sink_info *si, int isLast, void *userdata) { Q_UNUSED(si); Q_UNUSED(isLast); pa_operation_unref(pa_context_set_sink_volume_by_name(ctx, g_sinkName, (const pa_cvolume *)userdata, paActionDoneCallback, NULL)); } void pulseAudioManager::paCvOperationHandle(pa_operation *paOp) { pa_operation_unref(paOp); } void pulseAudioManager::setVolume(int Volume) { Q_UNUSED(Volume); g_SetPaCV.channels = g_GetPaCV.channels; for (int k = 0; k < g_GetPaCV.channels; k++) { g_SetPaCV.values[k] = Volume; } pa_cvolume *pcv = pa_cvolume_set_balance(&g_SetPaCV, &g_sinkMap, g_balance); if (NULL == pcv) { USD_LOG(LOG_ERR, "pa_cvolume_set_balance error!"); return; } p_PaOp = pa_context_get_sink_info_by_name(p_PaCtx, g_sinkName, getSinkVolumeAndSetCallback, pcv); if (nullptr == p_PaOp) { USD_LOG(LOG_ERR, "pa_context_get_sink_info_by_name error![%s]",g_sinkName); return; } while (pa_operation_get_state(p_PaOp) == PA_OPERATION_RUNNING) { pa_mainloop_iterate(p_PaMl, 1, nullptr); } } void pulseAudioManager::setMute(bool MuteState) { Q_UNUSED(MuteState); USD_LOG(LOG_DEBUG,"set %s is %d", g_sinkName, MuteState); p_PaOp = pa_context_set_sink_mute_by_name(p_PaCtx, g_sinkName, MuteState, paActionDoneCallback, NULL); if ( nullptr == p_PaOp ) { return; } while (pa_operation_get_state(p_PaOp) == PA_OPERATION_RUNNING) { pa_mainloop_iterate(p_PaMl, 1, nullptr); } } void pulseAudioManager::upVolume(int PerVolume) { Q_UNUSED(PerVolume); } void pulseAudioManager::lowVolume(int PerVolume) { Q_UNUSED(PerVolume); } bool pulseAudioManager::getMute() { p_PaOp = pa_context_get_sink_info_by_name(p_PaCtx, g_sinkName, getSinkInfoCallback, NULL); if (nullptr == p_PaOp) { return 0; } while (pa_operation_get_state(p_PaOp) == PA_OPERATION_RUNNING) { pa_mainloop_iterate(p_PaMl, 1, nullptr); } return g_mute; } bool pulseAudioManager::getMicMute() { p_PaOp = pa_context_get_source_info_by_name(p_PaCtx, g_sourceName, getSourceInfoCallback, NULL); if (nullptr == p_PaOp) { return 0; } while (pa_operation_get_state(p_PaOp) == PA_OPERATION_RUNNING) { pa_mainloop_iterate(p_PaMl, 1, nullptr); } return g_sourceMute; } void pulseAudioManager::setMicMute(bool MuteState) { p_PaOp = pa_context_set_source_mute_by_name(p_PaCtx, g_sourceName, MuteState, paActionDoneCallback, NULL); if ( nullptr == p_PaOp ) { return; } while (pa_operation_get_state(p_PaOp) == PA_OPERATION_RUNNING) { pa_mainloop_iterate(p_PaMl, 1, nullptr); } } int pulseAudioManager::getVolume() { int ret = 0; p_PaOp = pa_context_get_sink_info_by_name(p_PaCtx, g_sinkName, getSinkInfoCallback, NULL); if (nullptr == p_PaOp) { return 0; } while (pa_operation_get_state(p_PaOp) == PA_OPERATION_RUNNING) { pa_mainloop_iterate(p_PaMl, 1, nullptr); } ret = g_GetPaCV.values[0]>g_GetPaCV.values[1] ?g_GetPaCV.values[0]:g_GetPaCV.values[1]; return ret; } int pulseAudioManager::getMaxVolume() { return PA_VOLUME_NORM; } int pulseAudioManager::getStepVolume() { return PA_VOLUME_NORM/100; } int pulseAudioManager::getMinVolume() { return PA_VOLUME_NORM/500; } bool pulseAudioManager::getMuteAndVolume(int *volume, int *mute) { getVolume(); *volume = g_volume; *mute = g_mute; } bool pulseAudioManager::getSourceMute() { p_PaOp = pa_context_get_source_info_by_name(p_PaCtx, g_sourceName, getSourceInfoCallback, NULL); if (nullptr == p_PaOp) { return 0; } while (pa_operation_get_state(p_PaOp) == PA_OPERATION_RUNNING) { pa_mainloop_iterate(p_PaMl, 1, nullptr); } } void pulseAudioManager::setSourceMute(bool Mute) { pa_context_set_source_mute_by_name(p_PaCtx, g_sourceName, Mute, paActionDoneCallback, NULL); if ( nullptr == p_PaOp ) { return; } while (pa_operation_get_state(p_PaOp) == PA_OPERATION_RUNNING) { pa_mainloop_iterate(p_PaMl, 1, nullptr); } } ukui-settings-daemon/plugins/media-keys/volumewindow.h0000644000175000017500000000507114205117202022170 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MEDIAKEYSWINDOW_H #define MEDIAKEYSWINDOW_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE namespace Ui {class VolumeWindow;} QT_END_NAMESPACE class VolumeWindow : public QWidget { Q_OBJECT public: VolumeWindow(QWidget *parent = nullptr); ~VolumeWindow(); void initWindowInfo(); void dialogVolumeShow(); void dialogBrightShow(); void setWidgetLayout(); void setVolumeMuted(bool); void setVolumeLevel(int); void setVolumeRange(int, int); void setBrightIcon(const QString icon); void setBrightValue(int value); int getScreenGeometry (QString methodName); QPixmap drawLightColoredPixmap(const QPixmap &source, const QString &style); private Q_SLOTS: void timeoutHandle(); void priScreenChanged(int x, int y, int width, int height); void geometryChangedHandle(); void onStyleChanged(const QString&); private: void showEvent(QShowEvent* e); void paintEvent(QPaintEvent* e); private: Ui::VolumeWindow *ui; QVBoxLayout *mVLayout; QHBoxLayout *mBarLayout; QHBoxLayout *mSvgLayout; QHBoxLayout *mLabLayout; QSpacerItem *mSpace; QLabel *mLabel; QProgressBar *mVolumeBar; QProgressBar *mBrightBar; QLabel *mBut; QTimer *mTimer; QString mIconName; QDBusInterface *mDbusXrandInter; QGSettings *m_styleSettings; double mScale = 1.0; int mVolumeLevel; int mMaxVolume,mMinVolume; bool mVolumeMuted; int mbrightValue; }; #endif // MEDIAKEYSWINDOW_H ukui-settings-daemon/plugins/media-keys/acme.h0000644000175000017500000000415414205117202020337 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef __ACME_H__ #define __ACME_H__ #include "ukui-keygrab.h" #define BINDING_SCHEMA "org.ukui.SettingsDaemon.plugins.media-keys" enum { TOUCHPAD_KEY, MUTE_KEY, VOLUME_DOWN_KEY, VOLUME_UP_KEY, MIC_MUTE_KEY, BRIGHT_UP_KEY, BRIGHT_DOWN_KEY, POWER_DOWN_KEY, POWER_OFF_KEY, EJECT_KEY, HOME_KEY, MEDIA_KEY, CALCULATOR_KEY, SEARCH_KEY, EMAIL_KEY, SCREENSAVER_KEY, SCREENSAVER_KEY_2, HELP_KEY, WWW_KEY, PLAY_KEY, PAUSE_KEY, STOP_KEY, PREVIOUS_KEY, NEXT_KEY, REWIND_KEY, FORWARD_KEY, REPEAT_KEY, RANDOM_KEY, MAGNIFIER_KEY, SCREENREADER_KEY, SETTINGS_KEY, SETTINGS_KEY_2, FILE_MANAGER_KEY, FILE_MANAGER_KEY_2, ON_SCREEN_KEYBOARD_KEY, LOGOUT_KEY, TERMINAL_KEY, TERMINAL_KEY_2, SCREENSHOT_KEY, WINDOW_SCREENSHOT_KEY, AREA_SCREENSHOT_KEY, WINDOWSWITCH_KEY, WINDOWSWITCH_KEY_2, SYSTEM_MONITOR_KEY, CONNECTION_EDITOR_KEY, GLOBAL_SEARCH_KEY, KDS_KEY, KDS_KEY2, WLAN_KEY, WEBCAM_KEY, HANDLED_KEYS, UKUI_SIDEBAR, UKUI_EYECARE_CENTER, TOUCHPAD_ON_KEY, TOUCHPAD_OFF_KEY, RFKILL_KEY, BLUETOOTH_KEY, }; static struct { int key_type; const char *settings_key; const char *hard_coded; Key *key; } keys[HANDLED_KEYS] = { }; #endif /* __ACME_H__ */ ukui-settings-daemon/plugins/media-keys/mediakey-plugin.cpp0000644000175000017500000000354514205117202023054 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mediakey-plugin.h" #include "clib-syslog.h" PluginInterface* MediakeyPlugin::mInstance = nullptr; MediakeyPlugin::MediakeyPlugin() { USD_LOG(LOG_ERR, "mediakey plugin init..."); mManager = MediaKeysManager::mediaKeysNew(); } MediakeyPlugin::~MediakeyPlugin() { USD_LOG(LOG_ERR,"MediakeyPlugin deconstructor!"); if(mManager){ delete mManager; mManager = nullptr; } } PluginInterface *MediakeyPlugin::getInstance() { if (nullptr == mInstance) { mInstance = new MediakeyPlugin(); } return mInstance; } void MediakeyPlugin::activate() { GError *error = NULL; USD_LOG (LOG_DEBUG, "Activating %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); if (!mManager->mediaKeysStart(error)) { USD_LOG(LOG_DEBUG,"Unable to start media-keys manager: %s", error->message); g_error_free (error); } } void MediakeyPlugin::deactivate() { USD_LOG(LOG_ERR, "deactivating mediakey plugin ..."); mManager->mediaKeysStop(); } PluginInterface* createSettingsPlugin() { return MediakeyPlugin::getInstance(); } ukui-settings-daemon/plugins/media-keys/media-keys.pro0000644000175000017500000000223114205117202022025 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-06-16T09:30:00 # #------------------------------------------------- QT += gui widgets svg x11extras dbus KGlobalAccel KWindowSystem TEMPLATE = lib CONFIG += c++11 plugin link_pkgconfig CONFIG -= app_bundle PKGCONFIG += \ glib-2.0 \ gio-2.0 \ gtk+-3.0 \ gsettings-qt \ # libmatemixer LIBS += \ -lX11 -lXi -lpulse include($$PWD/../../common/common.pri) DEFINES += QT_DEPRECATED_WARNINGS HAVE_X11_EXTENSIONS_XKB_H _FORTIFY_SOURCE=2 MODULE_NAME=\\\"mediakeys\\\" SOURCES += \ devicewindow.cpp \ pulseaudiomanager.cpp \ volumewindow.cpp \ mediakey-manager.cpp \ mediakey-plugin.cpp \ xEventMonitor.cpp HEADERS += \ acme.h \ devicewindow.h \ pulseaudiomanager.h \ volumewindow.h \ mediakey-manager.h \ mediakey-plugin.h \ xEventMonitor.h FORMS += \ devicewindow.ui \ volumewindow.ui DISTFILES += \ media-keys.ukui-settings-plugin.in media_keys_lib.path = $${PLUGIN_INSTALL_DIRS} media_keys_lib.files = $$OUT_PWD/libmedia-keys.so INSTALLS += media_keys_lib ukui-settings-daemon/plugins/media-keys/volumewindow.cpp0000644000175000017500000002750314205117202022527 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "volumewindow.h" #include "ui_volumewindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "clib-syslog.h" #include "usd_global_define.h" #define DBUS_NAME DBUS_XRANDR_NAME #define DBUS_PATH DBUS_XRANDR_PATH #define DBUS_INTERFACE DBUS_XRANDR_INTERFACE #define QT_THEME_SCHEMA "org.ukui.style" #define ICON_SIZE 24 const QString allIconName[] = { "audio-volume-muted-symbolic", "audio-volume-low-symbolic", "audio-volume-medium-symbolic", "audio-volume-high-symbolic", nullptr }; VolumeWindow::VolumeWindow(QWidget *parent) : QWidget(parent) , ui(new Ui::VolumeWindow) { ui->setupUi(this); mDbusXrandInter = new QDBusInterface(DBUS_NAME, DBUS_PATH, DBUS_INTERFACE, QDBusConnection::sessionBus(), this); if (!mDbusXrandInter->isValid()) { USD_LOG(LOG_DEBUG, "stderr:%s\n",qPrintable(QDBusConnection::sessionBus().lastError().message())); } //监听dbus变化 更改主屏幕时,会进行信号发送 connect(mDbusXrandInter, SIGNAL(screenPrimaryChanged(int,int,int,int)), this, SLOT(priScreenChanged(int,int,int,int))); m_styleSettings = new QGSettings(QT_THEME_SCHEMA); connect(m_styleSettings,SIGNAL(changed(const QString&)), this,SLOT(onStyleChanged(const QString&))); QGSettings *settings = new QGSettings("org.ukui.SettingsDaemon.plugins.xsettings"); if (settings) { mScale = settings->get("scaling-factor").toDouble(); mScale = mScale<1? 1.0:mScale; } delete settings; } VolumeWindow::~VolumeWindow() { delete ui; if (mBarLayout) delete mBarLayout; if (mSvgLayout) delete mSvgLayout; if (mBut) delete mBut; if (mVolumeBar) delete mVolumeBar; if (mVLayout) delete mVLayout; if (mTimer) delete mTimer; } int VolumeWindow::getScreenGeometry(QString methodName) { int res = 0; QDBusMessage message = QDBusMessage::createMethodCall(DBUS_NAME, DBUS_PATH, DBUS_INTERFACE, methodName); QDBusMessage response = QDBusConnection::sessionBus().call(message); if (response.type() == QDBusMessage::ReplyMessage) { if(response.arguments().isEmpty() == false) { int value = response.arguments().takeFirst().toInt(); res = value; } } else { USD_LOG(LOG_DEBUG, "%s called failed", methodName.toLatin1().data()); } return res; } /* 主屏幕变化监听函数 */ void VolumeWindow::priScreenChanged(int x, int y, int width, int height) { int ax,ay; ax = x + (width*0.01*mScale); ay = y + (height*0.04*mScale); move(ax, ay); } void VolumeWindow::geometryChangedHandle() { int x=QApplication::primaryScreen()->geometry().x(); int y=QApplication::primaryScreen()->geometry().y(); int width = QApplication::primaryScreen()->size().width(); int height = QApplication::primaryScreen()->size().height(); USD_LOG(LOG_DEBUG,"getchangehandle....%dx%d at(%d,%d)",width,height,x,y); priScreenChanged(x,y,width,height); } void VolumeWindow::onStyleChanged(const QString& style) { if(style == "icon-theme-name") { QSize iconSize(ICON_SIZE * mScale,ICON_SIZE * mScale); QIcon::setThemeName(m_styleSettings->get("icon-theme-name").toString()); mBut->setPixmap(drawLightColoredPixmap((QIcon::fromTheme(mIconName).pixmap(iconSize)) ,m_styleSettings->get("style-name").toString())); } else if(style == "style-name") { if(!this->isHidden()) { hide(); show(); } } } void VolumeWindow::initWindowInfo() { connect(QApplication::primaryScreen(), &QScreen::geometryChanged, this, &VolumeWindow::geometryChangedHandle); connect(static_cast(QCoreApplication::instance()), &QApplication::primaryScreenChanged, this, &VolumeWindow::geometryChangedHandle); //窗口性质 setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint); setAttribute(Qt::WA_TranslucentBackground, true); setFixedSize(QSize(64,300) * mScale); mVolumeBar = new QProgressBar(this); mBrightBar = new QProgressBar(this); mBut = new QLabel(this); mTimer = new QTimer(); connect(mTimer,SIGNAL(timeout()),this,SLOT(timeoutHandle())); mVolumeLevel = 0; mVolumeMuted = false; geometryChangedHandle();//had move action setWidgetLayout(); } //上下留出10个空间,音量条与svg图片之间留出10个空间 void VolumeWindow::setWidgetLayout() { //窗口性质 setFixedSize(QSize(64,300) * mScale); //button图片操作 mBut->setFixedSize(QSize(31,24) * mScale); mBut->setAlignment(Qt::AlignCenter); mBut->move(17 * mScale , 253 * mScale); //音量条操作 mVolumeBar->setOrientation(Qt::Vertical); mVolumeBar->setFixedSize(QSize(6,200) * mScale); mVolumeBar->move(29 * mScale,37 * mScale); mVolumeBar->setTextVisible(false); mVolumeBar->hide(); //亮度条操作 mBrightBar->setOrientation(Qt::Vertical); mBrightBar->setFixedSize(QSize(6,200) * mScale); mBrightBar->move(29 * mScale,37 * mScale); mBrightBar->setTextVisible(false); mBrightBar->hide(); } int doubleToInt(double d) { int I = d; if(d - I >= 0.5) return I+1; else return I; } QPixmap VolumeWindow::drawLightColoredPixmap(const QPixmap &source, const QString &style) { int value = 255; if(style == "ukui-light") { value = 0; } QColor gray(255,255,255); QColor standard (0,0,0); QImage img = source.toImage(); for (int x = 0; x < img.width(); x++) { for (int y = 0; y < img.height(); y++) { auto color = img.pixelColor(x, y); if (color.alpha() > 0) { if (qAbs(color.red()-gray.red())<20 && qAbs(color.green()-gray.green())<20 && qAbs(color.blue()-gray.blue())<20) { color.setRed(value); color.setGreen(value); color.setBlue(value); img.setPixelColor(x, y, color); } else { color.setRed(value); color.setGreen(value); color.setBlue(value); img.setPixelColor(x, y, color); } } } } return QPixmap::fromImage(img); } void VolumeWindow::dialogVolumeShow() { geometryChangedHandle(); mBrightBar->hide(); mVolumeBar->show(); QSize iconSize(ICON_SIZE * mScale,ICON_SIZE * mScale); mBut->setPixmap(drawLightColoredPixmap((QIcon::fromTheme(mIconName).pixmap(iconSize)),m_styleSettings->get("style-name").toString())); show(); mTimer->start(2000); } void VolumeWindow::dialogBrightShow() { geometryChangedHandle(); mVolumeBar->hide(); mBrightBar->show(); mBrightBar->setValue(mbrightValue); QSize iconSize(ICON_SIZE * mScale,ICON_SIZE * mScale); mBut->setPixmap(drawLightColoredPixmap((QIcon::fromTheme(mIconName).pixmap(iconSize)),m_styleSettings->get("style-name").toString())); show(); mTimer->start(2000); } void VolumeWindow::setVolumeMuted(bool muted) { if(this->mVolumeMuted != muted) { mVolumeMuted = muted; } } void VolumeWindow::setVolumeLevel(int level) { double percentage; mVolumeBar->reset(); mIconName.clear(); mVolumeLevel = level; mVolumeBar->setValue(mVolumeLevel/(mMaxVolume/100)); if(mVolumeMuted){ mIconName = allIconName[0]; return; } percentage = double(mVolumeLevel-mMinVolume) / (mMaxVolume-mMinVolume); if(0 <= percentage && percentage <= 0.01) mIconName = allIconName[0]; if(percentage <= 0.33) mIconName = allIconName[1]; else if(percentage <= 0.66) mIconName = allIconName[2]; else mIconName = allIconName[3]; } void VolumeWindow::setVolumeRange(int min, int max) { if(min == mMinVolume && max == mMaxVolume) return ; mMaxVolume = max; mMinVolume = min; mVolumeBar->setRange(mMinVolume/(mMaxVolume/100),100); } void VolumeWindow::setBrightIcon(const QString icon) { mIconName = icon; } void VolumeWindow::setBrightValue(int value) { mbrightValue = value; } void VolumeWindow::timeoutHandle() { hide(); mTimer->stop(); } void VolumeWindow::showEvent(QShowEvent* e) { QSize iconSize(ICON_SIZE * mScale,ICON_SIZE * mScale); /*适应主题颜色*/ if(m_styleSettings->get("style-name").toString() == "ukui-light") { mVolumeBar->setStyleSheet("QProgressBar{border:none;border-radius:3px;background:#33000000}" "QProgressBar::chunk{border-radius:3px;background:black}"); mBrightBar->setStyleSheet("QProgressBar{border:none;border-radius:3px;background:#33000000}" "QProgressBar::chunk{border-radius:3px;background:black}"); setPalette(QPalette(QColor("#F5F5F5")));//设置窗口背景色 } else { mVolumeBar->setStyleSheet("QProgressBar{border:none;border-radius:3px;background:#33000000}" "QProgressBar::chunk{border-radius:3px;background:white}"); mBrightBar->setStyleSheet("QProgressBar{border:none;border-radius:3px;background:#33000000}" "QProgressBar::chunk{border-radius:3px;background:white}"); setPalette(QPalette(QColor("#232426")));//设置窗口背景色 } mBut->setPixmap(drawLightColoredPixmap((QIcon::fromTheme(mIconName).pixmap(iconSize)),m_styleSettings->get("style-name").toString())); } void VolumeWindow::paintEvent(QPaintEvent* e) { QRect rect = this->rect(); QPainterPath path; QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); // 反锯齿; painter.setPen(Qt::transparent); qreal radius=12; path.moveTo(rect.topRight() - QPointF(radius, 0)); path.lineTo(rect.topLeft() + QPointF(radius, 0)); path.quadTo(rect.topLeft(), rect.topLeft() + QPointF(0, radius)); path.lineTo(rect.bottomLeft() + QPointF(0, -radius)); path.quadTo(rect.bottomLeft(), rect.bottomLeft() + QPointF(radius, 0)); path.lineTo(rect.bottomRight() - QPointF(radius, 0)); path.quadTo(rect.bottomRight(), rect.bottomRight() + QPointF(0, -radius)); path.lineTo(rect.topRight() + QPointF(0, radius)); path.quadTo(rect.topRight(), rect.topRight() + QPointF(-radius, -0)); painter.setBrush(this->palette().base()); painter.setPen(Qt::transparent); painter.setOpacity(0.75); painter.drawPath(path); KWindowEffects::enableBlurBehind(this->winId(), true, QRegion(path.toFillPolygon().toPolygon())); QWidget::paintEvent(e); } ukui-settings-daemon/plugins/media-keys/media-keys.ukui-settings-plugin.in0000644000175000017500000000021614205117202025742 0ustar fengfeng[UKUI Settings Plugin] Module=media-keys IAge=0 _Name=Media keys _Description=Media keys plugin Authors= Copyright=Copyright © 2007 Website= ukui-settings-daemon/plugins/media-keys/devicewindow.ui0000644000175000017500000000061514205117202022305 0ustar fengfeng DeviceWindow 0 0 400 300 DeviceWindow ukui-settings-daemon/plugins/xrdb/0000755000175000017500000000000014205117202016164 5ustar fengfengukui-settings-daemon/plugins/xrdb/xrdb-plugin.h0000644000175000017500000000244714205117202020577 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XRDB_H #define XRDB_H #include "plugin-interface.h" #include "ixrdb-manager.h" #ifdef __cplusplus extern "C" { #endif #include "clib-syslog.h" #ifdef __cplusplus } #endif class XrdbPlugin : public PluginInterface { public: ~XrdbPlugin(); static PluginInterface* getInstance(); virtual void activate (); virtual void deactivate (); protected: static XrdbPlugin* mXrdbPlugin; IXrdbManager *m_pIXdbMgr; private: XrdbPlugin(); }; extern "C" PluginInterface* Q_DECL_EXPORT createSettingsPlugin(); #endif // XRDB_H ukui-settings-daemon/plugins/xrdb/xrdb-manager.h0000644000175000017500000000561414205117202020712 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UKUIXRDBMANAGER_H #define UKUIXRDBMANAGER_H #include #include #include "ixrdb-manager.h" /* qt会将glib的signals成员识别为宏,所以取消该宏 * 如果程序中需要使用qt的信号机制,则使用Q_SIGNALS即可 */ #ifdef signals #undef signals #endif extern "C"{ #include #include #include #include #include } #define SYSCONFDIR "/etc" #define SYSTEM_AD_DIR SYSCONFDIR "/xrdb" #define GENERAL_AD SYSTEM_AD_DIR "/General.ad" #define USER_AD_DIR ".config/ukui/xrdb" #define USER_X_RESOURCES ".Xresources" #define USER_X_DEFAULTS ".Xdefaults" #define SCHEMAS "org.mate.interface" #define SYSTEM_THEME_DIR "/usr/share/themes/" class ukuiXrdbManager:public QObject,public IXrdbManager { Q_OBJECT public: ~ukuiXrdbManager(); static ukuiXrdbManager* ukuiXrdbManagerNew(); bool start(GError **error); void stop(); private: ukuiXrdbManager(); ukuiXrdbManager(const ukuiXrdbManager&) = delete; QList* scanForFiles(GError** error); void removeSameItemFromFirst(QList* first, QList* second); void applySettings(); void appendFile(QString file,GError** error); void appendXresourceFile(QString fileName,GError **error); QString fileGetContents(QString fileName,GError **error); void getColorConfigFromGtkWindow(); void appendColor(QString name,GdkColor* color); void colorShade(QString name,GdkColor* color,double shade); private Q_SLOTS: void themeChanged (const QString& key); private: static ukuiXrdbManager* mXrdbManager; QGSettings* settings; GtkWidget* widget; QList m_whiteThemeNameList = {"ukui-light", "ukui-default","ukui-white-unity","ukui-white"}; QList m_blackThemeNameList = {"ukui-dark", "ukui-black-unity","ukui-black"}; //after call spawn_with_input(),the following three members must be Empty. QList *allUsefulAdFiles; QList *tmpFileList; QStringList colorDefineList; QString needMerge; }; #endif // UKUIXRDBMANAGER_H ukui-settings-daemon/plugins/xrdb/ixrdb-manager.h0000644000175000017500000000211714205117202021056 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef IXRDBMANAGER_H #define IXRDBMANAGER_H #include #ifdef __cplusplus extern "C" { #endif #include "clib-syslog.h" #ifdef __cplusplus } #endif class IXrdbManager { public: IXrdbManager(){}; virtual ~IXrdbManager(){}; virtual bool start(GError**) = 0; virtual void stop() = 0; }; #endif // IXRDBMANAGER_H ukui-settings-daemon/plugins/xrdb/xrdb.pro0000644000175000017500000000245414205117202017652 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-03-20T09:50:48 # #------------------------------------------------- QT -= gui QT += dbus TARGET = xrdb TEMPLATE = lib DEFINES += XRDB_LIBRARY CONFIG += c++11 plugin link_pkgconfig CONFIG -= app_bundle # The following define makes your compiler emit warnings if you use # any feature of Qt which has been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"xrdb\\\" # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 include($$PWD/../../common/common.pri) PKGCONFIG +=\ gtk+-3.0 \ gsettings-qt \ atk \ mate-desktop-2.0 SOURCES += \ xrdb-plugin.cpp \ xrdb-manager.cpp HEADERS += \ xrdb-plugin.h \ xrdb-manager.h \ ixrdb-manager.h xrdb_lib.path = $${PLUGIN_INSTALL_DIRS} xrdb_lib.files += $$OUT_PWD/libxrdb.so \ INSTALLS += xrdb_lib ukui-settings-daemon/plugins/xrdb/xrdb-plugin.cpp0000644000175000017500000000345014205117202021125 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "xrdb-plugin.h" #include "xrdb-manager.h" XrdbPlugin* XrdbPlugin::mXrdbPlugin = nullptr; XrdbPlugin::XrdbPlugin() { USD_LOG(LOG_DEBUG,"XrdbPlugin initializing!"); m_pIXdbMgr = ukuiXrdbManager::ukuiXrdbManagerNew(); } XrdbPlugin::~XrdbPlugin() { USD_LOG(LOG_DEBUG,"XrdbPlugin deconstructor!"); if (m_pIXdbMgr) { delete m_pIXdbMgr; } m_pIXdbMgr = nullptr; } void XrdbPlugin::activate () { GError* error; USD_LOG (LOG_DEBUG, "Activating %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); error = NULL; if(!m_pIXdbMgr->start(&error)){ USD_LOG(LOG_DEBUG,"unable to start xrdb manager: %s",error->message); g_error_free(error); } } void XrdbPlugin::deactivate () { USD_LOG(LOG_DEBUG,"Deactivating xrdn plugin!"); m_pIXdbMgr->stop(); } PluginInterface* XrdbPlugin::getInstance() { if(nullptr == mXrdbPlugin) mXrdbPlugin = new XrdbPlugin(); return mXrdbPlugin; } PluginInterface* createSettingsPlugin() { return XrdbPlugin::getInstance(); } ukui-settings-daemon/plugins/xrdb/xrdb-manager.cpp0000644000175000017500000004041414205117202021242 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include "xrdb-manager.h" #include #define midColor(x,low,high) (((x) > (high)) ? (high): (((x) < (low)) ? (low) : (x))) ukuiXrdbManager* ukuiXrdbManager::mXrdbManager = nullptr; ukuiXrdbManager::ukuiXrdbManager() { settings = new QGSettings(SCHEMAS); allUsefulAdFiles = new QList(); gtk_init(NULL,NULL); } ukuiXrdbManager::~ukuiXrdbManager() { if (settings) { delete settings; settings = nullptr; } if (allUsefulAdFiles) { allUsefulAdFiles->clear(); delete allUsefulAdFiles; allUsefulAdFiles = nullptr; } } //singleton ukuiXrdbManager* ukuiXrdbManager::ukuiXrdbManagerNew() { if(nullptr == mXrdbManager) mXrdbManager = new ukuiXrdbManager(); return mXrdbManager; } bool ukuiXrdbManager::start(GError **error) { USD_LOG(LOG_DEBUG,"Starting xrdb manager!"); widget = gtk_window_new (GTK_WINDOW_TOPLEVEL); //gtk_widget_realize (widget); gtk_widget_ensure_style(widget); /* the initialization is done here otherwise ukui_settings_xsettings_load would generate false hit as gtk-theme-name is set to Default in ukui_settings_xsettings_init */ if(nullptr != settings) connect(settings,SIGNAL(changed(const QString&)),this,SLOT(themeChanged(const QString&))); return true; } void ukuiXrdbManager::stop() { USD_LOG(LOG_DEBUG,"Stopping xrdb manager!"); //destroy newed GtkWidget window gtk_widget_destroy(widget); } /** func : Scan .ad file from @path, and return them all in a QList * 从@path目录下查找 .ad 文件,并存储在 QList。 */ QList* scanAdDirectory(QString path,GError** error) { QFileInfoList fileList; QString tmpFileName; QList* tmpFileList; QDir dir; int fileCount; int i = 0; dir.setPath(path); if(!dir.exists()){ g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_EXIST, "%s does not exist!", path.toLatin1().data()); return nullptr; } fileList = dir.entryInfoList(); fileCount = fileList.count(); tmpFileList = new QList(); for(;i < fileCount; ++i){ tmpFileName = fileList.at(i).absoluteFilePath(); if(tmpFileName.contains(".ad")) tmpFileList->push_back(tmpFileName); } if(tmpFileList->size() > 0) tmpFileList->sort(); return tmpFileList; } /** * @brief ukuiXrdbManager::scanForFiles * scan .ad file from @SYSTEM_AD_DIR and $HOME, and return them at a QList; * 从@SYSTEM_AD_DIR 和 $HOME扫描 .ad 文件,将结果存储在QList * @param error * @return */ QList* ukuiXrdbManager::scanForFiles(GError** error) { QString userHomeDir; QList* userAdFileList; QList* systemAdFileList;//remeber free GError* localError; systemAdFileList = userAdFileList = nullptr; //look for system ad files at /etc/xrdb/ localError = NULL; systemAdFileList = scanAdDirectory(SYSTEM_AD_DIR,&localError); if(NULL != localError){ g_propagate_error(error,localError); //copy error info return nullptr; } //look for ad files at user's home. userHomeDir = QDir::homePath(); if(!userHomeDir.isEmpty()){ QString userAdDir; QFileInfo fileInfo; userAdDir = userHomeDir + "/" + USER_AD_DIR; fileInfo.setFile(userAdDir); if(fileInfo.exists() && fileInfo.isDir()){ userAdFileList = scanAdDirectory(userAdDir,&localError); //what remians here is open source logic 这里保留的是开源的逻辑 if(NULL != localError){ g_propagate_error(error,localError); //copy error info systemAdFileList->clear(); //memery free for QList delete systemAdFileList; return nullptr; } }else USD_LOG(LOG_INFO,"User's ad file not found at %s!",userAdDir.toLatin1().data()); }else USD_LOG(LOG_WARNING,"Cannot datermine user's home directory!"); //After get all ad files,we handle it. 在得到所有的ad文件后,我们开始处理数据 if(systemAdFileList->contains(GENERAL_AD)) systemAdFileList->removeOne(GENERAL_AD); if(nullptr != userAdFileList) removeSameItemFromFirst(systemAdFileList,userAdFileList); //here,we get all ad files that we needed(without repetition). 到这里,取得我们所有需要的 ad 文件(不重复) allUsefulAdFiles->append(*systemAdFileList); if(nullptr != userAdFileList) allUsefulAdFiles->append(*userAdFileList); allUsefulAdFiles->append(GENERAL_AD); //QList.append() operator is deep-copy,so we free memory. QList.append()会进行深拷贝,所以这里释放内存 systemAdFileList->clear(); delete systemAdFileList; if(nullptr != userAdFileList){ userAdFileList->clear(); delete userAdFileList; } return allUsefulAdFiles; } /** * Append the contents of @file onto the end of a QString * 追加 @file 文件的内容到QString尾部 */ void ukuiXrdbManager::appendFile(QString file,GError** error) { GError* localError; QString fileContents; //first get all contents from file. localError = NULL; fileContents = fileGetContents(file,&localError); if(NULL != localError){ g_propagate_error(error,localError); //copy error info localError = NULL; return; } //then append all contents to @needMerge if(!fileContents.isNull()) needMerge.append(fileContents); } /** func : append contents from .Xresources or .Xdefaults to @needMerge. */ void ukuiXrdbManager::appendXresourceFile(QString fileName,GError **error) { QString homePath; QString xResources; QFile file; GError* localError; char* tmpName; homePath = QDir::homePath(); xResources = homePath + "/" + fileName; file.setFileName(xResources); if(!file.exists()){ tmpName = xResources.toLatin1().data(); g_set_error(error,G_FILE_ERROR, G_FILE_ERROR_NOENT, "%s does not exist!",tmpName); //USD_LOG(LOG_WARNING,"%s does not exist!",tmpName); return; } localError = NULL; appendFile(xResources,&localError); if(NULL != localError){ g_propagate_error(error,localError); //USD_LOG(LOG_WARNING,"%s",localError->message); localError = NULL; } } bool write_all (int fd,const char *buf,ulong to_write) { while (to_write > 0) { long count = write (fd, buf, to_write); if (count < 0) { return false; } else { to_write -= count; buf += count; } } return true; } void child_watch_cb (int pid, int status, gpointer user_data) { char *command = (char*)user_data; if (!WIFEXITED (status) || WEXITSTATUS (status)) { USD_LOG(LOG_WARNING,"Command %s failed", command); } } void spawn_with_input (const char *command, const char *input) { char **argv; int child_pid; int inpipe; GError *error; bool res; argv = NULL; res = g_shell_parse_argv (command, NULL, &argv, NULL); if (! res) { USD_LOG(LOG_WARNING,"Unable to parse command: %s", command); return; } error = NULL; res = g_spawn_async_with_pipes (NULL, argv, NULL, (GSpawnFlags)(G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD), NULL, NULL, &child_pid, &inpipe, NULL, NULL, &error); g_strfreev (argv); if (! res) { USD_LOG(LOG_WARNING,"Could not execute %s: %s", command, error->message); g_error_free (error); return; } if (input != NULL) { if (! write_all (inpipe, input, strlen (input))) { USD_LOG(LOG_WARNING,"Could not write input to %s", command); } close (inpipe); } g_child_watch_add (child_pid, (GChildWatchFunc) child_watch_cb, (gpointer)command); } /* 1 according to the current theme,get color value. * 2 get contents from ad files. * 3 exec command: "xrdb -merge -quiet ....". */ void ukuiXrdbManager::applySettings(){ char* command; GError* error; int i,fileNum; int listCount; command = "xrdb -merge -quiet"; if(!colorDefineList.isEmpty()){ listCount = colorDefineList.count(); for( i = 0; i < listCount; ++i) needMerge.append(colorDefineList.at(i)); colorDefineList.clear(); } //first, get system ad files and user's ad files error = NULL; scanForFiles(&error); if(NULL != error){ USD_LOG(LOG_WARNING,"%s",error->message); g_error_free(error); } //second, get contents from every file,and append contends to @needMerge. fileNum = allUsefulAdFiles->count(); for(i = 0; i < fileNum; ++i){ error = NULL; appendFile(allUsefulAdFiles->at(i),&error); if(NULL != error){ USD_LOG(LOG_WARNING,"%s",error->message); g_error_free(error); } } //third, append Xresources file's contents to @needMerge. error = NULL; appendXresourceFile(USER_X_RESOURCES,&error); if(NULL != error){ USD_LOG(LOG_WARNING,"%s",error->message); g_error_free(error); } error = NULL; appendXresourceFile(USER_X_DEFAULTS,&error); if(NULL != error){ USD_LOG(LOG_WARNING,"%s",error->message); g_error_free(error); } //last, exec shell: @command + @needMerge spawn_with_input(command,needMerge.toLatin1().data()); needMerge.clear(); allUsefulAdFiles->clear(); } /** func : private slots for gsettings key 'gtk-theme' changed * 监听 'gtk-theme' key值变化的槽函数 */ void ukuiXrdbManager::themeChanged (const QString& key) { USD_LOG(LOG_DEBUG,"key:%s", key.toLatin1().data()); /* 监听主题更改,发送dbus信号 */ if(key.compare("gtk-theme")==0){ QString value = settings->get(key).toString(); USD_LOG(LOG_DEBUG,"key:%s value:%s", key.toLatin1().data(), value.toLatin1().data()); if (m_whiteThemeNameList.contains(value)) { QDBusMessage message = QDBusMessage::createSignal("/KGlobalSettings", "org.kde.KGlobalSettings", "slotThemeChange"); message << int(0); QDBusConnection::sessionBus().send(message); USD_LOG(LOG_DEBUG,"set white theme keys:%s",value.toLatin1().data()); } else if (m_blackThemeNameList.contains(value)) { QDBusMessage message = QDBusMessage::createSignal("/KGlobalSettings", "org.kde.KGlobalSettings", "slotThemeChange"); message << int(1); QDBusConnection::sessionBus().send(message); USD_LOG(LOG_DEBUG,"set black theme keys %s",value.toLatin1().data()); } } //getColorConfigFromGtkWindow(); //applySettings(); } /* func : remove one item from first,if second have this item too. * the point is : name is same. * example: first.at(3) == "/etc/xrdb/tmp1.ad" * second.at(1) == $QDir::homePath + "/.config/ukui/tmp1.ad" * then exec : first.removeAt(3); */ void ukuiXrdbManager::removeSameItemFromFirst(QList* first, QList* second){ QFileInfo tmpFirstName; QFileInfo tmpSecondName; QString firstBaseName; //real file name,not include path 不含路径的真实文件名 QString secondBaseName; //same as above 同上 int i,j; int firstSize,secondSize; // if(first->isEmpty() || second->isEmpty()){ // return; // } first->length(); firstSize = first->size(); secondSize = second->size(); for(i = 0; i < firstSize; ++i){ firstBaseName.clear(); tmpFirstName.setFile(first->at(i)); firstBaseName = tmpFirstName.fileName(); for(j = 0; j < secondSize; ++j){ secondBaseName.clear(); tmpSecondName.setFile(second->at(j)); secondBaseName = tmpSecondName.fileName(); if(firstBaseName == secondBaseName){ first->removeAt(i); firstSize -= 1; break; } } } } /** func : read all contents from @fileName. * 从文件 @fileName 读取全部内容 * @return * return nullptr if open failed or @fileName does not exist * 若文件 @fileName 不存在或者对打开失败,则返回 nullptr */ QString ukuiXrdbManager::fileGetContents(QString fileName,GError **error) { QFile file; QString fileContents; file.setFileName(fileName); if(!file.exists()){ g_set_error(error,G_FILE_ERROR, G_FILE_ERROR_NOENT, "%s does not exists!",fileName.toLatin1().data()); return nullptr; } if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){ g_set_error(error,G_FILE_ERROR, G_FILE_ERROR_FAILED, "%s open failed!",fileName.toLatin1().data()); return nullptr; } fileContents = file.readAll(); return fileContents; } /** * @brief ukuiXrdbManager::getColorConfigFromGtkWindow * gets the color configuration for the gtk window. * 获取gtk窗体的颜色配置信息 */ void ukuiXrdbManager::getColorConfigFromGtkWindow() { GtkStyle* style; style = gtk_widget_get_style(widget); appendColor("BACKGROUND",&style->bg[GTK_STATE_NORMAL]); appendColor("FOREGROUND",&style->fg[GTK_STATE_NORMAL]); appendColor("SELECT_BACKGROUND",&style->bg[GTK_STATE_SELECTED]); appendColor("SELECT_FOREGROUND",&style->text[GTK_STATE_SELECTED]); appendColor("WINDOW_BACKGROUND",&style->base[GTK_STATE_NORMAL]); appendColor("WINDOW_FOREGROUND",&style->text[GTK_STATE_NORMAL]); appendColor("INACTIVE_BACKGROUND",&style->bg[GTK_STATE_INSENSITIVE]); appendColor("INACTIVE_FOREGROUND",&style->text[GTK_STATE_INSENSITIVE]); appendColor("ACTIVE_BACKGROUND",&style->bg[GTK_STATE_SELECTED]); appendColor("ACTIVE_FOREGROUND",&style->text[GTK_STATE_SELECTED]); colorShade("HIGHLIGHT",&style->bg[GTK_STATE_NORMAL],1.2); colorShade("LOWLIGHT",&style->fg[GTK_STATE_NORMAL],2.0/3.0); } /* func : Gets the hexadecimal value of the color * 获取颜色值的16进制表示 * example : #define BACKGROUND #ffffff\n */ void ukuiXrdbManager::appendColor(QString name,GdkColor* color) { QString tmp; tmp = QString("#%1%2%3\n").arg(color->red>>8,2,16,QLatin1Char('0')) .arg(color->green>>8,2,16,QLatin1Char('0')).arg(color->blue>>8,2,16,QLatin1Char('0')); colorDefineList.append("#define " + name + " " + tmp); } void ukuiXrdbManager::colorShade(QString name,GdkColor* color,double shade) { GdkColor tmp; tmp.red = midColor((color->red)*shade,0,0xFFFF); tmp.green = midColor((color->green)*shade,0,0xFFFF); tmp.blue = midColor((color->blue)*shade,0,0xFFFF); appendColor(name,&tmp); } ukui-settings-daemon/plugins/mpris/0000755000175000017500000000000014205117202016357 5ustar fengfengukui-settings-daemon/plugins/mpris/mpris-manager.cpp0000644000175000017500000002150314205117202021626 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "mpris-manager.h" #include const QString MPRIS_OBJECT_PATH = "/org/mpris/MediaPlayer2"; const QString MPRIS_INTERFACE = "org.mpris.MediaPlayer2.Player"; const QString MPRIS_PREFIX = "org.mpris.MediaPlayer2."; const QString DBUS_NAME = "org.ukui.SettingsDaemon"; const QString DBUS_PATH = "/org/ukui/SettingsDaemon"; const QString MEDIAKEYS_DBUS_NAME = DBUS_NAME + ".MediaKeys"; const QString MEDIAKEYS_DBUS_PATH = DBUS_PATH + "/MediaKeys"; /* Number of media players supported. * Correlates to the number of elements in BUS_NAMES */ /* Names to we want to watch */ const QStringList busNames ={"org.mpris.MediaPlayer2.audacious", "org.mpris.MediaPlayer2.clementine", "org.mpris.MediaPlayer2.vlc", "org.mpris.MediaPlayer2.mpd", "org.mpris.MediaPlayer2.exaile", "org.mpris.MediaPlayer2.banshee", "org.mpris.MediaPlayer2.rhythmbox", "org.mpris.MediaPlayer2.pragha", "org.mpris.MediaPlayer2.quodlibet", "org.mpris.MediaPlayer2.guayadeque", "org.mpris.MediaPlayer2.amarok", "org.mpris.MediaPlayer2.nuvolaplayer", "org.mpris.MediaPlayer2.xbmc", "org.mpris.MediaPlayer2.xnoise", "org.mpris.MediaPlayer2.gmusicbrowser", "org.mpris.MediaPlayer2.spotify", "org.mpris.MediaPlayer2.KylinVideo", }; MprisManager* MprisManager::mMprisManager = nullptr; MprisManager::MprisManager(QObject *parent):QObject(parent) { } MprisManager::~MprisManager() { } bool MprisManager::MprisManagerStart (GError **error) { QStringList list; QDBusConnection conn = QDBusConnection::sessionBus(); QDBusMessage tmpMsg,response ; mPlayerQuque = new QQueue(); mDbusWatcher = new QDBusServiceWatcher(); mDbusWatcher->setWatchMode(QDBusServiceWatcher::WatchForRegistration | QDBusServiceWatcher::WatchForUnregistration); mDbusWatcher->setConnection(conn); mDbusInterface = new QDBusInterface(DBUS_NAME,MEDIAKEYS_DBUS_PATH,MEDIAKEYS_DBUS_NAME, conn); USD_LOG(LOG_DEBUG,"Starting mpris manager"); /* Register all the names we wish to watch.*/ mDbusWatcher->setWatchedServices(busNames); mDbusWatcher->addWatchedService(DBUS_NAME); connect(mDbusWatcher, &QDBusServiceWatcher::serviceRegistered, this, &MprisManager::serviceRegisteredSlot); connect(mDbusWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &MprisManager::serviceUnregisteredSlot); if(!mDbusInterface->isValid()){ USD_LOG(LOG_ERR,"create %s failed",MEDIAKEYS_DBUS_NAME.toLatin1().data()); return false; } /** create a dbus method call by QDBusInterface。here we call GrabMediaPlayerKeys(QString) from "org.ukui.SettingsDaemon.MediaKeys", * you can find it's definition at media-keys mprismanager.cpp * * 通过QDBusInterface的方式创建一个dbus方法调用。这里我们调用的方法是来自org.ukui.SettingsDaemon.MediaKeys的 * GrabMediaPlayerKeys(QString), 你可以在media-keys插件内的mprismanager.cpp找到它的定义 */ response = mDbusInterface->call("GrabMediaPlayerKeys","UsdMpris"); if(QDBusMessage::ErrorMessage == response.ReplyMessage){ USD_LOG(LOG_ERR,"error: %s",response.errorMessage().toLatin1().data()); return false; } /** wait signal MediaPlayerKeyPressed() from "org.ukui.SettingsDaemon.MediaKeys" * you can find it's definition at media-keys mprismanager.h * * 等待连接来自于org.ukui.SettingsDaemon.MediaKeys的MediaPlayerKeyPressed()信号 * 你可以在media-keys 插件的 mrpismanager.h文件内找到它的定义 */ connect(mDbusInterface,SIGNAL(MediaPlayerKeyPressed(QString,QString)), this,SLOT(keyPressed(QString,QString))); // connect(mDbusInterface, &QDBusInterface::) return true; } void MprisManager::MprisManagerStop() { USD_LOG(LOG_DEBUG,"Stopping mpris manager"); delete mDbusInterface; mDbusInterface = nullptr; delete mDbusWatcher; mDbusWatcher = nullptr; mPlayerQuque->clear(); delete mPlayerQuque; mPlayerQuque = nullptr; } MprisManager* MprisManager::MprisManagerNew() { if(nullptr == mMprisManager) mMprisManager = new MprisManager(); return mMprisManager; } /** Returns the name of the media player. * @name if @name=="org.mpris.MediaPlayer2.vlc" * @return then @return=="vlc" */ QString getPlayerName(const QString& name) { QString ret_name=name.section(".", 3, 4); return ret_name; } void MprisManager::serviceRegisteredSlot(const QString& service) { QString realPlayername; USD_LOG(LOG_DEBUG,"MPRIS Name Registered: %s\n", service.toLatin1().data()); if(DBUS_NAME == service){ return; }else{ /* A media player was just run and should be * added to the head of @mPlayerQuque. */ realPlayername = getPlayerName(service); mPlayerQuque->push_front(realPlayername); } } /** * @brief MprisManager::serviceUnregisteredSlot * if anyone dbus service that from @busNames quit,this func will be called. * 如果来自于@busNames的任意一个dbus服务关闭,则该函数被执行 * @param service * for example: @service can be "org.mpris.MediaPlayer2.vlc" */ void MprisManager::serviceUnregisteredSlot(const QString& service) { QString realPlayername; USD_LOG(LOG_DEBUG,"MPRIS Name Unregistered: %s\n", service.toLatin1().data()); if(DBUS_NAME == service){ if(nullptr != mDbusInterface){ delete mDbusInterface; mDbusInterface = nullptr; } }else{ /* A media player quit running and should be removed from @mPlayerQueue. * 一个媒体播放器退出时应当从@mPlayerQueue中移除 */ realPlayername = getPlayerName(service); if(mPlayerQuque->contains(realPlayername)) mPlayerQuque->removeOne(realPlayername); } } /** * @brief MprisManager::keyPressed * after catch MediaPlayerKeyPressed() signal, this function will be called * 在接收到MediaPlayerKeyPressed() signal后,这个函数将被调用 * @param application @application=="UsdMpris" is true * @param operation * we control media player by @operation value,for example: play 、pause 、stop * 我们通过@operation的值去控制媒体播放器,如: 播放、暂停、停止 */ void MprisManager::keyPressed(QString application,QString operation) { QString mprisKey = nullptr; QString mprisHead,mprisName; QDBusMessage playerMsg,response; if("UsdMpris" != application) return; if(mPlayerQuque->isEmpty()) return; if("Play" == operation) mprisKey = "PlayPause"; else if("Pause" == operation) mprisKey = "Pause"; else if("Previous" == operation) mprisKey = "Previous"; else if("Next" == operation) mprisKey = "Next"; else if("Stop" == operation) mprisKey = "Stop"; if(mprisKey.isNull()) return; mprisHead = mPlayerQuque->head(); mprisName = MPRIS_PREFIX + mprisHead; /* create a dbus method call by QDBusMessage, the @mprisName is a member of @busNames * 通过QDBusMessage的方式创建一个dbus方法调用,@mprisName 来自于 @busNames */ USD_LOG(LOG_DEBUG,"mprisHead:%s mpriName:%s.",mprisHead.toLatin1().data(),mprisName.toLatin1().data()); playerMsg = QDBusMessage::createMethodCall(mprisName,MPRIS_OBJECT_PATH,MPRIS_INTERFACE,mprisKey); response = QDBusConnection::sessionBus().call(playerMsg); if(response.type() == QDBusMessage::ErrorMessage) { USD_LOG(LOG_ERR,"error: %s",response.errorMessage().toLatin1().data()); } } ukui-settings-daemon/plugins/mpris/mpris.pro0000644000175000017500000000116614205117202020237 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-06-24T09:30:00 # #------------------------------------------------- QT -= gui QT += dbus TEMPLATE = lib TARGET = mpris CONFIG += c++11 plugin link_pkgconfig CONFIG -= app_bundle DEFINES += QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"mpris\\\" include($$PWD/../../common/common.pri) PKGCONFIG += \ glib-2.0 \ gio-2.0 SOURCES += \ mpris-manager.cpp \ mpris-plugin.cpp HEADERS += \ mpris-manager.h \ mpris-plugin.h mpris_lib.path = $${PLUGIN_INSTALL_DIRS} mpris_lib.files = $$OUT_PWD/libmpris.so INSTALLS += mpris_lib ukui-settings-daemon/plugins/mpris/mpris-plugin.h0000644000175000017500000000240014205117202021152 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MPRISPLUGIN_H #define MPRISPLUGIN_H #include "mpris-manager.h" #include "plugin-interface.h" class MprisPlugin : public PluginInterface{ public: static PluginInterface* getInstance(); virtual void activate(); virtual void deactivate(); private: MprisPlugin(); MprisPlugin(MprisPlugin&)=delete; ~MprisPlugin(); MprisManager* mprisManager; static PluginInterface* mInstance; }; extern "C" PluginInterface* Q_DECL_EXPORT createSettingsPlugin(); #endif /* MPRISPLUGIN_H */ ukui-settings-daemon/plugins/mpris/mpris-manager.h0000644000175000017500000000356514205117202021303 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MPRISMANAGER_H #define MPRISMANAGER_H #include #include #include #include #include #include /** undef 'signals' from qt,avoid conflict with Glib * undef qt中的 'signals' 关键字,避免与 Glib 冲突 */ #ifdef __cplusplus extern "C" { #endif #include "clib-syslog.h" #ifdef __cplusplus } #endif #ifdef signals #undef signals #endif #include //for GError class MprisManager : public QObject{ Q_OBJECT public: ~MprisManager(); static MprisManager* MprisManagerNew(); bool MprisManagerStart(GError **error); void MprisManagerStop(); private: MprisManager(QObject *parent = nullptr); MprisManager(const MprisManager&) = delete; private Q_SLOTS: void serviceRegisteredSlot(const QString&); void serviceUnregisteredSlot(const QString&); void keyPressed(QString,QString); private: static MprisManager *mMprisManager; QDBusServiceWatcher *mDbusWatcher; QDBusInterface *mDbusInterface; QQueue *mPlayerQuque; }; #endif /* MPRISMANAGER_H */ ukui-settings-daemon/plugins/mpris/mpris.ukui-settings-plugin.in0000644000175000017500000000024414205117202024147 0ustar fengfeng[UKUI Settings Plugin] Module=mpris IAge=0 _Name=Mpris _Description=Mpris plugin Authors=Stefano Karapetsas Copyright=Copyright © 2013 Stefano Karapetsas Website= ukui-settings-daemon/plugins/mpris/mpris-plugin.cpp0000644000175000017500000000361314205117202021514 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mpris-plugin.h" #include "clib-syslog.h" PluginInterface* MprisPlugin::mInstance = nullptr; MprisPlugin::MprisPlugin() { USD_LOG(LOG_DEBUG,"UsdMprisPlugin initializing!"); mprisManager = MprisManager::MprisManagerNew(); } MprisPlugin::~MprisPlugin() { USD_LOG(LOG_DEBUG,"UsdMprisPlugin deconstructor!"); if(mprisManager) delete mprisManager; } void MprisPlugin::activate() { gboolean res; GError *error; USD_LOG (LOG_DEBUG, "Activating %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); error = NULL; res = mprisManager->MprisManagerStart(&error); if (! res) { USD_LOG(LOG_WARNING,"Unable to start mpris manager: %s", error->message); g_error_free (error); } } void MprisPlugin::deactivate() { USD_LOG(LOG_DEBUG,"Deactivating mpris plugin"); mprisManager->MprisManagerStop(); } PluginInterface* MprisPlugin::getInstance() { if(nullptr == mInstance) mInstance = new MprisPlugin(); return mInstance; } PluginInterface* createSettingsPlugin() { return MprisPlugin::getInstance(); } ukui-settings-daemon/plugins/tablet-mode/0000755000175000017500000000000014205117202017422 5ustar fengfengukui-settings-daemon/plugins/tablet-mode/tabletMode-plugin.h0000644000175000017500000000253114205117202023150 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef TABLETMODEPLUGIN_H #define TABLETMODEPLUGIN_H #include #include "plugin-interface.h" #include "tabletMode-manager.h" class TabletModePlugin : public PluginInterface { private: TabletModePlugin(); TabletModePlugin(TabletModePlugin&)=delete; public: ~TabletModePlugin(); static PluginInterface *getInstance(); virtual void activate(); virtual void deactivate(); private: static TabletModeManager *mTableManager; static PluginInterface *mInstance; }; extern "C" Q_DECL_EXPORT PluginInterface *createSettingsPlugin(); #endif // TABLETMODEPLUGIN_H ukui-settings-daemon/plugins/tablet-mode/tabletMode-manager.h0000644000175000017500000000356614205117202023275 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef TABLETMODEMANAGET_H #define TABLETMODEMANAGET_H #include #include #include #include #include #include class TabletModeManager : public QObject { Q_OBJECT private: TabletModeManager(); TabletModeManager(TabletModeManager&)=delete; TabletModeManager&operator=(const TabletModeManager&)=delete; public: ~TabletModeManager(); static TabletModeManager *TabletModeManagerNew(); bool TabletModeManagerStart(); void TabletModeManagerStop(); void SetEnabled(bool enabled); void setConfig(KSharedConfig::Ptr config) { mConfig = std::move(config); } public Q_SLOTS: void TabletUpdateState(); void TabletRefresh(); void TabletSettingsChanged(const bool tablemode); private: QDBusInterface *t_DbusTableMode; bool mEnabled = false; QGSettings *mXrandrSettings; QGSettings *mTableSettings; static TabletModeManager *mTabletManager; QOrientationSensor *mSensor; KSharedConfig::Ptr mConfig; }; #endif // TABLETMODEMANAGET_H ukui-settings-daemon/plugins/tablet-mode/tabletMode-manager.cpp0000644000175000017500000001372114205117202023622 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "tabletMode-manager.h" #define SETTINGS_XRANDR_SCHEMAS "org.ukui.SettingsDaemon.plugins.xrandr" #define XRANDR_ROTATION_KEY "xrandr-rotations" #define SETTINGS_TABLET_SCHEMAS "org.ukui.SettingsDaemon.plugins.tablet-mode" #define TABLET_AUTO_KEY "auto-rotation" #define TABLET_MODE_KEY "tablet-mode" TabletModeManager *TabletModeManager::mTabletManager = nullptr; TabletModeManager::TabletModeManager() { mSensor = new QOrientationSensor(this); mXrandrSettings = new QGSettings(SETTINGS_XRANDR_SCHEMAS); mTableSettings = new QGSettings(SETTINGS_TABLET_SCHEMAS); t_DbusTableMode = new QDBusInterface("com.kylin.statusmanager.interface","/","com.kylin.statusmanager.interface",QDBusConnection::sessionBus(),this); if (t_DbusTableMode->isValid()) { connect(t_DbusTableMode, SIGNAL(mode_change_signal(bool)),this,SLOT(TabletSettingsChanged(bool))); //USD_LOG(LOG_DEBUG, ".."); } else { //USD_LOG(LOG_DEBUG, "..."); } } TabletModeManager::~TabletModeManager() { if(mTabletManager) delete mTabletManager; if(mSensor) delete mSensor; if(mXrandrSettings) delete mXrandrSettings; if(mTableSettings) delete mTableSettings; } TabletModeManager *TabletModeManager::TabletModeManagerNew() { if(nullptr == mTabletManager) mTabletManager = new TabletModeManager(); return mTabletManager; } void TabletModeManager::TabletUpdateState() { mSensor->reading(); QOrientationReading *reading = mSensor->reading(); switch (reading->orientation()) { case QOrientationReading::Undefined: // qDebug("return TabletModeManager::Orientation::Undefined"); //return TabletModeManager::Orientation::Undefined; break; case QOrientationReading::TopUp: // qDebug("return TabletModeManager::Orientation::TopUp"); mXrandrSettings->setEnum(XRANDR_ROTATION_KEY,0); break; case QOrientationReading::TopDown: // qDebug("return TabletModeManager::Orientation::TopDown"); mXrandrSettings->setEnum(XRANDR_ROTATION_KEY,2); break; case QOrientationReading::LeftUp: // qDebug("return TabletModeManager::Orientation::LeftUp"); mXrandrSettings->setEnum(XRANDR_ROTATION_KEY,1); break; case QOrientationReading::RightUp: // qDebug("return TabletModeManager::Orientation::RightUp"); mXrandrSettings->setEnum(XRANDR_ROTATION_KEY,3); break; case QOrientationReading::FaceUp: // qDebug("return TabletModeManager::Orientation::FaceUp"); break; case QOrientationReading::FaceDown: // qDebug("return TabletModeManager::Orientation::FaceDown"); break; default: Q_UNREACHABLE(); } } void TabletModeManager::TabletRefresh() { // qDebug()<<__func__; if(mSensor->isActive()){ // qDebug()<isActive(); TabletUpdateState(); } else { // qDebug()<isActive(); } } void TabletModeManager::SetEnabled(bool enabled) { if(mEnabled == enabled) return; mEnabled = enabled; if (mEnabled) { TabletRefresh(); QDBusConnection::sessionBus().registerObject(QStringLiteral("/Orientation"), this); } else { QDBusConnection::sessionBus().unregisterObject(QStringLiteral("/Orientation")); } if (mEnabled) { mSensor->start(); } else { mSensor->stop(); } } void TabletModeManager::TabletSettingsChanged(const bool tablemode) { // bool rotations, table; // rotations = mTableSettings->get(TABLET_AUTO_KEY).toBool(); // table = mTableSettings->get(TABLET_MODE_KEY).toBool(); // if(table) // SetEnabled(rotations); if(tablemode){ QDBusMessage message = QDBusMessage::createSignal("/KGlobalSettings", "org.kde.KGlobalSettings", "send_to_client"); message << bool(1); QDBusConnection::sessionBus().send(message); }else{ QDBusMessage message = QDBusMessage::createSignal("/KGlobalSettings", "org.kde.KGlobalSettings", "send_to_client"); message << bool(0); QDBusConnection::sessionBus().send(message); } mTableSettings->set(TABLET_MODE_KEY, tablemode); } bool TabletModeManager::TabletModeManagerStart() { // qDebug("TabletMode Manager Start"); bool rotations, table; rotations = mTableSettings->get(TABLET_AUTO_KEY).toBool(); table = mTableSettings->get(TABLET_MODE_KEY).toBool(); connect(mSensor,SIGNAL(readingChanged()),this,SLOT(TabletUpdateState())); connect(mSensor,SIGNAL(activeChanged()),this,SLOT(TabletRefresh())); connect(mTableSettings,SIGNAL(changed(QString)),this,SLOT(TabletSettingsChanged(QString))); if(table) SetEnabled(rotations); return true; } void TabletModeManager::TabletModeManagerStop() { SetEnabled(false); // qDebug("TabletMode Manager stop"); } ukui-settings-daemon/plugins/tablet-mode/tablet-mode.pro0000644000175000017500000000120214205117202022334 0ustar fengfengQT += gui widgets x11extras dbus sensors KConfigCore KConfigGui TEMPLATE = lib CONFIG += c++11 plugin link_pkgconfig DEFINES += TABLETMODE_LIBRARY DEFINES += QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"tablet-mode\\\" include($$PWD/../../common/common.pri) INCLUDEPATH += \ -I ukui-settings-daemon/ \ PKGCONFIG += \ xrandr x11 \ glib-2.0 SOURCES += \ tabletMode-manager.cpp \ tabletMode-plugin.cpp HEADERS += \ tabletMode-manager.h \ tabletMode-plugin.h tablet_mode_lib.path = $${PLUGIN_INSTALL_DIRS} tablet_mode_lib.files = $$OUT_PWD/libtablet-mode.so INSTALLS += tablet_mode_lib ukui-settings-daemon/plugins/tablet-mode/tabletMode-plugin.cpp0000644000175000017500000000361614205117202023510 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "tabletMode-plugin.h" #include "clib-syslog.h" PluginInterface *TabletModePlugin::mInstance = nullptr; TabletModeManager *TabletModePlugin::mTableManager = nullptr; TabletModePlugin::TabletModePlugin() { USD_LOG(LOG_DEBUG,"TabletMode Plugin initializing"); if(nullptr == mTableManager) mTableManager = TabletModeManager::TabletModeManagerNew(); } TabletModePlugin::~TabletModePlugin() { if(mTableManager) { delete mTableManager; mTableManager = nullptr; } } void TabletModePlugin::activate() { USD_LOG (LOG_DEBUG, "Activating %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); bool res; res = mTableManager->TabletModeManagerStart(); if(!res) qWarning("Unable to start Tablet manager"); } PluginInterface *TabletModePlugin::getInstance() { if(nullptr == mInstance) mInstance = new TabletModePlugin(); return mInstance; } void TabletModePlugin::deactivate() { USD_LOG(LOG_DEBUG,"Deactivating Xrandr plugin"); mTableManager->TabletModeManagerStop(); } PluginInterface *createSettingsPlugin() { return TabletModePlugin::getInstance(); } ukui-settings-daemon/plugins/color/0000755000175000017500000000000014205117202016343 5ustar fengfengukui-settings-daemon/plugins/color/color-state.h0000644000175000017500000001112014205117202020743 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef COLORSTATE_H #define COLORSTATE_H #include #include #include #include #include #include #include #include "color-edid.h" #include "usd_base_class.h" extern "C" { #define MATE_DESKTOP_USE_UNSTABLE_API #include #include "clib-syslog.h" } #ifdef GDK_WINDOWING_X11 #include #endif class ColorState : public QObject { Q_OBJECT public: ColorState(); ColorState(ColorState&)=delete; ~ColorState(); bool ColorStateStart(); void ColorStateStop(); public: void ColorStateSetTemperature(guint temperature); static bool GetSystemIccProfile (ColorState *state, GFile *file); static gchar *SessionGetOutputId (ColorState *state, MateRROutput *output); static ColorEdid *SessionGetOutputEdid (ColorState *state, MateRROutput *output); static bool SessionUseOutputProfileForScreen (ColorState *state, MateRROutput *output); static bool SessionScreenSetIccProfile (ColorState *state, const gchar *filename, GError **error); static MateRROutput *SessionGetStateOutputById (ColorState *state, const gchar *device_id); static gboolean SessionCheckProfileDeviceMd (GFile *file); static bool ApplyCreateIccProfileForEdid (ColorState *state, CdDevice *device, ColorEdid *edid, GFile *file, GError **error); static bool SessionDeviceResetGamma (MateRROutput *output, guint color_temperature); static void SessionDeviceAssignProfileConnectCb (GObject *object, GAsyncResult *res, gpointer user_data); static void SessionAddStateOutput (ColorState *state, MateRROutput *output); static void SessionProfileGammaFindDeviceCb (GObject *object, GAsyncResult *res, gpointer user_data); static void SessionDeviceAssignConnectCb (GObject *object, GAsyncResult *res, gpointer user_data); static void SessionClientConnectCb (GObject *source_object, GAsyncResult *res, gpointer user_data); static void SessionSetGammaForAllDevices (ColorState *state); static void SessionGetDevicesCb (GObject *object, GAsyncResult *res, gpointer user_data); static void SessionDeviceAssign (ColorState *state, CdDevice *device); static void SessionDeviceChangedAssignCb (CdClient *client, CdDevice *device, ColorState *stata); static void SessionDeviceAddedAssignCb (CdClient *client, CdDevice *device, ColorState *state); static void MateRrScreenOutputChangedCb (MateRRScreen *screen, ColorState *state); private: GCancellable *cancellable; CdClient *client; MateRRScreen *state_screen; GHashTable *edid_cache; GdkWindow *gdk_window; GHashTable *device_assign_hash; guint color_temperature; }; #endif // COLORSTATE_H ukui-settings-daemon/plugins/color/color-profiles.cpp0000644000175000017500000001544714205117202022021 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "color-profiles.h" static void SessionCreateProfileCb (GObject *object, GAsyncResult *res, gpointer user_data) { CdProfile *profile; GError *error = NULL; CdClient *client = CD_CLIENT (object); profile = cd_client_create_profile_finish (client, res, &error); if (profile == NULL) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) && !g_error_matches (error, CD_CLIENT_ERROR, CD_CLIENT_ERROR_ALREADY_EXISTS)) g_warning ("%s", error->message); g_error_free (error); return; } g_object_unref (profile); } static void SessionDeleteProfileCb (GObject *object, GAsyncResult *res, gpointer user_data) { gboolean ret; GError *error = NULL; CdClient *client = CD_CLIENT (object); ret = cd_client_delete_profile_finish (client, res, &error); if (!ret) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) g_warning ("%s", error->message); g_error_free (error); } } void ColorProfiles::SessionFindProfileByFilenameCb (GObject *object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; CdProfile *profile; CdClient *client = CD_CLIENT (object); ColorProfiles *profiles = (ColorProfiles *)user_data; profile = cd_client_find_profile_by_filename_finish (client, res, &error); if (profile == NULL) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) g_warning ("%s", error->message); g_error_free (error); goto out; } /* remove it from colord */ cd_client_delete_profile (profiles->client, profile, profiles->cancellable, SessionDeleteProfileCb, profiles); out: if (profile != NULL) g_object_unref (profile); } void ColorProfiles::SessionIccStoreAddedCb (CdIccStore *icc_store, CdIcc *icc, ColorProfiles *profiles) { cd_client_create_profile_for_icc (profiles->client, icc, CD_OBJECT_SCOPE_TEMP, profiles->cancellable, SessionCreateProfileCb, profiles); } void ColorProfiles::SessionIccStoreRemovedCb (CdIccStore *icc_store, CdIcc *icc, ColorProfiles *profiles) { /* find the ID for the filename */ // qDebug ("filename %s removed", cd_icc_get_filename (icc)); cd_client_find_profile_by_filename (profiles->client, cd_icc_get_filename (icc), profiles->cancellable, SessionFindProfileByFilenameCb, profiles); } ColorProfiles::ColorProfiles() { cancellable = nullptr; client = cd_client_new (); icc_store = cd_icc_store_new (); cd_icc_store_set_load_flags (icc_store, CD_ICC_LOAD_FLAGS_FALLBACK_MD5); g_signal_connect (icc_store, "added", G_CALLBACK (SessionIccStoreAddedCb), this); g_signal_connect (icc_store, "removed", G_CALLBACK (SessionIccStoreRemovedCb), this); } ColorProfiles::~ColorProfiles() { g_cancellable_cancel (cancellable); g_clear_object (&cancellable); g_clear_object (&icc_store); g_clear_object (&client); } void ColorProfiles::SessionClientConnectCb (GObject *source_object, GAsyncResult *res, gpointer user_data) { gboolean ret; GError *error = NULL; CdClient *client = CD_CLIENT (source_object); ColorProfiles *profiles; /* connected */ ret = cd_client_connect_finish (client, res, &error); if (!ret) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { USD_LOG(LOG_DEBUG,"failed to connect to colord: %s", error->message); } g_error_free (error); return; } /* is there an available colord instance? */ profiles = (ColorProfiles *)user_data; ret = cd_client_get_has_server (profiles->client); if (!ret) { USD_LOG(LOG_DEBUG,"There is no colord server available"); return; } /* add profiles */ ret = cd_icc_store_search_kind (profiles->icc_store, CD_ICC_STORE_SEARCH_KIND_USER, CD_ICC_STORE_SEARCH_FLAGS_CREATE_LOCATION, profiles->cancellable, &error); if (!ret) { g_error_free (error); USD_LOG(LOG_DEBUG,"failed to add user icc: %s", error->message); } USD_LOG(LOG_DEBUG,"SessionClientConnectCb over.."); } bool ColorProfiles::ColorProfilesStart() { /* use a fresh cancellable for each start->stop operation */ g_cancellable_cancel (cancellable); g_clear_object (&cancellable); cancellable = g_cancellable_new (); cd_client_connect (client, cancellable, SessionClientConnectCb, this); return true; } void ColorProfiles::ColorProfilesStop() { g_cancellable_cancel (cancellable); } ukui-settings-daemon/plugins/color/color-edid.h0000644000175000017500000000512214205117202020535 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef COLOREDID_H #define COLOREDID_H #include #include extern "C"{ #include #include "clib-syslog.h" } #define USD_COLOR_TEMPERATURE_MIN 1000 /* Kelvin */ #define USD_COLOR_TEMPERATURE_DEFAULT 6500 /* Kelvin, is RGB [1.0,1.0,1.0] */ #define USD_COLOR_TEMPERATURE_MAX 10000 /* Kelvin */ class ColorEdid { public: ColorEdid(); void EdidReset (); gboolean EdidParse (const guint8 *data, gsize length); const gchar *EdidGetMonitorName (); const gchar *EdidGetVendorName (); const gchar *EdidGetSerialNumber (); const gchar *EdidGetEisaId (); const gchar *EdidGetChecksum (); const gchar *EdidGetPnpId (); guint EdidGetWidth (); guint EdidGetHeight (); gfloat EdidGetGamma (); const CdColorYxy *EdidGetRed (); const CdColorYxy *EdidGetGreen (); const CdColorYxy *EdidGetBlue (); const CdColorYxy *EdidGetWhite (); private: gchar *monitor_name; gchar *vendor_name; gchar *serial_number; gchar *eisa_id; gchar *checksum; gchar *pnp_id; guint width; guint height; gfloat gamma; CdColorYxy *red; CdColorYxy *green; CdColorYxy *blue; CdColorYxy *white; GnomePnpIds *pnp_ids; }; #endif // COLOREDID_H ukui-settings-daemon/plugins/color/color-manager.h0000644000175000017500000000642114205117202021245 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef COLORMANAGER_H #define COLORMANAGER_H #include #include #include #include #include #include "color-state.h" #include "color-profiles.h" #define USD_COLOR_TEMPERATURE_MIN 1000 /* Kelvin */ #define USD_COLOR_TEMPERATURE_DEFAULT 6500 /* Kelvin, is RGB [1.0,1.0,1.0] */ #define USD_COLOR_TEMPERATURE_MAX 10000 /* Kelvin */ class ColorManager : public QObject { Q_OBJECT private: ColorManager(); ColorManager(ColorManager&)=delete; ColorManager&operator=(const ColorManager&)=delete; public: ~ColorManager(); static ColorManager* ColorManagerNew(); bool ColorManagerStart(); void ColorManagerStop(); void StartGeoclue(); void StopGeoclue(); static void OnGeoclueSimpleReady (GObject *source_object, GAsyncResult *res, gpointer user_data); static void OnLocationNotify (GClueSimple *simple, GParamSpec *pspec, gpointer user_data); static void NightLightRecheck(ColorManager *manager); GDateTime *NightLightGetDateTimeNow(); void PollSmoothCreate (double temperature); void PollSmoothDestroy (); void NightLightSetTemperatureInternal (double temperature); void NightLightSetTemperature(double temperature); static bool NightLightSmoothCb (ColorManager *manager); void NightLightSetActive(bool active); bool UpdateCachedSunriseSunset(); bool ReadKwinColorTempConfig(); public Q_SLOTS: void SettingsChangedCb(QString); void checkTime(); private: static ColorManager *mColorManager; ColorProfiles *mColorProfiles; ColorState *mColorState; QGSettings *settings; QGSettings *gtk_settings; QGSettings *qt_settings; bool forced; GSource *source; bool geoclue_enabled; bool smooth_enabled; bool cached_active; double cached_sunrise; double cached_sunset; double cached_temperature; bool disabled_until_tmw; GDateTime *disabled_until_tmw_dt; GDateTime *datetime_override; GTimer *smooth_timer; QTimer *m_NightChecktimer; guint smooth_id; double smooth_target_temperature; GCancellable *cancellable; GClueClient *geoclue_client; GClueSimple *geoclue_simple; QHash mNightConfig; }; #endif // COLORMANAGER_H ukui-settings-daemon/plugins/color/color-plugin.cpp0000644000175000017500000000376614205117202021475 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "color-plugin.h" #include "usd_base_class.h" PluginInterface *ColorPlugin::mInstance = nullptr; ColorManager *ColorPlugin::mColorManager = nullptr; ColorPlugin::ColorPlugin() { if(UsdBaseClass::isLoongarch()){ return; } USD_LOG (LOG_DEBUG , "new %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); if(nullptr == mColorManager) mColorManager = ColorManager::ColorManagerNew(); } ColorPlugin::~ColorPlugin() { if(mColorManager) delete mColorManager; } void ColorPlugin::activate() { if(UsdBaseClass::isLoongarch()){ return; } USD_LOG (LOG_DEBUG, "Activating %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); bool res = mColorManager->ColorManagerStart(); if(!res) qWarning("Unable to start Color manager!"); } void ColorPlugin::deactivate() { USD_LOG (LOG_DEBUG, "deactivate %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); mColorManager->ColorManagerStop(); } PluginInterface *ColorPlugin::getInstance() { if(nullptr == mInstance) mInstance = new ColorPlugin(); return mInstance; } PluginInterface *createSettingsPlugin() { return ColorPlugin::getInstance(); } ukui-settings-daemon/plugins/color/color-info.h0000644000175000017500000000262514205117202020570 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef COLORINFO_H #define COLORINFO_H #include #include #include #include struct ColorInfo { QString arg; QDBusVariant out; }; QDBusArgument &operator<<(QDBusArgument &argument, const ColorInfo &mystruct) { argument.beginStructure(); argument << mystruct.arg << mystruct.out; argument.endStructure(); return argument; } const QDBusArgument &operator>>(const QDBusArgument &argument, ColorInfo &mystruct) { argument.beginStructure(); argument >> mystruct.arg >> mystruct.out; argument.endStructure(); return argument; } Q_DECLARE_METATYPE(ColorInfo) #endif // COLORINFO_H ukui-settings-daemon/plugins/color/color-profiles.h0000644000175000017500000000401614205117202021454 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef COLORPROFILES_H #define COLORPROFILES_H #include #include "config.h" #include #include #include extern "C"{ #include "clib-syslog.h" } class ColorProfiles : public QObject { Q_OBJECT public: ColorProfiles(); ColorProfiles(ColorProfiles&)=delete; ~ColorProfiles(); bool ColorProfilesStart(); void ColorProfilesStop(); public: static void SessionIccStoreAddedCb (CdIccStore *icc_store, CdIcc *icc, ColorProfiles *profiles); static void SessionIccStoreRemovedCb (CdIccStore *icc_store, CdIcc *icc, ColorProfiles *profiles); static void SessionFindProfileByFilenameCb (GObject *object, GAsyncResult *res, gpointer user_data); static void SessionClientConnectCb (GObject *source_object, GAsyncResult *res, gpointer user_data); private: GCancellable *cancellable; CdClient *client; CdIccStore *icc_store; }; #endif // COLORPROFILES_H ukui-settings-daemon/plugins/color/color-edid.cpp0000644000175000017500000002217114205117202021073 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "color-edid.h" #define EDID_OFFSET_PNPID 0x08 #define EDID_OFFSET_SERIAL 0x0c #define EDID_OFFSET_SIZE 0x15 #define EDID_OFFSET_GAMMA 0x17 #define EDID_OFFSET_DATA_BLOCKS 0x36 #define EDID_OFFSET_LAST_BLOCK 0x6c #define EDID_OFFSET_EXTENSION_BLOCK_COUNT 0x7e #define DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc #define DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff #define DESCRIPTOR_COLOR_MANAGEMENT_DATA 0xf9 #define DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe #define DESCRIPTOR_COLOR_POINT 0xfb ColorEdid::ColorEdid() { pnp_ids = gnome_pnp_ids_new (); pnp_id = g_new0 (gchar, 4); red = cd_color_yxy_new (); green = cd_color_yxy_new (); blue = cd_color_yxy_new (); white = cd_color_yxy_new (); } const gchar *ColorEdid::EdidGetMonitorName () { return monitor_name; } const gchar *ColorEdid::EdidGetVendorName () { if (vendor_name == NULL) vendor_name = gnome_pnp_ids_get_pnp_id (pnp_ids, pnp_id); return vendor_name; } const gchar *ColorEdid::EdidGetSerialNumber () { return serial_number; } const gchar *ColorEdid::EdidGetEisaId () { return eisa_id; } const gchar *ColorEdid::EdidGetChecksum () { return checksum; } const gchar *ColorEdid::EdidGetPnpId () { return pnp_id; } guint ColorEdid::EdidGetWidth () { return width; } guint ColorEdid::EdidGetHeight () { return height; } gfloat ColorEdid::EdidGetGamma () { return gamma; } const CdColorYxy *ColorEdid::EdidGetRed () { return red; } const CdColorYxy *ColorEdid::EdidGetGreen () { return green; } const CdColorYxy *ColorEdid::EdidGetBlue () { return blue; } const CdColorYxy *ColorEdid::EdidGetWhite () { return white; } void ColorEdid::EdidReset () { /* free old data */ /* g_free (monitor_name); g_free (vendor_name); g_free (serial_number); g_free (eisa_id); g_free (checksum); */ /* do not deallocate, just blank */ pnp_id[0] = '\0'; /* set to default values */ monitor_name = NULL; vendor_name = NULL; serial_number = NULL; eisa_id = NULL; checksum = NULL; width = 0; height = 0; gamma = 0.0f; } static gint EdidGetBit (gint in, gint bit) { return (in & (1 << bit)) >> bit; } /** * EdidGetBits: **/ static gint EdidGetBits (gint in, gint begin, gint end) { gint mask = (1 << (end - begin + 1)) - 1; return (in >> begin) & mask; } /** * edid_decode_fraction: **/ static gdouble EdidDecodeFraction (gint high, gint low) { gdouble result = 0.0; gint i; high = (high << 2) | low; for (i = 0; i < 10; ++i) result += EdidGetBit (high, i) * pow (2, i - 10); return result; } static gchar * EdidParseString (const guint8 *data) { gchar *text; guint i; guint replaced = 0; /* this is always 13 bytes, but we can't guarantee it's null * terminated or not junk. */ text = g_strndup ((const gchar *) data, 13); /* remove insane newline chars */ g_strdelimit (text, "\n\r", '\0'); /* remove spaces */ g_strchomp (text); /* nothing left? */ if (text[0] == '\0') { g_free (text); text = NULL; goto out; } /* ensure string is printable */ for (i = 0; text[i] != '\0'; i++) { if (!g_ascii_isprint (text[i])) { text[i] = '-'; replaced++; } } /* if the string is junk, ignore the string */ if (replaced > 4) { g_free (text); text = NULL; goto out; } out: return text; } gboolean ColorEdid::EdidParse (const guint8 *data, gsize length) { gboolean ret = TRUE; guint i; guint32 serial; gchar *tmp; /* check header */ if (length < 128) { USD_LOG(LOG_DEBUG,"EDID length is too small"); ret = FALSE; goto out; } if (data[0] != 0x00 || data[1] != 0xff) { USD_LOG(LOG_DEBUG,"Failed to parse EDID header"); ret = FALSE; goto out; } /* free old data */ EdidReset (); /* decode the PNP ID from three 5 bit words packed into 2 bytes * /--08--\/--09--\ * 7654321076543210 * |\---/\---/\---/ * R C1 C2 C3 */ pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID+0] & 0x7c) / 4) - 1; pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID+0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID+1] & 0xe0) / 32) - 1; pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID+1] & 0x1f) - 1; /* maybe there isn't a ASCII serial number descriptor, so use this instead */ serial = (guint32) data[EDID_OFFSET_SERIAL+0]; serial += (guint32) data[EDID_OFFSET_SERIAL+1] * 0x100; serial += (guint32) data[EDID_OFFSET_SERIAL+2] * 0x10000; serial += (guint32) data[EDID_OFFSET_SERIAL+3] * 0x1000000; if (serial > 0) serial_number = g_strdup_printf ("%" G_GUINT32_FORMAT, serial); /* get the size */ width = data[EDID_OFFSET_SIZE+0]; height = data[EDID_OFFSET_SIZE+1]; /* we don't care about aspect */ if (width == 0 || height == 0) { width = 0; height = 0; } /* get gamma */ if (data[EDID_OFFSET_GAMMA] == 0xff) { gamma = 1.0f; } else { gamma = ((gfloat) data[EDID_OFFSET_GAMMA] / 100) + 1; } /* get color red */ red->x = EdidDecodeFraction (data[0x1b], EdidGetBits (data[0x19], 6, 7)); red->y = EdidDecodeFraction (data[0x1c], EdidGetBits (data[0x19], 4, 5)); /* get color green */ green->x = EdidDecodeFraction (data[0x1d], EdidGetBits (data[0x19], 2, 3)); green->y = EdidDecodeFraction (data[0x1e], EdidGetBits (data[0x19], 0, 1)); /* get color blue */ blue->x = EdidDecodeFraction (data[0x1f], EdidGetBits (data[0x1a], 6, 7)); blue->y = EdidDecodeFraction (data[0x20], EdidGetBits (data[0x1a], 4, 5)); /* get color white */ white->x = EdidDecodeFraction (data[0x21], EdidGetBits (data[0x1a], 2, 3)); white->y = EdidDecodeFraction (data[0x22], EdidGetBits (data[0x1a], 0, 1)); /* parse EDID data */ for (i = EDID_OFFSET_DATA_BLOCKS; i <= EDID_OFFSET_LAST_BLOCK; i += 18) { /* ignore pixel clock data */ if (data[i] != 0) continue; if (data[i+2] != 0) continue; /* any useful blocks? */ if (data[i+3] == DESCRIPTOR_DISPLAY_PRODUCT_NAME) { tmp = EdidParseString (&data[i+5]); if (tmp != NULL) { g_free (monitor_name); monitor_name = tmp; } } else if (data[i+3] == DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) { tmp = EdidParseString (&data[i+5]); if (tmp != NULL) { g_free (serial_number); serial_number = tmp; } } else if (data[i+3] == DESCRIPTOR_COLOR_MANAGEMENT_DATA) { g_warning ("failing to parse color management data"); } else if (data[i+3] == DESCRIPTOR_ALPHANUMERIC_DATA_STRING) { tmp = EdidParseString (&data[i+5]); if (tmp != NULL) { g_free (eisa_id); eisa_id = tmp; } } else if (data[i+3] == DESCRIPTOR_COLOR_POINT) { if (data[i+3+9] != 0xff) { /* extended EDID block(1) which contains * a better gamma value */ gamma = ((gfloat) data[i+3+9] / 100) + 1; } if (data[i+3+14] != 0xff) { /* extended EDID block(2) which contains * a better gamma value */ gamma = ((gfloat) data[i+3+9] / 100) + 1; } } } /* calculate checksum */ checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5, data, length); out: return ret; } ukui-settings-daemon/plugins/color/color-plugin.h0000644000175000017500000000242414205117202021130 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef COLORPLUGIN_H #define COLORPLUGIN_H #include "plugin-interface.h" #include "color-manager.h" class ColorPlugin : public PluginInterface { private: ColorPlugin(); ColorPlugin(ColorPlugin&)=delete; public: ~ColorPlugin(); static PluginInterface *getInstance(); virtual void activate(); virtual void deactivate(); private: static ColorManager *mColorManager; static PluginInterface *mInstance; }; extern "C" Q_DECL_EXPORT PluginInterface *createSettingsPlugin(); #endif // COLORPLUGIN_H ukui-settings-daemon/plugins/color/color-state.cpp0000644000175000017500000013307714205117202021316 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "color-state.h" #include "config.h" typedef struct { guint32 red; guint32 green; guint32 blue; } MateRROutputClutItem; typedef struct { ColorState *state; CdProfile *profile; CdDevice *device; guint32 output_id; } SessionAsyncHelper; /* see http://www.oyranos.org/wiki/index.php?title=ICC_Profiles_in_X_Specification_0.3 */ #define USD_ICC_PROFILE_IN_X_VERSION_MAJOR 0 #define USD_ICC_PROFILE_IN_X_VERSION_MINOR 3 bool g_hadQuit = false; ColorState::ColorState() { #ifdef GDK_WINDOWING_X11 /* set the _ICC_PROFILE atoms on the root screen */ if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) gdk_window = gdk_screen_get_root_window (gdk_screen_get_default ()); #endif /* parsing the EDID is expensive */ edid_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); /* we don't want to assign devices multiple times at startup */ device_assign_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); /* default color temperature */ color_temperature = USD_COLOR_TEMPERATURE_DEFAULT; client = cd_client_new (); cancellable = nullptr; g_hadQuit = false; } ColorState::~ColorState() { g_hadQuit = true; g_cancellable_cancel (cancellable); g_clear_object (&cancellable); g_clear_object (&client); g_clear_pointer (&edid_cache, g_hash_table_destroy); g_clear_pointer (&device_assign_hash, g_hash_table_destroy); g_clear_object (&state_screen); } void ColorState::ColorStateSetTemperature(guint temperature) { if (color_temperature == temperature) { return; } if (g_hadQuit) { USD_LOG(LOG_DEBUG, "usd had quit can't set gamma..."); return; } if(temperature < USD_COLOR_TEMPERATURE_MIN) temperature = USD_COLOR_TEMPERATURE_MIN; if(temperature > USD_COLOR_TEMPERATURE_MAX) temperature = USD_COLOR_TEMPERATURE_MAX; color_temperature = temperature; USD_LOG(LOG_DEBUG,"color_temperature %d",color_temperature); SessionSetGammaForAllDevices (this); } ColorEdid *ColorState::SessionGetOutputEdid (ColorState *state, MateRROutput *output) { const guint8 *data; gsize size = 128; ColorEdid *edid = NULL; gboolean ret; /* can we find it in the cache */ edid = (ColorEdid *)g_hash_table_lookup (state->edid_cache, mate_rr_output_get_name (output)); if (edid != NULL) { return edid; } /* parse edid */ data = mate_rr_output_get_edid_data (output); if (data == nullptr) { // qDebug("unable to get EDID for output"); return nullptr; } edid = new ColorEdid (); ret = edid->EdidParse (data, size); if (!ret) { // delete edid; return nullptr; } /* add to cache */ g_hash_table_insert (state->edid_cache, g_strdup (mate_rr_output_get_name (output)), edid); return edid; } gchar *ColorState::SessionGetOutputId (ColorState *state, MateRROutput *output) { const gchar *name = nullptr; const gchar *serial = nullptr; const gchar *vendor = nullptr; ColorEdid *edid = NULL; GString *device_id; /* all output devices are prefixed with this */ device_id = g_string_new ("xrandr"); /* get the output EDID if possible */ edid = SessionGetOutputEdid (state, output); if (edid == NULL) { USD_LOG(LOG_ERR,"no edid for %s, falling back to connection name", mate_rr_output_get_name (output)); g_string_append_printf (device_id, "-%s", mate_rr_output_get_name (output)); goto out; } /* check EDID data is okay to use */ vendor = edid->EdidGetVendorName(); name = edid->EdidGetMonitorName(); serial = edid->EdidGetSerialNumber(); if (vendor == NULL && name == NULL && serial == NULL) { USD_LOG(LOG_ERR,"no edid for %s, falling back to connection name", mate_rr_output_get_name (output)); g_string_append_printf (device_id, "-%s", mate_rr_output_get_name (output)); goto out; } /* use EDID data */ if (vendor != NULL) g_string_append_printf (device_id, "-%s", vendor); if (name != NULL) g_string_append_printf (device_id, "-%s", name); if (serial != NULL) g_string_append_printf (device_id, "-%s", serial); out: if (edid != NULL) edid = nullptr; return g_string_free (device_id, FALSE); } static void SessionCreateDeviceCb (GObject *object, GAsyncResult *res, gpointer user_data) { CdDevice *device; GError *error = NULL; device = cd_client_create_device_finish (CD_CLIENT (object), res, &error); if (device == NULL) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) && !g_error_matches (error, CD_CLIENT_ERROR, CD_CLIENT_ERROR_ALREADY_EXISTS)) { qWarning ("failed to create device: %s", error->message); } g_error_free (error); return; } // fprintf(stderr, "success to create device\n"); g_object_unref (device); } void ColorState::SessionAddStateOutput (ColorState *state, MateRROutput *output) { const gchar *edid_checksum = NULL; const gchar *model = NULL; const gchar *output_name = NULL; const gchar *serial = NULL; const gchar *vendor = NULL; gboolean ret; gchar *device_id = NULL; ColorEdid *edid; GHashTable *device_props = NULL; /* VNC creates a fake device that cannot be color managed */ output_name = mate_rr_output_get_name (output); if (output_name != NULL && g_str_has_prefix (output_name, "VNC-")) { qDebug ("ignoring %s as fake VNC device detected", output_name); return; } /* try to get edid */ edid = SessionGetOutputEdid (state, output); if (edid == nullptr) { qWarning ("failed to get edid:"); } /* prefer DMI data for the internal output */ ret = mate_rr_output_is_laptop (output); if (ret) { model = cd_client_get_system_model (state->client); vendor = cd_client_get_system_vendor (state->client); } /* use EDID data if we have it */ if (edid != nullptr) { edid_checksum = edid->EdidGetChecksum(); if (model == NULL) model = edid->EdidGetMonitorName(); if (vendor == NULL) vendor = edid->EdidGetVendorName(); if (serial == NULL) serial = edid->EdidGetSerialNumber(); } /* ensure mandatory fields are set */ if (model == NULL) model = mate_rr_output_get_name (output); if (vendor == NULL) vendor = "unknown"; if (serial == NULL) serial = "unknown"; device_id = SessionGetOutputId (state, output); // qDebug ("output %s added", device_id); device_props = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_KIND, (gpointer) cd_device_kind_to_string (CD_DEVICE_KIND_DISPLAY)); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_MODE, (gpointer) cd_device_mode_to_string (CD_DEVICE_MODE_PHYSICAL)); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_COLORSPACE, (gpointer) cd_colorspace_to_string (CD_COLORSPACE_RGB)); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_VENDOR, (gpointer) vendor); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_MODEL, (gpointer) model); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_SERIAL, (gpointer) serial); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_METADATA_XRANDR_NAME, (gpointer) mate_rr_output_get_name (output)); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_METADATA_OUTPUT_PRIORITY, mate_rr_output_get_is_primary (output) ? (gpointer) CD_DEVICE_METADATA_OUTPUT_PRIORITY_PRIMARY : (gpointer) CD_DEVICE_METADATA_OUTPUT_PRIORITY_SECONDARY); if (edid_checksum != NULL) { g_hash_table_insert (device_props, (gpointer) CD_DEVICE_METADATA_OUTPUT_EDID_MD5, (gpointer) edid_checksum); } /* set this so we can call the device a 'Laptop Screen' in the * control center main panel */ if (mate_rr_output_is_laptop (output)) { g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_EMBEDDED, NULL); } cd_client_create_device (state->client, device_id, CD_OBJECT_SCOPE_TEMP, device_props, state->cancellable, SessionCreateDeviceCb, state); g_free (device_id); if (device_props != NULL) g_hash_table_unref (device_props); if (edid != nullptr) edid = nullptr; } static guint MateRrOutputGetGammaSize (MateRROutput *output) { MateRRCrtc *crtc; gint len = 0; crtc = mate_rr_output_get_crtc (output); if (crtc == NULL) return 0; mate_rr_crtc_get_gamma (crtc, &len, NULL, NULL, NULL); return (guint) len; } static void SessionAsyncHelperFree (SessionAsyncHelper *helper) { if (helper->state != NULL){ helper->state = NULL; } if (helper->profile != NULL) g_object_unref (helper->profile); /* * helper-device的引用计数一直是0,所以会报g_object_unref: assertion 'G_IS_OBJECT (object)' failed *if (helper->device != NULL) * g_object_unref (helper->device); */ g_free (helper); } static gboolean SessionOutputSetGamma (MateRROutput *output, GPtrArray *array) { gboolean ret = TRUE; guint16 *red = NULL; guint16 *green = NULL; guint16 *blue = NULL; guint i; MateRROutputClutItem *data; MateRRCrtc *crtc; /* no length? */ if (array->len == 0) { ret = FALSE; // qDebug("no data in the CLUT array"); goto out; } /* convert to a type X understands */ red = g_new (guint16, array->len); green = g_new (guint16, array->len); blue = g_new (guint16, array->len); for (i = 0; i < array->len; i++) { data = (MateRROutputClutItem *)g_ptr_array_index (array, i); red[i] = data->red; green[i] = data->green; blue[i] = data->blue; } /* send to LUT */ crtc = mate_rr_output_get_crtc (output); if (crtc == NULL) { ret = FALSE; // qDebug("failed to get ctrc for %s",mate_rr_output_get_name (output)); goto out; } mate_rr_crtc_set_gamma (crtc, array->len, red, green, blue); out: g_free (red); g_free (green); g_free (blue); return ret; } bool ColorState::SessionDeviceResetGamma(MateRROutput *output, guint color_temperature) { bool ret; guint i; guint size; guint32 value; GPtrArray *clut; MateRROutputClutItem *data; CdColorRGB temp; /* create a linear ramp */ // qDebug ("falling back to dummy ramp"); clut = g_ptr_array_new_with_free_func (g_free); size = MateRrOutputGetGammaSize (output); if (size == 0) { ret = true; goto out; } /* get the color temperature */ if (!cd_color_get_blackbody_rgb_full (color_temperature, &temp, CD_COLOR_BLACKBODY_FLAG_USE_PLANCKIAN)) { // qWarning ("failed to get blackbody for %uK", color_temperature); cd_color_rgb_set (&temp, 1.0, 1.0, 1.0); } for (i = 0; i < size; i++) { value = (i * 0xffff) / (size - 1); data = g_new0 (MateRROutputClutItem, 1); data->red = value * temp.R; data->green = value * temp.G; data->blue = value * temp.B; g_ptr_array_add (clut, data); } /* apply the vcgt to this output */ ret = SessionOutputSetGamma (output, clut); if (!ret) goto out; out: g_ptr_array_unref (clut); return ret; } /* * Check to see if the on-disk profile has the MAPPING_device_id * metadata, and if not, we should delete the profile and re-create it * so that it gets mapped by the daemon. */ gboolean ColorState::SessionCheckProfileDeviceMd (GFile *file) { const gchar *key_we_need = CD_PROFILE_METADATA_MAPPING_DEVICE_ID; CdIcc *icc = NULL; gboolean ret; icc = cd_icc_new (); ret = cd_icc_load_file (icc, file, CD_ICC_LOAD_FLAGS_METADATA, NULL, NULL); if (!ret) goto out; ret = cd_icc_get_metadata_item (icc, key_we_need) != NULL; if (!ret) { qDebug ("auto-edid profile is old, and contains no %s data", key_we_need); } out: if (icc != NULL) g_object_unref (icc); return ret; } MateRROutput *ColorState::SessionGetStateOutputById (ColorState *state, const gchar *device_id) { gchar *output_id; MateRROutput *output = NULL; MateRROutput **outputs = NULL; guint i; /* search all STATE outputs for the device id */ outputs = mate_rr_screen_list_outputs (state->state_screen); if (outputs == NULL) { // qDebug("Failed to get outputs"); goto out; } for (i = 0; outputs[i] != NULL && output == NULL; i++) { if (mate_rr_output_is_connected(outputs[i])) { output_id = SessionGetOutputId (state, outputs[i]); if (g_strcmp0 (output_id, device_id) == 0) output = outputs[i]; g_free (output_id); } } if (output == NULL) { USD_LOG(LOG_DEBUG,"Failed to find output %s", device_id); } out: return output; } bool ColorState::GetSystemIccProfile(ColorState *state, GFile *file) { const char efi_path[] = "/sys/firmware/efi/efivars/INTERNAL_PANEL_COLOR_INFO-01e1ada1-79f2-46b3-8d3e-71fc0996ca6b"; /* efi variables have a 4-byte header */ const int efi_var_header_length = 4; g_autoptr(GFile) efi_file = g_file_new_for_path (efi_path); gboolean ret; g_autofree char *data = NULL; gsize length; g_autoptr(GError) error = NULL; ret = g_file_query_exists (efi_file, NULL); if (!ret) return false; ret = g_file_load_contents (efi_file, NULL /* cancellable */, &data, &length, NULL /* etag_out */, &error); if (!ret) { qWarning ("failed to read EFI system color profile: %s", error->message); return false; } if (length <= efi_var_header_length) { qWarning ("EFI system color profile was too short"); return false; } ret = g_file_replace_contents (file, data + efi_var_header_length, length - efi_var_header_length, NULL /* etag */, FALSE /* make_backup */, G_FILE_CREATE_NONE, NULL /* new_etag */, NULL /* cancellable */, &error); if (!ret) { qWarning ("failed to write system color profile: %s", error->message); return false; } return true; } static gboolean UtilsMkdirForFilename (GFile *file) { gboolean ret = FALSE; GFile *parent_dir = NULL; /* get parent directory */ parent_dir = g_file_get_parent (file); if (parent_dir == NULL) { USD_LOG(LOG_DEBUG,"could not get parent dir"); goto out; } /* ensure desination does not already exist */ ret = g_file_query_exists (parent_dir, NULL); if (ret) goto out; ret = g_file_make_directory_with_parents (parent_dir, NULL, NULL); if (!ret) goto out; out: if (parent_dir != NULL) g_object_unref (parent_dir); return ret; } bool ColorState::ApplyCreateIccProfileForEdid (ColorState *state, CdDevice *device, ColorEdid *edid, GFile *file, GError **error) { CdIcc *icc = NULL; const gchar *data; bool ret = false; /* ensure the per-user directory exists */ ret = UtilsMkdirForFilename (file); if (!ret) goto out; /* create our generated profile */ icc = cd_icc_new (); ret = cd_icc_create_from_edid (icc, edid->EdidGetGamma(), edid->EdidGetRed(), edid->EdidGetGreen(), edid->EdidGetBlue(), edid->EdidGetWhite(), NULL); if (!ret) goto out; /* set copyright */ cd_icc_set_copyright (icc, NULL, /* deliberately not translated */ "This profile is free of known copyright restrictions."); /* set model and title */ data = edid->EdidGetMonitorName(); if (data == NULL) data = cd_client_get_system_model (state->client); if (data == NULL) data = "Unknown monitor"; cd_icc_set_model (icc, NULL, data); cd_icc_set_description (icc, NULL, data); /* get manufacturer */ data = edid->EdidGetVendorName(); if (data == NULL) data = cd_client_get_system_vendor (state->client); if (data == NULL) data = "Unknown vendor"; cd_icc_set_manufacturer (icc, NULL, data); /* set the framework creator metadata */ cd_icc_add_metadata (icc, CD_PROFILE_METADATA_CMF_PRODUCT, PACKAGE_NAME); cd_icc_add_metadata (icc, CD_PROFILE_METADATA_CMF_BINARY, PACKAGE_NAME); cd_icc_add_metadata (icc, CD_PROFILE_METADATA_CMF_VERSION, PACKAGE_VERSION); cd_icc_add_metadata (icc, CD_PROFILE_METADATA_MAPPING_DEVICE_ID, cd_device_get_id (device)); /* set 'ICC meta Tag for Monitor Profiles' data */ cd_icc_add_metadata (icc, CD_PROFILE_METADATA_EDID_MD5, edid->EdidGetChecksum()); data = edid->EdidGetMonitorName(); if (data != NULL) cd_icc_add_metadata (icc, CD_PROFILE_METADATA_EDID_MODEL, data); data = edid->EdidGetSerialNumber(); if (data != NULL) cd_icc_add_metadata (icc, CD_PROFILE_METADATA_EDID_SERIAL, data); data = edid->EdidGetPnpId(); if (data != NULL) cd_icc_add_metadata (icc, CD_PROFILE_METADATA_EDID_MNFT, data); data = edid->EdidGetVendorName(); if (data != NULL) cd_icc_add_metadata (icc, CD_PROFILE_METADATA_EDID_VENDOR, data); /* save */ ret = cd_icc_save_file (icc, file, CD_ICC_SAVE_FLAGS_NONE, NULL, error); if (!ret) goto out; out: if (icc != NULL) g_object_unref (icc); return ret; } /* this function is more complicated than it should be, due to the * fact that XOrg sometimes assigns no primary devices when using * "xrandr --auto" or when the version of RANDR is < 1.3 */ bool ColorState::SessionUseOutputProfileForScreen (ColorState *state, MateRROutput *output) { gboolean has_laptop = FALSE; gboolean has_primary = FALSE; MateRROutput **outputs; MateRROutput *connected = NULL; guint i; /* do we have any screens marked as primary */ outputs = mate_rr_screen_list_outputs (state->state_screen); if (outputs == NULL || outputs[0] == NULL) { // qWarning ("failed to get outputs"); return false; } for (i = 0; outputs[i] != NULL; i++) { if (connected == NULL) connected = outputs[i]; if (mate_rr_output_get_is_primary (outputs[i])) has_primary = TRUE; if (mate_rr_output_is_laptop (outputs[i])) has_laptop = TRUE; } /* we have an assigned primary device, are we that? */ if (has_primary) return mate_rr_output_get_is_primary (output); /* choosing the internal panel is probably sane */ if (has_laptop) return mate_rr_output_is_laptop (output); /* we have to choose one, so go for the first connected device */ if (connected != NULL) return mate_rr_output_get_id (connected) == mate_rr_output_get_id (output); return false; } bool ColorState::SessionScreenSetIccProfile (ColorState *state, const gchar *filename, GError **error) { gchar *data = NULL; gsize length; guint version_data; g_return_val_if_fail (filename != NULL, FALSE); /* wayland */ if (state->gdk_window == NULL) { qDebug ("not setting atom as running under wayland"); return true; } // qDebug ("setting root window ICC profile atom from %s", filename); /* get contents of file */ if (!g_file_get_contents (filename, &data, &length, error)) return false; /* set profile property */ gdk_property_change (state->gdk_window, gdk_atom_intern_static_string ("_ICC_PROFILE"), gdk_atom_intern_static_string ("CARDINAL"), 8, GDK_PROP_MODE_REPLACE, (const guchar *) data, length); /* set version property */ version_data = USD_ICC_PROFILE_IN_X_VERSION_MAJOR * 100 + USD_ICC_PROFILE_IN_X_VERSION_MINOR * 1; gdk_property_change (state->gdk_window, gdk_atom_intern_static_string ("_ICC_PROFILE_IN_X_VERSION"), gdk_atom_intern_static_string ("CARDINAL"), 8, GDK_PROP_MODE_REPLACE, (const guchar *) &version_data, 1); g_free (data); return true; } static GPtrArray * SessionGenerateVcgt (CdProfile *profile, guint color_temperature, guint size) { MateRROutputClutItem *tmp; GPtrArray *array = NULL; const cmsToneCurve **vcgt; cmsFloat32Number in; guint i; cmsHPROFILE lcms_profile; CdIcc *icc = NULL; CdColorRGB temp; /* invalid size */ if (size == 0) goto out; /* open file */ icc = cd_profile_load_icc (profile, CD_ICC_LOAD_FLAGS_NONE, NULL, NULL); if (icc == NULL) goto out; /* get tone curves from profile */ lcms_profile = cd_icc_get_handle (icc); vcgt = (const cmsToneCurve **)cmsReadTag (lcms_profile, cmsSigVcgtTag); if (vcgt == NULL || vcgt[0] == NULL) { // qDebug ("profile does not have any VCGT data"); goto out; } /* get the color temperature */ if (!cd_color_get_blackbody_rgb_full (color_temperature, &temp, CD_COLOR_BLACKBODY_FLAG_USE_PLANCKIAN)) { // qWarning ("failed to get blackbody for %uK", color_temperature); cd_color_rgb_set (&temp, 1.0, 1.0, 1.0); } else { qDebug ("using VCGT gamma of %uK = %.1f,%.1f,%.1f", color_temperature, temp.R, temp.G, temp.B); } /* create array */ array = g_ptr_array_new_with_free_func (g_free); for (i = 0; i < size; i++) { in = (gdouble) i / (gdouble) (size - 1); tmp = g_new0 (MateRROutputClutItem, 1); tmp->red = cmsEvalToneCurveFloat(vcgt[0], in) * temp.R * (gdouble) 0xffff; tmp->green = cmsEvalToneCurveFloat(vcgt[1], in) * temp.G * (gdouble) 0xffff; tmp->blue = cmsEvalToneCurveFloat(vcgt[2], in) * temp.B * (gdouble) 0xffff; g_ptr_array_add (array, tmp); } out: if (icc != NULL) g_object_unref (icc); return array; } static gboolean SessionDeviceSetGamma (MateRROutput *output, CdProfile *profile, guint color_temperature) { gboolean ret = FALSE; guint size; GPtrArray *clut = NULL; /* create a lookup table */ size = MateRrOutputGetGammaSize (output); if (size == 0) { ret = TRUE; goto out; } clut = SessionGenerateVcgt (profile, color_temperature, size); if (clut == NULL) { // qDebug("failed to generate vcgt"); goto out; } /* apply the vcgt to this output */ ret = SessionOutputSetGamma (output, clut); if (!ret) goto out; out: if (clut != NULL) g_ptr_array_unref (clut); return ret; } void ColorState::SessionDeviceAssignProfileConnectCb (GObject *object, GAsyncResult *res, gpointer user_data) { CdProfile *profile = CD_PROFILE (object); const gchar *filename; gboolean ret; GError *error = NULL; MateRROutput *output; SessionAsyncHelper *helper = (SessionAsyncHelper *) user_data; ColorState *state = (ColorState *) (helper->state); /* get properties */ ret = cd_profile_connect_finish (profile, res, &error); if (!ret) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { qWarning ("failed to connect to profile: %s", error->message); } g_error_free (error); goto out; } /* get the filename */ filename = cd_profile_get_filename (profile); g_assert (filename != NULL); /* get the output (can't save in helper as GnomeRROutput isn't * a GObject, just a pointer */ output = mate_rr_screen_get_output_by_id (state->state_screen, helper->output_id); if (output == NULL) goto out; /* set the _ICC_PROFILE atom */ ret = SessionUseOutputProfileForScreen (state, output); if (ret) { ret = SessionScreenSetIccProfile (state, filename, &error); if (!ret) { qWarning ("failed to set screen _ICC_PROFILE: %s", error->message); g_clear_error (&error); } } /* create a vcgt for this icc file */ ret = cd_profile_get_has_vcgt (profile); if (ret) { ret = SessionDeviceSetGamma (output, profile, state->color_temperature); if (!ret) { qWarning ("failed to set %s gamma tables", cd_device_get_id (helper->device)); goto out; } } else { ret = SessionDeviceResetGamma (output, state->color_temperature); if (!ret) { qWarning ("failed to reset %s gamma tables", cd_device_get_id (helper->device)); goto out; } } out: SessionAsyncHelperFree (helper); } void ColorState::SessionDeviceAssignConnectCb (GObject *object, GAsyncResult *res, gpointer user_data) { CdDeviceKind kind; CdProfile *profile = NULL; gboolean ret; gchar *autogen_filename = NULL; gchar *autogen_path = NULL; ColorEdid *edid = nullptr; MateRROutput *output = NULL; GError *error = NULL; GFile *file = NULL; const gchar *xrandr_id; SessionAsyncHelper *helper; CdDevice *device = CD_DEVICE (object); ColorState *state = (ColorState *)user_data; /* remove from assign array */ g_hash_table_remove (state->device_assign_hash, cd_device_get_object_path (device)); /* get properties */ ret = cd_device_connect_finish (device, res, &error); if (!ret) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { qWarning ("failed to connect to device: %s", error->message); } g_error_free (error); goto out; } /* check we care */ kind = cd_device_get_kind (device); if (kind != CD_DEVICE_KIND_DISPLAY) goto out; // qDebug ("need to assign display device %s", cd_device_get_id (device)); /* get the GnomeRROutput for the device id */ xrandr_id = cd_device_get_id (device); output = SessionGetStateOutputById (state, xrandr_id); if (output == NULL) { qWarning ("no %s device found", cd_device_get_id (device)); goto out; } /* create profile from device edid if it exists */ edid = SessionGetOutputEdid (state, output); if (edid == nullptr) { qWarning ("unable to get EDID for %s", cd_device_get_id (device)); } else { autogen_filename = g_strdup_printf ("edid-%s.icc", edid->EdidGetChecksum ()); autogen_path = g_build_filename (g_get_user_data_dir (), "icc", autogen_filename, NULL); /* check if auto-profile has up-to-date metadata */ file = g_file_new_for_path (autogen_path); // 新建~/.local/share/icc/edid-*.icc文件 if (SessionCheckProfileDeviceMd (file)) { // qDebug ("auto-profile edid %s exists with md", autogen_path); } else { qDebug ("auto-profile edid does not exist, creating as %s", autogen_path); /* check if the system has a built-in profile */ ret = mate_rr_output_is_laptop (output) && GetSystemIccProfile (state, file); /* try creating one from the EDID */ if (!ret) { ret = ApplyCreateIccProfileForEdid (state, device, edid, file, &error); } if (!ret) { qWarning ("failed to create profile from EDID data: %s", error->message); g_clear_error (&error); } } } /* get the default profile for the device */ profile = cd_device_get_default_profile (device); if (profile == NULL) { qDebug ("%s has no default profile to set", cd_device_get_id (device)); /* the default output? */ if (mate_rr_output_get_is_primary (output) && state->gdk_window != NULL) { gdk_property_delete (state->gdk_window, gdk_atom_intern_static_string ("_ICC_PROFILE")); gdk_property_delete (state->gdk_window, gdk_atom_intern_static_string ("_ICC_PROFILE_IN_X_VERSION")); } /* reset, as we want linear profiles for profiling */ ret = SessionDeviceResetGamma (output, state->color_temperature); if (!ret) { qWarning ("failed to reset %s gamma tables", cd_device_get_id (device)); goto out; } goto out; } /* get properties */ helper = g_new0 (SessionAsyncHelper, 1); helper->output_id = mate_rr_output_get_id (output); // if(!helper->state) // helper->state = state; helper->state = state; helper->device = device; cd_profile_connect (profile, state->cancellable, SessionDeviceAssignProfileConnectCb, helper); out: g_free (autogen_filename); g_free (autogen_path); if (file != NULL) g_object_unref (file); if (edid != nullptr) edid = nullptr; if (profile != NULL) g_object_unref (profile); } void ColorState::SessionProfileGammaFindDeviceCb (GObject *object, GAsyncResult *res, gpointer user_data) { if (g_hadQuit) { USD_LOG(LOG_DEBUG, "usd had quit can't set gamma..."); return; } CdClient *client = CD_CLIENT (object); CdDevice *device = NULL; GError *error = NULL; ColorState *state = (ColorState *) user_data; device = cd_client_find_device_by_property_finish (client, res, &error); if (device == NULL) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)){ USD_LOG(LOG_DEBUG,"."); } g_error_free (error); return; } /* get properties */ cd_device_connect (device, state->cancellable, SessionDeviceAssignConnectCb, state); if (device != NULL) g_object_unref (device); USD_LOG(LOG_DEBUG,"set gamma over.."); } void ColorState::SessionSetGammaForAllDevices (ColorState *state) { MateRROutput **outputs; guint i; /* setting the temperature before we get the list of devices is fine, * as we use the temperature in the calculation */ if (state->state_screen == NULL) { USD_LOG(LOG_DEBUG,"state->state_screen is nullptr"); return; } /* get STATE outputs */ outputs = mate_rr_screen_list_outputs (state->state_screen); if (outputs == NULL) { USD_LOG(LOG_ERR,"failed to get outputs"); return; } for (i = 0; outputs[i] != NULL; i++) { // if (mate_rr_output_get_is_primary (outputs[i]) || mate_rr_output_is_laptop (outputs[i])){ /* * 目前需求是外显通过物理按键调节色温值,所以这里只是判断当前屏幕是否是笔记本的屏幕。 * 如果在台式机上就会无法调节色温 */ // if (mate_rr_output_is_laptop (outputs[i])) if (mate_rr_output_is_connected(outputs[i])){ // qDebug("Output Name %s\n", mate_rr_output_get_name (outputs[i])); /* get CdDevice for this output */ cd_client_find_device_by_property (state->client, CD_DEVICE_METADATA_XRANDR_NAME, mate_rr_output_get_name (outputs[i]), state->cancellable, SessionProfileGammaFindDeviceCb, state); continue; } } } /* We have to reset the gamma tables each time as if the primary output * has changed then different crtcs are going to be used. * See https://bugzilla.gnome.org/show_bug.cgi?id=660164 for an example */ void ColorState::MateRrScreenOutputChangedCb (MateRRScreen *screen, ColorState *state) { SessionSetGammaForAllDevices (state); } void ColorState::SessionDeviceAssign (ColorState *state, CdDevice *device) { const gchar *key; gpointer found; /* are we already assigning this device */ key = cd_device_get_object_path (device); found = g_hash_table_lookup (state->device_assign_hash, key); if (found != NULL) { qDebug ("assign for %s already in progress", key); return; } g_hash_table_insert (state->device_assign_hash, g_strdup (key), GINT_TO_POINTER (TRUE)); cd_device_connect (device, state->cancellable, SessionDeviceAssignConnectCb, state); } void ColorState::SessionDeviceAddedAssignCb (CdClient *client, CdDevice *device, ColorState *state) { SessionDeviceAssign (state, device); } void ColorState::SessionDeviceChangedAssignCb (CdClient *client, CdDevice *device, ColorState *state) { qDebug ("%s changed", cd_device_get_object_path (device)); SessionDeviceAssign (state, device); } void ColorState::SessionGetDevicesCb (GObject *object, GAsyncResult *res, gpointer user_data) { CdDevice *device; GError *error = NULL; GPtrArray *array; guint i; ColorState *state = (ColorState *)user_data; array = cd_client_get_devices_finish (CD_CLIENT (object), res, &error); if (array == NULL) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) qWarning ("failed to get devices: %s", error->message); g_error_free (error); return; } for (i = 0; i < array->len; i++) { device = (CdDevice *)g_ptr_array_index (array, i); SessionDeviceAssign (state, device); } if (array != NULL) g_ptr_array_unref (array); } void ColorState::SessionClientConnectCb (GObject *source_object, GAsyncResult *res, gpointer user_data) { gboolean ret; GError *error = NULL; MateRROutput **outputs; guint i; ColorState *state = (ColorState *)user_data; USD_LOG(LOG_DEBUG, "ready to connect to colord"); /* connected */ ret = cd_client_connect_finish (state->client, res, &error); USD_LOG(LOG_DEBUG, "connect to colord over!ret:%d",ret); if (!ret) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { qWarning ("failed to connect to colord: %s", error->message); } g_error_free (error); return; } USD_LOG(LOG_DEBUG, "success to connect to colord"); /* is there an available colord instance? */ ret = cd_client_get_has_server (state->client); if (!ret) { USD_LOG(LOG_DEBUG, "There is no colord server available"); return; } USD_LOG(LOG_DEBUG, "cd_client_get_has_server ok"); /* add screens */ mate_rr_screen_refresh (state->state_screen, &error); if (error != NULL) { USD_LOG(LOG_DEBUG,"failed to refresh: %s", error->message); g_error_free (error); return; } USD_LOG(LOG_DEBUG, "mate_rr_screen_refresh ok"); /* get STATE outputs */ outputs = mate_rr_screen_list_outputs (state->state_screen); if (outputs == NULL) { USD_LOG(LOG_DEBUG,"failed to get outputs"); return; } USD_LOG(LOG_DEBUG,"start add output.."); ret = false; for (i = 0; outputs[i] != NULL; i++) { if (UsdBaseClass::isTablet()) { if (mate_rr_output_is_laptop (outputs[i])) { SessionAddStateOutput (state, outputs[i]); ret = true; } } else { if (mate_rr_output_is_connected(outputs[i])) { SessionAddStateOutput (state, outputs[i]); USD_LOG(LOG_DEBUG,"find laptop screen :%s",mate_rr_output_get_name(outputs[i])); ret = true; } } } if (false == ret) { USD_LOG(LOG_DEBUG,"can't find laptop screen.."); } /* only connect when colord is awake */ // g_signal_connect (state->state_screen, "changed", // G_CALLBACK (MateRrScreenOutputChangedCb), // state); // g_signal_connect (state->client, "device-added", // G_CALLBACK (SessionDeviceAddedAssignCb), // state); // g_signal_connect (state->client, "device-changed", // G_CALLBACK (SessionDeviceChangedAssignCb), // state); /* set for each device that already exist */ cd_client_get_devices (state->client, state->cancellable, SessionGetDevicesCb, state); } bool ColorState::ColorStateStart() { g_cancellable_cancel (cancellable); g_clear_object (&cancellable); cancellable = g_cancellable_new (); gdk_init(NULL,NULL); GError *error = NULL; state_screen = mate_rr_screen_new(gdk_screen_get_default (), &error); if (state_screen == NULL) { qWarning ("failed to get screens: %s", error->message); g_error_free (error); return false; } cd_client_connect (client, cancellable, SessionClientConnectCb, this); return true; } void ColorState::ColorStateStop() { g_cancellable_cancel (cancellable); } ukui-settings-daemon/plugins/color/color-manager.cpp0000644000175000017500000006530114205117202021602 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "color-manager.h" #define PLUGIN_COLOR_SCHEMA "org.ukui.SettingsDaemon.plugins.color" #define COLOR_KEY_LAST_COORDINATES "night-light-last-coordinates" #define COLOR_KEY_ENABLED "night-light-enabled" #define COLOR_KEY_ALLDAY "night-light-allday" #define COLOR_KEY_AUTO_THEME "theme-schedule-automatic" #define COLOR_KEY_TEMPERATURE "night-light-temperature" #define COLOR_KEY_AUTOMATIC "night-light-schedule-automatic" #define COLOR_KEY_AUTOMATIC_FROM "night-light-schedule-automatic-from" #define COLOR_KEY_AUTOMATIC_TO "night-light-schedule-automatic-to" #define COLOR_KEY_FROM "night-light-schedule-from" #define COLOR_KEY_TO "night-light-schedule-to" #define GTK_THEME_SCHEMA "org.mate.interface" #define GTK_THEME_KEY "gtk-theme" #define QT_THEME_SCHEMA "org.ukui.style" #define QT_THEME_KEY "style-name" #define HAD_READ_KWIN "had-read-kwin-config" #define KWIN_COLOR_ACTIVE "Active" #define KWIN_NIGHT_TEMP "NightTemperature" #define KWIN_COLOR_MODE "Mode" #define KWIN_COLOR_START "EveningBeginFixed" #define KWIN_COLOR_END "MorningBeginFixed" #define KWIN_CURRENT_TEMP "CurrentColorTemperature" #define USD_NIGHT_LIGHT_SCHEDULE_TIMEOUT 5 /* seconds */ #define USD_NIGHT_LIGHT_POLL_TIMEOUT 60 /* seconds */ #define USD_NIGHT_LIGHT_POLL_SMEAR 1 /* hours */ #define USD_NIGHT_LIGHT_SMOOTH_SMEAR 5.f /* seconds */ #define USD_FRAC_DAY_MAX_DELTA (1.f/60.f) /* 1 minute */ #define USD_TEMPERATURE_MAX_DELTA (10.f) #define DESKTOP_ID "ukui-color-panel" #include #include enum theme_status_switch{ white_mode, black_mode }; double hour_minute_to_value(int hour, int minute) { double value = (double)minute/60; return (double)hour + value; } ColorManager *ColorManager::mColorManager = nullptr; ColorManager::ColorManager() { forced = false; smooth_id = 0; smooth_timer = nullptr; disabled_until_tmw = false; datetime_override = NULL; geoclue_enabled = true; smooth_enabled = true; cached_sunrise = -1.f; cached_sunset = -1.f; cached_temperature = USD_COLOR_TEMPERATURE_DEFAULT; settings = new QGSettings (PLUGIN_COLOR_SCHEMA); gtk_settings = new QGSettings (GTK_THEME_SCHEMA); qt_settings = new QGSettings (QT_THEME_SCHEMA); mColorState = new ColorState(); mColorProfiles = new ColorProfiles(); m_NightChecktimer = new QTimer(this); } ColorManager::~ColorManager() { if (m_NightChecktimer) { delete m_NightChecktimer; m_NightChecktimer = nullptr; } if (settings) { delete settings; settings = nullptr; } if (gtk_settings) { delete gtk_settings; gtk_settings = nullptr; } if (qt_settings) { delete qt_settings; qt_settings = nullptr; } if (mColorState) { delete mColorState; mColorState = nullptr; } if (mColorProfiles) { delete mColorProfiles; mColorProfiles = nullptr; } } ColorManager *ColorManager::ColorManagerNew() { if (nullptr == mColorManager) mColorManager = new ColorManager(); return mColorManager; } GDateTime *ColorManager::NightLightGetDateTimeNow() { if (datetime_override != NULL) return g_date_time_ref (datetime_override); return g_date_time_new_now_local(); } bool ColorManager::NightLightSmoothCb (ColorManager *manager) { double tmp; double frac; /* find fraction */ frac = g_timer_elapsed (manager->smooth_timer, NULL) / USD_NIGHT_LIGHT_SMOOTH_SMEAR; if (frac >= 1.f) { manager->NightLightSetTemperatureInternal (manager->smooth_target_temperature); manager->smooth_id = 0; return G_SOURCE_REMOVE; } /* set new temperature step using log curve */ tmp = manager->smooth_target_temperature - manager->cached_temperature; tmp *= frac; tmp += manager->cached_temperature; manager->NightLightSetTemperatureInternal (tmp); // USD_LOG(LOG_DEBUG,"set Temp...%f",tmp); return G_SOURCE_CONTINUE; } void ColorManager::PollSmoothCreate (double temperature) { g_assert (smooth_id == 0); smooth_target_temperature = temperature; smooth_timer = g_timer_new (); smooth_id = g_timeout_add (50, (GSourceFunc)NightLightSmoothCb, this); } void ColorManager::PollSmoothDestroy () { if (smooth_id != 0) { g_source_remove (smooth_id); smooth_id = 0; } if (smooth_timer != NULL) g_clear_pointer (&smooth_timer, g_timer_destroy); } void ColorManager::NightLightSetTemperatureInternal (double temperature) { if (ABS (cached_temperature - temperature) <= USD_TEMPERATURE_MAX_DELTA) { // USD_LOG(LOG_DEBUG,"set night light %f error ABS:%f delta:%f", temperature,ABS (cached_temperature - temperature),USD_TEMPERATURE_MAX_DELTA); return; } cached_temperature = temperature; mColorState->ColorStateSetTemperature (cached_temperature); } void ColorManager::NightLightSetTemperature(double temperature) { /* immediate */ if (!smooth_enabled) { USD_LOG(LOG_DEBUG,"set night light %f", temperature); NightLightSetTemperatureInternal (temperature); return; } /* Destroy any smooth transition, it will be recreated if neccessary */ PollSmoothDestroy (); /* small jump */ if (ABS (temperature - cached_temperature) < USD_TEMPERATURE_MAX_DELTA) { NightLightSetTemperatureInternal (temperature); return; } /* smooth out the transition */ PollSmoothCreate (temperature); USD_LOG(LOG_DEBUG,"set color temp to :%f",temperature); } void ColorManager::NightLightSetActive(bool active) { cached_active = active; /* ensure set to unity temperature */ if (!active){ NightLightSetTemperature (USD_COLOR_TEMPERATURE_DEFAULT); } } static gdouble deg2rad (gdouble degrees) { return (M_PI * degrees) / 180.f; } static gdouble rad2deg (gdouble radians) { return radians * (180.f / M_PI); } /* * Formulas taken from https://www.esrl.noaa.gov/gmd/grad/solcalc/calcdetails.html * * The returned values are fractional hours, so 6am would be 6.0 and 4:30pm * would be 16.5. * * The values returned by this function might not make sense for locations near * the polar regions. For example, in the north of Lapland there might not be * a sunrise at all. */ bool NightLightGetSunriseSunset (GDateTime *dt, double pos_lat, double pos_long, double *sunrise, double *sunset) { g_autoptr(GDateTime) dt_zero = g_date_time_new_utc (1900, 1, 1, 0, 0, 0); GTimeSpan ts = g_date_time_difference (dt, dt_zero); g_return_val_if_fail (pos_lat <= 90.f && pos_lat >= -90.f, false); g_return_val_if_fail (pos_long <= 180.f && pos_long >= -180.f, false); double tz_offset = (double) g_date_time_get_utc_offset (dt) / G_USEC_PER_SEC / 60 / 60; // B5 double date_as_number = ts / G_USEC_PER_SEC / 24 / 60 / 60 + 2; // B7 double time_past_local_midnight = 0; // E2, unused in this calculation double julian_day = date_as_number + 2415018.5 + time_past_local_midnight - tz_offset / 24; double julian_century = (julian_day - 2451545) / 36525; double geom_mean_long_sun = fmod (280.46646 + julian_century * (36000.76983 + julian_century * 0.0003032), 360); // I2 double geom_mean_anom_sun = 357.52911 + julian_century * (35999.05029 - 0.0001537 * julian_century); // J2 double eccent_earth_orbit = 0.016708634 - julian_century * (0.000042037 + 0.0000001267 * julian_century); // K2 double sun_eq_of_ctr = sin (deg2rad (geom_mean_anom_sun)) * (1.914602 - julian_century * (0.004817 + 0.000014 * julian_century)) + sin (deg2rad (2 * geom_mean_anom_sun)) * (0.019993 - 0.000101 * julian_century) + sin (deg2rad (3 * geom_mean_anom_sun)) * 0.000289; // L2 double sun_true_long = geom_mean_long_sun + sun_eq_of_ctr; // M2 double sun_app_long = sun_true_long - 0.00569 - 0.00478 * sin (deg2rad (125.04 - 1934.136 * julian_century)); // P2 double mean_obliq_ecliptic = 23 + (26 + ((21.448 - julian_century * (46.815 + julian_century * (0.00059 - julian_century * 0.001813)))) / 60) / 60; // Q2 double obliq_corr = mean_obliq_ecliptic + 0.00256 * cos (deg2rad (125.04 - 1934.136 * julian_century)); // R2 double sun_declin = rad2deg (asin (sin (deg2rad (obliq_corr)) * sin (deg2rad (sun_app_long)))); // T2 double var_y = tan (deg2rad (obliq_corr/2)) * tan (deg2rad (obliq_corr / 2)); // U2 double eq_of_time = 4 * rad2deg (var_y * sin (2 * deg2rad (geom_mean_long_sun)) - 2 * eccent_earth_orbit * sin (deg2rad (geom_mean_anom_sun)) + 4 * eccent_earth_orbit * var_y * sin (deg2rad (geom_mean_anom_sun)) * cos (2 * deg2rad (geom_mean_long_sun)) - 0.5 * var_y * var_y * sin (4 * deg2rad (geom_mean_long_sun)) - 1.25 * eccent_earth_orbit * eccent_earth_orbit * sin (2 * deg2rad (geom_mean_anom_sun))); // V2 double ha_sunrise = rad2deg (acos (cos (deg2rad (90.833)) / (cos (deg2rad (pos_lat)) * cos (deg2rad (sun_declin))) - tan (deg2rad (pos_lat)) * tan (deg2rad (sun_declin)))); // W2 double solar_noon = (720 - 4 * pos_long - eq_of_time + tz_offset * 60) / 1440; // X2 double sunrise_time = solar_noon - ha_sunrise * 4 / 1440; // Y2 double sunset_time = solar_noon + ha_sunrise * 4 / 1440; // Z2 /* convert to hours */ if (sunrise != NULL) *sunrise = sunrise_time * 24; if (sunset != NULL) *sunset = sunset_time * 24; return true; } double NightLightFracDayFromDt (GDateTime *dt) { return g_date_time_get_hour (dt) + (double) g_date_time_get_minute (dt) / 60.f + (double) g_date_time_get_second (dt) / 3600.f; } bool NightLightFracDayIsBetween (double value, double start, double end) { /* wrap end to the next day if it is before start, * considering equal values as a full 24h period */ if (end <= start) end += 24; /* wrap value to the next day if it is before the range */ if (value < start && value < end) value += 24; /* Check whether value falls into range; together with the 24h * wrap around above this means that TRUE is always returned when * start == end. */ return value >= start && value < end; } static double LinearInterpolate (double val1, double val2, double factor) { g_return_val_if_fail (factor >= 0.f, -1.f); g_return_val_if_fail (factor <= 1.f, -1.f); return ((val1 - val2) * factor) + val2; } bool ColorManager::UpdateCachedSunriseSunset() { bool ret = false; double latitude; double longitude; double sunrise; double sunset; g_autoptr(GVariant) tmp = NULL; g_autoptr(GDateTime) dt_now = NightLightGetDateTimeNow (); GSettings *setting = g_settings_new(PLUGIN_COLOR_SCHEMA); /* calculate the sunrise/sunset for the location */ tmp = g_settings_get_value (setting, COLOR_KEY_LAST_COORDINATES); g_clear_object(&setting); g_variant_get (tmp, "(dd)", &latitude, &longitude); if (latitude > 90.f || latitude < -90.f) return false; if (longitude > 180.f || longitude < -180.f) return false; if (!NightLightGetSunriseSunset (dt_now, latitude, longitude, &sunrise, &sunset)) { qWarning ("failed to get sunset/sunrise for %.3f,%.3f", longitude, longitude); return false; } /* anything changed */ if (ABS (cached_sunrise - sunrise) > USD_FRAC_DAY_MAX_DELTA) { cached_sunrise = sunrise; ret = true; } if (ABS (cached_sunset - sunset) > USD_FRAC_DAY_MAX_DELTA) { cached_sunset = sunset; ret = true; } return ret; } /*Active:1,使能,0禁用。 *0:全天,1跟随日出日落,2自定义 *Mode:1 自定义 *Mode:2--EveningBeginFixed(17:55:01)---跟随日出日落 *Mode:3--全天 */ bool ColorManager::ReadKwinColorTempConfig() { QVector nightColor; if (settings->keys().contains(HAD_READ_KWIN)) { if (settings->get(HAD_READ_KWIN).toBool() == true) { USD_LOG(LOG_DEBUG,"Kwin had read over.."); return false; } } else { USD_LOG(LOG_DEBUG,"can't find key:%s", HAD_READ_KWIN); return false; } QDBusInterface colorIft("org.ukui.KWin", "/ColorCorrect", "org.ukui.kwin.ColorCorrect", QDBusConnection::sessionBus()); QDBusMessage result = colorIft.call("nightColorInfo"); const QDBusArgument &dbusArgs = result.arguments().at(0).value().asVariant().value(); dbusArgs.beginArray(); while (!dbusArgs.atEnd()) { ColorInfo color; dbusArgs >> color; nightColor.push_back(color); } dbusArgs.endArray(); for (ColorInfo it : nightColor) { mNightConfig.insert(it.arg, it.out.variant()); } settings->set(COLOR_KEY_TEMPERATURE, mNightConfig[KWIN_NIGHT_TEMP].toInt()); settings->set(COLOR_KEY_ENABLED,mNightConfig[KWIN_COLOR_ACTIVE].toBool()); if (3 == mNightConfig[KWIN_COLOR_MODE].toInt()) { settings->set(COLOR_KEY_ALLDAY, true); } else if (2 == mNightConfig[KWIN_COLOR_MODE].toInt() && mNightConfig[KWIN_COLOR_START].toString() == "17:55:01"){ settings->set(COLOR_KEY_AUTOMATIC, true); } else { QTime startTime = QTime::fromString(mNightConfig[KWIN_COLOR_START].toString(),"hh:mm:ss"); QTime endTime = QTime::fromString(mNightConfig[KWIN_COLOR_END].toString(),"hh:mm:ss"); settings->set(COLOR_KEY_FROM, hour_minute_to_value(startTime.hour(), startTime.minute())); settings->set(COLOR_KEY_TO, hour_minute_to_value(endTime.hour(), endTime.minute())); } USD_LOG_SHOW_PARAM1(mNightConfig[KWIN_COLOR_ACTIVE].toBool()); USD_LOG_SHOW_PARAM1(mNightConfig[KWIN_COLOR_MODE].toInt()); USD_LOG_SHOW_PARAMS(mNightConfig[KWIN_COLOR_START].toString().toLatin1().data()); USD_LOG_SHOW_PARAMS(mNightConfig[KWIN_COLOR_END].toString().toLatin1().data()); settings->set(HAD_READ_KWIN,true); mNightConfig[KWIN_COLOR_ACTIVE] = false; colorIft.call("setNightColorConfig", mNightConfig); mNightConfig[KWIN_NIGHT_TEMP] = mNightConfig[KWIN_CURRENT_TEMP]; mNightConfig[KWIN_COLOR_ACTIVE] = false; colorIft.call("setNightColorConfig", mNightConfig); // USD_LOG(LOG_DEBUG,"."); return true; } void ColorManager::NightLightRecheck(ColorManager *manager) { double frac_day; double schedule_from = -1.f; double schedule_to = -1.f; double theme_from = -1.f; double theme_to = -1.f; double smear = USD_NIGHT_LIGHT_POLL_SMEAR; /* hours */ int theme_now = -1; guint temperature; guint temp_smeared; GDateTime *dt_now = manager->NightLightGetDateTimeNow (); /* Forced mode, just set the temperature to night light. * Proper rechecking will happen once forced mode is disabled again */ if (manager->forced) { temperature = manager->settings->get(COLOR_KEY_TEMPERATURE).toUInt(); manager->NightLightSetTemperature (temperature); USD_LOG(LOG_DEBUG,"set color to :%d",temperature); return; } /* calculate the position of the sun */ if (manager->settings->get(COLOR_KEY_AUTO_THEME).toBool()) { manager->UpdateCachedSunriseSunset (); // if (manager->cached_sunrise > 0.f && manager->cached_sunset > 0.f) { // theme_to = manager->cached_sunrise; // theme_from = manager->cached_sunset; // } else { // theme_to = 7.0; // theme_from = 18.0; // } theme_to = 7.0; theme_from = 18.0; /* get the current hour of a day as a fraction */ frac_day = NightLightFracDayFromDt (dt_now); if(frac_day > theme_to && frac_day < theme_from) theme_now = 0; else theme_now = 1; if(theme_now) {//需要根据项目进行设置 manager->gtk_settings->set(GTK_THEME_KEY, "ukui-black-unity"); manager->qt_settings->set(QT_THEME_KEY, "ukui-dark"); } else { manager->gtk_settings->set(GTK_THEME_KEY, "ukui-white-unity"); manager->qt_settings->set(QT_THEME_KEY, "ukui-light"); } } if(!manager->settings->get(COLOR_KEY_ENABLED).toBool()){ USD_LOG(LOG_DEBUG, "stop it.."); manager->NightLightSetActive (false); return; } if(manager->settings->get(COLOR_KEY_ALLDAY).toBool()){ temperature = manager->settings->get(COLOR_KEY_TEMPERATURE).toUInt(); manager->NightLightSetTemperature (temperature); USD_LOG(LOG_DEBUG,"COLOR_KEY_ALLDAY temperature:%d",temperature); return; } /* calculate the position of the sun */ if (manager->settings->get(COLOR_KEY_AUTOMATIC).toBool()) { manager->UpdateCachedSunriseSunset (); if (manager->cached_sunrise > 0.f && manager->cached_sunset > 0.f) { schedule_to = manager->cached_sunrise; schedule_from = manager->cached_sunset; manager->settings->set(COLOR_KEY_AUTOMATIC_FROM, 18.00); manager->settings->set(COLOR_KEY_AUTOMATIC_TO, 7.00); } } /* fall back to manual settings */ if (schedule_to <= 0.f || schedule_from <= 0.f) { schedule_from = manager->settings->get(COLOR_KEY_FROM).toDouble(); schedule_to = manager->settings->get(COLOR_KEY_TO).toDouble(); } /* get the current hour of a day as a fraction */ frac_day = NightLightFracDayFromDt (dt_now); // //qDebug("fractional day = %.3f, limits = %.3f->%.3f", // frac_day, schedule_from, schedule_to); /* disabled until tomorrow */ if (manager->disabled_until_tmw) { GTimeSpan time_span; bool reset = false; time_span = g_date_time_difference (dt_now, manager->disabled_until_tmw_dt); /* Reset if disabled until tomorrow is more than 24h ago. */ if (time_span > (GTimeSpan) 24 * 60 * 60 * 1000000) { //qDebug("night light disabled until tomorrow is older than 24h, resetting disabled until tomorrow"); reset = true; } else if (time_span > 0) { /* Or if a sunrise lies between the time it was disabled and now. */ gdouble frac_disabled; frac_disabled = NightLightFracDayFromDt (manager->disabled_until_tmw_dt); if (frac_disabled != frac_day && NightLightFracDayIsBetween (schedule_to, frac_disabled, frac_day)) { //qDebug("night light sun rise happened, resetting disabled until tomorrow"); reset = true; } } if (reset) { manager->disabled_until_tmw = false; g_clear_pointer(&manager->disabled_until_tmw_dt, g_date_time_unref); } else { USD_LOG(LOG_DEBUG,"night light still day-disabled, resetting"); manager->NightLightSetTemperature (USD_COLOR_TEMPERATURE_DEFAULT); return; } } /* lower smearing period to be smaller than the time between start/stop */ smear = MIN (smear, MIN (ABS (schedule_to - schedule_from), 24 - ABS (schedule_to - schedule_from))); if (!NightLightFracDayIsBetween (frac_day, schedule_from - smear, schedule_to)) { manager->NightLightSetActive (false); return; } /* smear the temperature for a short duration before the set limits * * |----------------------| = from->to * |-| = smear down * |-| = smear up * * \ / * \ / * \--------------------/ */ temperature = manager->settings->get(COLOR_KEY_TEMPERATURE).toUInt(); if (smear < 0.01) { /* Don't try to smear for extremely short or zero periods */ temp_smeared = temperature; } else if (NightLightFracDayIsBetween (frac_day, schedule_from - smear, schedule_from)) { double factor = 1.f - ((frac_day - (schedule_from - smear)) / smear); temp_smeared = LinearInterpolate (USD_COLOR_TEMPERATURE_DEFAULT, temperature, factor); } else if (NightLightFracDayIsBetween (frac_day, schedule_to - smear, schedule_to)) { double factor = (frac_day - (schedule_to - smear)) / smear; temp_smeared = LinearInterpolate (USD_COLOR_TEMPERATURE_DEFAULT, temperature, factor); } else { temp_smeared = temperature; } // //qDebug("night light mode on, using temperature of %uK (aiming for %uK)", // temp_smeared, temperature); manager->NightLightSetActive (true); manager->NightLightSetTemperature (temp_smeared); USD_LOG(LOG_DEBUG,"set temp :%d",temp_smeared); } void ColorManager::OnLocationNotify(GClueSimple *simple, GParamSpec *pspec, gpointer user_data) { GClueLocation *location; gdouble latitude, longitude; ColorManager *manager = (ColorManager *)user_data; location = gclue_simple_get_location (simple); latitude = gclue_location_get_latitude (location); longitude = gclue_location_get_longitude (location); GSettings *setting = g_settings_new(PLUGIN_COLOR_SCHEMA); /* calculate the sunrise/sunset for the location */ g_settings_set_value (setting, COLOR_KEY_LAST_COORDINATES, g_variant_new ("(dd)", latitude, longitude)); g_clear_object(&setting); // //qDebug("got geoclue latitude %f, longitude %f", latitude, longitude); /* recheck the levels if the location changed significantly */ if (manager->UpdateCachedSunriseSunset ()) manager->NightLightRecheck (manager); } void ColorManager::OnGeoclueSimpleReady(GObject *source_object, GAsyncResult *res, gpointer user_data) { GClueSimple *geoclue_simple; ColorManager *manager = (ColorManager *)user_data; g_autoptr(GError) error = NULL; geoclue_simple = gclue_simple_new_finish (res, &error); if (geoclue_simple == NULL) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) qWarning ("Failed to connect to GeoClue2 service: %s", error->message); return; } manager->geoclue_simple = geoclue_simple; manager->geoclue_client = gclue_simple_get_client (manager->geoclue_simple); g_object_set (G_OBJECT (manager->geoclue_client), "time-threshold", 60*60, NULL); /* 1 hour */ g_signal_connect (manager->geoclue_simple, "notify::location", G_CALLBACK (OnLocationNotify), user_data); OnLocationNotify (manager->geoclue_simple, NULL, user_data); } void ColorManager::StartGeoclue() { cancellable = g_cancellable_new (); gclue_simple_new (DESKTOP_ID, GCLUE_ACCURACY_LEVEL_CITY, cancellable, OnGeoclueSimpleReady, this); } void ColorManager::StopGeoclue() { g_cancellable_cancel (cancellable); g_clear_object (&cancellable); if (geoclue_client != NULL) { gclue_client_call_stop (geoclue_client, NULL, NULL, NULL); geoclue_client = NULL; } g_clear_object (&geoclue_simple); } void ColorManager::SettingsChangedCb(QString key) { // //qDebug("settings changed"); if(key == COLOR_KEY_AUTOMATIC_FROM || key == COLOR_KEY_AUTOMATIC_TO){ return; } USD_LOG(LOG_DEBUG,"KEY:%s",key.toLatin1().data()); NightLightRecheck(this); mColorState->ColorStateSetTemperature (cached_temperature); } bool ColorManager::ColorManagerStart() { USD_LOG(LOG_DEBUG,"--Color manager start--"); int ms = 2000; if (false == ReadKwinColorTempConfig()) { ms = 100; } QTimer::singleShot(ms, this, [=](){ mColorProfiles->ColorProfilesStart(); mColorState->ColorStateStart(); NightLightRecheck(this); connect(m_NightChecktimer, SIGNAL(timeout()), this, SLOT(checkTime())); m_NightChecktimer->start(USD_NIGHT_LIGHT_POLL_TIMEOUT*1000); StartGeoclue(); connect(settings,SIGNAL(changed(QString)),this,SLOT(SettingsChangedCb(QString))); }); return true; } void ColorManager::checkTime() { NightLightRecheck (this); } void ColorManager::ColorManagerStop() { USD_LOG(LOG_DEBUG,"Color manager stop"); mColorProfiles->ColorProfilesStop(); mColorState->ColorStateStop(); StopGeoclue(); } ukui-settings-daemon/plugins/color/color.pro0000644000175000017500000000207114205117202020203 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-09-10T14:30:00 # #------------------------------------------------- QT += gui QT += core xml widgets x11extras TEMPLATE = lib DEFINES += COLOR_LIBRARY CONFIG += c++11 link_pkgconfig no_keywords plugin app_bundle DEFINES += QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"color\\\" include($$PWD/../../common/common.pri) INCLUDEPATH += \ -I ukui-settings-daemon/ PKGCONFIG += \ glib-2.0 \ gtk+-3.0 \ colord \ libgeoclue-2.0 \ gobject-2.0 \ libnotify \ libcanberra \ libcanberra-gtk3 \ gio-2.0 \ mate-desktop-2.0 \ gnome-desktop-3.0 SOURCES += \ color-edid.cpp \ color-manager.cpp \ color-plugin.cpp \ color-profiles.cpp \ color-state.cpp HEADERS += \ color-edid.h \ color-info.h \ color-manager.h \ color-plugin.h \ color-profiles.h \ color-state.h color_lib.path = $${PLUGIN_INSTALL_DIRS} color_lib.files = $$OUT_PWD/libcolor.so INSTALLS += color_lib ukui-settings-daemon/plugins/save-param/0000755000175000017500000000000014210057506017267 5ustar fengfengukui-settings-daemon/plugins/save-param/xrandr-output.h0000644000175000017500000000433514205117202022273 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2012 by Alejandro Fiestas Olivares * Copyright 2016 by Sebastian Kügler * Copyright (c) 2018 Kai Uwe Broulik * Work sponsored by the LiMux project of * the city of Munich. * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef OUTPUT_H #define OUTPUT_H #include //#include #include class xrandrOutput { public: static void readInOutputs(KScreen::ConfigPtr config, const QVariantList &outputsInfo); static void writeGlobal(const KScreen::OutputPtr &output); static bool writeGlobalPart(const KScreen::OutputPtr &output, QVariantMap &info, const KScreen::OutputPtr &fallback); static QString dirPath(); private: static QString globalFileName(const QString &hash); static QVariantMap getGlobalData(KScreen::OutputPtr output); static void readIn(KScreen::OutputPtr output, const QVariantMap &info); static bool readInGlobal(KScreen::OutputPtr output); static void readInGlobalPartFromInfo(KScreen::OutputPtr output, const QVariantMap &info); /* * When a global output value (scale, rotation) is changed we might * need to reposition the outputs when another config is read. */ static void adjustPositions(KScreen::ConfigPtr config, const QVariantList &outputsInfo); static QString mDirName; }; #endif // OUTPUT_H ukui-settings-daemon/plugins/save-param/color-temp-info.h0000644000175000017500000000264114205117202022447 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef COLORTEMPINFO_H #define COLORTEMPINFO_H #include #include #include #include struct ColorInfo { QString arg; QDBusVariant out; }; QDBusArgument &operator<<(QDBusArgument &argument, const ColorInfo &mystruct) { argument.beginStructure(); argument << mystruct.arg << mystruct.out; argument.endStructure(); return argument; } const QDBusArgument &operator>>(const QDBusArgument &argument, ColorInfo &mystruct) { argument.beginStructure(); argument >> mystruct.arg >> mystruct.out; argument.endStructure(); return argument; } Q_DECLARE_METATYPE(ColorInfo) #endif // COLORTEMPINFO_H ukui-settings-daemon/plugins/save-param/xrandr-config.h0000644000175000017500000000553114205117202022177 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2012 by Alejandro Fiestas Olivares * Copyright 2016 by Sebastian Kügler * Copyright (c) 2018 Kai Uwe Broulik * Work sponsored by the LiMux project of * the city of Munich. * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XRANDRCONFIG_H #define XRANDRCONFIG_H #include #include #include //#include #include #include "xrandr-output.h" class xrandrConfig : public QObject { Q_OBJECT public: explicit xrandrConfig(KScreen::ConfigPtr config, QObject *parent = nullptr); ~xrandrConfig() = default; QString id() const; bool fileExists() const; bool fileScreenModeExists(QString screenMode); std::unique_ptr readFile(bool isUseModeDirConfig); std::unique_ptr readOpenLidFile(); std::unique_ptr readFile(const QString &fileName, bool state); std::unique_ptr readScreensConfigFromDbus(const QString &screensParam); bool writeFile(bool state); bool writeOpenLidFile(); bool writeConfigAndBackupToModeDir(); bool writeFile(const QString &filePath, bool state); QString getScreensParam(); KScreen::ConfigPtr data() const { return mConfig; } void log(); void setPriName(QString name){ priName = name; } void setValidityFlags(KScreen::Config::ValidityFlags flags) { mValidityFlags = flags; } bool canBeApplied() const; QString filePath() const; QString fileModeConfigPath(); void setScreenMode(QString modeName); private: bool canBeApplied(KScreen::ConfigPtr config) const; static QString configsDirPath(); QString configsModeDirPath(); static QString sleepDirPath(); KScreen::ConfigPtr mConfig; KScreen::Config::ValidityFlags mValidityFlags; QString priName; bool mAddScreen = false; QString mScreenMode; static QString mConfigsDirName; static QString mFixedConfigFileName; }; #endif // XRANDRCONFIG_H ukui-settings-daemon/plugins/save-param/xrandr-config.cpp0000644000175000017500000002744014205117202022535 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2012 by Alejandro Fiestas Olivares * Copyright 2016 by Sebastian Kügler * Copyright (c) 2018 Kai Uwe Broulik * Work sponsored by the LiMux project of * the city of Munich. * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "xrandr-config.h" #include "clib-syslog.h" QString xrandrConfig::mFixedConfigFileName = QStringLiteral("fixed-config"); QString xrandrConfig::mConfigsDirName = QStringLiteral("" /*"configs/"*/); // TODO: KDE6 - move these files into the subfolder QString xrandrConfig::configsDirPath() { QString dirPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QStringLiteral("/kscreen/"); return dirPath % mConfigsDirName; } void xrandrConfig::setScreenMode(QString modeName) { mScreenMode = modeName; USD_LOG(LOG_DEBUG,"set mScreenMode to :%s",mScreenMode.toLatin1().data()); } QString xrandrConfig::configsModeDirPath() { QString dirPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QStringLiteral("/kscreen/") % mScreenMode % QStringLiteral("/"); return dirPath; } QString xrandrConfig::sleepDirPath() { QString dirPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QStringLiteral("/sleep-state/"); return dirPath % mConfigsDirName; } xrandrConfig::xrandrConfig(KScreen::ConfigPtr config, QObject *parent) : QObject(parent) { mConfig = config; } QString xrandrConfig::fileModeConfigPath() { if (!QDir().mkpath(configsModeDirPath())) { return QString(); } return configsModeDirPath() % id(); } QString xrandrConfig::filePath() const { if (!QDir().mkpath(configsDirPath())) { return QString(); } return configsDirPath() % id(); } QString xrandrConfig::id() const { if (!mConfig) { return QString(); } return mConfig->connectedOutputsHash(); } bool xrandrConfig::fileExists() const { return (QFile::exists(configsDirPath() % id())); } bool xrandrConfig::fileScreenModeExists(QString screenMode) { USD_LOG(LOG_DEBUG,"%s status:%d",(fileModeConfigPath()).toLatin1().data(),QFile::exists(fileModeConfigPath())); return QFile::exists(fileModeConfigPath()); } /* * isUseModeConfig:是否读取模式配置 * 模式配置只是在kds调用接口时使用 */ std::unique_ptr xrandrConfig::readFile(bool isUseModeDirConfig) { bool res = false; if (res){//Device::self()->isLaptop() && !Device::self()->isLidClosed()) { // We may look for a config that has been set when the lid was closed, Bug: 353029 const QString lidOpenedFilePath(filePath() % QStringLiteral("_lidOpened")); const QFile srcFile(lidOpenedFilePath); if (srcFile.exists()) { QFile::remove(filePath()); if (QFile::copy(lidOpenedFilePath, filePath())) { QFile::remove(lidOpenedFilePath); //qDebug() << "Restored lid opened config to" << id(); } } } return readFile(id(), isUseModeDirConfig); } std::unique_ptr xrandrConfig::readOpenLidFile() { const QString openLidFile = id() % QStringLiteral("_lidOpened"); auto config = readFile(openLidFile, false); QFile::remove(configsDirPath() % openLidFile); return config; } std::unique_ptr xrandrConfig::readScreensConfigFromDbus(const QString &screensParam) { std::unique_ptr config = std::unique_ptr(new xrandrConfig(mConfig->clone())); config->setValidityFlags(mValidityFlags); QJsonDocument parser; QVariantList outputs = parser.fromJson(screensParam.toLatin1().data()).toVariant().toList(); xrandrOutput::readInOutputs(config->data(), outputs); QSize screenSize; for (const auto &output : config->data()->outputs()) { if (!output->isConnected()) { continue; } if (1 == outputs.count() && (0 != output->pos().x() || 0 != output->pos().y())) { const QPoint pos(0,0); output->setPos(std::move(pos)); } const QRect geom = output->geometry(); if (geom.x() + geom.width() > screenSize.width()) { screenSize.setWidth(geom.x() + geom.width()); } if (geom.y() + geom.height() > screenSize.height()) { screenSize.setHeight(geom.y() + geom.height()); } } if (!canBeApplied(config->data())) { USD_LOG(LOG_ERR,"is a error param form dbus.."); return nullptr; } return config; } std::unique_ptr xrandrConfig::readFile(const QString &fileName, bool state) { int enabledOutputsCount = 0; if (!mConfig) { USD_LOG(LOG_ERR,"config is nullptr..."); return nullptr; } std::unique_ptr config = std::unique_ptr(new xrandrConfig(mConfig->clone())); config->setValidityFlags(mValidityFlags); QFile file; if(!state){ if (QFile::exists(configsDirPath() % mFixedConfigFileName)) { file.setFileName(configsDirPath() % mFixedConfigFileName);//先读取特定模式的配置, } else { file.setFileName(configsDirPath() % fileName); } if (!file.open(QIODevice::ReadOnly)) { USD_LOG(LOG_ERR,"config is nullptr..."); return nullptr; } } else { if (QFile::exists(configsModeDirPath())) { file.setFileName(configsModeDirPath() % fileName); } if (!file.open(QIODevice::ReadOnly)) { USD_LOG(LOG_ERR,"config is nullptr...%s",file.fileName().toLatin1().data()); return nullptr; } } QJsonDocument parser; QVariantList outputs = parser.fromJson(file.readAll()).toVariant().toList(); xrandrOutput::readInOutputs(config->data(), outputs); QSize screenSize; for (const auto &output : config->data()->outputs()) { if (output->isEnabled()) { enabledOutputsCount++; } if (!output->isConnected()) { continue; } if (1 == outputs.count() && (0 != output->pos().x() || 0 != output->pos().y())) { const QPoint pos(0,0); output->setPos(std::move(pos)); } const QRect geom = output->geometry(); if (geom.x() + geom.width() > screenSize.width()) { screenSize.setWidth(geom.x() + geom.width()); } if (geom.y() + geom.height() > screenSize.height()) { screenSize.setHeight(geom.y() + geom.height()); } } config->data()->screen()->setCurrentSize(screenSize); if (!canBeApplied(config->data())) { config->data()->screen()->setMaxActiveOutputsCount(enabledOutputsCount); if (!canBeApplied(config->data())) { return nullptr; } } return config; } bool xrandrConfig::canBeApplied() const { return canBeApplied(mConfig); } bool xrandrConfig::canBeApplied(KScreen::ConfigPtr config) const { return KScreen::Config::canBeApplied(config, mValidityFlags); } bool xrandrConfig::writeFile(bool state) { bool ret = 0; QDir dir; mAddScreen = state; writeFile(filePath(), false); if (dir.exists("/etc/usd/") == false) { dir.mkdir("/etc/usd/"); printf("mkdir.....\n"); } ret = QFile::copy(filePath(), "/etc/usd/" % id()); USD_LOG(LOG_DEBUG,"go...%d",ret); return true; } bool xrandrConfig::writeConfigAndBackupToModeDir() { return true; } QString xrandrConfig::getScreensParam() { const KScreen::OutputList outputs = mConfig->outputs(); QVariantList outputList; for (const KScreen::OutputPtr &output : outputs) { QVariantMap info; if (false == output->isConnected()) { continue; } xrandrOutput::writeGlobalPart(output, info, nullptr); info[QStringLiteral("primary")] = output->isPrimary();; // info[QStringLiteral("enabled")] = output->isEnabled(); auto setOutputConfigInfo = [&info](const KScreen::OutputPtr &out) { if (!out) { return; } QVariantMap pos; pos[QStringLiteral("x")] = out->pos().x(); pos[QStringLiteral("y")] = out->pos().y(); info[QStringLiteral("pos")] = pos; }; setOutputConfigInfo(output->isEnabled() ? output : nullptr); outputList.append(info); } return QJsonDocument::fromVariant(outputList).toJson(); } bool xrandrConfig::writeFile(const QString &filePath, bool state) { int screenConnectedCount = 0; bool priState = false; if (id().isEmpty()) { USD_LOG(LOG_DEBUG,"id is empty!"); return false; } const KScreen::OutputList outputs = mConfig->outputs(); QVariantList outputList; for (const KScreen::OutputPtr &output : outputs) { QVariantMap info; if (!output->isConnected()) { continue; } screenConnectedCount++; if (state || mAddScreen){ if (priName.compare(output->name()) == 0){ priState = true; } } else{ priState = output->isPrimary(); } xrandrOutput::writeGlobalPart(output, info, nullptr); info[QStringLiteral("primary")] = output->isPrimary();; // info[QStringLiteral("enabled")] = output->isEnabled(); auto setOutputConfigInfo = [&info](const KScreen::OutputPtr &out) { if (!out) { return; } QVariantMap pos; pos[QStringLiteral("x")] = out->pos().x(); pos[QStringLiteral("y")] = out->pos().y(); info[QStringLiteral("pos")] = pos; }; setOutputConfigInfo(output->isEnabled() ? output : nullptr); // if (output->isEnabled()) { // // try to update global output data // xrandrOutput::writeGlobal(output); // } outputList.append(info); } if (mAddScreen) mAddScreen = false; QFile file(filePath); if (file.open(QIODevice::WriteOnly)) { file.write(QJsonDocument::fromVariant(outputList).toJson()); } else { USD_LOG(LOG_DEBUG,"write file [%s] fail.cuz:%s.",file.fileName().toLatin1().data(),file.errorString().toLatin1().data()); } if (screenConnectedCount > 1) { QFile backFile(fileModeConfigPath()); if (backFile.open(QIODevice::WriteOnly)) { backFile.write(QJsonDocument::fromVariant(outputList).toJson()); } else { // USD_LOG(LOG_DEBUG,"write file [%s] fail.cuz:%s.",file.fileName().toLatin1().data(),backFile.errorString().toLatin1().data()); } } // printf("save [%s] ok\n",); USD_LOG(LOG_DEBUG,"write file:\n %s ok",filePath.toLatin1().data()); return true; } void xrandrConfig::log() { if (!mConfig) { return; } const auto outputs = mConfig->outputs(); for (const auto &o : outputs) { if (o->isConnected()) { USD_LOG_SHOW_OUTPUT(o); } } } ukui-settings-daemon/plugins/save-param/xrandr-output.cpp0000644000175000017500000004016614210057506022636 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2012 by Alejandro Fiestas Olivares * Copyright 2016 by Sebastian Kügler * Copyright (c) 2018 Kai Uwe Broulik * Work sponsored by the LiMux project of * the city of Munich. * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "xrandr-output.h" #include #include #include #include #include #include #include #include #include #include #include "xrandr-config.h" #include "clib-syslog.h" QString xrandrOutput::mDirName = QStringLiteral("outputs/"); QString xrandrOutput::dirPath() { return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QStringLiteral("/kscreen/") % mDirName; } QString xrandrOutput::globalFileName(const QString &hash) { return QString();//dir % hash; } void xrandrOutput::readInGlobalPartFromInfo(KScreen::OutputPtr output, const QVariantMap &info) { output->setRotation(static_cast(info.value(QStringLiteral("rotation"), 1).toInt())); bool scaleOk; const qreal scale = info.value(QStringLiteral("scale"), 1.).toDouble(&scaleOk); if (scaleOk) { output->setScale(scale); } const QVariantMap modeInfo = info[QStringLiteral("mode")].toMap(); const QVariantMap modeSize = modeInfo[QStringLiteral("size")].toMap(); const QSize size = QSize(modeSize[QStringLiteral("width")].toInt(), modeSize[QStringLiteral("height")].toInt()); const KScreen::ModeList modes = output->modes(); KScreen::ModePtr matchingMode; if (modes.count()<1) { USD_LOG(LOG_DEBUG, "%s mode count = 0.",output->name().toLatin1().data()); } for(const KScreen::ModePtr &mode : modes) { if (mode->size() != size) { continue; } if (!qFuzzyCompare(mode->refreshRate(), modeInfo[QStringLiteral("refresh")].toFloat())) { continue; } USD_LOG(LOG_DEBUG,"find mode id:%s %dx%d@%f", mode->id().toLatin1().data(), mode->size().height(), mode->size().width(),mode->refreshRate()); matchingMode = mode; break; } if (!matchingMode) { USD_LOG(LOG_DEBUG,"Failed to find a matching mode - this means that our config is corrupted"); matchingMode = output->preferredMode(); } if (!matchingMode) { USD_LOG(LOG_DEBUG,"Failed to get a preferred mode, falling back to biggest mode."); } if (!matchingMode) { USD_LOG(LOG_DEBUG,"Failed to get biggest mode. Which means there are no modes. Turning off the screen."); output->setEnabled(false); return; } output->setCurrentModeId(matchingMode->id()); } QVariantMap xrandrOutput::getGlobalData(KScreen::OutputPtr output) { QFile file(globalFileName(output->hashMd5())); if (!file.open(QIODevice::ReadOnly)) { return QVariantMap(); } QJsonDocument parser; return parser.fromJson(file.readAll()).toVariant().toMap(); } bool xrandrOutput::readInGlobal(KScreen::OutputPtr output) { const QVariantMap info = getGlobalData(output); if (info.empty()) { // if info is empty, the global file does not exists, or is in an unreadable state return false; } readInGlobalPartFromInfo(output, info); return true; } // TODO: move this into the Layouter class. void xrandrOutput::adjustPositions(KScreen::ConfigPtr config, const QVariantList &outputsInfo) { typedef QPair Out; KScreen::OutputList outputs = config->outputs(); QVector sortedOutputs; // for (const KScreen::OutputPtr &output : outputs) { sortedOutputs.append(Out(output->id(), output->pos())); } // go from left to right, top to bottom std::sort(sortedOutputs.begin(), sortedOutputs.end(), [](const Out &o1, const Out &o2) { const int x1 = o1.second.x(); const int x2 = o2.second.x(); return x1 < x2 || (x1 == x2 && o1.second.y() < o2.second.y()); }); for (int cnt = 1; cnt < sortedOutputs.length(); cnt++) { auto getOutputInfoProperties = [outputsInfo](KScreen::OutputPtr output, QRect &geo) -> bool { if (!output) { return false; } const auto hash = output->hash(); auto it = std::find_if(outputsInfo.begin(), outputsInfo.end(), [hash](QVariant v) { const QVariantMap info = v.toMap(); return info[QStringLiteral("id")].toString() == hash; } ); if (it == outputsInfo.end()) { return false; } auto isPortrait = [](const QVariant &info) { bool ok; const int rot = info.toInt(&ok); if (!ok) { return false; } return rot & KScreen::Output::Rotation::Left || rot & KScreen::Output::Rotation::Right; }; const QVariantMap outputInfo = it->toMap(); const QVariantMap posInfo = outputInfo[QStringLiteral("pos")].toMap(); const QVariant scaleInfo = outputInfo[QStringLiteral("scale")]; const QVariantMap modeInfo = outputInfo[QStringLiteral("mode")].toMap(); const QVariantMap modeSize = modeInfo[QStringLiteral("size")].toMap(); const bool portrait = isPortrait(outputInfo[QStringLiteral("rotation")]); if (posInfo.isEmpty() || modeSize.isEmpty() || !scaleInfo.canConvert()) { return false; } const qreal scale = scaleInfo.toDouble(); if (scale <= 0) { return false; } const QPoint pos = QPoint(posInfo[QStringLiteral("x")].toInt(), posInfo[QStringLiteral("y")].toInt()); QSize size = QSize(modeSize[QStringLiteral("width")].toInt() / scale, modeSize[QStringLiteral("height")].toInt() / scale); if (portrait) { size.transpose(); } geo = QRect(pos, size); return true; }; // it's guaranteed that we find the following values in the QMap KScreen::OutputPtr prevPtr = outputs.find(sortedOutputs[cnt - 1].first).value(); KScreen::OutputPtr curPtr = outputs.find(sortedOutputs[cnt].first).value(); QRect prevInfoGeo, curInfoGeo; if (!getOutputInfoProperties(prevPtr, prevInfoGeo) || !getOutputInfoProperties(curPtr, curInfoGeo)) { // no info found, nothing can be adjusted for the next output continue; } const QRect prevGeo = prevPtr->geometry(); const QRect curGeo = curPtr->geometry(); // the old difference between previous and current output read from the config file const int xInfoDiff = curInfoGeo.x() - (prevInfoGeo.x() + prevInfoGeo.width()); // the proposed new difference const int prevRight = prevGeo.x() + prevGeo.width(); const int xCorrected = prevRight + prevGeo.width() * xInfoDiff / (double)prevInfoGeo.width(); const int xDiff = curGeo.x() - prevRight; // In the following calculate the y-correction. This is more involved since we // differentiate between overlapping and non-overlapping pairs and align either // top to top/bottom or bottom to top/bottom const bool yOverlap = prevInfoGeo.y() + prevInfoGeo.height() > curInfoGeo.y() && prevInfoGeo.y() < curInfoGeo.y() + curInfoGeo.height(); // these values determine which horizontal edge of previous output we align with const int topToTopDiffAbs = qAbs(prevInfoGeo.y() - curInfoGeo.y()); const int topToBottomDiffAbs = qAbs(prevInfoGeo.y() - curInfoGeo.y() - curInfoGeo.height()); const int bottomToBottomDiffAbs = qAbs(prevInfoGeo.y() + prevInfoGeo.height() - curInfoGeo.y() - curInfoGeo.height()); const int bottomToTopDiffAbs = qAbs(prevInfoGeo.y() + prevInfoGeo.height() - curInfoGeo.y()); const bool yTopAligned = (topToTopDiffAbs < bottomToBottomDiffAbs && topToTopDiffAbs <= bottomToTopDiffAbs) || topToBottomDiffAbs < bottomToBottomDiffAbs; int yInfoDiff = curInfoGeo.y() - prevInfoGeo.y(); int yDiff = curGeo.y() - prevGeo.y(); int yCorrected; if (yTopAligned) { // align to previous top if (!yOverlap) { // align previous top with current bottom yInfoDiff += curInfoGeo.height(); yDiff += curGeo.height(); } // When we align with previous top we are interested in the changes to the // current geometry and not in the ones of the previous one. const double yInfoRel = yInfoDiff / (double)curInfoGeo.height(); yCorrected = prevGeo.y() + yInfoRel * curGeo.height(); } else { // align previous bottom... yInfoDiff -= prevInfoGeo.height(); yDiff -= prevGeo.height(); yCorrected = prevGeo.y() + prevGeo.height(); if (yOverlap) { // ... with current bottom yInfoDiff += curInfoGeo.height(); yDiff += curGeo.height(); yCorrected -= curGeo.height(); } // ... else with current top // When we align with previous bottom we are interested in changes to the // previous geometry. const double yInfoRel = yInfoDiff / (double)prevInfoGeo.height(); yCorrected += yInfoRel * prevGeo.height(); } const int x = xDiff == xInfoDiff ? curGeo.x() : xCorrected; const int y = yDiff == yInfoDiff ? curGeo.y() : yCorrected; curPtr->setPos(QPoint(x, y)); } } void xrandrOutput::readIn(KScreen::OutputPtr output, const QVariantMap &info) { const QVariantMap posInfo = info[QStringLiteral("pos")].toMap(); QPoint point(posInfo[QStringLiteral("x")].toInt(), posInfo[QStringLiteral("y")].toInt()); output->setPos(point); output->setPrimary(info[QStringLiteral("primary")].toBool()); output->setEnabled(info[QStringLiteral("enabled")].toBool()); if (readInGlobal(output)) { USD_LOG(LOG_DEBUG,"out it...."); // output data read from global output file return; } // output data read directly from info readInGlobalPartFromInfo(output, info); } void xrandrOutput::readInOutputs(KScreen::ConfigPtr config, const QVariantList &outputsInfo) { const KScreen::OutputList outputs = config->outputs(); // As global outputs are indexed by a hash of their edid, which is not unique, // to be able to tell apart multiple identical outputs, these need special treatment QStringList duplicateIds; { QStringList allIds; allIds.reserve(outputs.count()); for (const KScreen::OutputPtr &output : outputs) { const auto outputId = output->hash(); if (allIds.contains(outputId) && !duplicateIds.contains(outputId)) { duplicateIds << outputId; } allIds << outputId; } } for (const KScreen::OutputPtr &output : outputs) { if (!output->isConnected()) { output->setEnabled(false); continue; } const auto outputId = output->hash(); bool infoFound = false; for (const auto &variantInfo : outputsInfo) { const QVariantMap info = variantInfo.toMap(); if (outputId != info[QStringLiteral("id")].toString()) { continue; } if (!output->name().isEmpty() && duplicateIds.contains(outputId)) { // We may have identical outputs connected, these will have the same id in the config // in order to find the right one, also check the output's name (usually the connector) const auto metadata = info[QStringLiteral("metadata")].toMap(); const auto outputName = metadata[QStringLiteral("name")].toString(); if (output->name() != outputName) { // was a duplicate id, but info not for this output continue; } } infoFound = true; readIn(output, info);//, control.getOutputRetention(output)); break; } if (!infoFound) { // no info in info for this output, try reading in global output info at least or set some default values qWarning() << "\tFailed to find a matching output in the current info data - this means that our info is corrupted" "or a different device with the same serial number has been connected (very unlikely)."; if (!readInGlobal(output)) { // set some default values instead readInGlobalPartFromInfo(output, QVariantMap()); } } } for (KScreen::OutputPtr output : outputs) { auto replicationSource = nullptr;//control.getReplicationSource(output); if (replicationSource) { //output->setPos(replicationSource->pos()); //output->setLogicalSize(replicationSource->logicalSize()); } else { output->setExplicitLogicalSize(QSizeF()); } } // TODO: this does not work at the moment with logical size replication. Deactivate for now. // correct positional config regressions on global output data changes #if 1 adjustPositions(config, outputsInfo); #endif } QVariantMap metadata(const KScreen::OutputPtr &output) { QVariantMap metadata; metadata[QStringLiteral("name")] = output->name(); if (!output->edid() || !output->edid()->isValid()) { return metadata; } metadata[QStringLiteral("fullname")] = output->edid()->deviceId(); return metadata; } void xrandrOutput::writeGlobal(const KScreen::OutputPtr &output) { // get old values and subsequently override QVariantMap info = getGlobalData(output); if (!writeGlobalPart(output, info, nullptr)) { return; } QFile file(globalFileName(output->hashMd5())); if (!file.open(QIODevice::WriteOnly)) { USD_LOG(LOG_DEBUG, "Failed to open global output file for writing! ", file.errorString().toLatin1().data()); return; } file.write(QJsonDocument::fromVariant(info).toJson()); return; } bool xrandrOutput::writeGlobalPart(const KScreen::OutputPtr &output, QVariantMap &info, const KScreen::OutputPtr &fallback) { info[QStringLiteral("id")] = output->hash(); info[QStringLiteral("metadata")] = metadata(output); info[QStringLiteral("rotation")] = output->rotation(); // Round scale to four digits info[QStringLiteral("scale")] = int(output->scale() * 10000 + 0.5) / 10000.; QVariantMap modeInfo; float refreshRate = -1.; QSize modeSize; if (output->currentMode() && output->isEnabled()) { refreshRate = output->currentMode()->refreshRate(); modeSize = output->currentMode()->size(); } if (refreshRate < 0 || !modeSize.isValid()) { return false; } modeInfo[QStringLiteral("refresh")] = refreshRate; QVariantMap modeSizeMap; modeSizeMap[QStringLiteral("width")] = modeSize.width(); modeSizeMap[QStringLiteral("height")] = modeSize.height(); modeInfo[QStringLiteral("size")] = modeSizeMap; info[QStringLiteral("mode")] = modeInfo; return true; } ukui-settings-daemon/plugins/save-param/save-screen.cpp0000644000175000017500000000403114205117202022176 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include "save-screen.h" #include "clib-syslog.h" SaveScreenParam::SaveScreenParam(QObject *parent) { Q_UNUSED(parent); } SaveScreenParam::~SaveScreenParam() { } void SaveScreenParam::getConfig(){ QObject::connect(new KScreen::GetConfigOperation(), &KScreen::GetConfigOperation::finished, [&](KScreen::ConfigOperation *op) { if (m_MonitoredConfig) { if (m_MonitoredConfig->data()) { KScreen::ConfigMonitor::instance()->removeConfig(m_MonitoredConfig->data()); for (const KScreen::OutputPtr &output : m_MonitoredConfig->data()->outputs()) { output->disconnect(this); } m_MonitoredConfig->data()->disconnect(this); } m_MonitoredConfig = nullptr; } m_MonitoredConfig = std::unique_ptr(new xrandrConfig(qobject_cast(op)->config())); m_MonitoredConfig->setValidityFlags(KScreen::Config::ValidityFlag::RequireAtLeastOneEnabledScreen); m_MonitoredConfig->writeFile(false); exit(0); }); } ukui-settings-daemon/plugins/save-param/save-screen.h0000644000175000017500000000251314205117202021646 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef KDSWIDGET_H #define KDSWIDGET_H #include #include #include #include #include #include #include "xrandr-config.h" class SaveScreenParam : QObject { Q_OBJECT public: explicit SaveScreenParam(QObject *parent = nullptr); ~SaveScreenParam(); void getConfig(); private: std::unique_ptr m_MonitoredConfig = nullptr; }; #endif // KDSWIDGET_H ukui-settings-daemon/plugins/save-param/main.cpp0000644000175000017500000000206614205117202020715 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright (C) 2019 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 "save-screen.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); SaveScreenParam saveParam; saveParam.getConfig(); return app.exec(); } ukui-settings-daemon/plugins/save-param/save-param.pro0000644000175000017500000000277714205117202022054 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-11-12T15:37:31 # #------------------------------------------------- QT +=xml core gui dbus network KWindowSystem KScreen greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = save-param TEMPLATE = app # The following define makes your compiler emit warnings if you use # any feature of Qt which as been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"save-param\\\" LIBS += -lX11 -lgsettings-qt CONFIG += link_pkgconfig CONFIG += C++11 PKGCONFIG += mate-desktop-2.0 \ PKGCONFIG += glib-2.0 gio-2.0 libxklavier x11 xrandr xtst atk gdk-3.0 gtk+-3.0 xi # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 target.source += $$TARGET target.path = /usr/bin INSTALLS += \ target SOURCES += \ save-screen.cpp \ xrandr-config.cpp \ xrandr-output.cpp \ main.cpp HEADERS += \ color-temp-info.h \ save-screen.h \ xrandr-config.h \ xrandr-output.h TRANSLATIONS += \ res/zh_CN.ts \ include($$PWD/../../common/common.pri) ukui-settings-daemon/plugins/a11y-settings/0000755000175000017500000000000014205117202017636 5ustar fengfengukui-settings-daemon/plugins/a11y-settings/a11y-settings-plugin.cpp0000644000175000017500000000351014205117202024246 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "a11y-settings-plugin.h" #include "clib-syslog.h" PluginInterface* A11ySettingsPlugin::mInstance = nullptr; A11ySettingsPlugin::A11ySettingsPlugin() { USD_LOG(LOG_DEBUG,"A11SettingsPlugin initializing!"); settingsManager=A11ySettingsManager::A11ySettingsManagerNew(); } A11ySettingsPlugin::~A11ySettingsPlugin() { if (settingsManager) delete settingsManager; } void A11ySettingsPlugin::activate() { bool res; USD_LOG(LOG_DEBUG,"Activating a11y-settings plugincompilation time:[%s] [%s]",__DATE__,__TIME__); res=settingsManager->A11ySettingsManagerStart(); if(!res){ USD_LOG(LOG_WARNING,"Unable to start a11y-settings manager!"); } } PluginInterface *A11ySettingsPlugin::getInstance() { if (nullptr == mInstance) { mInstance = new A11ySettingsPlugin(); } return mInstance; } void A11ySettingsPlugin::deactivate() { USD_LOG(LOG_DEBUG,"Deactivating a11y-settings plugin!"); settingsManager->A11ySettingsMAnagerStop(); } PluginInterface* createSettingsPlugin() { return A11ySettingsPlugin::getInstance(); } ukui-settings-daemon/plugins/a11y-settings/a11y-settings.pro0000644000175000017500000000142614205117202022774 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-08-05T19:30:00 # #------------------------------------------------- QT -= gui QT += core widgets x11extras TEMPLATE = lib TARGET = a11y-settings CONFIG += c++11 plugin link_pkgconfig CONFIG -= app_bundle DEFINES += QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"a11y-settings\\\" include($$PWD/../../common/common.pri) PKGCONFIG += \ glib-2.0 \ gio-2.0 \ gsettings-qt SOURCES += \ $$PWD/a11y-settings-manager.cpp \ $$PWD/a11y-settings-plugin.cpp HEADERS += \ $$PWD/a11y-settings-manager.h \ $$PWD/a11y-settings-plugin.h a11_settings_lib.path = $${PLUGIN_INSTALL_DIRS} a11_settings_lib.files = $$OUT_PWD/liba11y-settings.so INSTALLS += a11_settings_lib ukui-settings-daemon/plugins/a11y-settings/a11y-settings-manager.h0000644000175000017500000000256014205117202024033 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef A11YSETTINGS_H #define A11YSETTINGS_H #include #include #include #include class A11ySettingsManager : public QObject { Q_OBJECT private: A11ySettingsManager(); public: ~A11ySettingsManager(); static A11ySettingsManager* A11ySettingsManagerNew(); bool A11ySettingsManagerStart(); void A11ySettingsMAnagerStop(); public Q_SLOTS: void AppsSettingsChanged(QString); private: static A11ySettingsManager* mA11ySettingsManager; QGSettings *interface_settings; QGSettings *a11y_apps_settings; }; #endif // A11YSETTINGS_H ukui-settings-daemon/plugins/a11y-settings/a11y-settings-manager.cpp0000644000175000017500000000575514205117202024377 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "a11y-settings-manager.h" #include "clib-syslog.h" A11ySettingsManager* A11ySettingsManager::mA11ySettingsManager = nullptr; A11ySettingsManager::A11ySettingsManager() { interface_settings = new QGSettings("org.mate.interface"); a11y_apps_settings = new QGSettings("org.gnome.desktop.a11y.applications"); } A11ySettingsManager::~A11ySettingsManager() { delete interface_settings; delete a11y_apps_settings; } A11ySettingsManager* A11ySettingsManager::A11ySettingsManagerNew() { if(nullptr == mA11ySettingsManager) mA11ySettingsManager = new A11ySettingsManager(); return mA11ySettingsManager; } void A11ySettingsManager::AppsSettingsChanged(QString key){ bool screen_reader,keyboard; if((key == "screen-reader-enabled") == false && (key == "screen-keyboard-enabled") == false) return; USD_LOG(LOG_DEBUG,"screen reader or OSK enabledment changed"); screen_reader = a11y_apps_settings->get("screen-reader-enabled").toBool(); keyboard = a11y_apps_settings->get("screen-keyboard-enabled").toBool(); if(screen_reader || keyboard){ USD_LOG(LOG_DEBUG,"Enabling accessibility,screen reader or OSK enabled!"); interface_settings->set("accessibility",true); }else if((screen_reader == false) && (keyboard == false)){ USD_LOG(LOG_DEBUG,"Disabling accessibility,screen reader or OSK disabled!"); interface_settings->set("accessibility",false); } } bool A11ySettingsManager::A11ySettingsManagerStart() { USD_LOG(LOG_DEBUG,"Starting a11y_settings manager!"); connect(a11y_apps_settings, SIGNAL(changed(QString)), this, SLOT(AppsSettingsChanged(QString))); /* If any of the screen reader or on-screen keyboard are enabled, * make sure a11y is enabled for the toolkits. * We don't do the same thing for the reverse so it's possible to * enable AT-SPI for the toolkits without using an a11y app */ if(a11y_apps_settings->get("screen-keyboard-enabled").toBool()|| a11y_apps_settings->get("screen-reader-enabled").toBool()) interface_settings->set("accessibility",true); return true; } void A11ySettingsManager::A11ySettingsMAnagerStop() { USD_LOG(LOG_DEBUG,"Stopping a11y_settings manager"); } ukui-settings-daemon/plugins/a11y-settings/a11y-settings-plugin.h0000644000175000017500000000250414205117202023715 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef A11YSETTINGSPLUGIN_H #define A11YSETTINGSPLUGIN_H #include "plugin-interface.h" #include "a11y-settings-manager.h" class A11ySettingsPlugin : public PluginInterface { public: ~A11ySettingsPlugin(); static PluginInterface* getInstance(); void activate(); void deactivate(); private: A11ySettingsPlugin(); A11ySettingsPlugin(A11ySettingsPlugin&) = delete; A11ySettingsManager* settingsManager; static PluginInterface* mInstance; }; extern "C" Q_DECL_EXPORT PluginInterface* createSettingsPlugin(); #endif // A11YSETTINGSPLUGIN_H ukui-settings-daemon/plugins/locate-pointer/0000755000175000017500000000000014205117202020152 5ustar fengfengukui-settings-daemon/plugins/locate-pointer/usd-locate-pointer.c0000644000175000017500000004442314205117202024043 0ustar fengfeng/* usd-locate-pointer.c * * Copyright (C) 2008 Carlos Garnacho * * This program is free software; you can redistribute it and/or modify it * under the terms of the 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 "usd-timeline.h" #include "usd-locate-pointer.h" #include #include #include #define ANIMATION_LENGTH 750 #define WINDOW_SIZE 101 #define N_CIRCLES 4 /* All circles are supposed to be moving when progress * reaches 0.5, and each of them are supposed to long * for half of the progress, hence the need of 0.5 to * get the circles interval, and the multiplication * by 2 to know a circle progress */ #define CIRCLES_PROGRESS_INTERVAL (0.5 / N_CIRCLES) #define CIRCLE_PROGRESS(p) (MIN (1., ((gdouble) (p) * 2.))) typedef struct UsdLocatePointerData UsdLocatePointerData; struct UsdLocatePointerData { UsdTimeline *timeline; GtkWindow *widget; GdkWindow *window; gdouble progress; }; static UsdLocatePointerData *data = NULL; static void locate_pointer_paint (UsdLocatePointerData *data, cairo_t *cr, gboolean composited) { GdkRGBA color; gdouble progress, circle_progress; gint width, height, i; GtkStyleContext *style; color.red = color.green = color.blue = 0.7; color.alpha = 0.; progress = data->progress; width = gdk_window_get_width (data->window); height = gdk_window_get_height (data->window); style = gtk_widget_get_style_context (GTK_WIDGET (data->widget)); gtk_style_context_save (style); gtk_style_context_set_state (style, GTK_STATE_FLAG_SELECTED); gtk_style_context_add_class (style, GTK_STYLE_CLASS_VIEW); gtk_style_context_get_background_color (style, gtk_style_context_get_state (style), &color); if (color.alpha == 0.) { gtk_style_context_remove_class (style, GTK_STYLE_CLASS_VIEW); gtk_style_context_get_background_color (style, gtk_style_context_get_state (style), &color); } gtk_style_context_restore (style); cairo_save (cr); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgba (cr, 1., 1., 1., 0.); cairo_paint (cr); for (i = 0; i <= N_CIRCLES; i++) { if (progress < 0.) break; circle_progress = MIN (1., (progress * 2)); progress -= CIRCLES_PROGRESS_INTERVAL; if (circle_progress >= 1.) continue; if (composited) { cairo_set_source_rgba (cr, color.red, color.green, color.blue, 1 - circle_progress); cairo_arc (cr, width / 2, height / 2, circle_progress * width / 2, 0, 2 * G_PI); cairo_fill (cr); cairo_stroke (cr); } else { cairo_set_source_rgb (cr, 0., 0., 0.); cairo_set_line_width (cr, 3.); cairo_arc (cr, width / 2, height / 2, circle_progress * width / 2, 0, 2 * G_PI); cairo_stroke (cr); cairo_set_source_rgb (cr, 1., 1., 1.); cairo_set_line_width (cr, 1.); cairo_arc (cr, width / 2, height / 2, circle_progress * width / 2, 0, 2 * G_PI); cairo_stroke (cr); } } cairo_restore (cr); } static void update_shape (UsdLocatePointerData *data) { cairo_t *cr; cairo_surface_t *mask; cairo_region_t *region; mask = gdk_window_create_similar_image_surface (data->window, CAIRO_FORMAT_A1, WINDOW_SIZE, WINDOW_SIZE, 0); cr = cairo_create (mask); locate_pointer_paint (data, cr, FALSE); region = gdk_cairo_region_create_from_surface (mask); gdk_window_shape_combine_region (data->window, region, 0, 0); cairo_region_destroy (region); cairo_destroy (cr); cairo_surface_destroy (mask); } static void timeline_frame_cb (UsdTimeline *timeline, gdouble progress, gpointer user_data) { UsdLocatePointerData *data = (UsdLocatePointerData *) user_data; GdkDisplay *display = gdk_window_get_display (data->window); GdkScreen *screen = gdk_display_get_default_screen (display); #if GTK_CHECK_VERSION (3, 20, 0) GdkSeat *seat; #else GdkDeviceManager *device_manager; #endif GdkDevice *pointer; gint cursor_x, cursor_y; if (gdk_screen_is_composited (screen)) { gtk_widget_queue_draw (GTK_WIDGET (data->widget)); data->progress = progress; } else if (progress >= data->progress + CIRCLES_PROGRESS_INTERVAL) { /* only invalidate window each circle interval */ update_shape (data); gtk_widget_queue_draw (GTK_WIDGET (data->widget)); data->progress += CIRCLES_PROGRESS_INTERVAL; } #if GTK_CHECK_VERSION (3, 20, 0) seat = gdk_display_get_default_seat (display); pointer = gdk_seat_get_pointer (seat); #else device_manager = gdk_display_get_device_manager (display); pointer = gdk_device_manager_get_client_pointer (device_manager); #endif gdk_device_get_position (pointer, NULL, &cursor_x, &cursor_y); gtk_window_move (data->widget, cursor_x - WINDOW_SIZE / 2, cursor_y - WINDOW_SIZE / 2); } static void set_transparent_shape (GdkWindow *window) { cairo_t *cr; cairo_surface_t *mask; cairo_region_t *region; mask = gdk_window_create_similar_image_surface (window, CAIRO_FORMAT_A1, WINDOW_SIZE, WINDOW_SIZE, 0); cr = cairo_create (mask); cairo_set_source_rgba (cr, 1., 1., 1., 0.); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); region = gdk_cairo_region_create_from_surface (mask); gdk_window_shape_combine_region (window, region, 0, 0); cairo_region_destroy (region); cairo_destroy (cr); cairo_surface_destroy (mask); } static void unset_transparent_shape (GdkWindow *window) { gdk_window_shape_combine_region (window, NULL, 0, 0); } static void composited_changed (GdkScreen *screen, UsdLocatePointerData *data) { if (gdk_screen_is_composited (screen)) { unset_transparent_shape (data->window); } else { set_transparent_shape (data->window); } } static void timeline_finished_cb (UsdTimeline *timeline, gpointer user_data) { UsdLocatePointerData *data = (UsdLocatePointerData *) user_data; GdkScreen *screen = gdk_window_get_screen (data->window); /* set transparent shape and hide window */ if (!gdk_screen_is_composited (screen)) { set_transparent_shape (data->window); } gtk_widget_hide (GTK_WIDGET (data->widget)); } static void locate_pointer_unrealize_cb (GtkWidget *widget, UsdLocatePointerData *data) { if (data->window != NULL) { gtk_widget_unregister_window (GTK_WIDGET (data->widget), data->window); gdk_window_destroy (data->window); } data->window = NULL; } static void locate_pointer_realize_cb (GtkWidget *widget, UsdLocatePointerData *data) { GdkDisplay *display; GdkScreen *screen; GdkVisual *visual; GdkWindowAttr attributes; gint attributes_mask; display = gtk_widget_get_display (GTK_WIDGET (data->widget)); screen = gdk_display_get_default_screen (display); visual = gdk_screen_get_rgba_visual (screen); if (visual == NULL) visual = gdk_screen_get_system_visual (screen); locate_pointer_unrealize_cb (GTK_WIDGET (data->widget), data); attributes_mask = GDK_WA_X | GDK_WA_Y; if (visual != NULL) { attributes_mask |= GDK_WA_VISUAL; } attributes.window_type = GDK_WINDOW_TEMP; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = visual; attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK; attributes.width = 1; attributes.height = 1; data->window = gdk_window_new (gdk_screen_get_root_window (screen), &attributes, attributes_mask); gtk_widget_set_window (GTK_WIDGET (data->widget), data->window); gtk_widget_register_window (GTK_WIDGET (data->widget), data->window); } static gboolean locate_pointer_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data) { UsdLocatePointerData *data = (UsdLocatePointerData *) user_data; GdkScreen *screen = gdk_window_get_screen (data->window); if (gtk_cairo_should_draw_window (cr, data->window)) { locate_pointer_paint (data, cr, gdk_screen_is_composited (screen)); } return TRUE; } static UsdLocatePointerData * usd_locate_pointer_data_new (void) { UsdLocatePointerData *data; data = g_new0 (UsdLocatePointerData, 1); data->widget = GTK_WINDOW (gtk_window_new (GTK_WINDOW_POPUP)); g_signal_connect (GTK_WIDGET (data->widget), "unrealize", G_CALLBACK (locate_pointer_unrealize_cb), data); g_signal_connect (GTK_WIDGET (data->widget), "realize", G_CALLBACK (locate_pointer_realize_cb), data); g_signal_connect (GTK_WIDGET (data->widget), "draw", G_CALLBACK (locate_pointer_draw_cb), data); gtk_widget_set_app_paintable (GTK_WIDGET (data->widget), TRUE); gtk_widget_realize (GTK_WIDGET (data->widget)); data->timeline = usd_timeline_new (ANIMATION_LENGTH); g_signal_connect (data->timeline, "frame", G_CALLBACK (timeline_frame_cb), data); g_signal_connect (data->timeline, "finished", G_CALLBACK (timeline_finished_cb), data); return data; } static void move_locate_pointer_window (UsdLocatePointerData *data, GdkDisplay *display) { #if GTK_CHECK_VERSION (3, 20, 0) GdkSeat *seat; #else GdkDeviceManager *device_manager; #endif GdkDevice *pointer; gint cursor_x, cursor_y; cairo_t *cr; cairo_surface_t *mask; cairo_region_t *region; #if GTK_CHECK_VERSION (3, 20, 0) seat = gdk_display_get_default_seat (display); pointer = gdk_seat_get_pointer (seat); #else device_manager = gdk_display_get_device_manager (display); pointer = gdk_device_manager_get_client_pointer (device_manager); #endif gdk_device_get_position (pointer, NULL, &cursor_x, &cursor_y); gtk_window_move (data->widget, cursor_x - WINDOW_SIZE / 2, cursor_y - WINDOW_SIZE / 2); gtk_window_resize (data->widget, WINDOW_SIZE, WINDOW_SIZE); mask = gdk_window_create_similar_image_surface (data->window, CAIRO_FORMAT_A1, WINDOW_SIZE, WINDOW_SIZE, 0); cr = cairo_create (mask); cairo_set_source_rgba (cr, 0., 0., 0., 0.); cairo_paint (cr); region = gdk_cairo_region_create_from_surface (mask); gdk_window_input_shape_combine_region (data->window, region, 0, 0); cairo_region_destroy (region); cairo_destroy (cr); cairo_surface_destroy (mask); } void usd_locate_pointer (GdkDisplay *display) { GdkScreen *screen = gdk_display_get_default_screen (display); if (data == NULL) { data = usd_locate_pointer_data_new (); } usd_timeline_pause (data->timeline); usd_timeline_rewind (data->timeline); data->progress = 0.; g_signal_connect (screen, "composited-changed", G_CALLBACK (composited_changed), data); move_locate_pointer_window (data, display); composited_changed (screen, data); gtk_widget_show (GTK_WIDGET (data->widget)); usd_timeline_start (data->timeline); } #define KEYBOARD_GROUP_SHIFT 13 #define KEYBOARD_GROUP_MASK ((1 << 13) | (1 << 14)) /* Owen magic */ static GdkFilterReturn event_filter (GdkXEvent *gdkxevent, GdkEvent *event, gpointer user_data) { XEvent *xevent = (XEvent *) gdkxevent; GdkDisplay *display = (GdkDisplay *) user_data; if (xevent->xany.type == KeyPress || xevent->xany.type == KeyRelease) { guint keyval; gint group; /* get the keysym */ group = (xevent->xkey.state & KEYBOARD_GROUP_MASK) >> KEYBOARD_GROUP_SHIFT; gdk_keymap_translate_keyboard_state (gdk_keymap_get_for_display (display), xevent->xkey.keycode, xevent->xkey.state, group, &keyval, NULL, NULL, NULL); if (keyval == GDK_KEY_Control_L || keyval == GDK_KEY_Control_R) { if (xevent->xany.type == KeyRelease) { XUngrabButton (xevent->xany.display, AnyButton, AnyModifier, xevent->xany.window); XAllowEvents (xevent->xany.display, AsyncKeyboard, xevent->xkey.time); usd_locate_pointer (display); } else { XAllowEvents (xevent->xany.display, SyncKeyboard, xevent->xkey.time); XGrabButton (xevent->xany.display, AnyButton, AnyModifier, xevent->xany.window, False, ButtonPressMask, GrabModeSync, GrabModeAsync, None, None); } } else { XAllowEvents (xevent->xany.display, ReplayKeyboard, xevent->xkey.time); XUngrabButton (xevent->xany.display, AnyButton, AnyModifier, xevent->xany.window); XUngrabKeyboard (xevent->xany.display, xevent->xkey.time); } } else if (xevent->xany.type == ButtonPress) { XAllowEvents (xevent->xany.display, ReplayPointer, xevent->xbutton.time); XUngrabButton (xevent->xany.display, AnyButton, AnyModifier, xevent->xany.window); XUngrabKeyboard (xevent->xany.display, xevent->xbutton.time); } return GDK_FILTER_CONTINUE; } static void set_locate_pointer (void) { GdkKeymapKey *keys; GdkDisplay *display; GdkScreen *screen; int n_keys; gboolean has_entries = FALSE; static const guint keyvals[] = { GDK_KEY_Control_L, GDK_KEY_Control_R }; unsigned int i, j; display = gdk_display_get_default (); screen = gdk_display_get_default_screen (display); for (i = 0; i < G_N_ELEMENTS (keyvals); ++i) { if (gdk_keymap_get_entries_for_keyval (gdk_keymap_get_for_display (display), keyvals[i], &keys, &n_keys)) { has_entries = TRUE; for (j = 0; j < n_keys; ++j) { Window xroot; xroot = GDK_WINDOW_XID (gdk_screen_get_root_window (screen)); XGrabKey (GDK_DISPLAY_XDISPLAY (display), keys[j].keycode, 0, xroot, False, GrabModeAsync, GrabModeSync); XGrabKey (GDK_DISPLAY_XDISPLAY (display), keys[j].keycode, LockMask, xroot, False, GrabModeAsync, GrabModeSync); XGrabKey (GDK_DISPLAY_XDISPLAY (display), keys[j].keycode, Mod2Mask, xroot, False, GrabModeAsync, GrabModeSync); XGrabKey (GDK_DISPLAY_XDISPLAY (display), keys[j].keycode, Mod4Mask, xroot, False, GrabModeAsync, GrabModeSync); } g_free (keys); } } if (has_entries) { gdk_window_add_filter (gdk_screen_get_root_window (screen), (GdkFilterFunc) event_filter, display); } } static void mouse_callback (GSettings *settings, const gchar *key, gpointer *manager) { if(g_strcmp0 (key, "locate-pointer") == 0){ GdkDisplay *display = gdk_display_get_default (); usd_locate_pointer (display); } } int main (int argc, char *argv[]) { gtk_init (&argc, &argv); //set_locate_pointer (); GSettings *settings = g_settings_new ("org.ukui.SettingsDaemon.plugins.mouse"); g_signal_connect (settings, "changed", G_CALLBACK (mouse_callback), NULL); gdk_x11_display_error_trap_push(gdk_display_get_default()); gtk_main (); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default()); g_object_unref(settings); return 0; } ukui-settings-daemon/plugins/locate-pointer/usd-locate-pointer.pro0000644000175000017500000000115714205117202024416 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-04-30T09:30:00 # #------------------------------------------------- QT -= gui QT += core widgets x11extras CONFIG += c++11 console no_keywords link_pkgconfig plugin CONFIG -= app_bundle DEFINES += QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"ULP\\\" PKGCONFIG += \ gtk+-3.0 glib-2.0 x11 SOURCES += \ usd-locate-pointer.c \ usd-timeline.c HEADERS += \ usd-locate-pointer.h \ usd-timeline.h locate_pointer.path = /usr/bin/ locate_pointer.files = $$OUT_PWD/usd-locate-pointer INSTALLS += locate_pointer ukui-settings-daemon/plugins/locate-pointer/usd-timeline.c0000644000175000017500000004730314205117202022724 0ustar fengfeng/* usd-timeline.c * * Copyright (C) 2008 Carlos Garnacho * * This program is free software; you can redistribute it and/or modify it * under the terms of the 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 "usd-timeline.h" #define USD_TIMELINE_GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), USD_TYPE_TIMELINE, UsdTimelinePriv)) #define MSECS_PER_SEC 1000 #define FRAME_INTERVAL(nframes) (MSECS_PER_SEC / nframes) #define DEFAULT_FPS 30 typedef struct UsdTimelinePriv UsdTimelinePriv; struct UsdTimelinePriv { guint duration; guint fps; guint source_id; GTimer *timer; GdkScreen *screen; UsdTimelineProgressType progress_type; UsdTimelineProgressFunc progress_func; guint loop : 1; guint direction : 1; }; enum { PROP_0, PROP_FPS, PROP_DURATION, PROP_LOOP, PROP_DIRECTION, PROP_SCREEN, PROP_PROGRESS_TYPE, }; enum { STARTED, PAUSED, FINISHED, FRAME, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0, }; static void usd_timeline_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void usd_timeline_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void usd_timeline_finalize (GObject *object); G_DEFINE_TYPE (UsdTimeline, usd_timeline, G_TYPE_OBJECT) GType usd_timeline_direction_get_type (void) { static GType type = 0; if (G_UNLIKELY (type == 0)) { static const GEnumValue values[] = { { USD_TIMELINE_DIRECTION_FORWARD, "USD_TIMELINE_DIRECTION_FORWARD", "forward" }, { USD_TIMELINE_DIRECTION_BACKWARD, "USD_TIMELINE_DIRECTION_BACKWARD", "backward" }, { 0, NULL, NULL } }; type = g_enum_register_static (g_intern_static_string ("UsdTimelineDirection"), values); } return type; } GType usd_timeline_progress_type_get_type (void) { static GType type = 0; if (G_UNLIKELY (type == 0)) { static const GEnumValue values[] = { { USD_TIMELINE_PROGRESS_LINEAR, "USD_TIMELINE_PROGRESS_LINEAR", "linear" }, { USD_TIMELINE_PROGRESS_SINUSOIDAL, "USD_TIMELINE_PROGRESS_SINUSOIDAL", "sinusoidal" }, { USD_TIMELINE_PROGRESS_EXPONENTIAL, "USD_TIMELINE_PROGRESS_EXPONENTIAL", "exponential" }, { 0, NULL, NULL } }; type = g_enum_register_static (g_intern_static_string ("UsdTimelineProgressType"), values); } return type; } static void usd_timeline_class_init (UsdTimelineClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); object_class->set_property = usd_timeline_set_property; object_class->get_property = usd_timeline_get_property; object_class->finalize = usd_timeline_finalize; g_object_class_install_property (object_class, PROP_FPS, g_param_spec_uint ("fps", "FPS", "Frames per second for the timeline", 1, G_MAXUINT, DEFAULT_FPS, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_DURATION, g_param_spec_uint ("duration", "Animation Duration", "Animation Duration", 0, G_MAXUINT, 0, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_LOOP, g_param_spec_boolean ("loop", "Loop", "Whether the timeline loops or not", FALSE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_DIRECTION, g_param_spec_enum ("direction", "Direction", "Whether the timeline moves forward or backward in time", USD_TYPE_TIMELINE_DIRECTION, USD_TIMELINE_DIRECTION_FORWARD, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_DIRECTION, g_param_spec_enum ("progress-type", "Progress type", "Type of progress through the timeline", USD_TYPE_TIMELINE_PROGRESS_TYPE, USD_TIMELINE_PROGRESS_LINEAR, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_SCREEN, g_param_spec_object ("screen", "Screen", "Screen to get the settings from", GDK_TYPE_SCREEN, G_PARAM_READWRITE)); signals[STARTED] = g_signal_new ("started", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (UsdTimelineClass, started), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[PAUSED] = g_signal_new ("paused", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (UsdTimelineClass, paused), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[FINISHED] = g_signal_new ("finished", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (UsdTimelineClass, finished), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[FRAME] = g_signal_new ("frame", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (UsdTimelineClass, frame), NULL, NULL, g_cclosure_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE); g_type_class_add_private (class, sizeof (UsdTimelinePriv)); } static void usd_timeline_init (UsdTimeline *timeline) { UsdTimelinePriv *priv; priv = USD_TIMELINE_GET_PRIV (timeline); priv->fps = DEFAULT_FPS; priv->duration = 0; priv->direction = USD_TIMELINE_DIRECTION_FORWARD; priv->screen = gdk_screen_get_default (); } static void usd_timeline_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { UsdTimeline *timeline; timeline = USD_TIMELINE (object); switch (prop_id) { case PROP_FPS: usd_timeline_set_fps (timeline, g_value_get_uint (value)); break; case PROP_DURATION: usd_timeline_set_duration (timeline, g_value_get_uint (value)); break; case PROP_LOOP: usd_timeline_set_loop (timeline, g_value_get_boolean (value)); break; case PROP_DIRECTION: usd_timeline_set_direction (timeline, g_value_get_enum (value)); break; case PROP_SCREEN: usd_timeline_set_screen (timeline, GDK_SCREEN (g_value_get_object (value))); break; case PROP_PROGRESS_TYPE: usd_timeline_set_progress_type (timeline, g_value_get_enum (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void usd_timeline_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { UsdTimeline *timeline; UsdTimelinePriv *priv; timeline = USD_TIMELINE (object); priv = USD_TIMELINE_GET_PRIV (timeline); switch (prop_id) { case PROP_FPS: g_value_set_uint (value, priv->fps); break; case PROP_DURATION: g_value_set_uint (value, priv->duration); break; case PROP_LOOP: g_value_set_boolean (value, priv->loop); break; case PROP_DIRECTION: g_value_set_enum (value, priv->direction); break; case PROP_SCREEN: g_value_set_object (value, priv->screen); break; case PROP_PROGRESS_TYPE: g_value_set_enum (value, priv->progress_type); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void usd_timeline_finalize (GObject *object) { UsdTimelinePriv *priv; priv = USD_TIMELINE_GET_PRIV (object); if (priv->source_id) { g_source_remove (priv->source_id); priv->source_id = 0; } if (priv->timer) g_timer_destroy (priv->timer); G_OBJECT_CLASS (usd_timeline_parent_class)->finalize (object); } /* Sinusoidal progress */ static gdouble sinusoidal_progress (gdouble progress) { return (sinf ((progress * G_PI) / 2)); } static gdouble exponential_progress (gdouble progress) { return progress * progress; } static UsdTimelineProgressFunc progress_type_to_func (UsdTimelineProgressType type) { if (type == USD_TIMELINE_PROGRESS_SINUSOIDAL) return sinusoidal_progress; else if (type == USD_TIMELINE_PROGRESS_EXPONENTIAL) return exponential_progress; return NULL; } static gboolean usd_timeline_run_frame (UsdTimeline *timeline, gboolean enable_animations) { UsdTimelinePriv *priv; gdouble linear_progress, progress; guint elapsed_time; UsdTimelineProgressFunc progress_func = NULL; priv = USD_TIMELINE_GET_PRIV (timeline); if (enable_animations) { elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000); linear_progress = (gdouble) elapsed_time / priv->duration; if (priv->direction == USD_TIMELINE_DIRECTION_BACKWARD) linear_progress = 1 - linear_progress; linear_progress = CLAMP (linear_progress, 0., 1.); if (priv->progress_func) progress_func = priv->progress_func; else if (priv->progress_type) progress_func = progress_type_to_func (priv->progress_type); if (progress_func) progress = (progress_func) (linear_progress); else progress = linear_progress; } else progress = (priv->direction == USD_TIMELINE_DIRECTION_FORWARD) ? 1.0 : 0.0; g_signal_emit (timeline, signals [FRAME], 0, CLAMP (progress, 0.0, 1.0)); if ((priv->direction == USD_TIMELINE_DIRECTION_FORWARD && progress >= 1.0) || (priv->direction == USD_TIMELINE_DIRECTION_BACKWARD && progress <= 0.0)) { if (!priv->loop) { if (priv->source_id) { g_source_remove (priv->source_id); priv->source_id = 0; } g_signal_emit (timeline, signals [FINISHED], 0); return FALSE; } else usd_timeline_rewind (timeline); } return TRUE; } static gboolean usd_timeline_frame_idle_func (UsdTimeline *timeline) { return usd_timeline_run_frame (timeline, TRUE); } /** * usd_timeline_new: * @duration: duration in milliseconds for the timeline * * Creates a new #UsdTimeline with the specified number of frames. * * Return Value: the newly created #UsdTimeline **/ UsdTimeline * usd_timeline_new (guint duration) { return g_object_new (USD_TYPE_TIMELINE, "duration", duration, NULL); } UsdTimeline * usd_timeline_new_for_screen (guint duration, GdkScreen *screen) { return g_object_new (USD_TYPE_TIMELINE, "duration", duration, "screen", screen, NULL); } /** * usd_timeline_start: * @timeline: A #UsdTimeline * * Runs the timeline from the current frame. **/ void usd_timeline_start (UsdTimeline *timeline) { UsdTimelinePriv *priv; GtkSettings *settings; gboolean enable_animations = FALSE; g_return_if_fail (USD_IS_TIMELINE (timeline)); priv = USD_TIMELINE_GET_PRIV (timeline); if (priv->screen) { settings = gtk_settings_get_for_screen (priv->screen); g_object_get (settings, "gtk-enable-animations", &enable_animations, NULL); } if (enable_animations) { if (!priv->source_id) { if (priv->timer) g_timer_continue (priv->timer); else priv->timer = g_timer_new (); /* sanity check */ g_assert (priv->fps > 0); g_signal_emit (timeline, signals [STARTED], 0); priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps), (GSourceFunc) usd_timeline_frame_idle_func, timeline); } } else { /* If animations are not enabled, only run the last frame, * it take us instantaneously to the last state of the animation. * The only potential flaw happens when people use the ::finished * signal to trigger another animation, or even worse, finally * loop into this animation again. */ g_signal_emit (timeline, signals [STARTED], 0); usd_timeline_run_frame (timeline, FALSE); } } /** * usd_timeline_pause: * @timeline: A #UsdTimeline * * Pauses the timeline. **/ void usd_timeline_pause (UsdTimeline *timeline) { UsdTimelinePriv *priv; g_return_if_fail (USD_IS_TIMELINE (timeline)); priv = USD_TIMELINE_GET_PRIV (timeline); if (priv->source_id) { g_source_remove (priv->source_id); priv->source_id = 0; g_timer_stop (priv->timer); g_signal_emit (timeline, signals [PAUSED], 0); } } /** * usd_timeline_rewind: * @timeline: A #UsdTimeline * * Rewinds the timeline. **/ void usd_timeline_rewind (UsdTimeline *timeline) { UsdTimelinePriv *priv; g_return_if_fail (USD_IS_TIMELINE (timeline)); priv = USD_TIMELINE_GET_PRIV (timeline); /* destroy and re-create timer if neccesary */ if (priv->timer) { g_timer_destroy (priv->timer); if (usd_timeline_is_running (timeline)) priv->timer = g_timer_new (); else priv->timer = NULL; } } /** * usd_timeline_is_running: * @timeline: A #UsdTimeline * * Returns whether the timeline is running or not. * * Return Value: %TRUE if the timeline is running **/ gboolean usd_timeline_is_running (UsdTimeline *timeline) { UsdTimelinePriv *priv; g_return_val_if_fail (USD_IS_TIMELINE (timeline), FALSE); priv = USD_TIMELINE_GET_PRIV (timeline); return (priv->source_id != 0); } /** * usd_timeline_get_fps: * @timeline: A #UsdTimeline * * Returns the number of frames per second. * * Return Value: frames per second **/ guint usd_timeline_get_fps (UsdTimeline *timeline) { UsdTimelinePriv *priv; g_return_val_if_fail (USD_IS_TIMELINE (timeline), 1); priv = USD_TIMELINE_GET_PRIV (timeline); return priv->fps; } /** * usd_timeline_set_fps: * @timeline: A #UsdTimeline * @fps: frames per second * * Sets the number of frames per second that * the timeline will play. **/ void usd_timeline_set_fps (UsdTimeline *timeline, guint fps) { UsdTimelinePriv *priv; g_return_if_fail (USD_IS_TIMELINE (timeline)); g_return_if_fail (fps > 0); priv = USD_TIMELINE_GET_PRIV (timeline); priv->fps = fps; if (usd_timeline_is_running (timeline)) { g_source_remove (priv->source_id); priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps), (GSourceFunc) usd_timeline_run_frame, timeline); } g_object_notify (G_OBJECT (timeline), "fps"); } /** * usd_timeline_get_loop: * @timeline: A #UsdTimeline * * Returns whether the timeline loops to the * beginning when it has reached the end. * * Return Value: %TRUE if the timeline loops **/ gboolean usd_timeline_get_loop (UsdTimeline *timeline) { UsdTimelinePriv *priv; g_return_val_if_fail (USD_IS_TIMELINE (timeline), FALSE); priv = USD_TIMELINE_GET_PRIV (timeline); return priv->loop; } /** * usd_timeline_set_loop: * @timeline: A #UsdTimeline * @loop: %TRUE to make the timeline loop * * Sets whether the timeline loops to the beginning * when it has reached the end. **/ void usd_timeline_set_loop (UsdTimeline *timeline, gboolean loop) { UsdTimelinePriv *priv; g_return_if_fail (USD_IS_TIMELINE (timeline)); priv = USD_TIMELINE_GET_PRIV (timeline); priv->loop = loop; g_object_notify (G_OBJECT (timeline), "loop"); } void usd_timeline_set_duration (UsdTimeline *timeline, guint duration) { UsdTimelinePriv *priv; g_return_if_fail (USD_IS_TIMELINE (timeline)); priv = USD_TIMELINE_GET_PRIV (timeline); priv->duration = duration; g_object_notify (G_OBJECT (timeline), "duration"); } guint usd_timeline_get_duration (UsdTimeline *timeline) { UsdTimelinePriv *priv; g_return_val_if_fail (USD_IS_TIMELINE (timeline), 0); priv = USD_TIMELINE_GET_PRIV (timeline); return priv->duration; } /** * usd_timeline_get_direction: * @timeline: A #UsdTimeline * * Returns the direction of the timeline. * * Return Value: direction **/ UsdTimelineDirection usd_timeline_get_direction (UsdTimeline *timeline) { UsdTimelinePriv *priv; g_return_val_if_fail (USD_IS_TIMELINE (timeline), USD_TIMELINE_DIRECTION_FORWARD); priv = USD_TIMELINE_GET_PRIV (timeline); return priv->direction; } /** * usd_timeline_set_direction: * @timeline: A #UsdTimeline * @direction: direction * * Sets the direction of the timeline. **/ void usd_timeline_set_direction (UsdTimeline *timeline, UsdTimelineDirection direction) { UsdTimelinePriv *priv; g_return_if_fail (USD_IS_TIMELINE (timeline)); priv = USD_TIMELINE_GET_PRIV (timeline); priv->direction = direction; g_object_notify (G_OBJECT (timeline), "direction"); } GdkScreen * usd_timeline_get_screen (UsdTimeline *timeline) { UsdTimelinePriv *priv; g_return_val_if_fail (USD_IS_TIMELINE (timeline), NULL); priv = USD_TIMELINE_GET_PRIV (timeline); return priv->screen; } void usd_timeline_set_screen (UsdTimeline *timeline, GdkScreen *screen) { UsdTimelinePriv *priv; g_return_if_fail (USD_IS_TIMELINE (timeline)); g_return_if_fail (GDK_IS_SCREEN (screen)); priv = USD_TIMELINE_GET_PRIV (timeline); if (priv->screen) g_object_unref (priv->screen); priv->screen = g_object_ref (screen); g_object_notify (G_OBJECT (timeline), "screen"); } void usd_timeline_set_progress_type (UsdTimeline *timeline, UsdTimelineProgressType type) { UsdTimelinePriv *priv; g_return_if_fail (USD_IS_TIMELINE (timeline)); priv = USD_TIMELINE_GET_PRIV (timeline); priv->progress_type = type; g_object_notify (G_OBJECT (timeline), "progress-type"); } UsdTimelineProgressType usd_timeline_get_progress_type (UsdTimeline *timeline) { UsdTimelinePriv *priv; g_return_val_if_fail (USD_IS_TIMELINE (timeline), USD_TIMELINE_PROGRESS_LINEAR); priv = USD_TIMELINE_GET_PRIV (timeline); if (priv->progress_func) return USD_TIMELINE_PROGRESS_LINEAR; return priv->progress_type; } /** * usd_timeline_set_progress_func: * @timeline: A #UsdTimeline * @progress_func: progress function * * Sets the progress function. This function will be used to calculate * a different progress to pass to the ::frame signal based on the * linear progress through the timeline. Setting progress_func * to %NULL will make the timeline use the default function, * which is just a linear progress. * * All progresses are in the [0.0, 1.0] range. **/ void usd_timeline_set_progress_func (UsdTimeline *timeline, UsdTimelineProgressFunc progress_func) { UsdTimelinePriv *priv; g_return_if_fail (USD_IS_TIMELINE (timeline)); priv = USD_TIMELINE_GET_PRIV (timeline); priv->progress_func = progress_func; } gdouble usd_timeline_get_progress (UsdTimeline *timeline) { UsdTimelinePriv *priv; UsdTimelineProgressFunc progress_func = NULL; gdouble linear_progress, progress; guint elapsed_time; g_return_val_if_fail (USD_IS_TIMELINE (timeline), 0.0); priv = USD_TIMELINE_GET_PRIV (timeline); if (!priv->timer) return 0.; elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000); linear_progress = (gdouble) elapsed_time / priv->duration; if (priv->direction == USD_TIMELINE_DIRECTION_BACKWARD) linear_progress = 1 - linear_progress; linear_progress = CLAMP (linear_progress, 0., 1.); if (priv->progress_func) progress_func = priv->progress_func; else if (priv->progress_type) progress_func = progress_type_to_func (priv->progress_type); if (progress_func) progress = (progress_func) (linear_progress); else progress = linear_progress; return CLAMP (progress, 0., 1.); } ukui-settings-daemon/plugins/locate-pointer/usd-locate-pointer.h0000644000175000017500000000153514205117202024045 0ustar fengfeng/* * Copyright 2001 Jonathan Blandford * * 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, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * Authors: Jonathan Blandford */ #ifndef LOCATE_POINTER_H #define LOCATE_POINTER_H #include void usd_locate_pointer (GdkDisplay *display); #endif ukui-settings-daemon/plugins/locate-pointer/usd-timeline.h0000644000175000017500000001215414205117202022725 0ustar fengfeng/* usdtimeline.c * * Copyright (C) 2008 Carlos Garnacho * * This program is free software; you can redistribute it and/or modify it * under the terms of the 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 __USD_TIMELINE_H__ #define __USD_TIMELINE_H__ #include #include #ifdef __cplusplus extern "C" { #endif #define USD_TYPE_TIMELINE_DIRECTION (usd_timeline_direction_get_type ()) #define USD_TYPE_TIMELINE_PROGRESS_TYPE (usd_timeline_progress_type_get_type ()) #define USD_TYPE_TIMELINE (usd_timeline_get_type ()) #define USD_TIMELINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), USD_TYPE_TIMELINE, UsdTimeline)) #define USD_TIMELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), USD_TYPE_TIMELINE, UsdTimelineClass)) #define USD_IS_TIMELINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), USD_TYPE_TIMELINE)) #define USD_IS_TIMELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), USD_TYPE_TIMELINE)) #define USD_TIMELINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), USD_TYPE_TIMELINE, UsdTimelineClass)) typedef enum { USD_TIMELINE_DIRECTION_FORWARD, USD_TIMELINE_DIRECTION_BACKWARD } UsdTimelineDirection; typedef enum { USD_TIMELINE_PROGRESS_LINEAR, USD_TIMELINE_PROGRESS_SINUSOIDAL, USD_TIMELINE_PROGRESS_EXPONENTIAL } UsdTimelineProgressType; typedef struct UsdTimeline UsdTimeline; typedef struct UsdTimelineClass UsdTimelineClass; struct UsdTimeline { GObject parent_instance; }; struct UsdTimelineClass { GObjectClass parent_class; void (* started) (UsdTimeline *timeline); void (* finished) (UsdTimeline *timeline); void (* paused) (UsdTimeline *timeline); void (* frame) (UsdTimeline *timeline, gdouble progress); void (* __usd_reserved1) (void); void (* __usd_reserved2) (void); void (* __usd_reserved3) (void); void (* __usd_reserved4) (void); }; typedef gdouble (*UsdTimelineProgressFunc) (gdouble progress); GType usd_timeline_get_type (void) G_GNUC_CONST; GType usd_timeline_direction_get_type (void) G_GNUC_CONST; GType usd_timeline_progress_type_get_type (void) G_GNUC_CONST; UsdTimeline *usd_timeline_new (guint duration); UsdTimeline *usd_timeline_new_for_screen (guint duration, GdkScreen *screen); void usd_timeline_start (UsdTimeline *timeline); void usd_timeline_pause (UsdTimeline *timeline); void usd_timeline_rewind (UsdTimeline *timeline); gboolean usd_timeline_is_running (UsdTimeline *timeline); guint usd_timeline_get_fps (UsdTimeline *timeline); void usd_timeline_set_fps (UsdTimeline *timeline, guint fps); gboolean usd_timeline_get_loop (UsdTimeline *timeline); void usd_timeline_set_loop (UsdTimeline *timeline, gboolean loop); guint usd_timeline_get_duration (UsdTimeline *timeline); void usd_timeline_set_duration (UsdTimeline *timeline, guint duration); GdkScreen *usd_timeline_get_screen (UsdTimeline *timeline); void usd_timeline_set_screen (UsdTimeline *timeline, GdkScreen *screen); UsdTimelineDirection usd_timeline_get_direction (UsdTimeline *timeline); void usd_timeline_set_direction (UsdTimeline *timeline, UsdTimelineDirection direction); UsdTimelineProgressType usd_timeline_get_progress_type (UsdTimeline *timeline); void usd_timeline_set_progress_type (UsdTimeline *timeline, UsdTimelineProgressType type); void usd_timeline_get_progress_func (UsdTimeline *timeline); void usd_timeline_set_progress_func (UsdTimeline *timeline, UsdTimelineProgressFunc progress_func); gdouble usd_timeline_get_progress (UsdTimeline *timeline); #ifdef __cplusplus } #endif #endif /* __USD_TIMELINE_H__ */ ukui-settings-daemon/plugins/a11y-keyboard/0000755000175000017500000000000014205117202017576 5ustar fengfengukui-settings-daemon/plugins/a11y-keyboard/a11y-preferences-dialog.h0000644000175000017500000000236314205117202024262 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef A11YPREFERENCESDIALOG_H #define A11YPREFERENCESDIALOG_H #include #include "clib-syslog.h" namespace Ui { class A11yPreferencesDialog; } class A11yPreferencesDialog : public QWidget { Q_OBJECT public: explicit A11yPreferencesDialog(QWidget *parent = nullptr); ~A11yPreferencesDialog(); Q_SIGNALS: void singalCloseWidget(); protected: void closeEvent(QCloseEvent *event); private: Ui::A11yPreferencesDialog *ui; }; #endif // A11YPREFERENCESDIALOG_H ukui-settings-daemon/plugins/a11y-keyboard/a11y-keyboard-plugin.cpp0000644000175000017500000000371014205117202024150 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "a11y-keyboard-plugin.h" #include "clib-syslog.h" PluginInterface *A11yKeyboardPlugin::mInstance = nullptr; A11yKeyboardManager *A11yKeyboardPlugin::UsdA11yManager= nullptr; A11yKeyboardPlugin::A11yKeyboardPlugin() { USD_LOG(LOG_DEBUG,"A11yKeyboardPlugin initializing "); if(nullptr == UsdA11yManager) UsdA11yManager = A11yKeyboardManager::A11KeyboardManagerNew(); } A11yKeyboardPlugin::~A11yKeyboardPlugin() { if(UsdA11yManager){ delete UsdA11yManager; UsdA11yManager = nullptr; } } void A11yKeyboardPlugin::activate() { bool res; USD_LOG (LOG_DEBUG, "Activating %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); res = UsdA11yManager->A11yKeyboardManagerStart(); if(!res) USD_LOG(LOG_ERR,"Unable to start A11y-Keyboard manager"); } PluginInterface * A11yKeyboardPlugin::getInstance() { if(nullptr == mInstance) mInstance = new A11yKeyboardPlugin(); return mInstance; } void A11yKeyboardPlugin::deactivate() { USD_LOG(LOG_DEBUG,"Deactivating A11y-Keyboard plugin"); UsdA11yManager->A11yKeyboardManagerStop(); } PluginInterface *createSettingsPlugin() { return A11yKeyboardPlugin::getInstance(); } ukui-settings-daemon/plugins/a11y-keyboard/a11y-preferences-dialog.ui0000644000175000017500000000631314205117202024447 0ustar fengfeng A11yPreferencesDialog 0 0 767 430 Form 121 0 371 401 Use on-screen _keyboard false false Use screen _reader Use screen _magnifier Enhance _contrast in colors Make _text larger and easier to read Press keyboard shortcuts one key at a time (Sticky Keys) Ignore duplicate keypresses (Bounce Keys) Press and _hold keys to accept them (Slow Keys) 560 200 80 26 close ukui-settings-daemon/plugins/a11y-keyboard/a11y-keyboard-manager.h0000644000175000017500000001257414205117202023741 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef A11YKEYBOARDMANAGER_H #define A11YKEYBOARDMANAGER_H #include #include #include #include #include #include #include "QGSettings/qgsettings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "a11y-preferences-dialog.h" #ifdef HAVE_LIBNOTIFY #include #endif /* HAVE_LIBNOTIFY */ class A11yKeyboardManager : public QObject { Q_OBJECT private: A11yKeyboardManager()=delete ; A11yKeyboardManager(A11yKeyboardManager&)=delete ; A11yKeyboardManager&operator=(const A11yKeyboardManager&)=delete ; A11yKeyboardManager(QObject *parent = nullptr); public: ~A11yKeyboardManager(); static A11yKeyboardManager *A11KeyboardManagerNew(); bool A11yKeyboardManagerStart(); void A11yKeyboardManagerStop(); public Q_SLOTS: void StartA11yKeyboardIdleCb(); void KeyboardCallback(QString); void OnPreferencesDialogResponse(); void ax_stickykeys_response(QAbstractButton *button); void ax_slowkeys_response (QAbstractButton *button); public: static XkbDescRec *GetXkbDescRec (); static void SetServerFromSettings (A11yKeyboardManager *manager); static void MaybeShowStatusIcon (A11yKeyboardManager *manager); static void A11yKeyboardManagerEnsureStatusIcon(A11yKeyboardManager *manager); static void OnStatusIconActivate (GtkStatusIcon *status_icon, A11yKeyboardManager *manager); static bool XkbEnabled (A11yKeyboardManager *manager); static void SetDevicepresenceHandler (A11yKeyboardManager *manager); static void SetSettingsFromServer (A11yKeyboardManager *manager); static void RestoreServerXkbConfig (A11yKeyboardManager *manager); static bool AxResponseCallback (A11yKeyboardManager *manager, QMessageBox *parent, int response_id, unsigned int revert_controls_mask, bool enabled); static void AxSlowkeysWarningPost (A11yKeyboardManager *manager, bool enabled); static void AxStickykeysWarningPost (A11yKeyboardManager *manager,bool enabled); static void AxStickykeysWarningPostDialog (A11yKeyboardManager *manager, bool enabled); static void AxSlowkeysWarningPostDialog (A11yKeyboardManager *manager, bool enabled); private: friend GdkFilterReturn CbXkbEventFilter (GdkXEvent *xevent, GdkEvent *ignored1, A11yKeyboardManager *manager); friend void OnNotificationClosed (NotifyNotification *notification, A11yKeyboardManager *manager); friend bool AxSlowkeysWarningPostDubble (A11yKeyboardManager *manager, bool enabled); friend void on_sticky_keys_action (NotifyNotification *notification, const char *action, A11yKeyboardManager *manager); friend void on_slow_keys_action (NotifyNotification *notification, const char *action, A11yKeyboardManager *manager); friend bool AxStickykeysWarningPostBubble (A11yKeyboardManager *manager, bool enabled); private: static A11yKeyboardManager *mA11yKeyboard; QTimer *time; int xkbEventBase; bool StickykeysShortcutVal; bool SlowkeysShortcutVal; QMessageBox *StickykeysAlert = nullptr; QMessageBox *SlowkeysAlert = nullptr; A11yPreferencesDialog *preferences_dialog=nullptr; //GtkStatusIcon *status_icon; XkbDescRec *OriginalXkbDesc; QGSettings *settings; #ifdef HAVE_LIBNOTIFY NotifyNotification *notification; #endif /* HAVE_LIBNOTIFY */ }; #endif // A11YKEYBOARDMANAGER_H ukui-settings-daemon/plugins/a11y-keyboard/a11y-keyboard-manager.cpp0000644000175000017500000011311214205117202024262 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "a11y-keyboard-manager.h" #include "clib-syslog.h" #define CONFIG_SCHEMA "org.mate.accessibility-keyboard" #define NOTIFICATION_TIMEOUT 30 static GdkFilterReturn DevicepresenceFilter (GdkXEvent *xevent, GdkEvent *event,gpointer data); GdkFilterReturn CbXkbEventFilter (GdkXEvent *xevent, GdkEvent *ignored1, A11yKeyboardManager *manager); A11yKeyboardManager *A11yKeyboardManager::mA11yKeyboard=nullptr; //TODO:需要给出设置界面的呼出窗口(MaybeShowStatusIcon),并且需要针对功能进行完善 by Leon Sun 2021年07月24日15:17:44 A11yKeyboardManager::A11yKeyboardManager(QObject *parent) : QObject(parent) { time = new QTimer(this); settings = new QGSettings(CONFIG_SCHEMA); } A11yKeyboardManager::~A11yKeyboardManager() { settings->deleteLater(); time->deleteLater(); } A11yKeyboardManager * A11yKeyboardManager::A11KeyboardManagerNew() { if(nullptr == mA11yKeyboard) mA11yKeyboard = new A11yKeyboardManager(nullptr); return mA11yKeyboard; } bool A11yKeyboardManager::A11yKeyboardManagerStart() { USD_LOG(LOG_DEBUG," %s Manager Start compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); connect(time, &QTimer::timeout, this, &A11yKeyboardManager::StartA11yKeyboardIdleCb); time->start(); return true; } void A11yKeyboardManager::A11yKeyboardManagerStop() { USD_LOG(LOG_DEBUG,"Stopping A11y Keyboard manager"); gdk_window_remove_filter (NULL, DevicepresenceFilter, this); /*if (status_icon) gtk_status_icon_set_visible (status_icon, false); */ gdk_window_remove_filter (NULL, (GdkFilterFunc) CbXkbEventFilter, this); /* Disable all the AccessX bits */ RestoreServerXkbConfig (this); if (SlowkeysAlert != nullptr){ USD_LOG(LOG_DEBUG,"delete SlowkeysAlert"); SlowkeysAlert->deleteLater(); } if (StickykeysAlert != nullptr){ USD_LOG(LOG_DEBUG,"delete StickykeysAlert"); StickykeysAlert->deleteLater(); } SlowkeysShortcutVal = false; StickykeysShortcutVal = false; } static int GetInt (QGSettings *settings, char const *key) { int res = settings->get(key).toInt(); if (res <= 0) { res = 1; } return res; } static bool SetInt (QGSettings *settings, char const *key, int val) { int pre_val = settings->get(key).toInt(); settings->set(key,val); #ifdef DEBUG_ACCESSIBILITY if (val != pre_val) { g_warning ("%s changed", key); } #endif return val != pre_val; } static bool SetBool (QGSettings *settings, char const *key, int val) { bool bval = (val != 0); bool pre_val = settings->get(key).toBool(); settings->set(key,bval ? true : false); #ifdef DEBUG_ACCESSIBILITY if (bval != pre_val) { d ("%s changed", key); return true; } #endif return (bval != pre_val); } static unsigned long SetClear(bool flag, unsigned long value, unsigned long mask) { if(flag) return value | mask; return value & ~mask; } void A11yKeyboardManager::RestoreServerXkbConfig (A11yKeyboardManager *manager) { gdk_x11_display_error_trap_push (gdk_display_get_default()); XkbSetControls (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), XkbSlowKeysMask | XkbBounceKeysMask | XkbStickyKeysMask | XkbMouseKeysMask | XkbMouseKeysAccelMask | XkbAccessXKeysMask | XkbAccessXTimeoutMask | XkbAccessXFeedbackMask | XkbControlsEnabledMask, manager->OriginalXkbDesc); XkbFreeKeyboard (manager->OriginalXkbDesc, XkbAllComponentsMask, True); XSync (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), false); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default()); manager->OriginalXkbDesc = NULL; } XkbDescRec * A11yKeyboardManager::GetXkbDescRec() { XkbDescRec *desc = NULL; Status status = Success; gdk_x11_display_error_trap_push (gdk_display_get_default()); desc = XkbGetMap (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), XkbAllMapComponentsMask, XkbUseCoreKbd); if (desc != NULL) { desc->ctrls = NULL; status = XkbGetControls (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), XkbAllControlsMask, desc); } else { desc = NULL; gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default()); return NULL; } gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default()); g_return_val_if_fail (desc != NULL, NULL); g_return_val_if_fail (desc->ctrls != NULL, NULL); g_return_val_if_fail (status == Success, NULL); return desc; } static bool SetCtrlFromSettings (XkbDescRec *desc, QGSettings *settings, char const *key, unsigned long mask) { bool result = settings->get(key).toBool(); desc->ctrls->enabled_ctrls = SetClear(result, desc->ctrls->enabled_ctrls, mask); return result; } void A11yKeyboardManager::SetServerFromSettings(A11yKeyboardManager *manager) { XkbDescRec *desc; bool enable_accessX; desc = GetXkbDescRec (); if (!desc) { return; } /* general */ enable_accessX = manager->settings->get("enable").toBool(); desc->ctrls->enabled_ctrls = SetClear (enable_accessX, desc->ctrls->enabled_ctrls, XkbAccessXKeysMask); if (SetCtrlFromSettings (desc, manager->settings, "timeout-enable", XkbAccessXTimeoutMask)) { desc->ctrls->ax_timeout = GetInt (manager->settings, "timeout"); /* disable only the master flag via the server we will disable * the rest on the rebound without affecting gsettings state * don't change the option flags at all. */ desc->ctrls->axt_ctrls_mask = XkbAccessXKeysMask | XkbAccessXFeedbackMask; desc->ctrls->axt_ctrls_values = 0; desc->ctrls->axt_opts_mask = 0; } desc->ctrls->ax_options = SetClear (manager->settings->get("feature-state-change-beep").toBool(), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask); /* bounce keys */ if (SetCtrlFromSettings (desc, manager->settings, "bouncekeys-enable", XkbBounceKeysMask)) { desc->ctrls->debounce_delay = GetInt (manager->settings, "bouncekeys-delay"); desc->ctrls->ax_options = SetClear (manager->settings->get("bouncekeys-beep-reject").toBool(), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_BKRejectFBMask); } /* mouse keys */ if (SetCtrlFromSettings (desc, manager->settings, "mousekeys-enable", XkbMouseKeysMask | XkbMouseKeysAccelMask)) { desc->ctrls->mk_interval = 100; /* msec between mousekey events */ desc->ctrls->mk_curve = 50; /* We store pixels / sec, XKB wants pixels / event */ desc->ctrls->mk_max_speed = GetInt (manager->settings, "mousekeys-max-speed") / (1000 / desc->ctrls->mk_interval); if (desc->ctrls->mk_max_speed <= 0) desc->ctrls->mk_max_speed = 1; desc->ctrls->mk_time_to_max = GetInt (manager->settings, /* events before max */ "mousekeys-accel-time") / desc->ctrls->mk_interval; if (desc->ctrls->mk_time_to_max <= 0) desc->ctrls->mk_time_to_max = 1; desc->ctrls->mk_delay = GetInt (manager->settings, /* ms before 1st event */ "mousekeys-init-delay"); } /* slow keys */ if (SetCtrlFromSettings (desc, manager->settings, "slowkeys-enable", XkbSlowKeysMask)) { desc->ctrls->ax_options = SetClear(manager->settings->get("slowkeys-beep-press").toBool(), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKPressFBMask); desc->ctrls->ax_options = SetClear(manager->settings->get("slowkeys-beep-accept").toBool(), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKAcceptFBMask); desc->ctrls->ax_options = SetClear(manager->settings->get("slowkeys-beep-reject").toBool(), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKRejectFBMask); desc->ctrls->slow_keys_delay = GetInt(manager->settings, "slowkeys-delay"); /* anything larger than 500 seems to loose all keyboard input */ if (desc->ctrls->slow_keys_delay > 500) desc->ctrls->slow_keys_delay = 500; } /* sticky keys */ if (SetCtrlFromSettings (desc, manager->settings, "stickykeys-enable", XkbStickyKeysMask)) { desc->ctrls->ax_options |= XkbAX_LatchToLockMask; desc->ctrls->ax_options = SetClear(manager->settings->get("stickykeys-two-key-off").toBool(), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_TwoKeysMask); desc->ctrls->ax_options = SetClear(manager->settings->get("stickykeys-modifier-beep").toBool(), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_StickyKeysFBMask); } /* toggle keys */ desc->ctrls->ax_options = SetClear(manager->settings->get("togglekeys-enable").toBool(), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_IndicatorFBMask); USD_LOG(LOG_DEBUG,"CHANGE to : 0x%x", desc->ctrls->enabled_ctrls); USD_LOG(LOG_DEBUG,"CHANGE to : 0x%x (2)", desc->ctrls->ax_options); gdk_x11_display_error_trap_push (gdk_display_get_default()); XkbSetControls (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), XkbSlowKeysMask | XkbBounceKeysMask | XkbStickyKeysMask | XkbMouseKeysMask | XkbMouseKeysAccelMask | XkbAccessXKeysMask | XkbAccessXTimeoutMask | XkbAccessXFeedbackMask | XkbControlsEnabledMask, desc); XkbFreeKeyboard (desc, XkbAllComponentsMask, True); XSync (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), false); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default()); } void A11yKeyboardManager::OnPreferencesDialogResponse() { USD_LOG(LOG_DEBUG,"get close dialog signal"); this->preferences_dialog->close(); preferences_dialog->deleteLater(); } void A11yKeyboardManager::OnStatusIconActivate(GtkStatusIcon *status_icon, A11yKeyboardManager *manager) { if (manager->preferences_dialog == NULL) { manager->preferences_dialog = new A11yPreferencesDialog(); // connect(manager->preferences_dialog,SIGNAL(response(A11yKeyboardManager)),manager,SLOT(OnPreferencesDialogResponse(A11yKeyboardManager))); connect(manager->preferences_dialog, &A11yPreferencesDialog::singalCloseWidget, manager, &A11yKeyboardManager::OnPreferencesDialogResponse); manager->preferences_dialog->show(); } else { manager->preferences_dialog->close(); delete manager->preferences_dialog; } } void A11yKeyboardManager::A11yKeyboardManagerEnsureStatusIcon(A11yKeyboardManager *manager) { /*if (!manager->status_icon) { manager->status_icon = gtk_status_icon_new_from_icon_name ("preferences-desktop-accessibility"); g_signal_connect (manager->status_icon, "activate", G_CALLBACK (OnStatusIconActivate), manager); }*/ } void A11yKeyboardManager::MaybeShowStatusIcon(A11yKeyboardManager *manager) { bool show; /* for now, show if accessx is enabled */ show = manager->settings->get("enable").toBool(); /* if (!show && manager->status_icon == NULL) return; */ A11yKeyboardManagerEnsureStatusIcon (manager); } void A11yKeyboardManager::KeyboardCallback(QString key) { SetServerFromSettings (this); } bool A11yKeyboardManager::XkbEnabled (A11yKeyboardManager *manager) { bool have_xkb; int opcode, errorBase, major, minor; have_xkb = XkbQueryExtension (gdk_x11_get_default_xdisplay(), &opcode, &manager->xkbEventBase, &errorBase, &major, &minor) && XkbUseExtension (gdk_x11_get_default_xdisplay(), &major, &minor); return have_xkb; } static bool SupportsXinputDevices (void) { int op_code, event, error; return XQueryExtension (gdk_x11_get_default_xdisplay(), "XInputExtension", &op_code, &event, &error); } static GdkFilterReturn DevicepresenceFilter (GdkXEvent *xevent, GdkEvent *event, gpointer data) { XEvent *xev = (XEvent *) xevent; XEventClass class_presence; int xi_presence; A11yKeyboardManager *manager = (A11yKeyboardManager *)data; DevicePresence (gdk_x11_get_default_xdisplay (), xi_presence, class_presence); if (xev->type == xi_presence) { XDevicePresenceNotifyEvent *dpn = (XDevicePresenceNotifyEvent *) xev; if (dpn->devchange == DeviceEnabled) { manager->SetServerFromSettings (manager); } } return GDK_FILTER_CONTINUE; } void A11yKeyboardManager::SetDevicepresenceHandler (A11yKeyboardManager *manager) { Display *display; XEventClass class_presence; int xi_presence; if (!SupportsXinputDevices ()) return; display = gdk_x11_get_default_xdisplay (); gdk_x11_display_error_trap_push(gdk_display_get_default()); DevicePresence (display, xi_presence, class_presence); /* FIXME: * Note that this might overwrite other events, see: * https://bugzilla.gnome.org/show_bug.cgi?id=610245#c2 **/ XSelectExtensionEvent (display, RootWindow (display, DefaultScreen (display)), &class_presence, 1); gdk_display_flush(gdk_display_get_default()); if (!gdk_x11_display_error_trap_pop(gdk_display_get_default())) gdk_window_add_filter (NULL, DevicepresenceFilter, manager); } GdkFilterReturn CbXkbEventFilter (GdkXEvent *xevent, GdkEvent *ignored1, A11yKeyboardManager *manager) { XEvent *xev = (XEvent *) xevent; XkbEvent *xkbEv = (XkbEvent *) xevent; if (xev->xany.type == (manager->xkbEventBase + XkbEventCode) && xkbEv->any.xkb_type == XkbControlsNotify) { qDebug ("XKB state changed"); manager->SetSettingsFromServer (manager); } else if (xev->xany.type == (manager->xkbEventBase + XkbEventCode) && xkbEv->any.xkb_type == XkbAccessXNotify) { if (xkbEv->accessx.detail == XkbAXN_AXKWarning) { qDebug ("About to turn on an AccessX feature from the keyboard!"); /* * TODO: when XkbAXN_AXKWarnings start working, we need to * invoke ax_keys_warning_dialog_run here instead of in * SetSettingsFromServer(). */ } } return GDK_FILTER_CONTINUE; } bool A11yKeyboardManager::AxResponseCallback(A11yKeyboardManager *manager, QMessageBox *parent, int response_id, unsigned int revert_controls_mask, bool enabled) { switch (response_id) { case GTK_RESPONSE_DELETE_EVENT: case GTK_RESPONSE_REJECT: case GTK_RESPONSE_CANCEL: /* we're reverting, so we invert sense of 'enabled' flag */ qDebug ("cancelling AccessX request"); if (revert_controls_mask == XkbStickyKeysMask) { manager->settings->set("stickykeys-enable", !enabled); } else if (revert_controls_mask == XkbSlowKeysMask) { manager->settings->set("slowkeys-enable",!enabled); } manager->SetServerFromSettings (manager); break; case GTK_RESPONSE_HELP: if(!parent->isActiveWindow()) { QMessageBox *error_dialog = new QMessageBox(); error_dialog->warning(nullptr,nullptr,tr("There was an error displaying help"),QMessageBox::Close); error_dialog->setResult(false); error_dialog->show(); } return FALSE; default: break; } return TRUE; } #ifdef HAVE_LIBNOTIFY void OnNotificationClosed (NotifyNotification *notification, A11yKeyboardManager *manager) { g_object_unref (manager->notification); manager->notification = NULL; } void on_sticky_keys_action (NotifyNotification *notification, const char *action, A11yKeyboardManager *manager) { bool res; int response_id; g_assert (action != NULL); if (strcmp (action, "accept") == 0) { response_id = GTK_RESPONSE_ACCEPT; } else if (strcmp (action, "reject") == 0) { response_id = GTK_RESPONSE_REJECT; } else { return; } res = manager->AxResponseCallback (manager, nullptr, response_id, XkbStickyKeysMask, manager->StickykeysShortcutVal); if (res) { notify_notification_close (manager->notification, NULL); } } void on_slow_keys_action (NotifyNotification *notification, const char *action, A11yKeyboardManager *manager) { bool res; int response_id; g_assert (action != NULL); if (strcmp (action, "accept") == 0) { response_id = GTK_RESPONSE_ACCEPT; } else if (strcmp (action, "reject") == 0) { response_id = GTK_RESPONSE_REJECT; } else { return; } res = manager->AxResponseCallback (manager, nullptr, response_id, XkbSlowKeysMask, manager->SlowkeysShortcutVal); if (res) { notify_notification_close (manager->notification, NULL); } } #endif /* HAVE_LIBNOTIFY */ bool AxSlowkeysWarningPostDubble (A11yKeyboardManager *manager, bool enabled) { #ifdef HAVE_LIBNOTIFY bool res; QString title; QString message; GError *error; title = enabled ? QObject::tr("Do you want to activate Slow Keys?") : QObject::tr("Do you want to deactivate Slow Keys?"); message = QObject::tr("You just held down the Shift key for 8 seconds. This is the shortcut " "for the Slow Keys feature, which affects the way your keyboard works."); /* if (manager->status_icon == NULL || ! gtk_status_icon_is_embedded (manager->status_icon)) { return FALSE; } */ if (manager->SlowkeysAlert != NULL) { manager->SlowkeysAlert->close(); delete manager->SlowkeysAlert; } if (manager->notification != NULL) { notify_notification_close (manager->notification, NULL); } manager->A11yKeyboardManagerEnsureStatusIcon (manager); manager->notification = notify_notification_new (title.toLatin1().data(), message.toLatin1().data(), "preferences-desktop-accessibility"); notify_notification_set_timeout (manager->notification, NOTIFICATION_TIMEOUT * 1000); notify_notification_add_action (manager->notification, "reject", enabled ? _("Don't activate") : _("Don't deactivate"), (NotifyActionCallback) on_slow_keys_action, manager, NULL); notify_notification_add_action (manager->notification, "accept", enabled ? _("Activate") : _("Deactivate"), (NotifyActionCallback) on_slow_keys_action, manager, NULL); g_signal_connect (manager->notification, "closed", G_CALLBACK (OnNotificationClosed), manager); error = NULL; res = notify_notification_show (manager->notification, &error); if (! res) { g_warning ("UsdA11yKeyboardManager: unable to show notification: %s", error->message); g_error_free (error); notify_notification_close (manager->notification, NULL); } return res; #else return false; #endif } void A11yKeyboardManager::ax_slowkeys_response (QAbstractButton *button) { int response_id = 0; if(button == (QAbstractButton *)QMessageBox::Help) response_id = GTK_RESPONSE_HELP; else if(button == (QAbstractButton *)QMessageBox::Cancel) response_id = GTK_RESPONSE_CANCEL; if (AxResponseCallback (this, StickykeysAlert, response_id, XkbSlowKeysMask, SlowkeysShortcutVal)) { StickykeysAlert->close(); } } void A11yKeyboardManager::AxSlowkeysWarningPostDialog (A11yKeyboardManager *manager, bool enabled) { QString title; QString message; title = enabled ? tr("Do you want to activate Slow Keys?") : tr("Do you want to deactivate Slow Keys?"); message = tr("You just held down the Shift key for 8 seconds. This is the shortcut " "for the Slow Keys feature, which affects the way your keyboard works."); if (manager->SlowkeysAlert != NULL) { manager->SlowkeysAlert->show(); return; } manager->SlowkeysAlert = new QMessageBox(); manager->SlowkeysAlert->warning(nullptr,tr("Slow Keys Alert"), title); manager->SlowkeysAlert->setText(message); manager->SlowkeysAlert->setStandardButtons(QMessageBox::Help); manager->SlowkeysAlert->setButtonText(QMessageBox::Rejected, enabled ? tr("Do_n't activate") : tr("Do_n't deactivate")); manager->SlowkeysAlert->setButtonText(QMessageBox::Accepted, enabled ? tr("_Activate") : tr("_Deactivate")); manager->SlowkeysAlert->setWindowIconText(tr("input-keyboard")); manager->SlowkeysAlert->setDefaultButton(QMessageBox::Default); QObject::connect(manager->SlowkeysAlert,SIGNAL(buttonClicked(QAbstractButton *button)), manager,SLOT(ax_slowkeys_response(QAbstractButton *button))); manager->SlowkeysAlert->show(); /*g_object_add_weak_pointer (G_OBJECT (manager->StickykeysAlert), (gpointer*) &manager->StickykeysAlert);*/ } void A11yKeyboardManager::AxSlowkeysWarningPost (A11yKeyboardManager *manager, bool enabled) { manager->SlowkeysShortcutVal = enabled; /* alway try to show something */ if (! AxSlowkeysWarningPostDubble (manager, enabled)) { AxSlowkeysWarningPostDialog (manager, enabled); } } bool AxStickykeysWarningPostBubble (A11yKeyboardManager *manager, bool enabled) { #ifdef HAVE_LIBNOTIFY bool res; QString title; QString message; GError *error; title = enabled ? QObject::tr("Do you want to activate Sticky Keys?") : QObject::tr("Do you want to deactivate Sticky Keys?"); message = enabled ? QObject::tr("You just pressed the Shift key 5 times in a row. This is the shortcut " "for the Sticky Keys feature, which affects the way your keyboard works.") : QObject::tr("You just pressed two keys at once, or pressed the Shift key 5 times in a row. " "This turns off the Sticky Keys feature, which affects the way your keyboard works."); if (manager->SlowkeysAlert != NULL) { manager->SlowkeysAlert->close(); delete manager->SlowkeysAlert; } if (manager->notification != NULL) { notify_notification_close (manager->notification, NULL); } //usd_a11y_keyboard_manager_ensure_status_icon (manager); manager->notification = notify_notification_new (title.toLatin1().data(), message.toLatin1().data(), "preferences-desktop-accessibility"); notify_notification_set_timeout (manager->notification, NOTIFICATION_TIMEOUT * 1000); notify_notification_add_action (manager->notification, "reject", enabled ? _("Don't activate") : _("Don't deactivate"), (NotifyActionCallback) on_sticky_keys_action, manager, NULL); notify_notification_add_action (manager->notification, "accept", enabled ? _("Activate") : _("Deactivate"), (NotifyActionCallback) on_sticky_keys_action, manager, NULL); g_signal_connect (manager->notification, "closed", G_CALLBACK (OnNotificationClosed), manager); error = NULL; res = notify_notification_show (manager->notification, &error); if (! res) { qWarning ("UsdA11yKeyboardManager: unable to show notification: %s", error->message); g_error_free (error); notify_notification_close (manager->notification, NULL); } return res; #else return FALSE; #endif /* HAVE_LIBNOTIFY */ } void A11yKeyboardManager::ax_stickykeys_response(QAbstractButton *button) { int response_id = 0; if(button == (QAbstractButton *)QMessageBox::Help) response_id = GTK_RESPONSE_HELP; else if(button == (QAbstractButton *)QMessageBox::Cancel) response_id = GTK_RESPONSE_CANCEL; if(AxResponseCallback(this,StickykeysAlert, response_id,XkbStickyKeysMask,StickykeysShortcutVal)) StickykeysAlert->close(); } void A11yKeyboardManager::AxStickykeysWarningPostDialog (A11yKeyboardManager *manager, bool enabled) { QString title; QString message; title = enabled ? tr("Do you want to activate Sticky Keys?") : tr("Do you want to deactivate Sticky Keys?"); message = enabled ? tr("You just pressed the Shift key 5 times in a row. This is the shortcut " "for the Sticky Keys feature, which affects the way your keyboard works.") : tr("You just pressed two keys at once, or pressed the Shift key 5 times in a row. " "This turns off the Sticky Keys feature, which affects the way your keyboard works."); if (manager->StickykeysAlert != NULL) { manager->StickykeysAlert->show(); return; } manager->StickykeysAlert = new QMessageBox(); manager->StickykeysAlert->warning(nullptr,tr("Sticky Keys Alert"), title); manager->StickykeysAlert->setText(message); manager->StickykeysAlert->setStandardButtons(QMessageBox::Help); manager->StickykeysAlert->setButtonText(QMessageBox::Rejected, enabled ? tr("Do_n't activate") : tr("Do_n't deactivate")); manager->StickykeysAlert->setButtonText(QMessageBox::Accepted, enabled ? tr("_Activate") : tr("_Deactivate")); manager->StickykeysAlert->setWindowIconText(tr("input-keyboard")); manager->StickykeysAlert->setDefaultButton(QMessageBox::Default); QObject::connect(manager->StickykeysAlert,SIGNAL(buttonClicked(QAbstractButton *button)), manager,SLOT(ax_stickykeys_response(QAbstractButton *button))); manager->StickykeysAlert->show(); /*g_object_add_weak_pointer (G_OBJECT (manager->stickykeys_alert), (gpointer*) &manager->stickykeys_alert);*/ } void A11yKeyboardManager::AxStickykeysWarningPost (A11yKeyboardManager *manager, bool enabled) { manager->StickykeysShortcutVal = enabled; /* alway try to show something */ if (! AxStickykeysWarningPostBubble (manager, enabled)) { AxStickykeysWarningPostDialog (manager, enabled); } } /* * */ void A11yKeyboardManager::SetSettingsFromServer(A11yKeyboardManager *manager) { QGSettings *settings; XkbDescRec *desc; bool changed = false; bool slowkeys_changed; bool stickykeys_changed; desc = GetXkbDescRec (); if (! desc) { return; } settings = new QGSettings(CONFIG_SCHEMA); settings->delay(); /* fprintf (stderr, "changed to : 0x%x\n", desc->ctrls->enabled_ctrls); fprintf (stderr, "changed to : 0x%x (2)\n", desc->ctrls->ax_options); */ changed |= SetBool (settings, "enable", desc->ctrls->enabled_ctrls & XkbAccessXKeysMask); changed |= SetBool (settings, "feature-state-change-beep", desc->ctrls->ax_options & (XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask)); changed |= SetBool (settings, "timeout-enable", desc->ctrls->enabled_ctrls & XkbAccessXTimeoutMask); changed |= SetInt (settings, "timeout", desc->ctrls->ax_timeout); changed |= SetBool (settings, "bouncekeys-enable", desc->ctrls->enabled_ctrls & XkbBounceKeysMask); changed |= SetInt (settings, "bouncekeys-delay", desc->ctrls->debounce_delay); changed |= SetBool (settings, "bouncekeys-beep-reject", desc->ctrls->ax_options & XkbAX_BKRejectFBMask); changed |= SetBool (settings, "mousekeys-enable", desc->ctrls->enabled_ctrls & XkbMouseKeysMask); changed |= SetInt (settings, "mousekeys-max-speed", desc->ctrls->mk_max_speed * (1000 / desc->ctrls->mk_interval)); /* NOTE : mk_time_to_max is measured in events not time */ changed |= SetInt (settings, "mousekeys-accel-time", desc->ctrls->mk_time_to_max * desc->ctrls->mk_interval); changed |= SetInt (settings, "mousekeys-init-delay", desc->ctrls->mk_delay); slowkeys_changed = SetBool (settings, "slowkeys-enable", desc->ctrls->enabled_ctrls & XkbSlowKeysMask); changed |= SetBool (settings, "slowkeys-beep-press", desc->ctrls->ax_options & XkbAX_SKPressFBMask); changed |= SetBool (settings, "slowkeys-beep-accept", desc->ctrls->ax_options & XkbAX_SKAcceptFBMask); changed |= SetBool (settings, "slowkeys-beep-reject", desc->ctrls->ax_options & XkbAX_SKRejectFBMask); changed |= SetInt (settings, "slowkeys-delay", desc->ctrls->slow_keys_delay); stickykeys_changed = SetBool (settings, "stickykeys-enable", desc->ctrls->enabled_ctrls & XkbStickyKeysMask); changed |= SetBool (settings, "stickykeys-two-key-off", desc->ctrls->ax_options & XkbAX_TwoKeysMask); changed |= SetBool (settings, "stickykeys-modifier-beep", desc->ctrls->ax_options & XkbAX_StickyKeysFBMask); changed |= SetBool (settings, "togglekeys-enable", desc->ctrls->ax_options & XkbAX_IndicatorFBMask); if (!changed && stickykeys_changed ^ slowkeys_changed) { /* * sticky or slowkeys has changed, singly, without our intervention. * 99% chance this is due to a keyboard shortcut being used. * we need to detect via this hack until we get * XkbAXN_AXKWarning notifications working (probable XKB bug), * at which time we can directly intercept such shortcuts instead. * See CbXkbEventFilter () below. */ /* sanity check: are keyboard shortcuts available? */ if (desc->ctrls->enabled_ctrls & XkbAccessXKeysMask) { if (slowkeys_changed) { AxSlowkeysWarningPost (manager, desc->ctrls->enabled_ctrls & XkbSlowKeysMask); } else { AxStickykeysWarningPost (manager, desc->ctrls->enabled_ctrls & XkbStickyKeysMask); } } } XkbFreeKeyboard (desc, XkbAllComponentsMask, True); changed |= (stickykeys_changed | slowkeys_changed); if (changed) { settings->apply(); } delete settings; } void A11yKeyboardManager::StartA11yKeyboardIdleCb() { unsigned int event_mask; USD_LOG(LOG_DEBUG, "Starting a11y_keyboard manager"); // OnStatusIconActivate(NULL,this); just for show config form. time->stop(); if (!XkbEnabled (this)) goto out; connect(settings, &QGSettings::changed, this, &A11yKeyboardManager::KeyboardCallback); SetDevicepresenceHandler (this); /* Save current xkb state so we can restore it on exit */ OriginalXkbDesc = GetXkbDescRec (); event_mask = XkbControlsNotifyMask; #ifdef DEBUG_ACCESSIBILITY event_mask |= XkbAccessXNotifyMask; /* make default when AXN_AXKWarning works */ #endif /* be sure to init before starting to monitor the server */ SetServerFromSettings (this); XkbSelectEvents (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), XkbUseCoreKbd, event_mask, event_mask); gdk_window_add_filter (NULL, (GdkFilterFunc) CbXkbEventFilter, this); //MaybeShowStatusIcon (this); out: return; } ukui-settings-daemon/plugins/a11y-keyboard/a11y-preferences-dialog.cpp0000644000175000017500000000230514205117202024611 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "a11y-preferences-dialog.h" #include "ui_a11y-preferences-dialog.h" A11yPreferencesDialog::A11yPreferencesDialog(QWidget *parent) : QWidget(parent), ui(new Ui::A11yPreferencesDialog) { ui->setupUi(this); } A11yPreferencesDialog::~A11yPreferencesDialog() { delete ui; } void A11yPreferencesDialog::closeEvent(QCloseEvent *event) { Q_UNUSED(event); USD_LOG(LOG_DEBUG,"dialog had close"); Q_EMIT singalCloseWidget(); } ukui-settings-daemon/plugins/a11y-keyboard/a11y-keyboard.pro0000644000175000017500000000166614205117202022702 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-08-05T19:30:00 # #------------------------------------------------- QT += gui core widgets x11extras TARGET = a11y-keyboard TEMPLATE = lib DEFINES += A11YKEYBOARD_LIBRARY MODULE_NAME=\\\"a11y-keyboard\\\" CONFIG += c++11 no_keywords link_pkgconfig plugin debug CONFIG += app_bunale DEFINES += QT_DEPRECATED_WARNINGS include($$PWD/../../common/common.pri) PKGCONFIG += \ gtk+-3.0 \ glib-2.0 \ libnotify \ gsettings-qt \ xi SOURCES += \ a11y-keyboard-manager.cpp \ a11y-keyboard-plugin.cpp \ a11y-preferences-dialog.cpp HEADERS += \ a11y-keyboard-manager.h \ a11y-keyboard-plugin.h \ a11y-preferences-dialog.h a11y_keyboard_lib.path = $${PLUGIN_INSTALL_DIRS} a11y_keyboard_lib.files = $$OUT_PWD/liba11y-keyboard.so INSTALLS += a11y_keyboard_lib FORMS += \ a11y-preferences-dialog.ui ukui-settings-daemon/plugins/a11y-keyboard/a11y-keyboard-plugin.h0000644000175000017500000000252414205117202023617 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef A11YKEYBOARDPLUGIN_H #define A11YKEYBOARDPLUGIN_H #include "plugin-interface.h" #include "a11y-keyboard-manager.h" class A11yKeyboardPlugin : public PluginInterface { public: ~A11yKeyboardPlugin(); static PluginInterface * getInstance(); virtual void activate(); virtual void deactivate(); private: A11yKeyboardPlugin(); A11yKeyboardPlugin(A11yKeyboardPlugin&)=delete; static A11yKeyboardManager *UsdA11yManager; static PluginInterface *mInstance; }; extern "C" Q_DECL_EXPORT PluginInterface* createSettingsPlugin(); #endif // A11YKEYBOARDPLUGIN_H ukui-settings-daemon/plugins/mouse/0000755000175000017500000000000014205117202016355 5ustar fengfengukui-settings-daemon/plugins/mouse/mouse-plugin.h0000755000175000017500000000244614205117202021163 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MOUSEPLUGIN_H #define MOUSEPLUGIN_H #include "mouse-manager.h" #include "plugin-interface.h" #include class MousePlugin : public PluginInterface { public: ~MousePlugin(); static PluginInterface * getInstance(); virtual void activate(); virtual void deactivate(); private: MousePlugin(); MousePlugin(MousePlugin&)=delete; static MouseManager * UsdMouseManager; static PluginInterface * mInstance; }; extern "C" Q_DECL_EXPORT PluginInterface* createSettingsPlugin(); #endif // MOUSEPLUGIN_H ukui-settings-daemon/plugins/mouse/mouse-manager.cpp0000755000175000017500000017637314205117202021645 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mouse-manager.h" #include "clib-syslog.h" #include "usd_base_class.h" /* Keys with same names for both touchpad and mouse */ #define KEY_LEFT_HANDED "left-handed" /* a boolean for mouse, an enum for touchpad */ #define KEY_MOTION_ACCELERATION "motion-acceleration" #define KEY_MOTION_THRESHOLD "motion-threshold" /* Mouse settings */ #define UKUI_MOUSE_SCHEMA "org.ukui.peripherals-mouse" #define KEY_MOUSE_LOCATE_POINTER "locate-pointer" #define KEY_MIDDLE_BUTTON_EMULATION "middle-button-enabled" #define KEY_MOUSE_WHEEL_SPEED "wheel-speed" #define KEY_MOUSE_ACCEL "mouse-accel" /* Touchpad settings */ #define UKUI_TOUCHPAD_SCHEMA "org.ukui.peripherals-touchpad" #define KEY_TOUCHPAD_DISABLE_W_TYPING "disable-while-typing" #define KEY_TOUCHPAD_TWO_FINGER_CLICK "two-finger-click" #define KEY_TOUCHPAD_THREE_FINGER_CLICK "three-finger-click" #define KEY_TOUCHPAD_NATURAL_SCROLL "natural-scroll" #define KEY_TOUCHPAD_TAP_TO_CLICK "tap-to-click" #define KEY_TOUCHPAD_ONE_FINGER_TAP "tap-button-one-finger" #define KEY_TOUCHPAD_TWO_FINGER_TAP "tap-button-two-finger" #define KEY_TOUCHPAD_THREE_FINGER_TAP "tap-button-three-finger" #define KEY_VERT_EDGE_SCROLL "vertical-edge-scrolling" #define KEY_HORIZ_EDGE_SCROLL "horizontal-edge-scrolling" #define KEY_VERT_TWO_FINGER_SCROLL "vertical-two-finger-scrolling" #define KEY_HORIZ_TWO_FINGER_SCROLL "horizontal-two-finger-scrolling" #define KEY_TOUCHPAD_ENABLED "touchpad-enabled" #define KEY_TOUCHPAD_DISBLE_O_E_MOUSE "disable-on-external-mouse" //插入鼠标,禁用触摸板 true/false #define KEY_TOUCHPAD_DOUBLE_CLICK_DRAG "double-click-drag" //点击两次拖动 true/false #define KEY_TOUCHPAD_BOTTOM_R_C_CLICK_M "bottom-right-corner-click-menu" //右下角点击菜单 true/false #define KEY_TOUCHPAD_MOUSE_SENSITVITY "mouse-sensitivity" //鼠标敏感度 1-4 四个档位 低中高最高 extern "C"{ #include } typedef enum { TOUCHPAD_HANDEDNESS_RIGHT, TOUCHPAD_HANDEDNESS_LEFT, TOUCHPAD_HANDEDNESS_MOUSE } TouchpadHandedness; GdkFilterReturn devicepresence_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data); bool supports_xinput_devices (void); bool touchpad_is_present (void); MouseManager * MouseManager::mMouseManager =nullptr; MouseManager::MouseManager(QObject *parent) : QObject (parent) { gdk_init(NULL,NULL); syndaemon_spawned = false; syndaemon_pid = 0; locate_pointer_spawned = false; locate_pointer_pid = 0; imwheelSpawned = false; settings_mouse = new QGSettings(UKUI_MOUSE_SCHEMA); settings_touchpad = new QGSettings(UKUI_TOUCHPAD_SCHEMA); } MouseManager::~MouseManager() { delete settings_mouse; delete settings_touchpad; if(time) delete time; } MouseManager * MouseManager::MouseManagerNew() { if(nullptr == mMouseManager) mMouseManager = new MouseManager(nullptr); return mMouseManager; } bool MouseManager::MouseManagerStart() { USD_LOG(LOG_DEBUG,"-- Mouse Start Manager --"); if (!supports_xinput_devices()){ qWarning("XInput is not supported, not applying any settings"); return TRUE; } time = new QTimer(this); connect(time, &QTimer::timeout, this, &MouseManager::MouseManagerIdleCb); time->start(); return true; } void MouseManager::MouseManagerStop() { USD_LOG(LOG_DEBUG,"-- Stopping Mouse Manager --"); SetLocatePointer(FALSE); gdk_window_remove_filter (NULL, devicepresence_filter, this); } /* transplant usd-input-helper.h */ /* Checks whether the XInput device is supported * 检测是否支持xinput设备 */ bool supports_xinput_devices (void) { int op_code, event, error; return XQueryExtension (QX11Info::display(), "XInputExtension", &op_code, &event, &error); } static bool device_has_property (XDevice *device, const char *property_name) { Atom realtype, prop; int realformat; unsigned long nitems, bytes_after; unsigned char *data; prop = XInternAtom (QX11Info::display(), property_name, True); if (!prop) return FALSE; try { if ((XGetDeviceProperty (QX11Info::display(), device, prop, 0, 1, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data) == Success) && (realtype != None)) { XFree (data); return TRUE; } } catch (int x) { } return FALSE; } XDevice* device_is_touchpad (XDeviceInfo *deviceinfo) { XDevice *device; if (deviceinfo->type != XInternAtom (QX11Info::display(), XI_TOUCHPAD, True)) return NULL; try { device = XOpenDevice (QX11Info::display(), deviceinfo->id); if (device == NULL) throw 1; if (device_has_property (device, "libinput Tapping Enabled") || device_has_property (device, "Synaptics Off")) { return device; } XCloseDevice (QX11Info::display(), device); } catch (int x) { return NULL; } return NULL; } bool touchpad_is_present (void) { XDeviceInfo *device_info; int n_devices; int i; bool retval; if (supports_xinput_devices () == false) return true; retval = false; device_info = XListInputDevices (QX11Info::display(), &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; } bool MouseManager::GetTouchpadHandedness (bool mouse_left_handed) { int a = settings_touchpad->getEnum(KEY_LEFT_HANDED); switch (a) { case TOUCHPAD_HANDEDNESS_RIGHT: return false; case TOUCHPAD_HANDEDNESS_LEFT: return true; case TOUCHPAD_HANDEDNESS_MOUSE: return mouse_left_handed; default: g_assert_not_reached (); } } Atom property_from_name (const char *property_name) { return XInternAtom (QX11Info::display(), property_name, True); } bool query_device_had_property(XDeviceInfo *device_info,const char *property_name) { XDevice *device; int nProps = 0; Atom* type_data; unsigned char *data; Atom Xdata; bool ret = false; Display * display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); device = XOpenDevice (display, device_info->id); USD_LOG(LOG_DEBUG,"device name:%s",device_info->name); if (device == NULL) { USD_LOG(LOG_DEBUG, "%s find %s had a error:can't open id(%d) device in XOpenDevice,type:%d",device_info->name, property_name,device_info->id,device_info->type); return false; } type_data = XListDeviceProperties(display ,device, &nProps); Xdata = XInternAtom (QX11Info::display(), property_name, True); //USD_LOG_SHOW_PARAM1(nProps); //USD_LOG_SHOW_PARAM1(Xdata); //USD_LOG_SHOW_PARAMS(property_name); if (Xdata == 0) { ret = false; goto END; } for (int k = 0; k < nProps; k++) { // USD_LOG_SHOW_PARAM1(type_data[k]); if (Xdata == type_data[k]) { USD_LOG(LOG_DEBUG,"find: props"); //USD_LOG_SHOW_PARAM1(type_data[k]); ret = true; goto END; } } END: XCloseDevice (display, device); return ret; } /* This is an example of the last function. bool property_exists_on_device (XDeviceInfo *device_info, const char *property_name) { XDevice *device; int rc; Atom type, prop; int format; unsigned long nitems, bytes_after; unsigned char *data; // Display *display = gdk_x11_get_default_xdisplay ();//QX11Info::display(); Display * display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); prop = property_from_name (property_name); if (!prop) return FALSE; try { device = XOpenDevice (display, device_info->id); if (device == NULL) { USD_LOG(LOG_DEBUG, "%s find %s had a error:can't open id(%d) device in XOpenDevice,type:%d",device_info->name, property_name,device_info->id,device_info->type); throw 1; } // USD_LOG(LOG_DEBUG,"prop [%s] had find in %d type:%d", property_name, device_info->id, device_info->type); rc = XGetDeviceProperty (display, device, prop, 0, 1, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); USD_LOG_SHOW_PARAM1(rc); if (rc == Success) XFree (data); XCloseDevice (display, device); } catch (int str) { USD_LOG(LOG_DEBUG,"MOUSE: WRING ID: %d",str); return FALSE; } return rc == Success; } */ void property_set_bool (XDeviceInfo *device_info, XDevice *device, const char *property_name, int property_index, bool enabled) { int rc; unsigned long nitems, bytes_after; unsigned char *data; int act_format; Atom act_type, property; Display *display = gdk_x11_get_default_xdisplay ();//QX11Info::display(); property = property_from_name (property_name); if (!property) return; try { gdk_x11_display_error_trap_push (gdk_display_get_default()); rc = XGetDeviceProperty (display, device, property, 0, 1, False, XA_INTEGER, &act_type, &act_format, &nitems, &bytes_after, &data); if (rc == Success && act_type == XA_INTEGER && act_format == 8 && nitems >(unsigned long)property_index) { data[property_index] = enabled ? 1 : 0; XChangeDeviceProperty (display, device, property, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (rc == Success) XFree (data); if(gdk_x11_display_error_trap_pop (gdk_display_get_default())) USD_LOG(LOG_DEBUG,"Error while setting %s on \"%s\"", property_name, device_info->name); } catch (int x) { USD_LOG(LOG_DEBUG,"MOUSE:Error while setting %s on \"%s\"", property_name, device_info->name) } } void set_left_handed_libinput (XDeviceInfo *device_info, bool mouse_left_handed, bool touchpad_left_handed) { XDevice *device; bool want_lefthanded; Display *display = QX11Info::display(); device = device_is_touchpad (device_info); try { if (device == NULL) { device = XOpenDevice (display, device_info->id); if (device == NULL) throw 1; want_lefthanded = mouse_left_handed; } else { /* touchpad device is already open after * return from device_is_touchpad function */ want_lefthanded = touchpad_left_handed; } property_set_bool (device_info, device, "libinput Left Handed Enabled", 0, want_lefthanded); XCloseDevice (display, device); } catch (int x) { return; } } gboolean xinput_device_has_buttons (XDeviceInfo *device_info) { int i; XAnyClassInfo *class_info; class_info = device_info->inputclassinfo; for (i = 0; i < device_info->num_classes; i++) { if (class_info->c_class == ButtonClass) { XButtonInfo *button_info; button_info = (XButtonInfo *) class_info; if (button_info->num_buttons > 0) return TRUE; } class_info = (XAnyClassInfo *) (((guchar *) class_info) + class_info->length); } return FALSE; } bool touchpad_has_single_button (XDevice *device) { Atom type, prop; int format; unsigned long nitems, bytes_after; unsigned char *data; bool is_single_button = FALSE; int rc; prop = property_from_name ("Synaptics Capabilities"); if (!prop) return false; try { rc = XGetDeviceProperty (QX11Info::display(), device, prop, 0, 1, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 3) is_single_button = (data[0] == 1 && data[1] == 0 && data[2] == 0); if (rc == Success) XFree (data); } catch (int x) { } return is_single_button; } void set_tap_to_click_synaptics (XDeviceInfo *device_info, bool state, bool left_handed, int one_finger_tap, int two_finger_tap, int three_finger_tap) { XDevice *device; int format, rc; unsigned long nitems, bytes_after; unsigned char* data; Atom prop, type; Display *display = gdk_x11_get_default_xdisplay (); //QX11Info::display(); prop = property_from_name ("Synaptics Tap Action"); if (!prop) return; device = device_is_touchpad (device_info); if (device == NULL) { return; } try { rc = XGetDeviceProperty (display, device, prop, 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (one_finger_tap > 3 || one_finger_tap < 1) one_finger_tap = 1; if (two_finger_tap > 3 || two_finger_tap < 1) two_finger_tap = 3; if (three_finger_tap > 3 || three_finger_tap < 0) three_finger_tap = 0; if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 7) { /* Set RLM mapping for 1/2/3 fingers*/ data[4] = (state) ? ((left_handed) ? (4-one_finger_tap) : one_finger_tap) : 0; data[5] = (state) ? ((left_handed) ? (4-two_finger_tap) : two_finger_tap) : 0; data[6] = (state) ? three_finger_tap : 0; XChangeDeviceProperty (display, device, prop, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (rc == Success) XFree (data); USD_LOG(LOG_DEBUG,"..."); XCloseDevice (display, device); } catch (int x) { qWarning("Error in setting tap to click on \"%s\"", device_info->name); } } void configure_button_layout (guchar *buttons, int n_buttons, bool left_handed) { const int left_button = 1; int right_button; int i; /* if the button is higher than 2 (3rd button) then it's * probably one direction of a scroll wheel or something else * uninteresting */ right_button = MIN (n_buttons, 3); /* If we change things we need to make sure we only swap buttons. * If we end up with multiple physical buttons assigned to the same * logical button the server will complain. This code assumes physical * button 0 is the physical left mouse button, and that the physical * button other than 0 currently assigned left_button or right_button * is the physical right mouse button. */ /* check if the current mapping satisfies the above assumptions */ if (buttons[left_button - 1] != left_button && buttons[left_button - 1] != right_button) /* The current mapping is weird. Swapping buttons is probably not a * good idea. */ return; /* check if we are left_handed and currently not swapped */ if (left_handed && buttons[left_button - 1] == left_button) { /* find the right button */ for (i = 0; i < n_buttons; i++) { if (buttons[i] == right_button) { buttons[i] = left_button; break; } } /* swap the buttons */ buttons[left_button - 1] = right_button; } /* check if we are not left_handed but are swapped */ else if (!left_handed && buttons[left_button - 1] == right_button) { /* find the right button */ for (i = 0; i < n_buttons; i++) { if (buttons[i] == left_button) { buttons[i] = right_button; break; } } /* swap the buttons */ buttons[left_button - 1] = left_button; } } void MouseManager::SetLeftHandedLegacyDriver (XDeviceInfo *device_info, bool mouse_left_handed, bool touchpad_left_handed) { XDevice *device; unsigned char *buttons; unsigned long buttons_capacity = 16; int n_buttons; bool left_handed; Display *display = QX11Info::display(); if ((device_info->use == IsXPointer) || (device_info->use == IsXKeyboard) || (g_strcmp0 ("Virtual core XTEST pointer", device_info->name) == 0) || (!xinput_device_has_buttons (device_info))) return; /* If the device is a touchpad, swap tap buttons * around too, otherwise a tap would be a right-click */ device = device_is_touchpad (device_info); if (device != NULL) { bool tap = settings_touchpad->get(KEY_TOUCHPAD_TAP_TO_CLICK).toBool(); bool single_button = touchpad_has_single_button (device); left_handed = touchpad_left_handed; if (tap && !single_button) { int one_finger_tap = settings_touchpad->get(KEY_TOUCHPAD_ONE_FINGER_TAP).toInt(); int two_finger_tap = settings_touchpad->get(KEY_TOUCHPAD_TWO_FINGER_TAP).toInt(); int three_finger_tap = settings_touchpad->get(KEY_TOUCHPAD_THREE_FINGER_TAP).toInt(); USD_LOG_SHOW_PARAM1(left_handed); set_tap_to_click_synaptics (device_info, tap, left_handed, one_finger_tap, two_finger_tap, three_finger_tap); } XCloseDevice (display, device); if (single_button) return; } else { left_handed = mouse_left_handed; USD_LOG(LOG_DEBUG,"SET IT"); USD_LOG_SHOW_PARAM1(left_handed); //USD_LOG(LOG_DEBUG,"."); } try { device = XOpenDevice (display, device_info->id); if (device == NULL) throw 1; buttons = g_new (guchar, buttons_capacity); n_buttons = XGetDeviceButtonMapping (display, device, buttons, buttons_capacity); while (n_buttons > (int)buttons_capacity) { buttons_capacity = n_buttons; buttons = (guchar *) g_realloc (buttons, buttons_capacity * sizeof (guchar)); n_buttons = XGetDeviceButtonMapping (display, device, buttons, buttons_capacity); } configure_button_layout (buttons, n_buttons, left_handed); XSetDeviceButtonMapping (display, device, buttons, n_buttons); XCloseDevice (display, device); g_free (buttons); } catch (int x) { USD_LOG(LOG_DEBUG,"MOUSE :error id %d",x); return; } } void MouseManager::SetLeftHanded (XDeviceInfo *device_info, bool mouse_left_handed, bool touchpad_left_handed) { if (query_device_had_property (device_info, "libinput Left Handed Enabled")){ set_left_handed_libinput (device_info, mouse_left_handed, touchpad_left_handed); USD_LOG_SHOW_PARAM1(mouse_left_handed); } else { USD_LOG_SHOW_PARAM1(touchpad_left_handed); SetLeftHandedLegacyDriver (device_info, mouse_left_handed, touchpad_left_handed); } } void MouseManager::SetLeftHandedAll (bool mouse_left_handed, bool touchpad_left_handed) { XDeviceInfo *device_info = nullptr; int n_devices; int i; Display * dpy = QX11Info::display(); device_info = XListInputDevices (dpy, &n_devices); if(!device_info){ qWarning("SetLeftHandedAll: device_info is null"); return; } for (i = 0; i < n_devices; i++) { SetLeftHanded (&device_info[i], mouse_left_handed, touchpad_left_handed); } if (device_info != NULL) XFreeDeviceList (device_info); } void MouseManager::SetMotionLibinput (XDeviceInfo *device_info) { XDevice *device; Atom prop; Atom type; Atom float_type; int format, rc; unsigned long nitems, bytes_after; QGSettings *settings; Display * dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());// gdk_x11_get_default_xdisplay ();//QX11Info::display(); union { unsigned char *c; long *l; } data; float accel; float motion_acceleration; float_type = property_from_name ("FLOAT"); if (!float_type) return; prop = property_from_name ("libinput Accel Speed"); if (!prop) { return; } try { device = device_is_touchpad (device_info); if (device != NULL) { USD_LOG(LOG_DEBUG,"device != NULL settings = settings_touchpad"); settings = settings_touchpad; } else { device = XOpenDevice (dpy, device_info->id); if (device == NULL) throw 1; settings = settings_mouse; } /* Calculate acceleration */ motion_acceleration = settings->get(KEY_MOTION_ACCELERATION).toDouble(); /* panel gives us a range of 1.0-10.0, map to libinput's [-1, 1] * * oldrange = (oldmax - oldmin) * newrange = (newmax - newmin) * * mapped = (value - oldmin) * newrange / oldrange + oldmin */ if (motion_acceleration == -1.0) /* unset */ accel = 0.0; else accel = (motion_acceleration - 1.0) * 2.0 / 9.0 - 1; rc = XGetDeviceProperty (dpy,device, prop, 0, 1, False, float_type, &type, &format, &nitems, &bytes_after, &data.c); if (rc == Success && type == float_type && format == 32 && nitems >= 1) { *(float *) data.l = accel; XChangeDeviceProperty (dpy, device, prop, float_type, 32, PropModeReplace, data.c, nitems); } if (rc == Success) { XFree (data.c); } XCloseDevice (dpy, device); } catch (int x) { qWarning("%s Error while setting accel speed on \"%s\"", device_info->name); return; } } void MouseManager::SetMotionLegacyDriver (XDeviceInfo *device_info) { XDevice *device; XPtrFeedbackControl feedback; XFeedbackState *states, *state; int num_feedbacks, i; QGSettings *settings; double motion_acceleration; int motion_threshold; int numerator, denominator; Display * dpy = gdk_x11_get_default_xdisplay ();//QX11Info::display(); device = device_is_touchpad (device_info); if (device != NULL) { settings = settings_touchpad; } else { try { device = XOpenDevice (dpy, device_info->id); if (device == NULL) throw 1; } catch (int x) { USD_LOG(LOG_DEBUG,"%s: error id %d","MOUSE", x); return; } settings = settings_mouse; } /* Calculate acceleration */ motion_acceleration = settings->get(KEY_MOTION_ACCELERATION).toDouble(); if (motion_acceleration >= 1.0) { /* we want to get the acceleration, with a resolution of 0.5 */ if ((motion_acceleration - floor (motion_acceleration)) < 0.25) { numerator = floor (motion_acceleration); denominator = 1; } else if ((motion_acceleration - floor (motion_acceleration)) < 0.5) { numerator = ceil (2.0 * motion_acceleration); denominator = 2; } else if ((motion_acceleration - floor (motion_acceleration)) < 0.75) { numerator = floor (2.0 *motion_acceleration); denominator = 2; } else { numerator = ceil (motion_acceleration); denominator = 1; } } else if (motion_acceleration < 1.0 && motion_acceleration > 0) { /* This we do to 1/10ths */ numerator = floor (motion_acceleration * 10) + 1; denominator= 10; } else { numerator = -1; denominator = -1; } /* And threshold */ motion_threshold = settings->get(KEY_MOTION_THRESHOLD).toInt(); // qDebug()<<__func__<<" motion_threshold = "<c_class == PtrFeedbackClass) { /* And tell the device */ feedback.c_class = PtrFeedbackClass; feedback.length = sizeof (XPtrFeedbackControl); feedback.id = state->id; feedback.threshold = motion_threshold; feedback.accelNum = numerator; feedback.accelDenom = denominator; USD_LOG(LOG_DEBUG,"Setting accel %d/%d, threshold %d for device '%s'", numerator, denominator, motion_threshold, device_info->name); XChangeFeedbackControl (dpy, device, DvAccelNum | DvAccelDenom | DvThreshold, (XFeedbackControl *) &feedback); break; } state = (XFeedbackState *) ((char *) state + state->length); } XFreeFeedbackList (states); XCloseDevice (dpy, device); } void MouseManager::SetTouchpadMotionAccel(XDeviceInfo *device_info) { XDevice *device; Atom prop; Atom type; Atom float_type; int format, rc; unsigned long nitems, bytes_after; // Display * dpy = gdk_x11_get_default_xdisplay ();//QX11Info::display(); Display * dpy = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());//Display * dpy = QX11Info::display(); union { unsigned char *c; long *l; } data; float accel; float motion_acceleration; float_type = property_from_name ("FLOAT"); if (!float_type) return; prop = property_from_name ("Device Accel Constant Deceleration"); if (!prop) { return; } try { device = device_is_touchpad (device_info); if (device == NULL) return; /* Calculate acceleration */ motion_acceleration = settings_touchpad->get(KEY_MOTION_ACCELERATION).toDouble(); if (motion_acceleration == -1.0) /* unset */ accel = 0.0; else accel = motion_acceleration; rc = XGetDeviceProperty (dpy,device, prop, 0, 1, False, float_type, &type, &format, &nitems, &bytes_after, &data.c); USD_LOG_SHOW_PARAM2(format,nitems) if (rc == Success && type == float_type && format == 32 && nitems >= 1) { *(float *) data.l = accel; XChangeDeviceProperty (dpy, device, prop, float_type, 32, PropModeReplace, data.c, nitems); } if (rc == Success) { XFree (data.c); } XCloseDevice (dpy, device); } catch (int x) { USD_LOG(LOG_ERR,"catch a bug..."); return; } } void MouseManager::SetMouseAccel(XDeviceInfo *device_info) { XDevice *device; Atom prop; Atom type; int format, rc; unsigned long nitems, bytes_after; //Display * dpy = QX11Info::display(); Display * dpy = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); unsigned char *data; bool MouseAccel; prop = property_from_name ("libinput Accel Profile Enabled"); if (!prop) { return; } try { device = XOpenDevice (dpy, device_info->id); if (device == NULL) throw 1; rc = XGetDeviceProperty (dpy,device, prop, 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 1) { MouseAccel = settings_mouse->get(KEY_MOUSE_ACCEL).toBool(); if(MouseAccel){ data[0] = 1; data[1] = 0; }else{ data[0] = 0; data[1] = 1; } XChangeDeviceProperty (dpy, device, prop, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (rc == Success) { XFree (data); } XCloseDevice (dpy, device); } catch (int x) { USD_LOG(LOG_ERR,"catch a bug..."); // qWarning("%s Error while setting accel speed on \"%s\"", device_info->name); return; } } void MouseManager::SetMotion (XDeviceInfo *device_info) { if (query_device_had_property (device_info, "libinput Accel Speed")) { SetMotionLibinput (device_info); } else { SetMotionLegacyDriver (device_info); } if(query_device_had_property (device_info, "Device Accel Constant Deceleration")) { SetTouchpadMotionAccel(device_info); } if(query_device_had_property (device_info, "libinput Accel Profile Enabled")) { SetMouseAccel(device_info); } } void MouseManager::SetMotionAll() { XDeviceInfo *device_info = nullptr; int n_devices; int i; device_info = XListInputDevices (gdk_x11_get_default_xdisplay (), &n_devices); if(!device_info){ qWarning("SetMotionAll: device_info is null"); return; } for (i = 0; i < n_devices; i++) { SetMotion (&device_info[i]); } if (device_info != NULL) XFreeDeviceList (device_info); } void set_middle_button_evdev (XDeviceInfo *device_info, bool middle_button) { XDevice *device; Atom prop; Atom type; int format, rc; unsigned long nitems, bytes_after; unsigned char *data; Display * display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); // Display * display = QX11Info::display(); prop = property_from_name ("Evdev Middle Button Emulation"); if (!prop) /* no evdev devices */ return; try { device = XOpenDevice (display, device_info->id); if (device == NULL) throw 1; rc = XGetDeviceProperty (display, device, prop, 0, 1, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (rc == Success && format == 8 && type == XA_INTEGER && nitems == 1) { data[0] = middle_button ? 1 : 0; XChangeDeviceProperty (display, device, prop, type, format, PropModeReplace, data, nitems); } if (rc == Success) XFree (data); XCloseDevice (display, device); } catch (int x) { qWarning("Error in setting middle button emulation on \"%s\"", device_info->name); return; } } void set_middle_button_libinput (XDeviceInfo *device_info, bool middle_button) { XDevice *device; Display *display = QX11Info::display(); /* touchpad devices are excluded as the old code * only applies to evdev devices */ device = device_is_touchpad (device_info); if (device != NULL) { try { XCloseDevice (display, device); } catch (int x) { return; } } try { device = XOpenDevice (display, device_info->id); if (device == NULL) throw 1; property_set_bool (device_info, device, "libinput Middle Emulation Enabled", 0, middle_button); XCloseDevice (display, device); } catch (int x) { USD_LOG(LOG_DEBUG,"%s:error id %d","MOUSE",x); return; } } void MouseManager::SetMiddleButton (XDeviceInfo *device_info, bool middle_button) { if (property_from_name ("Evdev Middle Button Emulation")) set_middle_button_evdev (device_info, middle_button); if (property_from_name ("libinput Middle Emulation Enabled")) set_middle_button_libinput (device_info, middle_button); } void MouseManager::SetMiddleButtonAll (bool middle_button) { XDeviceInfo *device_info = nullptr; int n_devices; int i; Display * display = QX11Info::display(); device_info = XListInputDevices (display, &n_devices); if(!device_info){ qWarning("SetMiddleButtonAll: device_info is null"); return; } for (i = 0; i < n_devices; i++) { SetMiddleButton (&device_info[i], middle_button); } if (device_info != NULL) XFreeDeviceList (device_info); } void MouseManager::SetLocatePointer (bool state) { if (state) { GError *error = NULL; char **args; int argc; if (locate_pointer_spawned) return; QString str = "/usr/bin/usd-locate-pointer"; if( g_shell_parse_argv (str.toLatin1().data(), &argc, &args, NULL)){ g_spawn_async (g_get_home_dir (), args, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &locate_pointer_pid, &error); locate_pointer_spawned = (error == NULL); } if (error) { settings_mouse->set(KEY_MOUSE_LOCATE_POINTER,false); g_error_free (error); } g_strfreev (args); } else if (locate_pointer_spawned) { kill (locate_pointer_pid, SIGHUP); g_spawn_close_pid (locate_pointer_pid); locate_pointer_spawned = FALSE; } } void MouseManager::SetMouseWheelSpeed (int speed) { if(speed <= 0 ) return; GPid pid; QDir dir; QString FilePath = dir.homePath() + "/.imwheelrc"; QFile file; int delay = 240000 / speed; QString date = QString("\".*\"\n" "Control_L, Up, Control_L|Button4\n" "Control_R, Up, Control_R|Button4\n" "Control_L, Down, Control_L|Button5\n" "Control_R, Down, Control_R|Button5\n" "Shift_L, Up, Shift_L|Button4\n" "Shift_R, Up, Shift_R|Button4\n" "Shift_L, Down, Shift_L|Button5\n" "Shift_R, Down, Shift_R|Button5\n" "None, Up, Button4, %1, 0, %2\n" "None, Down, Button5, %3, 0, %4\n" "None, Thumb1, Alt_L|Left\n" "None, Thumb2, Alt_L|Right") .arg(speed).arg(delay).arg(speed).arg(delay); file.setFileName(FilePath); if(file.open(QIODevice::WriteOnly | QIODevice::Text)){ file.write(date.toLatin1().data()); } GError *error = NULL; char **args; int argc; // if (imwheelSpawned){ // QProcess::execute("killall imwheel"); // imwheelSpawned = false; // } QString str = "/usr/bin/imwheel -k"; if( g_shell_parse_argv (str.toLatin1().data(), &argc, &args, NULL)){ g_spawn_async (g_get_home_dir (), args, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &pid, &error); imwheelSpawned = (error == NULL); } file.close(); g_strfreev (args); } void MouseManager::MouseCallback (QString keys) { if (keys.compare(QString::fromLocal8Bit(KEY_LEFT_HANDED))==0){ bool mouse_left_handed = settings_mouse->get(keys).toBool(); bool touchpad_left_handed = GetTouchpadHandedness (mouse_left_handed); SetLeftHandedAll (mouse_left_handed, touchpad_left_handed); USD_LOG(LOG_DEBUG,"..............."); SetTapToClickAll (); } else if ((keys.compare(QString::fromLocal8Bit(KEY_MOTION_ACCELERATION))==0) || (keys.compare(QString::fromLocal8Bit(KEY_MOTION_THRESHOLD))==0) || (keys.compare(QString::fromLocal8Bit(KEY_MOUSE_ACCEL)) == 0)){ SetMotionAll (); } else if (keys.compare(QString::fromLocal8Bit(KEY_MIDDLE_BUTTON_EMULATION))==0){ SetMiddleButtonAll (settings_mouse->get(keys).toBool()); } else if (keys.compare(QString::fromLocal8Bit(KEY_MOUSE_LOCATE_POINTER))==0){ SetLocatePointer (settings_mouse->get(keys).toBool()); } else if(keys.compare(QString::fromLocal8Bit(KEY_MOUSE_WHEEL_SPEED)) == 0 ) { SetMouseWheelSpeed (settings_mouse->get(keys).toInt()); }else{ USD_LOG(LOG_DEBUG,"keys:is skip..k%s", keys.toLatin1().data()); } } gboolean have_program_in_path (const char *name) { char *path; bool result; path = g_find_program_in_path (name); result = (path != NULL); g_free (path); return result; } void MouseManager::SetDisableWTypingSynaptics (bool state) { if (state && touchpad_is_present ()) { GError *error = NULL; char **args; int argc; QString cmd = "syndaemon -i 0.3 -K -R"; if (syndaemon_spawned) { kill (syndaemon_pid, SIGHUP); g_spawn_close_pid (syndaemon_pid); syndaemon_spawned = FALSE; USD_LOG(LOG_DEBUG,"stop syndaemon"); } if (!have_program_in_path ("syndaemon")) { return; } if (g_shell_parse_argv (cmd.toLatin1().data(), &argc, &args, NULL)) { g_spawn_async (g_get_home_dir (), args, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &syndaemon_pid, &error); syndaemon_spawned = (error == NULL); } USD_LOG(LOG_DEBUG,"start syndaemon(%d)", syndaemon_pid); if (error) { settings_touchpad->set(KEY_TOUCHPAD_DISABLE_W_TYPING,false); USD_LOG(LOG_ERR,"find error %s",error->message); g_error_free (error); } g_strfreev (args); } else if (syndaemon_spawned) { kill (syndaemon_pid, SIGHUP); g_spawn_close_pid (syndaemon_pid); syndaemon_spawned = FALSE; } } void touchpad_set_bool (XDeviceInfo *device_info, const char *property_name, int property_index, bool enabled) { XDevice *device; device = device_is_touchpad (device_info); if (device == NULL) { return; } property_set_bool (device_info, device, property_name, property_index, enabled); try { XCloseDevice (QX11Info::display(), device); } catch (int x) { qWarning("%s:error",__func__); } } void MouseManager::SetDisableWTypingLibinput (bool state) { XDeviceInfo *device_info = nullptr; int n_devices; int i; /* This is only called once for synaptics but for libinput * we need to loop through the list of devices */ device_info = XListInputDevices (QX11Info::display(), &n_devices); if(!device_info){ qWarning("SetDisableWTypingLibinput: device_info is null"); return; } for (i = 0; i < n_devices; i++) { touchpad_set_bool (&device_info[i], "libinput Disable While Typing Enabled", 0, state); } if (device_info != NULL) XFreeDeviceList (device_info); } void MouseManager::SetDisableWTyping (bool state) { if (property_from_name ("Synaptics Off")) SetDisableWTypingSynaptics (state); if (property_from_name ("libinput Disable While Typing Enabled")) SetDisableWTypingLibinput (state); } static void set_tap_to_click_libinput (XDeviceInfo *device_info, bool state) { touchpad_set_bool (device_info, "libinput Tapping Enabled", 0, state); } static void set_tap_to_click(XDeviceInfo *device_info, bool state, bool left_handed, int one_finger_tap, int two_finger_tap, int three_finger_tap) { if (query_device_had_property(device_info,"Synaptics Tap Action")) { set_tap_to_click_synaptics (device_info, state, 0, one_finger_tap, two_finger_tap, three_finger_tap); USD_LOG_SHOW_PARAM1(left_handed); USD_LOG(LOG_DEBUG,"device name:%s",device_info->name); } if (property_from_name ("libinput Tapping Enabled")) set_tap_to_click_libinput (device_info, state); } void MouseManager::SetTapToClickAll () { int numdevices, i; XDeviceInfo *devicelist = XListInputDevices (QX11Info::display(), &numdevices); if (devicelist == NULL) return; bool state = settings_touchpad->get(KEY_TOUCHPAD_TAP_TO_CLICK).toBool(); bool left_handed = GetTouchpadHandedness (settings_mouse->get(KEY_LEFT_HANDED).toBool()); int one_finger_tap = settings_touchpad->get(KEY_TOUCHPAD_ONE_FINGER_TAP).toInt(); int two_finger_tap = settings_touchpad->get(KEY_TOUCHPAD_TWO_FINGER_TAP).toInt(); int three_finger_tap = settings_touchpad->get(KEY_TOUCHPAD_THREE_FINGER_TAP).toInt(); for (i = 0; i < numdevices; i++) { set_tap_to_click(&devicelist[i], state, left_handed, one_finger_tap, two_finger_tap, three_finger_tap); } XFreeDeviceList (devicelist); } static void set_scrolling_synaptics (XDeviceInfo *device_info, QGSettings *settings) { touchpad_set_bool (device_info, "Synaptics Edge Scrolling", 0, settings->get(KEY_VERT_EDGE_SCROLL).toBool()); touchpad_set_bool (device_info, "Synaptics Edge Scrolling", 1, settings->get(KEY_HORIZ_EDGE_SCROLL).toBool()); touchpad_set_bool (device_info, "Synaptics Two-Finger Scrolling", 0, settings->get(KEY_VERT_TWO_FINGER_SCROLL).toBool()); touchpad_set_bool (device_info, "Synaptics Two-Finger Scrolling", 1, settings->get(KEY_HORIZ_TWO_FINGER_SCROLL).toBool()); } static void set_scrolling_libinput (XDeviceInfo *device_info, QGSettings *settings) { XDevice *device; int format, rc; unsigned long nitems, bytes_after; unsigned char *data; Atom prop, type; bool want_edge, want_2fg; bool want_horiz; //Display *display = QX11Info::display(); Display * display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); prop = property_from_name ("libinput Scroll Method Enabled"); if (!prop) return; device = device_is_touchpad (device_info); if (device == NULL) { return; } want_2fg = settings->get(KEY_VERT_TWO_FINGER_SCROLL).toBool(); want_edge = settings->get(KEY_VERT_EDGE_SCROLL).toBool(); /* libinput only allows for one scroll method at a time. * If both are set, pick 2fg scrolling. */ if (want_2fg) want_edge = false; USD_LOG(LOG_DEBUG,"setting scroll method on %s", device_info->name); try { rc = XGetDeviceProperty (display, device, prop, 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 3) { data[0] = want_2fg; data[1] = want_edge; XChangeDeviceProperty (display, device, prop, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (rc == Success) XFree (data); XCloseDevice (display, device); } catch (int x) { USD_LOG(LOG_DEBUG,"Error in setting scroll method on \"%s\"", device_info->name); } /* Horizontal scrolling is handled by xf86-input-libinput and * there's only one bool. Pick the one matching the scroll method * we picked above. */ if (want_2fg) want_horiz = settings->get(KEY_HORIZ_TWO_FINGER_SCROLL).toBool(); else if (want_edge) want_horiz = settings->get(KEY_HORIZ_EDGE_SCROLL).toBool(); else return; touchpad_set_bool (device_info, "libinput Horizontal Scroll Enabled", 0, want_horiz); } static void set_scrolling (XDeviceInfo *device_info, QGSettings *settings) { if (property_from_name ("Synaptics Edge Scrolling")) set_scrolling_synaptics (device_info, settings); if (property_from_name ("libinput Scroll Method Enabled")) set_scrolling_libinput (device_info, settings); } void SetScrollingAll (QGSettings *settings) { int numdevices, i; XDeviceInfo *devicelist = XListInputDevices (QX11Info::display(), &numdevices); if (devicelist == NULL) return; for (i = 0; i < numdevices; i++) { set_scrolling (&devicelist[i], settings); } XFreeDeviceList (devicelist); } void set_natural_scroll_synaptics (XDeviceInfo *device_info, bool natural_scroll) { XDevice *device; int format, rc; unsigned long nitems, bytes_after; unsigned char* data; long *ptr; Atom prop, type; Display * display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); // Display *display = QX11Info::display(); prop = property_from_name ("Synaptics Scrolling Distance"); if (!prop) return; device = device_is_touchpad (device_info); if (device == NULL) { return; } qDebug ("Trying to set %s for \"%s\"", natural_scroll ? "natural (reverse) scroll" : "normal scroll", device_info->name); try { rc = XGetDeviceProperty (display , device, prop, 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (rc == Success && type == XA_INTEGER && format == 32 && nitems >= 2) { ptr = (glong *) data; if (natural_scroll) { ptr[0] = -abs(ptr[0]); ptr[1] = -abs(ptr[1]); } else { ptr[0] = abs(ptr[0]); ptr[1] = abs(ptr[1]); } XChangeDeviceProperty (display, device, prop, XA_INTEGER, 32, PropModeReplace, data, nitems); } if (rc == Success) XFree (data); XCloseDevice (display, device); } catch (int x) { qWarning("Error in setting natural scroll on \"%s\"", device_info->name); } } void set_natural_scroll_libinput (XDeviceInfo *device_info, bool natural_scroll) { USD_LOG (LOG_DEBUG,"Trying to set %s for \"%s\"", natural_scroll ? "natural (reverse) scroll" : "normal scroll", device_info->name); touchpad_set_bool (device_info, "libinput Natural Scrolling Enabled", 0, natural_scroll); } void set_natural_scroll (XDeviceInfo *device_info, bool natural_scroll) { if (property_from_name ("Synaptics Scrolling Distance")) set_natural_scroll_synaptics (device_info, natural_scroll); if (property_from_name ("libinput Natural Scrolling Enabled")) set_natural_scroll_libinput (device_info, natural_scroll); } void MouseManager::SetNaturalScrollAll () { int numdevices, i; XDeviceInfo *devicelist = XListInputDevices (QX11Info::display(), &numdevices); if (devicelist == NULL) return; bool natural_scroll = settings_touchpad->get(KEY_TOUCHPAD_NATURAL_SCROLL).toBool(); for (i = 0; i < numdevices; i++) { set_natural_scroll (&devicelist[i], natural_scroll); } XFreeDeviceList (devicelist); } void set_touchpad_enabled (XDeviceInfo *device_info, bool state) { Display* display = gdk_x11_get_default_xdisplay (); XDevice * device; device = device_is_touchpad (device_info); if (device == NULL) { return; } int realformat; unsigned long nitems, bytes_after; unsigned char *data; Atom realtype, prop; prop = XInternAtom (display, "Device Enabled", False); if (!prop) { return; } if (XGetDeviceProperty (display, device, prop, 0, 1, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data) == Success) { if (nitems == 1){ data[0] = state ? 1 : 0; XChangeDeviceProperty(display, device, prop, XA_INTEGER, realformat, PropModeReplace, data, nitems); } XFree(data); } XCloseDevice (display, device); } void SetTouchpadEnabledAll (bool state) { int numdevices, i; XDeviceInfo *devicelist = XListInputDevices ( QX11Info::display(), &numdevices); if (devicelist == NULL) return; for (i = 0; i < numdevices; i++) { set_touchpad_enabled (&devicelist[i], state); } XFreeDeviceList (devicelist); } bool SetDisbleTouchpad(XDeviceInfo *device_info, QGSettings *settings) { QString name; bool state; name = device_info->name; bool PReceiver = name.contains("Receiver", Qt::CaseInsensitive); bool PWireless = name.contains("Wireless", Qt::CaseInsensitive); bool Pmouse = name.contains("Mouse", Qt::CaseInsensitive); bool Pusb = name.contains("USB", Qt::CaseInsensitive); if(Pmouse && ( PWireless || PReceiver || Pusb )) { state = settings->get(KEY_TOUCHPAD_DISBLE_O_E_MOUSE).toBool(); if(state){//如果开启插入鼠标禁用触摸板,则直接修改触摸板状态 SetTouchpadEnabledAll(!state); return true; } else {//如果没有开启插入鼠标禁用触摸板,则根据触摸板总开关的状态,设置触摸板的enable状态 SetTouchpadEnabledAll(settings->get(KEY_TOUCHPAD_ENABLED).toBool()); } } return false; } bool checkMouseExists() { int numdevices, i; XDeviceInfo *devicelist = XListInputDevices (QX11Info::display(), &numdevices); if (devicelist == NULL){ return false; } for (i = 0; i < numdevices; i++) { QString name; name = devicelist[i].name; bool PReceiver = name.contains("Receiver", Qt::CaseInsensitive); bool PWireless = name.contains("Wireless", Qt::CaseInsensitive); bool Pmouse = name.contains("Mouse", Qt::CaseInsensitive); bool Pusb = name.contains("USB", Qt::CaseInsensitive); if(Pmouse && ( PWireless || PReceiver || Pusb )) { return true; } } XFreeDeviceList (devicelist); return false; } // while remove mouse void SetPlugRemoveMouseEnableTouchpad(QGSettings *settings) { if(UsdBaseClass::isTablet()){ if(settings->get(KEY_TOUCHPAD_ENABLED).toBool()) { SetTouchpadEnabledAll(settings->get(KEY_TOUCHPAD_ENABLED).toBool()); } } else { if(!checkMouseExists()) { SetTouchpadEnabledAll(settings->get(KEY_TOUCHPAD_ENABLED).toBool()); } } } void SetPlugMouseDisbleTouchpad(QGSettings *settings) { int numdevices, i; XDeviceInfo *devicelist = XListInputDevices (QX11Info::display(), &numdevices); if (devicelist == NULL) { return; } for (i = 0; i < numdevices; i++) { if(SetDisbleTouchpad (&devicelist[i], settings)) { break; } } XFreeDeviceList (devicelist); } void SetTouchpadDoubleClick(XDeviceInfo *device_info, bool state) { XDevice *device; int format, rc; unsigned long nitems, bytes_after; unsigned char* data; Atom prop, type; Display * display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); // Display *display = gdk_x11_get_default_xdisplay ();//QX11Info::display(); prop = property_from_name ("Synaptics Gestures"); if (!prop) return; device = device_is_touchpad (device_info); if (device == NULL) { return; } qDebug ("Trying to set for \"%s\"", device_info->name); try { rc = XGetDeviceProperty (display , device, prop, 0, 1, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 1) { if(state) data[0]=1; else data[0]=0; XChangeDeviceProperty (display, device, prop, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (rc == Success) XFree (data); XCloseDevice (display, device); } catch (int x) { qWarning("Error in setting natural scroll on \"%s\"", device_info->name); } } void SetTouchpadDoubleClickAll(bool state) { int numdevices, i; XDeviceInfo *devicelist = XListInputDevices (QX11Info::display(), &numdevices); if (devicelist == NULL) return; for (i = 0; i < numdevices; i++) { SetTouchpadDoubleClick (&devicelist[i], state); } XFreeDeviceList (devicelist); } //设置关闭右下角菜单 void MouseManager::SetBottomRightClickMenu(XDeviceInfo *device_info, bool state) { XDevice *device; int format, rc; unsigned long nitems, bytes_after; unsigned char* data; long *ptr; Atom prop, type; Display * display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); // Display *display = gdk_x11_get_default_xdisplay ();//QX11Info::display(); prop = property_from_name ("Synaptics Soft Button Areas"); if (!prop) return; device = device_is_touchpad (device_info); if (device == NULL) { return; } qDebug ("Trying to set for \"%s\"", device_info->name); try { rc = XGetDeviceProperty (display , device, prop, 0, 8, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (rc == Success && type == XA_INTEGER && format == 32 && nitems >= 3) { ptr = (long *)data; if(ptr[0] != 0){ mAreaLeft = ptr[0]; mAreaTop = ptr[2]; } if (state) { ptr[0] = mAreaLeft; ptr[2] = mAreaTop; } else { ptr[0] = 0; ptr[2] = 0; } XChangeDeviceProperty (display, device, prop, XA_INTEGER, 32, PropModeReplace, data, nitems); } if (rc == Success) XFree (data); XCloseDevice (display, device); } catch (int x) { qWarning("Error in setting natural scroll on \"%s\"", device_info->name); } } void MouseManager::SetBottomRightConrnerClickMenu(bool state) { int numdevices, i; XDeviceInfo *devicelist = XListInputDevices (QX11Info::display(), &numdevices); if (devicelist == NULL) return; for (i = 0; i < numdevices; i++) { SetBottomRightClickMenu(&devicelist[i], state); } XFreeDeviceList (devicelist); } void MouseManager::TouchpadCallback (QString keys) { if (keys.compare(QString::fromLocal8Bit(KEY_TOUCHPAD_DISABLE_W_TYPING))==0) { SetDisableWTyping (settings_touchpad->get(keys).toBool()); //设置打字时禁用触摸板 } else if (keys.compare(QString::fromLocal8Bit(KEY_LEFT_HANDED))== 0) { bool mouse_left_handed = settings_mouse->get(keys).toBool(); bool touchpad_left_handed = GetTouchpadHandedness (mouse_left_handed); SetLeftHandedAll (mouse_left_handed, touchpad_left_handed); //设置左右手 } else if ((keys.compare(QString::fromLocal8Bit(KEY_TOUCHPAD_TAP_TO_CLICK)) == 0) || (keys.compare(QString::fromLocal8Bit(KEY_TOUCHPAD_ONE_FINGER_TAP)) == 0) || (keys.compare(QString::fromLocal8Bit(KEY_TOUCHPAD_TWO_FINGER_TAP)) == 0) || (keys.compare(QString::fromLocal8Bit(KEY_TOUCHPAD_THREE_FINGER_TAP))== 0)) { SetTapToClickAll (); //设置多指手势 } else if ((keys.compare(QString::fromLocal8Bit(KEY_VERT_EDGE_SCROLL)) == 0) || (keys.compare(QString::fromLocal8Bit(KEY_HORIZ_EDGE_SCROLL)) == 0) || (keys.compare(QString::fromLocal8Bit(KEY_VERT_TWO_FINGER_SCROLL)) == 0) || (keys.compare(QString::fromLocal8Bit(KEY_HORIZ_TWO_FINGER_SCROLL)) == 0)) { SetScrollingAll (settings_touchpad); //设置滚动 } else if (keys.compare(QString::fromLocal8Bit(KEY_TOUCHPAD_NATURAL_SCROLL)) == 0) { SetNaturalScrollAll (); //设置上移下滚或上移上滚 USD_LOG(LOG_DEBUG,"set %s",KEY_TOUCHPAD_NATURAL_SCROLL); } else if (keys.compare(QString::fromLocal8Bit(KEY_TOUCHPAD_ENABLED)) == 0) { SetTouchpadEnabledAll (settings_touchpad->get(keys).toBool());//设置触摸板开关 } else if ((keys.compare((KEY_MOTION_ACCELERATION)) == 0) || (keys.compare((KEY_MOTION_THRESHOLD)) == 0)) { SetMotionAll (); //设置鼠标速度 }else if (0 == QString::compare(keys, QString(KEY_MOTION_ACCELERATION), Qt::CaseInsensitive)|| 0 == QString::compare(keys, QString(KEY_MOTION_THRESHOLD), Qt::CaseInsensitive)){ SetMotionAll (); //设置鼠标速度 }else if (keys == "motion-acceleration" || keys==KEY_MOTION_THRESHOLD){ }else if (keys.compare(QString::fromLocal8Bit(KEY_TOUCHPAD_DISBLE_O_E_MOUSE)) == 0) { SetPlugMouseDisbleTouchpad(settings_touchpad); //设置插入鼠标时禁用触摸板 } else if (keys.compare(QString::fromLocal8Bit(KEY_TOUCHPAD_DOUBLE_CLICK_DRAG)) == 0){ SetTouchpadDoubleClickAll(settings_touchpad->get(KEY_TOUCHPAD_DOUBLE_CLICK_DRAG).toBool());//设置轻点击两次拖动打开关闭 } else if (keys.compare(QString::fromLocal8Bit(KEY_TOUCHPAD_BOTTOM_R_C_CLICK_M)) == 0){ SetBottomRightConrnerClickMenu(settings_touchpad->get(KEY_TOUCHPAD_BOTTOM_R_C_CLICK_M).toBool());//打开关闭右下角点击弹出菜单 } else if (keys.compare(QString::fromLocal8Bit(KEY_TOUCHPAD_MOUSE_SENSITVITY)) == 0){ } else { USD_LOG(LOG_DEBUG,"keys:is skip..k%s", keys.toLatin1().data(),keys.toLatin1().data()); } } void MouseManager::SetMouseSettings () { bool mouse_left_handed = settings_mouse->get(KEY_LEFT_HANDED).toBool(); bool touchpad_left_handed = GetTouchpadHandedness (mouse_left_handed); SetLeftHandedAll (mouse_left_handed, touchpad_left_handed); SetMotionAll (); SetMiddleButtonAll (settings_mouse->get(KEY_MIDDLE_BUTTON_EMULATION).toBool()); SetMouseWheelSpeed (settings_mouse->get(KEY_MOUSE_WHEEL_SPEED).toInt()); SetPlugMouseDisbleTouchpad(settings_touchpad); } void MouseManager::SetTouchSettings () { SetTapToClickAll (); SetScrollingAll (settings_touchpad); SetNaturalScrollAll (); SetTouchpadEnabledAll (settings_touchpad->get(KEY_TOUCHPAD_ENABLED).toBool()); // SetPlugMouseDisbleTouchpad(settings_touchpad); SetPlugRemoveMouseEnableTouchpad(settings_touchpad); SetTouchpadDoubleClickAll(settings_touchpad->get(KEY_TOUCHPAD_DOUBLE_CLICK_DRAG).toBool()); SetBottomRightConrnerClickMenu(settings_touchpad->get(KEY_TOUCHPAD_BOTTOM_R_C_CLICK_M).toBool()); } GdkFilterReturn devicepresence_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data) { XEvent *xev = (XEvent *) xevent; XEventClass class_presence; int xi_presence; MouseManager * manager = (MouseManager *) data; DevicePresence (gdk_x11_get_default_xdisplay (), xi_presence, class_presence); if (xev->type == xi_presence) { XDevicePresenceNotifyEvent *dpn = (XDevicePresenceNotifyEvent *) xev; if (dpn->devchange == DeviceEnabled) { USD_LOG(LOG_DEBUG,"new add deviced ID : %d",dpn->deviceid); manager->SetMouseSettings (); } else if(dpn->devchange == DeviceRemoved) { manager->SetTouchSettings(); } } return GDK_FILTER_CONTINUE; } void MouseManager::SetDevicepresenceHandler () { Display *display; XEventClass class_presence; int xi_presence; display = QX11Info::display(); gdk_x11_display_error_trap_push (gdk_display_get_default()); DevicePresence (display, xi_presence, class_presence); XSelectExtensionEvent (display, RootWindow (display, DefaultScreen (display)), &class_presence, 1); gdk_display_flush (gdk_display_get_default()); if (!gdk_x11_display_error_trap_pop (gdk_display_get_default())) gdk_window_add_filter (NULL, devicepresence_filter,this); } void MouseManager::MouseManagerIdleCb() { time->stop(); // connect(settings_mouse, &QGSettings::changed, this, &MouseManager::MouseCallback); // connect(settings_touchpad, &QGSettings::changed, this, &MouseManager::TouchpadCallback); QObject::connect(settings_mouse,SIGNAL(changed(QString)), this,SLOT(MouseCallback(QString))); QObject::connect(settings_touchpad,SIGNAL(changed(QString)),this,SLOT(TouchpadCallback(QString))); syndaemon_spawned = FALSE; SetDevicepresenceHandler (); SetMouseSettings (); SetTouchSettings (); SetDisableWTyping (settings_touchpad->get(KEY_TOUCHPAD_DISABLE_W_TYPING).toBool()); SetLocatePointer (settings_mouse->get(KEY_MOUSE_LOCATE_POINTER).toBool()); if(checkMouseExists()){ SetPlugMouseDisbleTouchpad(settings_touchpad); } else { SetPlugRemoveMouseEnableTouchpad(settings_touchpad); } } ukui-settings-daemon/plugins/mouse/01-touchpad-state-onmouse.rules0000644000175000017500000000036614205117202024264 0ustar fengfeng# Set touchpad state dependent on mouse availability. SUBSYSTEM=="input", KERNEL=="mouse[0-9]*", ACTION=="add", RUN+="/usr/bin/touchpad-state --off" SUBSYSTEM=="input", KERNEL=="mouse[0-9]*", ACTION=="remove", RUN+="/usr/bin/touchpad-state --on" ukui-settings-daemon/plugins/mouse/mouse.pro0000755000175000017500000000167014205117202020236 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-04-10T09:30:00 # #------------------------------------------------- QT += gui QT += core widgets x11extras TARGET = mouse TEMPLATE = lib DEFINES += MOUSE_LIBRARY CONFIG += c++11 no_keywords link_pkgconfig plugin CONFIG += app_bunale DEFINES += QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"mouse\\\" include($$PWD/../../common/common.pri) PKGCONFIG += \ gtk+-3.0 \ glib-2.0 \ gsettings-qt \ xi INCLUDEPATH += \ -I ukui-settings-daemon/ SOURCES += \ mouse-manager.cpp \ mouse-plugin.cpp \ HEADERS += \ mouse-manager.h \ mouse-plugin.h \ mouse_lib.path = $${PLUGIN_INSTALL_DIRS} mouse_lib.files = $$OUT_PWD/libmouse.so touchpad.path = /usr/bin/ touchpad.files = $$PWD/touchpad-state udev.path = /lib/udev/rules.d/ udev.files = $$PWD/01-touchpad-state-onmouse.rules INSTALLS += mouse_lib touchpad udev ukui-settings-daemon/plugins/mouse/mouse-manager.h0000755000175000017500000000762514205117202021303 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MOUSEMANAGER_H #define MOUSEMANAGER_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class MouseManager : public QObject { Q_OBJECT private: MouseManager()=delete; MouseManager(MouseManager&)=delete; MouseManager&operator=(const MouseManager&)=delete; MouseManager(QObject *parent = nullptr); public: ~MouseManager(); static MouseManager * MouseManagerNew(); bool MouseManagerStart(); void MouseManagerStop(); public Q_SLOTS: void MouseManagerIdleCb(); void MouseCallback(QString); void TouchpadCallback(QString); public: void SetLeftHandedAll (bool mouse_left_handed, bool touchpad_left_handed); void SetLeftHanded (XDeviceInfo *device_info, bool mouse_left_handed, bool touchpad_left_handed); void SetLeftHandedLegacyDriver (XDeviceInfo *device_info, bool mouse_left_handed, bool touchpad_left_handed); void SetMotionAll (); void SetMotion (XDeviceInfo *device_info); void SetMotionLibinput (XDeviceInfo *device_info); void SetMotionLegacyDriver(XDeviceInfo *device_info); bool GetTouchpadHandedness (bool mouse_left_handed); void SetMouseAccel(XDeviceInfo *device_info); void SetTouchpadStateAll(int num, bool state); void SetTouchpadMotionAccel(XDeviceInfo *device_info); void SetBottomRightClickMenu (XDeviceInfo *device_info, bool state); void SetBottomRightConrnerClickMenu(bool state); void SetDisableWTyping (bool state); void SetDisableWTypingSynaptics (bool state); void SetDisableWTypingLibinput (bool state); void SetMiddleButtonAll (bool middle_button); void SetMiddleButton (XDeviceInfo *device_info, bool middle_button); void SetLocatePointer (bool state); void SetTapToClickAll (); void SetNaturalScrollAll (); void SetDevicepresenceHandler (); void SetMouseWheelSpeed (int speed); void SetMouseSettings(); void SetTouchSettings(); private: friend GdkFilterReturn devicepresence_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data); private: unsigned long mAreaLeft; unsigned long mAreaTop; QTimer * time; QGSettings *settings_mouse; QGSettings *settings_touchpad; #if 0 /* FIXME need to fork (?) mousetweaks for this to work */ gboolean mousetweaks_daemon_running; #endif gboolean syndaemon_spawned; GPid syndaemon_pid; gboolean locate_pointer_spawned; GPid locate_pointer_pid; bool imwheelSpawned; static MouseManager *mMouseManager; }; #endif // MOUSEMANAGER_H ukui-settings-daemon/plugins/mouse/mouse-plugin.cpp0000755000175000017500000000353414205117202021515 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mouse-plugin.h" #include "clib-syslog.h" PluginInterface * MousePlugin::mInstance = nullptr; MouseManager * MousePlugin::UsdMouseManager = nullptr; MousePlugin::MousePlugin() { USD_LOG(LOG_DEBUG,"MousePlugin initializing!"); if (nullptr == UsdMouseManager) UsdMouseManager = MouseManager::MouseManagerNew(); } MousePlugin::~MousePlugin() { if (UsdMouseManager){ delete UsdMouseManager; UsdMouseManager = nullptr; } } void MousePlugin::activate() { bool res; USD_LOG (LOG_DEBUG, "Activating %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); res = UsdMouseManager->MouseManagerStart(); if(!res){ USD_LOG(LOG_ERR,"Unable to start Mouse manager!"); } } PluginInterface * MousePlugin::getInstance() { if (nullptr == mInstance){ mInstance = new MousePlugin(); } return mInstance; } void MousePlugin::deactivate() { USD_LOG(LOG_DEBUG,"Deactivating Mouse Plugin"); UsdMouseManager->MouseManagerStop(); } PluginInterface *createSettingsPlugin() { return MousePlugin::getInstance(); } ukui-settings-daemon/plugins/mouse/touchpad-state0000755000175000017500000000017314205117202021231 0ustar fengfeng#!/bin/bash # Set the touchpad state. #disable this script cuz had root permission # Usage # vim: set ft=sh ts=2 sw=2 et: ukui-settings-daemon/plugins/sharing/0000755000175000017500000000000014205117202016660 5ustar fengfengukui-settings-daemon/plugins/sharing/sharing-plugin.cpp0000644000175000017500000000341114205117202022312 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2021 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "sharing-plugin.h" SharingPlugin* SharingPlugin::mSharingPlugin = nullptr; SharingPlugin::SharingPlugin() { USD_LOG(LOG_DEBUG,"SharingPlugin initializing!"); mSharingManager = SharingManager::SharingManagerNew(); } SharingPlugin::~SharingPlugin() { USD_LOG(LOG_DEBUG,"SharingPlugin deconstructor!"); if (mSharingManager) { delete mSharingManager; } mSharingManager = nullptr; } void SharingPlugin::activate () { USD_LOG (LOG_DEBUG, "Activating %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); if(!mSharingManager->start()){ USD_LOG(LOG_DEBUG,"unable to start sharing manager"); } } void SharingPlugin::deactivate () { USD_LOG(LOG_DEBUG,"Deactivating sharing plugin!"); mSharingManager->stop(); } PluginInterface* SharingPlugin::getInstance() { if(nullptr == mSharingPlugin) mSharingPlugin = new SharingPlugin(); return mSharingPlugin; } PluginInterface* createSettingsPlugin() { return SharingPlugin::getInstance(); } ukui-settings-daemon/plugins/sharing/sharing-adaptor.h0000644000175000017500000000330214205117202022112 0ustar fengfeng/* * This file was generated by qdbusxml2cpp version 0.8 * Command line was: qdbusxml2cpp usd-sharing-manager.xml -a sharing-adaptor * * qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. * * This is an auto-generated file. * This file may have been hand-edited. Look for HAND-EDIT comments * before re-generating it. */ #ifndef SHARING-ADAPTOR_H #define SHARING-ADAPTOR_H #include #include QT_BEGIN_NAMESPACE class QByteArray; template class QList; template class QMap; class QString; class QStringList; class QVariant; QT_END_NAMESPACE /* * Adaptor class for interface org.ukui.SettingsDaemon.Sharing */ class SharingAdaptor: public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.ukui.SettingsDaemon.Sharing") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") public: SharingAdaptor(QObject *parent); virtual ~SharingAdaptor(); public: // PROPERTIES public Q_SLOTS: // METHODS void DisableService(const QString &serviceName); void EnableService(const QString &serviceName); Q_SIGNALS: // SIGNALS void serviceChange(const QString &state, const QString &serviceName); }; #endif ukui-settings-daemon/plugins/sharing/sharing-manager.cpp0000644000175000017500000001342214205117202022431 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2021 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "sharing-manager.h" #include "clib-syslog.h" #define SHATINGS_SCHEMA "org.ukui.SettingsDaemon.plugins.sharing" #define KEY_SERVICE_NAME "service-name" #define USD_DBUS_NAME "org.ukui.SettingsDaemon" #define USD_DBUS_PATH "/org/ukui/SettingsDaemon" #define USD_DBUS_BASE_INTERFACE "org.ukui.SettingsDaemon" #define RYGEL_BUS_NAME "org.ukui.Rygel1" #define RYGEL_OBJECT_PATH "/org/ukui/Rygel1" #define RYGEL_INTERFACE_NAME "org.ukui.Rygel1" #define SYSTEM_DBUS_NAME "org.freedesktop.systemd1" #define SYSTEM_DBUS_PATH "/org/freedesktop/systemd1" #define SYSTEM_DBUS_INTER "org.freedesktop.systemd1.Manager" #define USD_SHARING_DBUS_NAME USD_DBUS_NAME ".Sharing" #define USD_SHARING_DBUS_PATH USD_DBUS_PATH "/Sharing" SharingManager* SharingManager::mSharingManager = nullptr; SharingManager::SharingManager() { mDbus = new sharingDbus(this); new SharingAdaptor(mDbus); QDBusConnection sessionBus = QDBusConnection::sessionBus(); if(sessionBus.registerService(USD_SHARING_DBUS_NAME)){ sessionBus.registerObject(USD_SHARING_DBUS_PATH, mDbus, QDBusConnection::ExportAllContents); } connect(mDbus, &sharingDbus::serviceChange, this, &SharingManager::sharingManagerServiceChange); } SharingManager::~SharingManager() { if(mSharingManager) delete mSharingManager; } SharingManager *SharingManager::SharingManagerNew() { if(nullptr == mSharingManager) mSharingManager = new SharingManager(); return mSharingManager; } bool SharingManager::sharingManagerStartService(QString service) { bool serviceState; USD_LOG(LOG_DEBUG, "About to start %s", service.toLatin1().data()); serviceState = sharingManagerHandleService("StartUnit", service); return serviceState; } bool SharingManager::sharingManagerStopService(QString service) { bool serviceState; USD_LOG(LOG_DEBUG, "About to stop %s", service.toLatin1().data()); serviceState = sharingManagerHandleService("StopUnit", service); return serviceState; } bool SharingManager::sharingManagerHandleService(QString method, QString service ) { QString service_file = QString("%1.service").arg(service); QDBusMessage message = QDBusMessage::createMethodCall(SYSTEM_DBUS_NAME, SYSTEM_DBUS_PATH, SYSTEM_DBUS_INTER, method); message <** ignore_paths,QString serviceName,bool state) { bool found=(*ignore_paths)->contains(serviceName.toLatin1().data()); if(state && found==false){ (*ignore_paths)->push_front(serviceName.toLatin1().data()); return true; } if(!state && found==true){ (*ignore_paths)->removeOne(serviceName.toLatin1().data()); return true; } return false; } void SharingManager::updateSaveService(bool state, QString serviceName) { QStringList service_list; QStringList serviceStr; QList* service; bool updated; QList::iterator l; service =new QList(); //get contents from "ignore-paths" key if (!settings->get(KEY_SERVICE_NAME).toStringList().isEmpty()) service_list.append(settings->get(KEY_SERVICE_NAME).toStringList()); for(auto str: service_list){ if(!str.isEmpty()) service->push_back(str); } updated = update_ignore_paths(&service, serviceName, state); if(updated){ for(l = service->begin(); l != service->end(); ++l){ serviceStr.append(*l); } //set latest contents to gsettings "ignore-paths" key settings->set(KEY_SERVICE_NAME, QVariant::fromValue(serviceStr)); } //free QList Memory if(service){ service->clear(); } } void SharingManager::sharingManagerServiceChange(QString state, QString service) { bool serviceState; if(state.compare("enable") == 0){ serviceState = sharingManagerStartService(service); if (serviceState) updateSaveService(true, service); } else if (state.compare("disable") == 0) { serviceState = sharingManagerStopService(service); if (serviceState) updateSaveService(false, service); } } bool SharingManager::start() { USD_LOG(LOG_DEBUG,"Starting sharing manager!"); settings = new QGSettings(SHATINGS_SCHEMA); QStringList serviceList = settings->get(KEY_SERVICE_NAME).toStringList(); for (QString serviceName : serviceList) { sharingManagerStartService(serviceName); } return true; } void SharingManager::stop() { USD_LOG(LOG_DEBUG,"Stopping sharing manager!"); if(settings) delete settings; } ukui-settings-daemon/plugins/sharing/sharing-manager.h0000644000175000017500000000373214205117202022101 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2021 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHARING_MANAGER_H #define SHARING_MANAGER_H #include #include #include #include #include #include #include "sharing-dbus.h" #include "sharing-adaptor.h" typedef enum { USD_SHARING_STATUS_OFFLINE, USD_SHARING_STATUS_DISABLED_MOBILE_BROADBAND, USD_SHARING_STATUS_DISABLED_LOW_SECURITY, USD_SHARING_STATUS_AVAILABLE } UsdSharingStatus; class SharingManager:public QObject { Q_OBJECT public: ~SharingManager(); static SharingManager *SharingManagerNew(); bool start(); void stop(); public: bool sharingManagerStartService(QString service); bool sharingManagerStopService(QString service); bool sharingManagerHandleService(QString method, QString service); void sharingManagerServiceChange(QString state, QString service); void updateSaveService(bool state, QString serviceName); private: SharingManager(); SharingManager(const SharingManager&) = delete; private: static SharingManager *mSharingManager; QGSettings *settings; UsdSharingStatus sharing_status; sharingDbus *mDbus; }; #endif // SHARING_MANAGER_H ukui-settings-daemon/plugins/sharing/sharing-adaptor.cpp0000644000175000017500000000230514205117202022447 0ustar fengfeng/* * This file was generated by qdbusxml2cpp version 0.8 * Command line was: qdbusxml2cpp usd-sharing-manager.xml -a sharing-adaptor * * qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. * * This is an auto-generated file. * Do not edit! All changes made to it will be lost. */ #include "sharing-adaptor.h" #include #include #include #include #include #include #include /* * Implementation of adaptor class SharingAdaptor */ SharingAdaptor::SharingAdaptor(QObject *parent) : QDBusAbstractAdaptor(parent) { // constructor setAutoRelaySignals(true); } SharingAdaptor::~SharingAdaptor() { // destructor } void SharingAdaptor::DisableService(const QString &serviceName) { // handle method call org.ukui.SettingsDaemon.Sharing.DisableService QMetaObject::invokeMethod(parent(), "DisableService", Q_ARG(QString, serviceName)); } void SharingAdaptor::EnableService(const QString &serviceName) { // handle method call org.ukui.SettingsDaemon.Sharing.EnableService QMetaObject::invokeMethod(parent(), "EnableService", Q_ARG(QString, serviceName)); } ukui-settings-daemon/plugins/sharing/sharing.pro0000644000175000017500000000253714205117202021044 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2021-08-30T19:50:48 # #------------------------------------------------- QT += gui dbus TARGET = sharing TEMPLATE = lib DEFINES += SHARING_LIBRARY CONFIG += c++11 plugin link_pkgconfig CONFIG -= app_bundle # The following define makes your compiler emit warnings if you use # any feature of Qt which has been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"sharing\\\" # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 include($$PWD/../../common/common.pri) PKGCONFIG +=\ gsettings-qt SOURCES += \ sharing-plugin.cpp \ sharing-manager.cpp \ sharing-dbus.cpp \ sharing-adaptor.cpp HEADERS += \ sharing-plugin.h \ sharing-manager.h \ sharing-dbus.h \ sharing-adaptor.h sharing_lib.path = $${PLUGIN_INSTALL_DIRS} sharing_lib.files += $$OUT_PWD/libsharing.so \ INSTALLS += sharing_lib ukui-settings-daemon/plugins/sharing/sharing-plugin.h0000644000175000017500000000255714205117202021771 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2021 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHARING_H #define SHARING_H #include "plugin-interface.h" #include "sharing-manager.h" #ifdef __cplusplus extern "C" { #endif #include "clib-syslog.h" #ifdef __cplusplus } #endif class SharingPlugin : public PluginInterface { public: ~SharingPlugin(); SharingPlugin(); static PluginInterface* getInstance(); virtual void activate (); virtual void deactivate (); protected: static SharingPlugin* mSharingPlugin; SharingManager *mSharingManager; private: QDBusInterface *mLoginInter; }; extern "C" PluginInterface* Q_DECL_EXPORT createSettingsPlugin(); #endif // SHARING_H ukui-settings-daemon/plugins/sharing/sharing-dbus.h0000644000175000017500000000231314205117202021416 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2021 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHARINGDBUS_H #define SHARINGDBUS_H #include class sharingDbus : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface","org.ukui.SettingsDaemon.Sharing") public: sharingDbus(QObject* parent=0); ~sharingDbus(); public Q_SLOTS: void EnableService(QString serviceName); void DisableService(QString serviceName); Q_SIGNALS: void serviceChange(QString state, QString serviceName); }; #endif // SHARINGDBUS_H ukui-settings-daemon/plugins/sharing/sharing-dbus.cpp0000644000175000017500000000235014205117202021752 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2021 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "sharing-dbus.h" #include #include #include sharingDbus::sharingDbus(QObject *parent) : QObject(parent) { } sharingDbus::~sharingDbus() { } void sharingDbus::EnableService(QString serviceName) { // qDebug()<<__func__< ukui-settings-daemon/plugins/clipboard/0000755000175000017500000000000014205117202017164 5ustar fengfengukui-settings-daemon/plugins/clipboard/xutils.h0000644000175000017500000000260414205117202020667 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef X_UTILS_H #define X_UTILS_H #include #ifdef __cplusplus extern "C" { #endif extern Atom XA_ATOM_PAIR; extern Atom XA_CLIPBOARD_MANAGER; extern Atom XA_CLIPBOARD; extern Atom XA_DELETE; extern Atom XA_INCR; extern Atom XA_INSERT_PROPERTY; extern Atom XA_INSERT_SELECTION; extern Atom XA_MANAGER; extern Atom XA_MULTIPLE; extern Atom XA_NULL; extern Atom XA_SAVE_TARGETS; extern Atom XA_TARGETS; extern Atom XA_TIMESTAMP; extern unsigned long SELECTION_MAX_SIZE; void init_atoms (Display *display); Time get_server_time (Display *display, Window window); #ifdef __cplusplus } #endif #endif /* X_UTILS_H */ ukui-settings-daemon/plugins/clipboard/clipboard-plugin.cpp0000644000175000017500000000335314205117202023127 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "clipboard-plugin.h" #include "clib-syslog.h" ClipboardManager* ClipboardPlugin::mManager = nullptr; PluginInterface* ClipboardPlugin::mInstance = nullptr; ClipboardPlugin::~ClipboardPlugin() { delete mManager; mManager = nullptr; } PluginInterface *ClipboardPlugin::getInstance() { if (nullptr == mInstance) { mInstance = new ClipboardPlugin(); } return mInstance; } void ClipboardPlugin::activate() { USD_LOG (LOG_DEBUG, "Activating %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); if (nullptr != mManager) mManager->managerStart(); } void ClipboardPlugin::deactivate() { if (nullptr != mManager) mManager->managerStop(); if (nullptr != mInstance) { delete mInstance; mInstance = nullptr; } } ClipboardPlugin::ClipboardPlugin() { if ((nullptr == mManager)) { mManager = new ClipboardManager(); } } PluginInterface* createSettingsPlugin() { return ClipboardPlugin::getInstance(); } ukui-settings-daemon/plugins/clipboard/xutils.c0000644000175000017500000000675614205117202020676 0ustar fengfeng/* * Copyright © 2004 Red Hat, Inc. * * 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, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Matthias Clasen, Red Hat, Inc. */ #include #include "xutils.h" Atom XA_ATOM_PAIR; Atom XA_CLIPBOARD_MANAGER; Atom XA_CLIPBOARD; Atom XA_DELETE; Atom XA_INCR; Atom XA_INSERT_PROPERTY; Atom XA_INSERT_SELECTION; Atom XA_MANAGER; Atom XA_MULTIPLE; Atom XA_NULL; Atom XA_SAVE_TARGETS; Atom XA_TARGETS; Atom XA_TIMESTAMP; unsigned long SELECTION_MAX_SIZE = 0; void init_atoms (Display *display) { unsigned long max_request_size; if (SELECTION_MAX_SIZE > 0) return; XA_ATOM_PAIR = XInternAtom (display, "ATOM_PAIR", False); XA_CLIPBOARD_MANAGER = XInternAtom (display, "CLIPBOARD_MANAGER", False); XA_CLIPBOARD = XInternAtom (display, "CLIPBOARD", False); XA_DELETE = XInternAtom (display, "DELETE", False); XA_INCR = XInternAtom (display, "INCR", False); XA_INSERT_PROPERTY = XInternAtom (display, "INSERT_PROPERTY", False); XA_INSERT_SELECTION = XInternAtom (display, "INSERT_SELECTION", False); XA_MANAGER = XInternAtom (display, "MANAGER", False); XA_MULTIPLE = XInternAtom (display, "MULTIPLE", False); XA_NULL = XInternAtom (display, "NULL", False); XA_SAVE_TARGETS = XInternAtom (display, "SAVE_TARGETS", False); XA_TARGETS = XInternAtom (display, "TARGETS", False); XA_TIMESTAMP = XInternAtom (display, "TIMESTAMP", False); max_request_size = XExtendedMaxRequestSize (display); if (max_request_size == 0) max_request_size = XMaxRequestSize (display); SELECTION_MAX_SIZE = max_request_size - 100; if (SELECTION_MAX_SIZE > 262144) SELECTION_MAX_SIZE = 262144; } typedef struct { Window window; Atom timestamp_prop_atom; } TimeStampInfo; static Bool timestamp_predicate (Display *display, XEvent *xevent, XPointer arg) { TimeStampInfo *info = (TimeStampInfo *)arg; if (xevent->type == PropertyNotify && xevent->xproperty.window == info->window && xevent->xproperty.atom == info->timestamp_prop_atom) return True; return False; } Time get_server_time (Display *display, Window window) { unsigned char c = 'a'; XEvent xevent; TimeStampInfo info; info.timestamp_prop_atom = XInternAtom (display, "_TIMESTAMP_PROP", False); info.window = window; XChangeProperty (display, window, info.timestamp_prop_atom, info.timestamp_prop_atom, 8, PropModeReplace, &c, 1); XIfEvent (display, &xevent, timestamp_predicate, (XPointer)&info); return xevent.xproperty.time; } ukui-settings-daemon/plugins/clipboard/clipboard.pro0000644000175000017500000000140014205117202021640 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-04-10T09:30:00 # #------------------------------------------------- TEMPLATE = lib TARGET = clipboard QT += gui CONFIG += no_keywords c++11 plugin link_pkgconfig CONFIG -= app_bundle DEFINES += QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"clipboard\\\" include($$PWD/../../common/common.pri) PKGCONFIG += \ gdk-3.0 SOURCES += \ $$PWD/list.c \ $$PWD/xutils.c \ $$PWD/clipboard-plugin.cpp \ $$PWD/clipboard-manager.cpp \ HEADERS += \ $$PWD/list.h \ $$PWD/xutils.h \ $$PWD/clipboard-plugin.h \ $$PWD/clipboard-manager.h clipboard_lib.path = $${PLUGIN_INSTALL_DIRS} clipboard_lib.files = $$OUT_PWD/libclipboard.so INSTALLS += clipboard_lib ukui-settings-daemon/plugins/clipboard/clipboard-manager.h0000644000175000017500000001306414205117202022710 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef CLIPBOARDMANAGER_H #define CLIPBOARDMANAGER_H #include #include "list.h" #include #include #include #include #include /* always defined to indicate that i18n is enabled */ #define ENABLE_NLS 1 /* enable profiling */ /* #undef ENABLE_PROFILING */ /* Name of default gettext domain */ #define GETTEXT_PACKAGE "ukui-settings-daemon" /* Warn on use of APIs added after GLib 2.36 */ #define GLIB_VERSION_MAX_ALLOWED GLIB_VERSION_2_36 /* Warn on use of APIs deprecated before GLib 2.36 */ #define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_36 /* Define to 1 if you have the `bind_textdomain_codeset' function. */ #define HAVE_BIND_TEXTDOMAIN_CODESET 1 /* Define to 1 if you have the Mac OS X function CFLocaleCopyCurrent in the CoreFoundation framework. */ /* #undef HAVE_CFLOCALECOPYCURRENT */ /* Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in the CoreFoundation framework. */ /* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */ /* Define to 1 if you have the `dcgettext' function. */ #define HAVE_DCGETTEXT 1 /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define if the GNU gettext() function is already present or preinstalled. */ #define HAVE_GETTEXT 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define if your file defines LC_MESSAGES. */ #define HAVE_LC_MESSAGES 1 /* Define if libcanberra-gtk3 is available */ #define HAVE_LIBCANBERRA 1 /* Define if libmatemixer is available */ #define HAVE_LIBMATEMIXER 1 /* Define if libnotify is available */ #define HAVE_LIBNOTIFY 1 /* Define to 1 if you have the header file. */ #define HAVE_LOCALE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Defined if PolicyKit support is enabled */ #define HAVE_POLKIT 1 /* Define if PulseAudio support is available */ /* #undef HAVE_PULSE */ /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_X11_EXTENSIONS_XF86MISC_H */ /* Define to 1 if you have the header file. */ #define HAVE_X11_EXTENSIONS_XKB_H 1 typedef struct { int length; int format; int refcount; Atom target; Atom type; unsigned char* data; } TargetData; typedef struct { int offset; Atom target; Atom property; Window requestor; TargetData* data; } IncrConversion; class ClipboardManager : public QThread { Q_OBJECT public: explicit ClipboardManager(QObject *parent = nullptr); ~ClipboardManager(); bool managerStart (); bool managerStop (); void run() override; private: bool mExit; Display* mDisplay; Window mWindow; Time mTimestamp; List* mContents; List* mConversions; Window mRequestor; Atom mProperty; Time mTime; friend void get_property (TargetData* tdata, ClipboardManager* manager); friend bool send_incrementally (ClipboardManager* manager, XEvent* xev); friend bool receive_incrementally (ClipboardManager* manager, XEvent* xev); friend void send_selection_notify (ClipboardManager* manager, bool success); friend void convert_clipboard_manager (ClipboardManager* manager, XEvent* xev); friend void collect_incremental (IncrConversion* rdata, ClipboardManager* manager); friend bool clipboard_manager_process_event(ClipboardManager* manager, XEvent* xev); friend void save_targets (ClipboardManager* manager, Atom* save_targets, int nitems); friend void convert_clipboard_target (IncrConversion* rdata, ClipboardManager* manager); friend void finish_selection_request (ClipboardManager* manager, XEvent* xev, bool success); friend void clipboard_manager_watch_cb(ClipboardManager* manager, Window window, bool isStart, long mask, void* cbData); }; #endif // CLIPBOARDMANAGER_H ukui-settings-daemon/plugins/clipboard/clipboard-manager.cpp0000644000175000017500000006157614205117202023256 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "clipboard-manager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "list.h" #include "xutils.h" #include "clib-syslog.h" ClipboardManager::ClipboardManager(QObject *parent) : QThread(parent) { mExit = false; mDisplay = nullptr; mContents = nullptr; mConversions = nullptr; gdk_init(NULL, NULL); GdkDisplay* display = gdk_display_get_default(); if (nullptr == display) { USD_LOG(LOG_ERR, "get GdkDisplay error"); return; } mDisplay = gdk_x11_display_get_xdisplay(display); } ClipboardManager::~ClipboardManager() { } void target_data_unref (TargetData *data) { data->refcount--; if (data->refcount == 0) { free (data->data); free (data); } } void conversion_free (IncrConversion* rdata) { if (rdata->data) { target_data_unref (rdata->data); } free (rdata); } bool ClipboardManager::managerStart() { if (nullptr == mDisplay) { return false; } start(QThread::LowestPriority); return true; } bool ClipboardManager::managerStop() { clipboard_manager_watch_cb (this, mWindow, FALSE, 0, NULL); XDestroyWindow (mDisplay, mWindow); list_foreach (mConversions, (Callback) conversion_free, NULL); list_free (mConversions); list_foreach (mContents, (Callback) target_data_unref, NULL); list_free (mContents); mExit = true; QThread::exit(0); return true; } void ClipboardManager::run() { while (!mExit) { XClientMessageEvent xev; if (nullptr == mDisplay) { return; } init_atoms (mDisplay); /* check if there is a clipboard manager running */ if (XGetSelectionOwner (mDisplay, XA_CLIPBOARD_MANAGER)) { USD_LOG(LOG_ERR, "Clipboard manager is already running."); mExit = false; return; } mContents = nullptr; mConversions = nullptr; mRequestor = None; mWindow = XCreateSimpleWindow (mDisplay, DefaultRootWindow (mDisplay), 0, 0, 10, 10, 0, WhitePixel (mDisplay, DefaultScreen (mDisplay)), WhitePixel (mDisplay, DefaultScreen (mDisplay))); clipboard_manager_watch_cb (this, mWindow, True, PropertyChangeMask, NULL); XSelectInput (mDisplay, mWindow, PropertyChangeMask); mTimestamp = get_server_time (mDisplay, mWindow); XSetSelectionOwner (mDisplay, XA_CLIPBOARD_MANAGER, mWindow, mTimestamp); /* Check to see if we managed to claim the selection. If not, we treat it as if we got it then immediately lost it */ if (XGetSelectionOwner (mDisplay, XA_CLIPBOARD_MANAGER) == mWindow) { xev.type = ClientMessage; xev.window = DefaultRootWindow (mDisplay); xev.message_type = XA_MANAGER; xev.format = 32; xev.data.l[0] = mTimestamp; xev.data.l[1] = XA_CLIPBOARD_MANAGER; xev.data.l[2] = mWindow; xev.data.l[3] = 0; /* manager specific data */ xev.data.l[4] = 0; /* manager specific data */ XSendEvent (mDisplay, DefaultRootWindow (mDisplay), False, StructureNotifyMask, (XEvent *)&xev); } else { clipboard_manager_watch_cb (this, mWindow, False, 0, NULL); /* FIXME: manager->priv->terminate (manager->priv->cb_data); */ } } } GdkFilterReturn clipboard_manager_event_filter (GdkXEvent* xevent, GdkEvent*, ClipboardManager* manager) { if (clipboard_manager_process_event (manager, (XEvent *)xevent)) { return GDK_FILTER_REMOVE; } else { return GDK_FILTER_CONTINUE; } } void clipboard_manager_watch_cb(ClipboardManager* manager, Window window, bool isStart, long, void*) { GdkWindow* gdkwin; GdkDisplay* display; display = gdk_display_get_default (); gdkwin = gdk_x11_window_lookup_for_display (display, window); if (isStart) { if (gdkwin == NULL) { gdkwin = gdk_x11_window_foreign_new_for_display (display, window); } else { g_object_ref (gdkwin); } gdk_window_add_filter (gdkwin, (GdkFilterFunc)clipboard_manager_event_filter, manager); } else { if (gdkwin == NULL) { return; } gdk_window_remove_filter (gdkwin, (GdkFilterFunc)clipboard_manager_event_filter, manager); g_object_unref (gdkwin); } } int clipboard_bytes_per_item (int format) { switch (format) { case 8: return sizeof (char); case 16: return sizeof (short); case 32: return sizeof (long); default: ; } return 0; } void get_property (TargetData* tdata, ClipboardManager* manager) { Atom type; int format; unsigned long length; unsigned long remaining; unsigned char* data; XGetWindowProperty (manager->mDisplay, manager->mWindow, tdata->target, 0, 0x1FFFFFFF, true, AnyPropertyType, &type, &format, &length, &remaining, &data); if (type == None) { manager->mContents = list_remove (manager->mContents, tdata); free (tdata); } else if (type == XA_INCR) { tdata->type = type; tdata->length = 0; XFree (data); } else { tdata->type = type; tdata->data = data; tdata->length = length * clipboard_bytes_per_item (format); tdata->format = format; } } int find_content_type (TargetData* tdata, Atom type) { return tdata->type == type; } int find_content_target (TargetData* tdata, Atom target) { return tdata->target == target; } TargetData* target_data_ref (TargetData *data) { data->refcount++; return data; } void convert_clipboard_target (IncrConversion* rdata, ClipboardManager* manager) { TargetData *tdata; Atom *targets; int n_targets; List *list; unsigned long items; XWindowAttributes atts; if (rdata->target == XA_TARGETS) { n_targets = list_length (manager->mContents) + 2; targets = (Atom *) malloc (n_targets * sizeof (Atom)); n_targets = 0; targets[n_targets++] = XA_TARGETS; targets[n_targets++] = XA_MULTIPLE; for (list = manager->mContents; list; list = list->next) { tdata = (TargetData *) list->data; targets[n_targets++] = tdata->target; } XChangeProperty (manager->mDisplay, rdata->requestor, rdata->property, XA_ATOM, 32, PropModeReplace, (unsigned char *) targets, n_targets); free (targets); } else { /* Convert from stored CLIPBOARD data */ list = list_find (manager->mContents, (ListFindFunc) find_content_target, (void *) rdata->target); /* We got a target that we don't support */ if (!list) return; tdata = (TargetData *)list->data; if (tdata->type == XA_INCR) { /* we haven't completely received this target yet */ rdata->property = None; return; } rdata->data = target_data_ref (tdata); items = tdata->length / clipboard_bytes_per_item (tdata->format); if (tdata->length <= (int)SELECTION_MAX_SIZE) XChangeProperty (manager->mDisplay, rdata->requestor, rdata->property, tdata->type, tdata->format, PropModeReplace, tdata->data, items); else { /* start incremental transfer */ rdata->offset = 0; gdk_x11_display_error_trap_push(gdk_display_get_default()); XGetWindowAttributes (manager->mDisplay, rdata->requestor, &atts); XSelectInput (manager->mDisplay, rdata->requestor, atts.your_event_mask | PropertyChangeMask); XChangeProperty (manager->mDisplay, rdata->requestor, rdata->property, XA_INCR, 32, PropModeReplace, (unsigned char *) &items, 1); XSync (manager->mDisplay, False); gdk_x11_display_error_trap_pop_ignored(gdk_display_get_default()); } } } void collect_incremental (IncrConversion* rdata, ClipboardManager* manager) { if (rdata->offset >= 0) manager->mConversions = list_prepend (manager->mConversions, rdata); else { if (rdata->data) { target_data_unref (rdata->data); rdata->data = NULL; } free (rdata); } } void convert_clipboard (ClipboardManager* manager, XEvent* xev) { int format; unsigned long nitems; unsigned long remaining; List* list; List* conversions; Atom type; Atom* multiple = nullptr; IncrConversion* rdata; conversions = NULL; type = None; if (xev->xselectionrequest.target == XA_MULTIPLE) { XGetWindowProperty (xev->xselectionrequest.display, xev->xselectionrequest.requestor, xev->xselectionrequest.property, 0, 0x1FFFFFFF, False, XA_ATOM_PAIR, &type, &format, &nitems, &remaining, (unsigned char **) &multiple); if (type != XA_ATOM_PAIR || nitems == 0) { if (multiple) free (multiple); return; } for (unsigned long i = 0; i < nitems; i += 2) { rdata = (IncrConversion *) malloc (sizeof (IncrConversion)); rdata->requestor = xev->xselectionrequest.requestor; rdata->target = multiple[i]; rdata->property = multiple[i+1]; rdata->data = NULL; rdata->offset = -1; conversions = list_prepend (conversions, rdata); } } else { multiple = NULL; rdata = (IncrConversion *) malloc (sizeof (IncrConversion)); rdata->requestor = xev->xselectionrequest.requestor; rdata->target = xev->xselectionrequest.target; rdata->property = xev->xselectionrequest.property; rdata->data = NULL; rdata->offset = -1; conversions = list_prepend (conversions, rdata); } list_foreach (conversions, (Callback) convert_clipboard_target, manager); if (conversions->next == NULL && ((IncrConversion *) conversions->data)->property == None) { finish_selection_request (manager, xev, False); } else { if (multiple) { int i = 0; for (list = conversions; list; list = list->next) { rdata = (IncrConversion *)list->data; multiple[i++] = rdata->target; multiple[i++] = rdata->property; } XChangeProperty (xev->xselectionrequest.display, xev->xselectionrequest.requestor, xev->xselectionrequest.property, XA_ATOM_PAIR, 32, PropModeReplace, (unsigned char *) multiple, nitems); } finish_selection_request (manager, xev, True); } list_foreach (conversions, (Callback) collect_incremental, manager); list_free (conversions); if (multiple) free (multiple); } bool clipboard_manager_process_event(ClipboardManager* manager, XEvent* xev) { int format; Atom type; Atom* targets; unsigned long nitems; unsigned long remaining; targets = nullptr; switch (xev->xany.type) { case DestroyNotify: if (xev->xdestroywindow.window == manager->mRequestor) { list_foreach (manager->mContents, (Callback)target_data_unref, nullptr); list_free (manager->mContents); manager->mContents = nullptr; clipboard_manager_watch_cb (manager, manager->mRequestor, false, 0, nullptr); manager->mRequestor = None; } break; case PropertyNotify: if (xev->xproperty.state == PropertyNewValue) { return receive_incrementally (manager, xev); } else { return send_incrementally (manager, xev); } case SelectionClear: if (xev->xany.window != manager->mWindow) return false; if (xev->xselectionclear.selection == XA_CLIPBOARD_MANAGER) { /* We lost the manager selection */ if (manager->mContents) { list_foreach (manager->mContents, (Callback)target_data_unref, nullptr); list_free (manager->mContents); manager->mContents = nullptr; XSetSelectionOwner (manager->mDisplay, XA_CLIPBOARD, None, manager->mTime); } return True; } if (xev->xselectionclear.selection == XA_CLIPBOARD) { /* We lost the clipboard selection */ list_foreach (manager->mContents, (Callback)target_data_unref, nullptr); list_free (manager->mContents); manager->mContents = nullptr; clipboard_manager_watch_cb (manager, manager->mRequestor, false, 0, nullptr); manager->mRequestor = None; return true; } break; case SelectionNotify: if (xev->xany.window != manager->mWindow) return false; if (xev->xselection.selection == XA_CLIPBOARD) { /* a CLIPBOARD conversion is done */ if (xev->xselection.property == XA_TARGETS) { XGetWindowProperty (xev->xselection.display, xev->xselection.requestor, xev->xselection.property, 0, 0x1FFFFFFF, True, XA_ATOM, &type, &format, &nitems, &remaining, (unsigned char **) &targets); save_targets (manager, targets, nitems); } else if (xev->xselection.property == XA_MULTIPLE) { List *tmp; tmp = list_copy (manager->mContents); list_foreach (tmp, (Callback) get_property, manager); list_free (tmp); manager->mTime = xev->xselection.time; XSetSelectionOwner (manager->mDisplay, XA_CLIPBOARD, manager->mWindow, manager->mTime); if (manager->mProperty != None) XChangeProperty (manager->mDisplay, manager->mRequestor, manager->mProperty, XA_ATOM, 32, PropModeReplace, (unsigned char *)&XA_NULL, 1); if (!list_find (manager->mContents, (ListFindFunc)find_content_type, (void *)XA_INCR)) { /* all transfers done */ send_selection_notify (manager, True); clipboard_manager_watch_cb (manager, manager->mRequestor, false, 0, nullptr); manager->mRequestor = None; } } else if (xev->xselection.property == None) { send_selection_notify (manager, false); clipboard_manager_watch_cb (manager, manager->mRequestor, false, 0, nullptr); manager->mRequestor = None; } return true; } break; case SelectionRequest: if (xev->xany.window != manager->mWindow) { return false; } if (xev->xselectionrequest.selection == XA_CLIPBOARD_MANAGER) { convert_clipboard_manager (manager, xev); return true; } else if (xev->xselectionrequest.selection == XA_CLIPBOARD) { convert_clipboard (manager, xev); return true; } break; default: ; } return false; } bool receive_incrementally (ClipboardManager* manager, XEvent* xev) { List* list; TargetData* tdata; Atom type; int format; unsigned char* data; unsigned long length, nitems, remaining; if (xev->xproperty.window != manager->mWindow) return false; list = list_find (manager->mContents, (ListFindFunc) find_content_target, (void *) xev->xproperty.atom); if (!list) return false; tdata = (TargetData *) list->data; if (tdata->type != XA_INCR) return false; XGetWindowProperty (xev->xproperty.display, xev->xproperty.window, xev->xproperty.atom, 0, 0x1FFFFFFF, True, AnyPropertyType, &type, &format, &nitems, &remaining, &data); length = nitems * clipboard_bytes_per_item (format); if (length == 0) { tdata->type = type; tdata->format = format; if (!list_find (manager->mContents, (ListFindFunc) find_content_type, (void *)XA_INCR)) { /* all incremental transfers done */ send_selection_notify (manager, True); manager->mRequestor = None; } XFree (data); } else { if (!tdata->data) { tdata->data = data; tdata->length = length; } else { tdata->data = (unsigned char*)realloc (tdata->data, tdata->length + length + 1); memcpy (tdata->data + tdata->length, data, length + 1); tdata->length += length; XFree (data); } } return True; } int find_conversion_requestor (IncrConversion* rdata, XEvent* xev) { return (rdata->requestor == xev->xproperty.window && rdata->property == xev->xproperty.atom); } bool send_incrementally (ClipboardManager* manager, XEvent* xev) { List* list; unsigned long length; unsigned long items; unsigned char* data; IncrConversion* rdata; list = list_find (manager->mConversions, (ListFindFunc) find_conversion_requestor, xev); if (list == NULL) return false; rdata = (IncrConversion *) list->data; data = rdata->data->data + rdata->offset; length = rdata->data->length - rdata->offset; if (length > SELECTION_MAX_SIZE) length = SELECTION_MAX_SIZE; rdata->offset += length; items = length / clipboard_bytes_per_item (rdata->data->format); XChangeProperty (manager->mDisplay, rdata->requestor, rdata->property, rdata->data->type, rdata->data->format, PropModeAppend, data, items); if (length == 0) { manager->mConversions = list_remove (manager->mConversions, rdata); conversion_free (rdata); } return true; } void save_targets (ClipboardManager* manager, Atom* save_targets, int nitems) { int nout, i; Atom *multiple; TargetData *tdata; multiple = (Atom *) malloc (2 * nitems * sizeof (Atom)); nout = 0; for (i = 0; i < nitems; i++) { if (save_targets[i] != XA_TARGETS && save_targets[i] != XA_MULTIPLE && save_targets[i] != XA_DELETE && save_targets[i] != XA_INSERT_PROPERTY && save_targets[i] != XA_INSERT_SELECTION && save_targets[i] != XA_PIXMAP) { tdata = (TargetData *) malloc (sizeof (TargetData)); tdata->data = NULL; tdata->length = 0; tdata->target = save_targets[i]; tdata->type = None; tdata->format = 0; tdata->refcount = 1; manager->mContents = list_prepend (manager->mContents, tdata); multiple[nout++] = save_targets[i]; multiple[nout++] = save_targets[i]; } } XFree (save_targets); XChangeProperty (manager->mDisplay, manager->mWindow, XA_MULTIPLE, XA_ATOM_PAIR, 32, PropModeReplace, (const unsigned char *) multiple, nout); free (multiple); XConvertSelection (manager->mDisplay, XA_CLIPBOARD, XA_MULTIPLE, XA_MULTIPLE, manager->mWindow, manager->mTime); } void send_selection_notify (ClipboardManager* manager, bool success) { XSelectionEvent notify; notify.type = SelectionNotify; notify.serial = 0; notify.send_event = True; notify.display = manager->mDisplay; notify.requestor = manager->mRequestor; notify.selection = XA_CLIPBOARD_MANAGER; notify.target = XA_SAVE_TARGETS; notify.property = success ? manager->mProperty : None; notify.time = manager->mTime; gdk_x11_display_error_trap_push(gdk_display_get_default()); XSendEvent (manager->mDisplay, manager->mRequestor, false, NoEventMask, (XEvent *)¬ify); XSync (manager->mDisplay, false); gdk_x11_display_error_trap_pop_ignored(gdk_display_get_default()); } void convert_clipboard_manager (ClipboardManager* manager, XEvent* xev) { Atom type = None; int format; unsigned long nitems; unsigned long remaining; Atom *targets = NULL; if (xev->xselectionrequest.target == XA_SAVE_TARGETS) { if (manager->mRequestor != None || manager->mContents != nullptr) { /* We're in the middle of a conversion request, or own the CLIPBOARD already */ finish_selection_request (manager, xev, False); } else { gdk_x11_display_error_trap_push(gdk_display_get_default()); clipboard_manager_watch_cb (manager, xev->xselectionrequest.requestor, true, StructureNotifyMask, nullptr); XSelectInput (manager->mDisplay, xev->xselectionrequest.requestor, StructureNotifyMask); XSync (manager->mDisplay, false); if (gdk_x11_display_error_trap_pop (gdk_display_get_default()) != Success) return; gdk_x11_display_error_trap_push(gdk_display_get_default()); if (xev->xselectionrequest.property != None) { XGetWindowProperty (manager->mDisplay, xev->xselectionrequest.requestor, xev->xselectionrequest.property, 0, 0x1FFFFFFF, False, XA_ATOM, &type, &format, &nitems, &remaining, (unsigned char **) &targets); if (gdk_x11_display_error_trap_pop (gdk_display_get_default()) != Success) { if (targets) XFree (targets); return; } } manager->mRequestor = xev->xselectionrequest.requestor; manager->mProperty = xev->xselectionrequest.property; manager->mTime = xev->xselectionrequest.time; if (type == None) XConvertSelection (manager->mDisplay, XA_CLIPBOARD, XA_TARGETS, XA_TARGETS, manager->mWindow, manager->mTime); else save_targets (manager, targets, nitems); } } else if (xev->xselectionrequest.target == XA_TIMESTAMP) { XChangeProperty (manager->mDisplay, xev->xselectionrequest.requestor, xev->xselectionrequest.property, XA_INTEGER, 32, PropModeReplace, (unsigned char *) &manager->mTimestamp, 1); finish_selection_request (manager, xev, true); } else if (xev->xselectionrequest.target == XA_TARGETS) { int n_targets = 0; Atom targets[3]; targets[n_targets++] = XA_TARGETS; targets[n_targets++] = XA_TIMESTAMP; targets[n_targets++] = XA_SAVE_TARGETS; XChangeProperty (manager->mDisplay, xev->xselectionrequest.requestor, xev->xselectionrequest.property, XA_ATOM, 32, PropModeReplace, (unsigned char *) targets, n_targets); finish_selection_request (manager, xev, true); } else { finish_selection_request (manager, xev, false); } } void finish_selection_request (ClipboardManager* manager, XEvent* xev, bool success) { XSelectionEvent notify; notify.type = SelectionNotify; notify.serial = 0; notify.send_event = true; notify.display = xev->xselectionrequest.display; notify.requestor = xev->xselectionrequest.requestor; notify.selection = xev->xselectionrequest.selection; notify.target = xev->xselectionrequest.target; notify.property = success ? xev->xselectionrequest.property : None; notify.time = xev->xselectionrequest.time; gdk_x11_display_error_trap_push (gdk_display_get_default()); XSendEvent (xev->xselectionrequest.display, xev->xselectionrequest.requestor, false, NoEventMask, (XEvent *) ¬ify); XSync (manager->mDisplay, false); gdk_x11_display_error_trap_pop_ignored(gdk_display_get_default()); } ukui-settings-daemon/plugins/clipboard/list.c0000644000175000017500000000550414205117202020307 0ustar fengfeng/* * Copyright © 2004 Red Hat, Inc. * * 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, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Matthias Clasen, Red Hat, Inc. */ #include #include void list_foreach (List *list, Callback func, void *user_data) { while (list) { func (list->data, user_data); list = list->next; } } List * list_prepend (List *list, void *data) { List *link; link = (List *) malloc (sizeof (List)); link->next = list; link->data = data; return link; } void list_free (List *list) { while (list) { List *next = list->next; free (list); list = next; } } List * list_find (List *list, ListFindFunc func, void *user_data) { List *tmp; for (tmp = list; tmp; tmp = tmp->next) { if ((*func) (tmp->data, user_data)) break; } return tmp; } List * list_remove (List *list, void *data) { List *tmp, *prev; prev = NULL; for (tmp = list; tmp; tmp = tmp->next) { if (tmp->data == data) { if (prev) prev->next = tmp->next; else list = tmp->next; free (tmp); break; } prev = tmp; } return list; } int list_length (List *list) { List *tmp; int length; length = 0; for (tmp = list; tmp; tmp = tmp->next) length++; return length; } List * list_copy (List *list) { List *new_list = NULL; if (list) { List *last; new_list = (List *) malloc (sizeof (List)); new_list->data = list->data; new_list->next = NULL; last = new_list; list = list->next; while (list) { last->next = (List *) malloc (sizeof (List)); last = last->next; last->data = list->data; list = list->next; } last->next = NULL; } return new_list; } ukui-settings-daemon/plugins/clipboard/clipboard-plugin.h0000644000175000017500000000253614205117202022576 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef CLIPBOARDPLUGIN_H #define CLIPBOARDPLUGIN_H #include "clipboard-manager.h" #include "plugin-interface.h" #include class ClipboardPlugin : public PluginInterface { public: ~ClipboardPlugin(); static PluginInterface* getInstance(); virtual void activate (); virtual void deactivate (); private: ClipboardPlugin(); ClipboardPlugin(ClipboardPlugin&)=delete; private: static ClipboardManager* mManager; static PluginInterface* mInstance; }; extern "C" Q_DECL_EXPORT PluginInterface* createSettingsPlugin(); #endif // CLIPBOARDPLUGIN_H ukui-settings-daemon/plugins/clipboard/list.h0000644000175000017500000000367114205117202020317 0ustar fengfeng/* * Copyright © 2004 Red Hat, Inc. * * 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, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Matthias Clasen, Red Hat, Inc. */ #ifndef LIST_H #define LIST_H #ifdef __cplusplus extern "C" { #endif typedef struct _List List; typedef void (*Callback) (void *data, void *user_data); struct _List { void *data; List *next; }; typedef int (*ListFindFunc) (void *data, void *user_data); void list_foreach (List *list, Callback func, void *user_data); List *list_prepend (List *list, void *data); void list_free (List *list); List *list_find (List *list, ListFindFunc func, void *user_data); List *list_remove (List *list, void *data); int list_length (List *list); List *list_copy (List *list); #ifdef __cplusplus } #endif #endif /* LIST_H */ ukui-settings-daemon/plugins/clipboard/main.cpp0000644000175000017500000000243214205117202020615 0ustar fengfeng/* * Copyright © 2004 Red Hat, Inc. * * 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, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Matthias Clasen, Red Hat, Inc. */ #include int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); return a.exec(); } ukui-settings-daemon/plugins/sound/0000755000175000017500000000000014205117202016355 5ustar fengfengukui-settings-daemon/plugins/sound/sound.pro0000644000175000017500000000135014205117202020226 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-04-16T09:30:00 # #------------------------------------------------- QT -= gui TEMPLATE = lib TARGET = sound CONFIG += c++11 plugin link_pkgconfig CONFIG -= app_bundle DEFINES += QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"sound\\\" include($$PWD/../../common/common.pri) PKGCONFIG += glib-2.0 \ gio-2.0 \ INCLUDEPATH += \ -I /usr/include/pulse LIBS += \ -lpulse SOURCES += \ sound-manager.cpp \ sound-plugin.cpp DISTFILES += \ sound.ukui-settings-plugin.in HEADERS += \ sound-manager.h \ sound-plugin.h sound_lib.path = $${PLUGIN_INSTALL_DIRS} sound_lib.files = $$OUT_PWD/libsound.so INSTALLS += sound_lib ukui-settings-daemon/plugins/sound/sound-plugin.cpp0000644000175000017500000000353114205117202021507 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "sound-plugin.h" #include "clib-syslog.h" SoundPlugin* SoundPlugin::mSoundPlugin = nullptr; SoundPlugin::SoundPlugin() { USD_LOG(LOG_DEBUG,"UsdSoundPlugin initializing!"); soundManager = SoundManager::SoundManagerNew(); } SoundPlugin::~SoundPlugin() { USD_LOG(LOG_DEBUG,"UsdSoundPlugin deconstructor!"); if(soundManager) delete soundManager; } void SoundPlugin::activate () { GError *error = NULL; USD_LOG (LOG_DEBUG, "Activating %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); if (!soundManager->SoundManagerStart(&error)) { USD_LOG(LOG_DEBUG,"Unable to start sound manager: %s", error->message); g_error_free (error); } } void SoundPlugin::deactivate () { USD_LOG(LOG_DEBUG,"Deactivating sound plugin!"); soundManager->SoundManagerStop(); } PluginInterface* SoundPlugin::getInstance() { if(nullptr == mSoundPlugin) mSoundPlugin = new SoundPlugin(); return mSoundPlugin; } PluginInterface* createSettingsPlugin() { return SoundPlugin::getInstance(); } ukui-settings-daemon/plugins/sound/sound-manager.h0000644000175000017500000000355514205117202021276 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SOUNDMANAGER_H #define SOUNDMANAGER_H #include #include #include #include #include "QGSettings/qgsettings.h" #ifdef signals #undef signals #endif extern "C"{ #include #include #include #include "clib-syslog.h" #include } #define UKUI_SOUND_SCHEMA "org.mate.sound" #define PACKAGE_NAME "ukui-settings-daemon" #define PACKAGE_VERSION "1.1.1" class SoundManager : public QObject{ Q_OBJECT public: ~SoundManager(); static SoundManager* SoundManagerNew(); bool SoundManagerStart(GError **error); void SoundManagerStop(); private: SoundManager(); void trigger_flush(); bool register_directory_callback(const QString path, GError **error); private Q_SLOTS: bool flush_cb(); void gsettings_notify_cb (const QString& key); void file_monitor_changed_cb(const QString& path); private: static SoundManager* mSoundManager; QGSettings* settings; QList* monitors; QTimer* timer; }; #endif /* SOUNDMANAGER_H */ ukui-settings-daemon/plugins/sound/sound-manager.cpp0000644000175000017500000001713514205117202021630 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "sound-manager.h" SoundManager* SoundManager::mSoundManager = nullptr; SoundManager::SoundManager() { timer = new QTimer(); connect(timer, &QTimer::timeout, this, &SoundManager::flush_cb); } SoundManager::~SoundManager() { USD_LOG(LOG_DEBUG,"SoundManager destructor!"); if(mSoundManager) delete mSoundManager; } void sample_info_cb (pa_context *c, const pa_sample_info *i, int eol, void *userdata) { pa_operation *o; if (!i) { USD_LOG(LOG_DEBUG,"can't find sample"); return; } USD_LOG(LOG_DEBUG,"Found sample %s", i->name); /* We only flush those samples which have an XDG sound name * attached, because only those originate from themeing */ if (!(pa_proplist_gets (i->proplist, PA_PROP_EVENT_ID))) return; USD_LOG(LOG_DEBUG,"Dropping sample %s from cache", i->name); if (!(o = pa_context_remove_sample (c, i->name, NULL, NULL))) { USD_LOG(LOG_DEBUG,"pa_context_remove_sample (): %s", pa_strerror (pa_context_errno (c))); return; } pa_operation_unref (o); /* We won't wait until the operation is actually executed to * speed things up a bit.*/ } void flush_cache (void) { pa_mainloop *ml = NULL; pa_context *c = NULL; pa_proplist *pl = NULL; pa_operation *o = NULL; if (!(ml = pa_mainloop_new ())) { USD_LOG(LOG_DEBUG,"Failed to allocate pa_mainloop"); goto fail; } if (!(pl = pa_proplist_new ())) { USD_LOG(LOG_DEBUG,"Failed to allocate pa_proplist"); goto fail; } pa_proplist_sets (pl, PA_PROP_APPLICATION_NAME, PACKAGE_NAME); pa_proplist_sets (pl, PA_PROP_APPLICATION_VERSION, PACKAGE_VERSION); pa_proplist_sets (pl, PA_PROP_APPLICATION_ID, "org.ukui.SettingsDaemon"); if (!(c = pa_context_new_with_proplist (pa_mainloop_get_api (ml), PACKAGE_NAME, pl))) { USD_LOG(LOG_DEBUG,"Failed to allocate pa_context"); goto fail; } pa_proplist_free (pl); pl = NULL; if (pa_context_connect (c, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) { USD_LOG(LOG_DEBUG,"pa_context_connect(): %s", pa_strerror (pa_context_errno (c))); goto fail; } /* Wait until the connection is established */ while (pa_context_get_state (c) != PA_CONTEXT_READY) { if (!PA_CONTEXT_IS_GOOD (pa_context_get_state (c))) { USD_LOG(LOG_DEBUG,"Connection failed: %s", pa_strerror (pa_context_errno (c))); goto fail; } if (pa_mainloop_iterate (ml, TRUE, NULL) < 0) { USD_LOG(LOG_DEBUG,"pa_mainloop_iterate() failed"); goto fail; } } /* Enumerate all cached samples */ if (!(o = pa_context_get_sample_info_list (c, sample_info_cb, NULL))) { USD_LOG(LOG_DEBUG,"pa_context_get_sample_info_list(): %s", pa_strerror (pa_context_errno (c))); goto fail; } /* Wait until our operation is finished and there's nothing * more queued to send to the server */ while (pa_operation_get_state (o) == PA_OPERATION_RUNNING || pa_context_is_pending (c)) { if (!PA_CONTEXT_IS_GOOD (pa_context_get_state (c))) { USD_LOG(LOG_DEBUG,"Connection failed: %s", pa_strerror (pa_context_errno (c))); goto fail; } if (pa_mainloop_iterate (ml, TRUE, NULL) < 0) { USD_LOG(LOG_DEBUG,"pa_mainloop_iterate() failed"); goto fail; } } USD_LOG(LOG_DEBUG,"send over..."); fail: if (o) { pa_operation_cancel (o); pa_operation_unref (o); } if (c) { pa_context_disconnect (c); pa_context_unref (c); } if (pl) pa_proplist_free (pl); if (ml) pa_mainloop_free (ml); } bool SoundManager::flush_cb () { flush_cache(); timer->stop(); USD_LOG(LOG_DEBUG,"sound it"); return false; } void SoundManager::trigger_flush () { if(timer->isActive()) timer->stop(); /* We delay the flushing a bit so that we can coalesce * multiple changes into a single cache flush */ timer->start(500); USD_LOG(LOG_DEBUG,"sound it"); } /* func: listen for org.mate.sound */ void SoundManager::gsettings_notify_cb (const QString& key) { trigger_flush(); } /*func : listen for follow directory. * $HOME/.locale/share/sounds * /usr/share/ukui/ * /usr/share/ * /usr/locale/share/ */ void SoundManager::file_monitor_changed_cb (const QString& path) { trigger_flush (); } bool SoundManager::register_directory_callback (const QString path, GError **error) { QDir dir; QFileSystemWatcher* w; bool succ = false; w = new QFileSystemWatcher(); if(w->addPath(path)){ connect(w,&QFileSystemWatcher::directoryChanged, this, &SoundManager::file_monitor_changed_cb); monitors->push_front(w); succ = true; } return succ; } bool SoundManager::SoundManagerStart (GError **error) { const char *env, *dd; QString path; QString homePath; QStringList pathList; int pathNum; int i; USD_LOG(LOG_DEBUG,"Starting sound manager"); monitors = new QList(); /* We listen for change of the selected theme ... */ settings = new QGSettings(UKUI_SOUND_SCHEMA); // QObject::connect(settings, &QGSettings::changed, this, &SoundManager::gsettings_notify_cb); connect(settings, SIGNAL(changed(QString)), this, SLOT(gsettings_notify_cb(QString))); /* ... and we listen to changes of the theme base directories * in $HOME ...*/ homePath = QDir::homePath(); if ((env = getenv ("XDG_DATA_HOME")) && *env == '/') { path = QString(env) + "/sounds"; } else if (!homePath.isEmpty()) { path = homePath + "/.local" + "/share" + "/sounds"; } else { path = nullptr; } if (!path.isNull() && !path.isEmpty()) { USD_LOG(LOG_DEBUG,"ready register callback:%s",path.toLatin1().data()); register_directory_callback (path, NULL); } /* ... and globally. */ if (!(dd = getenv ("XDG_DATA_DIRS")) || *dd == 0) { dd = "/usr/local/share:/usr/share"; } pathList = QString(dd).split(":"); pathNum = pathList.count(); for (i = 0; i < pathNum; ++i) { USD_LOG(LOG_DEBUG,"ready register callback:%s",pathList.at(i).toLatin1().data()); register_directory_callback (pathList.at(i), NULL); } trigger_flush(); return true; } void SoundManager::SoundManagerStop () { USD_LOG(LOG_DEBUG,"Stopping sound manager"); if (settings) { delete settings; settings = nullptr; } while (monitors->length()) { delete monitors->first(); monitors->removeFirst(); } delete monitors; monitors = nullptr; } SoundManager *SoundManager::SoundManagerNew () { if(nullptr == mSoundManager) mSoundManager = new SoundManager(); return mSoundManager; } ukui-settings-daemon/plugins/sound/sound-plugin.h0000644000175000017500000000232714205117202021156 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SOUNDPLUGIN_H #define SOUNDPLUGIN_H #include "sound-manager.h" #include "plugin-interface.h" class SoundPlugin : public PluginInterface{ public: ~SoundPlugin(); static PluginInterface* getInstance(); virtual void activate(); virtual void deactivate(); private: SoundPlugin(); SoundManager* soundManager; static SoundPlugin* mSoundPlugin; }; extern "C" PluginInterface* Q_DECL_EXPORT createSettingsPlugin(); #endif /*SOUND_PLUGIN_H */ ukui-settings-daemon/plugins/kds/0000755000175000017500000000000014205117214016011 5ustar fengfengukui-settings-daemon/plugins/kds/kdswidget.cpp0000644000175000017500000005616214205117202020511 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "kdswidget.h" #include "ui_kdswidget.h" #include #include #include #include #include #include "expendbutton.h" #define TITLEHEIGHT 90 #define OPTIONSHEIGHT 70 #define BOTTOMHEIGHT 60 enum { FIRSTSCREEN, CLONESCREEN, EXTENDSCREEN, // LEXTENDSCREEN, OTHERSCREEN, ALLMODES, }; bool operator<(const QSize &s1, const QSize &s2) { return s1.width() * s1.height() < s2.width() * s2.height(); } template<> bool qMapLessThanKey(const QSize &s1, const QSize &s2) { return s1 < s2; } KDSWidget::KDSWidget(QWidget *parent) : QWidget(parent), ui(new Ui::KDSWidget) { ui->setupUi(this); } KDSWidget::~KDSWidget() { delete ui; } void KDSWidget::beginSetupKF5(){ QObject::connect(new KScreen::GetConfigOperation(), &KScreen::GetConfigOperation::finished, [&](KScreen::ConfigOperation *op) { setConfig(qobject_cast(op)->config()); }); setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); setAttribute(Qt::WA_TranslucentBackground, true); /* 不在任务栏显示图标 */ KWindowSystem::setState(winId(), NET::SkipTaskbar | NET::SkipPager); btnsGroup = new QButtonGroup; QDBusConnection::systemBus().connect(QString(), \ QString(), \ "org.ukui.kds.interface", \ "signalNextOption", \ this, SLOT(nextSelectedOption())); QDBusConnection::systemBus().connect(QString(), \ QString(), \ "org.ukui.kds.interface", \ "signalLastOption", \ this, SLOT(lastSelectedOption())); QDBusConnection::systemBus().connect(QString(), \ QString(), \ "org.ukui.kds.interface", \ "signalCloseApp", \ this, SLOT(closeApp())); QDBusConnection::systemBus().connect(QString(), \ QString(), \ "org.ukui.kds.interface", \ "signalMakeClicked", \ this, SLOT(confirmCurrentOption())); QDBusConnection::systemBus().connect(QString(), \ QString(), \ "org.ukui.kds.interface", \ "signalButtonClicked", \ this, SLOT(receiveButtonClick(int,int))); } QString KDSWidget::getCurrentPrimaryScreenName(){ QDBusInterface usdiface("org.ukui.SettingsDaemon", "/org/ukui/SettingsDaemon/wayland", "org.ukui.SettingsDaemon.wayland", QDBusConnection::sessionBus()); if (usdiface.isValid()){ QDBusReply reply = usdiface.call("priScreenName"); if (reply.isValid()){ return reply.value(); } } return QString(""); } int KDSWidget::getCurrentScale(){ QDBusInterface usdiface("org.ukui.SettingsDaemon", "/org/ukui/SettingsDaemon/wayland", "org.ukui.SettingsDaemon.wayland", QDBusConnection::sessionBus()); if (usdiface.isValid()){ QDBusReply reply = usdiface.call("scale"); if (reply.isValid()){ return reply.value(); } } return 1; } QPoint KDSWidget::getWinPos(){ QString pName = getCurrentPrimaryScreenName(); if (!pName.isEmpty()){ const KScreen::ConfigPtr &config = this->currentConfig(); Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { if (QString::compare(output.data()->name(), pName) == 0){ QRect rect = output.data()->geometry(); return rect.center(); } } } QScreen * pScreen = QGuiApplication::screens().at(0); return pScreen->geometry().center(); } void KDSWidget::setupComponent(){ ui->outputPrimaryTip->hide(); // setCurrentFirstOutputTip(); for (int i = 0; i < ALLMODES; i++){ ExpendButton * btn = new ExpendButton(); btn->setFixedHeight(70); btnsGroup->addButton(btn, i); switch (i) { case FIRSTSCREEN: btn->setSign(FIRSTSCREEN % 2); btn->setBtnText(tr("First Screen")); btn->setBtnLogo(":/img/main.png"); break; case CLONESCREEN: btn->setSign(CLONESCREEN % 2); btn->setBtnText(tr("Clone Screen")); btn->setBtnLogo(":/img/clone.png"); break; case EXTENDSCREEN: btn->setSign(EXTENDSCREEN % 2); btn->setBtnText(tr("Extend Screen")); btn->setBtnLogo(":/img/extend.png"); break; // case LEXTENDSCREEN: // btn->setSign(LEXTENDSCREEN % 2); // btn->setBtnText(tr("Left Extend Screen")); // btn->setBtnLogo(":/img/extend.png"); // break; case OTHERSCREEN: btn->setSign(OTHERSCREEN % 2); btn->setBtnText(tr("Vice Screen")); btn->setBtnLogo(":/img/vice.png"); break; default: break; } ui->btnsVerLayout->addWidget(btn); } int h = TITLEHEIGHT + OPTIONSHEIGHT * ALLMODES + BOTTOMHEIGHT; setFixedWidth(400); setFixedHeight(h); /// QSS ui->titleFrame->setStyleSheet("QFrame#titleFrame{background: #A6000000; border: none; border-top-left-radius: 24px; border-top-right-radius: 24px;}"); ui->bottomFrame->setStyleSheet("QFrame#bottomFrame{background: #A6000000; border: none; border-bottom-left-radius: 24px; border-bottom-right-radius: 24px;}"); ui->splitFrame->setStyleSheet("QFrame#splitFrame{background: #99000000; border: none;}"); ui->titleLabel->setStyleSheet("QLabel{color: #FFFFFF; font-size: 24px;}"); ui->outputPrimaryTip->setStyleSheet("QLabel{color: #60FFFFFF; font-size: 18px;}"); ui->outputName->setStyleSheet("QLabel{color: #60FFFFFF; font-size: 18px;}"); ui->outputDisplayName->setStyleSheet("QLabel{color: #60FFFFFF; font-size: 18px;}"); } void KDSWidget::setupConnect(){ connect(btnsGroup, static_cast(&QButtonGroup::buttonClicked), this, [=](int id){ /* 获取旧选项 */ for (QAbstractButton * button : btnsGroup->buttons()){ ExpendButton * btn = dynamic_cast(button); // qDebug() << "old index: " << btn->getBtnChecked(); int index = btnsGroup->id(button); if (index == id && btn->getBtnChecked()){ goto closeapp; } } switch (id) { case FIRSTSCREEN: setFirstModeSetup(); setCurrentUIStatus(FIRSTSCREEN); break; case CLONESCREEN: setCloneModeSetup(); setCurrentUIStatus(CLONESCREEN); break; case EXTENDSCREEN: setExtendModeSetup(); setCurrentUIStatus(EXTENDSCREEN); break; // case LEXTENDSCREEN: // setLeftExtendModeSetup(); // setCurrentUIStatus(LEXTENDSCREEN); // break; case OTHERSCREEN: setOtherModeSetup(); setCurrentUIStatus(OTHERSCREEN); break; default: break; } closeapp: close(); }); } int KDSWidget::getCurrentStatus(){ QString firstOutputName; const KScreen::ConfigPtr &config = this->currentConfig(); const KScreen::OutputList &outputs = config->connectedOutputs(); firstOutputName = findFirstOutput(); if (outputs.count() < 2){ return FIRSTSCREEN; } else { /* output.data()->clones().isEmpty() is not valid */ Q_FOREACH(const KScreen::OutputPtr &output, outputs) { // if (!output.data()->clones().isEmpty()){ // return CLONESCREEN; // } if (QString::compare(firstOutputName, output.data()->name()) == 0){ if (!output.data()->isEnabled()){ return OTHERSCREEN; } } if (!output.data()->isEnabled()){ return FIRSTSCREEN; } } Q_FOREACH(const KScreen::OutputPtr &output, outputs) { if (output.data()->pos().x() != 0){ return EXTENDSCREEN; } } return CLONESCREEN; } // Q_FOREACH(const KScreen::OutputPtr &output, outputs) { // if (QString::compare(firstOutputName, output.data()->name()) == 0){ // QPoint pPos = output.data()->pos(); // if (pPos.x() > 0){ // return LEXTENDSCREEN; // } else { // return REXTENDSCREEN; // } // } // } } void KDSWidget::setCurrentUIStatus(int id){ //set all no checked for (QAbstractButton * button : btnsGroup->buttons()){ ExpendButton * btn = dynamic_cast(button); btn->setBtnChecked(false); if (id == btnsGroup->id(button)){ btn->setBtnChecked(true); btn->setChecked(true); } } // status == -1 if (id == -1){ ExpendButton * btn1 = dynamic_cast(btnsGroup->button(FIRSTSCREEN)); // btn1->setBtnChecked(true); btn1->setChecked(true); } } void KDSWidget::setConfig(const KScreen::ConfigPtr &config) { mConfig = config; //获取主屏位置 QPoint point = getWinPos(); move(point.x() - width()/2, point.y() - height()/2); setupComponent(); setupConnect(); setCurrentUIStatus(getCurrentStatus()); } KScreen::ConfigPtr KDSWidget::currentConfig() const { return mConfig; } void KDSWidget::setCurrentFirstOutputTip(){ const KScreen::ConfigPtr &config = this->currentConfig(); QString firstOutputName = findFirstOutput(); Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { QString opName = output.data()->name(); QString opDisName = output.data()->edid()->name(); if (QString::compare(firstOutputName, output.data()->name()) == 0){ ui->outputName->setText(opName); ui->outputDisplayName->setText(""/*opDisName*/); return; } } ui->outputName->setText(tr("N/A")); } QString KDSWidget::findFirstOutput(){ int firstopID = -1; QString firstopName; const KScreen::ConfigPtr &config = this->currentConfig(); Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { if (firstopID == -1){ firstopID = output.data()->id(); firstopName = output.data()->name(); } if (firstopID > output.data()->id()){ firstopID = output.data()->id(); firstopName = output.data()->name(); } } return firstopName; } void KDSWidget::setCloneModeSetup(){ QDBusMessage message = QDBusMessage::createMethodCall("org.ukui.SettingsDaemon", "/org/ukui/SettingsDaemon/wayland", "org.ukui.SettingsDaemon.wayland", "setScreenMode"); message << "clone"; QDBusConnection::sessionBus().send(message); // QList clones; // const KScreen::ConfigPtr &config = this->currentConfig(); // QSize cloneSize = findBestCloneSize(); // Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { // float bestRate = 0.0; // QString bestID; // output.data()->setEnabled(true); // Q_FOREACH (const KScreen::ModePtr &mode, output->modes()) { // if (mode.data()->size() == cloneSize){ // float r = mode.data()->refreshRate(); // if (bestRate < r){ // bestRate = r; // bestID = mode.data()->id(); // } // } // } // if (bestRate > 0){ // output.data()->setCurrentModeId(bestID); // output.data()->setRotation(KScreen::Output::None); // output.data()->setPos(QPoint(0, 0)); // if (!output.data()->isPrimary()){ // clones.append(output.data()->id()); // } // } // } // Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { // if (output.data()->isPrimary()){ // output.data()->setClones(clones); // } else { // output.data()->setClones(QList()); // } // } // if (!KScreen::Config::canBeApplied(config)) { //// qDebug() << "Can not apply!"; // return; // } // auto *op = new KScreen::SetConfigOperation(config); // op->exec(); // syncPrimaryScreenData(getCurrentPrimaryScreenName()); } void KDSWidget::setExtendModeSetup(){ QDBusMessage message = QDBusMessage::createMethodCall("org.ukui.SettingsDaemon", "/org/ukui/SettingsDaemon/wayland", "org.ukui.SettingsDaemon.wayland", "setScreenMode"); message << "extend"; QDBusConnection::sessionBus().send(message); // const KScreen::ConfigPtr &config = this->currentConfig(); // int x = 0; // Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { // if (!output.data()->isPrimary()){ // continue; // } // output.data()->setEnabled(true); // output.data()->setClones(QList()); // x = turnonAndGetRightmostOffset(output, x); // } // Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { // if (output.data()->isPrimary()){ // continue; // } // output.data()->setEnabled(true); // output.data()->setClones(QList()); // x = turnonAndGetRightmostOffset(output, x); // } // if (!KScreen::Config::canBeApplied(config)) { //// qDebug() << "Can not apply!"; // return; // } // auto *op = new KScreen::SetConfigOperation(config); // op->exec(); // // // syncPrimaryScreenData(getCurrentPrimaryScreenName()); } void KDSWidget::setLeftExtendModeSetup(){ const KScreen::ConfigPtr &config = this->currentConfig(); int x = 0; Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { if (output.data()->isPrimary()){ continue; } output.data()->setEnabled(true); output.data()->setClones(QList()); x = turnonAndGetRightmostOffset(output, x); } Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { if (!output.data()->isPrimary()){ continue; } output.data()->setEnabled(true); output.data()->setClones(QList()); x = turnonAndGetRightmostOffset(output, x); } if (!KScreen::Config::canBeApplied(config)) { // qDebug() << "Can not apply!"; return; } auto *op = new KScreen::SetConfigOperation(config); op->exec(); Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { // qDebug() << "\n" << output.data()->name() << output.data()->clones() << output.data()->clone(); } } void KDSWidget::setFirstModeSetup(){ QDBusMessage message = QDBusMessage::createMethodCall("org.ukui.SettingsDaemon", "/org/ukui/SettingsDaemon/wayland", "org.ukui.SettingsDaemon.wayland", "setScreenMode"); message << "first"; QDBusConnection::sessionBus().send(message); // const KScreen::ConfigPtr &config = this->currentConfig(); // QString firstName = findFirstOutput(); // Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { // /* 取消镜像模式标志位 */ // output.data()->setClones(QList()); // if (QString::compare(output.data()->name(), firstName) == 0){ // turnonSpecifiedOutput(output, 0, 0); // } else { // output.data()->setEnabled(false); // } // } // if (!KScreen::Config::canBeApplied(config)) { //// qDebug() << "Can not apply!"; // return; // } // auto * op = new KScreen::SetConfigOperation(config); // op->exec(); // syncPrimaryScreenData(firstName); } void KDSWidget::setOtherModeSetup(){ QDBusMessage message = QDBusMessage::createMethodCall("org.ukui.SettingsDaemon", "/org/ukui/SettingsDaemon/wayland", "org.ukui.SettingsDaemon.wayland", "setScreenMode"); message << "second"; QDBusConnection::sessionBus().send(message); // const KScreen::ConfigPtr &config = this->currentConfig(); // QString firstName = findFirstOutput(); // QString otherName; // Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { // /* 取消镜像模式标志位 */ // output.data()->setClones(QList()); // if (QString::compare(output.data()->name(), firstName) == 0){ // output.data()->setEnabled(false); // } else { //// output.data()->setEnabled(true); // turnonSpecifiedOutput(output, 0, 0); // } // //获取非主屏的Name。TODO:多屏(>2)情况下呢? // if (QString::compare(output.data()->name(), firstName) == 0){ // } else { // otherName = output.data()->name(); // } // } // if (!KScreen::Config::canBeApplied(config)) { //// qDebug() << "Can not apply!"; // return; // } // auto * op = new KScreen::SetConfigOperation(config); // op->exec(); // syncPrimaryScreenData(otherName); } int KDSWidget::turnonAndGetRightmostOffset(const KScreen::OutputPtr &output, int x){ turnonSpecifiedOutput(output, x, 0); int width; // width = output.data()->size().width(); width = output.data()->preferredMode().data()->size().width(); // qDebug() << output.data()->name() << "width is " << output.data()->size() << output.data()->preferredMode().data()->size(); // Q_FOREACH (const KScreen::ModePtr &mode, output->modes()) { // qDebug() << "mode is: " << mode.data()->id() << mode.data()->size(); // } x += width; return x; } bool KDSWidget::turnonSpecifiedOutput(const KScreen::OutputPtr &output, int x, int y){ output->setEnabled(true); output->setCurrentModeId(output.data()->preferredModeId()); output->setRotation(KScreen::Output::None); output->setPos(QPoint(x, y)); return true; } QSize KDSWidget::findBestCloneSize(){ const KScreen::ConfigPtr &config = this->currentConfig(); QMap commonSizes; Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { QList pSizes; Q_FOREACH (const KScreen::ModePtr &mode, output->modes()) { QSize s = mode.data()->size(); if (pSizes.contains(s)) continue; pSizes.append(s); if (commonSizes.contains(s)){ commonSizes[s]++; } else { commonSizes.insert(s, 1); } } } QList commonResults = commonSizes.keys(config->connectedOutputs().count()); QSize smallestSize; /* TODO: */ if (commonSizes.isEmpty()){ // Q_FOREACH (const KScreen::OutputPtr &output, config->connectedOutputs()) { // if (!smallestSize.isValid() || output->preferredMode()->size() < smallestSize) { // smallestSize = output->preferredMode()->size(); // } // } } else { Q_FOREACH(QSize s1, commonResults){ if (!smallestSize.isValid() || smallestSize < s1){ smallestSize = s1; } } } return smallestSize; } void KDSWidget::nextSelectedOption(){ int current = btnsGroup->checkedId(); int next; /* no button checked */ // if (current == -1) // ; next = current == ALLMODES - 1 ? 0 : current + 1; ExpendButton * btn = dynamic_cast(btnsGroup->button(next)); btn->setChecked(true); } void KDSWidget::lastSelectedOption(){ int current = btnsGroup->checkedId(); int last; /* no button checked */ if (current == -1) current = ALLMODES; last = current == 0 ? ALLMODES - 1 : current - 1; ExpendButton * btn = dynamic_cast(btnsGroup->button(last)); btn->setChecked(true); } void KDSWidget::confirmCurrentOption(){ int current = btnsGroup->checkedId(); // qDebug() << "current checked" << current; if (current == -1) return; ExpendButton * btn = dynamic_cast(btnsGroup->button(current)); btn->click(); } void KDSWidget::closeApp(){ close(); } void KDSWidget::receiveButtonClick(int x, int y){ // qDebug() << "receive button press " << x << y; if (!this->geometry().contains(x, y)){ close(); } } void KDSWidget::msgReceiveAnotherOne(const QString &msg){ // qDebug() << "another one " << msg; nextSelectedOption(); } void KDSWidget::syncPrimaryScreenData(QString pName){ if (!pName.isEmpty()){ const KScreen::ConfigPtr &config = this->currentConfig(); int scale = getCurrentScale(); Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { if (QString::compare(output.data()->name(), pName) == 0){ QRect rect = output.data()->geometry(); QDBusMessage message = QDBusMessage::createMethodCall("org.ukui.SettingsDaemon", "/org/ukui/SettingsDaemon/wayland", "org.ukui.SettingsDaemon.wayland", "priScreenChanged"); message << rect.x() / scale << rect.y() / scale << rect.width() / scale << rect.height() / scale << pName; QDBusConnection::sessionBus().send(message); } } } } ukui-settings-daemon/plugins/kds/qtlockedfile/0000755000175000017500000000000014205117202020454 5ustar fengfengukui-settings-daemon/plugins/kds/qtlockedfile/qtlockedfile.cpp0000644000175000017500000001110714205117202023626 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "qtlockedfile.h" //namespace SharedTools { /*! \class QtLockedFile \brief The QtLockedFile class extends QFile with advisory locking functions. A file may be locked in read or write mode. Multiple instances of \e QtLockedFile, created in multiple processes running on the same machine, may have a file locked in read mode. Exactly one instance may have it locked in write mode. A read and a write lock cannot exist simultaneously on the same file. The file locks are advisory. This means that nothing prevents another process from manipulating a locked file using QFile or file system functions offered by the OS. Serialization is only guaranteed if all processes that access the file use QtLockedFile. Also, while holding a lock on a file, a process must not open the same file again (through any API), or locks can be unexpectedly lost. The lock provided by an instance of \e QtLockedFile is released whenever the program terminates. This is true even when the program crashes and no destructors are called. */ /*! \enum QtLockedFile::LockMode This enum describes the available lock modes. \value ReadLock A read lock. \value WriteLock A write lock. \value NoLock Neither a read lock nor a write lock. */ /*! Constructs an unlocked \e QtLockedFile object. This constructor behaves in the same way as \e QFile::QFile(). \sa QFile::QFile() */ QtLockedFile::QtLockedFile() : QFile() { #ifdef Q_OS_WIN m_semaphore_hnd = 0; m_mutex_hnd = 0; #endif m_lock_mode = NoLock; } /*! Constructs an unlocked QtLockedFile object with file \a name. This constructor behaves in the same way as \e QFile::QFile(const QString&). \sa QFile::QFile() */ QtLockedFile::QtLockedFile(const QString &name) : QFile(name) { #ifdef Q_OS_WIN m_semaphore_hnd = 0; m_mutex_hnd = 0; #endif m_lock_mode = NoLock; } /*! Returns \e true if this object has a in read or write lock; otherwise returns \e false. \sa lockMode() */ bool QtLockedFile::isLocked() const { return m_lock_mode != NoLock; } /*! Returns the type of lock currently held by this object, or \e QtLockedFile::NoLock. \sa isLocked() */ QtLockedFile::LockMode QtLockedFile::lockMode() const { return m_lock_mode; } /*! \fn bool QtLockedFile::lock(LockMode mode, bool block = true) Obtains a lock of type \a mode. If \a block is true, this function will block until the lock is acquired. If \a block is false, this function returns \e false immediately if the lock cannot be acquired. If this object already has a lock of type \a mode, this function returns \e true immediately. If this object has a lock of a different type than \a mode, the lock is first released and then a new lock is obtained. This function returns \e true if, after it executes, the file is locked by this object, and \e false otherwise. \sa unlock(), isLocked(), lockMode() */ /*! \fn bool QtLockedFile::unlock() Releases a lock. If the object has no lock, this function returns immediately. This function returns \e true if, after it executes, the file is not locked by this object, and \e false otherwise. \sa lock(), isLocked(), lockMode() */ /*! \fn QtLockedFile::~QtLockedFile() Destroys the \e QtLockedFile object. If any locks were held, they are released. */ //} // namespace SharedTools ukui-settings-daemon/plugins/kds/qtlockedfile/qtlockedfile_win.cpp0000644000175000017500000001403314205117202024504 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "qtlockedfile.h" #include #include //namespace SharedTools { #define SEMAPHORE_PREFIX "QtLockedFile semaphore " #define MUTEX_PREFIX "QtLockedFile mutex " #define SEMAPHORE_MAX 100 static QString errorCodeToString(DWORD errorCode) { QString result; char *data = 0; FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, errorCode, 0, (char*)&data, 0, 0); result = QString::fromLocal8Bit(data); if (data != 0) LocalFree(data); if (result.endsWith(QLatin1Char('\n'))) result.truncate(result.length() - 1); return result; } bool QtLockedFile::lock(LockMode mode, bool block) { if (!isOpen()) { qWarning("QtLockedFile::lock(): file is not opened"); return false; } if (mode == m_lock_mode) return true; if (m_lock_mode != 0) unlock(); if (m_semaphore_hnd == 0) { QFileInfo fi(*this); QString sem_name = QString::fromLatin1(SEMAPHORE_PREFIX) + fi.absoluteFilePath().toLower(); m_semaphore_hnd = CreateSemaphoreW(0, SEMAPHORE_MAX, SEMAPHORE_MAX, (TCHAR*)sem_name.utf16()); if (m_semaphore_hnd == 0) { qWarning("QtLockedFile::lock(): CreateSemaphore: %s", errorCodeToString(GetLastError()).toLatin1().constData()); return false; } } bool gotMutex = false; int decrement; if (mode == ReadLock) { decrement = 1; } else { decrement = SEMAPHORE_MAX; if (m_mutex_hnd == 0) { QFileInfo fi(*this); QString mut_name = QString::fromLatin1(MUTEX_PREFIX) + fi.absoluteFilePath().toLower(); m_mutex_hnd = CreateMutexW(NULL, FALSE, (TCHAR*)mut_name.utf16()); if (m_mutex_hnd == 0) { qWarning("QtLockedFile::lock(): CreateMutex: %s", errorCodeToString(GetLastError()).toLatin1().constData()); return false; } } DWORD res = WaitForSingleObject(m_mutex_hnd, block ? INFINITE : 0); if (res == WAIT_TIMEOUT) return false; if (res == WAIT_FAILED) { qWarning("QtLockedFile::lock(): WaitForSingleObject (mutex): %s", errorCodeToString(GetLastError()).toLatin1().constData()); return false; } gotMutex = true; } for (int i = 0; i < decrement; ++i) { DWORD res = WaitForSingleObject(m_semaphore_hnd, block ? INFINITE : 0); if (res == WAIT_TIMEOUT) { if (i) { // A failed nonblocking rw locking. Undo changes to semaphore. if (ReleaseSemaphore(m_semaphore_hnd, i, NULL) == 0) { qWarning("QtLockedFile::unlock(): ReleaseSemaphore: %s", errorCodeToString(GetLastError()).toLatin1().constData()); // Fall through } } if (gotMutex) ReleaseMutex(m_mutex_hnd); return false; } if (res != WAIT_OBJECT_0) { if (gotMutex) ReleaseMutex(m_mutex_hnd); qWarning("QtLockedFile::lock(): WaitForSingleObject (semaphore): %s", errorCodeToString(GetLastError()).toLatin1().constData()); return false; } } m_lock_mode = mode; if (gotMutex) ReleaseMutex(m_mutex_hnd); return true; } bool QtLockedFile::unlock() { if (!isOpen()) { qWarning("QtLockedFile::unlock(): file is not opened"); return false; } if (!isLocked()) return true; int increment; if (m_lock_mode == ReadLock) increment = 1; else increment = SEMAPHORE_MAX; DWORD ret = ReleaseSemaphore(m_semaphore_hnd, increment, 0); if (ret == 0) { qWarning("QtLockedFile::unlock(): ReleaseSemaphore: %s", errorCodeToString(GetLastError()).toLatin1().constData()); return false; } m_lock_mode = QtLockedFile::NoLock; remove(); return true; } QtLockedFile::~QtLockedFile() { if (isOpen()) unlock(); if (m_mutex_hnd != 0) { DWORD ret = CloseHandle(m_mutex_hnd); if (ret == 0) { qWarning("QtLockedFile::~QtLockedFile(): CloseHandle (mutex): %s", errorCodeToString(GetLastError()).toLatin1().constData()); } m_mutex_hnd = 0; } if (m_semaphore_hnd != 0) { DWORD ret = CloseHandle(m_semaphore_hnd); if (ret == 0) { qWarning("QtLockedFile::~QtLockedFile(): CloseHandle (semaphore): %s", errorCodeToString(GetLastError()).toLatin1().constData()); } m_semaphore_hnd = 0; } } //} // namespace SharedTools ukui-settings-daemon/plugins/kds/qtlockedfile/qtlockedfile_unix.cpp0000644000175000017500000000523114205117202024672 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "qtlockedfile.h" #include #include #include #include //namespace SharedTools { bool QtLockedFile::lock(LockMode mode, bool block) { if (!isOpen()) { qWarning("QtLockedFile::lock(): file is not opened"); return false; } if (mode == NoLock) return unlock(); if (mode == m_lock_mode) return true; if (m_lock_mode != NoLock) unlock(); struct flock fl; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK; int cmd = block ? F_SETLKW : F_SETLK; int ret = fcntl(handle(), cmd, &fl); if (ret == -1) { if (errno != EINTR && errno != EAGAIN) qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); return false; } m_lock_mode = mode; return true; } bool QtLockedFile::unlock() { if (!isOpen()) { qWarning("QtLockedFile::unlock(): file is not opened"); return false; } if (!isLocked()) return true; struct flock fl; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_type = F_UNLCK; int ret = fcntl(handle(), F_SETLKW, &fl); if (ret == -1) { qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); return false; } m_lock_mode = NoLock; remove(); return true; } QtLockedFile::~QtLockedFile() { if (isOpen()) unlock(); } //} // namespace SharedTools ukui-settings-daemon/plugins/kds/qtlockedfile/qtlockedfile.h0000644000175000017500000000427614205117202023304 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #pragma once #include #if defined(Q_OS_WIN) # if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT) # define QT_QTLOCKEDFILE_EXPORT # elif defined(QT_QTLOCKEDFILE_IMPORT) # if defined(QT_QTLOCKEDFILE_EXPORT) # undef QT_QTLOCKEDFILE_EXPORT # endif # define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport) # elif defined(QT_QTLOCKEDFILE_EXPORT) # undef QT_QTLOCKEDFILE_EXPORT # define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport) # endif #else # define QT_QTLOCKEDFILE_EXPORT #endif //namespace SharedTools { class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile { public: enum LockMode { NoLock = 0, ReadLock, WriteLock }; QtLockedFile(); QtLockedFile(const QString &name); ~QtLockedFile(); bool lock(LockMode mode, bool block = true); bool unlock(); bool isLocked() const; LockMode lockMode() const; private: #ifdef Q_OS_WIN Qt::HANDLE m_semaphore_hnd; Qt::HANDLE m_mutex_hnd; #endif LockMode m_lock_mode; }; //} // namespace SharedTools ukui-settings-daemon/plugins/kds/qtlockedfile/namespace.patch0000644000175000017500000000246214205117202023435 0ustar fengfeng --- qtlockedfile.cpp 1970-01-01 01:00:00.000000000 +++ qtlockedfile.cpp 2008/05/16 10:51:19.000000000 @@ -1,5 +1,7 @@ #include "qtlockedfile.h" +namespace SharedTools { + /*! \class QtLockedFile @@ -123,3 +125,5 @@ Destroys the \e QtLockedFile object. If any locks were held, they are released. */ + +} --- qtlockedfile.h 1970-01-01 01:00:00.000000000 +++ qtlockedfile.h 2008/05/16 10:51:19.000000000 @@ -19,6 +19,8 @@ # define QT_QTLOCKEDFILE_EXPORT #endif +namespace SharedTools { + class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile { public: @@ -41,4 +43,6 @@ LockMode m_lock_mode; }; +} + #endif --- qtlockedfile_unix.cpp 1970-01-01 01:00:00.000000000 +++ qtlockedfile_unix.cpp 2008/05/16 10:51:19.000000000 @@ -5,6 +5,8 @@ #include "qtlockedfile.h" +namespace SharedTools { + bool QtLockedFile::lock(LockMode mode, bool block) { if (!isOpen()) { @@ -73,3 +75,4 @@ unlock(); } +} --- qtlockedfile_win.cpp 1970-01-01 01:00:00.000000000 +++ qtlockedfile_win.cpp 2008/05/16 10:51:19.000000000 @@ -2,6 +2,8 @@ #include #include +namespace SharedTools { + #define SEMAPHORE_PREFIX "QtLockedFile semaphore " #define MUTEX_PREFIX "QtLockedFile mutex " #define SEMAPHORE_MAX 100 @@ -168,3 +170,4 @@ } } +} ukui-settings-daemon/plugins/kds/qtlockedfile/README.txt0000644000175000017500000000041514205117202022152 0ustar fengfengThis is the src directory of the QtLockedFile solution integrated over from addons/main/utils/qtlockedfile/src . namespace.patch was applied to introduce the SharedTools namespace. It is required by the QtSingleApplication solution. History: 16.05.2008 Integrated ukui-settings-daemon/plugins/kds/qtlockedfile/qtlockedfile.pri0000644000175000017500000000047614205117202023645 0ustar fengfengINCLUDEPATH += $$PWD DEPENDPATH += $$PWD HEADERS += $$PWD/qtlockedfile.h SOURCES += $$PWD/qtlockedfile.cpp unix:SOURCES += $$PWD/qtlockedfile_unix.cpp win32:SOURCES += $$PWD/qtlockedfile_win.cpp win32:contains(TEMPLATE, lib):contains(CONFIG, shared) { DEFINES += QT_QTLOCKEDFILE_EXPORT=__declspec(dllexport) } ukui-settings-daemon/plugins/kds/widget.h0000644000175000017500000000511314205117202017442 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright (C) 2019 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 WIDGET_H #define WIDGET_H #include #include #include #include #include "usd_base_class.h" #ifdef signals #undef signals #endif extern "C" { #define MATE_DESKTOP_USE_UNSTABLE_API #include #include #include #include } class QDBusInterface; namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); public: void beginSetup(); void initData(); void setupComponent(); void setupConnect(); void setScreenModeByDbus(QString modeName); int getCurrentStatus(); QString getScreensParam(); void initCurrentStatus(int id); private: Ui::Widget *ui; QButtonGroup *btnsGroup; QMetaEnum metaEnum; private: MateRRScreen * kScreen; // MateRRConfig * kConfig; bool m_superPresss; QGSettings *m_scaleSetting; QGSettings *m_styleSettings; QString m_qssDefaultOrDark; QString m_qssLight; double m_scale; protected: void keyPressEvent(QKeyEvent *event); void paintEvent(QPaintEvent *event); void showEvent(QShowEvent* event); public Q_SLOTS: void XkbButtonEvent(int,int); void msgReceiveAnotherOne(const QString &msg); void geometryChangedHandle(); void screensParamChangedSignal(QString screensParam); private: private Q_SLOTS: void nextSelectedOption(); void lastSelectedOption(); void confirmCurrentOption(); void receiveButtonClick(int x, int y); void closeApp(); Q_SIGNALS: void tellBtnClicked(int id); }; #endif // WIDGET_H ukui-settings-daemon/plugins/kds/kdswidget.ui0000644000175000017500000001375414205117202020344 0ustar fengfeng KDSWidget 0 0 535 512 Form 0 0 0 0 0 0 98 16777215 98 QFrame::StyledPanel QFrame::Raised 3 0 0 0 0 Qt::Vertical 20 40 0 0 System Screen Projection 3 Qt::Horizontal 40 20 0 0 FirstOutput: 0 0 0 0 Qt::Horizontal 40 20 Qt::Vertical 20 40 0 0 1 16777215 1 QFrame::StyledPanel QFrame::Raised 0 30 QFrame::StyledPanel QFrame::Raised ukui-settings-daemon/plugins/kds/widget.ui0000644000175000017500000001305014205117202017627 0ustar fengfeng Widget 0 0 400 460 KDS 0 0 0 0 0 0 98 16777215 98 0 0 0 0 0 0 Qt::Vertical 20 40 0 0 System Screen Projection 8 Qt::Horizontal 40 20 0 0 FirstOutput: 0 0 0 0 Qt::Horizontal 40 20 Qt::Vertical QSizePolicy::Fixed 20 10 0 ukui-settings-daemon/plugins/kds/kdswidget.h0000644000175000017500000000471614205117202020154 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef KDSWIDGET_H #define KDSWIDGET_H #include #include #include #include #include #include #include #include namespace Ui { class KDSWidget; } class KDSWidget : public QWidget { Q_OBJECT public: explicit KDSWidget(QWidget *parent = nullptr); ~KDSWidget(); void beginSetupKF5(); QPoint getWinPos(); QString getCurrentPrimaryScreenName(); int getCurrentScale(); void setupComponent(); void setupConnect(); int getCurrentStatus(); void setCurrentUIStatus(int id); void setCurrentFirstOutputTip(); void syncPrimaryScreenData(QString pName); public: void setConfig(const KScreen::ConfigPtr &config); KScreen::ConfigPtr currentConfig() const; void setCloneModeSetup(); void setExtendModeSetup(); void setFirstModeSetup(); void setOtherModeSetup(); void setLeftExtendModeSetup(); private: QString findFirstOutput(); QSize findBestCloneSize(); bool turnonSpecifiedOutput(const KScreen::OutputPtr &output, int x, int y); int turnonAndGetRightmostOffset(const KScreen::OutputPtr &output, int x); private: Ui::KDSWidget *ui; QButtonGroup * btnsGroup; private: KScreen::ConfigPtr mConfig = nullptr; public Q_SLOTS: void msgReceiveAnotherOne(const QString &msg); void nextSelectedOption(); void lastSelectedOption(); void confirmCurrentOption(); void receiveButtonClick(int x, int y); void closeApp(); Q_SIGNALS: void tellBtnClicked(int id); }; #endif // KDSWIDGET_H ukui-settings-daemon/plugins/kds/qtsingleapplication/0000755000175000017500000000000014205117202022060 5ustar fengfengukui-settings-daemon/plugins/kds/qtsingleapplication/qtlocalpeer.cpp0000644000175000017500000001365414205117202025110 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "qtlocalpeer.h" #include #include #include #if defined(Q_OS_WIN) #include #include typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*); static PProcessIdToSessionId pProcessIdToSessionId = 0; #endif #if defined(Q_OS_UNIX) #include #include #endif //namespace SharedTools { static const char ack[] = "ack"; QString QtLocalPeer::appSessionId(const QString &appId) { QByteArray idc = appId.toUtf8(); quint16 idNum = qChecksum(idc.constData(), idc.size()); //### could do: two 16bit checksums over separate halves of id, for a 32bit result - improved uniqeness probability. Every-other-char split would be best. QString res = QLatin1String("qtsingleapplication-") + QString::number(idNum, 16); #if defined(Q_OS_WIN) if (!pProcessIdToSessionId) { QLibrary lib(QLatin1String("kernel32")); pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId"); } if (pProcessIdToSessionId) { DWORD sessionId = 0; pProcessIdToSessionId(GetCurrentProcessId(), &sessionId); res += QLatin1Char('-') + QString::number(sessionId, 16); } #else res += QLatin1Char('-') + QString::number(::getuid(), 16); #endif return res; } QtLocalPeer::QtLocalPeer(QObject *parent, const QString &appId) : QObject(parent), id(appId) { if (id.isEmpty()) id = QCoreApplication::applicationFilePath(); //### On win, check if this returns .../argv[0] without casefolding; .\MYAPP == .\myapp on Win socketName = appSessionId(id); server = new QLocalServer(this); QString lockName = QDir(QDir::tempPath()).absolutePath() + QLatin1Char('/') + socketName + QLatin1String("-lockfile"); lockFile.setFileName(lockName); lockFile.open(QIODevice::ReadWrite); } bool QtLocalPeer::isClient() { if (lockFile.isLocked()) return false; if (!lockFile.lock(QtLockedFile::WriteLock, false)) return true; if (!QLocalServer::removeServer(socketName)) qWarning("QtSingleCoreApplication: could not cleanup socket"); bool res = server->listen(socketName); if (!res) qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString())); QObject::connect(server, &QLocalServer::newConnection, this, &QtLocalPeer::receiveConnection); return false; } bool QtLocalPeer::sendMessage(const QString &message, int timeout, bool block) { if (!isClient()) return false; QLocalSocket socket; bool connOk = false; for (int i = 0; i < 2; i++) { // Try twice, in case the other instance is just starting up socket.connectToServer(socketName); connOk = socket.waitForConnected(timeout/2); if (connOk || i) break; int ms = 250; #if defined(Q_OS_WIN) Sleep(DWORD(ms)); #else struct timespec ts = {ms / 1000, (ms % 1000) * 1000 * 1000}; nanosleep(&ts, NULL); #endif } if (!connOk) return false; QByteArray uMsg(message.toUtf8()); QDataStream ds(&socket); ds.writeBytes(uMsg.constData(), uMsg.size()); bool res = socket.waitForBytesWritten(timeout); res &= socket.waitForReadyRead(timeout); // wait for ack res &= (socket.read(qstrlen(ack)) == ack); if (block) // block until peer disconnects socket.waitForDisconnected(-1); return res; } void QtLocalPeer::receiveConnection() { QLocalSocket* socket = server->nextPendingConnection(); if (!socket) return; // Why doesn't Qt have a blocking stream that takes care of this shait??? while (socket->bytesAvailable() < static_cast(sizeof(quint32))) { if (!socket->isValid()) // stale request return; socket->waitForReadyRead(1000); } QDataStream ds(socket); QByteArray uMsg; quint32 remaining; ds >> remaining; uMsg.resize(remaining); int got = 0; char* uMsgBuf = uMsg.data(); //qDebug() << "RCV: remaining" << remaining; do { got = ds.readRawData(uMsgBuf, remaining); remaining -= got; uMsgBuf += got; //qDebug() << "RCV: got" << got << "remaining" << remaining; } while (remaining && got >= 0 && socket->waitForReadyRead(2000)); //### error check: got<0 if (got < 0) { qWarning() << "QtLocalPeer: Message reception failed" << socket->errorString(); delete socket; return; } // ### async this QString message = QString::fromUtf8(uMsg.constData(), uMsg.size()); socket->write(ack, qstrlen(ack)); socket->waitForBytesWritten(1000); Q_EMIT messageReceived(message, socket); // ##(might take a long time to return) } //} // namespace SharedTools ukui-settings-daemon/plugins/kds/qtsingleapplication/qtlocalpeer.h0000644000175000017500000000356114205117202024551 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include #include #include #include //namespace SharedTools { class QtLocalPeer : public QObject { Q_OBJECT public: explicit QtLocalPeer(QObject *parent = 0, const QString &appId = QString()); bool isClient(); bool sendMessage(const QString &message, int timeout, bool block); QString applicationId() const { return id; } static QString appSessionId(const QString &appId); Q_SIGNALS: void messageReceived(const QString &message, QObject *socket); protected: void receiveConnection(); QString id; QString socketName; QLocalServer* server; QtLockedFile lockFile; }; //} // namespace SharedTools ukui-settings-daemon/plugins/kds/qtsingleapplication/qtsingleapplication.pri0000644000175000017500000000067114205117202026652 0ustar fengfengINCLUDEPATH += $$PWD DEPENDPATH += $$PWD HEADERS += $$PWD/qtsingleapplication.h $$PWD/qtlocalpeer.h SOURCES += $$PWD/qtsingleapplication.cpp $$PWD/qtlocalpeer.cpp QT *= network widgets gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h) isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri) win32:contains(TEMPLATE, lib):contains(CONFIG, shared) { DEFINES += QT_QTSINGLEAPPLICATION_EXPORT=__declspec(dllexport) } ukui-settings-daemon/plugins/kds/qtsingleapplication/qtsingleapplication.h0000644000175000017500000000422114205117202026302 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include QT_FORWARD_DECLARE_CLASS(QSharedMemory) //namespace SharedTools { class QtLocalPeer; class QtSingleApplication : public QApplication { Q_OBJECT public: QtSingleApplication(const QString &id, int &argc, char **argv); ~QtSingleApplication(); bool isRunning(qint64 pid = -1); void setActivationWindow(QWidget* aw, bool activateOnMessage = true); QWidget* activationWindow() const; bool event(QEvent *event); QString applicationId() const; void setBlock(bool value); bool sendMessage(const QString &message, int timeout = 5000, qint64 pid = -1); void activateWindow(); Q_SIGNALS: void messageReceived(const QString &message, QObject *socket); void fileOpenRequest(const QString &file); private: QString instancesFileName(const QString &appId); qint64 firstPeer; QSharedMemory *instances; QtLocalPeer *pidPeer; QWidget *actWin; QString appId; bool block; }; //} // namespace SharedTools ukui-settings-daemon/plugins/kds/qtsingleapplication/namespace.patch0000644000175000017500000000600414205117202025035 0ustar fengfeng --- qtlocalpeer.cpp 1970-01-01 01:00:00.000000000 +++ qtlocalpeer.cpp 2008/05/16 10:36:53.000000000 @@ -13,6 +13,8 @@ #include #endif +namespace SharedTools { + const char* QtLocalPeer::ack = "ack"; QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId) @@ -139,3 +141,5 @@ delete socket; emit messageReceived(message); // ##(might take a long time to return) } + +} --- qtlocalpeer.h 1970-01-01 01:00:00.000000000 +++ qtlocalpeer.h 2008/05/16 10:36:53.000000000 @@ -1,9 +1,11 @@ + #include #include #include #include +namespace SharedTools { class QtLocalPeer : public QObject { @@ -31,3 +33,5 @@ private: static const char* ack; }; + +} // SharedTools --- qtsingleapplication.cpp 1970-01-01 01:00:00.000000000 +++ qtsingleapplication.cpp 2008/05/16 10:36:53.000000000 @@ -3,6 +3,8 @@ #include "qtlocalpeer.h" #include +namespace SharedTools { + void QtSingleApplication::sysInit(const QString &appId) { actWin = 0; @@ -95,3 +97,5 @@ actWin->activateWindow(); } } + +} --- qtsingleapplication.h 1970-01-01 01:00:00.000000000 +++ qtsingleapplication.h 2008/05/16 10:36:53.000000000 @@ -1,6 +1,8 @@ #include +namespace SharedTools { + class QtLocalPeer; class QtSingleApplication : public QApplication @@ -47,3 +49,5 @@ QtLocalPeer *peer; QWidget *actWin; }; + +} --- qtsingleapplication.pri 1970-01-01 01:00:00.000000000 +++ qtsingleapplication.pri 2008/05/16 10:36:53.000000000 @@ -6,7 +6,7 @@ QT *= network gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h) -isEmpty(gotqtlockedfile):include(../../qtlockedfile/src/qtlockedfile.pri) +isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri) win32:contains(TEMPLATE, lib):contains(CONFIG, shared) { --- qtsinglecoreapplication.cpp 1970-01-01 01:00:00.000000000 +++ qtsinglecoreapplication.cpp 2008/05/16 10:36:53.000000000 @@ -2,6 +2,7 @@ #include "qtsinglecoreapplication.h" #include "qtlocalpeer.h" +namespace SharedTools { QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv) : QCoreApplication(argc, argv) @@ -36,3 +37,4 @@ return peer->applicationId(); } +} --- qtsinglecoreapplication.h 1970-01-01 01:00:00.000000000 +++ qtsinglecoreapplication.h 2008/05/16 10:36:53.000000000 @@ -1,6 +1,8 @@ #include +namespace SharedTools { + class QtLocalPeer; class QtSingleCoreApplication : public QCoreApplication @@ -25,3 +27,5 @@ private: QtLocalPeer* peer; }; + +} --- qtsinglecoreapplication.pri 1970-01-01 01:00:00.000000000 +++ qtsinglecoreapplication.pri 2008/05/16 10:36:53.000000000 @@ -6,7 +6,7 @@ QT *= network gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h) -isEmpty(gotqtlockedfile):include(../../qtlockedfile/src/qtlockedfile.pri) +isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri) win32:contains(TEMPLATE, lib):contains(CONFIG, shared) { ukui-settings-daemon/plugins/kds/qtsingleapplication/qtsingleapplication.cpp0000644000175000017500000001333314205117202026641 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "qtsingleapplication.h" #include "qtlocalpeer.h" #include #include #include #include #include //namespace SharedTools { static const int instancesSize = 1024; static QString instancesLockFilename(const QString &appSessionId) { const QChar slash(QLatin1Char('/')); QString res = QDir::tempPath(); if (!res.endsWith(slash)) res += slash; return res + appSessionId + QLatin1String("-instances"); } QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv) : QApplication(argc, argv), firstPeer(-1), pidPeer(0) { this->appId = appId; const QString appSessionId = QtLocalPeer::appSessionId(appId); // This shared memory holds a zero-terminated array of active (or crashed) instances instances = new QSharedMemory(appSessionId, this); actWin = 0; block = false; // First instance creates the shared memory, later instances attach to it const bool created = instances->create(instancesSize); if (!created) { if (!instances->attach()) { qWarning() << "Failed to initialize instances shared memory: " << instances->errorString(); delete instances; instances = 0; return; } } // QtLockedFile is used to workaround QTBUG-10364 QtLockedFile lockfile(instancesLockFilename(appSessionId)); lockfile.open(QtLockedFile::ReadWrite); lockfile.lock(QtLockedFile::WriteLock); qint64 *pids = static_cast(instances->data()); if (!created) { // Find the first instance that it still running // The whole list needs to be iterated in order to append to it for (; *pids; ++pids) { if (firstPeer == -1 && isRunning(*pids)) firstPeer = *pids; } } // Add current pid to list and terminate it *pids++ = QCoreApplication::applicationPid(); *pids = 0; pidPeer = new QtLocalPeer(this, appId + QLatin1Char('-') + QString::number(QCoreApplication::applicationPid())); connect(pidPeer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::messageReceived); pidPeer->isClient(); lockfile.unlock(); } QtSingleApplication::~QtSingleApplication() { if (!instances) return; const qint64 appPid = QCoreApplication::applicationPid(); QtLockedFile lockfile(instancesLockFilename(QtLocalPeer::appSessionId(appId))); lockfile.open(QtLockedFile::ReadWrite); lockfile.lock(QtLockedFile::WriteLock); // Rewrite array, removing current pid and previously crashed ones qint64 *pids = static_cast(instances->data()); qint64 *newpids = pids; for (; *pids; ++pids) { if (*pids != appPid && isRunning(*pids)) *newpids++ = *pids; } *newpids = 0; lockfile.unlock(); } bool QtSingleApplication::event(QEvent *event) { if (event->type() == QEvent::FileOpen) { QFileOpenEvent *foe = static_cast(event); Q_EMIT fileOpenRequest(foe->file()); return true; } return QApplication::event(event); } bool QtSingleApplication::isRunning(qint64 pid) { if (pid == -1) { pid = firstPeer; if (pid == -1) return false; } QtLocalPeer peer(this, appId + QLatin1Char('-') + QString::number(pid, 10)); return peer.isClient(); } bool QtSingleApplication::sendMessage(const QString &message, int timeout, qint64 pid) { if (pid == -1) { pid = firstPeer; if (pid == -1) return false; } QtLocalPeer peer(this, appId + QLatin1Char('-') + QString::number(pid, 10)); return peer.sendMessage(message, timeout, block); } QString QtSingleApplication::applicationId() const { return appId; } void QtSingleApplication::setBlock(bool value) { block = value; } void QtSingleApplication::setActivationWindow(QWidget *aw, bool activateOnMessage) { actWin = aw; if (!pidPeer) return; if (activateOnMessage) connect(pidPeer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow); else disconnect(pidPeer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow); } QWidget* QtSingleApplication::activationWindow() const { return actWin; } void QtSingleApplication::activateWindow() { if (actWin) { actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized); actWin->raise(); actWin->activateWindow(); } } //} // namespace SharedTools ukui-settings-daemon/plugins/kds/qtsingleapplication/README.txt0000644000175000017500000000043214205117202023555 0ustar fengfengThis is the src directory of the QtSingleApplication solution integrated over from addons/main/utils/qtsingleapplication/src . namespace.patch was applied to introduce the SharedTools namespace. It additionally requires the QtLockedFile solution. History: 16.05.2008 Integrated ukui-settings-daemon/plugins/kds/res/0000755000175000017500000000000014205117202016577 5ustar fengfengukui-settings-daemon/plugins/kds/res/zh_CN.qm0000644000175000017500000000156414205117202020145 0ustar fengfengV>sr8r `O. `OiY R6 Clone Screen KDSWidgetNf>y:{,N\O^U Extend Screen KDSWidgetNf>y:u5\O^U First Screen KDSWidget {,N\O^U FirstOutput: KDSWidgetN/AN/A KDSWidget|~b\OSystem Screen Projection KDSWidgetNf>y:{,N\O^U Vice Screen KDSWidget\P Clone ScreenWidgetbi\U Extend ScreenWidgetNf>y:u5\O^U First ScreenWidget {,N\O^U FirstOutput:Widget|~b\OKDSWidgeteNoneWidget|~b\OSystem Screen ProjectionWidgetNf>y:{,N\O^U Vice ScreenWidgetukui-settings-daemon/plugins/kds/res/img/0000755000175000017500000000000014205117202017353 5ustar fengfengukui-settings-daemon/plugins/kds/res/img/main.png0000644000175000017500000000104714205117202021007 0ustar fengfengPNG  IHDR<<:r pHYs  ~IDATh횱Q02-Uh.*-#0B2iSlJ Lr,=Otib=~${BH$AF҉҉ R @@1bkiH9&5ٍLmC1/p\07AkKPwŵ29e+aɗAIgGQR[,Rٙ~+l5j3 @NY6ei\N9k)ݾCyX u圇9<\ݺ3 Kl/iZ)63ϰ>ەrT,Z7 W PGGŨ1ᮣ{/*||H)6+SZng8oذ_KnR KYL7TF-3*3T4֢S[xwԆ[ g,<8gX>{ 5}dxG[ܔ۴[KDaDaDaDaDaDaDa0iAIENDB`ukui-settings-daemon/plugins/kds/res/img/extend.png0000644000175000017500000000115114205117202021346 0ustar fengfengPNG  IHDR<<:r pHYs  ~IDAThZm }_olPoNPolPwz&dgtvw*ңEQb|y'㸃,RIpHcG;f)8[K^!siIO¥&v'SV3w\2@.µ`*s`i,(Ɉ|БqCLm !+*p5n-Ցߞ\X<={Ϲx}&,\h tiyҚ Nh;yB7Y`Œ)ԋ5K6"Vf [lL b>gtnZR=Bpolf_ZJGQa騰tTX:*, o.|yOIENDB`ukui-settings-daemon/plugins/kds/res/img/selected.png0000644000175000017500000000063114205117202021651 0ustar fengfengPNG  IHDRۥ`IDAT8+DQǿ (,D YK6RRb%% $)ȏFLrnxosλ{ΧMru1s\IYId@RZҢIrìo@wj6 L}5z&|-AB[``@h1[LY% 8H)mX2q-,,[;0Z%_)pU8]&Ș s$Yx0؋m('=pe3e*rQon9gذ@kOb{V)" <%v%髪#RãOIENDB`ukui-settings-daemon/plugins/kds/res/img/clone.png0000644000175000017500000000117614205117202021166 0ustar fengfengPNG  IHDR<<:r pHYs  ~0IDAThq0?_6NP6lP7(#8n8A=r"H $mw3|B0B`JO6O@w`}$#%amUKHl+[zʖ=?h\.,{;ܠ`ыآ] LR^J " J4"8گ#yK\Ce]g)+eW6.^'oowlÏLNK97g~g]kc7qo*I%b]Z KDSWidget System Screen Projection 系统投屏 FirstOutput: 第一屏幕: First Screen 仅显示电脑屏幕 Clone Screen 复制 Extend Screen 仅显示第二屏幕 Vice Screen 仅显示第二屏幕 N/A N/A Widget KDS 系统投屏 System Screen Projection 系统投屏 FirstOutput: 第一屏幕: First Screen 仅显示电脑屏幕 Clone Screen 镜像 Extend Screen 扩展 Vice Screen 仅显示第二屏幕 None ukui-settings-daemon/plugins/kds/res/img.qrc0000644000175000017500000000045314205117202020064 0ustar fengfeng img/clone.png img/extend.png img/main.png img/phone.png img/selected.png img/vice.png zh_CN.qm ukui-settings-daemon/plugins/kds/expendbutton.h0000644000175000017500000000306314205117202020700 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef EXPENDBUTTON_H #define EXPENDBUTTON_H #include #include #include #include class ExpendButton : public QPushButton { Q_OBJECT public: explicit ExpendButton(QWidget *parent = 0); ~ExpendButton(); public: void setSign(int id ,const QString &style = ""); void setBtnLogo(QString logo,const QString &style = ""); void setBtnText(QString text); void setBtnChecked(bool checked); bool getBtnChecked(); private: QPixmap drawLightColoredPixmap(const QPixmap &source, const QString &style); private: QLabel * logoLabel; QLabel * textLabel; QLabel * spaceLabel; QLabel * statusLabel; QGSettings *m_styleSettings; int sign; QString qss0; QString qss1; }; #endif // EXPENDBUTTON_H ukui-settings-daemon/plugins/kds/widget.cpp0000644000175000017500000003613114205117214020004 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright (C) 2019 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 "widget.h" #include "ui_widget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "expendbutton.h" #include "qtsingleapplication.h" #include "xeventmonitor.h" #include "clib-syslog.h" #define TITLEHEIGHT 90 #define OPTIONSHEIGHT 70 #define BOTTOMHEIGHT 38 #define XSETTINGS_SCHEMA "org.ukui.SettingsDaemon.plugins.xsettings" #define XSETTINGS_KEY_SCALING "scaling-factor" #define QT_THEME_SCHEMA "org.ukui.style" Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); m_superPresss = false; metaEnum = QMetaEnum::fromType(); QDBusInterface *screensChangedSignalHandle = new QDBusInterface(DBUS_XRANDR_NAME,DBUS_XRANDR_PATH,DBUS_XRANDR_INTERFACE,QDBusConnection::sessionBus(),this); if (screensChangedSignalHandle->isValid()) { connect(screensChangedSignalHandle, SIGNAL(screensParamChanged(QString)), this, SLOT(screensParamChangedSignal(QString))); //USD_LOG(LOG_DEBUG, ".."); } else { USD_LOG(LOG_ERR, "screensChangedSignalHandle"); } } Widget::~Widget() { delete ui; delete m_scaleSetting; } void Widget::screensParamChangedSignal(QString screensParam) { close(); } void Widget::beginSetup() { setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); this->setProperty("useStyleWindowManager", false); setAttribute(Qt::WA_TranslucentBackground, true); m_scaleSetting = new QGSettings(XSETTINGS_SCHEMA); m_scale = m_scaleSetting->get(XSETTINGS_KEY_SCALING).toDouble(); m_styleSettings = new QGSettings(QT_THEME_SCHEMA); /* 不在任务栏显示图标 */ KWindowSystem::setState(winId(), NET::SkipTaskbar | NET::SkipPager); QScreen * pScreen = QGuiApplication::screens().at(0); QPoint point = pScreen->geometry().center(); move(point.x() - width()/2, point.y() - height()/2); initData(); setupComponent(); setupConnect(); initCurrentStatus(getCurrentStatus()); connect(QApplication::primaryScreen(), &QScreen::geometryChanged, this, &Widget::geometryChangedHandle); connect(XEventMonitor::instance(), SIGNAL(buttonPress(int,int)),this, SLOT(XkbButtonEvent(int,int))); connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this,[&](WId activeWindowId) { if (activeWindowId != this->winId()) { close(); } }); XEventMonitor::instance()->start(); } void Widget::initData() { btnsGroup = new QButtonGroup; gtk_init(NULL, NULL); //Monitor init kScreen = mate_rr_screen_new (gdk_screen_get_default (), NULL); //kConfig = mate_rr_config_new_current (kScreen, NULL); } void Widget::setupComponent() { QStringList btnTextList; QStringList btnImageList; QJsonDocument parser; QString firstScreen = nullptr; QString secondScreen = nullptr; QString screensParam = getScreensParam(); QTextCodec *tc = QTextCodec::codecForName("UTF-8"); QVariantList screensParamList = parser.fromJson(screensParam.toUtf8().data()).toVariant().toList(); for (const auto &variantInfo : screensParamList) { const QVariantMap info = variantInfo.toMap(); const auto metadata = info[QStringLiteral("metadata")].toMap(); const QString outputName = metadata[QStringLiteral("name")].toString(); if (firstScreen.isEmpty()){ firstScreen = outputName; continue; } if (secondScreen.isEmpty()) { secondScreen = outputName; continue; } } if (secondScreen.isEmpty()) { secondScreen = "None"; } if (UsdBaseClass::isTablet()) { btnTextList<<"Clone Screen"; btnTextList<<"Extend Screen"; } else { btnTextList<setFixedWidth(384); this->setFixedHeight(TITLEHEIGHT + OPTIONSHEIGHT * btnTextList.length() + BOTTOMHEIGHT); const QString style = m_styleSettings->get("style-name").toString(); ui->outputPrimaryTip->hide(); for (int i = 0; i < btnTextList.length(); i++) { ExpendButton * btn = new ExpendButton(); btn->setFixedHeight(70); btnsGroup->addButton(btn, i); btn->setSign(i % 2,style); btn->setBtnText(tr(btnTextList[i].toLatin1().data())); btn->setBtnLogo(btnImageList[i],style); ui->btnsVerLayout->addWidget(btn); } m_qssDefaultOrDark = ("QWidget#titleWidget{background: transparent;}"\ "QWidget#bottomWidget{background: transparent; border: none;}"\ "QLabel#titleLabel{color: #FFFFFF;background: transparent; }"\ ); m_qssLight = ("QWidget#titleWidget{background: transparent; border: none;}"\ "QWidget#bottomWidget{background: transparent; border: none; }"\ "QLabel#titleLabel{color: #232426;background: transparent;}"\ ); /*跟随系统字体变化*/ int fontSize = m_styleSettings->get("system-font-size").toInt(); QFont font; font.setPointSize(fontSize + 4); ui->titleLabel->setFont(font); } void Widget::setupConnect() { connect(btnsGroup, static_cast(&QButtonGroup::buttonClicked), this, [=](int id) { /* 获取旧选项 */ for (QAbstractButton * button : btnsGroup->buttons()) { ExpendButton * btn = dynamic_cast(button); //qDebug() << "old index: " << btn->getBtnChecked(); int index = btnsGroup->id(button); if (index == id && btn->getBtnChecked()){ close(); } } //0,1 ->1,2 if (true == UsdBaseClass::isTablet()) { id += 2; } { QString mode = ""; switch (id) { case UsdBaseClass::eScreenMode::firstScreenMode: mode = metaEnum.key(UsdBaseClass::eScreenMode::firstScreenMode); break; case UsdBaseClass::eScreenMode::cloneScreenMode: mode = metaEnum.key(UsdBaseClass::eScreenMode::secondScreenMode); break; case UsdBaseClass::eScreenMode::extendScreenMode: mode = metaEnum.key(UsdBaseClass::eScreenMode::cloneScreenMode); break; case UsdBaseClass::eScreenMode::secondScreenMode: mode = metaEnum.key(UsdBaseClass::eScreenMode::extendScreenMode); break; default: break; } setScreenModeByDbus(mode); } close(); }); } QString Widget::getScreensParam() { QDBusMessage message = QDBusMessage::createMethodCall(DBUS_XRANDR_NAME, DBUS_XRANDR_PATH, DBUS_XRANDR_INTERFACE, DBUS_XRANDR_GET_SCREEN_PARAM); QList args; args.append(qAppName()); message.setArguments(args); QDBusMessage response = QDBusConnection::sessionBus().call(message); if (response.type() == QDBusMessage::ReplyMessage) { if(response.arguments().isEmpty() == false) { QString value = response.arguments().takeFirst().toString(); return value; } } else { USD_LOG(LOG_DEBUG, "called failed cuz:%s", message.errorName().toLatin1().data()); } return nullptr; } int Widget::getCurrentStatus() { QDBusMessage message = QDBusMessage::createMethodCall(DBUS_XRANDR_NAME, DBUS_XRANDR_PATH, DBUS_XRANDR_INTERFACE, DBUS_XRANDR_GET_MODE); QList args; args.append(qAppName()); message.setArguments(args); QDBusMessage response = QDBusConnection::sessionBus().call(message); if (response.type() == QDBusMessage::ReplyMessage) { if(response.arguments().isEmpty() == false) { int value = response.arguments().takeFirst().toInt(); USD_LOG(LOG_DEBUG, "get mode :%s", metaEnum.key(value)); //0,1,2,3==>>>0,2,3,1 switch (value) { case UsdBaseClass::eScreenMode::firstScreenMode: value = UsdBaseClass::eScreenMode::firstScreenMode; break; case UsdBaseClass::eScreenMode::cloneScreenMode: value = UsdBaseClass::eScreenMode::extendScreenMode; break; case UsdBaseClass::eScreenMode::extendScreenMode: value = UsdBaseClass::eScreenMode::secondScreenMode; break; case UsdBaseClass::eScreenMode::secondScreenMode: value = UsdBaseClass::eScreenMode::cloneScreenMode; break; default: break; } return value; } } else { USD_LOG(LOG_DEBUG, "called failed cuz:%s", message.errorName().toLatin1().data()); } return 0; } void Widget::initCurrentStatus(int id) { //set all no checked if(true == UsdBaseClass::isTablet()) { id -= 2; } for (QAbstractButton * button : btnsGroup->buttons()) { ExpendButton * btn = dynamic_cast(button); btn->setBtnChecked(false); if (id == btnsGroup->id(button)){ btn->setBtnChecked(true); btn->setChecked(true); } } if (id == -1){ ExpendButton * btn1 = dynamic_cast(btnsGroup->button(0)); btn1->setChecked(true); } } void Widget::geometryChangedHandle() { int x=QApplication::primaryScreen()->geometry().x(); int y=QApplication::primaryScreen()->geometry().y(); int width = QApplication::primaryScreen()->size().width(); int height = QApplication::primaryScreen()->size().height(); int ax,ay; ax = x+(width - this->width())/2; ay = y+(height - this->height())/2; move(ax,ay); } void Widget::nextSelectedOption() { int current = btnsGroup->checkedId(); int next; next = current == btnsGroup->buttons().count() - 1 ? 0 : current + 1; ExpendButton * btn = dynamic_cast(btnsGroup->button(next)); btn->setChecked(true); } void Widget::lastSelectedOption() { int current = btnsGroup->checkedId(); int last; /* no button checked */ if (current == -1) current = btnsGroup->buttons().count(); last = current == 0 ? btnsGroup->buttons().count() - 1 : current - 1; ExpendButton * btn = dynamic_cast(btnsGroup->button(last)); btn->setChecked(true); } void Widget::confirmCurrentOption() { int current = btnsGroup->checkedId(); if (current == -1) return; ExpendButton * btn = dynamic_cast(btnsGroup->button(current)); //btn->click(); btn->animateClick(); } void Widget::closeApp() { close(); } void Widget::setScreenModeByDbus(QString modeName) { QList args; if (modeName.isEmpty()) { return; } QDBusMessage message = QDBusMessage::createMethodCall(DBUS_XRANDR_NAME, DBUS_XRANDR_PATH, DBUS_XRANDR_INTERFACE, DBUS_XRANDR_SET_MODE); args.append(modeName); args.append(qAppName()); message.setArguments(args); QDBusConnection::sessionBus().send(message); } void Widget::msgReceiveAnotherOne(const QString &msg) { nextSelectedOption(); } void Widget::receiveButtonClick(int x, int y) { if (!this->geometry().contains(x, y)) { close(); } } void Widget::keyPressEvent(QKeyEvent* event) { switch (event->key()) { case Qt::Key_Up: lastSelectedOption(); break; case Qt::Key_Down: nextSelectedOption(); break; case Qt::Key_Return: case Qt::Key_Enter: confirmCurrentOption(); break; case Qt::Key_Meta: case Qt::Key_Super_L: break; default: close(); break; } } void Widget::XkbButtonEvent(int x,int y) { receiveButtonClick( x/m_scale, y/m_scale); } void Widget::showEvent(QShowEvent* event) { if(m_styleSettings->get("style-name").toString() == "ukui-light") { setStyleSheet(m_qssLight); setPalette(QPalette(QColor("#FFFFFF")));//设置窗口背景色 } else { setPalette(QPalette(QColor("#40232426")));//设置窗口背景色 setStyleSheet(m_qssDefaultOrDark); } } void Widget::paintEvent(QPaintEvent *event) { QRect rect = this->rect(); QPainterPath path; QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); //反锯齿; painter.setPen(Qt::transparent); qreal radius=24; path.moveTo(rect.topRight() - QPointF(radius, 0)); path.lineTo(rect.topLeft() + QPointF(radius, 0)); path.quadTo(rect.topLeft(), rect.topLeft() + QPointF(0, radius)); path.lineTo(rect.bottomLeft() + QPointF(0, -radius)); path.quadTo(rect.bottomLeft(), rect.bottomLeft() + QPointF(radius, 0)); path.lineTo(rect.bottomRight() - QPointF(radius, 0)); path.quadTo(rect.bottomRight(), rect.bottomRight() + QPointF(0, -radius)); path.lineTo(rect.topRight() + QPointF(0, radius)); path.quadTo(rect.topRight(), rect.topRight() + QPointF(-radius, -0)); painter.setBrush(this->palette().base()); painter.setPen(Qt::transparent); painter.setOpacity(0.75); painter.drawPath(path); KWindowEffects::enableBlurBehind(this->winId(), true, QRegion(path.toFillPolygon().toPolygon())); QWidget::paintEvent(event); } ukui-settings-daemon/plugins/kds/kds.pro0000644000175000017500000000376314205117202017322 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-11-12T15:37:31 # #------------------------------------------------- QT += core gui dbus network KWindowSystem KScreen greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = ukydisplayswitch TEMPLATE = app # The following define makes your compiler emit warnings if you use # any feature of Qt which as been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"KDS\\\" include (qtsingleapplication/qtsingleapplication.pri) LIBS += -lX11 -lgsettings-qt CONFIG += link_pkgconfig CONFIG += C++11 PKGCONFIG += mate-desktop-2.0 \ PKGCONFIG += glib-2.0 gio-2.0 libxklavier x11 xrandr xtst atk gdk-3.0 gtk+-3.0 xi # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 target.source += $$TARGET target.path = /usr/bin gsetting.files += ../conf/org.ukui.kds.gschema.xml gsetting.path = /usr/share/glib-2.0/schemas desktop.files += ../kylin-display-switch-daemon.desktop desktop.files += ../kylin-display-switch-mkt.desktop desktop.path = /etc/xdg/autostart/ service.files += ../conf/kylin-display-switch.service service.path = /usr/lib/systemd/system/ INSTALLS += \ target \ gsetting \ desktop \ service \ SOURCES += \ kdswidget.cpp \ main.cpp \ widget.cpp \ expendbutton.cpp HEADERS += \ kdswidget.h \ widget.h \ expendbutton.h FORMS += \ kdswidget.ui \ widget.ui RESOURCES += \ res/img.qrc TRANSLATIONS += \ res/zh_CN.ts \ include($$PWD/../../common/common.pri) ukui-settings-daemon/plugins/kds/main.cpp0000644000175000017500000000547514205117202017451 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright (C) 2019 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 "widget.h" #include "kdswidget.h" #include #include "qtsingleapplication.h" #include #include #include int getCurrentScreenWidth(){ Display * pDis = XOpenDisplay(0); if (NULL == pDis){ return 0; } Screen * pScreen = DefaultScreenOfDisplay(pDis); if (NULL == pScreen){ return 0; } int width = pScreen->width; XCloseDisplay(pDis); return width; } int main(int argc, char *argv[]) { if (getCurrentScreenWidth() > 2560){ QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); } QString id = QString("kds" + QLatin1String(getenv("DISPLAY"))); QtSingleApplication app(id, argc, argv); if (app.isRunning()){ app.sendMessage("hello world!"); return 0; /* EXIT_SUCCESS */ } QTranslator qtTranslator; qtTranslator.load(QString(":/%1").arg(QLocale::system().name())); app.installTranslator(&qtTranslator); KDSWidget kdsw; Widget w; QString sessionType = qgetenv("XDG_SESSION_TYPE"); if (QString::compare(sessionType, "wayland") == 0){ kdsw.beginSetupKF5(); // QObject::connect(&app, SIGNAL(messageReceived(const QString&, NULL)), &w, SLOT(msgReceiveAnotherOne(QString))); QObject::connect(&app, &QtSingleApplication::messageReceived, &kdsw, &KDSWidget::msgReceiveAnotherOne); kdsw.show(); } else { w.beginSetup(); // QObject::connect(&app, SIGNAL(messageReceived(const QString&, NULL)), &w, SLOT(msgReceiveAnotherOne(QString))); QObject::connect(&app, &QtSingleApplication::messageReceived, &w, &Widget::msgReceiveAnotherOne); QObject::connect(&app, &QtSingleApplication::screenAdded, &w, &Widget::geometryChangedHandle); QObject::connect(&app, &QtSingleApplication::screenRemoved, &w, &Widget::geometryChangedHandle); w.show(); } return app.exec(); } ukui-settings-daemon/plugins/kds/expendbutton.cpp0000644000175000017500000001170114205117202021231 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "expendbutton.h" #include #include #define QT_THEME_SCHEMA "org.ukui.style" ExpendButton::ExpendButton(QWidget *parent) : QPushButton(parent) { setFocusPolicy(Qt::NoFocus); setCheckable(true); setAttribute(Qt::WA_TranslucentBackground, true); m_styleSettings = new QGSettings(QT_THEME_SCHEMA); sign = 0; QHBoxLayout * generalHorLayout = new QHBoxLayout(this); generalHorLayout->setSpacing(0); generalHorLayout->setContentsMargins(44, 0, 20, 0); logoLabel = new QLabel(this); logoLabel->setFixedSize(QSize(60, 60)); textLabel = new QLabel(this); QSizePolicy textSizePolicy = textLabel->sizePolicy(); textSizePolicy.setHorizontalPolicy(QSizePolicy::Fixed); textSizePolicy.setVerticalPolicy(QSizePolicy::Fixed); textLabel->setSizePolicy(textSizePolicy); spaceLabel = new QLabel(this); spaceLabel->setFixedSize(QSize(24, 30)); statusLabel = new QLabel(this); statusLabel->setFixedSize(QSize(27, 18)); generalHorLayout->addWidget(logoLabel, Qt::AlignVCenter); generalHorLayout->addWidget(spaceLabel, Qt::AlignVCenter); generalHorLayout->addWidget(textLabel, Qt::AlignVCenter); generalHorLayout->addStretch(); generalHorLayout->addWidget(statusLabel, Qt::AlignVCenter); setLayout(generalHorLayout); } ExpendButton::~ExpendButton() { } void ExpendButton::setSign(int id ,const QString &style){ if(style == "ukui-light") { qss1 = QString("QPushButton{background: #00F5F5F5; border: none;}"\ "QPushButton:hover{background: #40000000; border: none;}"\ "QPushButton:checked{background: #40000000; border: none;}"); qss0 = QString("QPushButton{background: #0D000000; border: none;}"\ "QPushButton:hover{background: #40000000; border: none;}"\ "QPushButton:checked{background: #40000000; border: none;}"); textLabel->setStyleSheet("color: #262626;"); }else { qss0 = QString("QPushButton{background: #0DFFFFFF; border: none;}"\ "QPushButton:hover{background: #40F5F5F5; border: none;}"\ "QPushButton:checked{background: #40F5F5F5; border: none;}"); qss1 = QString("QPushButton{background: #00232426; border: none;}"\ "QPushButton:hover{background: #40F5F5F5; border: none;}"\ "QPushButton:checked{background: #40F5F5F5; border: none;}"); textLabel->setStyleSheet("color: #FFFFFF;"); } statusLabel->setPixmap(drawLightColoredPixmap(QPixmap(":/img/selected.png"),style)); sign = id; if (sign == 0){ setStyleSheet(qss0); } else if (sign == 1){ setStyleSheet(qss1); } } void ExpendButton::setBtnLogo(QString logo,const QString &style){ logoLabel->setPixmap(drawLightColoredPixmap(QPixmap(logo),style)); } void ExpendButton::setBtnText(QString text){ textLabel->setText(text); } void ExpendButton::setBtnChecked(bool checked){ if (checked){ statusLabel->show(); } else { statusLabel->hide(); } } bool ExpendButton::getBtnChecked(){ return statusLabel->isVisible(); } QPixmap ExpendButton::drawLightColoredPixmap(const QPixmap &source, const QString &style) { int value = 255; if(style == "ukui-light") { value = 0; } QColor gray(255,255,255); QImage img = source.toImage(); for (int x = 0; x < img.width(); x++) { for (int y = 0; y < img.height(); y++) { auto color = img.pixelColor(x, y); if (color.alpha() > 0) { if (qAbs(color.red()-gray.red())<20 && qAbs(color.green()-gray.green())<20 && qAbs(color.blue()-gray.blue())<20) { color.setRed(value); color.setGreen(value); color.setBlue(value); img.setPixelColor(x, y, color); } else { color.setRed(value); color.setGreen(value); color.setBlue(value); img.setPixelColor(x, y, color); } } } } return QPixmap::fromImage(img); } ukui-settings-daemon/plugins/housekeeping/0000755000175000017500000000000014205117202017713 5ustar fengfengukui-settings-daemon/plugins/housekeeping/ldsm-trash-empty.cpp0000644000175000017500000001022214205117202023626 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ldsm-trash-empty.h" #include "ui_ldsm-trash-empty.h" #include #include #include #include #include #include #include #include #include LdsmTrashEmpty::LdsmTrashEmpty(QWidget *parent) : QDialog(parent), ui(new Ui::LdsmTrashEmpty) { ui->setupUi(this); windowLayoutInit(); connectEvent(); } LdsmTrashEmpty::~LdsmTrashEmpty() { delete ui; delete first_text; delete second_text; delete trash_empty; delete cancel; } void LdsmTrashEmpty::windowLayoutInit() { QFont font; QDesktopWidget* desktop=QApplication::desktop(); QRect desk_rect = desktop->screenGeometry(desktop->screenNumber(QCursor::pos())); Qt::WindowFlags flags=Qt::Dialog; flags |=Qt::WindowMinMaxButtonsHint; flags |=Qt::WindowCloseButtonHint; setWindowFlags(flags); setFixedSize(650,180); setWindowTitle(tr("Emptying the trash")); setWindowIcon(QIcon::fromTheme("user-trash-full")); int dialog_width=width(); int dialog_height=height(); int rect_width=desk_rect.width(); int rect_height=desk_rect.height(); this->move((rect_width-dialog_width)/2+desk_rect.left(),(rect_height-dialog_height)/2+desk_rect.top()); first_text=new QLabel(this); second_text=new QLabel(this); trash_empty=new QPushButton(this); cancel=new QPushButton(this); first_text->setGeometry(66,20,560,30); font.setBold(true); first_text->setFont(font); first_text->setText(tr("Empty all of the items from the trash?")); second_text->setGeometry(66,50,560,30*2); second_text->setWordWrap(true); second_text->setAlignment(Qt::AlignLeft); second_text->setText(tr("If you choose to empty the trash, all items in it will be permanently lost." \ "Please note that you can also delete them separately.")); cancel->setGeometry(dialog_width-140,dialog_height-45,120,30); cancel->setText(tr("cancel")); trash_empty->setGeometry(dialog_width-270,dialog_height-45,120,30); trash_empty->setText(tr("Empty Trash")); } void LdsmTrashEmpty::usdLdsmTrashEmpty() { this->exec(); } void LdsmTrashEmpty::connectEvent() { connect(trash_empty,SIGNAL(clicked()),this,SLOT(checkButtonTrashEmpty())); connect(cancel,SIGNAL(clicked()),this,SLOT(checkButtonCancel())); } void LdsmTrashEmpty::deleteContents(const QString path) { QDir dir(path); QFileInfoList fileList; QFileInfo curFile; if(!dir.exists()) return; fileList=dir.entryInfoList(QDir::Files|QDir::Dirs|QDir::Readable|QDir::Writable| QDir::Hidden|QDir::NoDotAndDotDot,QDir::Name); while(fileList.size()>0) { int infoNum=fileList.size(); for(int i=infoNum-1;i>=0;i--) { curFile=fileList[i]; if(curFile.isFile()) { QFile fileTemp(curFile.filePath()); fileTemp.remove(); } if(curFile.isDir()) { QDir dirTemp(curFile.filePath()); dirTemp.removeRecursively(); } fileList.removeAt(i); } } } void LdsmTrashEmpty::checkButtonTrashEmpty() { QString trash_path; trash_path=QDir::homePath()+"/.local/share/Trash"; deleteContents(trash_path); this->accept(); } void LdsmTrashEmpty::checkButtonCancel() { this->accept(); } ukui-settings-daemon/plugins/housekeeping/housekeeping.pro0000644000175000017500000000204014205117202023117 0ustar fengfengQT += gui QT += core widgets TARGET = housekeeping TEMPLATE = lib DEFINES += HOUSEKEPPING_LIBRARY MODULE_NAME=\\\"housekeeping\\\" CONFIG += c++11 no_keywords link_pkgconfig plugin DEFINES += QT_DEPRECATED_WARNINGS include($$PWD/../../common/common.pri) PKGCONFIG += gtk+-3.0 glib-2.0 harfbuzz gmodule-2.0 \ libxklavier gobject-2.0 gio-2.0 gio-unix-2.0 \ cairo cairo-gobject gsettings-qt INCLUDEPATH += \ -I $$PWD/../.. \ -I ukui-settings-daemon/ SOURCES += \ housekeeping-manager.cpp \ housekeeping-plugin.cpp \ ldsm-trash-empty.cpp \ usd-disk-space.cpp \ usd-ldsm-dialog.cpp HEADERS += \ housekeeping-manager.h \ housekeeping-plugin.h \ ldsm-trash-empty.h \ usd-disk-space.h \ usd-ldsm-dialog.h housekeeping_lib.path = $${PLUGIN_INSTALL_DIRS} housekeeping_lib.files = $$OUT_PWD/libhousekeeping.so INSTALLS += housekeeping_lib FORMS += \ ldsm-trash-empty.ui \ usd-ldsm-dialog.ui RESOURCES += \ trash_empty.qrc ukui-settings-daemon/plugins/housekeeping/usd-ldsm-dialog.cpp0000644000175000017500000002300614205117202023405 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "usd-ldsm-dialog.h" #include "ui_usd-ldsm-dialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "clib-syslog.h" #include "usd_global_define.h" LdsmDialog::LdsmDialog(QWidget *parent) : QDialog(parent) , ui(new Ui::LdsmDialog) { ui->setupUi(this); } LdsmDialog::LdsmDialog(bool other_usable_partitions,bool other_partitions,bool display_baobab,bool has_trash, long space_remaining,QString partition_name,QString mount_path, QWidget *parent) : QDialog(parent) , ui(new Ui::LdsmDialog) { ui->setupUi(this); this->other_usable_partitions=other_usable_partitions; this->other_partitions=other_partitions; this->has_trash=has_trash; this->space_remaining=space_remaining; this->partition_name=partition_name; this->mount_path=mount_path; this->analyze_button=nullptr; m_fontSetting = new QGSettings(ORG_UKUI_STYLE, QByteArray(), this); connect(m_fontSetting, &QGSettings::changed,[=](QString key) { USD_LOG(LOG_DEBUG,"font:%s",key.toLatin1().data()); if (key == SYSTEM_FONT_SIZE || key == SYSTEM_FONT) { updateText(); } }); windowLayoutInit(display_baobab); allConnectEvent(display_baobab); } LdsmDialog::~LdsmDialog() { delete ui; delete picture_label; delete primary_label; delete second_label; delete ignore_check_button; delete ignore_button; if(this->has_trash) delete trash_empty; if(analyze_button) delete analyze_button; } void LdsmDialog::windowLayoutInit(bool display_baobab) { QFont font; QDesktopWidget* desktop=QApplication::desktop(); QRect desk_rect = desktop->screenGeometry(desktop->screenNumber(QCursor::pos())); Qt::WindowFlags flags=Qt::Dialog; flags |=Qt::WindowMinMaxButtonsHint; flags |=Qt::WindowCloseButtonHint; setWindowFlags(flags); setFixedSize(660,210); setWindowIcon(QIcon::fromTheme("dialog-warning")); int dialog_width=width(); int dialog_height=height(); int rect_width=desk_rect.width(); int rect_height=desk_rect.height(); setWindowTitle(tr("Low Disk Space")); this->move((rect_width-dialog_width)/2+desk_rect.left(),(rect_height-dialog_height)/2+desk_rect.top()); picture_label=new QLabel(this); primary_label=new QLabel(this); second_label=new QLabel(this); ignore_check_button=new QCheckBox(this); ignore_button=new QPushButton(this); //warning picture picture_label->setGeometry(20,40,32,32); picture_label->setAlignment(Qt::AlignCenter); picture_label->setStyleSheet(QString("border-image:url(../ldsm_dialog/warning.png);")); //warning information text primary_label->setGeometry(66,20,560,30); second_label->setGeometry(66,50,560,30*2); second_label->setWordWrap(true); second_label->setAlignment(Qt::AlignLeft); primary_label->setText(getPrimaryText()); second_label->setText(getSecondText()); //gsettings set box ignore_check_button->setGeometry(70,135,400,30); ignore_check_button->setText(getCheckButtonText()); ignore_button->setGeometry(dialog_width-110,dialog_height-40,100,30); ignore_button->setText(tr("Ignore")); if(this->has_trash){ trash_empty = new QPushButton(this); trash_empty->setGeometry(dialog_width-240,dialog_height-40,120,30); trash_empty->setText(tr("Empty Trash")); } if(display_baobab){ analyze_button = new QPushButton(this); analyze_button->setText(tr("Examine")); if(this->has_trash) analyze_button->setGeometry(dialog_width-320,dialog_height-40,100,30); else analyze_button->setGeometry(dialog_width-215,dialog_height-40,100,30); } updateText(); } QString LdsmDialog::getPrimaryText() { QString primary_text; char* free_space=g_format_size(space_remaining); if(other_partitions) primary_text=QString().sprintf((tr("The volume \"%1\" has only %s disk space remaining.")).toLocal8Bit().constData(), free_space).arg(partition_name); else primary_text=QString().sprintf((tr("The computer has only %s disk space remaining.")).toLocal8Bit().constData(), free_space); return primary_text; } QString LdsmDialog::getSecondText() { if(other_usable_partitions){ if(has_trash) return QString(tr("You can free up disk space by emptying the Trash, removing " \ "unused programs or files, or moving files to another disk or partition.")); else return QString(tr("You can free up disk space by removing unused programs or files, " \ "or by moving files to another disk or partition.")); }else{ if(has_trash) return QString(tr("You can free up disk space by emptying the Trash, removing unused " \ "programs or files, or moving files to an external disk.")); else return QString(tr("You can free up disk space by removing unused programs or files, " \ "or by moving files to an external disk.")); } } QString LdsmDialog::getCheckButtonText() { if(other_partitions) return QString(tr("Don't show any warnings again for this file system")); else return QString(tr("Don't show any warnings again")); } void LdsmDialog::allConnectEvent(bool display_baobab) { connect(ignore_check_button, &QCheckBox::stateChanged, this, &LdsmDialog::checkButtonClicked); connect(ignore_button, &QPushButton::clicked, this, &LdsmDialog::checkButtonIgnore); if(has_trash) connect(trash_empty, &QPushButton::clicked, this, &LdsmDialog::checkButtonTrashEmpty); if(display_baobab) connect(analyze_button, &QPushButton::clicked, this, &LdsmDialog::checkButtonAnalyze); if(sender() == ignore_button) { USD_LOG(LOG_DEBUG,"Ignore button pressed!"); } else { USD_LOG(LOG_DEBUG,"Other button pressed!"); } } //update gsettings "ignore-paths" key contents bool update_ignore_paths(QList** ignore_paths,QString mount_path,bool ignore) { bool found=(*ignore_paths)->contains(mount_path.toLatin1().data()); if(ignore && found==false){ (*ignore_paths)->push_front(mount_path.toLatin1().data()); return true; } if(!ignore && found==true){ (*ignore_paths)->removeOne(mount_path.toLatin1().data()); return true; } return false; } /****************slots*********************/ void LdsmDialog::checkButtonIgnore() { done(LDSM_DIALOG_IGNORE); } void LdsmDialog::checkButtonTrashEmpty() { done(LDSM_DIALOG_RESPONSE_EMPTY_TRASH); } void LdsmDialog::updateText() { QFont font; uint font_size ; if (true == m_fontSetting->keys().contains(SYSTEM_FONT_SIZE)) { font_size = m_fontSetting->get(SYSTEM_FONT_SIZE).toUInt(); } else { font_size = 13; } if (true == m_fontSetting->keys().contains(SYSTEM_FONT)) { font.setFamily(m_fontSetting->get(SYSTEM_FONT).toString()); } font.setBold(true); font.setPixelSize(font_size+2); primary_label->setFont(font); font.setBold(false); font.setPixelSize(font_size); second_label->setFont(font); ignore_button->setFont(font); ignore_button->setFont(font); trash_empty->setFont(font); ignore_check_button->setFont(font); } void LdsmDialog::checkButtonAnalyze() { done(LDSM_DIALOG_RESPONSE_ANALYZE); } void LdsmDialog::checkButtonClicked(int state) { QGSettings* settings; QStringList ignore_list; QStringList ignoreStr; QList* ignore_paths; bool ignore,updated; int i; QList::iterator l; ignore_paths =new QList(); settings = new QGSettings(SETTINGS_SCHEMA); //get contents from "ignore-paths" key if (!settings->get(SETTINGS_IGNORE_PATHS).toStringList().isEmpty()) ignore_list.append(settings->get(SETTINGS_IGNORE_PATHS).toStringList()); for(auto str: ignore_list){ if(!str.isEmpty()) ignore_paths->push_back(str); } ignore = state; updated = update_ignore_paths(&ignore_paths, mount_path, ignore); if(updated){ for(l = ignore_paths->begin(); l != ignore_paths->end(); ++l){ ignoreStr.append(*l); } //set latest contents to gsettings "ignore-paths" key settings->set(SETTINGS_IGNORE_PATHS, QVariant::fromValue(ignoreStr)); } //free QList Memory if(ignore_paths){ ignore_paths->clear(); } delete settings; } ukui-settings-daemon/plugins/housekeeping/usd-disk-space.cpp0000644000175000017500000005163614205117202023246 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "usd-disk-space.h" #include #include "qtimer.h" #include "syslog.h" #define GIGABYTE 1024 * 1024 * 1024 #define CHECK_EVERY_X_SECONDS 120 * 1000 #define DISK_SPACE_ANALYZER "ukui-disk-usage-analyzer" #define SETTINGS_HOUSEKEEPING_SCHEMA "org.ukui.SettingsDaemon.plugins.housekeeping" #define SETTINGS_FREE_PC_NOTIFY_KEY "free-percent-notify" #define SETTINGS_FREE_PC_NOTIFY_AGAIN_KEY "free-percent-notify-again" #define SETTINGS_FREE_SIZE_NO_NOTIFY "free-size-gb-no-notify" #define SETTINGS_MIN_NOTIFY_PERIOD "min-notify-period" #define SETTINGS_IGNORE_PATHS "ignore-paths" static guint64 *time_read; DIskSpace::DIskSpace() { ldsm_timeout_cb = new QTimer(); trash_empty=new LdsmTrashEmpty(); ldsm_notified_hash=NULL; ldsm_monitor = NULL; free_percent_notify = 0.05; free_percent_notify_again = 0.01; free_size_gb_no_notify = 2; min_notify_period = 10; ignore_paths = NULL; done = FALSE; connect(ldsm_timeout_cb, &QTimer::timeout, this, &DIskSpace::ldsm_check_all_mounts); ldsm_timeout_cb->start(); if (QGSettings::isSchemaInstalled(SETTINGS_HOUSEKEEPING_SCHEMA)) { settings = new QGSettings(SETTINGS_HOUSEKEEPING_SCHEMA); } this->dialog = nullptr; } DIskSpace::~DIskSpace() { delete trash_empty; delete settings; } static gint ldsm_ignore_path_compare (gconstpointer a, gconstpointer b) { return g_strcmp0 ((const gchar *)a, (const gchar *)b); } bool DIskSpace::ldsm_mount_is_user_ignore (const char *path) { if (g_slist_find_custom (ignore_paths, path, (GCompareFunc) ldsm_ignore_path_compare) != NULL) return TRUE; else return FALSE; } //static gboolean //ldsm_is_hash_item_in_ignore_paths (gpointer key, // gpointer value, // gpointer user_data) //{ // return this->ldsm_mount_is_user_ignore ((char *)key); //} void DIskSpace::usdLdsmGetConfig() { // 先取得清理提醒的百分比时机 free_percent_notify =settings->get(SETTINGS_FREE_PC_NOTIFY_KEY).toDouble(); if (free_percent_notify >= 1 || free_percent_notify < 0) { /* FIXME define min and max in gschema! */ qWarning ("housekeeping: Invalid configuration of free_percent_notify: %f\n" \ "Using sensible default", free_percent_notify); free_percent_notify = 0.05; } // 取得第二次提醒的百分比时机 free_percent_notify_again = settings->get(SETTINGS_FREE_PC_NOTIFY_AGAIN_KEY).toDouble(); if (free_percent_notify_again >= 1 || free_percent_notify_again < 0) { /* FIXME define min and max in gschema! */ qWarning ("housekeeping: Invalid configuration of free_percent_notify_again: %f\n" \ "Using sensible default\n", free_percent_notify_again); free_percent_notify_again = 0.01; } // 取得不通知的g free_size_gb_no_notify = settings->get(SETTINGS_FREE_SIZE_NO_NOTIFY).toInt(); // 取得最小通知周期 min_notify_period = settings->get(SETTINGS_MIN_NOTIFY_PERIOD).toInt(); if (ignore_paths != NULL) { g_slist_foreach (ignore_paths, (GFunc) g_free, NULL); g_slist_free (ignore_paths); ignore_paths = NULL; } } static void ldsm_free_mount_info (gpointer data) { LdsmMountInfo *mount = (LdsmMountInfo *)data; g_return_if_fail (mount != NULL); g_unix_mount_free (mount->mount); g_free (mount); } void DIskSpace::usdLdsmUpdateConfig(QString key) { usdLdsmGetConfig(); } static gboolean is_hash_item_not_in_mounts(QHash &hash, GList* user_data) { for (GList *l = (GList *) user_data; l != NULL; l = l->next) { GUnixMountEntry *mount = (GUnixMountEntry *)l->data; const char *path; path = g_unix_mount_get_mount_path (mount); // 找到了,返回false if (hash.find(path) !=hash.end() ) return FALSE; } return TRUE; } static gboolean is_in (const gchar *value, const gchar *set[]) { int i; for (i = 0; set[i] != NULL; i++) { if (strcmp (set[i], value) == 0) return TRUE; } return FALSE; } bool DIskSpace::ldsm_mount_should_ignore (GUnixMountEntry *mount) { const gchar *fs, *device, *path; path = g_unix_mount_get_mount_path (mount); if (ldsm_mount_is_user_ignore (path)) return TRUE; /* This is borrowed from GLib and used as a way to determine * which mounts we should ignore by default. GLib doesn't * expose this in a way that allows it to be used for this * purpose */ /* We also ignore network filesystems */ const gchar *ignore_fs[] = { "adfs", "afs", "auto", "autofs", "autofs4", "cifs", "cxfs", "devfs", "devpts", "ecryptfs", "fdescfs", "gfs", "gfs2", "kernfs", "linprocfs", "linsysfs", "lustre", "lustre_lite", "ncpfs", "nfs", "nfs4", "nfsd", "ocfs2", "proc", "procfs", "ptyfs", "rpc_pipefs", "selinuxfs", "smbfs", "sysfs", "tmpfs", "usbfs", "zfs", NULL }; const gchar *ignore_devices[] = { "none", "sunrpc", "devpts", "nfsd", "/dev/loop", "/dev/vn", NULL }; fs = g_unix_mount_get_fs_type (mount); device = g_unix_mount_get_device_path (mount); if (is_in (fs, ignore_fs)) return TRUE; if (is_in (device, ignore_devices)) return TRUE; return FALSE; } bool DIskSpace::ldsm_mount_has_space (LdsmMountInfo *mount) { double free_space; bool percent_flag = false; bool size_falg = false; free_space = (double) mount->buf.f_bavail / (double) mount->buf.f_blocks; /* enough free space, nothing to do */ if (free_space > free_percent_notify) percent_flag = true; if (((gint64) mount->buf.f_frsize * (gint64) mount->buf.f_bavail) > ((gint64) free_size_gb_no_notify * GIGABYTE)) size_falg = true; /* If it returns false, then this volume is low on space */ return (percent_flag && size_falg); } static bool ldsm_mount_is_virtual (LdsmMountInfo *mount) { if (mount->buf.f_blocks == 0) { /* Filesystems with zero blocks are virtual */ return true; } return false; } static gchar* ldsm_get_fs_id_for_path (const gchar *path) { GFile *file; GFileInfo *fileinfo; gchar *attr_id_fs; file = g_file_new_for_path (path); fileinfo = g_file_query_info (file, G_FILE_ATTRIBUTE_ID_FILESYSTEM, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, NULL); if (fileinfo) { attr_id_fs = g_strdup (g_file_info_get_attribute_string (fileinfo, G_FILE_ATTRIBUTE_ID_FILESYSTEM)); g_object_unref (fileinfo); } else { attr_id_fs = NULL; } g_object_unref (file); return attr_id_fs; } static gboolean ldsm_mount_has_trash (LdsmMountInfo *mount) { const gchar *user_data_dir; gchar *user_data_attr_id_fs; gchar *path_attr_id_fs; gboolean mount_uses_user_trash = FALSE; gchar *trash_files_dir; gboolean has_trash = FALSE; GDir *dir; const gchar *path; user_data_dir = g_get_user_data_dir (); user_data_attr_id_fs = ldsm_get_fs_id_for_path (user_data_dir); path = g_unix_mount_get_mount_path (mount->mount); path_attr_id_fs = ldsm_get_fs_id_for_path (path); if (g_strcmp0 (user_data_attr_id_fs, path_attr_id_fs) == 0) { /* The volume that is low on space is on the same volume as our home * directory. This means the trash is at $XDG_DATA_HOME/Trash, * not at the root of the volume which is full. */ mount_uses_user_trash = TRUE; } g_free (user_data_attr_id_fs); g_free (path_attr_id_fs); /* I can't think of a better way to find out if a volume has any trash. Any suggestions? */ if (mount_uses_user_trash) { trash_files_dir = g_build_filename (g_get_user_data_dir (), "Trash", "files", NULL); } else { gchar *uid; uid = g_strdup_printf ("%d", getuid ()); trash_files_dir = g_build_filename (path, ".Trash", uid, "files", NULL); if (!g_file_test (trash_files_dir, G_FILE_TEST_IS_DIR)) { gchar *trash_dir; g_free (trash_files_dir); trash_dir = g_strdup_printf (".Trash-%s", uid); trash_files_dir = g_build_filename (path, trash_dir, "files", NULL); g_free (trash_dir); if (!g_file_test (trash_files_dir, G_FILE_TEST_IS_DIR)) { g_free (trash_files_dir); g_free (uid); return has_trash; } } g_free (uid); } dir = g_dir_open (trash_files_dir, 0, NULL); if (dir) { if (g_dir_read_name (dir)) has_trash = TRUE; g_dir_close (dir); } g_free (trash_files_dir); return has_trash; } static void ldsm_analyze_path (const gchar *path) { const gchar *argv[] = { DISK_SPACE_ANALYZER, path, NULL }; g_spawn_async (NULL, (gchar **) argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL); } bool DIskSpace::ldsm_notify_for_mount (LdsmMountInfo *mount, bool multiple_volumes, bool other_usable_volumes) { gchar *name, *program; signed long free_space; int response; bool has_trash; bool has_disk_analyzer; bool retval = TRUE; char *path; /* Don't show a dialog if one is already displayed */ if (dialog) return retval; name = g_unix_mount_guess_name (mount->mount); free_space = (gint64) mount->buf.f_frsize * (gint64) mount->buf.f_bavail; has_trash = ldsm_mount_has_trash (mount); path = g_strdup (g_unix_mount_get_mount_path (mount->mount)); program = g_find_program_in_path (DISK_SPACE_ANALYZER); has_disk_analyzer = (program != NULL); g_free (program); dialog = new LdsmDialog (other_usable_volumes, multiple_volumes, has_disk_analyzer, has_trash, free_space, name, path); g_free (name); // dialog->show(); response = dialog->exec(); delete dialog; dialog = nullptr; switch (response) { case GTK_RESPONSE_CANCEL: retval = false; break; case LDSM_DIALOG_RESPONSE_ANALYZE: retval = false; ldsm_analyze_path (path); break; case LDSM_DIALOG_RESPONSE_EMPTY_TRASH: retval = false; trash_empty->usdLdsmTrashEmpty();//调清空回收站dialog break; case GTK_RESPONSE_NONE: case GTK_RESPONSE_DELETE_EVENT: retval = true; break; case LDSM_DIALOG_IGNORE: retval = true; break; default: retval = false; } free (path); return retval; } // 目前希望吧GList mounts替换为QList void DIskSpace::ldsm_maybe_warn_mounts (GList *mounts, bool multiple_volumes, bool other_usable_volumes) { GList *l; for (l = mounts; l != NULL; l = l->next) { LdsmMountInfo *mount_info = (LdsmMountInfo *)l->data; LdsmMountInfo *previous_mount_info; gdouble free_space; gdouble previous_free_space; time_t curr_time; const char *path; gboolean show_notify; QString every_two_minutes_check; gdouble free_space_check; if (done) { /* Don't show any more dialogs if the user took action with the last one. The user action * might free up space on multiple volumes, making the next dialog redundant. */ ldsm_free_mount_info (mount_info); continue; } path = g_unix_mount_get_mount_path (mount_info->mount); previous_mount_info = (LdsmMountInfo *)g_hash_table_lookup (ldsm_notified_hash, path); if (previous_mount_info != NULL) previous_free_space = (gdouble) previous_mount_info->buf.f_bavail / (gdouble) previous_mount_info->buf.f_blocks; // liutong // 找m_notified_hash中(mount_info->mount)得到的path QHash::iterator it = m_notified_hash.find(path); if (it != m_notified_hash.end()) { // 如果找到了,就计算上一次的 //LdsmMountInfo* ptmp = it.value() previous_free_space = (gdouble) ((*it)->buf.f_bavail) / (gdouble) ((*it)->buf.f_blocks); } free_space = (gdouble) mount_info->buf.f_bavail / (gdouble) mount_info->buf.f_blocks; if (previous_mount_info == NULL) { /* We haven't notified for this mount yet */ show_notify = TRUE; mount_info->notify_time = time (NULL); m_notified_hash.insert(path, mount_info); } else if ((previous_free_space - free_space) > free_percent_notify_again) { /* We've notified for this mount before and free space has decreased sufficiently since last time to notify again */ curr_time = time (NULL); if (difftime (curr_time, previous_mount_info->notify_time) > (gdouble)(min_notify_period * 60)) { show_notify = TRUE; mount_info->notify_time = curr_time; }else { /* It's too soon to show the dialog again. However, we still replace the LdsmMountInfo * struct in the hash table, but give it the notfiy time from the previous dialog. * This will stop the notification from reappearing unnecessarily as soon as the timeout expires. */ show_notify = FALSE; mount_info->notify_time = previous_mount_info->notify_time; } m_notified_hash.insert(path, mount_info); } else { /* We've notified for this mount before, but the free space hasn't decreased sufficiently to notify again */ ldsm_free_mount_info (mount_info); show_notify = FALSE; } if (show_notify) { if (ldsm_notify_for_mount (mount_info, multiple_volumes, other_usable_volumes)) done = TRUE; } free_space_check = (gint64) mount_info->buf.f_frsize * (gint64) mount_info->buf.f_bavail; every_two_minutes_check = QString().sprintf("The volume \"%1\" has %s disk space remaining.", g_format_size(free_space_check)).arg(g_unix_mount_guess_name(mount_info->mount)); printf("%s\n",every_two_minutes_check.toStdString().data()); } } bool DIskSpace::ldsmGetIgnorePath(const gchar *path) { // 取得清理忽略的目录 QStringList ignoreList = settings->get(SETTINGS_IGNORE_PATHS).toStringList(); for (QString it : ignoreList) { if (it.compare(path) == 0) return true; } return false; } bool DIskSpace::ldsm_check_all_mounts () { GList *mounts; GList *l; GList *check_mounts = NULL; GList *full_mounts = NULL; guint number_of_mounts; guint number_of_full_mounts; gboolean multiple_volumes = FALSE; gboolean other_usable_volumes = FALSE; /* We iterate through the static mounts in /etc/fstab first, seeing if * they're mounted by checking if the GUnixMountPoint has a corresponding GUnixMountEntry. * Iterating through the static mounts means we automatically ignore dynamically mounted media. */ ldsm_timeout_cb->stop(); ldsm_timeout_cb->start(CHECK_EVERY_X_SECONDS); mounts = g_unix_mount_points_get (time_read); for (l = mounts; l != NULL; l = l->next) { GUnixMountPoint *mount_point = (GUnixMountPoint *)l->data; GUnixMountEntry *mount; LdsmMountInfo *mount_info; const gchar *path; path = g_unix_mount_point_get_mount_path (mount_point); mount = g_unix_mount_at (path, time_read); g_unix_mount_point_free (mount_point); if (mount == NULL) { /* The GUnixMountPoint is not mounted */ continue; } mount_info = g_new0 (LdsmMountInfo, 1); mount_info->mount = mount; path = g_unix_mount_get_mount_path (mount); if (g_strcmp0 (path, "/boot/efi") == 0 || g_strcmp0 (path, "/boot") == 0 ){ ldsm_free_mount_info (mount_info); continue; } if (ldsmGetIgnorePath(path)){ ldsm_free_mount_info (mount_info); continue; } if (g_unix_mount_is_readonly (mount)) { ldsm_free_mount_info (mount_info); continue; } if (ldsm_mount_should_ignore (mount)) { ldsm_free_mount_info (mount_info); continue; } if (statvfs (path, &mount_info->buf) != 0) { ldsm_free_mount_info (mount_info); continue; } if (ldsm_mount_is_virtual (mount_info)) { ldsm_free_mount_info (mount_info); continue; } check_mounts = g_list_prepend (check_mounts, mount_info); } g_list_free (mounts); number_of_mounts = g_list_length (check_mounts); if (number_of_mounts > 1) multiple_volumes = TRUE; for (l = check_mounts; l != NULL; l = l->next) { LdsmMountInfo *mount_info = (LdsmMountInfo *)l->data; if (!ldsm_mount_has_space (mount_info)) { full_mounts = g_list_prepend (full_mounts, mount_info); } else { ldsm_free_mount_info (mount_info); } } number_of_full_mounts = g_list_length (full_mounts); if (number_of_mounts > number_of_full_mounts) other_usable_volumes = TRUE; ldsm_maybe_warn_mounts (full_mounts, multiple_volumes, other_usable_volumes); g_list_free (check_mounts); g_list_free (full_mounts); return TRUE; } void DIskSpace::ldsm_mounts_changed (GObject *monitor,gpointer data,DIskSpace *disk) { GList *mounts; /* remove the saved data for mounts that got removed */ mounts = g_unix_mounts_get (time_read); is_hash_item_not_in_mounts(disk->m_notified_hash, mounts); g_list_free_full (mounts, (GDestroyNotify) g_unix_mount_free); /* check the status now, for the new mounts */ disk->ldsm_check_all_mounts(); } void DIskSpace::UsdLdsmSetup(bool check_now) { if (!m_notified_hash.empty() || ldsm_timeout_cb || ldsm_monitor) { qWarning ("Low disk space monitor already initialized."); //return; } usdLdsmGetConfig(); connect(settings, &QGSettings::changed, this, &DIskSpace::usdLdsmUpdateConfig); #if GLIB_CHECK_VERSION (2, 44, 0) ldsm_monitor = g_unix_mount_monitor_get (); #else ldsm_monitor = g_unix_mount_monitor_new (); g_unix_mount_monitor_set_rate_limit (ldsm_monitor, 1000); #endif /*g_signal_connect (ldsm_monitor, "mounts-changed", G_CALLBACK (DIskSpace::ldsm_mounts_changed), this);*/ if (check_now) ldsm_check_all_mounts (); //ldsm_timeout_cb->start(CHECK_EVERY_X_SECONDS); } void DIskSpace::cleanNotifyHash() { for(auto it=m_notified_hash.begin();it!=m_notified_hash.end();it++) { auto p = it.value(); if (nullptr != p) { delete p; } } m_notified_hash.clear(); } void DIskSpace::UsdLdsmClean() { cleanNotifyHash(); if (ldsm_monitor) g_object_unref (ldsm_monitor); ldsm_monitor = NULL; if (settings) { g_object_unref (settings); } if (ignore_paths) { g_slist_foreach (ignore_paths, (GFunc) g_free, NULL); g_slist_free (ignore_paths); ignore_paths = NULL; } } #ifdef TEST int main (int argc, char **argv) { GMainLoop *loop; DIskSpace *mDisk; mDisk = DIskSpace::DiskSpaceNew(); gtk_init (&argc, &argv); loop = g_main_loop_new (NULL, FALSE); mDisk->UsdLdsmSetup (true); g_main_loop_run (loop); mDisk->UsdLdsmClean (); g_main_loop_unref (loop); delete mDisk; return 0; } #endif ukui-settings-daemon/plugins/housekeeping/housekeeping-manager.cpp0000644000175000017500000001713314205117202024522 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "housekeeping-manager.h" #include "clib-syslog.h" #include "qtimer.h" #include #include /* General */ #define INTERVAL_ONCE_A_DAY 24*60*60*1000 #define INTERVAL_TWO_MINUTES 1 //#define INTERVAL_TWO_MINUTES 60*2000 /* Thumbnail cleaner */ #define THUMB_CACHE_SCHEMA "org.mate.thumbnail-cache" #define THUMB_CACHE_KEY_AGE "maximum-age" #define THUMB_CACHE_KEY_SIZE "maximum-size" HousekeepingManager *HousekeepingManager::mHouseManager = nullptr; DIskSpace *HousekeepingManager::mDisk = nullptr; typedef struct { long now; long max_age; signed long total_size; signed long max_size; } PurgeData; typedef struct { time_t mtime; char *path; long size; } ThumbData; /* * 初始化DIskSpace, QGSettings,两个QTimer */ HousekeepingManager::HousekeepingManager() { mDisk = new DIskSpace(); settings = new QGSettings(THUMB_CACHE_SCHEMA); long_term_handler = new QTimer(this); short_term_handler = new QTimer(this); connect(long_term_handler, &QTimer::timeout, this, &HousekeepingManager::do_cleanup); connect(short_term_handler, &QTimer::timeout, this, &HousekeepingManager::do_cleanup_once); } /* * 清理DIskSpace, QGSettings,两个QTimer */ HousekeepingManager::~HousekeepingManager() { delete mDisk; delete settings; delete long_term_handler; delete short_term_handler; } static GList * read_dir_for_purge (const char *path, GList *files) { GFile *read_path; GFileEnumerator *enum_dir; if (opendir(path) == NULL) return files; read_path = g_file_new_for_path (path); enum_dir = g_file_enumerate_children (read_path, G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_TIME_MODIFIED "," G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, NULL, NULL); if (enum_dir != NULL) { GFileInfo *info; while ((info = g_file_enumerator_next_file (enum_dir, NULL, NULL)) != NULL) { const char *name; name = g_file_info_get_name (info); if (strlen (name) == 36 && strcmp (name + 32, ".png") == 0) { ThumbData *td; GFile *entry; char *entry_path; GTimeVal mod_time; entry = g_file_get_child (read_path, name); entry_path = g_file_get_path (entry); g_object_unref (entry); g_file_info_get_modification_time (info, &mod_time); td = g_new0 (ThumbData, 1); td->path = entry_path; td->mtime = mod_time.tv_sec; td->size = g_file_info_get_size (info); files = g_list_prepend (files, td); } g_object_unref (info); } g_object_unref (enum_dir); } g_object_unref (read_path); return files; } static void purge_old_thumbnails (ThumbData *info, PurgeData *purge_data) { if ((purge_data->now - info->mtime) > purge_data->max_age) { g_unlink (info->path); info->size = 0; } else { purge_data->total_size += info->size; } } static int sort_file_mtime (ThumbData *file1, ThumbData *file2) { return file1->mtime - file2->mtime; } static void thumb_data_free (gpointer data) { ThumbData *info = (ThumbData *)data; if (info) { g_free (info->path); g_free (info); } } void HousekeepingManager::purge_thumbnail_cache () { char *path; GList *files; PurgeData purge_data; GTimeVal current_time; purge_data.max_age = settings->get(THUMB_CACHE_KEY_AGE).toInt() * 24 * 60 * 60; purge_data.max_size = settings->get(THUMB_CACHE_KEY_SIZE).toInt() * 1024 * 1024; /* if both are set to -1, we don't need to read anything */ if ((purge_data.max_age < 0) && (purge_data.max_size < 0)) return; path = g_build_filename (g_get_user_cache_dir (), "thumbnails", "normal", NULL); files = read_dir_for_purge (path, NULL); g_free (path); path = g_build_filename (g_get_user_cache_dir (), "thumbnails", "large", NULL); files = read_dir_for_purge (path, files); g_free (path); path = g_build_filename (g_get_user_cache_dir (), "thumbnails", "fail", "ukui-thumbnail-factory", NULL); files = read_dir_for_purge (path, files); g_free (path); g_get_current_time (¤t_time); purge_data.now = current_time.tv_sec; purge_data.total_size = 0; if (purge_data.max_age >= 0) g_list_foreach (files, (GFunc) purge_old_thumbnails, &purge_data); if ((purge_data.total_size > purge_data.max_size) && (purge_data.max_size >= 0)) { GList *scan; files = g_list_sort (files, (GCompareFunc) sort_file_mtime); for (scan = files; scan && (purge_data.total_size > purge_data.max_size); scan = scan->next) { ThumbData *info = (ThumbData *)scan->data; g_unlink (info->path); purge_data.total_size -= info->size; } } g_list_foreach (files, (GFunc) thumb_data_free, NULL); g_list_free (files); } void HousekeepingManager::do_cleanup () { purge_thumbnail_cache (); } void HousekeepingManager::do_cleanup_once () { do_cleanup (); short_term_handler->stop(); } void HousekeepingManager::do_cleanup_soon() { short_term_handler->start(INTERVAL_TWO_MINUTES); } void HousekeepingManager::settings_changed_callback(QString key) { do_cleanup_soon(); } bool HousekeepingManager::HousekeepingManagerStart() { mDisk->UsdLdsmSetup(false); connect (settings, &QGSettings::changed, this,&HousekeepingManager::settings_changed_callback); /* Clean once, a few minutes after start-up */ do_cleanup_soon(); long_term_handler->start(INTERVAL_ONCE_A_DAY); return true; } void HousekeepingManager::HousekeepingManagerStop() { // 时间 if (short_term_handler) { short_term_handler->stop(); } // 时间 if (long_term_handler) { long_term_handler->stop(); /* Do a clean-up on shutdown if and only if the size or age * limits have been set to a paranoid level of cleaning (zero) */ if ((settings->get(THUMB_CACHE_KEY_AGE).toInt() == 0) || (settings->get(THUMB_CACHE_KEY_SIZE).toInt() == 0)) { do_cleanup (); } } mDisk->UsdLdsmClean(); } ukui-settings-daemon/plugins/housekeeping/warning.png0000644000175000017500000000034014205117202022063 0ustar fengfengPNG  IHDR g PLTEe-g tRNS@fIDATU 0 P2ܙ%KQzD'SiQOeט =~(ؖ -0i ((ZڑćȄ 14u(a}*Q8*3W. */ #ifndef DISKSPACE_H #define DISKSPACE_H #include #include #include #include "usd-ldsm-dialog.h" #include "config.h" #include #include #include #include #include #include #include #include #include #include #include typedef struct { GUnixMountEntry *mount; struct statvfs buf; time_t notify_time; } LdsmMountInfo; class DIskSpace : public QObject { Q_OBJECT public: DIskSpace(); ~DIskSpace(); void UsdLdsmSetup (bool check_now); void UsdLdsmClean (); void usdLdsmGetConfig (); bool ldsm_mount_is_user_ignore (const char *path); bool ldsm_mount_should_ignore (GUnixMountEntry *mount); bool ldsm_mount_has_space (LdsmMountInfo *mount); void ldsm_maybe_warn_mounts (GList *mounts, bool multiple_volumes, bool other_usable_volumes); bool ldsm_notify_for_mount (LdsmMountInfo *mount, bool multiple_volumes, bool other_usable_volumes); static void ldsm_mounts_changed (GObject *monitor,gpointer data,DIskSpace *disk); bool ldsmGetIgnorePath(const gchar *path); bool ldsm_check_all_mounts(); void usdLdsmUpdateConfig(QString); private: void cleanNotifyHash(); DIskSpace *mDisk; GHashTable *ldsm_notified_hash ; QHash m_notified_hash; QTimer *ldsm_timeout_cb; GUnixMountMonitor *ldsm_monitor; double free_percent_notify; double free_percent_notify_again; unsigned int free_size_gb_no_notify; unsigned int min_notify_period; GSList *ignore_paths; QGSettings *settings; LdsmDialog *dialog; LdsmTrashEmpty *trash_empty; QVariantList ignoreList; bool done; }; #endif // DISKSPACE_H ukui-settings-daemon/plugins/housekeeping/ldsm-trash-empty.ui0000644000175000017500000000061314205117202023464 0ustar fengfeng LdsmTrashEmpty 0 0 517 326 Dialog ukui-settings-daemon/plugins/housekeeping/ldsm-trash-empty.h0000644000175000017500000000267614205117202023311 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef LDSMTRASHEMPTY_H #define LDSMTRASHEMPTY_H #include #include #include #include namespace Ui { class LdsmTrashEmpty; } class LdsmTrashEmpty : public QDialog { Q_OBJECT public: explicit LdsmTrashEmpty(QWidget *parent = nullptr); ~LdsmTrashEmpty(); void usdLdsmTrashEmpty(); public Q_SLOTS: void checkButtonCancel(); void checkButtonTrashEmpty(); private: Ui::LdsmTrashEmpty *ui; QLabel *first_text; QLabel *second_text; QPushButton *trash_empty; QPushButton *cancel; private: void windowLayoutInit(); void connectEvent(); void deleteContents(const QString path); }; #endif // LDSMTRASHEMPTY_H ukui-settings-daemon/plugins/housekeeping/trash_empty.qrc0000644000175000017500000000014514205117202022761 0ustar fengfeng warning.png ukui-settings-daemon/plugins/housekeeping/usd-ldsm-dialog.h0000644000175000017500000000474014205117202023056 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef USDLDSMDIALOG_H #define USDLDSMDIALOG_H #include #include #include #include #include #include #define SETTINGS_SCHEMA "org.ukui.SettingsDaemon.plugins.housekeeping" #define SETTINGS_IGNORE_PATHS "ignore-paths" #define LDSM_DIALOG_IGNORE 10 #define LDSM_DIALOG_RESPONSE_ANALYZE 30 #define LDSM_DIALOG_RESPONSE_EMPTY_TRASH 40 QT_BEGIN_NAMESPACE namespace Ui { class LdsmDialog; } QT_END_NAMESPACE class LdsmDialog : public QDialog { Q_OBJECT public: LdsmDialog(QWidget *parent = nullptr); LdsmDialog(bool other_usable_partitions,bool other_partitions,bool display_baobab,bool has_trash, long space_remaining,QString partition_name,QString mount_path, QWidget *parent = nullptr); ~LdsmDialog(); private: Ui::LdsmDialog *ui; QLabel* picture_label; QLabel* primary_label; QLabel* second_label; QCheckBox* ignore_check_button; QPushButton* trash_empty; QPushButton* ignore_button; QPushButton* analyze_button; QDialog* m_dialog; QGSettings* m_fontSetting; bool other_usable_partitions; bool other_partitions; bool has_trash; long space_remaining; /*char *partition_name; char *mount_path;*/ QString partition_name; QString mount_path; public: void checkButtonClicked(int); void checkButtonIgnore (); void checkButtonAnalyze (); void checkButtonTrashEmpty(); void updateText(); private: void windowLayoutInit(bool display_baobab); QString getPrimaryText(); QString getSecondText(); QString getCheckButtonText(); void allConnectEvent(bool display_baobab); }; #endif // USDLDSMDIALOG_H ukui-settings-daemon/plugins/housekeeping/housekeeping-plugin.cpp0000644000175000017500000000624714205117202024412 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "housekeeping-plugin.h" #include "clib-syslog.h" PluginInterface *HousekeepingPlugin::mInstance=nullptr; QString getCurrentUserName() { QString name; if (name.isEmpty()) { QStringList envList = QProcess::systemEnvironment(); for(const QString& env : envList){ if (env.startsWith("USERNAME")) { QStringList strList = env.split('='); if (strList.size() > 2) { name = strList[1]; } } } } if (!name.isEmpty()) return name; QProcess process; process.start("whoami", QStringList()); process.waitForFinished(); name = QString::fromLocal8Bit(process.readAllStandardOutput()).trimmed(); return name.isEmpty() ? QString("User") : name; } HousekeepingPlugin::HousekeepingPlugin() { userName = getCurrentUserName(); if (userName.compare("lightdm") != 0) { mHouseManager = new HousekeepingManager(); if (!mHouseManager) USD_LOG(LOG_ERR,"Unable to start Housekeeping Manager!"); } } HousekeepingPlugin::~HousekeepingPlugin() { if (mHouseManager) { delete mHouseManager; mHouseManager = nullptr; } } bool HousekeepingPlugin::isTrialMode() { QString str; QStringList symbList ; QFile file("/proc/cmdline"); if (file.open(QIODevice::ReadOnly)) { QByteArray data = file.readAll(); str = QString::fromLocal8Bit(data); symbList = str.split("\r\n"); } if (symbList.indexOf("boot=casper") != -1) { file.close(); return true; } file.close(); if (getuid() == 999) return true; return false; } void HousekeepingPlugin::activate() { if (isTrialMode()) { USD_LOG(LOG_DEBUG,"Housekeeping Manager Not Active"); return; } if (userName.compare("lightdm") != 0) { USD_LOG(LOG_DEBUG,"Housekeeping Manager Is Start"); mHouseManager->HousekeepingManagerStart(); } } PluginInterface *HousekeepingPlugin::getInstance() { if (nullptr == mInstance) mInstance = new HousekeepingPlugin(); return mInstance; } void HousekeepingPlugin::deactivate() { //if(isTrialMode()) // return; //if (mHouseManager) mHouseManager->HousekeepingManagerStop(); } PluginInterface *createSettingsPlugin() { return HousekeepingPlugin::getInstance(); } ukui-settings-daemon/plugins/housekeeping/usd-ldsm-dialog.ui0000644000175000017500000000065414205117202023244 0ustar fengfeng LdsmDialog 0 0 800 600 LdsmDialog ukui-settings-daemon/plugins/housekeeping/housekeeping-plugin.h0000644000175000017500000000261414205117202024051 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef HOUSEKEPPINGPLUGIN_H #define HOUSEKEPPINGPLUGIN_H #include "housekeeping-manager.h" #include "plugin-interface.h" class HousekeepingPlugin : public PluginInterface { public: ~HousekeepingPlugin(); static PluginInterface *getInstance(); virtual void activate(); virtual void deactivate(); bool isTrialMode(); private: HousekeepingPlugin(); HousekeepingPlugin(HousekeepingPlugin&)=delete; private: QString userName; HousekeepingManager *mHouseManager; static PluginInterface *mInstance; }; extern "C" Q_DECL_EXPORT PluginInterface *createSettingsPlugin(); #endif // HOUSEKEPPINGPLUGIN_H ukui-settings-daemon/plugins/housekeeping/housekeeping-manager.h0000644000175000017500000000320614205117202024163 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef HOUSEKEEPINGMANAGER_H #define HOUSEKEEPINGMANAGER_H #include #include #include #include #include #include #include "usd-disk-space.h" extern "C"{ #include "config.h" } class HousekeepingManager : public QObject { Q_OBJECT public: HousekeepingManager(); HousekeepingManager(HousekeepingManager&)=delete; ~HousekeepingManager(); bool HousekeepingManagerStart(); void HousekeepingManagerStop(); public: void settings_changed_callback(QString); void do_cleanup_soon(); void purge_thumbnail_cache (); void do_cleanup (); void do_cleanup_once (); private: static HousekeepingManager *mHouseManager; static DIskSpace *mDisk; QTimer *long_term_handler; QTimer *short_term_handler; QGSettings *settings; }; #endif // HOUSEKEEPINGMANAGER_H ukui-settings-daemon/plugins/README.md0000644000175000017500000000000014205117202016472 0ustar fengfengukui-settings-daemon/plugins/xrandr/0000755000175000017500000000000014210057545016534 5ustar fengfengukui-settings-daemon/plugins/xrandr/xrandr-plugin.h0000644000175000017500000000255114205117202021471 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XRANDRPLUGIN_H #define XRANDRPLUGIN_H #include #include #include "plugin-interface.h" #include "xrandr-manager.h" #include "usd_base_class.h" class XrandrPlugin : public PluginInterface { private: XrandrPlugin(); XrandrPlugin(XrandrPlugin&)=delete; public: ~XrandrPlugin(); static PluginInterface *getInstance(); virtual void activate(); virtual void deactivate(); private: static XrandrManager *mXrandrManager; static PluginInterface *mInstance; }; extern "C" Q_DECL_EXPORT PluginInterface *createSettingsPlugin(); #endif // XRANDRPLUGIN_H ukui-settings-daemon/plugins/xrandr/xrandr-output.h0000644000175000017500000000433314205117202021533 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2012 by Alejandro Fiestas Olivares * Copyright 2016 by Sebastian Kügler * Copyright (c) 2018 Kai Uwe Broulik * Work sponsored by the LiMux project of * the city of Munich. * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef OUTPUT_H #define OUTPUT_H #include #include #include class xrandrOutput { public: static void readInOutputs(KScreen::ConfigPtr config, const QVariantList &outputsInfo); static void writeGlobal(const KScreen::OutputPtr &output); static bool writeGlobalPart(const KScreen::OutputPtr &output, QVariantMap &info, const KScreen::OutputPtr &fallback); static QString dirPath(); private: static QString globalFileName(const QString &hash); static QVariantMap getGlobalData(KScreen::OutputPtr output); static void readIn(KScreen::OutputPtr output, const QVariantMap &info); static bool readInGlobal(KScreen::OutputPtr output); static void readInGlobalPartFromInfo(KScreen::OutputPtr output, const QVariantMap &info); /* * When a global output value (scale, rotation) is changed we might * need to reposition the outputs when another config is read. */ static void adjustPositions(KScreen::ConfigPtr config, const QVariantList &outputsInfo); static QString mDirName; }; #endif // OUTPUT_H ukui-settings-daemon/plugins/xrandr/usd-xrandr-manager.xml0000644000175000017500000000253614205117202022752 0ustar fengfeng ukui-settings-daemon/plugins/xrandr/xrandr-config.h0000644000175000017500000000556414205117202021447 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2012 by Alejandro Fiestas Olivares * Copyright 2016 by Sebastian Kügler * Copyright (c) 2018 Kai Uwe Broulik * Work sponsored by the LiMux project of * the city of Munich. * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XRANDRCONFIG_H #define XRANDRCONFIG_H #include #include #include //#include #include #include "xrandr-output.h" class xrandrConfig : public QObject { Q_OBJECT public: explicit xrandrConfig(KScreen::ConfigPtr config, QObject *parent = nullptr); ~xrandrConfig() = default; QString id() const; bool fileExists() const; bool fileScreenModeExists(QString screenMode); std::unique_ptr readFile(bool isUseModeDirConfig); std::unique_ptr readOpenLidFile(); std::unique_ptr readFile(const QString &fileName, bool state); std::unique_ptr readScreensConfigFromDbus(const QString &screensParam); bool writeFile(bool state); bool writeOpenLidFile(); bool writeConfigAndBackupToModeDir(); bool writeFile(const QString &filePath, bool state); QString getScreensParam(); KScreen::ConfigPtr data() const { return mConfig; } void log(); void setPriName(QString name){ priName = name; } void setValidityFlags(KScreen::Config::ValidityFlags flags) { mValidityFlags = flags; } bool canBeApplied() const; QString filePath() const; QString fileModeConfigPath(); void setScreenMode(QString modeName); bool copyMateConfig(); private: bool canBeApplied(KScreen::ConfigPtr config) const; static QString configsDirPath(); QString configsModeDirPath(); static QString sleepDirPath(); KScreen::ConfigPtr mConfig; KScreen::Config::ValidityFlags mValidityFlags; QString priName; bool mAddScreen = false; QString mScreenMode; static QString mConfigsDirName; static QString mFixedConfigFileName; }; #endif // XRANDRCONFIG_H ukui-settings-daemon/plugins/xrandr/xrandr-plugin.cpp0000644000175000017500000000747214205117202022033 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "xrandr-plugin.h" #include "clib-syslog.h" PluginInterface *XrandrPlugin::mInstance = nullptr; XrandrManager *XrandrPlugin::mXrandrManager = nullptr; /* * TODO: *《》《》《》《》屏幕处理流程: * 控制面板(UCC) * 用户配置服务(USD) * 屏幕模式切换(KDS) *《》《》《》《》将用户屏幕分为五个文件夹: *(share/kscreen/):记录用户设置最后一次的设置。 *(share/kscreen/first):记录用户在内屏模式下的设置 *(share/kscreen/clone):记录用户在克隆模式下的设置 *(share/kscreen/extend):记录用户在拓展模式下的设置 *(share/kscreen/other):记录用户在其他屏模式下的设置 * 《》《》《》《》四个模式缺省设置: * 内屏模式:以最大分辨率进行显示内屏并将内屏坐标迁移到0,0,disable外屏。 * 克隆模式:以最大分辨率进行显示克隆模式,enable全部已链接屏幕。 * 拓展模式:以最大分辨率显示拓展模式,enable全部已链接屏幕,并将外屏迁移到内屏的右侧。 * 其他屏幕:以最大分辨率显示外屏,并且将外屏迁移到0,0坐标。 * 《》《》《》《》交互逻辑: * KDS:调用xrandr组件的模式切换dbus,传入(setScreenMode)模式字段(first,exten,clone,extend)进行处理,调用接口(getScreenMode)获取当前的模式(实现) * UCC:调用底层库,发送信号. * 《》《》《》《》《设计模式》 * 将实时的配置文件放入kscreen内,同时根据模式放入一份到first,clone,exten,other内。首次运行时直接载入kscreen文件夹下,模式切换时载入备份中,如果没有再按照缺省模式设置进行加载。 * */ XrandrPlugin::XrandrPlugin() { if (UsdBaseClass::isWayland()) { QString str = "/usr/bin/peony-qt-desktop -b"; QProcess::startDetached(str); USD_LOG(LOG_DEBUG, "disable xrandr in wayland..."); return; } USD_LOG(LOG_DEBUG, "Xrandr Plugin initializing!:%s",QGuiApplication::platformName().toLatin1().data()); if(nullptr == mXrandrManager) mXrandrManager = new XrandrManager(); } XrandrPlugin::~XrandrPlugin() { if(mXrandrManager) delete mXrandrManager; } void XrandrPlugin::activate() { bool res = QGuiApplication::platformName().startsWith(QLatin1String("wayland")); if (true == res) { USD_LOG(LOG_DEBUG, "wayland need't usd to manage the screen"); return; } USD_LOG (LOG_DEBUG, "Activating %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); res = mXrandrManager->XrandrManagerStart(); if(!res) { USD_LOG(LOG_ERR,"Unable to start Xrandr manager!"); } } PluginInterface *XrandrPlugin::getInstance() { if(nullptr == mInstance) mInstance = new XrandrPlugin(); return mInstance; } void XrandrPlugin::deactivate() { USD_LOG(LOG_ERR,"Deactivating Xrandr plugin"); mXrandrManager->XrandrManagerStop(); } PluginInterface *createSettingsPlugin() { return XrandrPlugin::getInstance(); } ukui-settings-daemon/plugins/xrandr/xrandr-config.cpp0000644000175000017500000003050414205117202021772 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2012 by Alejandro Fiestas Olivares * Copyright 2016 by Sebastian Kügler * Copyright (c) 2018 Kai Uwe Broulik * Work sponsored by the LiMux project of * the city of Munich. * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include //#include #include #include "xrandr-config.h" #include "clib-syslog.h" QString xrandrConfig::mFixedConfigFileName = QStringLiteral("fixed-config"); QString xrandrConfig::mConfigsDirName = QStringLiteral("" /*"configs/"*/); // TODO: KDE6 - move these files into the subfolder QString xrandrConfig::configsDirPath() { QString dirPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QStringLiteral("/kscreen/"); return dirPath % mConfigsDirName; } void xrandrConfig::setScreenMode(QString modeName) { mScreenMode = modeName; USD_LOG(LOG_DEBUG,"set mScreenMode to :%s",mScreenMode.toLatin1().data()); } bool xrandrConfig::copyMateConfig() { QString oldConfig = "/etc/usd/" % id(); QString newConfig = configsDirPath() % id(); if (QFile::exists(configsDirPath() % id()) == false) { USD_LOG(LOG_DEBUG,"."); if (QFile::exists(oldConfig)) { USD_LOG(LOG_DEBUG,"."); QFile::copy(oldConfig, configsDirPath() % id()); USD_LOG(LOG_DEBUG,"copy from %s to %s", oldConfig.toLatin1().data(), newConfig.toLatin1().data()); } else { USD_LOG(LOG_DEBUG,"."); USD_LOG(LOG_DEBUG,"fail copy....%s ",oldConfig.toLatin1().data()); } } else { USD_LOG(LOG_DEBUG,"skip copy....%s ",oldConfig.toLatin1().data()); } return true; } QString xrandrConfig::configsModeDirPath() { QString dirPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QStringLiteral("/kscreen/") % mScreenMode % QStringLiteral("/"); return dirPath; } QString xrandrConfig::sleepDirPath() { QString dirPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QStringLiteral("/sleep-state/"); return dirPath % mConfigsDirName; } xrandrConfig::xrandrConfig(KScreen::ConfigPtr config, QObject *parent) : QObject(parent) { mConfig = config; } QString xrandrConfig::fileModeConfigPath() { if (!QDir().mkpath(configsModeDirPath())) { return QString(); } return configsModeDirPath() % id(); } QString xrandrConfig::filePath() const { if (!QDir().mkpath(configsDirPath())) { return QString(); } return configsDirPath() % id(); } QString xrandrConfig::id() const { if (!mConfig) { return QString(); } return mConfig->connectedOutputsHash(); } bool xrandrConfig::fileExists() const { return (QFile::exists(configsDirPath() % id())); } bool xrandrConfig::fileScreenModeExists(QString screenMode) { USD_LOG(LOG_DEBUG,"%s status:%d",(fileModeConfigPath()).toLatin1().data(),QFile::exists(fileModeConfigPath())); return QFile::exists(fileModeConfigPath()); } /* * isUseModeConfig:是否读取模式配置 * 模式配置只是在kds调用接口时使用 */ std::unique_ptr xrandrConfig::readFile(bool isUseModeDirConfig) { bool res = false; if (res){//Device::self()->isLaptop() && !Device::self()->isLidClosed()) { // We may look for a config that has been set when the lid was closed, Bug: 353029 const QString lidOpenedFilePath(filePath() % QStringLiteral("_lidOpened")); const QFile srcFile(lidOpenedFilePath); if (srcFile.exists()) { QFile::remove(filePath()); if (QFile::copy(lidOpenedFilePath, filePath())) { QFile::remove(lidOpenedFilePath); //qDebug() << "Restored lid opened config to" << id(); } } } return readFile(id(), isUseModeDirConfig); } std::unique_ptr xrandrConfig::readOpenLidFile() { const QString openLidFile = id() % QStringLiteral("_lidOpened"); auto config = readFile(openLidFile, false); QFile::remove(configsDirPath() % openLidFile); return config; } std::unique_ptr xrandrConfig::readScreensConfigFromDbus(const QString &screensParam) { std::unique_ptr config = std::unique_ptr(new xrandrConfig(mConfig->clone())); config->setValidityFlags(mValidityFlags); QJsonDocument parser; QVariantList outputs = parser.fromJson(screensParam.toLatin1().data()).toVariant().toList(); xrandrOutput::readInOutputs(config->data(), outputs); QSize screenSize; for (const auto &output : config->data()->outputs()) { if (!output->isConnected()) { continue; } if (1 == outputs.count() && (0 != output->pos().x() || 0 != output->pos().y())) { const QPoint pos(0,0); output->setPos(std::move(pos)); } const QRect geom = output->geometry(); if (geom.x() + geom.width() > screenSize.width()) { screenSize.setWidth(geom.x() + geom.width()); } if (geom.y() + geom.height() > screenSize.height()) { screenSize.setHeight(geom.y() + geom.height()); } } if (!canBeApplied(config->data())) { USD_LOG(LOG_ERR,"is a error param form dbus.."); return nullptr; } return config; } std::unique_ptr xrandrConfig::readFile(const QString &fileName, bool state) { int enabledOutputsCount = 0; if (!mConfig) { USD_LOG(LOG_ERR,"config is nullptr..."); return nullptr; } std::unique_ptr config = std::unique_ptr(new xrandrConfig(mConfig->clone())); config->setValidityFlags(mValidityFlags); QFile file; if(!state){ if (QFile::exists(configsDirPath() % mFixedConfigFileName)) { file.setFileName(configsDirPath() % mFixedConfigFileName);//先读取特定模式的配置, } else { file.setFileName(configsDirPath() % fileName); } if (!file.open(QIODevice::ReadOnly)) { USD_LOG(LOG_ERR,"config is nullptr..."); return nullptr; } } else { if (QFile::exists(configsModeDirPath())) { file.setFileName(configsModeDirPath() % fileName); } if (!file.open(QIODevice::ReadOnly)) { USD_LOG(LOG_ERR,"config is nullptr...%s",file.fileName().toLatin1().data()); return nullptr; } } QJsonDocument parser; QVariantList outputs = parser.fromJson(file.readAll()).toVariant().toList(); xrandrOutput::readInOutputs(config->data(), outputs); QSize screenSize; for (const auto &output : config->data()->outputs()) { if (output->isEnabled()) { enabledOutputsCount++; } if (!output->isConnected()) { continue; } if (1 == outputs.count() && (0 != output->pos().x() || 0 != output->pos().y())) { const QPoint pos(0,0); output->setPos(std::move(pos)); } const QRect geom = output->geometry(); if (geom.x() + geom.width() > screenSize.width()) { screenSize.setWidth(geom.x() + geom.width()); } if (geom.y() + geom.height() > screenSize.height()) { screenSize.setHeight(geom.y() + geom.height()); } } config->data()->screen()->setCurrentSize(screenSize); if (!canBeApplied(config->data())) { config->data()->screen()->setMaxActiveOutputsCount(enabledOutputsCount); if (!canBeApplied(config->data())) { return nullptr; } } return config; } bool xrandrConfig::canBeApplied() const { return canBeApplied(mConfig); } bool xrandrConfig::canBeApplied(KScreen::ConfigPtr config) const { return KScreen::Config::canBeApplied(config, mValidityFlags); } bool xrandrConfig::writeFile(bool state) { mAddScreen = state; return writeFile(filePath(), false); } bool xrandrConfig::writeConfigAndBackupToModeDir() { return true; } QString xrandrConfig::getScreensParam() { const KScreen::OutputList outputs = mConfig->outputs(); QVariantList outputList; for (const KScreen::OutputPtr &output : outputs) { QVariantMap info; if (false == output->isConnected()) { continue; } xrandrOutput::writeGlobalPart(output, info, nullptr); info[QStringLiteral("primary")] = output->isPrimary();; // info[QStringLiteral("enabled")] = output->isEnabled(); auto setOutputConfigInfo = [&info](const KScreen::OutputPtr &out) { if (!out) { return; } QVariantMap pos; pos[QStringLiteral("x")] = out->pos().x(); pos[QStringLiteral("y")] = out->pos().y(); info[QStringLiteral("pos")] = pos; }; setOutputConfigInfo(output->isEnabled() ? output : nullptr); outputList.append(info); } return QJsonDocument::fromVariant(outputList).toJson(); } bool xrandrConfig::writeFile(const QString &filePath, bool state) { int screenConnectedCount = 0; if (id().isEmpty()) { USD_LOG(LOG_DEBUG,"id is empty!"); return false; } const KScreen::OutputList outputs = mConfig->outputs(); QVariantList outputList; for (const KScreen::OutputPtr &output : outputs) { QVariantMap info; if (!output->isConnected()) { continue; } screenConnectedCount++; bool priState = false; if (state || mAddScreen){ if (priName.compare(output->name()) == 0){ priState = true; } } else{ priState = output->isPrimary(); } xrandrOutput::writeGlobalPart(output, info, nullptr); info[QStringLiteral("primary")] = output->isPrimary();; // info[QStringLiteral("enabled")] = output->isEnabled(); auto setOutputConfigInfo = [&info](const KScreen::OutputPtr &out) { if (!out) { return; } QVariantMap pos; pos[QStringLiteral("x")] = out->pos().x(); pos[QStringLiteral("y")] = out->pos().y(); info[QStringLiteral("pos")] = pos; }; setOutputConfigInfo(output->isEnabled() ? output : nullptr); // if (output->isEnabled()) { // // try to update global output data // xrandrOutput::writeGlobal(output); // } outputList.append(info); } if (mAddScreen) mAddScreen = false; QFile file(filePath); if (file.open(QIODevice::WriteOnly)) { file.write(QJsonDocument::fromVariant(outputList).toJson()); } else { USD_LOG(LOG_DEBUG,"write file [%s] fail.cuz:%s.",file.fileName().toLatin1().data(),file.errorString().toLatin1().data()); } if (screenConnectedCount > 1) { QFile backFile(fileModeConfigPath()); if (backFile.open(QIODevice::WriteOnly)) { backFile.write(QJsonDocument::fromVariant(outputList).toJson()); } else { // USD_LOG(LOG_DEBUG,"write file [%s] fail.cuz:%s.",file.fileName().toLatin1().data(),backFile.errorString().toLatin1().data()); } } // USD_LOG(LOG_DEBUG,"write file:\n%s ok \n%s ok.",filePath.toLatin1().data(),mScreenMode == nullptr? "" : fileModeConfigPath().toLatin1().data()); return true; } void xrandrConfig::log() { if (!mConfig) { return; } const auto outputs = mConfig->outputs(); for (const auto &o : outputs) { if (o->isConnected()) { USD_LOG_SHOW_OUTPUT(o); } } } ukui-settings-daemon/plugins/xrandr/xrandr-adaptor.cpp0000644000175000017500000000400314205117202022152 0ustar fengfeng/* * This file was generated by qdbusxml2cpp version 0.8 * Command line was: qdbusxml2cpp usd-xrandr-manager.xml -a xrandr-adaptor * * qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. * * This is an auto-generated file. * Do not edit! All changes made to it will be lost. */ #include "xrandr-adaptor.h" #include #include #include #include #include #include #include #include "clib-syslog.h" /* * Implementation of adaptor class WaylandAdaptor */ XrandrAdaptor::XrandrAdaptor(QObject *parent) : QDBusAbstractAdaptor(parent) { // constructor setAutoRelaySignals(true); } XrandrAdaptor::~XrandrAdaptor() { // destructor } int XrandrAdaptor::setScreensParam(const QString &screensParam, const QString &appName){ int out0; USD_LOG(LOG_DEBUG," appName:%s", appName.toLatin1().data()); QMetaObject::invokeMethod(parent(), "setScreensParam", Q_RETURN_ARG(int, out0), Q_ARG(QString, screensParam), Q_ARG(QString, appName)); return out0; } QString XrandrAdaptor::getScreensParam( const QString &appName){ QString out0; USD_LOG(LOG_DEBUG," appName:%s", appName.toLatin1().data()); QMetaObject::invokeMethod(parent(), "getScreensParam", Q_RETURN_ARG(QString, out0), Q_ARG(QString, appName)); return out0; } int XrandrAdaptor::setScreenMode(const QString &modeName, const QString &appName){ int out0; USD_LOG(LOG_DEBUG,"change screen :%s, appName:%s",modeName.toLatin1().data(), appName.toLatin1().data()); QMetaObject::invokeMethod(parent(), "setScreenMode", Q_RETURN_ARG(int, out0), Q_ARG(QString, modeName), Q_ARG(QString, appName)); return out0; } int XrandrAdaptor::getScreenMode(const QString &appName){ int out0; USD_LOG(LOG_DEBUG,"get screen mode request from appName:%s", appName.toLatin1().data()); QMetaObject::invokeMethod(parent(), "getScreenMode", Q_RETURN_ARG(int, out0), Q_ARG(QString, appName)); return out0; } ukui-settings-daemon/plugins/xrandr/xrandr-output.cpp0000644000175000017500000004150714210057545022103 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2012 by Alejandro Fiestas Olivares * Copyright 2016 by Sebastian Kügler * Copyright (c) 2018 Kai Uwe Broulik * Work sponsored by the LiMux project of * the city of Munich. * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "xrandr-output.h" #include #include #include #include #include #include #include #include #include #include #include "xrandr-config.h" #include "clib-syslog.h" QString xrandrOutput::mDirName = QStringLiteral("outputs/"); QString xrandrOutput::dirPath() { return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QStringLiteral("/kscreen/") % mDirName; } QString xrandrOutput::globalFileName(const QString &hash) { // const auto dir = dirPath(); // if (!QDir().mkpath(dir)) { // USD_LOG(LOG_DEBUG,":::::::::::::::::::::::::::::::::::::::::::::::::::::::::[%s],dir:[%s]",QString().toLatin1().data(), dirPath().toLatin1().data()); // return QString(); // } // USD_LOG(LOG_DEBUG,":::::::::::::::::::::::::::::::::::::::::::::::::::::::::[%s],dir:[%s]",QString().toLatin1().data(), dirPath().toLatin1().data()); return QString();//dir % hash; } void xrandrOutput::readInGlobalPartFromInfo(KScreen::OutputPtr output, const QVariantMap &info) { output->setRotation(static_cast(info.value(QStringLiteral("rotation"), 1).toInt())); bool scaleOk; const qreal scale = info.value(QStringLiteral("scale"), 1.).toDouble(&scaleOk); if (scaleOk) { output->setScale(scale); } const QVariantMap modeInfo = info[QStringLiteral("mode")].toMap(); const QVariantMap modeSize = modeInfo[QStringLiteral("size")].toMap(); const QSize size = QSize(modeSize[QStringLiteral("width")].toInt(), modeSize[QStringLiteral("height")].toInt()); //qDebug() << "Finding a mode for" << size << "@" << modeInfo[QStringLiteral("refresh")].toFloat(); const KScreen::ModeList modes = output->modes(); KScreen::ModePtr matchingMode; if (modes.count()<1) { USD_LOG(LOG_DEBUG, "%s mode count = 0.",output->name().toLatin1().data()); } for(const KScreen::ModePtr &mode : modes) { if (mode->size() != size) { continue; } if (!qFuzzyCompare(mode->refreshRate(), modeInfo[QStringLiteral("refresh")].toFloat())) { continue; } USD_LOG(LOG_DEBUG,"find mode id:%s %dx%d@%f", mode->id().toLatin1().data(), mode->size().height(), mode->size().width(),mode->refreshRate()); matchingMode = mode; break; } if (!matchingMode) { USD_LOG(LOG_DEBUG,"Failed to find a matching mode - this means that our config is corrupted"); matchingMode = output->preferredMode(); } if (!matchingMode) { USD_LOG(LOG_DEBUG,"Failed to get a preferred mode, falling back to biggest mode."); // matchingMode = Generator::biggestMode(modes); } if (!matchingMode) { USD_LOG(LOG_DEBUG,"Failed to get biggest mode. Which means there are no modes. Turning off the screen."); output->setEnabled(false); return; } output->setCurrentModeId(matchingMode->id()); } QVariantMap xrandrOutput::getGlobalData(KScreen::OutputPtr output) { QFile file(globalFileName(output->hashMd5())); if (!file.open(QIODevice::ReadOnly)) { // USD_LOG(LOG_DEBUG, "Failed to open file %s" , file.fileName().toLatin1().data()); return QVariantMap(); } QJsonDocument parser; return parser.fromJson(file.readAll()).toVariant().toMap(); } bool xrandrOutput::readInGlobal(KScreen::OutputPtr output) { const QVariantMap info = getGlobalData(output); if (info.empty()) { // USD_LOG(LOG_DEBUG,"can't get info..."); // if info is empty, the global file does not exists, or is in an unreadable state return false; } readInGlobalPartFromInfo(output, info); return true; } // TODO: move this into the Layouter class. void xrandrOutput::adjustPositions(KScreen::ConfigPtr config, const QVariantList &outputsInfo) { typedef QPair Out; KScreen::OutputList outputs = config->outputs(); QVector sortedOutputs; // for (const KScreen::OutputPtr &output : outputs) { sortedOutputs.append(Out(output->id(), output->pos())); } // go from left to right, top to bottom std::sort(sortedOutputs.begin(), sortedOutputs.end(), [](const Out &o1, const Out &o2) { const int x1 = o1.second.x(); const int x2 = o2.second.x(); return x1 < x2 || (x1 == x2 && o1.second.y() < o2.second.y()); }); for (int cnt = 1; cnt < sortedOutputs.length(); cnt++) { auto getOutputInfoProperties = [outputsInfo](KScreen::OutputPtr output, QRect &geo) -> bool { if (!output) { return false; } const auto hash = output->hash(); auto it = std::find_if(outputsInfo.begin(), outputsInfo.end(), [hash](QVariant v) { const QVariantMap info = v.toMap(); return info[QStringLiteral("id")].toString() == hash; } ); if (it == outputsInfo.end()) { return false; } auto isPortrait = [](const QVariant &info) { bool ok; const int rot = info.toInt(&ok); if (!ok) { return false; } return rot & KScreen::Output::Rotation::Left || rot & KScreen::Output::Rotation::Right; }; const QVariantMap outputInfo = it->toMap(); const QVariantMap posInfo = outputInfo[QStringLiteral("pos")].toMap(); const QVariant scaleInfo = outputInfo[QStringLiteral("scale")]; const QVariantMap modeInfo = outputInfo[QStringLiteral("mode")].toMap(); const QVariantMap modeSize = modeInfo[QStringLiteral("size")].toMap(); const bool portrait = isPortrait(outputInfo[QStringLiteral("rotation")]); if (posInfo.isEmpty() || modeSize.isEmpty() || !scaleInfo.canConvert()) { return false; } const qreal scale = scaleInfo.toDouble(); if (scale <= 0) { return false; } const QPoint pos = QPoint(posInfo[QStringLiteral("x")].toInt(), posInfo[QStringLiteral("y")].toInt()); QSize size = QSize(modeSize[QStringLiteral("width")].toInt() / scale, modeSize[QStringLiteral("height")].toInt() / scale); if (portrait) { size.transpose(); } geo = QRect(pos, size); return true; }; // it's guaranteed that we find the following values in the QMap KScreen::OutputPtr prevPtr = outputs.find(sortedOutputs[cnt - 1].first).value(); KScreen::OutputPtr curPtr = outputs.find(sortedOutputs[cnt].first).value(); QRect prevInfoGeo, curInfoGeo; if (!getOutputInfoProperties(prevPtr, prevInfoGeo) || !getOutputInfoProperties(curPtr, curInfoGeo)) { // no info found, nothing can be adjusted for the next output continue; } const QRect prevGeo = prevPtr->geometry(); const QRect curGeo = curPtr->geometry(); // the old difference between previous and current output read from the config file const int xInfoDiff = curInfoGeo.x() - (prevInfoGeo.x() + prevInfoGeo.width()); // the proposed new difference const int prevRight = prevGeo.x() + prevGeo.width(); const int xCorrected = prevRight + prevGeo.width() * xInfoDiff / (double)prevInfoGeo.width(); const int xDiff = curGeo.x() - prevRight; // In the following calculate the y-correction. This is more involved since we // differentiate between overlapping and non-overlapping pairs and align either // top to top/bottom or bottom to top/bottom const bool yOverlap = prevInfoGeo.y() + prevInfoGeo.height() > curInfoGeo.y() && prevInfoGeo.y() < curInfoGeo.y() + curInfoGeo.height(); // these values determine which horizontal edge of previous output we align with const int topToTopDiffAbs = qAbs(prevInfoGeo.y() - curInfoGeo.y()); const int topToBottomDiffAbs = qAbs(prevInfoGeo.y() - curInfoGeo.y() - curInfoGeo.height()); const int bottomToBottomDiffAbs = qAbs(prevInfoGeo.y() + prevInfoGeo.height() - curInfoGeo.y() - curInfoGeo.height()); const int bottomToTopDiffAbs = qAbs(prevInfoGeo.y() + prevInfoGeo.height() - curInfoGeo.y()); const bool yTopAligned = (topToTopDiffAbs < bottomToBottomDiffAbs && topToTopDiffAbs <= bottomToTopDiffAbs) || topToBottomDiffAbs < bottomToBottomDiffAbs; int yInfoDiff = curInfoGeo.y() - prevInfoGeo.y(); int yDiff = curGeo.y() - prevGeo.y(); int yCorrected; if (yTopAligned) { // align to previous top if (!yOverlap) { // align previous top with current bottom yInfoDiff += curInfoGeo.height(); yDiff += curGeo.height(); } // When we align with previous top we are interested in the changes to the // current geometry and not in the ones of the previous one. const double yInfoRel = yInfoDiff / (double)curInfoGeo.height(); yCorrected = prevGeo.y() + yInfoRel * curGeo.height(); } else { // align previous bottom... yInfoDiff -= prevInfoGeo.height(); yDiff -= prevGeo.height(); yCorrected = prevGeo.y() + prevGeo.height(); if (yOverlap) { // ... with current bottom yInfoDiff += curInfoGeo.height(); yDiff += curGeo.height(); yCorrected -= curGeo.height(); } // ... else with current top // When we align with previous bottom we are interested in changes to the // previous geometry. const double yInfoRel = yInfoDiff / (double)prevInfoGeo.height(); yCorrected += yInfoRel * prevGeo.height(); } const int x = xDiff == xInfoDiff ? curGeo.x() : xCorrected; const int y = yDiff == yInfoDiff ? curGeo.y() : yCorrected; curPtr->setPos(QPoint(x, y)); } } void xrandrOutput::readIn(KScreen::OutputPtr output, const QVariantMap &info) { const QVariantMap posInfo = info[QStringLiteral("pos")].toMap(); QPoint point(posInfo[QStringLiteral("x")].toInt(), posInfo[QStringLiteral("y")].toInt()); output->setPos(point); output->setPrimary(info[QStringLiteral("primary")].toBool()); output->setEnabled(info[QStringLiteral("enabled")].toBool()); if (readInGlobal(output)) { // USD_LOG(LOG_DEBUG,"out it...."); // output data read from global output file return; } // output data read directly from info readInGlobalPartFromInfo(output, info); } void xrandrOutput::readInOutputs(KScreen::ConfigPtr config, const QVariantList &outputsInfo) { const KScreen::OutputList outputs = config->outputs(); // As global outputs are indexed by a hash of their edid, which is not unique, // to be able to tell apart multiple identical outputs, these need special treatment QStringList duplicateIds; { QStringList allIds; allIds.reserve(outputs.count()); for (const KScreen::OutputPtr &output : outputs) { const auto outputId = output->hash(); if (allIds.contains(outputId) && !duplicateIds.contains(outputId)) { duplicateIds << outputId; } allIds << outputId; } } for (const KScreen::OutputPtr &output : outputs) { if (!output->isConnected()) { output->setEnabled(false); continue; } const auto outputId = output->hash(); bool infoFound = false; for (const auto &variantInfo : outputsInfo) { const QVariantMap info = variantInfo.toMap(); if (outputId != info[QStringLiteral("id")].toString()) { continue; } if (!output->name().isEmpty() && duplicateIds.contains(outputId)) { // We may have identical outputs connected, these will have the same id in the config // in order to find the right one, also check the output's name (usually the connector) const auto metadata = info[QStringLiteral("metadata")].toMap(); const auto outputName = metadata[QStringLiteral("name")].toString(); if (output->name() != outputName) { // was a duplicate id, but info not for this output continue; } } infoFound = true; readIn(output, info);//, control.getOutputRetention(output)); break; } if (!infoFound) { // no info in info for this output, try reading in global output info at least or set some default values qWarning() << "\tFailed to find a matching output in the current info data - this means that our info is corrupted" "or a different device with the same serial number has been connected (very unlikely)."; if (!readInGlobal(output)) { // set some default values instead readInGlobalPartFromInfo(output, QVariantMap()); } } } for (KScreen::OutputPtr output : outputs) { auto replicationSource = nullptr;//control.getReplicationSource(output); if (replicationSource) { //output->setPos(replicationSource->pos()); //output->setLogicalSize(replicationSource->logicalSize()); } else { output->setExplicitLogicalSize(QSizeF()); } } // TODO: this does not work at the moment with logical size replication. Deactivate for now. // correct positional config regressions on global output data changes #if 1 adjustPositions(config, outputsInfo); #endif } QVariantMap metadata(const KScreen::OutputPtr &output) { QVariantMap metadata; metadata[QStringLiteral("name")] = output->name(); if (!output->edid() || !output->edid()->isValid()) { return metadata; } metadata[QStringLiteral("fullname")] = output->edid()->deviceId(); return metadata; } void xrandrOutput::writeGlobal(const KScreen::OutputPtr &output) { // get old values and subsequently override QVariantMap info = getGlobalData(output); if (!writeGlobalPart(output, info, nullptr)) { return; } QFile file(globalFileName(output->hashMd5())); if (!file.open(QIODevice::WriteOnly)) { USD_LOG(LOG_DEBUG, "Failed to open global output file for writing! ", file.errorString().toLatin1().data()); return; } file.write(QJsonDocument::fromVariant(info).toJson()); return; } bool xrandrOutput::writeGlobalPart(const KScreen::OutputPtr &output, QVariantMap &info, const KScreen::OutputPtr &fallback) { info[QStringLiteral("id")] = output->hash(); info[QStringLiteral("metadata")] = metadata(output); info[QStringLiteral("rotation")] = output->rotation(); // Round scale to four digits info[QStringLiteral("scale")] = int(output->scale() * 10000 + 0.5) / 10000.; QVariantMap modeInfo; float refreshRate = -1.; QSize modeSize; if (output->currentMode() && output->isEnabled()) { refreshRate = output->currentMode()->refreshRate(); modeSize = output->currentMode()->size(); } if (refreshRate < 0 || !modeSize.isValid()) { return false; } modeInfo[QStringLiteral("refresh")] = refreshRate; QVariantMap modeSizeMap; modeSizeMap[QStringLiteral("width")] = modeSize.width(); modeSizeMap[QStringLiteral("height")] = modeSize.height(); modeInfo[QStringLiteral("size")] = modeSizeMap; info[QStringLiteral("mode")] = modeInfo; return true; } ukui-settings-daemon/plugins/xrandr/xrandr-manager.h0000644000175000017500000001373614205117202021614 0ustar fengfeng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2012 by Alejandro Fiestas Olivares * Copyright 2016 by Sebastian Kügler * Copyright (c) 2018 Kai Uwe Broulik * Work sponsored by the LiMux project of * the city of Munich. * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XRANDRMANAGER_H #define XRANDRMANAGER_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xrandr-dbus.h" #include "xrandr-adaptor.h" #include "xrandr-config.h" #include "usd_base_class.h" #include "usd_global_define.h" #define SAVE_CONFIG_TIME 800 typedef struct _MapInfoFromFile { QString sTouchName; //触摸屏的名称 QString sTouchSerial; //触摸屏的序列号 QString sMonitorName; //显示器的名称 }MapInfoFromFile; //配置文件中记录的映射关系信息 //END 触摸屏自动映射相关 typedef struct _TouchpadMap { int sTouchId; QString sMonitorName; //显示器的名称 }touchpadMap; //END 触摸屏自动映射相关 class XrandrManager: public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.KScreen") public: XrandrManager(); ~XrandrManager() override; public: bool XrandrManagerStart(); void XrandrManagerStop(); void StartXrandrIdleCb(); void monitorsInit(); void changeScreenPosition(); void applyConfig(); void applyKnownConfig(bool state); void applyIdealConfig(); void outputConnectedChanged(); void doApplyConfig(const KScreen::ConfigPtr &config); void doApplyConfig(std::unique_ptr config); void refreshConfig(); UsdBaseClass::eScreenMode discernScreenMode(); void saveCurrentConfig(); void setMonitorForChanges(bool enabled); static void printScreenApplyFailReason(KScreen::ConfigPtr KsData); void orientationChangedProcess(Qt::ScreenOrientation orientation); void init_primary_screens(KScreen::ConfigPtr config); void primaryScreenChange(); void callMethod(QRect geometry, QString name); void calingPeonyProcess(); bool pretreatScreenInfo(); void outputChangedHandle(KScreen::Output *senderOutput); void lightLastScreen(); void outputConnectedWithoutConfigFile(KScreen::Output *senderOutput ,char outputCount); void setScreenModeToClone(); void setScreenModeToFirst(bool isFirstMode); void setScreenModeToExtend(); bool checkPrimaryScreenIsSetable(); bool readAndApplyScreenModeFromConfig(UsdBaseClass::eScreenMode eMode); int8_t getCurrentMode(); uint8_t getCurrentRotation(); void sendScreenModeToDbus(); void autoRemapTouchscreen(); void remapFromConfig(QString mapPath); void SetTouchscreenCursorRotation(); void intel_SetTouchscreenCursorRotation(); void doRemapAction (int input_name, char *output_name , bool isRemapFromFile = false); bool checkScreenByName(QString screenName); bool checkMapTouchDeviceById(int id); bool checkMapScreenByName(const QString screenName); public Q_SLOTS: void TabletSettingsChanged(const bool tablemode); void configChanged(); void RotationChangedEvent(const QString &rotation); void outputAddedHandle(const KScreen::OutputPtr &output); void outputRemoved(int outputId); void primaryOutputChanged(const KScreen::OutputPtr &output); // void applyConfigTimerHandle(); void setScreenMode(QString modeName); void setScreensParam(QString screensParam); void SaveConfigTimerHandle(); QString getScreesParam(); void screenModeChangedSignal(int mode); void screensParamChangedSignal(QString param); /*台式机screen旋转后触摸*/ void controlScreenMap(const QString screenMap); Q_SIGNALS: // DBus void outputConnected(const QString &outputName); void unknownOutputConnected(const QString &outputName); private: QList mTouchMapList; //存储已映射的关系 Q_INVOKABLE void getInitialConfig(); QDBusInterface *t_DbusTableMode; QDBusInterface *m_DbusRotation; QTimer *mAcitveTime = nullptr; QTimer *mKscreenInitTimer = nullptr; QTimer *mSaveConfigTimer = nullptr; QTimer *mChangeCompressor = nullptr; QTimer *mApplyConfigTimer = nullptr; QGSettings *mXrandrSetting = nullptr; QGSettings *mXsettings = nullptr; double mScale = 1.0; QDBusInterface *mLoginInter; QDBusInterface *mUkccDbus; std::unique_ptr mMonitoredConfig = nullptr; KScreen::ConfigPtr mConfig = nullptr; xrandrDbus *mDbus; QMetaEnum metaEnum; bool mMonitoring; bool mConfigDirty = true; bool mSleepState = false; bool mAddScreen = false; QScreen *mScreen = nullptr; bool mStartingUp = true; bool mIsApplyConfigWhenSave = false; }; #endif // XRANDRMANAGER_H ukui-settings-daemon/plugins/xrandr/xrandr-dbus.cpp0000644000175000017500000000637314205117202021471 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "xrandr-dbus.h" #include #include #include #include #include #include #include #include #include "clib-syslog.h" #include "usd_base_class.h" #include "xrandr-manager.h" #define UKUI_DAEMON_NAME "ukui-settings-daemon" XrandrManager *xrandrManager = nullptr; xrandrDbus::xrandrDbus(QObject* parent) : QObject(parent) { mXsettings =new QGSettings("org.ukui.SettingsDaemon.plugins.xsettings"); mScale = mXsettings->get("scaling-factor").toDouble(); xrandrManager = static_cast(parent); //QDBusConnection::sessionBus().unregisterService("org.ukui.SettingsDaemon.xrandr"); //QDBusConnection::sessionBus().registerService("org.ukui.SettingsDaemon.xrandr"); QDBusConnection::sessionBus().registerObject("0",this,QDBusConnection::ExportAllSlots); } xrandrDbus::~xrandrDbus() { delete mXsettings; } int xrandrDbus::setScreenMode(QString modeName,QString appName){ USD_LOG(LOG_DEBUG,"change screen :%s, appName:%s",modeName.toLatin1().data(), appName.toLatin1().data()); Q_EMIT setScreenModeSignal(modeName); return true; } int xrandrDbus::getScreenMode(QString appName){ USD_LOG(LOG_DEBUG,"get screen mode appName:%s", appName.toLatin1().data()); return xrandrManager->discernScreenMode(); } int xrandrDbus::setScreensParam(QString screensParam, QString appName) { USD_LOG(LOG_DEBUG,"appName:%s",screensParam.toLatin1().data(),appName); Q_EMIT setScreensParamSignal(screensParam); return 1; } QString xrandrDbus::getScreensParam(QString appName) { USD_LOG(LOG_DEBUG,"dbus from %s",appName.toLatin1().data()); return xrandrManager->getScreesParam(); } void xrandrDbus::sendModeChangeSignal(int screensMode) { static int lastScreenMode = 0xff; if (lastScreenMode == screensMode) { return; } lastScreenMode = screensMode; USD_LOG(LOG_DEBUG,"send mode:%d",screensMode); Q_EMIT screenModeChanged(screensMode); } void xrandrDbus::sendScreensParamChangeSignal(QString screensParam) { // USD_LOG(LOG_DEBUG,"send param:%s",screensParam.toLatin1().data()); Q_EMIT screensParamChanged(screensParam); } void xrandrDbus::setScreenMap() { xrandrManager->autoRemapTouchscreen(); } QString xrandrDbus::controlScreenSlot(const QString &conRotation) { USD_LOG(LOG_DEBUG,"control call this slot"); Q_EMIT controlScreen(conRotation); return QString("Get messageMethod reply: %1").arg(conRotation); } ukui-settings-daemon/plugins/xrandr/xrandr-manager.cpp0000644000175000017500000016512214205117202022144 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2012 by Alejandro Fiestas Olivares * Copyright 2016 by Sebastian Kügler * Copyright (c) 2018 Kai Uwe Broulik * Work sponsored by the LiMux project of * the city of Munich. * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "xrandr-manager.h" #include #include #include extern "C"{ #include //#include #include #include #include #include #include #include "clib-syslog.h" #include } #define SETTINGS_XRANDR_SCHEMAS "org.ukui.SettingsDaemon.plugins.xrandr" #define XRANDR_ROTATION_KEY "xrandr-rotations" #define XRANDR_PRI_KEY "primary" #define XSETTINGS_SCHEMA "org.ukui.SettingsDaemon.plugins.xsettings" #define XSETTINGS_KEY_SCALING "scaling-factor" #define MAX_SIZE_MATCH_DIFF 0.05 #define MAP_CONFIG "/.config/touchcfg.ini" #define MONITOR_NULL_SERIAL "kydefault" unsigned char *getDeviceNode (XIDeviceInfo devinfo); typedef struct { unsigned char *input_node; XIDeviceInfo dev_info; }TsInfo; XrandrManager::XrandrManager() { QGSettings *mXsettings = new QGSettings(XSETTINGS_SCHEMA); mScale = mXsettings->get(XSETTINGS_KEY_SCALING).toDouble(); KScreen::Log::instance(); mDbus = new xrandrDbus(this); mXrandrSetting = new QGSettings(SETTINGS_XRANDR_SCHEMAS); new XrandrAdaptor(mDbus); QDBusConnection sessionBus = QDBusConnection::sessionBus(); if (sessionBus.registerService(DBUS_XRANDR_NAME)) { sessionBus.registerObject(DBUS_XRANDR_PATH, mDbus, QDBusConnection::ExportAllContents); } mUkccDbus = new QDBusInterface("org.ukui.ukcc.session", "/", "org.ukui.ukcc.session.interface", QDBusConnection::sessionBus()); mAcitveTime = new QTimer(this); mKscreenInitTimer = new QTimer(this); metaEnum = QMetaEnum::fromType(); m_DbusRotation = new QDBusInterface("com.kylin.statusmanager.interface","/","com.kylin.statusmanager.interface",QDBusConnection::sessionBus(),this); if (nullptr != m_DbusRotation) { if (m_DbusRotation->isValid()) { connect(m_DbusRotation, SIGNAL(rotations_change_signal(QString)),this,SLOT(RotationChangedEvent(QString))); // USD_LOG(LOG_DEBUG, "m_DbusRotation ok...."); } else { USD_LOG(LOG_ERR, "m_DbusRotation fail..."); } } t_DbusTableMode = new QDBusInterface("com.kylin.statusmanager.interface","/","com.kylin.statusmanager.interface",QDBusConnection::sessionBus(),this); if (t_DbusTableMode->isValid()) { connect(t_DbusTableMode, SIGNAL(mode_change_signal(bool)),this,SLOT(TabletSettingsChanged(bool))); //USD_LOG(LOG_DEBUG, ".."); } else { USD_LOG(LOG_ERR, "m_DbusRotation"); } connect(mDbus,&xrandrDbus::controlScreen,this,&XrandrManager::controlScreenMap); // connect(mDbus,SIGNAL(xrandrDbus::controlScreen()),this,SLOT(controlScreenMap())); } void XrandrManager::getInitialConfig() { connect(new KScreen::GetConfigOperation, &KScreen::GetConfigOperation::finished, this, [this](KScreen::ConfigOperation* op) { mKscreenInitTimer->stop(); if (op->hasError()) { USD_LOG(LOG_DEBUG,"Error getting initial configuration:%s",op->errorString().toLatin1().data()); return; } if (mMonitoredConfig) { if (mMonitoredConfig->data()) { KScreen::ConfigMonitor::instance()->removeConfig(mMonitoredConfig->data()); for (const KScreen::OutputPtr &output : mMonitoredConfig->data()->outputs()) { output->disconnect(this); } mMonitoredConfig->data()->disconnect(this); } mMonitoredConfig = nullptr; } mMonitoredConfig = std::unique_ptr(new xrandrConfig(qobject_cast(op)->config())); mMonitoredConfig->setValidityFlags(KScreen::Config::ValidityFlag::RequireAtLeastOneEnabledScreen); if (mXrandrSetting->keys().contains("hadmate2kscreen")) { if (mXrandrSetting->get("hadmate2kscreen").toBool() == false) { mXrandrSetting->set("hadmate2kscreen", true); mMonitoredConfig->copyMateConfig(); } } monitorsInit(); mDbus->mScreenMode = discernScreenMode(); mMonitoredConfig->setScreenMode(metaEnum.valueToKey(mDbus->mScreenMode)); }); } XrandrManager::~XrandrManager() { if (mAcitveTime) { delete mAcitveTime; mAcitveTime = nullptr; } if (mXrandrSetting) { delete mXrandrSetting; mXrandrSetting = nullptr; } if (mXsettings) { delete mXsettings; mXsettings = nullptr; } qDeleteAll(mTouchMapList); mTouchMapList.clear(); // if(mLoginInter) { // delete mLoginInter; // mLoginInter = nullptr; // } } bool XrandrManager::XrandrManagerStart() { USD_LOG(LOG_DEBUG,"Xrandr Manager Start"); connect(mAcitveTime, &QTimer::timeout, this,&XrandrManager::StartXrandrIdleCb); mAcitveTime->start(); return true; } void XrandrManager::XrandrManagerStop() { USD_LOG(LOG_DEBUG,"Xrandr Manager Stop"); } /*查找触摸屏设备ID*/ static bool find_touchscreen_device(Display* display, XIDeviceInfo *dev) { int i = 0; if (dev->use != XISlavePointer) { return false; } if (!dev->enabled) { USD_LOG(LOG_DEBUG,"%s device is disabled.",dev->name); return false; } QString devName = QString::fromUtf8(dev->name); if (devName.toUpper().contains("TOUCHPAD")) { return true; } for (int j = 0; j < dev->num_classes; j++) { if (dev->classes[j]->type == XIValuatorClass) { XIValuatorClassInfo *t = (XIValuatorClassInfo*)dev->classes[j]; // 如果当前的设备是绝对坐标映射 则认为该设备需要进行一次屏幕映射 if (t->mode == XIModeAbsolute) { USD_LOG(LOG_DEBUG,"%s type:%d mode:%d", dev->name, dev->classes[i]->type, t->mode); return true; } } } return false; } /* Get device node for gudev node like "/dev/input/event6" */ unsigned char * getDeviceNode (XIDeviceInfo devinfo) { Atom prop; Atom act_type; int act_format; unsigned long nitems, bytes_after; unsigned char *data; prop = XInternAtom(QX11Info::display(), XI_PROP_DEVICE_NODE, False); if (!prop) return NULL; if (XIGetProperty(QX11Info::display(), devinfo.deviceid, prop, 0, 1000, False, AnyPropertyType, &act_type, &act_format, &nitems, &bytes_after, &data) == Success) { return data; } XFree(data); return NULL; } /* Get touchscreen info */ GList * getTouchscreen(Display* display) { gint n_devices; XIDeviceInfo *devs_info; int i; GList *ts_devs = NULL; Display *dpy = QX11Info::display(); devs_info = XIQueryDevice(dpy, XIAllDevices, &n_devices); for (i = 0; i < n_devices; i ++) { if (find_touchscreen_device(dpy, &devs_info[i])) { unsigned char *node; TsInfo *ts_info = g_new(TsInfo, 1); node = getDeviceNode (devs_info[i]); if (node) { ts_info->input_node = node; ts_info->dev_info = devs_info[i]; ts_devs = g_list_append (ts_devs, ts_info); } } } return ts_devs; } bool checkMatch(double output_width, double output_height, double input_width, double input_height) { double w_diff, h_diff; w_diff = ABS (1 - (output_width / input_width)); h_diff = ABS (1 - (output_height / input_height)); USD_LOG(LOG_DEBUG,"w_diff--------%f,h_diff----------%f",w_diff,h_diff); if (w_diff < MAX_SIZE_MATCH_DIFF && h_diff < MAX_SIZE_MATCH_DIFF) { return true; } else return false; } /* Here to run command xinput 更新触摸屏触点位置 */ void XrandrManager::doRemapAction (int input_name, char *output_name , bool isRemapFromFile) { if(!UsdBaseClass::isTablet()) { touchpadMap *map = new touchpadMap; map->sMonitorName = QString(output_name); map->sTouchId = input_name; mTouchMapList.append(map); } char buff[128] = ""; sprintf(buff, "xinput --map-to-output \"%d\" \"%s\"", input_name, output_name); USD_LOG(LOG_DEBUG,"map touch-screen [%s]\n", buff); QProcess::execute(buff); } bool XrandrManager::checkScreenByName(QString screenName) { Q_FOREACH (const KScreen::OutputPtr &output, mMonitoredConfig->data()->outputs()) { if (output->isConnected() && output->name() == screenName ) { return true; } } return false; } bool XrandrManager::checkMapTouchDeviceById(int id) { Q_FOREACH (touchpadMap *map,mTouchMapList) { if(map->sTouchId == id) { return true; } } return false; } bool XrandrManager::checkMapScreenByName(const QString name) { Q_FOREACH (touchpadMap *map,mTouchMapList) { if(map->sMonitorName == name) { return true; } } return false; } static int find_event_from_name(char *_name, char *_serial, char *_event) { int ret = -1; if((NULL == _name) || (NULL == _serial) || (NULL == _event)) { USD_LOG(LOG_DEBUG,"parameter NULL ptr."); return ret; } struct udev *udev; struct udev_enumerate *enumerate; struct udev_list_entry *devices, *dev_list_entry; struct udev_device *dev; udev = udev_new(); enumerate = udev_enumerate_new(udev); udev_enumerate_add_match_subsystem(enumerate, "input"); udev_enumerate_scan_devices(enumerate); devices = udev_enumerate_get_list_entry(enumerate); udev_list_entry_foreach(dev_list_entry, devices) { const char *pPath; const char *pEvent; const char cName[] = "event"; pPath = udev_list_entry_get_name(dev_list_entry); dev = udev_device_new_from_syspath(udev, pPath); //touchScreen is usb_device dev = udev_device_get_parent_with_subsystem_devtype( dev, "usb", "usb_device"); if (!dev) { continue; } pEvent = strstr(pPath, cName); if(NULL == pEvent) { udev_device_unref(dev); continue; } const char *pProduct = udev_device_get_sysattr_value(dev,"product"); const char *pSerial = udev_device_get_sysattr_value(dev, "serial"); if(NULL == pProduct) { continue; } //有的设备没有pSerial, 可能导致映射错误, 不处理 //pProduct 是_name的子串 if((NULL == _serial)||(0 == strcmp(MONITOR_NULL_SERIAL, _serial))) { if(NULL != strstr(_name, pProduct)) { strcpy(_event, pEvent); ret = Success; udev_device_unref(dev); USD_LOG(LOG_DEBUG,"pEvent: %s _name:%s _serial:%s product:%s serial:%s" ,pEvent, _name, _serial, pProduct, pSerial); break; } } else { if((NULL != strstr(_name, pProduct)) && (0 == strcmp(_serial, pSerial))) { strcpy(_event, pEvent); ret = Success; udev_device_unref(dev); USD_LOG(LOG_DEBUG,"pEvent: %s _name:%s _serial:%s product:%s serial:%s" ,pEvent, _name, _serial, pProduct, pSerial); break; } } udev_device_unref(dev); } udev_enumerate_unref(enumerate); udev_unref(udev); return ret; } static int find_touchId_from_event(Display *_dpy, char *_event, int *pId) { int ret = -1; if((NULL == pId) || (NULL == _event) || (NULL == _dpy)) { USD_LOG(LOG_DEBUG,"parameter NULL ptr."); return ret; } int i = 0; int j = 0; int num_devices = 0; XDeviceInfo *pXDevs_info = NULL; XDevice *pXDev = NULL; unsigned char *cNode = NULL; const char cName[] = "event"; const char *cEvent = NULL; int nprops = 0; Atom *props = NULL; char *name; Atom act_type; int act_format; unsigned long nitems, bytes_after; unsigned char *data; pXDevs_info = XListInputDevices(_dpy, &num_devices); for(i = 0; i < num_devices; i++) { pXDev = XOpenDevice(_dpy, pXDevs_info[i].id); if (!pXDev) { USD_LOG(LOG_DEBUG,"unable to open device '%s'\n", pXDevs_info[i].name); continue; } props = XListDeviceProperties(_dpy, pXDev, &nprops); if (!props) { USD_LOG(LOG_DEBUG,"Device '%s' does not report any properties.\n", pXDevs_info[i].name); continue; } for(j = 0; j < nprops; j++) { name = XGetAtomName(_dpy, props[j]); if(0 != strcmp(name, "Device Node")) { continue; } XGetDeviceProperty(_dpy, pXDev, props[j], 0, 1000, False, AnyPropertyType, &act_type, &act_format, &nitems, &bytes_after, &data); cNode = data; } if(NULL == cNode) { continue; } cEvent = strstr((const char *)cNode, cName); if( 0 == strcmp(_event, cEvent)) { *pId = pXDevs_info[i].id; USD_LOG(LOG_DEBUG,"cNode:%s id:%d ",cNode, *pId); ret = Success; break; } } return ret; } static int find_touchId_from_name(Display *_dpy, char *_name, char *_serial, int *_pId) { int ret = -1; if((NULL == _name) || (NULL == _serial) || (NULL == _pId) || (NULL == _dpy)){ USD_LOG(LOG_DEBUG,"parameter NULL ptr. "); goto LEAVE; } char cEventName[32]; // eg:event25 ret = find_event_from_name(_name, _serial, cEventName); if(Success != ret) { // USD_LOG(LOG_DEBUG,"find_event_from_name ret[%d]", ret); goto LEAVE; } ret = find_touchId_from_event(_dpy, cEventName, _pId); if(Success != ret) { // USD_LOG(LOG_DEBUG,"find_touchId_from_event ret[%d]", ret); goto LEAVE; } LEAVE: return ret; } int getMapInfoListFromConfig(QString confPath,MapInfoFromFile* mapInfoList) { int ret = -1; QSettings *configIniRead = new QSettings(confPath, QSettings::IniFormat); int mapNum = configIniRead->value("/COUNT/num").toInt(); if(mapNum < 1) { return ret; } for(int i = 0; i < mapNum ;++i){ QString mapName = QString("/MAP%1/%2"); QString touchName = configIniRead->value(mapName.arg(i+1).arg("name")).toString(); QString scrname = configIniRead->value(mapName.arg(i+1).arg("scrname")).toString(); QString serial = configIniRead->value(mapName.arg(i+1).arg("serial")).toString(); if(NULL != touchName) { mapInfoList[i].sTouchName = touchName; } if(NULL != scrname) { mapInfoList[i].sMonitorName = scrname; } if(NULL != serial) { mapInfoList[i].sTouchSerial = serial; } } return mapNum; } /* * * 触摸设备映射方案: * 首先找出输出设备的尺寸,然后找到触摸设备的尺寸,最后如果尺寸一致,则为一一对应的关系,需要处理映射。 * */ void XrandrManager::SetTouchscreenCursorRotation() { int event_base, error_base, major, minor; int o; Window root; int xscreen; XRRScreenResources *res; Display *dpy = QX11Info::display(); GList *ts_devs = NULL; ts_devs = getTouchscreen (dpy); if (!g_list_length (ts_devs)) { fprintf(stdin, "No touchscreen find...\n"); return; } GList *l = NULL; if (!XRRQueryExtension (dpy, &event_base, &error_base) || !XRRQueryVersion (dpy, &major, &minor)) { fprintf (stderr, "RandR extension missing\n"); return; } xscreen = DefaultScreen (dpy); root = RootWindow (dpy, xscreen); if ( major >= 1 && minor >= 5) { res = XRRGetScreenResources (dpy, root); if (!res) return; for (o = 0; o < res->noutput; o++) { XRROutputInfo *output_info = XRRGetOutputInfo (dpy, res, res->outputs[o]); if (!output_info){ fprintf (stderr, "could not get output 0x%lx information\n", res->outputs[o]); continue; } int output_mm_width = output_info->mm_width; int output_mm_height = output_info->mm_height; if (output_info->connection == 0) { if(checkMapScreenByName(QString(output_info->name))) { continue; } USD_LOG(LOG_DEBUG,"output_info->name : %s ",output_info->name); for ( l = ts_devs; l; l = l->next) { TsInfo *info = (TsInfo *)l -> data; if(checkMapTouchDeviceById(info->dev_info.deviceid)) { continue; } gint64 width, height; QString deviceName = QString::fromLocal8Bit(info->dev_info.name); QString ouputName = QString::fromLocal8Bit(output_info->name); const char *udev_subsystems[] = {"input", NULL}; GUdevDevice *udev_device; GUdevClient *udev_client = g_udev_client_new (udev_subsystems); udev_device = g_udev_client_query_by_device_file (udev_client, (const gchar *)info->input_node); USD_LOG(LOG_DEBUG,"%s(%d) %d %d had touch",info->dev_info.name,info->dev_info.deviceid,g_udev_device_has_property(udev_device,"ID_INPUT_WIDTH_MM"), g_udev_device_has_property(udev_device,"ID_INPUT_HEIGHT_MM")); //sp1的触摸板不一定有此属性,所以根据名字进行适配by sjh 2021年10月20日11:23:58 if ((udev_device && g_udev_device_has_property (udev_device, "ID_INPUT_WIDTH_MM")) || deviceName.toUpper().contains("TOUCHPAD")) { width = g_udev_device_get_property_as_uint64 (udev_device, "ID_INPUT_WIDTH_MM"); height = g_udev_device_get_property_as_uint64 (udev_device, "ID_INPUT_HEIGHT_MM"); if (checkMatch(output_mm_width, output_mm_height, width, height)) {// doRemapAction(info->dev_info.deviceid,output_info->name); USD_LOG(LOG_DEBUG,".map checkMatch"); break; } else if (deviceName.toUpper().contains("TOUCHPAD") && ouputName == "eDP-1"){//触摸板只映射主屏幕 USD_LOG(LOG_DEBUG,".map touchpad."); doRemapAction(info->dev_info.deviceid,output_info->name); break; } } g_clear_object (&udev_client); } /*屏幕尺寸与触摸设备对应不上且未映射,映射剩下的设备*/ for ( l = ts_devs; l; l = l->next) { TsInfo *info = (TsInfo *)l -> data; if(checkMapTouchDeviceById(info->dev_info.deviceid) || checkMapScreenByName(QString(output_info->name))) { continue; } QString deviceName = QString::fromLocal8Bit(info->dev_info.name); const char *udev_subsystems[] = {"input", NULL}; GUdevDevice *udev_device; GUdevClient *udev_client = g_udev_client_new (udev_subsystems); udev_device = g_udev_client_query_by_device_file (udev_client, (const gchar *)info->input_node); USD_LOG(LOG_DEBUG,"Size correspondence error"); if ((udev_device && g_udev_device_has_property (udev_device, "ID_INPUT_WIDTH_MM")) || deviceName.toUpper().contains("TOUCHPAD")) { doRemapAction(info->dev_info.deviceid,output_info->name); } g_clear_object (&udev_client); } } } }else { g_list_free(ts_devs); fprintf(stderr, "xrandr extension too low\n"); return; } g_list_free(ts_devs); } void XrandrManager::intel_SetTouchscreenCursorRotation() { int event_base, error_base, major, minor; int o; Window root; int xscreen; XRRScreenResources *res; Display *dpy = QX11Info::display(); GList *ts_devs = NULL; ts_devs = getTouchscreen (dpy); if (!g_list_length (ts_devs)) { fprintf(stdin, "No touchscreen find...\n"); return; } GList *l = NULL; if (!XRRQueryExtension (dpy, &event_base, &error_base) || !XRRQueryVersion (dpy, &major, &minor)) { fprintf (stderr, "RandR extension missing\n"); return; } xscreen = DefaultScreen (dpy); root = RootWindow (dpy, xscreen); if ( major >= 1 && minor >= 5) { res = XRRGetScreenResources (dpy, root); if (!res) return; for (o = 0; o < res->noutput; o++) { XRROutputInfo *output_info = XRRGetOutputInfo (dpy, res, res->outputs[o]); if (!output_info){ fprintf (stderr, "could not get output 0x%lx information\n", res->outputs[o]); continue; } int output_mm_width = output_info->mm_width; int output_mm_height = output_info->mm_height; if (output_info->connection == 0) { for ( l = ts_devs; l; l = l->next) { TsInfo *info = (TsInfo *)l -> data; double width, height; QString deviceName = QString::fromLocal8Bit(info->dev_info.name); QString ouputName = QString::fromLocal8Bit(output_info->name); const char *udev_subsystems[] = {"input", NULL}; GUdevDevice *udev_device; GUdevClient *udev_client = g_udev_client_new (udev_subsystems); udev_device = g_udev_client_query_by_device_file (udev_client, (const gchar *)info->input_node); USD_LOG(LOG_DEBUG,"%s(%d) %d %d had touch",info->dev_info.name,info->dev_info.deviceid,g_udev_device_has_property(udev_device,"ID_INPUT_WIDTH_MM"), g_udev_device_has_property(udev_device,"ID_INPUT_HEIGHT_MM")); //sp1的触摸板不一定有此属性,所以根据名字进行适配by sjh 2021年10月20日11:23:58 if ((udev_device && g_udev_device_has_property (udev_device, "ID_INPUT_WIDTH_MM")) || deviceName.toUpper().contains("TOUCHPAD")) { width = g_udev_device_get_property_as_double (udev_device, "ID_INPUT_WIDTH_MM"); height = g_udev_device_get_property_as_double (udev_device, "ID_INPUT_HEIGHT_MM"); if (checkMatch(output_mm_width, output_mm_height, width, height)) {// USD_LOG(LOG_DEBUG,".output_mm_width:%d output_mm_height:%d width:%d. height:%d",output_mm_width,output_mm_height,width,height); doRemapAction(info->dev_info.deviceid,output_info->name); } else if (deviceName.toUpper().contains("TOUCHPAD") && ouputName == "eDP-1"){//触摸板只映射主屏幕 USD_LOG(LOG_DEBUG,".map touchpad."); doRemapAction(info->dev_info.deviceid,output_info->name); } } g_clear_object (&udev_client); } } } }else { g_list_free(ts_devs); fprintf(stderr, "xrandr extension too low\n"); return; } g_list_free(ts_devs); } void XrandrManager::remapFromConfig(QString mapPath) { MapInfoFromFile mapInfoList[64]; Display *pDpy = XOpenDisplay(NULL); int deviceId = 0; int mapNum = getMapInfoListFromConfig(mapPath,mapInfoList); USD_LOG(LOG_DEBUG,"getMapInfoListFromConfig : %d",mapNum); if(mapNum < 1) { USD_LOG(LOG_DEBUG,"get map num error"); SetTouchscreenCursorRotation(); return; } for (int i = 0; i < mapNum; ++i) { int ret = find_touchId_from_name(pDpy, mapInfoList[i].sTouchName.toLatin1().data(),mapInfoList[i].sTouchSerial.toLatin1().data(), &deviceId); USD_LOG(LOG_DEBUG,"find_touchId_from_name : %d",deviceId); if(Success == ret){ //屏幕连接时进行映射 if(checkScreenByName(mapInfoList[i].sMonitorName)) { doRemapAction(deviceId,mapInfoList[i].sMonitorName.toLatin1().data(),true); } } } } void XrandrManager::orientationChangedProcess(Qt::ScreenOrientation orientation) { // SetTouchscreenCursorRotation(); autoRemapTouchscreen(); } /*监听旋转键值回调 并设置旋转角度*/ void XrandrManager::RotationChangedEvent(const QString &rotation) { int value = 0; QString angle_Value = rotation; if (angle_Value == "normal") { value = 1; } else if (angle_Value == "left") { value = 2; } else if (angle_Value == "upside-down") { value = 4; } else if (angle_Value == "right") { value = 8; } else { USD_LOG(LOG_ERR,"Find a error !!!"); return ; } const KScreen::OutputList outputs = mMonitoredConfig->data()->outputs(); for(auto output : outputs){ if (!output->isConnected() || !output->isEnabled() || !output->currentMode()) { continue; } output->setRotation(static_cast(value)); // qDebug()<rotation() <name(); USD_LOG(LOG_DEBUG,"set %s rotaion:%s", output->name().toLatin1().data(), rotation.toLatin1().data()); } applyConfig(); } void XrandrManager::applyIdealConfig() { // const bool showOsd = mMonitoredConfig->data()->connectedOutputs().count() > 1 && !mStartingUp; //qDebug()<<"show Sod is "<(new xrandrConfig(config)); configWrapper->setValidityFlags(KScreen::Config::ValidityFlag::RequireAtLeastOneEnabledScreen); doApplyConfig(std::move(configWrapper)); } void XrandrManager::doApplyConfig(std::unique_ptr config) { mMonitoredConfig = std::move(config); //monitorsInit(); refreshConfig(); primaryScreenChange(); } void XrandrManager::refreshConfig() { } void XrandrManager::saveCurrentConfig() { } void XrandrManager::configChanged() { } void XrandrManager::setMonitorForChanges(bool enabled) { if (mMonitoring == enabled) { return; } mMonitoring = enabled; if (mMonitoring) { connect(KScreen::ConfigMonitor::instance(), &KScreen::ConfigMonitor::configurationChanged, this, &XrandrManager::configChanged, Qt::UniqueConnection); } else { disconnect(KScreen::ConfigMonitor::instance(), &KScreen::ConfigMonitor::configurationChanged, this, &XrandrManager::configChanged); } } void XrandrManager::applyKnownConfig(bool state) { } void XrandrManager::autoRemapTouchscreen() { if(UsdBaseClass::isTablet()) { intel_SetTouchscreenCursorRotation(); } else { qDeleteAll(mTouchMapList); mTouchMapList.clear(); QString configPath = QDir::homePath() + MAP_CONFIG; QFileInfo file(configPath); if(file.exists()) { remapFromConfig(configPath); } SetTouchscreenCursorRotation(); } } void XrandrManager::init_primary_screens (KScreen::ConfigPtr Config) { } void XrandrManager::sendScreenModeToDbus() { const QStringList ukccModeList = {"first", "copy", "expand", "second"}; int screenConnectedCount = 0; int screenMode = discernScreenMode(); mDbus->sendModeChangeSignal(screenMode); mDbus->sendScreensParamChangeSignal(mMonitoredConfig->getScreensParam()); ///send screens mode to ukcc(ukui-control-center) by sjh 2021.11.08 Q_FOREACH (const KScreen::OutputPtr &output, mMonitoredConfig->data()->outputs()) { if (true == output->isConnected()) { screenConnectedCount++; } } if (screenConnectedCount > 1) { mUkccDbus->call("setScreenMode", ukccModeList[screenMode]); } else { mUkccDbus->call("setScreenMode", ukccModeList[0]); } } void XrandrManager::applyConfig() { if (mMonitoredConfig->canBeApplied()) { connect(new KScreen::SetConfigOperation(mMonitoredConfig->data()), &KScreen::SetConfigOperation::finished, this, [this]() { autoRemapTouchscreen(); sendScreenModeToDbus(); }); } else { USD_LOG(LOG_ERR,"--|can't be apply|--"); Q_FOREACH (const KScreen::OutputPtr &output, mMonitoredConfig->data()->outputs()) { USD_LOG_SHOW_OUTPUT(output); } } } void XrandrManager::outputConnectedChanged() { } void XrandrManager::outputAddedHandle(const KScreen::OutputPtr &output) { // USD_LOG(LOG_DEBUG,"."); } void XrandrManager::outputRemoved(int outputId) { // USD_LOG(LOG_DEBUG,"."); } void XrandrManager::primaryOutputChanged(const KScreen::OutputPtr &output) { // USD_LOG(LOG_DEBUG,"."); } void XrandrManager::primaryScreenChange() { // USD_LOG(LOG_DEBUG,"."); } void XrandrManager::callMethod(QRect geometry, QString name) { Q_UNUSED(geometry); Q_UNUSED(name); } /* * *接入时没有配置文件的处理流程: *单屏:最优分辨率。 *多屏幕:镜像模式。 * */ void XrandrManager::outputConnectedWithoutConfigFile(KScreen::Output *newOutput, char outputCount) { if (1 == outputCount) {//单屏接入时需要设置模式,主屏 setScreenMode(metaEnum.key(UsdBaseClass::eScreenMode::firstScreenMode)); } else { setScreenMode(metaEnum.key(UsdBaseClass::eScreenMode::cloneScreenMode)); } } void XrandrManager::lightLastScreen() { int enableCount = 0; int connectCount = 0; Q_FOREACH(const KScreen::OutputPtr &output,mMonitoredConfig->data()->outputs()) { if (output->isConnected()){ connectCount++; } if (output->isEnabled()){ enableCount++; } } if (connectCount==1 && enableCount==0){ Q_FOREACH(const KScreen::OutputPtr &output,mMonitoredConfig->data()->outputs()) { if (output->isConnected()){ output->setEnabled(true); break; } } } } uint8_t XrandrManager::getCurrentRotation() { uint8_t ret = 1; QDBusMessage message = QDBusMessage::createMethodCall(DBUS_STATUSMANAGER_NAME, DBUS_STATUSMANAGER_PATH, DBUS_STATUSMANAGER_NAME, DBUS_STATUSMANAGER_GET_ROTATION); QDBusMessage response = QDBusConnection::sessionBus().call(message); if (response.type() == QDBusMessage::ReplyMessage) { if(response.arguments().isEmpty() == false) { QString value = response.arguments().takeFirst().toString(); USD_LOG(LOG_DEBUG, "get mode :%s", value.toLatin1().data()); if (value == "normal") { ret = 1; } else if (value == "left") { ret = 2; } else if (value == "upside-down") { ret = 4; } else if (value == "right") { ret = 8; } else { USD_LOG(LOG_DEBUG,"Find a error !!! value%s",value.toLatin1().data()); return ret = 1; } } } return ret; } /* * * -1:无接口 * 0:PC模式 * 1:tablet模式 * */ int8_t XrandrManager::getCurrentMode() { QDBusMessage message = QDBusMessage::createMethodCall(DBUS_STATUSMANAGER_NAME, DBUS_STATUSMANAGER_PATH, DBUS_STATUSMANAGER_NAME, DBUS_STATUSMANAGER_GET_MODE); QDBusMessage response = QDBusConnection::sessionBus().call(message); if (response.type() == QDBusMessage::ReplyMessage) { if(response.arguments().isEmpty() == false) { bool value = response.arguments().takeFirst().toBool(); // USD_LOG(LOG_DEBUG, "get mode :%d", value); return value; } } return -1; } void XrandrManager::outputChangedHandle(KScreen::Output *senderOutput) { char outputConnectCount = 0; Q_FOREACH(const KScreen::OutputPtr &output, mMonitoredConfig->data()->outputs()) { if (output->name()==senderOutput->name() && output->hash()!=senderOutput->hash()) { senderOutput->setEnabled(true); mMonitoredConfig->data()->removeOutput(output->id()); mMonitoredConfig->data()->addOutput(senderOutput->clone()); break; } } Q_FOREACH(const KScreen::OutputPtr &output,mMonitoredConfig->data()->outputs()) { if (output->name()==senderOutput->name()) {//这里只设置connect,enbale由配置设置。 output->setEnabled(senderOutput->isConnected()); output->setConnected(senderOutput->isConnected()); if (0 == output->modes().count()) { output->setModes(senderOutput->modes()); } } if (output->isConnected()) { outputConnectCount++; } } if (UsdBaseClass::isTablet()) { int ret = getCurrentMode(); USD_LOG(LOG_DEBUG,"intel edu is't need use config file"); if (0 < ret) { //tablet模式 setScreenMode(metaEnum.key(UsdBaseClass::eScreenMode::cloneScreenMode)); } else { //PC模式 setScreenMode(metaEnum.key(UsdBaseClass::eScreenMode::extendScreenMode)); } } else {//非intel项目无此接口 if (false == mMonitoredConfig->fileExists()) { if (senderOutput->isConnected()) { senderOutput->setEnabled(senderOutput->isConnected()); } outputConnectedWithoutConfigFile(senderOutput, outputConnectCount); } else { if (outputConnectCount) { std::unique_ptr MonitoredConfig = mMonitoredConfig->readFile(false); if (MonitoredConfig!=nullptr) { mMonitoredConfig = std::move(MonitoredConfig); } else { USD_LOG(LOG_DEBUG,"read config file error! "); } } } } applyConfig(); } //处理来自控制面板的操作,保存配置 void XrandrManager::SaveConfigTimerHandle() { int enableScreenCount = 0; mSaveConfigTimer->stop(); if (false == mIsApplyConfigWhenSave) { Q_FOREACH(const KScreen::OutputPtr &output, mMonitoredConfig->data()->outputs()) { if (output->isEnabled()) { enableScreenCount++; } } if (0 == enableScreenCount) {//When user disable last one connected screen USD must enable the screen. mIsApplyConfigWhenSave = true; mSaveConfigTimer->start(SAVE_CONFIG_TIME*5); return; } } if (mIsApplyConfigWhenSave) { mIsApplyConfigWhenSave = false; setScreenMode(metaEnum.key(UsdBaseClass::eScreenMode::firstScreenMode)); } else { mMonitoredConfig->setScreenMode(metaEnum.valueToKey(discernScreenMode())); mMonitoredConfig->writeFile(true); // SetTouchscreenCursorRotation();//When other app chenge screen'param usd must remap touch device autoRemapTouchscreen(); sendScreenModeToDbus(); } } QString XrandrManager::getScreesParam() { return mMonitoredConfig->getScreensParam(); } void XrandrManager::monitorsInit() { char connectedOutputCount = 0; if (mConfig) { KScreen::ConfigMonitor::instance()->removeConfig(mConfig); for (const KScreen::OutputPtr &output : mConfig->outputs()) { output->disconnect(this); } mConfig->disconnect(this); } mConfig = std::move(mMonitoredConfig->data()); for (const KScreen::OutputPtr &output: mConfig->outputs()) { USD_LOG_SHOW_OUTPUT(output); if (output->isConnected()){ connectedOutputCount++; } connect(output.data(), &KScreen::Output::outputChanged, this, [this](){ KScreen::Output *senderOutput = static_cast (sender()); outputChangedHandle(senderOutput); mSaveConfigTimer->start(SAVE_CONFIG_TIME); }); connect(output.data(), &KScreen::Output::isPrimaryChanged, this, [this](){ KScreen::Output *senderOutput = static_cast (sender()); USD_LOG(LOG_DEBUG,"PrimaryChanged:%s",senderOutput->name().toLatin1().data()); Q_FOREACH(const KScreen::OutputPtr &output,mMonitoredConfig->data()->outputs()) { if (output->name() == senderOutput->name()) { output->setPrimary(senderOutput->isPrimary()); break; } } mSaveConfigTimer->start(SAVE_CONFIG_TIME); }); connect(output.data(), &KScreen::Output::posChanged, this, [this](){ KScreen::Output *senderOutput = static_cast (sender()); USD_LOG(LOG_DEBUG,"posChanged:%s",senderOutput->name().toLatin1().data()); Q_FOREACH(const KScreen::OutputPtr &output,mMonitoredConfig->data()->outputs()) { if (output->name() == senderOutput->name()) { output->setPos(senderOutput->pos()); break; } } mSaveConfigTimer->start(SAVE_CONFIG_TIME); }); connect(output.data(), &KScreen::Output::sizeChanged, this, [this](){ KScreen::Output *senderOutput = static_cast (sender()); USD_LOG(LOG_DEBUG,"sizeChanged:%s",senderOutput->name().toLatin1().data()); mSaveConfigTimer->start(SAVE_CONFIG_TIME); }); connect(output.data(), &KScreen::Output::clonesChanged, this, [this](){ KScreen::Output *senderOutput = static_cast (sender()); USD_LOG(LOG_DEBUG,"clonesChanged:%s",senderOutput->name().toLatin1().data()); mSaveConfigTimer->start(SAVE_CONFIG_TIME); }); connect(output.data(), &KScreen::Output::rotationChanged, this, [this](){ KScreen::Output *senderOutput = static_cast (sender()); USD_LOG(LOG_DEBUG,"clonesChanged:%s",senderOutput->name().toLatin1().data()); Q_FOREACH(const KScreen::OutputPtr &output,mMonitoredConfig->data()->outputs()) { if (output->name() == senderOutput->name()) { output->setRotation(senderOutput->rotation()); break; } } USD_LOG(LOG_DEBUG,"rotationChanged:%s",senderOutput->name().toLatin1().data()); mSaveConfigTimer->start(SAVE_CONFIG_TIME); }); connect(output.data(), &KScreen::Output::currentModeIdChanged, this, [this](){ KScreen::Output *senderOutput = static_cast (sender()); USD_LOG(LOG_DEBUG,"currentModeIdChanged:%s",senderOutput->name().toLatin1().data()); Q_FOREACH(const KScreen::OutputPtr &output,mMonitoredConfig->data()->outputs()) { if (output->name() == senderOutput->name()) { output->setCurrentModeId(senderOutput->currentModeId()); output->setEnabled(senderOutput->isEnabled()); break; } } mSaveConfigTimer->start(SAVE_CONFIG_TIME); }); connect(output.data(), &KScreen::Output::isEnabledChanged, this, [this](){ KScreen::Output *senderOutput = static_cast (sender()); USD_LOG(LOG_DEBUG,"isEnabledChanged:%s",senderOutput->name().toLatin1().data()); Q_FOREACH(const KScreen::OutputPtr &output,mMonitoredConfig->data()->outputs()) { if (output->name() == senderOutput->name()) { output->setEnabled(senderOutput->isEnabled()); break; } } mSaveConfigTimer->start(SAVE_CONFIG_TIME); }); } KScreen::ConfigMonitor::instance()->addConfig(mConfig); //connect(mConfig.data(), &KScreen::Config::outputAdded, // this, &XrandrManager::outputAddedHandle); connect(mConfig.data(), SIGNAL(outputAdded(KScreen::OutputPtr)), this, SLOT(outputAddedHandle(KScreen::OutputPtr))); connect(mConfig.data(), &KScreen::Config::outputRemoved, this, &XrandrManager::outputRemoved, static_cast(Qt::QueuedConnection | Qt::UniqueConnection)); connect(mConfig.data(), &KScreen::Config::primaryOutputChanged, this, &XrandrManager::primaryOutputChanged); if (mMonitoredConfig->fileExists()) { USD_LOG(LOG_DEBUG,"read config:%s.",mMonitoredConfig->filePath().toLatin1().data()); if (UsdBaseClass::isTablet()) { for (const KScreen::OutputPtr &output: mConfig->outputs()) { if (output->isConnected() && output->isEnabled()) { output->setRotation(static_cast(getCurrentRotation())); } } } else { std::unique_ptr MonitoredConfig = mMonitoredConfig->readFile(false); if (MonitoredConfig == nullptr ) { USD_LOG(LOG_DEBUG,"config a error"); setScreenMode(metaEnum.key(UsdBaseClass::eScreenMode::cloneScreenMode)); return; } mMonitoredConfig = std::move(MonitoredConfig); } applyConfig(); } else { int foreachTimes = 0; USD_LOG(LOG_DEBUG,"creat a config:%s.",mMonitoredConfig->filePath().toLatin1().data()); for (const KScreen::OutputPtr &output: mMonitoredConfig->data()->outputs()) { USD_LOG_SHOW_OUTPUT(output); if (1==connectedOutputCount){ outputChangedHandle(output.data()); break; } else { if (output->isConnected()){ foreachTimes++; } if (foreachTimes>1) { USD_LOG_SHOW_OUTPUT(output); outputChangedHandle(output.data()); break; } } } mMonitoredConfig->writeFile(false); } } bool XrandrManager::checkPrimaryScreenIsSetable() { int connecedScreenCount = 0; Q_FOREACH(const KScreen::OutputPtr &output, mMonitoredConfig->data()->outputs()){ if (output->isConnected()){ connecedScreenCount++; } } if (connecedScreenCount < 2) { USD_LOG(LOG_DEBUG, "skip set command cuz ouputs count :%d connected:%d",mMonitoredConfig->data()->outputs().count(), connecedScreenCount); return false; } if (nullptr == mMonitoredConfig->data()->primaryOutput()){ USD_LOG(LOG_DEBUG,"can't find primary screen."); Q_FOREACH(const KScreen::OutputPtr &output, mMonitoredConfig->data()->outputs()) { if (output->isConnected()) { output->setPrimary(true); output->setEnabled(true); USD_LOG(LOG_DEBUG,"set %s as primary screen.",output->name().toLatin1().data()); break; } } } return true; } bool XrandrManager::readAndApplyScreenModeFromConfig(UsdBaseClass::eScreenMode eMode) { if (UsdBaseClass::isTablet()) { return false; } mMonitoredConfig->setScreenMode(metaEnum.valueToKey(eMode)); if (mMonitoredConfig->fileScreenModeExists(metaEnum.valueToKey(eMode))) { std::unique_ptr MonitoredConfig = mMonitoredConfig->readFile(true); if (MonitoredConfig == nullptr) { USD_LOG(LOG_DEBUG,"config a error"); return false; } else { mMonitoredConfig = std::move(MonitoredConfig); applyConfig(); return true; } } return false; } void XrandrManager::TabletSettingsChanged(const bool tablemode) { if(tablemode) { setScreenMode(metaEnum.key(UsdBaseClass::eScreenMode::cloneScreenMode)); } else { setScreenMode(metaEnum.key(UsdBaseClass::eScreenMode::extendScreenMode)); } USD_LOG(LOG_DEBUG,"recv mode changed:%d", tablemode); } void XrandrManager::setScreenModeToClone() { int bigestResolution = 0; bool hadFindFirstScreen = false; QString primaryModeId; QString secondaryModeId; QString secondScreen; QSize primarySize(0,0); float primaryRefreshRate = 0; float secondaryRefreshRate = 0; KScreen::OutputPtr primaryOutput;// = mMonitoredConfig->data()->primaryOutput(); if (false == checkPrimaryScreenIsSetable()) { return; } if (readAndApplyScreenModeFromConfig(UsdBaseClass::eScreenMode::cloneScreenMode)) { return; } Q_FOREACH(const KScreen::OutputPtr &output, mMonitoredConfig->data()->outputs()) { if (false == output->isConnected()) { continue; } output->setEnabled(true); if (false == hadFindFirstScreen) { hadFindFirstScreen = true; primaryOutput = output; continue; } secondScreen = output->name().toLatin1().data(); //遍历模式找出最大分辨率的克隆模式 Q_FOREACH (auto primaryMode, primaryOutput->modes()) { Q_FOREACH (auto newOutputMode, output->modes()) { primaryOutput->setPos(QPoint(0,0)); output->setPos(QPoint(0,0)); bigestResolution = primarySize.width()*primarySize.height(); if (primaryMode->size() == newOutputMode->size()) { if (bigestResolution < primaryMode->size().width() * primaryMode->size().height()) { primarySize = primaryMode->size(); primaryRefreshRate = primaryMode->refreshRate(); primaryOutput->setCurrentModeId(primaryMode->id()); secondaryRefreshRate = newOutputMode->refreshRate(); output->setCurrentModeId(newOutputMode->id()); } else if (bigestResolution == primaryMode->size().width() * primaryMode->size().height()) { if (primaryRefreshRate < primaryMode->refreshRate()) { primaryRefreshRate = primaryMode->refreshRate(); primaryOutput->setCurrentModeId(primaryMode->id()); } if (secondaryRefreshRate < newOutputMode->refreshRate()) { secondaryRefreshRate = newOutputMode->refreshRate(); output->setCurrentModeId(newOutputMode->id()); } } } } } if (UsdBaseClass::isTablet()) { output->setRotation(static_cast(getCurrentRotation())); primaryOutput->setRotation(static_cast(getCurrentRotation())); } USD_LOG_SHOW_OUTPUT(output); } if (0 == bigestResolution) { setScreenMode(metaEnum.key(UsdBaseClass::eScreenMode::extendScreenMode)); } else { applyConfig(); } } void XrandrManager::setScreenModeToFirst(bool isFirstMode) { int posX = 0; int maxScreenSize = 0; bool hadFindFirstScreen = false; bool hadSetPrimary = false; float refreshRate = 0.0; if (false == checkPrimaryScreenIsSetable()) { //return; //因为有用户需要在只有一个屏幕的情况下进行了打开,所以必须走如下流程。 } if (isFirstMode){ if (readAndApplyScreenModeFromConfig(UsdBaseClass::eScreenMode::firstScreenMode)) { return; } } else { if (readAndApplyScreenModeFromConfig(UsdBaseClass::eScreenMode::secondScreenMode)) { return; } } Q_FOREACH(const KScreen::OutputPtr &output, mMonitoredConfig->data()->outputs()) { if (output->isConnected()) { output->setEnabled(true); } else { continue; } //找到第一个屏幕(默认为内屏) if (hadFindFirstScreen) { output->setEnabled(!isFirstMode); } else { hadFindFirstScreen = true; output->setEnabled(isFirstMode); } if (output->isEnabled()) { if(hadSetPrimary) { output->setPrimary(false); } else { hadSetPrimary = true; output->setPrimary(true); } Q_FOREACH (auto Mode, output->modes()){ if (Mode->size().width()*Mode->size().height() < maxScreenSize) { continue; } else if (Mode->size().width()*Mode->size().height() == maxScreenSize) { if (refreshRate < Mode->refreshRate()) { refreshRate = Mode->refreshRate(); output->setCurrentModeId(Mode->id()); USD_LOG(LOG_DEBUG,"use mode :%s %f",Mode->id().toLatin1().data(), Mode->refreshRate()); } continue; } maxScreenSize = Mode->size().width()*Mode->size().height(); output->setCurrentModeId(Mode->id()); USD_LOG_SHOW_PARAM1(maxScreenSize); } output->setPos(QPoint(posX,0)); posX+=output->size().width(); } USD_LOG_SHOW_OUTPUT(output); } applyConfig(); } void XrandrManager::setScreenModeToExtend() { int primaryX = 0; int screenSize = 0; int singleMaxWidth = 0; if (false == checkPrimaryScreenIsSetable()) { return; } if (readAndApplyScreenModeFromConfig(UsdBaseClass::eScreenMode::extendScreenMode)) { return; } Q_FOREACH(const KScreen::OutputPtr &output, mMonitoredConfig->data()->outputs()) { screenSize = 0; singleMaxWidth = 0; USD_LOG_SHOW_OUTPUT(output); if (output->isConnected()){ output->setEnabled(true); } else { output->setEnabled(false); continue; } Q_FOREACH (auto Mode, output->modes()){ if (Mode->size().width()*Mode->size().height() > screenSize) { screenSize = Mode->size().width()*Mode->size().height(); output->setCurrentModeId(Mode->id()); if (Mode->size().width() > singleMaxWidth) { singleMaxWidth = Mode->size().width(); } } } if (UsdBaseClass::isTablet()) { output->setRotation(static_cast(getCurrentRotation())); } output->setPos(QPoint(primaryX,0)); primaryX += singleMaxWidth; USD_LOG_SHOW_OUTPUT(output); } applyConfig(); } void XrandrManager::setScreensParam(QString screensParam) { USD_LOG(LOG_DEBUG,"param:%s", screensParam.toLatin1().data()); std::unique_ptr temp = mMonitoredConfig->readScreensConfigFromDbus(screensParam); if (nullptr != temp) { mMonitoredConfig = std::move(temp); } applyConfig(); } /* * 设置显示模式 */ void XrandrManager::setScreenMode(QString modeName) { //检查当前屏幕数量,只有一个屏幕时不设置 int screenConnectedCount = 0; int modeValue = metaEnum.keyToValue(modeName.toLatin1().data()); Q_FOREACH (const KScreen::OutputPtr &output, mMonitoredConfig->data()->outputs()) { if (true == output->isConnected()) { screenConnectedCount++; } } if(screenConnectedCount <= 1) { if (modeValue == UsdBaseClass::eScreenMode::cloneScreenMode || modeValue == UsdBaseClass::eScreenMode::extendScreenMode) { return; } } switch (modeValue) { case UsdBaseClass::eScreenMode::cloneScreenMode: USD_LOG(LOG_DEBUG,"ready set mode to %s",modeName.toLatin1().data()); setScreenModeToClone(); break; case UsdBaseClass::eScreenMode::firstScreenMode: USD_LOG(LOG_DEBUG,"ready set mode to %s",modeName.toLatin1().data()); setScreenModeToFirst(true); break; case UsdBaseClass::eScreenMode::secondScreenMode: USD_LOG(LOG_DEBUG,"ready set mode to %s",modeName.toLatin1().data()); setScreenModeToFirst(false); break; case UsdBaseClass::eScreenMode::extendScreenMode: USD_LOG(LOG_DEBUG,"ready set mode to %s",modeName.toLatin1().data()); setScreenModeToExtend(); break; default: USD_LOG(LOG_DEBUG,"set mode fail can't set to %s",modeName.toLatin1().data()); return; } sendScreenModeToDbus(); } /* * 识别当前显示的模式 */ UsdBaseClass::eScreenMode XrandrManager::discernScreenMode() { bool firstScreenIsEnable = false; bool secondScreenIsEnable = false; bool hadFindFirstScreen = false; QPoint firstScreenQPoint; QPoint secondScreenQPoint; QSize firstScreenQsize; QSize secondScreenQsize; Q_FOREACH (const KScreen::OutputPtr &output, mMonitoredConfig->data()->outputs()) { if (output->isConnected()) { if (false == hadFindFirstScreen) { firstScreenIsEnable = output->isEnabled(); if (output->isEnabled() && output->currentMode()!=nullptr) { firstScreenQsize = output->currentMode()->size(); firstScreenQPoint = output->pos(); } hadFindFirstScreen = true; } else { secondScreenIsEnable = output->isEnabled(); secondScreenQPoint = output->pos(); if (secondScreenIsEnable && output->currentMode()!=nullptr) { secondScreenQsize = output->currentMode()->size(); } break; } } } if (true == firstScreenIsEnable && false == secondScreenIsEnable) { USD_LOG(LOG_DEBUG,"mode : firstScreenMode"); return UsdBaseClass::eScreenMode::firstScreenMode; } if (false == firstScreenIsEnable && true == secondScreenIsEnable) { USD_LOG(LOG_DEBUG,"mode : secondScreenMode"); return UsdBaseClass::eScreenMode::secondScreenMode; } if (firstScreenQPoint == secondScreenQPoint && firstScreenQsize==secondScreenQsize) { USD_LOG(LOG_DEBUG,"mode : cloneScreenMode"); return UsdBaseClass::eScreenMode::cloneScreenMode; } USD_LOG(LOG_DEBUG,"mode : extendScreenMode"); return UsdBaseClass::eScreenMode::extendScreenMode; } void XrandrManager::screenModeChangedSignal(int mode) { USD_LOG(LOG_DEBUG,"mode:%d",mode); } void XrandrManager::screensParamChangedSignal(QString param) { USD_LOG(LOG_DEBUG,"param:%s",param.toLatin1().data()); } void XrandrManager::controlScreenMap(const QString screenMap) { USD_LOG(LOG_DEBUG,"controlScreenMap ..."); RotationChangedEvent(screenMap); } /** * @brief XrandrManager::StartXrandrIdleCb * 开始时间回调函数 */ void XrandrManager::StartXrandrIdleCb() { mAcitveTime->stop(); mSaveConfigTimer = new QTimer(this); connect(mSaveConfigTimer, SIGNAL(timeout()), this, SLOT(SaveConfigTimerHandle())); USD_LOG(LOG_DEBUG,"StartXrandrIdleCb ok."); // QMetaObject::invokeMethod(this, "getInitialConfig", Qt::QueuedConnection); connect(mKscreenInitTimer, SIGNAL(timeout()), this, SLOT(getInitialConfig())); mKscreenInitTimer->start(1500); connect(mDbus, SIGNAL(setScreenModeSignal(QString)), this, SLOT(setScreenMode(QString))); connect(mDbus, SIGNAL(setScreensParamSignal(QString)), this, SLOT(setScreensParam(QString))); #if 0 QDBusInterface *modeChangedSignalHandle = new QDBusInterface(DBUS_XRANDR_NAME,DBUS_XRANDR_PATH,DBUS_XRANDR_INTERFACE,QDBusConnection::sessionBus(),this); if (modeChangedSignalHandle->isValid()) { connect(modeChangedSignalHandle, SIGNAL(screenModeChanged(int)), this, SLOT(screenModeChangedSignal(int))); } else { USD_LOG(LOG_ERR, "modeChangedSignalHandle"); } QDBusInterface *screensChangedSignalHandle = new QDBusInterface(DBUS_XRANDR_NAME,DBUS_XRANDR_PATH,DBUS_XRANDR_INTERFACE,QDBusConnection::sessionBus(),this); if (screensChangedSignalHandle->isValid()) { connect(screensChangedSignalHandle, SIGNAL(screensParamChanged(QString)), this, SLOT(screensParamChangedSignal(QString))); //USD_LOG(LOG_DEBUG, ".."); } else { USD_LOG(LOG_ERR, "screensChangedSignalHandle"); } #endif } ukui-settings-daemon/plugins/xrandr/xrandr.pro0000644000175000017500000000174014205117202020545 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-05-10T09:30:00 # #------------------------------------------------- QT += gui QT += core xml widgets x11extras dbus KGlobalAccel TEMPLATE = lib DEFINES += XRANDR_LIBRARY _FORTIFY_SOURCE=2 CONFIG += c++11 no_keywords link_pkgconfig plugin xrandr CONFIG += app_bundle DEFINES += QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"xrandr\\\" include($$PWD/../../common/common.pri) PKGCONFIG += \ Qt5Sensors \ kscreen2 \ x11 \ xi \ gudev-1.0 SOURCES += \ xrandr-adaptor.cpp \ xrandr-config.cpp \ xrandr-dbus.cpp \ xrandr-manager.cpp \ xrandr-output.cpp \ xrandr-plugin.cpp HEADERS += \ xrandr-adaptor.h \ xrandr-config.h \ xrandr-dbus.h \ xrandr-manager.h \ xrandr-output.h \ xrandr-plugin.h xrandr_lib.path = $${PLUGIN_INSTALL_DIRS} xrandr_lib.files = $$OUT_PWD/libxrandr.so INSTALLS += xrandr_lib ukui-settings-daemon/plugins/xrandr/xrandr-dbus.h0000644000175000017500000000376414205117202021137 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XRANDRDBUS_H #define XRANDRDBUS_H #include #include #include "usd_global_define.h" class xrandrDbus : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface",DBUS_XRANDR_INTERFACE) public: xrandrDbus(QObject* parent=0); ~xrandrDbus(); void sendModeChangeSignal(int screensMode); void sendScreensParamChangeSignal(QString screensParam); public Q_SLOTS: int setScreenMode(QString modeName, QString appName); int getScreenMode(QString appName); int setScreensParam(QString screensParam, QString appName); QString getScreensParam(QString appName); void setScreenMap(); QString controlScreenSlot(const QString &arg); Q_SIGNALS: //供xrandrManager监听 void setScreenModeSignal(QString modeName); void setScreensParamSignal(QString screensParam); //与adaptor一致 void screensParamChanged(QString screensParam); void screenModeChanged(int screenMode); //控制面板旋转触摸映射 void controlScreen(QString conRotation); public: int mX = 0; int mY = 0; int mWidth = 0; int mHeight = 0; double mScale = 1.0; int mScreenMode = 0; QString mName; QGSettings *mXsettings; }; #endif // XRANDRDBUS_H ukui-settings-daemon/plugins/xrandr/xrandr-adaptor.h0000644000175000017500000000675514205117202021637 0ustar fengfeng/* * This file was generated by qdbusxml2cpp version 0.8 * Command line was: qdbusxml2cpp usd-xrandr-manager.xml -a xrandr-adaptor * * qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. * * This is an auto-generated file. * This file may have been hand-edited. Look for HAND-EDIT comments * before re-generating it. */ #ifndef XRANDR_ADAPTOR_H #define XRANDR_ADAPTOR_H #include #include QT_BEGIN_NAMESPACE class QByteArray; template class QList; template class QMap; class QString; class QStringList; class QVariant; QT_END_NAMESPACE /* * Adaptor class for interface org.ukui.SettingsDaemon.xrandr */ class XrandrAdaptor: public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.ukui.SettingsDaemon.xrandr") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") public: XrandrAdaptor(QObject *parent); virtual ~XrandrAdaptor(); public: // PROPERTIES public Q_SLOTS: // METHODS int setScreenMode(const QString &modeName, const QString &appName); int setScreensParam(const QString &modeName, const QString &appName); int getScreenMode(const QString &appName); QString getScreensParam(const QString &appName); Q_SIGNALS: // SIGNALS void screensParamChanged(const QString &screensParam); void screenModeChanged(const int screenMode); }; #endif ukui-settings-daemon/plugins/keyboard/0000755000175000017500000000000014205117214017030 5ustar fengfengukui-settings-daemon/plugins/keyboard/keyboard-widget.cpp0000644000175000017500000001540514205117214022622 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "keyboard-widget.h" #include "ui_keyboardwidget.h" #include #include #include #include #include "clib-syslog.h" #include #include #include #include #include #include #include "usd_base_class.h" #define QT_THEME_SCHEMA "org.ukui.style" #define PANEL_SCHEMA "org.ukui.panel.settings" #define PANEL_SIZE_KEY "panelsize" #define DEFAULT_LOCALE_ICON_NAME ":/ukui_res/ukui/" #define INTEL_LOCALE_ICON_NAME ":/ukui_res/ukui_intel/" KeyboardWidget::KeyboardWidget(QWidget *parent) : QWidget(parent), ui(new Ui::KeyboardWidget) { ui->setupUi(this); initWidgetInfo(); } KeyboardWidget::~KeyboardWidget() { delete ui; } void KeyboardWidget::initWidgetInfo() { setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint | Qt::Popup); setFixedSize(72,72); setAttribute(Qt::WA_TranslucentBackground, true); if(UsdBaseClass::isTablet()) { m_LocalIconPath = INTEL_LOCALE_ICON_NAME; } else { m_LocalIconPath = DEFAULT_LOCALE_ICON_NAME; } m_styleSettings = new QGSettings(QT_THEME_SCHEMA); connect(m_styleSettings,SIGNAL(changed(const QString&)), this,SLOT(onStyleChanged(const QString&))); m_timer = new QTimer(this); connect(m_timer,SIGNAL(timeout()),this,SLOT(timeoutHandle())); connect(QApplication::primaryScreen(), &QScreen::geometryChanged, this, &KeyboardWidget::geometryChangedHandle); connect(static_cast(QCoreApplication::instance()), &QApplication::primaryScreenChanged, this, &KeyboardWidget::geometryChangedHandle); QVBoxLayout *layout = new QVBoxLayout(this); layout->setMargin(0); m_btnStatus = new QLabel(this); m_btnStatus->setFixedSize(QSize(48,48)); layout->addWidget(m_btnStatus, 0, Qt::AlignTop | Qt::AlignHCenter); setAutoFillBackground(true); geometryChangedHandle(); } void KeyboardWidget::timeoutHandle() { m_timer->stop(); hide(); } void KeyboardWidget::showWidget() { geometryChangedHandle(); repaintWidget(); show(); m_timer->start(2500); } void KeyboardWidget::setIcons(QString icon) { m_iconName = icon; } void KeyboardWidget::geometryChangedHandle() { int x=QApplication::primaryScreen()->geometry().x(); int y=QApplication::primaryScreen()->geometry().y(); int width = QApplication::primaryScreen()->size().width(); int height = QApplication::primaryScreen()->size().height(); int pSize = 0; const QByteArray id(PANEL_SCHEMA); if (QGSettings::isSchemaInstalled(id)){ QGSettings * settings = new QGSettings(id); pSize = settings->get(PANEL_SIZE_KEY).toInt(); delete settings; } int ax,ay; ax = x+width - this->width() - 200; ay = y+height - this->height() - pSize-4; move(ax,ay); } void KeyboardWidget::onStyleChanged(const QString& key) { Q_UNUSED(key) if(!this->isHidden()) { hide(); repaintWidget(); show(); } } QPixmap KeyboardWidget::drawLightColoredPixmap(const QPixmap &source, const QString &style) { int value = 255; if(style == "ukui-light") { value = 0; } QColor gray(255,255,255); QColor standard (0,0,0); QImage img = source.toImage(); for (int x = 0; x < img.width(); x++) { for (int y = 0; y < img.height(); y++) { auto color = img.pixelColor(x, y); if (color.alpha() > 0) { if (qAbs(color.red()-gray.red())<20 && qAbs(color.green()-gray.green())<20 && qAbs(color.blue()-gray.blue())<20) { color.setRed(value); color.setGreen(value); color.setBlue(value); img.setPixelColor(x, y, color); } else { color.setRed(value); color.setGreen(value); color.setBlue(value); img.setPixelColor(x, y, color); } } } } return QPixmap::fromImage(img); } void KeyboardWidget::repaintWidget() { if(m_styleSettings->get("style-name").toString() == "ukui-light"){ setPalette(QPalette(QColor("#F5F5F5")));//设置窗口背景 } else{ setPalette(QPalette(QColor("#232426")));//设置窗口背景色 } QString m_LocalIconName; m_LocalIconName = m_LocalIconPath + m_iconName + QString(".svg"); QPixmap m_pixmap = QIcon::fromTheme(m_iconName,QIcon(m_LocalIconName)).pixmap(QSize(48,48)); m_btnStatus->setPixmap(drawLightColoredPixmap(m_pixmap,m_styleSettings->get("style-name").toString())); } void KeyboardWidget::resizeEvent(QResizeEvent* event) { m_btnStatus->move((width() - m_btnStatus->width())/2,(height() - m_btnStatus->height())/2); QWidget::resizeEvent(event); } void KeyboardWidget::paintEvent(QPaintEvent *event) { QRect rect = this->rect(); QPainterPath path; QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); // 反锯齿; painter.setPen(Qt::transparent); qreal radius=12; path.moveTo(rect.topRight() - QPointF(radius, 0)); path.lineTo(rect.topLeft() + QPointF(radius, 0)); path.quadTo(rect.topLeft(), rect.topLeft() + QPointF(0, radius)); path.lineTo(rect.bottomLeft() + QPointF(0, -radius)); path.quadTo(rect.bottomLeft(), rect.bottomLeft() + QPointF(radius, 0)); path.lineTo(rect.bottomRight() - QPointF(radius, 0)); path.quadTo(rect.bottomRight(), rect.bottomRight() + QPointF(0, -radius)); path.lineTo(rect.topRight() + QPointF(0, radius)); path.quadTo(rect.topRight(), rect.topRight() + QPointF(-radius, -0)); painter.setBrush(this->palette().base()); painter.setPen(Qt::transparent); painter.setOpacity(0.75); painter.drawPath(path); KWindowEffects::enableBlurBehind(this->winId(), true, QRegion(path.toFillPolygon().toPolygon())); QWidget::paintEvent(event); } ukui-settings-daemon/plugins/keyboard/keyboard-manager.h0000755000175000017500000000543114205117202022414 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef KEYBOARDMANAGER_H #define KEYBOARDMANAGER_H #include #include #include #include #include #include #include #include #include #include #include #include "xeventmonitor.h" #include "keyboard-xkb.h" #include "keyboard-widget.h" #include "usd_base_class.h" #ifdef HAVE_X11_EXTENSIONS_XF86MISC_H #include #endif #ifdef HAVE_X11_EXTENSIONS_XKB_H #include #include #endif class KeyboardXkb; class KeyboardManager : public QObject { Q_OBJECT private: KeyboardManager()=delete; KeyboardManager(KeyboardManager&)=delete; KeyboardManager&operator=(const KeyboardManager&)=delete; KeyboardManager(QObject *parent = nullptr); public: ~KeyboardManager(); static KeyboardManager *KeyboardManagerNew(); bool KeyboardManagerStart(); void KeyboardManagerStop (); void usd_keyboard_manager_apply_settings(KeyboardManager *manager); void numlock_install_xkb_callback (); public Q_SLOTS: void start_keyboard_idle_cb (); void apply_settings (QString); void XkbEventsFilter(int keyCode); private: friend void numlock_xkb_init (KeyboardManager *manager); friend void apply_bell (KeyboardManager *manager); friend void apply_numlock (KeyboardManager *manager); friend void apply_repeat (KeyboardManager *manager); friend void numlock_install_xkb_callback (KeyboardManager *manager); private: QTimer *time; static KeyboardManager *mKeyboardManager; static KeyboardXkb *mKeyXkb; bool have_xkb; int xkb_event_base; QGSettings *settings; QGSettings *ksettings; int old_state; bool stInstalled; KeyboardWidget* m_statusWidget; QDBusInterface * ifaceScreenSaver; }; #endif // KEYBOARDMANAGER_H ukui-settings-daemon/plugins/keyboard/keyboard-widget.h0000644000175000017500000000350014205117202022255 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef KEYBOARDWIDGET_H #define KEYBOARDWIDGET_H #include #include #include #include #include #include namespace Ui { class KeyboardWidget; } class KeyboardWidget : public QWidget { Q_OBJECT public: explicit KeyboardWidget(QWidget *parent = nullptr); ~KeyboardWidget(); void setIcons(QString icon); void showWidget(); protected: void paintEvent(QPaintEvent *event); void resizeEvent(QResizeEvent* even); private: void initWidgetInfo(); void geometryChangedHandle(); QPixmap drawLightColoredPixmap(const QPixmap &source, const QString &style); void repaintWidget(); public Q_SLOTS: void timeoutHandle(); void onStyleChanged(const QString&); private: Ui::KeyboardWidget *ui; QWidget* m_backgroudWidget; QString m_iconName; QString m_LocalIconPath; QLabel *m_btnStatus; QTimer *m_timer; QGSettings *m_styleSettings; }; #endif // KEYBOARDWIDGET_H ukui-settings-daemon/plugins/keyboard/keyboard-xkb.cpp0000755000175000017500000002417314205117202022125 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "keyboard-xkb.h" #include "clib-syslog.h" #define MATEKBD_DESKTOP_SCHEMA "org.mate.peripherals-keyboard-xkb.general" #define MATEKBD_KBD_SCHEMA "org.mate.peripherals-keyboard-xkb.kbd" #define KNOWN_FILES_KEY "known-file-list" #define DISABLE_INDICATOR_KEY "disable-indicator" KeyboardManager *KeyboardXkb::manager = KeyboardManager::KeyboardManagerNew(); static void *pa_callback_user_data = NULL; static XklConfigRegistry* xkl_registry = NULL; static MatekbdDesktopConfig current_desktop_config; static MatekbdKeyboardConfig current_kbd_config; /* never terminated */ static MatekbdKeyboardConfig initial_sys_kbd_config; static PostActivationCallback pa_callback = NULL; static XklEngine* xkl_engine; static bool inited_ok = false; KeyboardXkb::KeyboardXkb() { USD_LOG(LOG_DEBUG,"Keyboard Xkb initializing!"); } KeyboardXkb::~KeyboardXkb() { USD_LOG(LOG_DEBUG,"Keyboard Xkb free"); if(settings_desktop) delete settings_desktop; if(settings_kbd) delete settings_kbd; } void KeyboardXkb::usd_keyboard_xkb_analyze_sysconfig (void) { if (!inited_ok) return; matekbd_keyboard_config_init (&initial_sys_kbd_config, xkl_engine); matekbd_keyboard_config_load_from_x_initial (&initial_sys_kbd_config,NULL); } void KeyboardXkb::apply_desktop_settings (void) { if (!inited_ok) return; manager->usd_keyboard_manager_apply_settings (manager); matekbd_desktop_config_load_from_gsettings (¤t_desktop_config); /* again, probably it would be nice to compare things before activating them */ matekbd_desktop_config_activate (¤t_desktop_config); } bool KeyboardXkb::try_activating_xkb_config_if_new (MatekbdKeyboardConfig *current_sys_kbd_config) { /* Activate - only if different! */ if (!matekbd_keyboard_config_equals (¤t_kbd_config, current_sys_kbd_config)) { if (matekbd_keyboard_config_activate (¤t_kbd_config)) { if (pa_callback != NULL) { (*pa_callback) (pa_callback_user_data); return TRUE; } } else { return FALSE; } } return TRUE; } static void g_strv_behead (gchar **arr) { if (arr == NULL || *arr == NULL) return; g_free (*arr); memmove (arr, arr + 1, g_strv_length (arr) * sizeof (gchar *)); } bool KeyboardXkb::filter_xkb_config (void) { XklConfigItem *item; char *lname; char *vname; char **lv; bool any_change = FALSE; xkl_debug (100, "Filtering configuration against the registry\n"); if (!xkl_registry) { xkl_registry = xkl_config_registry_get_instance (xkl_engine); /* load all materials, unconditionally! */ if (!xkl_config_registry_load (xkl_registry, TRUE)){ g_object_unref (xkl_registry); xkl_registry = NULL; return FALSE; } } lv = current_kbd_config.layouts_variants; item = xkl_config_item_new (); while (*lv) { xkl_debug (100, "Checking [%s]\n", *lv); if (matekbd_keyboard_config_split_items (*lv, &lname, &vname)) { bool should_be_dropped = FALSE; snprintf (item->name ,sizeof (item->name), "%s",lname); if (!xkl_config_registry_find_layout(xkl_registry, item)) { xkl_debug (100, "Bad layout [%s]\n",lname); should_be_dropped = TRUE; } else if (vname) { snprintf (item->name,sizeof (item->name), "%s", vname); if (!xkl_config_registry_find_variant (xkl_registry, lname, item)) { xkl_debug (100,"Bad variant [%s(%s)]\n",lname, vname); should_be_dropped = TRUE; } } if (should_be_dropped) { g_strv_behead (lv); any_change = TRUE; continue; } } lv++; } g_object_unref (item); return any_change; } static void activation_error (void) { Display *dpy = QX11Info::display(); char const *vendor = ServerVendor (dpy);//GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); int release = VendorRelease (dpy);//GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); QMessageBox *dialog; /* VNC viewers will not work, do not barrage them with warnings */ if (NULL != vendor && NULL != strstr (vendor, "VNC")) return; QString message = QObject::tr("Error activating XKB configuration.\n" "It can happen under various circumstances:\n" " • a bug in libxklavier library\n" " • a bug in X server (xkbcomp, xmodmap utilities)\n" " • X server with incompatible libxkbfile implementation\n\n" "X server version data:\n %1 \n %2 \n" "If you report this situation as a bug, please include:\n" " • The result of xprop -root | grep XKB \n" " • The result of gsettings list-keys org.mate.peripherals-keyboard-xkb.kbd ").arg(vendor).arg(release); dialog = new QMessageBox(); dialog->setButtonText(QMessageBox::Close,QObject::tr("Close")); dialog->setButtonText(QMessageBox::Warning,QObject::tr("Error")); dialog->setText(message); dialog->show(); dialog->close(); delete dialog; } void KeyboardXkb::apply_xkb_settings (void) { MatekbdKeyboardConfig current_sys_kbd_config; if (!inited_ok) return; matekbd_keyboard_config_init (¤t_sys_kbd_config, xkl_engine); matekbd_keyboard_config_load_from_gsettings (¤t_kbd_config, &initial_sys_kbd_config); matekbd_keyboard_config_load_from_x_current (¤t_sys_kbd_config, NULL); if (!try_activating_xkb_config_if_new (¤t_sys_kbd_config)) { if (filter_xkb_config ()) { if (!try_activating_xkb_config_if_new(¤t_sys_kbd_config)) { qWarning ("Could not activate the filtered XKB configuration"); activation_error (); } } else { qWarning("Could not activate the XKB configuration"); activation_error (); } } else xkl_debug (100, "Actual KBD configuration was not changed: redundant notification\n"); matekbd_keyboard_config_term (¤t_sys_kbd_config); } void KeyboardXkb::apply_desktop_settings_cb (QString key) { apply_desktop_settings (); } void KeyboardXkb::apply_desktop_settings_mate_cb(GSettings *settings,char *key) { apply_desktop_settings (); } void KeyboardXkb::apply_xkb_settings_cb (QString key) { apply_xkb_settings (); } void KeyboardXkb::apply_xkb_settings_mate_cb (GSettings *settings,char *key) { apply_xkb_settings (); } GdkFilterReturn usd_keyboard_xkb_evt_filter (GdkXEvent * xev, GdkEvent * event,gpointer data) { KeyboardXkb *xkb = (KeyboardXkb *)data; XEvent *xevent = (XEvent *) xev; xkl_engine_filter_events (xkl_engine, xevent); return GDK_FILTER_CONTINUE; } /* When new Keyboard is plugged in - reload the settings */ void KeyboardXkb::usd_keyboard_new_device (XklEngine * engine) { apply_desktop_settings (); apply_xkb_settings (); } void KeyboardXkb::usd_keyboard_xkb_init(KeyboardManager* kbd_manager) { USD_LOG(LOG_DEBUG,"init --- XKB"); Display *display; display = QX11Info::display(); manager = kbd_manager; xkl_engine = xkl_engine_get_instance (display); if (xkl_engine) { inited_ok = TRUE; settings_desktop = new QGSettings(MATEKBD_DESKTOP_SCHEMA); settings_kbd = new QGSettings(MATEKBD_KBD_SCHEMA); matekbd_desktop_config_init (¤t_desktop_config,xkl_engine); matekbd_keyboard_config_init (¤t_kbd_config,xkl_engine); xkl_engine_backup_names_prop (xkl_engine); usd_keyboard_xkb_analyze_sysconfig (); matekbd_desktop_config_start_listen (¤t_desktop_config, G_CALLBACK (apply_desktop_settings_mate_cb),NULL); matekbd_keyboard_config_start_listen (¤t_kbd_config,G_CALLBACK (apply_xkb_settings_mate_cb),NULL); QObject::connect(settings_desktop,SIGNAL(changed(QString)),this,SLOT(apply_desktop_settings_cb(QString))); QObject::connect(settings_kbd,SIGNAL(changed(QString)),this,SLOT(apply_xkb_settings_cb(QString))); gdk_window_add_filter (NULL, (GdkFilterFunc)usd_keyboard_xkb_evt_filter, this); if (xkl_engine_get_features (xkl_engine) &XKLF_DEVICE_DISCOVERY) g_signal_connect (xkl_engine, "X-new-device", G_CALLBACK(usd_keyboard_new_device), NULL); xkl_engine_start_listen (xkl_engine, XKLL_MANAGE_LAYOUTS |XKLL_MANAGE_WINDOW_STATES); apply_desktop_settings (); apply_xkb_settings (); } } void KeyboardXkb::usd_keyboard_xkb_shutdown (void) { pa_callback = NULL; pa_callback_user_data = NULL; manager = NULL; if (!inited_ok) return; xkl_engine_stop_listen (xkl_engine, XKLL_MANAGE_LAYOUTS | XKLL_MANAGE_WINDOW_STATES); gdk_window_remove_filter (NULL, (GdkFilterFunc)usd_keyboard_xkb_evt_filter, NULL); if (xkl_registry) { g_object_unref (xkl_registry); } g_object_unref (xkl_engine); xkl_engine = NULL; inited_ok = FALSE; } ukui-settings-daemon/plugins/keyboard/keyboard-plugin.h0000755000175000017500000000246614205117202022305 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef KEYBOARDPLUGIN_H #define KEYBOARDPLUGIN_H #include "keyboard-manager.h" #include "plugin-interface.h" class KeyboardPlugin : public PluginInterface { public: ~KeyboardPlugin(); static PluginInterface * getInstance(); virtual void activate(); virtual void deactivate(); private: KeyboardPlugin(); KeyboardPlugin(KeyboardPlugin&)=delete; private: static KeyboardManager *UsdKeyboardManager; static PluginInterface * mInstance; }; extern "C" Q_DECL_EXPORT PluginInterface * createSettingsPlugin(); #endif // KEYBOARDPLUGIN_H ukui-settings-daemon/plugins/keyboard/keyboard.pro0000755000175000017500000000243614205117202021357 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-04-20T09:30:00 # #------------------------------------------------- QT += gui QT += core widgets x11extras KWindowSystem TARGET = keyboard TEMPLATE = lib DEFINES += KEYBOARD_LIBRARY CONFIG += c++11 no_keywords link_pkgconfig plugin DEFINES += QT_DEPRECATED_WARNINGS MODULE_NAME=\\\"keyboard\\\" include($$PWD/../../common/common.pri) PKGCONFIG += \ gtk+-3.0 \ glib-2.0 harfbuzz gmodule-2.0 \ libxklavier gobject-2.0 gio-2.0 \ cairo cairo-gobject gsettings-qt INCLUDEPATH += \ -I ukui-settings-daemon/ \ -I /usr/include/libmatekbd LIBS += \ -L/usr/lib/*-linux-gnu -lmatekbdui -lmatekbd \ -Wl,--export-dynamic -lgmodule-2.0 \ -pthread -lgdk-3 -lpangocairo-1.0 \ -lpango-1.0 -lharfbuzz -lgdk_pixbuf-2.0 \ -lcairo-gobject -lcairo -lgio-2.0 -lgobject-2.0 SOURCES += \ keyboard-manager.cpp \ keyboard-plugin.cpp \ keyboard-widget.cpp \ keyboard-xkb.cpp HEADERS += \ keyboard-manager.h \ keyboard-widget.h \ keyboard-xkb.h \ keyboard-plugin.h keyboard_lib.path = $${PLUGIN_INSTALL_DIRS} keyboard_lib.files = $$OUT_PWD/libkeyboard.so INSTALLS += keyboard_lib FORMS += \ keyboardwidget.ui ukui-settings-daemon/plugins/keyboard/keyboard-manager.cpp0000644000175000017500000003746614205117202022761 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "keyboard-manager.h" #include "clib-syslog.h" #include "config.h" #include "rfkillswitch.h" #define USD_KEYBOARD_SCHEMA "org.ukui.peripherals-keyboard" #define UKCCOSD_SCHEMA "org.ukui.control-center.osd" #define KYCCOSD_SCHEMA "org.kylin.control-center.osd" #define KDSOSD_SCHEMA "org.ukui.kds.osd" #define SHOW_TIP_KEY "show-lock-tip" #define KEY_REPEAT "repeat" #define KEY_CLICK "click" #define KEY_RATE "rate" #define KEY_DELAY "delay" #define KEY_CLICK_VOLUME "click-volume" #define KEY_BELL_PITCH "bell-pitch" #define KEY_BELL_DURATION "bell-duration" #define KEY_BELL_MODE "bell-mode" #define KEY_NUMLOCK_STATE "numlock-state" #define KEY_CAPSLOCK_STATE "capslock-state" #define KEY_NUMLOCK_REMEMBER "remember-numlock-state" typedef enum { NUMLOCK_STATE_OFF = 0, NUMLOCK_STATE_ON = 1, NUMLOCK_STATE_UNKNOWN = 2 } NumLockState; static void numlock_set_xkb_state (NumLockState new_state); static void capslock_set_xkb_state(gboolean lock_state); KeyboardManager *KeyboardManager::mKeyboardManager = nullptr; KeyboardXkb *KeyboardManager::mKeyXkb = nullptr; KeyboardManager::KeyboardManager(QObject * parent) { if (mKeyXkb == nullptr) mKeyXkb = new KeyboardXkb; settings = new QGSettings(USD_KEYBOARD_SCHEMA); stInstalled = true; time = new QTimer(this); const QByteArray id(UKCCOSD_SCHEMA); const QByteArray idd(KYCCOSD_SCHEMA); const QByteArray iid(KDSOSD_SCHEMA); ifaceScreenSaver = new QDBusInterface("org.ukui.ScreenSaver", \ "/", \ "org.ukui.ScreenSaver", \ QDBusConnection::sessionBus()); if (QGSettings::isSchemaInstalled(id)){ ksettings = new QGSettings(id); } else if (QGSettings::isSchemaInstalled(idd)){ ksettings = new QGSettings(idd); } else if (QGSettings::isSchemaInstalled(iid)){ ksettings = new QGSettings(iid); } else { stInstalled = false; } m_statusWidget = new KeyboardWidget(); } KeyboardManager::~KeyboardManager() { if (mKeyXkb) { delete mKeyXkb; mKeyXkb = nullptr; } if (settings) { delete settings; settings = nullptr; } if (time) { delete time; time = nullptr; } if (m_statusWidget) { delete m_statusWidget; m_statusWidget = nullptr; } if (ksettings) { delete ksettings; ksettings = nullptr; } } KeyboardManager *KeyboardManager::KeyboardManagerNew() { if (nullptr == mKeyboardManager) mKeyboardManager = new KeyboardManager(nullptr); return mKeyboardManager; } bool KeyboardManager::KeyboardManagerStart() { USD_LOG(LOG_DEBUG,"-- Keyboard Start Manager --"); connect(time,SIGNAL(timeout()),this,SLOT(start_keyboard_idle_cb())); time->start(1500); return true; } void KeyboardManager::KeyboardManagerStop() { USD_LOG(LOG_DEBUG,"-- Keyboard Stop Manager --"); old_state = 0; numlock_set_xkb_state((NumLockState)old_state); capslock_set_xkb_state(FALSE); mKeyXkb->usd_keyboard_xkb_shutdown (); } #ifdef HAVE_X11_EXTENSIONS_XF86MISC_H static gboolean xfree86_set_keyboard_autorepeat_rate(int delay, int rate) { gboolean res = FALSE; int event_base_return; int error_base_return; if (XF86MiscQueryExtension (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), &event_base_return, &error_base_return) == True) { /* load the current settings */ XF86MiscKbdSettings kbdsettings; XF86MiscGetKbdSettings (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), &kbdsettings); /* assign the new values */ kbdsettings.delay = delay; kbdsettings.rate = rate; XF86MiscSetKbdSettings (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), &kbdsettings); res = TRUE; } return res; } #endif /* HAVE_X11_EXTENSIONS_XF86MISC_H */ void numlock_xkb_init (KeyboardManager *manager) { Display *dpy = QX11Info::display(); gboolean have_xkb; int opcode, error_base, major, minor; have_xkb = XkbQueryExtension (dpy, &opcode, &manager->xkb_event_base, &error_base, &major, &minor) && XkbUseExtension (dpy, &major, &minor); if (have_xkb) { XkbSelectEventDetails (dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbModifierLockMask, XkbModifierLockMask); } else { qWarning ("XKB extension not available"); } manager->have_xkb = have_xkb; } static NumLockState numlock_get_settings_state (QGSettings *settings) { int curr_state; curr_state = settings->getEnum(KEY_NUMLOCK_STATE); return (NumLockState)curr_state; } static void capslock_set_xkb_state(gboolean lock_state) { unsigned int caps_mask; Display *dpy = QX11Info::display(); caps_mask = XkbKeysymToModifiers (dpy, XK_Caps_Lock); XkbLockModifiers (dpy, XkbUseCoreKbd, caps_mask, lock_state ? caps_mask : 0); XSync (dpy, FALSE); } static unsigned numlock_NumLock_modifier_mask (void) { Display *dpy = QX11Info::display(); return XkbKeysymToModifiers (dpy, XK_Num_Lock); } static void numlock_set_xkb_state (NumLockState new_state) { unsigned int num_mask; Display *dpy = QX11Info::display(); if (new_state != NUMLOCK_STATE_ON && new_state != NUMLOCK_STATE_OFF) return; num_mask = numlock_NumLock_modifier_mask (); XkbLockModifiers (dpy, XkbUseCoreKbd, num_mask, new_state ? num_mask : 0); } void apply_bell (KeyboardManager *manager) { QGSettings *settings; XKeyboardControl kbdcontrol; bool click; int bell_volume; int bell_pitch; int bell_duration; char *volume_string; QString volume_strings; int click_volume; Display *dpy = QX11Info::display(); settings = manager->settings; click = settings->get(KEY_CLICK).toBool(); click_volume = settings->get(KEY_CLICK_VOLUME).toInt(); bell_pitch = settings->get(KEY_BELL_PITCH).toInt(); bell_duration = settings->get(KEY_BELL_DURATION).toInt(); volume_strings = settings->get(KEY_BELL_MODE).toChar(); volume_string = volume_strings.toLatin1().data(); bell_volume = (volume_string && !strcmp (volume_string, "on")) ? 50 : 0; /* as percentage from 0..100 inclusive */ if (click_volume < 0) { click_volume = 0; } else if (click_volume > 100) { click_volume = 100; } kbdcontrol.key_click_percent = click ? click_volume : 0; kbdcontrol.bell_percent = bell_volume; kbdcontrol.bell_pitch = bell_pitch; kbdcontrol.bell_duration = bell_duration; try { XChangeKeyboardControl (dpy,KBKeyClickPercent | KBBellPercent | KBBellPitch | KBBellDuration, &kbdcontrol); XSync (dpy, FALSE); } catch (int x) { } } void apply_numlock (KeyboardManager *manager) { QGSettings *settings; bool rnumlock; Display *dpy = QX11Info::display(); qDebug ("Applying the num-lock settings"); settings = manager->settings; rnumlock = settings->get(KEY_NUMLOCK_REMEMBER).toBool(); manager->old_state = settings->getEnum(KEY_NUMLOCK_STATE); try { if(true == UsdBaseClass::isTablet() && rnumlock) { numlock_set_xkb_state (NUMLOCK_STATE_OFF); } else { numlock_set_xkb_state ((NumLockState)manager->old_state); } XSync (dpy, FALSE); } catch (int x) { } } static gboolean xkb_set_keyboard_autorepeat_rate(int delay, int rate) { int interval = (rate <= 0) ? 1000000 : 1000/rate; Display *dpy = QX11Info::display(); if (delay <= 0) { delay = 1; } return XkbSetAutoRepeatRate(dpy, XkbUseCoreKbd, delay, interval); } void apply_repeat (KeyboardManager *manager) { bool repeat; int rate; int delay; Display *dpy = QX11Info::display(); repeat = manager->settings->get(KEY_REPEAT).toBool(); rate = manager->settings->get(KEY_RATE).toInt(); delay = manager->settings->get(KEY_DELAY).toInt(); try { if (repeat) { gboolean rate_set = FALSE; XAutoRepeatOn (dpy); /* Use XKB in preference */ rate_set = xkb_set_keyboard_autorepeat_rate (delay, rate); if (!rate_set) { USD_LOG(LOG_DEBUG,"Neither XKeyboard not Xfree86's keyboard extensions are available,\n" "no way to support keyboard autorepeat rate settings"); } } else { XAutoRepeatOff (dpy); } XSync (dpy, FALSE); } catch (int x) { USD_LOG(LOG_ERR,"ERROR"); } } void KeyboardManager::apply_settings (QString keys) { /** * Fix by HB* system reboot but rnumlock not available; **/ char *key; if(keys != NULL) key = keys.toLatin1().data(); else key=NULL; #ifdef HAVE_X11_EXTENSIONS_XKB_H bool rnumlock; rnumlock = settings->get(KEY_NUMLOCK_REMEMBER).toBool(); if (rnumlock == 0 || key == NULL) { if (have_xkb && rnumlock) { numlock_set_xkb_state (numlock_get_settings_state (settings)); capslock_set_xkb_state(settings->get(KEY_CAPSLOCK_STATE).toBool()); USD_LOG(LOG_DEBUG,"apply keyboard ok."); } } #endif /* HAVE_X11_EXTENSIONS_XKB_H */ if (keys.compare(QString::fromLocal8Bit(KEY_CLICK)) == 0|| keys.compare(QString::fromLocal8Bit(KEY_CLICK_VOLUME)) == 0 || keys.compare(QString::fromLocal8Bit(KEY_BELL_PITCH)) == 0 || keys.compare(QString::fromLocal8Bit(KEY_BELL_DURATION)) == 0 || keys.compare(QString::fromLocal8Bit(KEY_BELL_MODE)) == 0) { USD_LOG(LOG_DEBUG,"Bell setting '%s' changed, applying bell settings", key); apply_bell (this); } else if (keys.compare(QString::fromLocal8Bit(KEY_NUMLOCK_REMEMBER)) == 0) { USD_LOG(LOG_DEBUG,"Remember Num-Lock state '%s' changed, applying num-lock settings", key); apply_numlock (this); } else if (keys.compare(QString::fromLocal8Bit(KEY_NUMLOCK_STATE)) == 0) { USD_LOG(LOG_DEBUG,"Num-Lock state '%s' changed, will apply at next startup", key); } else if (keys.compare(QString::fromLocal8Bit(KEY_REPEAT)) == 0 || keys.compare(QString::fromLocal8Bit(KEY_RATE)) == 0 || keys.compare(QString::fromLocal8Bit(KEY_DELAY)) == 0) { USD_LOG(LOG_DEBUG,"Key repeat setting '%s' changed, applying key repeat settings", key); apply_repeat (this); } else { // USD_LOG(LOG_DEBUG,"Unhandled settings change, key '%s'", key); } } void KeyboardManager::usd_keyboard_manager_apply_settings (KeyboardManager *manager) { apply_settings(NULL); } void KeyboardManager::XkbEventsFilter(int keyCode) { Display *display = XOpenDisplay(NULL); NumLockState numlockState; bool capsLockState; if(keyCode == 77) { unsigned int numLockedMods; XkbGetIndicatorState(display, XkbUseCoreKbd, &numLockedMods); if(numLockedMods == 2 || numLockedMods==3) { numlockState = NUMLOCK_STATE_ON; } else { numlockState = NUMLOCK_STATE_OFF; } USD_LOG(LOG_ERR,"old_state=%d,locked_mods=%d,numlockState=%d", old_state,numLockedMods,numlockState); if (numlockState != old_state) { settings->setEnum(KEY_NUMLOCK_STATE, numlockState); old_state = numlockState; } if (stInstalled && !ksettings->get(SHOW_TIP_KEY).toBool()){ qWarning("MediaKey Tip is Closed\n"); return; } if (ifaceScreenSaver->isValid()){ QDBusReplyreply = ifaceScreenSaver->call("GetLockState"); if (reply.isValid()){ if (reply.value()){ qWarning("MediaKey Tip is Closed because ScreenLock\n"); return; } } } if(numlockState) { m_statusWidget->setIcons("ukui-numlock-on"); m_statusWidget->showWidget(); } else { m_statusWidget->setIcons("ukui-numlock-off"); m_statusWidget->showWidget(); } }else if(keyCode == 66) { unsigned int capsLockedMods; XkbGetIndicatorState(display, XkbUseCoreKbd, &capsLockedMods); if(capsLockedMods == 1 || capsLockedMods == 3){ settings->set(KEY_CAPSLOCK_STATE,true); capsLockState = true; } else{ settings->set(KEY_CAPSLOCK_STATE,false); capsLockState = false; } if (stInstalled && !ksettings->get(SHOW_TIP_KEY).toBool()){ qWarning("MediaKey Tip is Closed\n"); return; } if (ifaceScreenSaver->isValid()){ QDBusReplyreply = ifaceScreenSaver->call("GetLockState"); if (reply.isValid()){ if (reply.value()){ qWarning("MediaKey Tip is Closed because ScreenLock\n"); return; } } } if(capsLockState) { m_statusWidget->setIcons("ukui-capslock-on"); m_statusWidget->showWidget(); } else { m_statusWidget->setIcons("ukui-capslock-off"); m_statusWidget->showWidget(); } } XCloseDisplay (display); } void KeyboardManager::numlock_install_xkb_callback () { if (!have_xkb) return; // connect(XEventMonitor::instance(), static_cast(&XEventMonitor::keyRelease), // this, &KeyboardManager::XkbEventsFilter); connect(XEventMonitor::instance(), SIGNAL(keyRelease(int)), this, SLOT(XkbEventsFilter(int))); } void KeyboardManager::start_keyboard_idle_cb () { time->stop(); have_xkb = 0; settings->set(KEY_NUMLOCK_REMEMBER,TRUE); XEventMonitor::instance()->start(); /* Essential - xkb initialization should happen before */ mKeyXkb->usd_keyboard_xkb_init (this); #ifdef HAVE_X11_EXTENSIONS_XKB_H numlock_xkb_init (this); #endif /* HAVE_X11_EXTENSIONS_XKB_H */ /* apply current settings before we install the callback */ usd_keyboard_manager_apply_settings (this); // QObject::connect(settings, &QGSettings::changed, this, &KeyboardManager::apply_settings); connect(settings,SIGNAL(changed(QString)),this,SLOT(apply_settings(QString))); #ifdef HAVE_X11_EXTENSIONS_XKB_H numlock_install_xkb_callback(); #endif /* HAVE_X11_EXTENSIONS_XKB_H */ apply_repeat (this); apply_numlock (this); apply_bell(this); } ukui-settings-daemon/plugins/keyboard/keyboard-plugin.cpp0000755000175000017500000000372314205117202022635 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "keyboard-plugin.h" #include "clib-syslog.h" PluginInterface * KeyboardPlugin::mInstance=nullptr; KeyboardManager * KeyboardPlugin::UsdKeyboardManager=nullptr; KeyboardPlugin::KeyboardPlugin() { USD_LOG(LOG_DEBUG,"KeyboardPlugin initializing!"); if(nullptr == UsdKeyboardManager) UsdKeyboardManager = KeyboardManager::KeyboardManagerNew(); } KeyboardPlugin::~KeyboardPlugin() { USD_LOG(LOG_DEBUG,"Keyboard plugin free"); if (UsdKeyboardManager){ delete UsdKeyboardManager; UsdKeyboardManager =nullptr; } } void KeyboardPlugin::activate() { bool res; USD_LOG (LOG_DEBUG, "Activating %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); res = UsdKeyboardManager->KeyboardManagerStart(); if(!res){ USD_LOG(LOG_ERR,"Unable to start Keyboard Manager!") } } PluginInterface * KeyboardPlugin::getInstance() { if(nullptr == mInstance){ mInstance = new KeyboardPlugin(); } return mInstance; } void KeyboardPlugin::deactivate() { USD_LOG(LOG_DEBUG,"Deactivating Keyboard Plugin"); UsdKeyboardManager->KeyboardManagerStop(); } PluginInterface *createSettingsPlugin() { return KeyboardPlugin::getInstance(); } ukui-settings-daemon/plugins/keyboard/keyboard-xkb.h0000755000175000017500000000450614205117202021570 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef KEYBOARDXKB_H #define KEYBOARDXKB_H #include "keyboard-manager.h" #include "config.h" #include #include #include #include #include #include extern "C"{ #include #include #include #include #include } typedef void (*PostActivationCallback) (void* userData); class KeyboardManager; class KeyboardXkb : public QObject { Q_OBJECT public Q_SLOTS: static void apply_desktop_settings_cb (QString); static void apply_xkb_settings_cb(QString); public: KeyboardXkb(); KeyboardXkb(KeyboardXkb&)=delete; ~KeyboardXkb(); static KeyboardManager * manager; public: void usd_keyboard_xkb_init(KeyboardManager* kbd_manager); void usd_keyboard_xkb_shutdown(void); static void apply_desktop_settings (void); static void usd_keyboard_new_device (XklEngine * engine); static void apply_desktop_settings_mate_cb(GSettings *settings, gchar *key); static void apply_xkb_settings_mate_cb (GSettings *settings, gchar *key); static void apply_xkb_settings (void); friend GdkFilterReturn usd_keyboard_xkb_evt_filter (GdkXEvent * xev, GdkEvent * event,gpointer data); void usd_keyboard_xkb_analyze_sysconfig (void); static bool try_activating_xkb_config_if_new (MatekbdKeyboardConfig *current_sys_kbd_config); static bool filter_xkb_config (void); public: QGSettings* settings_desktop; QGSettings* settings_kbd; }; #endif // KEYBOARDXKB_H ukui-settings-daemon/plugins/keyboard/keyboardwidget.ui0000644000175000017500000000061614205117202022373 0ustar fengfeng KeyboardWidget 0 0 400 300 Form ukui-settings-daemon/doc/0000755000175000017500000000000014205117202014311 5ustar fengfengukui-settings-daemon/doc/debian.md0000644000175000017500000000040314205117202016052 0ustar fengfeng### 生成debian过程 1. 安装必需的包 ```shell sudo apt install build-essential sudo apt install debmake ``` 2. 生成debian目录 ```shell debmake -e "team+kylin@tracker.debian.org" -p "ukui-settings-daemon" -f "Kylin Team" -u 0.0.1 -m -n -x1 ``` ukui-settings-daemon/data/0000755000175000017500000000000014205117202014455 5ustar fengfengukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.sound.gschema.xml0000644000175000017500000000120014205117202026073 0ustar fengfeng true Activation of this plugin Whether this plugin would be activated by ukui-settings-daemon or not 6 Priority to use for this plugin Priority to use for this plugin in ukui-settings-daemon startup queue ukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.tablet-mode.gschema.xml0000644000175000017500000000220114205117202027142 0ustar fengfeng true Activation of this plugin Whether this plugin would be activated by ukui-settings-daemon or not 12 Priority to use for this plugin Priority to use for this plugin in ukui-settings-daemon startup queue false Whether to turn on tablet mode Use the switch to control whether to turn on the tablet mode false Whether to turn on automatic rotation mode Use the switch to control whether the auto-rotating screen is turned on in tablet mode ukui-settings-daemon/data/org.ukui.peripherals-touchpad.gschema.xml0000644000175000017500000001325214205117202024475 0ustar fengfeng true Disable touchpad while typing Set this to TRUE if you have problems with accidentally hitting the touchpad while typing. true Enable mouse clicks with touchpad Set this to TRUE to be able to send mouse clicks by tapping on the touchpad. false Enable vertical edge scrolling Set this to TRUE to allow vertical edge scrolling false Enable horizontal edge scrolling Set this to TRUE to allow horizontal edge scrolling true Enable vertical two-finger scrolling Set this to TRUE to allow vertical two-finger scrolling false Enable horizontal two-finger scrolling Set this to TRUE to allow horizontal two-finger scrolling false Natural scrolling Set this to true to enable natural (reverse) scrolling for touchpads true Enable touchpad Set this to TRUE to enable all touchpads. 3 Enabled two-finger button-click emulation 0 thru 3, 0 is inactive, 1-3 is button to emulate 2 Enable three-finger button-click emulation 0 thru 3, 0 is inactive, 1-3 is button to emulate 1 One finger tap button Select the button mapping for one-finger tap. Supported values are: 1: left mouse button 2: middle mouse button 3: right mouse button 3 Two finger tap button Select the button mapping for two-finger tap. Supported values are: 1: left mouse button 2: middle mouse button 3: right mouse button 0 Three finger tap button Select the button mapping for three-finger tap. Supported values are: 1: left mouse button 2: middle mouse button 3: right mouse button 'mouse' Touchpad button orientation Swap left and right buttons for left-handed touchpads with 'left', 'right' for right-handed, 'mouse' to follow the mouse setting. -1 Motion Acceleration Acceleration multiplier for touchpad motion. A value of -1 is the system default. -1 Motion Threshold Distance in pixels the pointer must move before accelerated touchpad motion is activated. A value of -1 is the system default. false Mouse plug closes the touchpad. Whether to open or close the trackpad when the mouse is inserted or pulled out. true Click twice and then drag to make multiple selections. Open or close, click twice and then drag or select multiple. true Close the bottom right corner click menu. Open or close the bottom right corner click pop-up menu event. 2 Set mouse sensitivity. 1-4 represents low sensitivity, medium sensitivity, high sensitivity and highest sensitivity. 5 Mouse wheel speed Set the mouse wheel speed by running imwheel. ukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.sharing.gschema.xml0000644000175000017500000000246614205117202026415 0ustar fengfeng true Activation of this plugin Whether this plugin would be activated by ukui-settings-daemon or not 16 Priority to use for this plugin Priority to use for this plugin in ukui-settings-daemon startup queue [] Start service name. Store the name of the service that needs to be opened when starting. [] On which connections the service is enabled The list of NetworkManager connections (each one represented with its UUID) on which this service is enabled and started. ukui-settings-daemon/data/sound.ukui-settings-plugin0000644000175000017500000000023414205117202021635 0ustar fengfeng[UKUI Settings Plugin] Module=sound IAge=0 Name=Sound Description=Sound Sample Cache plugin Authors=Lennart Poettering Copyright=Copyright © 2008 Website= ukui-settings-daemon/data/xrdb.ukui-settings-plugin0000644000175000017500000001625714205117202021460 0ustar fengfeng[UKUI Settings Plugin] Module=xrdb IAge=0 Name=X Resource Database Name[af]=X-hulpbrondatabasis Name[am]=የ X ምንጮች ዳታበዝ Name[ar]=قاعدة بيانات موارد X Name[as]=X ৰিসোৰ্স ডাটাবেস Name[ast]=Base de datos de recursos de les X Name[be]=База даных рэсурсаў X Name[bg]=База от данни с ресурси за X Name[bn]=X রিসোর্স ডাটাবেস Name[bn_IN]=X রিসোর্স ডাটাবেস Name[ca]=Base de dades dels recursos de les X Name[ca@valencia]=Base de dades de recursos de les X Name[cmn]=X 資源資料庫 Name[crh]=X Menba Veritabanı Name[cs]=Databáze zdrojů X Name[da]=X-ressourcedatabase Name[de]=X-Ressourcendatenbank Name[el]=Βάση δεδομένων πόρων X Name[en_AU]=X Resource Database Name[en_GB]=X Resource Database Name[es]=Base de datos de recursos de las X Name[et]=X'i ressursside andmebaas Name[eu]=X baliabideen datu-basea Name[fi]=X:n resurssitietokanta Name[fr]=Base de données des ressources X Name[ga]=Bunachar Sonraí Acmhainní X Name[gl]=Base de datos de recursos de X Name[gu]=X સ્ત્રોત ડેટાબેઝ Name[he]=מסד נתוני משאבי X Name[hi]=X संसाधन डेटाबेस Name[hu]=X erőforrás-adatbázis Name[hy]=X Ռեսուրսների Տվյալների բազա Name[id]=Basis Data Sumber Daya X Name[it]=Database risorse X Name[ja]=Xリソース・データベース Name[kn]=X ಸಂಪನ್ಮೂಲ ದತ್ತಸಂಚಯ Name[ko]=X 리소스 데이터베이스 Name[lt]=X resursų duomenų bazė Name[lv]=X resursu datubāze Name[mk]=База на податоци за ресурсот X Name[ml]=എക്സ്-വിഭവ വിവരസംഭരണി Name[mr]=X स्त्रोत माहितीकोष Name[ms]=Pangkalan Data Sumber X Name[nb]=X-ressursdatabase Name[nl]=X-resource database Name[nn]=X-ressursdatabase Name[or]=X ଉତ୍ସ ତଥ୍ୟାଧାର Name[pa]=X ਸਰੋਤ ਡਾਟਾਬੇਸ Name[pl]=Baza zasobów X Name[pt]=Base de dados do Recurso X Name[pt_BR]=Banco de dados de recursos do X Name[ro]=Bază de date cu resurse X Name[ru]=База данных ресурсов X Name[sk]=Databáza zdrojov X Name[sl]=Podatkovna zbirka virov X Name[sr]=Иксова база ресурса Name[sr@latin]=Iksova baza resursa Name[sv]=X-resursdatabas Name[ta]=எக்ஸ் வளங்கள் தரவுத்தளம் Name[te]=X వనరు డాటాబేస్ Name[th]=ฐานข้อมูลทรัพยากรของ X Name[tr]=X Kaynak Veritabanı Name[uk]=База даних ресурсів X Name[vi]=Cơ sở dữ liệu tài nguyên X Name[zh_CN]=X 资源数据库 Name[zh_HK]=X 資源資料庫 Name[zh_TW]=X 資源資料庫 Description=Manage the X resource database Description[af]=Bestuur die X-hulpbrondatabasis Description[am]=የ X ምንጮች ዳታበዝ አስተዳዳሪ Description[ar]=أدر قاعدة بيانات موارد X Description[as]=X ৰিসোৰ্সেৰ ডাটাবেস পৰিচালনা কৰক Description[ast]=Xestionar la base de datos de recursos de les X Description[be]=Кіраванне базай даных рэсурсаў X Description[bg]=Управление на базата от данни с ресурси за X Description[bn]=X রিসোর্সের ডাটাবেস পরিচালনা করুন Description[bn_IN]=X রিসোর্সের ডাটাবেস পরিচালনা করুন Description[ca]=Gestiona la base de dades dels recursos de les X Description[ca@valencia]=Gestiona la base de dades dels recursos de les X Description[cmn]=管理 X 資源資料庫 Description[crh]=X kaynak veritabanını yönet Description[cs]=Spravovat databázi zdrojů X Description[da]=Håndter X-ressourcedatabasen Description[de]=Die X-Ressourcendatenbank verwalten Description[el]=Διαχείριση της βάσης δεδομένων πόρων X Description[en_AU]=Manage the X resource database Description[en_GB]=Manage the X resource database Description[es]=Gestionar la base de datos de recursos de las X Description[et]=X'i ressursside andmebaasi haldamine Description[eu]=Kudeatu X baliabideen datu-basea Description[fi]=Hallitse X:n resurssitietokantaa Description[fr]=Gère la base de données des ressources X Description[ga]=Bainistigh an bunachar sonraí acmhainní X Description[gl]=Xestionar a base de datos de recursos de X Description[gu]=X સ્ત્રોત ડેટાબેઝ ને સંચાલિત કરો Description[he]=נהל את מסד נתוני משאבי X Description[hi]=X संसाधन डेटाबेस प्रबंधित करें Description[hu]=Az X erőforrás-adatbázis kezelése Description[hy]=Կառավարել X ռեսուրսների տվյալների բազան Description[id]=Kelola basis data sumber daya X Description[it]=Gestisce il database delle risorse X Description[ja]=Xのリソース・データベースを管理します Description[kn]=X ಸಂಪನ್ಮೂಲ ದತ್ತಸಂಚಯವನ್ನು ನಿರ್ವಹಿಸು Description[ko]=X 리소스 데이터베이스 관리 Description[lt]=Tvarkyti X resursų duomenų bazę Description[lv]=Pārvaldīt X resursu datubāzi Description[mk]=Менаџирај го ресурсот X на базата за податоци. Description[ml]=എക്സ്-വിഭവ വിവരസംഭരണി കയ്കാര്യം ചെയ്യുക Description[mr]=X स्त्रोत माहितीकोष व्यवस्थापीत करा Description[ms]=Urus pangkalan data sumber X Description[nb]=Håndter X-ressursdatabasen Description[nl]=De X-resource database beheren Description[nn]=Handter X-ressursdatabasen Description[or]=X ଉତ୍ସ ତଥ୍ୟାଧାରକୁ ପରିଚାଳନା କରନ୍ତୁ Description[pa]=X ਸਰੋਤ ਡਾਟਾਬੇਸ ਪਰਬੰਧ Description[pl]=Zarządzanie bazą zasobów X Description[pt]=Gerir a base de dados do recurso X Description[pt_BR]=Gerenciar o banco de dados de recursos do X Description[ro]=Administrare bază de date cu resurse X Description[ru]=Управление базой данных ресурсов X Description[sk]=Spravovanie databázy zdrojov X Description[sl]=Upravljanje s podatkovno zbirko virov X Description[sr]=Управљање Иксовом базом ресурса Description[sr@latin]=Upravljanje Iksovom bazom resursa Description[sv]=Hantera X-resursdatabasen Description[ta]=எக்ஸ் வளங்கள் தரவுத்தளத்தை மேலாளுக Description[te]=X వనరు డాటాబేస్ ను నిర్వహించు Description[th]=จัดการฐานข้อมูลทรัพยากรของ X Description[tr]=X kaynak veritabanını yönet Description[uk]=Керування базою даних ресурсів X Description[vi]=Quản lý cơ sở dữ liệu tài nguyên X Description[zh_CN]=管理 X 资源数据库 Description[zh_HK]=管理 X 資源資料庫 Description[zh_TW]=管理 X 資源資料庫 Authors=Ross Burton Copyright=Copyright © 2007 Ross Burton Website= ukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.xinput.gschema.xml0000644000175000017500000000120314205117202026275 0ustar fengfeng true Activation of this plugin Whether this plugin would be activated by ukui-settings-daemon or not 20 Priority to use for this plugin Priority to use for this plugin in ukui-settings-daemon startup queue ukui-settings-daemon/data/a11y-settings.ukui-settings-plugin0000644000175000017500000000032614205117202023120 0ustar fengfeng[UKUI Settings Plugin] Module=a11y-settings IAge=0 Name=Accessibility settings Description=Accessibility settings plugin Authors=Bastien Nocera Copyright=Copyright © 2011 Red Hat Inc. Website= ukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.color.gschema.xml0000644000175000017500000000711414205117202026073 0ustar fengfeng true Activation of this plugin Whether this plugin would be activated by unity-settings-daemon or not 16 Priority to use for this plugin Priority to use for this plugin in unity-settings-daemon startup queue false If the night light mode is enabled Night light mode changes the color temperature of your display when the sun has gone down or at preset times. 5500 Temperature of the display when enabled This temperature in Kelvin is used to modify the screen tones when night light mode is enabled. Higher values are bluer, lower redder. true Use the sunrise and sunset Calculate the sunrise and sunset times automatically, from the current location. 20.00 The start time When “night-light-schedule-automatic” is disabled, use this start time in hours from midnight. 6.00 The end time When “night-light-schedule-automatic” is disabled, use this end time in hours from midnight. (91,181) The last detected position When location services are available this represents the last detected location. The default value is an invalid value to ensure it is always updated at startup. false Open night light all day (intel)At any time, night mode is open. false Use the sunrise and sunset to set theme (intel)Calculate the sunrise and sunset times, and set the theme automatically. 18.00 The start time (intel)When “night-light-schedule-automatic” is enabled, calculate this start time in hours from midnight. 7.00 The end time (intel)When “night-light-schedule-automatic” is enabled, calculate this end time in hours from midnight. false Use the read kwin config . ukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml0000644000175000017500000002225714205117202027012 0ustar fengfeng true Activation of this plugin Whether this plugin would be activated by ukui-settings-daemon or not true Show OSD notification Whether an OSD notification is shown to notify about changes 7 Priority to use for this plugin Priority to use for this plugin in ukui-settings-daemon startup queue 6 Volume step Volume step as percentage of volume. 'XF86TouchpadToggle' Toggle touchpad Binding to enable or disable the touchpad. 'XF86AudioMute' Volume mute Binding to mute the system volume. 'XF86AudioLowerVolume' Volume down Binding to lower the system volume. 'XF86AudioRaiseVolume' Volume up Binding to raise the system volume. 'XF86AudioMicMute' Mic mute Mute the Mic from the system. '' Shut down Binding to shut down. '<Ctrl><Alt>Delete' Open the shutdown management interfac Binding to log out. 'XF86Eject' Eject Binding to eject an optical disc. 'XF86Explorer' Home folder Binding to open the Home folder. 'XF86Search' Search Binding to launch the search tool. 'XF86Mail' Launch email client Binding to launch the email client. '<Ctrl><Alt>l' Lock screen Binding to lock the screen. '<Win>l' Lock screen Binding to lock the screen. '<Win>i' Open System Settings Binding to open system settings. 'XF86Tools' Open System Settings Binding to open system settings. '<Win>e' Open File Manager Binding to open file manager. '<Ctrl><Alt>e' Open File Manager Binding to open file manager. '' Launch help browser Binding to launch the help browser. 'XF86Calculator' Launch calculator Binding to launch the calculator. 'XF86WWW' Launch web browser Binding to launch the web browser. 'XF86AudioMedia' Launch media player Binding to launch the media player. 'XF86AudioPlay' Play (or play/pause) Binding to start playback (or toggle play/pause). 'XF86AudioPause' Pause playback Binding to pause playback. 'XF86AudioStop' Stop playback Binding to stop playback. 'XF86AudioPrev' Previous track Binding to skip to previous track. 'XF86AudioNext' Next track Binding to skip to next track. '' Toggle magnifier Binding to show the screen magnifier '' Toggle screen reader Binding to start the screen reader '' Toggle on-screen keyboard Binding to show the on-screen keyboard '<Ctrl><Alt>t' Terminal Open mate terminal. '<Win>t' Terminal Open mate terminal. 'Print' Take a screenshot Binding to take a screenshot. '<Ctrl>Print' Take a screenshot of a window Binding to take a screenshot of a window. '<Shift>Print' Take a screenshot of an area Binding to take a screenshot of an area. '<Win>a' Unflod Ukui Sidebar Binding to unflod the sidebar. '<Ctrl><Alt>w' Open Window Switch Binding to open window switch. '<Win>w' Open Window Switch Binding to open window switch. '<Ctrl><Shift>Escape' Open the system monitor Binding open the ukui-system-monitor. '<Win>k' Open the internet connectionr Binding open the unm-connection-edito. '<Win>s' Unflod Ukui Search Binding to unflod the ukui-search. '<Win>p' Kylin Display Switch Binding open the kylin-display-switch. 'XF86Display' Kylin Display Switch Binding open the kylin-display-switch. ukui-settings-daemon/data/xsettings.ukui-settings-plugin0000644000175000017500000001370714205117202022546 0ustar fengfeng[UKUI Settings Plugin] Module=xsettings IAge=0 Name=X Settings Name[af]=X-instellings Name[am]=X ማሰናጃ Name[ar]=إعدادات X Name[as]=X সংক্ৰান্ত বৈশিষ্ট্য Name[ast]=Axustes de les X Name[be]=Настáўленні X-оў Name[bg]=Настройки на X Name[bn]=X সংক্রান্ত বৈশিষ্ট্য Name[bn_IN]=X সংক্রান্ত বৈশিষ্ট্য Name[br]=Arventennoù X Name[ca]=Ajusts de les X Name[ca@valencia]=Paràmetres de les X Name[cmn]=X 設定值 Name[crh]=X Ayarları Name[cs]=Nastavení X Name[da]=X-indstillinger Name[de]=X-Einstellungen Name[el]=Ρυθμίσεις X Name[en_AU]=X Settings Name[en_GB]=X Settings Name[es]=Ajustes de las X Name[et]=X'i sätted Name[eu]=Xen ezarpenak Name[fi]=X-asetukset Name[fr]=Paramètres X Name[frp]=Règllâjo d’X Name[ga]=Socruithe X Name[gl]=Configuracións de X Name[gu]=X સુયોજનો Name[he]=הגדרות X Name[hi]=X सेटिंग Name[hr]=X postavke Name[hu]=X-beállítások Name[hy]=X Պարամետրեր Name[id]=Tatanan X Name[is]=Stillingar X Name[it]=Impostazioni X Name[ja]=X の設定 Name[kk]=X баптаулары Name[kn]=X ಸಿದ್ಧತೆಗಳು Name[ko]=X 설정 Name[lt]=X serverio nustatymai Name[lv]=X iestatījumi Name[mk]=Поставувања за X Name[ml]=എക്സ് സജ്ജീകരണങ്ങള്‍ Name[mr]=X संयोजना Name[ms]=Tetapan X Name[nb]=Innstillinger for X Name[nds]=X Instellens Name[nl]=X-instellingen Name[nn]=Innstillingar for X Name[or]=X ବିନ୍ୟାସ Name[pa]=X ਸੈਟਿੰਗ Name[pl]=Ustawienia X Name[pt]=Definições X Name[pt_BR]=Configurações do X Name[ro]=Configurări X Name[ru]=Параметры системы X Window Name[sk]=Nastavenia X Name[sl]=Nastavitve strežnika X Name[sr]=Подешавања Икса Name[sr@latin]=Podešavanja Iksa Name[sv]=X-inställningar Name[ta]=x அமைப்பு Name[te]=X అమరికలు Name[th]=ค่าตั้งของ X Name[tr]=X Ayarları Name[uk]=Параметри X Window Name[ur]=ایکس X ترتیبات Name[vi]=Thiết lập X Name[zh_CN]=X 设置 Name[zh_HK]=X 設定值 Name[zh_TW]=X 設定值 Description=Manage X Settings Description[af]=Bestuur X-instellings Description[am]=የ X ማሰናጃ አስተዳዳሪ Description[ar]=أدِر إعدادات X Description[as]=X-ৰ বৈশিষ্ট্য পৰিচালনা কৰক Description[ast]=Xestionar los axustes de les X Description[be]=Кіраванне настáўленнямі X Description[bg]=Управление на настройките на X Description[bn]=X-এর বৈশিষ্ট্য পরিচালনা করুন Description[bn_IN]=X-র বৈশিষ্ট্য পরিচালনা করুন Description[br]=Ardeiñ an arventennoù X Description[ca]=Gestiona els ajusts de les X Description[ca@valencia]=Gestiona els paràmetres de les X Description[cmn]=管理 X 設定值 Description[crh]=X Ayarlarını İdare Et Description[cs]=Spravovat nastavení X Description[da]=Håndter indstillinger for X Description[de]=X-Einstellungen verwalten Description[el]=Διαχείριση ρυθμίσεων X Description[en_AU]=Manage X Settings Description[en_GB]=Manage X Settings Description[es]=Gestionar los ajustes de las X Description[et]=X'i seadistuste haldamine Description[eu]=Kudeatu Xen ezarpenak Description[fi]=Hallitse X-asetuksia Description[fr]=Gestion des paramètres X Description[frp]=Manèyér los règllâjos d’X Description[ga]=Bainistigh Socruithe X Description[gl]=Xestionar as configuracións de X Description[gu]=X સુયોજનો ને સંચાલિત કરો Description[he]=נהל הגדרות X Description[hi]=X सेटिंग प्रबंधित करें Description[hu]=X-beállítások kezelése Description[hy]=Կառավարել X Պարամետրերը Description[id]=Kelola Tatanan X Description[is]=Sýsla með stillingar fyrir X Description[it]=Gestisce le impostazioni di X Description[ja]=X の設定を管理します Description[kk]=X баптауларын түзету Description[kn]=X ಸಿದ್ಧತೆಗಳನ್ನು ವ್ಯವಸ್ಥಾಪಿಸು Description[ko]=X 설정 관리 Description[lt]=Tvarkyti X serverio nustatymus Description[lv]=Pārvaldīt X iestatījumus Description[mk]=Менаџирај поставувања за X Description[ml]=എക്സ് സജ്ജീകരണങ്ങള്‍ കയ്കാര്യം ചെയ്യുക Description[mr]=X संयोजना व्यवस्थापीत करा Description[ms]=Urus Tetapan X Description[nb]=Håndter innstillinger for X Description[nl]=X-instellingen beheren Description[nn]=Handter innstillingar for X Description[or]=X ବିନ୍ୟାସକୁ ପରିଚାଳନା କରନ୍ତୁ Description[pa]=X ਸੈਟਿੰਗ ਪਰਬੰਧ Description[pl]=Zmiana ustawień X Description[pt]=Gerir Definições X Description[pt_BR]=Gerenciar configurações do X Description[ro]=Administrare de configurări X Description[ru]=Управление параметрами системы X Window Description[sk]=Spravovanie nastavenia X Description[sl]=Nastavitev strežnika X Description[sr]=Уреди подешавања Икса Description[sr@latin]=Uredi podešavanja Iksa Description[sv]=Hantera X-inställningar Description[ta]=x அமைப்பை மேலாளுக Description[te]=X అమరికలను నిర్వహించు Description[th]=จัดการค่าตั้งของ X Description[tr]=X Ayarlarını Yönet Description[uk]=Керування параметрами X Window Description[ur]=ایکس X ترتیبات کی ادارت کریں Description[vi]=Quản lý thiết lập X Description[zh_CN]=管理 X 设置 Description[zh_HK]=管理 X 設定值 Description[zh_TW]=管理 X 設定值 Authors=William Jon McCann Copyright=Copyright © 2007 William Jon McCann Website= ukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.xsettings.gschema.xml0000644000175000017500000000267314205117202027012 0ustar fengfeng true Activation of this plugin Whether this plugin would be activated by ukui-settings-daemon or not 2 Priority to use for this plugin Priority to use for this plugin in ukui-settings-daemon startup queue {} A dictionary of XSETTINGS to override This dictionary maps XSETTINGS names to overrides values. The values must be either strings, signed int32s or (in the case of colors), 4-tuples of uint16 (red, green, blue, alpha; 65535 is fully opaque). 1 Window Scaling Factor This controls the GTK scale factor that maps from window coordinates to the actual device pixels. On traditional systems this is 1, but on very high density displays (e.g. HiDPI, Retina) this can be a higher value (often 2). Set to 0 to auto-detect. ukui-settings-daemon/data/media-keys.ukui-settings-plugin0000644000175000017500000001372514205117202022546 0ustar fengfeng[UKUI Settings Plugin] Module=media-keys IAge=0 Name=Media keys Name[af]=Mediasleutels Name[am]=መገናኛ ቁልፎች Name[ar]=مفاتيح الوسائط Name[as]=মিডিয়া কি Name[ast]=Tecles multimedia Name[be]=Медыя-кнопкі Name[bg]=Мултимедийни клавиши Name[bn]=মিডিয়া কী Name[bn_IN]=মিডিয়া কি Name[br]=Alc'hwezioù ar media Name[ca]=Tecles multimèdia Name[ca@valencia]=Tecles multimèdia Name[cmn]=多媒體按鍵 Name[crh]=Ortam tuşları Name[cs]=Multimediální klávesy Name[da]=Medietaster Name[de]=Medientasten Name[el]=Πλήκτρα πολυμέσων Name[en_AU]=Media keys Name[en_GB]=Media keys Name[es]=Teclas multimedia Name[et]=Meediaklahvid Name[eu]=Multimedia-teklak Name[fi]=Medianäppäimet Name[fr]=Touches multimédias Name[ga]=Eochracha meán Name[gl]=Teclas multimedia Name[gu]=મીડિયા કીઓ Name[he]=מקשי מדיה Name[hi]=मीडिया कुंजी Name[hu]=Médiabillentyűk Name[hy]=Մեդիա բանալիներ Name[id]=Kunci media Name[is]=Margmiðlunarlyklar Name[it]=Tasti multimediali Name[ja]=メディア・キー Name[kn]=ಮೀಡಿಯಾ ಕೀಲಿಗಳು Name[ko]=미디어 키 Name[lt]=Multimedijos klavišai Name[lv]=Mediju taustiņi Name[mk]=Музички копчиња Name[ml]=മാധ്യമ സംയോജകം Name[mr]=मिडीया कि Name[ms]=Kekunci media Name[nb]=Medietaster Name[nds]=Medienknöppe Name[nl]=Mediatoetsen Name[nn]=Mediatastar Name[or]=ମେଡିଆ କିଗୁଡ଼ିକ Name[pa]=ਮੀਡਿਆ ਸਵਿੱਚਾਂ Name[pl]=Klawisze multimedialne Name[pt]=Teclas de Media Name[pt_BR]=Teclas de mídia Name[ro]=Taste media Name[ru]=Мультимедийные клавиши Name[sk]=Multimediálne klávesy Name[sl]=Predstavnostne tipke Name[sr]=Мултимедијални тастери Name[sr@latin]=Multimedijalni tasteri Name[sv]=Mediatangenter Name[ta]=ஊடக விசைகள் Name[te]=మాద్యమం కీలు Name[th]=ปุ่มสั่งการสื่อ Name[tr]=Ortam tuşları Name[uk]=Мультимедійні клявіші Name[ur]=میڈیا کی کلیدیں Name[vi]=Phím nhạc/phim Name[zh_CN]=媒体键 Name[zh_HK]=多媒體按鍵 Name[zh_TW]=多媒體按鍵 Description=Media keys plugin Description[af]=Inprop vir mediasleutels Description[am]=የ መገናኛ ቁልፎች ተሰኪ Description[ar]=ملحق مفاتيح الوسائط Description[as]=মিডিয়া-কি প্লাগ-ইন Description[ast]=Complementu de tecles multimedia Description[be]=Плагін медыя-кнопак Description[bg]=Приставка за мултимедийни клавиши Description[bn]=মিডিয়া-কি প্লাগ-ইন Description[bn_IN]=মিডিয়া-কি প্লাগ-ইন Description[br]=Enlugellad alc'hwezioù ar media Description[ca]=Connector de les tecles multimèdia Description[ca@valencia]=Connector de les tecles multimèdia Description[cmn]=多媒體按鍵外掛程式 Description[crh]=Ortam tuşları eklentisi Description[cs]=Zásuvný modul multimediálních kláves Description[da]=Medietastmodul Description[de]=Medientastenmodul Description[el]=Πρόσθετη λειτουργία πλήκτρων πολυμέσων Description[en_AU]=Media keys plugin Description[en_GB]=Media keys plugin Description[es]=Complemento de teclas multimedia Description[et]=Meediaklahvide plugin Description[eu]=Multimedia-teklen plugina Description[fi]=Medianäppäinten liitännäinen Description[fr]=Greffon des touches multimédias Description[ga]=Breiseán eochracha meán Description[gl]=Engadido das teclas multimedia Description[gu]=મીડિયા કી પલ્ગઇન Description[he]=תוסף מקשי מדיה Description[hi]=मीडिया कुंजी प्लगिन Description[hu]=Médiabillentyűk bővítmény Description[hy]=Մեդիա ստեղների կոնտակտներ Description[id]=Plugin kunci media Description[is]=Viðbót fyrir margmiðlunarlykla Description[it]=Plugin per i tasti multimediali Description[ja]=メディア・キーのプラグイン Description[kn]=ಮೀಡಿಯಾ ಕೀಲಿಗಳು ಪ್ಲಗ್ಇನ್ Description[ko]=미디어 키 플러그인 Description[lt]=Multimedijos klavišų įskiepis Description[lv]=Mediju taustiņu spraudnis Description[mk]=Додаток за копчињата за музика Description[ml]= സംയോജകം Description[mr]=मिडीया कि पल्गइन Description[ms]=Pemalam kekunci media Description[nb]=Tillegg for medietaster Description[nds]=Medienknöppeplugin Description[nl]=Mediatoetsen-plugin Description[nn]=Tillegg for medietastar Description[or]=ମେଡ଼ିଆ କିଗୁଡ଼ିକର ପ୍ଲଗଇନ Description[pa]=ਮੀਡਿਆ ਸਵਿੱਚ ਪਲੱਗਇਨ Description[pl]=Wtyczka klawiszy multimedialnych Description[pt]=Suplemento das teclas de media Description[pt_BR]=Plug-in de teclas de mídia Description[ro]=Modul taste media Description[ru]=Модуль мультимедийных клавиш Description[sk]=Modul multimediálnych kláves Description[sl]=Vstavek predstavnostnih tipk Description[sr]=Додатак за мултимедијалне тастере Description[sr@latin]=Dodatak za multimedijalne tastere Description[sv]=Insticksmodul för mediatangenter Description[ta]=ஊடக விசைகள் சொருகி Description[te]=మాద్యమం కీల ప్లగ్ఇన్ Description[th]=ปลั๊กอินจัดการปุ่มสั่งการสื่อ Description[tr]=Ortam tuşları eklentisi Description[uk]=Втулка мультимедійних клявіш Description[ur]=میڈیا کلیدیں دخیلہ Description[vi]=Phần mở rộng phím nhạc/phim Description[zh_CN]=媒体键插件 Description[zh_HK]=多媒體按鍵外掛程式 Description[zh_TW]=多媒體按鍵外掛程式 Authors= Copyright=Copyright © 2007 Website= ukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.keybindings.gschema.xml0000644000175000017500000000121414205117202027256 0ustar fengfeng true Activation of this plugin Whether this plugin would be activated by ukui-settings-daemon or not 8 Priority to use for this plugin Priority to use for this plugin in ukui-settings-daemon startup queue ukui-settings-daemon/data/background.ukui-settings-plugin0000644000175000017500000001175514205117202022636 0ustar fengfeng[UKUI Settings Plugin] Module=background IAge=0 Name=Background Name[af]=Agtergrond Name[am]=መደብ Name[ar]=الخلفية Name[as]=পটভূমি Name[ast]=Fondu de pantalla Name[be]=Фон Name[bg]=Фон Name[bn]=পটভূমি Name[bn_IN]=পটভূমি Name[br]=Drekleur Name[ca]=Fons Name[ca@valencia]=Fons Name[cmn]=背景 Name[crh]=Arkaplan Name[cs]=Pozadí Name[cy]=Cefndir Name[da]=Baggrund Name[de]=Hintergrund Name[dz]=རྒྱབ་གཞི་ Name[el]=Παρασκήνιο Name[en_AU]=Background Name[en_GB]=Background Name[es]=Fondo de pantalla Name[et]=Taust Name[eu]=Atzeko planoa Name[fi]=Taustakuva Name[fr]=Arrière-plan Name[ga]=Cúlra Name[gl]=Fondo Name[gu]=પાશ્વ ભાગ Name[he]=רקע Name[hi]=पृष्ठभूमि Name[hr]=Pozadina Name[hu]=Háttér Name[hy]=Հետին պլան Name[id]=Latar Name[is]=Bakgrunnur Name[it]=Sfondo Name[ja]=背景 Name[ka]=ფონი Name[kk]=Фон Name[kn]=ಹಿನ್ನಲೆ Name[ko]=배경 Name[lt]=Fonas Name[lv]=Fons Name[mai]=पृष्ठभूमि Name[mk]=Позадина Name[ml]=പശ്ചാത്തലം Name[mr]=पार्श्वभूमी Name[ms]=Latar Belakang Name[nb]=Bakgrunn Name[nds]=Achtergrund Name[nl]=Achtergrond Name[nn]=Bakgrunn Name[oc]=Fons Name[or]=ପ୍ରୁଷ୍ଠଭୂମି Name[pa]=ਬੈਕਗਰਾਊਂਡ Name[pl]=Tło Name[pt]=Fundo Name[pt_BR]=Plano de fundo Name[ro]=Fundal Name[ru]=Фон рабочего стола Name[si]=පසුබිම Name[sk]=Pozadie Name[sl]=Ozadje Name[sr]=Позадина Name[sr@latin]=Pozadina Name[sv]=Bakgrund Name[ta]=பின்னணி Name[te]=బ్యాక్‌గ్రౌండ్ Name[th]=พื้นหลัง Name[tr]=Arkaplan Name[uk]=Тло Name[ur]=پس منظر Name[uz]=Orqa fon Name[vi]=Nền Name[zh_CN]=背景 Name[zh_HK]=背景 Name[zh_TW]=背景 Description=Background plugin Description[af]=Agtergrond-inprop Description[am]=የመደብ ተሰኪ Description[ar]=ملحق الخلفية Description[as]=পটভূমিৰ প্লাগ-ইন Description[ast]=Complementu de fondu de pantalla Description[be]=Плагін фону Description[bg]=Приставка за фон Description[bn]=পটভূমির প্লাগ-ইন Description[bn_IN]=পটভূমির প্লাগ-ইন Description[br]=Enlugellad an drekleur Description[ca]=Connector de fons Description[ca@valencia]=Connector de fons Description[cmn]=背景圖片外掛程式 Description[crh]=Arkaplan eklentisi Description[cs]=Zásuvný modul pozadí Description[da]=Baggrundsmodul Description[de]=Hintergrundmodul Description[el]=Πρόσθετη λειτουργία παρασκηνίου Description[en_AU]=Background plugin Description[en_GB]=Background plugin Description[es]=Complemento de fondo de pantalla Description[et]=Taustaplugin Description[eu]=Atzeko planoaren plugina Description[fi]=Taustakuvaliitännäinen Description[fr]=Greffon d'arrière-plan Description[ga]=Breiseán an chúlra Description[gl]=Engadido de fondo Description[gu]=પાશ્વ ભાગ પ્લગઇન Description[he]=תוסף רקע Description[hi]=पृष्ठभूमि प्लगिन Description[hr]=Priključak pozadine Description[hu]=Háttér bővítmény Description[hy]=Ֆոնի կոնտակտներ Description[id]=Plugin latar belakang Description[it]=Plugin per lo sfondo Description[ja]=背景のプラグイン Description[kn]=ಹಿನ್ನಲೆ ಪ್ಲಗ್ಇನ್ Description[ko]=배경 플러그인 Description[lt]=Fono įskiepis Description[lv]=Fona spraudnis Description[mk]=Додаток за позадина Description[ml]=പശ്ചാത്തലചിത്രം സമ്യോജകം Description[mr]=पार्श्वभूमी प्लगइन Description[ms]=Pemalam latar belakang Description[nb]=Tillegg for bakgrunn Description[nds]=Achtergrundplugin Description[nl]=Achtergrondplug-in Description[nn]=Tillegg for bakgrunn Description[or]=ପୃଷ୍ଠଭୂମି ପ୍ଲଗଇନ Description[pa]=ਬੈਕਗਰਾਊਂਡ ਪਲੱਗਇਨ Description[pl]=Wtyczka tła Description[pt]=Suplemento de fundo Description[pt_BR]=Plug-in do plano de fundo Description[ro]=Modul fundal Description[ru]=Модуль фона рабочего стола Description[sk]=Modul pozadia Description[sl]=Vstavek ozadja Description[sr]=Прикључак позадине Description[sr@latin]=Dodatak za pozadinu Description[sv]=Insticksmodul för bakgrund Description[ta]=பின்னணி சொருகி Description[te]=బ్యాక్‌గ్రౌండ్ ప్లగ్ఇన్ Description[th]=ปลั๊กอินจัดการพื้นหลัง Description[tr]=Arkaplan eklentisi Description[uk]=Втулка тла стільниці Description[ur]=پس منظر دخیلہ Description[vi]=Phần mở rộng nền Description[zh_CN]=背景插件 Description[zh_HK]=背景圖片外掛程式 Description[zh_TW]=背景圖片外掛程式 Authors= Copyright=Copyright © 2007 Website= ukui-settings-daemon/data/sharing.ukui-settings-plugin0000644000175000017500000000020314205117202022134 0ustar fengfeng[UKUI Settings Plugin] Module=sharing IAge=0 Name=Sharing Description=Sharing plugin Authors= Copyright=Copyright © 2020 Website= ukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.xrdb.gschema.xml0000644000175000017500000000117614205117202025716 0ustar fengfeng true Activation of this plugin Whether this plugin would be activated by ukui-settings-daemon or not 4 Priority to use for this plugin Priority to use for this plugin in ukui-settings-daemon startup queue ukui-settings-daemon/data/housekeeping.ukui-settings-plugin0000644000175000017500000000040714205117202023175 0ustar fengfeng[UKUI Settings Plugin] Module=housekeeping IAge=0 Name=Housekeeping Description=Automatically prunes thumbnail caches and other transient files, and warns about low disk space Authors=Michael J. Chudobiak Copyright=Copyright © 2008 Michael J. Chudobiak Website= ukui-settings-daemon/data/keyboard.ukui-settings-plugin0000644000175000017500000001304414205117202022310 0ustar fengfeng[UKUI Settings Plugin] Module=keyboard IAge=0 Name=Keyboard Name[af]=Sleutelbord Name[am]=የፊደል ሠሌዳ Name[ar]=لوحة المفاتيح Name[as]=কীবোৰ্ড Name[ast]=Tecláu Name[az]=Klaviatura Name[be]=Клавіятура Name[bg]=Клавиатура Name[bn]=কী-বোর্ড Name[bn_IN]=কি-বোর্ড Name[br]=Klavier Name[bs]=Tastatura Name[ca]=Teclat Name[ca@valencia]=Teclat Name[cmn]=鍵盤 Name[crh]=Klavye Name[cs]=Klávesnice Name[cy]=Bysellfwrdd Name[da]=Tastatur Name[de]=Tastatur Name[dz]=ལྡེ་སྒྲོམ། Name[el]=Πληκτρολόγιο Name[en_AU]=Keyboard Name[en_CA]=Keyboard Name[en_GB]=Keyboard Name[es]=Teclado Name[et]=Klaviatuur Name[eu]=Teklatua Name[fa]=صفحه‌کلید Name[fi]=Näppäimistö Name[fr]=Clavier Name[ga]=Méarchlár Name[gl]=Teclado Name[gu]=કીબોર્ડ Name[he]=מקלדת Name[hi]=कुंजीपटल Name[hr]=Tipkovnica Name[hu]=Billentyűzet Name[hy]=Ստեղնաշար Name[id]=Papan Ketik Name[is]=Lyklaborð Name[it]=Tastiera Name[ja]=キーボード Name[ka]=კლავიატურა Name[kk]=Пернетақта Name[kn]=ಕೀಲಿ ಮಣೆ Name[ko]=키보드 Name[ku]=Klavye Name[ku_IQ]=تەختەکلیل Name[lt]=Klaviatūra Name[lv]=Tastatūra Name[mai]=कुँजीपटल Name[mg]=Fafan-teny Name[mk]=Тастатура Name[ml]=കീബോര്‍ഡ് Name[mn]=Гар Name[mr]=कळफलक Name[ms]=Papan Kekunci Name[nb]=Tastatur Name[nds]=Knöppboord Name[ne]=कीबोर्ड Name[nl]=Toetsenbord Name[nn]=Tastatur Name[nso]=Boroto ya dinotlelo Name[oc]=Clavièr Name[or]=କି-ବୋର୍ଡ Name[pa]=ਕੀ-ਬੋਰਡ Name[pl]=Klawiatura Name[pt]=Teclado Name[pt_BR]=Teclado Name[ro]=Tastatură Name[ru]=Клавиатура Name[rw]=Mwandikisho Name[sk]=Klávesnica Name[sl]=Tipkovnica Name[sq]=Tastiera Name[sr]=Тастатура Name[sr@latin]=Tastatura Name[sv]=Tangentbord Name[ta]=விசைப்பலகை Name[te]=కీబోర్డు Name[th]=แป้นพิมพ์ Name[tr]=Klavye Name[uk]=Набірниця Name[ur]=کیبورڈ Name[uz]=Klaviatura Name[vi]=Bàn phím Name[wa]=Taprece Name[xh]=I-keyboard Name[zh_CN]=键盘 Name[zh_HK]=鍵盤 Name[zh_TW]=鍵盤 Name[zu]=Indawo yokushaya uma ubhala Description=Keyboard plugin Description[af]=Inprop vir die sleutelbord Description[am]=የ ፊደል ገበታ ተሰኪ Description[ar]=ملحق لوحة المفاتيح Description[as]=চাবিৰ ফলক প্লাগ-ইন Description[ast]=Complementu de tecláu Description[be]=Плагін клавіятуры Description[bg]=Приставка за клавиатурата Description[bn]=কী-বোর্ড প্লাগ-ইন Description[bn_IN]=কি-বোর্ড প্লাগ-ইন Description[br]=Enlugellad ar c'hlavier Description[ca]=Connector del teclat Description[ca@valencia]=Connector del teclat Description[cmn]=鍵盤外掛程式 Description[crh]=Klavye eklentisi Description[cs]=Zásuvný modul klávesnice Description[da]=Tastaturmodul Description[de]=Tastaturmodul Description[el]=Πρόσθετη λειτουργία πληκτρολογίου Description[en_AU]=Keyboard plugin Description[en_GB]=Keyboard plugin Description[es]=Complemento de teclado Description[et]=Klaviatuuriplugin Description[eu]=Teklatuaren plugina Description[fi]=Näppäimistöliitännäinen Description[fr]=Greffon du clavier Description[ga]=Breiseán an mhéarchláir Description[gl]=Engadido do teclado Description[gu]=કીબોર્ડ પ્લગઇન Description[he]=תוסף מקלדת Description[hi]=कुंजीपटल प्लगिन Description[hr]=Priključak tipkovnice Description[hu]=Billentyűzet bővítmény Description[hy]=Ստեղնաշարի կոնտակտներ Description[id]=Plugin papan tik Description[is]=Lyklaborðsviðbót Description[it]=Plugin per la tastiera Description[ja]=キーボードのプラグイン Description[kk]=Пернетақта плагині Description[kn]=ಕೀಲಿ ಮಣೆ ಪ್ಲಗ್ಇನ್ Description[ko]=키보드 플러그인 Description[lt]=Klaviatūros įskiepis Description[lv]=Tastatūras spraudnis Description[mk]=Додаток за тастатура Description[ml]=കീബോര്‍ഡ് സംയോജകം Description[mr]=कळफलक प्लगइन Description[ms]=Pemalam papan kekunci Description[nb]=Tillegg for tastatur Description[nds]=Knöppboordplugin Description[nl]=Toetsenbord-plugin Description[nn]=Tillegg for tastatur Description[oc]=Empeuton del clavièr Description[or]=କି-ବୋର୍ଡ ପ୍ଲଗଇନ Description[pa]=ਕੀ-ਬੋਰਡ ਪਲੱਗਇਨ Description[pl]=Wtyczka klawiatury Description[pt]=Suplemento de teclado Description[pt_BR]=Plug-in do teclado Description[ro]=Modul tastatură Description[ru]=Модуль клавиатуры Description[sk]=Modul klávesnice Description[sl]=Vstavek tipkovnice Description[sr]=Прикључак за тастатуру Description[sr@latin]=Dodatak za tastaturu Description[sv]=Insticksmodul för tangentbord Description[ta]=விசைப்பலகை சொருகி Description[te]=కీబోర్డు ప్లగ్ఇన్ Description[th]=ปลั๊กอินจัดการแป้นพิมพ์ Description[tr]=Klavye eklentisi Description[uk]=Втулка набірниці Description[ur]=کیبورڈ دخیلہ Description[vi]=Phần mở rộng bàn phím Description[zh_CN]=键盘插件 Description[zh_HK]=鍵盤外掛程式 Description[zh_TW]=鍵盤外掛程式 Authors= Copyright=Copyright © 2007 Website= ukui-settings-daemon/data/color.ukui-settings-plugin0000644000175000017500000000027114205117202021624 0ustar fengfeng[UKUI Settings Plugin] Module=color IAge=0 Name=Color Name[zh_CN]=色温调整 Description=Color plugin Authors=Shang Xiaoyang Copyright=Copyright (C) 2020 KylinSoft Co., Ltd. Website= ukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.a11y-keyboard.gschema.xml0000644000175000017500000000122114205117202027317 0ustar fengfeng true Activation of this plugin Whether this plugin would be activated by ukui-settings-daemon or not 14 Priority to use for this plugin Priority to use for this plugin in ukui-settings-daemon startup queue ukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.xrandr.gschema.xml0000644000175000017500000001231114205117202026246 0ustar fengfeng true Activation of this plugin Whether this plugin would be activated by ukui-settings-daemon or not 3 Priority to use for this plugin Priority to use for this plugin in ukui-settings-daemon startup queue false Show Displays in Notification Area Whether a notification icon with display-related things should be shown in the panel. true Do not touch monitor configuration Usually, ukui-settings-daemon configures internal and external monitors according to the turn_on_external_monitors_at_startup and turn_on_laptop_monitor_at_startup settings and determines an appropriate cloning/side-by-side mode. Setting this key to True disables this, and the monitor settings are not touched at all (unless there is an explicit user configuration). false Turn on external monitor after system boot Turn on external monitor after system boot if user plugs in external monitor on system boot. true Turn on laptop monitor after system boot Turn on laptop monitor after system boot if user plugs in external monitor on system boot. '/etc/ukui-settings-daemon/xrandr/monitors.xml' File for default configuration for RandR The XRandR plugin will look for a default configuration in the file specified by this key. This is similar to the ~/.config/monitors.xml that normally gets stored in users' home directories. If a user does not have such a file, or has one that does not match the user's setup of monitors, then the file specified by this key will be used instead. 'noshow' The xrandr apply window status the xrandr apply window show/notshow when true/false. 'normal' Modify the pc mode screen rotation angle Modify the screen rotation angle by value, only 0, 90, 180 and 270 degree rotation 'normal' Modify the pc mode screen rotation angle Modify the screen rotation angle by value, only 0, 90, 180 and 270 degree rotation 'normal' Modify the tablet mode screen rotation angle Modify the screen rotation angle by value, only 0, 90, 180 and 270 degree rotation 'normal' Modify the tablet mode screen rotation angle Modify the real time screen rotation angle by value, only 0, 90, 180 and 270 degree rotation 'expand' Whether to set the screen mirror or expand mode Use the switch to control whether the screen is mirror or expand mode false Whether the screen isClone or not Use the switch to control whether the screen is clone or expand mode false conver mate config to kscreen none ukui-settings-daemon/data/xrandr.ukui-settings-plugin0000644000175000017500000001605414205117202022012 0ustar fengfeng[UKUI Settings Plugin] Module=xrandr IAge=0 Name=XRandR Name[af]=XRandR Name[am]=XRandR Name[ar]=XRandR Name[as]=XRandR Name[ast]=XRandR Name[be]=XRandR Name[bg]=XRandR Name[bn]=XRandR Name[bn_IN]=XRandR Name[br]=XRandR Name[ca]=XRandR Name[ca@valencia]=XRandR Name[cmn]=XRandR Name[crh]=XRandR Name[cs]=XRandR Name[da]=XRandR Name[de]=XRandR Name[el]=XRandR Name[en_AU]=XRandR Name[en_GB]=XRandR Name[es]=XRandR Name[et]=XRandR Name[eu]=XRandR Name[fi]=XRandR Name[fr]=XRandR Name[ga]=XRandR Name[gl]=XRandR Name[gu]=XRandR Name[he]=XRandR Name[hi]=XRandR Name[hr]=XRandR Name[hu]=XRandR Name[hy]=XRևR Name[id]=XRandR Name[is]=XRandR Name[it]=XRandR Name[ja]=XRandR Name[kk]=XRandR Name[kn]=XRandR Name[ko]=XRandR Name[ky]=XRandR Name[lt]=XRandR Name[lv]=XRandR Name[mk]=XRandR Name[ml]=XRandR(എക്സ്-റാന്റ്-ആര്‍) Name[mr]=XRandR Name[ms]=XRandR Name[nb]=XRandR Name[nl]=XRandR Name[nn]=XRandR Name[oc]=XRandR Name[or]=XRandR Name[pa]=XRandR Name[pl]=XRandR Name[pms]=XRandR Name[pt]=XRandR Name[pt_BR]=XRandR Name[ro]=XRandR Name[ru]=XRandR Name[sk]=XRandR Name[sl]=XRandR Name[sr]=ХРандР Name[sr@latin]=XRandR Name[sv]=XRandR Name[ta]=XRandR Name[te]=XRandR Name[th]=XRandR Name[tr]=XRandR Name[uk]=XRandR Name[vi]=XRandR Name[zh_CN]=XRandR Name[zh_HK]=XRandR Name[zh_TW]=XRandR Description=Set up screen size and rotation settings Description[af]=Instellings vir skermgrootte en -rotasie Description[am]=የ መመልከቻ መጠን እና ማዞሪያ ማሰናጃ Description[ar]=اختر إعدادات حجم الشاشة والدوران Description[as]=পৰ্দ্দাৰ আকাৰ আৰু ৰ'টেছনৰ পছন্দ প্ৰতিষ্ঠা কৰক Description[ast]=Afitar los axustes de tamañu y rotación de la pantalla Description[be]=Наставіць памеры і паварот экрану Description[bg]=Настройки за размер на екрана и ротация Description[bn]=পর্দার মাপ ও আবর্তন সংক্রান্ত বৈশিষ্ট্য নির্ধারণ করুন Description[bn_IN]=পর্দার মাপ ও আবর্তন সংক্রান্ত বৈশিষ্ট্য নির্ধারণ করুন Description[ca]=Configura els ajusts de pantalla de la mida i de la rotació Description[ca@valencia]=Configura la mida de la pantalla i els paràmetres de rotació Description[cmn]=設定螢幕大小與旋轉設定值 Description[crh]=Ekran boyutu ve döndürme çevirimi ayarlarını ata Description[cs]=Zvolit velikost obrazovky a nastavení otočení Description[da]=Indstil skærmstørrelse og rotation Description[de]=Bildschirmgröße und -drehung einstellen Description[el]=Ρύθμιση μεγέθους οθόνης και περιστροφής Description[en_AU]=Set up screen size and rotation settings Description[en_GB]=Set up screen size and rotation settings Description[es]=Establecer los ajustes de tamaño y rotación de la pantalla Description[es_CO]=Establecer configuración de tamaño de pantalla y rotación Description[et]=Ekraani suuruse ja pööramise sätete määramine Description[eu]=Konfiguratu pantailaren tamaina eta biraketa Description[fi]=Määritä näytön koko ja kiertoasetukset Description[fr]=Définit la taille de l'écran et les paramètres de rotation Description[gl]=Definir o tamaño da pantalla e as configuracións de rotación Description[gu]=સ્ક્રીન માપ અને ફેરવણી સુયોજનો સુયોજીત કરો Description[he]=הגדרות גודל וסיבוב מסך Description[hi]=स्क्रीन आकार और चक्रीय सेटिंग सेट अप करें Description[hr]=Namjesti postavke veličine ekrana i rotacije Description[hu]=A képernyőméret és -forgatás beállítása Description[hy]=Կարգավորել էկրանի չափի և պտտման պարամետրերը Description[id]=Atur tatanan ukuran dan rotasi layar Description[is]=Stilla skjástærð og snúning Description[it]=Imposta la dimensione dello schermo e le impostazioni di rotazione Description[ja]=画面の大きさや回転といった設定を管理します Description[kk]=Экран өлшемі және бұру баптауларын орнату Description[kn]=ತೆರೆಯ ಗಾತ್ರ ಹಾಗು ಸುತ್ತುವಿಕೆಯನ್ನು ಹೊಂದಿಸು Description[ko]=화면 크기 및 회전 설정을 합니다 Description[lt]=Nustatyti ekrano dydį ir pasukimą Description[lv]=Iestatiet ekrāna izmēra un pagriešanas iestatījumus Description[mk]=Постави ги поставувањата за големина на екранот и ротацијата Description[ml]=സ്ക്രീന്‍ വലിപ്പവും തിരിക്കലും സജ്ജീകരിക്കുക Description[mr]=पडदा आकार व चक्राकार संयोजना निश्चित करा Description[ms]=Pasang tetapan saiz dan putaran skrin Description[nb]=Rediger innstillinger for skjermstørrelse og rotasjon Description[nl]=Schermafmeting en draaistand instellen Description[nn]=Rediger innstillingar for skjermstørrelse og rotasjon Description[or]=ପରଦା ଆକାର ଏବଂ ଆବର୍ତ୍ତନ ବିନ୍ୟାସ Description[pa]=ਸਕਰੀਨ ਸਾਈਜ਼ ਅਤੇ ਘੁੰਮਾਉਣ ਸੈਟਿੰਗ ਸੈੱਟਅੱਪ Description[pl]=Ustawia rozmiar i orientację ekranu Description[pt]=Estabelecer tamanho do ecrã e definições de rotação Description[pt_BR]=Definir um tamanho de tela e definições de rotação Description[ro]=Definire dimensiune și rotire ecran Description[ru]=Установить размер экрана и параметры поворота Description[sk]=Nastavenie veľkosti a rotácie obrazovky Description[sl]=Nastavitev velikosti in obračanja zaslona Description[sr]=Подешавање величине и ротације екрана Description[sr@latin]=Podešavanje veličine i rotacije ekrana Description[sv]=Konfigurera skärmstorlek och roteringsinställningar Description[ta]=திரை அளவு மற்றும் சுழற்சி அமைப்பு Description[te]=తెర పరిమాణంను మరియు సర్దుబాటు అమరికలను అమర్చుము Description[th]=ตั้งค่าความละเอียดของจอภาพและการหมุนภาพบนจอ Description[tr]=Ekran boyutu ve döndürme çevirimi ayarlarını ata Description[uk]=Встановити розмір екрану та параметри повороту Description[ur]=سکرین کا حجم اور گُھماؤ کی ترتیبات مُتعین کریں Description[vi]=Thiết lập kích cỡ màn hình và chức năng xoay Description[zh_CN]=设置屏幕尺寸及旋转 Description[zh_HK]=設定螢幕大小與旋轉設定值 Description[zh_TW]=設定螢幕大小與旋轉設定值 Authors=Various Copyright=Copyright © 2007 Novell Website= ukui-settings-daemon/data/org.ukui.peripherals-touchscreen.gschema.xml0000644000175000017500000000061214205117202025204 0ustar fengfeng false Whether the tablet’s orientation is locked, or rotated automatically. ukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.mouse.gschema.xml0000644000175000017500000000157514205117202026112 0ustar fengfeng true Activation of this plugin Whether this plugin would be activated by ukui-settings-daemon or not 10 Priority to use for this plugin Priority to use for this plugin in ukui-settings-daemon startup queue false Display mouse position according to gSettings value changes. Mainly realizes the signal transmission function. ukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.a11y-settings.gschema.xml0000644000175000017500000000122214205117202027360 0ustar fengfeng false Activation of this plugin Whether this plugin would be activated by ukui-settings-daemon or not 15 Priority to use for this plugin Priority to use for this plugin in ukui-settings-daemon startup queue ukui-settings-daemon/data/clipboard.ukui-settings-plugin0000644000175000017500000001323614205117202022452 0ustar fengfeng[UKUI Settings Plugin] Module=clipboard IAge=0 Name=Clipboard Name[af]=Knipbord Name[am]=ቁራጭ ሰሌዳ Name[ar]=الحافظة Name[as]=ক্লিপ-বোৰ্ড Name[ast]=Cartafueyu Name[be]=Буфер абмену Name[bg]=Буфер за обмен Name[bn]=ক্লিপ-বোর্ড Name[bn_IN]=ক্লিপ-বোর্ড Name[br]=Golver Name[ca]=Porta-retalls Name[ca@valencia]=Porta-retalls Name[cmn]=剪貼簿 Name[crh]=Pano Name[cs]=Schránka Name[da]=Udklipsholder Name[de]=Zwischenablage Name[el]=Πρόχειρο Name[en_AU]=Clipboard Name[en_GB]=Clipboard Name[es]=Portapapeles Name[et]=Lõikelaud Name[eu]=Arbela Name[fi]=Leikepöytä Name[fr]=Presse-papiers Name[ga]=Gearrthaisce Name[gl]=Portapapeis Name[gu]=ક્લિપબોર્ડ Name[he]=לוח Name[hi]=क्लिपबोर्ड Name[hu]=Vágólap Name[hy]=Փոխանակման բուֆեր Name[id]=Tempel isi clipboard Name[is]=Klippispjald Name[it]=Appunti Name[ja]=クリップボード Name[kk]=Алмасу буфері Name[kn]=ಕ್ಲಿಪ್‌ಬೋರ್ಡ್ Name[ko]=클립보드 Name[lt]=Iškarpinė Name[lv]=Starpliktuve Name[mai]=क्लिपबोर्ड Name[mk]=Табла со исечоци Name[ml]=താല്‍കാലിക വിവര ശേഖരം Name[mr]=क्लिपबोर्ड Name[ms]=Papan Keratan Name[nb]=Utklippstavle Name[nds]=Twüschenavlag Name[nl]=Klembord Name[nn]=Utklippstavle Name[oc]=Quichapapièrs Name[or]=କର୍ତ୍ତନପଟ୍ଟ Name[pa]=ਕਲਿੱਪਬੋਰਡ Name[pl]=Schowek Name[pt]=Área de Transferência Name[pt_BR]=Área de transferência Name[ro]=Clipboard Name[ru]=Буфер обмена Name[sk]=Schránka Name[sl]=Odložišče Name[sr]=Списак исечака Name[sr@latin]=Spisak isečaka Name[sv]=Urklipp Name[ta]=ஒட்டுப்பலகை Name[te]=క్లిప్‌బోర్డు Name[th]=คลิปบอร์ด Name[tr]=Pano Name[uk]=Буфер обміну Name[ur]=کلپ بورڈ Name[vi]=Bảng nháp Name[zh_CN]=剪贴板 Name[zh_HK]=剪貼簿 Name[zh_TW]=剪貼簿 Description=Clipboard plugin Description[af]=Inprop vir knipbord Description[am]=የቁራጭ ሰሌዳ ተሰኪ Description[ar]=ملحق الحافظة Description[as]=ক্লিপ-বোৰ্ডৰ প্লাগ-ইন Description[ast]=Complementu del Cartafueyu Description[be]=Плагін буфера абмену Description[bg]=Приставка за буфера за обмен Description[bn]=ক্লিপ-বোর্ডের প্লাগ-ইন Description[bn_IN]=ক্লিপ-বোর্ডের প্লাগ-ইন Description[br]=Enlugellad ar golver Description[ca]=Connector del porta-retalls Description[ca@valencia]=Connector del porta-retalls Description[cmn]=剪貼簿外掛程式 Description[crh]=Pano eklentisi Description[cs]=Zásuvný modul schránky Description[da]=Udklipsholdermodul Description[de]=Zwischenablagemodul Description[el]=Πρόσθετη λειτουργία προχείρου Description[en_AU]=Clipboard plugin Description[en_GB]=Clipboard plugin Description[es]=Complemento del portapapeles Description[et]=Lõikelaua plugin Description[eu]=Arbelaren plugina Description[fi]=Leikepöytäliitännäinen Description[fr]=Greffon du presse-papiers Description[ga]=Breiseán gearrthaisce Description[gl]=Engadido de portapapeis Description[gu]=ક્લિપબોર્ડ પ્લગઇન Description[he]=תוסף לוח Description[hi]=क्लिपबोर्ड प्लगिन Description[hu]=Vágólap bővítmény Description[hy]=Փոխանակման բուֆերի կոնտակտներ Description[id]=Plugin clipboard Description[is]=Klippispjaldsviðbót Description[it]=Plugin per gli appunti Description[ja]=クリップボードのプラグイン Description[kk]=Алмасу буфері плагині Description[kn]=ಕ್ಲಿಪ್‌ಬೋರ್ಡ್ ಪ್ಲಗ್ಇನ್ Description[ko]=클립보드 플러그인 Description[lt]=Iškarpinės įskiepis Description[lv]=Starpliktuves spraudnis Description[mai]=क्लिपबोर्ड प्लगिन Description[mk]=Додатоко за таблата со исечоци Description[ml]=താല്‍കാലിക വിവര ശേഖരം സംയോജകം Description[mr]=क्लिपबोर्ड प्लगइन Description[ms]=Pemalam papan keratan Description[nb]=Tillegg for utklippstavle Description[nds]=Twüschenavlagplugin Description[nl]=Klembord-plug-in Description[nn]=Tillegg for utklippstavle Description[or]=କ୍ଲିପବୋର୍ଡ ପ୍ଲଗ୍ଇନ Description[pa]=ਕਲਿੱਪਬੋਰਡ ਪਲੱਗਇਨ Description[pl]=Wtyczka schowka Description[pt]=Suplemento da área de transferência Description[pt_BR]=Plug-in da área de transferência Description[ro]=Modul clipboard Description[ru]=Модуль буфера обмена Description[sk]=Modul schránky Description[sl]=Vstavek odložišča Description[sr]=Додатак за списак исечака Description[sr@latin]=Dodatak za spisak isečaka Description[sv]=Insticksmodul för urklipp Description[ta]=ஒட்டுப்பலகை சொருகி Description[te]=క్లిప్‌బోర్డు ప్లగ్ఇన్ Description[th]=ปลั๊กอินจัดการคลิปบอร์ด Description[tr]=Pano eklentisi Description[uk]=Втулка буферу обміну Description[ur]=کلپ بورڈ دخیلہ Description[vi]=Phần mở rộng bảng nháp Description[zh_CN]=剪贴板插件 Description[zh_HK]=剪貼簿外掛程式 Description[zh_TW]=剪貼簿外掛程式 Authors=Matthias Clasen Copyright=Copyright © 2007 Matthias Clasen Website= ukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.mpris.gschema.xml0000644000175000017500000000120014205117202026075 0ustar fengfeng true Activation of this plugin Whether this plugin would be activated by ukui-settings-daemon or not 9 Priority to use for this plugin Priority to use for this plugin in ukui-settings-daemon startup queue ukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.keyboard.gschema.xml0000644000175000017500000000120714205117202026552 0ustar fengfeng true Activation of this plugin Whether this plugin would be activated by ukui-settings-daemon or not 11 Priority to use for this plugin Priority to use for this plugin in ukui-settings-daemon startup queue ukui-settings-daemon/data/ukui-settings-daemon.desktop0000644000175000017500000000577414205117202022141 0ustar fengfeng[Desktop Entry] Type=Application Name=UKUI Settings Daemon Name[am]=የ ሜት ማሰናጃ ረዳት Name[ar]=محثّ إعدادات متّة Name[as]=UKUI Settings ডেমন Name[ast]=Degorriu d'axustes de UKUI Name[be]=Дэман настáўленняў UKUI Name[bg]=Сървър за настройките на UKUI Name[bn]=UKUI Settings ডেমন Name[bn_IN]=UKUI Settings ডেমন Name[ca]=Dimoni dels ajusts de UKUI Name[ca@valencia]=Dimoni de paràmetres del UKUI Name[cmn]=UKUI 設定值守護程式 Name[crh]=UKUI Ayarları Cını Name[cs]=Démon nastavení UKUI Name[da]=UKUI-indstillingsdæmon Name[de]=UKUI-Einstellungsdienst Name[el]=Δαίμονας ρυθμίσεων UKUI Name[en_AU]=UKUI Settings Daemon Name[en_GB]=UKUI Settings Daemon Name[es]=Administrador de preferencias de UKUI Name[et]=UKUI sätetedeemon Name[eu]=UKUIren ezarpenen daemon-a Name[fi]=Maten asetuspalvelin Name[fr]=Service des paramètres UKUI Name[ga]=Deamhan Socruithe UKUI Name[gl]=Servizo de configuracións do UKUI Name[gu]=UKUI સુયોજનો ડેઇમન Name[he]=מנוע ההגדרות של UKUI Name[hi]=गनोम सेटिंग डेमॉन Name[hu]=UKUI beállításdémon Name[hy]=UKUI Կարգաբերման պարամետրերի օժանդակ ծրագիր Name[id]=Daemon Penataan UKUI Name[it]=Demone di impostazioni per UKUI Name[ja]=UKUI 設定デーモン Name[kn]=UKUI ಸಂಯೋಜನೆಗಳ ಡೀಮನ್(Daemon) Name[ko]=마테 설정 데몬 Name[lt]=UKUI nustatymų tarnyba Name[lv]=UKUI iestatījumu dēmons Name[mk]=Демонот за поставувања на UKUI Name[ml]=ഗ്നോമിലെ സജ്ജീകരണങ്ങളുടെ നിരന്തരപ്രവൃത്തി Name[mr]=UKUI संयोजना डीमन Name[ms]=Daemon Tetapan UKUI Name[nb]=UKUI oppsettstjenestenisse Name[nl]=Mate-instellingenvoorziening Name[nn]=UKUI innstillingsnisse Name[or]=UKUI ବିନ୍ୟାସ ଡେମନ Name[pa]=ਗਨੋਮ ਸੈਟਿੰਗ ਡੈਮਨ Name[pl]=Usługa ustawień środowiska UKUI Name[pt]=Servidor de Definições UKUI Name[pt_BR]=Daemon de configurações do UKUI Name[ro]=Serviciul de configurări UKUI Name[ru]=Демон параметров UKUI Name[sk]=Démon nastavení UKUI Name[sl]=Ozadnji program nastavitev UKUI Name[sr]=Мејтов услужник подешавања Name[sr@latin]=Uslužni program za podešavanje Gnoma Name[sv]=UKUI-inställningsdemon Name[ta]=UKUI அமைவுகள் கிங்கரன் Name[te]=UKUI అమర్పుల డెమోన్ Name[th]=ดีมอนค่าตั้ง UKUI Name[tr]=UKUI Ayarlar Servisi Name[uk]=Служба параметрів UKUI Name[ur]=میٹ ترتیبات ڈیمن Name[vi]=Trình nền Thiết lập UKUI Name[zh_CN]=UKUI 设置守护程序 Name[zh_HK]=UKUI 設定值伺服程式 Name[zh_TW]=UKUI 設定值守護程式 Exec=/usr/bin/ukui-settings-daemon OnlyShowIn=UKUI; X-UKUI-Autostart-Phase=Initialization X-UKUI-Autostart-Notify=true X-UKUI-AutoRestart=true ukui-settings-daemon/data/org.ukui.peripherals-mouse.gschema.xml0000644000175000017500000000650514205117202024021 0ustar fengfeng false Mouse button orientation Swap left and right mouse buttons for left-handed mice. -1 Motion Acceleration Acceleration multiplier for mouse motion. A value of -1 is the system default. -1 Motion Threshold Distance in pixels the pointer must move before accelerated mouse motion is activated. A value of -1 is the system default. 'default' Acceleration profile Acceleration profile used for connected mice. The acceleration profile can be set to either default ('default') which uses the default acceleration profile for each device, flat ('flat'), which accelerates by a device specific constant factor derived from the configured pointer speed, or adaptive ('adaptive') which adapts the acceleration depending on the mouse movement. If a mouse doesn't support the configured profile, 'default' will be used. 8 Drag Threshold Distance before a drag is started. 400 Double Click Time Length of a double click. false Middle button emulation Enables middle mouse button emulation through simultaneous left and right button click. false Locate Pointer Highlights the current location of the pointer when the Control key is pressed and released. 'dark-sense' Cursor theme Cursor theme name. 24 Cursor size Size of the cursor referenced by cursor_theme. 1 Mouse wheel speed Set the mouse wheel speed by running imwheel. true Mouse accel Set mouse acceleration ukui-settings-daemon/data/org.ukui.SettingsDaemon.service0000644000175000017500000000012014205117202022516 0ustar fengfeng[D-BUS Service] Name=org.ukui.SettingsDaemon Exec=/usr/bin/ukui-settings-daemon ukui-settings-daemon/data/keybindings.ukui-settings-plugin0000644000175000017500000001330014205117202023011 0ustar fengfeng[UKUI Settings Plugin] Module=keybindings IAge=0 Name=Keybindings Name[af]=Sleutelbindings Name[am]=ቁልፍ ማጣመሪያ Name[ar]=ارتباطات المفاتيح Name[as]=কি-বাইন্ডিং Name[ast]=Combinaciones de tecles Name[be]=Скароты Name[bg]=Клавишни комбинации Name[bn]=কী-বাইন্ডিং Name[bn_IN]=কি-বাইন্ডিং Name[ca]=Vinculacions Name[ca@valencia]=Vinculacions de tecla Name[cmn]=組合鍵 Name[crh]=Tuş bağları Name[cs]=Klávesové zkratky Name[da]=Tastegenveje Name[de]=Tastenkürzel Name[el]=Συνδυασμοί πλήκτρων Name[en_AU]=Keybindings Name[en_GB]=Keybindings Name[es]=Combinaciones de teclas Name[et]=Kiirklahvid Name[eu]=Laster-teklak Name[fi]=Näppäinsidokset Name[fr]=Raccourcis clavier Name[ga]=Ceangail eochrach Name[gl]=Combinacións de teclas Name[gu]=Keybindings Name[he]=צירופי מקשים Name[hi]=कीबाइंडिंग Name[hu]=Billentyűparancsok Name[hy]=Առանցքային կապերի Name[id]=Keybinding Name[it]=Associazioni di tasti Name[ja]=キーバインディング Name[kn]=ಕೀಲಿಬದ್ಧತೆಗಳು Name[ko]=키바인딩 Name[lt]=Klavišų susiejimai Name[lv]=Taustiņu sasaistes Name[mk]=Копчиња Name[ml]=കീ-ബന്ധങ്ങള്‍ Name[mr]=किबांधणी Name[ms]=Pengikatan Kunci Name[nb]=Tastaturbindinger Name[nl]=Sneltoetsen Name[nn]=Snøggtastar Name[or]=କି ବନ୍ଧନଗୁଡ଼ିକ Name[pa]=ਕੀਬਾਈਡਿੰਗ Name[pl]=Skróty klawiszowe Name[pt]=Atalhos de teclado Name[pt_BR]=Atalhos do teclado Name[ro]=Asociere taste Name[ru]=Комбинации клавиш клавиатуры Name[sk]=Klávesové skratky Name[sl]=Tipkovne bližnjice Name[sr]=Пречице Name[sr@latin]=Prečice na tastaturi Name[sv]=Tangentbindningar Name[ta]=விசை பிணைப்புகள் Name[te]=కీబందనాలు Name[th]=ปุ่มลัด Name[tr]=Tuş bağları Name[uk]=Сполучення клявіш Name[ur]=کی بائنڈنگ Name[vi]=Tổ hợp phím Name[zh_CN]=键绑定 Name[zh_HK]=組合鍵 Name[zh_TW]=組合鍵 Description=Keybindings plugin Description[af]=Inprop vir sleutelbindings Description[am]=የ ቁልፍ ማጣመሪያ ተሰኪ Description[ar]=ملحق ارتباطات المفاتيح Description[as]=কি-বাইন্ডিং প্লাগ-ইন Description[ast]=Complementu de combinaciones de tecles Description[be]=Плагін скаротаў Description[bg]=Приставка за клавишни комбинации Description[bn]=কী-বাইন্ডিং প্লাগ-ইন Description[bn_IN]=কি-বাইন্ডিং প্লাগ-ইন Description[ca]=Connector de vinculacions Description[ca@valencia]=Connector de vinculacions de tecla Description[cmn]=組合鍵外掛程式 Description[crh]=Tuş bağları eklentisi Description[cs]=Zásuvný modul klávesových zkratek Description[da]=Modul for tastegenveje Description[de]=Tastenkürzelmodul Description[el]=Πρόσθετη λειτουργία συνδυασμού πλήκτρων Description[en_AU]=Keybindings plugin Description[en_GB]=Keybindings plugin Description[es]=Complemento de combinaciones de teclas Description[et]=Kiirklahvide plugin Description[eu]=Laster-teklen plugina Description[fi]=Näppäinsidosten liitännäinen Description[fr]=Greffon des raccourcis clavier Description[ga]=Breiseán cheangail eochrach Description[gl]=Engadido de combinacións de teclas Description[gu]=Keybindings પ્લગઇન Description[he]=תוסף צירופי מקשים Description[hi]=कीबाइंडिंग प्लगिन Description[hu]=Billentyűparancsok bővítmény Description[hy]=Առանցքային կապերի կոնտակտներ Description[id]=Plugin keybinding Description[it]=Plugin per le associazioni di tasti Description[ja]=キーバインディングのプラグイン Description[kn]=ಕೀಲಿಬದ್ಧತೆಗಳ ಪ್ಲಗ್ಇನ್ Description[ko]=키바인딩 플러그인 Description[lt]=Klavišų susiejimų įskiepis Description[lv]=Taustiņu sasaistes spraudnis Description[mk]=Додаток за копчиња Description[ml]=കീ-ബന്ധങ്ങള്‍ സംയോജകം Description[mr]=किबांधणी प्लगइन Description[ms]=Pemalam pengikatan kunci Description[nb]=Tillegg for tastaturbindinger Description[nl]=Sneltoetsen-plugin Description[nn]=Tillegg for snøggtastar Description[or]=କି ବନ୍ଧନ ପ୍ଲଗଇନଗୁଡ଼ିକ Description[pa]=ਕੀਬਾਈਡਿੰਗ ਪਲੱਗਇਨ Description[pl]=Wtyczka skrótów klawiszowych Description[pt]=Suplemento de atalhos de teclado Description[pt_BR]=Plug-in de atalhos do teclado Description[ro]=Modul asociere taste Description[ru]=Модуль комбинаций клавиш клавиатуры Description[sk]=Modul klávesových skratiek Description[sl]=Vstavek tipkovnih bližnjic Description[sr]=Прикључак за пречице Description[sr@latin]=Dodatak za prečice na tastaturi Description[sv]=Insticksmodul för tangentbindningar Description[ta]=விசைப்பிணைப்புகள் சொருகி Description[te]=కీబందనాలు ప్లగ్ఇన్ Description[th]=ปลั๊กอินจัดการปุ่มลัด Description[tr]=Tuş bağları eklentisi Description[uk]=Втулка сполучень клявіш Description[ur]=کی بائنڈنگ دخیلہ Description[vi]=Phần mở rộng tổ hợp phím Description[zh_CN]=键绑定插件 Description[zh_HK]=組合鍵外掛程式 Description[zh_TW]=組合鍵外掛程式 Authors=AUTHOR Copyright=Copyright © 2007 AUTHOR Website= ukui-settings-daemon/data/ukui-settings-daemon.mo0000644000175000017500000004003214205117202021065 0ustar fengfeng< P 1Q Q  ! *, !W #y # # " "+G#[" #&$)Nd"1")(?h~"'J P&q!*$)9(c  "*>Rf y+ .DVk~%xE   ,3AZ3"9V17L)GqD"@c yChaIe +K'BZK O  !!!!""*3"\^"("Z"?#U#j#}##o# % (% 4%$@% e%Uo%<%,&*/&'Z&E&l&;5(<q((( (('()*5)$`)$)!)$)) *!#*E*!d**!*'*$*+!'+!I+3k+*++'+-,<,X,\,]x,,,,-!+-M-f-v----$-$.'. ..;.N.d.t.... ... /!/:/ M/ Z/ g/t/////// 000 0040 0 11+1Y21Y1Y1]@2$2-2$2-3KD3'3v3</4l474!44B4`55[5T5 G60T66"7)7?7[7 w77 888W9 :::;;;;;;$;B$<-g<Q<<<=%=5=BK= >> >!> >H>`'??!?!?.?aSgh%&Op1[_i.jeX#x m!`;7oB(3w]49A*>/NKt5JF{ -PVdQ=GEbRH\~8^MsrzZ+nU}vqTlf <I k2D?u:')|@6L$y,"WC0cY0 thru 3, 0 is inactive, 1-3 is button to emulateAcceleration multiplier for touchpad motion. A value of -1 is the system default.AccessibilityActivation of this pluginAntialiasingBinding to eject an optical disc.Binding to enable or disable the touchpad.Binding to launch the calculator.Binding to launch the email client.Binding to launch the help browser.Binding to launch the media player.Binding to launch the search tool.Binding to launch the web browser.Binding to lock the screen.Binding to log out.Binding to lower the system volume.Binding to mute the system volume.Binding to open the Home folder.Binding to pause playback.Binding to raise the system volume.Binding to show the on-screen keyboardBinding to show the screen magnifierBinding to shut down.Binding to skip to next track.Binding to skip to previous track.Binding to start playback (or toggle play/pause).Binding to start the screen readerBinding to stop playback.Binding to take a screenshot of a window.Binding to take a screenshot of an area.Binding to take a screenshot.DPIDisable touchpad while typingDistance in pixels the pointer must move before accelerated touchpad motion is activated. A value of -1 is the system default.Do not touch monitor configurationEjectEnable horizontal edge scrollingEnable horizontal two-finger scrollingEnable mouse clicks with touchpadEnable three-finger button-click emulationEnable touchpadEnable vertical edge scrollingEnable vertical two-finger scrollingEnabled two-finger button-click emulationFile for default configuration for RandRFree percentage notify thresholdFree space no notify thresholdHintingHome folderIf the night light mode is enabledKylin Display SwitchLaunch calculatorLaunch email clientLaunch help browserLaunch media playerLaunch web browserLock screenMinimum notify period for repeated warningsMotion AccelerationMotion ThresholdMount paths to ignoreMouse wheel speedNatural scrollingNext trackOn-screen keyboardOne finger tap buttonOpen File ManagerOpen System SettingsOpen Window SwitchOpen the internet connectionrOpen the shutdown management interfacOpen the system monitorPause playbackPercentage free space threshold for initial warning of low disk space. If the percentage free space drops below this, a warning will be shown.Play (or play/pause)Previous trackPriority to use for this pluginPriority to use for this plugin in ukui-settings-daemon startup queueRGBA orderScreen magnifierScreen readerSearchSelect the button mapping for one-finger tap. Supported values are: 1: left mouse button 2: middle mouse button 3: right mouse buttonSelect the button mapping for three-finger tap. Supported values are: 1: left mouse button 2: middle mouse button 3: right mouse buttonSelect the button mapping for two-finger tap. Supported values are: 1: left mouse button 2: middle mouse button 3: right mouse buttonSet this to TRUE if you have problems with accidentally hitting the touchpad while typing.Set this to TRUE to allow horizontal edge scrollingSet this to TRUE to allow horizontal two-finger scrollingSet this to TRUE to allow vertical edge scrollingSet this to TRUE to allow vertical two-finger scrollingSet this to TRUE to be able to send mouse clicks by tapping on the touchpad.Set this to TRUE to enable all touchpads.Set this to one of "none", "lock_screen", or "force_logout". The action will get performed when the smartcard used for log in is removed.Set this to true to enable natural (reverse) scrolling for touchpadsShow Displays in Notification AreaShow OSD notificationShut downSmartcard removal actionSpecify a list of mount paths to ignore when they run low on space.Specify a time in minutes. Subsequent warnings for a volume will not appear more often than this period.Specify an amount in GB. If the amount of free space is more than this, no warning will be shown.Specify the percentage that the free disk space should reduce by before issuing a subsequent warning.Stop playbackSubsequent free percentage notify thresholdSwap left and right buttons for left-handed touchpads with 'left', 'right' for right-handed, 'mouse' to follow the mouse setting.Take a screenshotTake a screenshot of a windowTake a screenshot of an areaTemperature of the display when enabledTerminalThe XRandR plugin will look for a default configuration in the file specified by this key. This is similar to the ~/.config/monitors.xml that normally gets stored in users' home directories. If a user does not have such a file, or has one that does not match the user's setup of monitors, then the file specified by this key will be used instead.The end timeThe last detected positionThe order of subpixel elements on an LCD screen; only used when antialiasing is set to "rgba". Possible values are: "rgb" for red on left (most common), "bgr" for blue on left, "vrgb" for red on top, "vbgr" for red on bottom.The resolution used for converting font sizes to pixel sizes, in dots per inch.The start timeThe type of antialiasing to use when rendering fonts. Possible values are: "none" for no antialiasing, "grayscale" for standard grayscale antialiasing, and "rgba" for subpixel antialiasing (LCD screens only).The type of hinting to use when rendering fonts. Possible values are: "none" for no hinting, "slight" for basic, "medium" for moderate, and "full" for maximum hinting (may cause distortion of letter forms).Three finger tap buttonToggle magnifierToggle on-screen keyboardToggle screen readerToggle touchpadTouchpad button orientationTurn on external monitor after system bootTurn on external monitor after system boot if user plugs in external monitor on system boot.Turn on laptop monitor after system bootTurn on laptop monitor after system boot if user plugs in external monitor on system boot.Two finger tap buttonUKUI Settings DaemonUnflod Ukui SearchUnflod Ukui SidebarUse the sunrise and sunsetUsually, ukui-settings-daemon configures internal and external monitors according to the turn_on_external_monitors_at_startup and turn_on_laptop_monitor_at_startup settings and determines an appropriate cloning/side-by-side mode. Setting this key to True disables this, and the monitor settings are not touched at all (unless there is an explicit user configuration).Volume downVolume muteVolume stepVolume step as percentage of volume.Volume upWhether a notification icon with display-related things should be shown in the panel.Whether an OSD notification is shown to notify about changesWhether the on-screen keyboard is turned on.Whether the screen magnifier is turned on.Whether the screen reader is turned on.Whether this plugin would be activated by ukui-settings-daemon or notProject-Id-Version: UKUI Desktop Environment Report-Msgid-Bugs-To: PO-Revision-Date: 2016-12-06 03:16+0000 Last-Translator: liushuyu011 Language-Team: Chinese (China) (http://wiki.ukui.org/trans/) Language: zh_CN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=1; plural=0; 值为 0 至 3,0 为禁用,1-3 为要模拟的鼠标键触摸板运动的加速倍数。系统的默认值是 -1。辅助插件激活状态反锯齿弹出光盘的键绑定。启用或禁用触摸板的键绑定。调用计算器的键绑定。调用电子邮件客户端的键绑定。调用帮助浏览器的键绑定。调用媒体播放机的键绑定。调用搜索工具的键绑定。调用网际浏览器的键绑定。锁住屏幕的键绑定。注销的键绑定。降低系统音量的键绑定。使系统静音的键绑定。打开主文件夹的键绑定。暂停播放的键绑定。升高系统音量的键绑定。用于显示屏幕键盘的键绑定。用于显示放大镜的键绑定。конец связи跳到下一音轨的键绑定。跳到上一音轨的键绑定。开始回放或切换 播放/暂停 的键绑定。用于显示屏幕阅读器的键绑定。停止回放的键绑定。截取窗口截图的快捷键绑定。截取一个区域的截图快捷键绑定。截图的快捷键绑定。DPI在输入时禁用触摸板启动触摸板运动加速前鼠标必须移动的像素点数。系统默认的值是 -1。不要修改显示器配置弹出启用水平边界滚动启用水平双指滚动使用触摸板启用鼠标点击开启三指单击模拟启用触摸板启用垂直边界滚动启用垂直双指滚动已开启双指单击模拟RandR 默认配置文件触发通知的最低可用百分比不触发通知的最低可用空间微调主文件夹启用夜灯模式打开显示器切换启动计算器启动电子邮件客户端启动帮助浏览器启动媒体播放机启动网际浏览器锁住屏幕重复警告的最短间隔触摸板移动加速度运动阈值要忽略的挂载路径鼠标滚轮速度自然滚动下一音轨屏幕键盘单指拍击按钮打开文件管理器打开控制面板打开工作区打开网络连接打开关机管理界面打开系统监视器暂停回放触发低硬盘空间初次警告的最低可用空间百分比。如果可用空间的百分比低于该值,将显示一个警告播放(或播放/暂停)上一音轨插件优先级插件在 ukui-settings-daemon 中的启动优先级RGBA 顺序屏幕放大镜屏幕阅读器搜索选择用于单指拍击的按钮映射。支持如下值:1: 左键 2: 中键 3: 右键选择用于三指拍击的按钮映射。支持如下值:1: 左键 2: 中键 3: 右键选择用于双指拍击的按钮映射。支持如下值:1: 左键 2: 中键 3: 右键如果您打字时会因偶尔会碰到触摸板而造成麻烦,将其设置为真(TRUE)。设置为真(TRUE)启用水平滚动设置为真(TRUE)以启用双指水平滚动设置为真(TRUE)启用垂直滚动设置为真(TRUE)以启用双指垂直滚动设置为真(TRUE),即可在轻敲触摸板时发送鼠标点击信息。设置为真(TRUE)启用所有触摸板设置为“none”、“lock_screen”或“force_logout”之一。 当智能卡移除时,这个动作被执行。设置为 true 以为触摸板开启自然(反向)滚动在通知区域显示выводить уведомления на экранвыключение.конец. 智能卡移除动作指定当运行在低硬盘空间时要忽略的挂载路径清单以分钟为单位指定某个时间。该周期内不会多次显示某个卷的后续警告。以 GB 为单位指定某个量。如果可用空间超过该值,将不再显示警告。在发布一个后续警告之前,指定应减少的可用硬盘空间百分比。停止回放触发通知的最低后续可用空间百分比交换触摸板上的左右按键,左撇子使用 ‘左’ 选项,右撇子使用 ‘右’ 选项,选择 ‘鼠标’ 可以跟随鼠标的设置。截图截取窗口的截图截取一个区域的截图启用时显示器的温度打开终端XRandR 插件将在本项指定的文件中寻找默认配置。通常,这类似于 获取存储在家目录下的~/.config/monitors.xml。如果用户没有这样的文件,或者有一个不符合用户显示器的设置,然后本项指定的文件将被替代。结束时间最后检测到的位置坐标LCD 屏幕上次像素的顺序;仅在反锯齿设为“rgba”时有用。可能的设定值有:“rgb” - 红色在左侧,最常见设置。“bgr” - 蓝色在左侧。“vrgb” - 红色在上端。“vbgr” - 红色在底部。将字体尺寸转换为像素值时所用的分辨率,以每英寸点数为单位。开始时间绘制字形时使用的反锯齿类型。可能的设定有:“无” - 无反锯齿。“灰度” - 标准灰度反锯齿。“rgba” - 次像素反锯齿 (LCD 屏幕专用)。绘制字形时使用微调的类型。可能的设定有:“无” - 无微调,“轻微”,“中等”以及“完全” - 尽量多地进行微调(可能会引起字形扭曲)。三指拍击按钮切换放大镜切换屏幕上键盘切换屏幕阅读器触摸板开关触摸板按键方向系统启动后打开外部显示器系统启动时,如果用户插入外部显示器就打开它。系统启动后打开笔记本电脑显示器系统启动时,如果用户插入外部显示器,打开笔记本显示器。双指拍击按钮UKUI 设置守护程序显示全局搜索展开侧边栏使用日出和日落在配置内置/外接显视器时,ukui-settings-daemon 通常根据turn_on_external_monitors_at_startup、turn_on_laptop_monitor_at_startup 进行配置,并确定合适的复制/并排模式。若将此键值设为True,就会停用这一功能,显视器的配置文件将不作改动(除非用户显式配置;)。音量降低静音音量步进以音量百分比步进音量。音量升高是否在面板中显示一个通知图标,其中包括相关信息。об изменениях уведомлять выводом показаний на экран是否已打开屏幕键盘。是否已打开屏幕放大镜。是否已打开屏幕阅读器。此插件是否由 ukui-settings-daemon 启动ukui-settings-daemon/data/xinput.ukui-settings-plugin0000644000175000017500000000031614205117202022035 0ustar fengfeng[UKUI Settings Plugin] Module=xinput IAge=0 Name=Xinput-Device-Manager Name[zh_CN]=输入设备管理 Description=Xinput plugin Authors=Zhu Yunpeng Copyright=Copyright (C) 2020 KylinSoft Co., Ltd. Website= ukui-settings-daemon/data/zh_CN.po0000644000175000017500000007643214205117202016032 0ustar fengfeng# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Aron Xu , 2009 # by Abel Cheung , 2001 # Deng Xiyue , 2009 # Cravix , 2013 # nyanyh , 2013 # He Qiangqiang , 2002 # liushuyu011 , 2016 # Sun G11n , 2002 # Tao Wang , 2010 # Tao Wei , 2009 # vicwjb , 2010 # Wylmer Wang, 2013 # павел назаров , 2016 # 甘 露 , 2009 # Mingcong Bai , 2015 # Shang Xiaooyang , 2020 msgid "" msgstr "" "Project-Id-Version: UKUI Desktop Environment\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-12-14 14:02+0800\n" "PO-Revision-Date: 2016-12-06 03:16+0000\n" "Last-Translator: liushuyu011 \n" "Language-Team: Chinese (China) (http://wiki.ukui.org/trans/)\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" #: ../data/50-accessibility.xml.in.h:1 msgid "Accessibility" msgstr "辅助" #: ../data/50-accessibility.xml.in.h:2 #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:53 msgid "Toggle magnifier" msgstr "切换放大镜" #: ../data/50-accessibility.xml.in.h:3 #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:55 msgid "Toggle screen reader" msgstr "切换屏幕阅读器" #: ../data/50-accessibility.xml.in.h:4 #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:57 msgid "Toggle on-screen keyboard" msgstr "切换屏幕上键盘" #: ../data/org.ukui.applications-at.gschema.xml.in.h:1 msgid "On-screen keyboard" msgstr "屏幕键盘" #: ../data/org.ukui.applications-at.gschema.xml.in.h:2 msgid "Whether the on-screen keyboard is turned on." msgstr "是否已打开屏幕键盘。" #: ../data/org.ukui.applications-at.gschema.xml.in.h:3 msgid "Screen magnifier" msgstr "屏幕放大镜" #: ../data/org.ukui.applications-at.gschema.xml.in.h:4 msgid "Whether the screen magnifier is turned on." msgstr "是否已打开屏幕放大镜。" #: ../data/org.ukui.applications-at.gschema.xml.in.h:5 msgid "Screen reader" msgstr "屏幕阅读器" #: ../data/org.ukui.applications-at.gschema.xml.in.h:6 msgid "Whether the screen reader is turned on." msgstr "是否已打开屏幕阅读器。" #: ../data/org.ukui.font-rendering.gschema.xml.in.h:1 msgid "DPI" msgstr "DPI" #: ../data/org.ukui.font-rendering.gschema.xml.in.h:2 msgid "" "The resolution used for converting font sizes to pixel sizes, in dots per " "inch." msgstr "将字体尺寸转换为像素值时所用的分辨率,以每英寸点数为单位。" #: ../data/org.ukui.font-rendering.gschema.xml.in.h:3 msgid "Antialiasing" msgstr "反锯齿" #: ../data/org.ukui.font-rendering.gschema.xml.in.h:4 msgid "" "The type of antialiasing to use when rendering fonts. Possible values are: " "\"none\" for no antialiasing, \"grayscale\" for standard grayscale " "antialiasing, and \"rgba\" for subpixel antialiasing (LCD screens only)." msgstr "" "绘制字形时使用的反锯齿类型。可能的设定有:“无” - 无反锯齿。“灰度” - 标准灰度" "反锯齿。“rgba” - 次像素反锯齿 (LCD 屏幕专用)。" #: ../data/org.ukui.font-rendering.gschema.xml.in.h:5 msgid "Hinting" msgstr "微调" #: ../data/org.ukui.font-rendering.gschema.xml.in.h:6 msgid "" "The type of hinting to use when rendering fonts. Possible values are: \"none" "\" for no hinting, \"slight\" for basic, \"medium\" for moderate, and \"full" "\" for maximum hinting (may cause distortion of letter forms)." msgstr "" "绘制字形时使用微调的类型。可能的设定有:“无” - 无微调,“轻微”,“中等”以及“完" "全” - 尽量多地进行微调(可能会引起字形扭曲)。" #: ../data/org.ukui.font-rendering.gschema.xml.in.h:7 msgid "RGBA order" msgstr "RGBA 顺序" #: ../data/org.ukui.font-rendering.gschema.xml.in.h:8 msgid "" "The order of subpixel elements on an LCD screen; only used when antialiasing " "is set to \"rgba\". Possible values are: \"rgb\" for red on left (most " "common), \"bgr\" for blue on left, \"vrgb\" for red on top, \"vbgr\" for red " "on bottom." msgstr "" "LCD 屏幕上次像素的顺序;仅在反锯齿设为“rgba”时有用。可能的设定值有:“rgb” - " "红色在左侧,最常见设置。“bgr” - 蓝色在左侧。“vrgb” - 红色在上端。“vbgr” - 红" "色在底部。" #: ../data/org.ukui.peripherals-smartcard.gschema.xml.in.h:1 msgid "Smartcard removal action" msgstr "智能卡移除动作" #: ../data/org.ukui.peripherals-smartcard.gschema.xml.in.h:2 msgid "" "Set this to one of \"none\", \"lock_screen\", or \"force_logout\". The " "action will get performed when the smartcard used for log in is removed." msgstr "" "设置为“none”、“lock_screen”或“force_logout”之一。 当智能卡移除时,这个动作被" "执行。" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:1 msgid "Disable touchpad while typing" msgstr "在输入时禁用触摸板" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:2 msgid "" "Set this to TRUE if you have problems with accidentally hitting the touchpad " "while typing." msgstr "如果您打字时会因偶尔会碰到触摸板而造成麻烦,将其设置为真(TRUE)。" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:3 msgid "Enable mouse clicks with touchpad" msgstr "使用触摸板启用鼠标点击" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:4 msgid "" "Set this to TRUE to be able to send mouse clicks by tapping on the touchpad." msgstr "设置为真(TRUE),即可在轻敲触摸板时发送鼠标点击信息。" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:5 msgid "Enable vertical edge scrolling" msgstr "启用垂直边界滚动" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:6 msgid "Set this to TRUE to allow vertical edge scrolling" msgstr "设置为真(TRUE)启用垂直滚动" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:7 msgid "Enable horizontal edge scrolling" msgstr "启用水平边界滚动" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:8 msgid "Set this to TRUE to allow horizontal edge scrolling" msgstr "设置为真(TRUE)启用水平滚动" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:9 msgid "Enable vertical two-finger scrolling" msgstr "启用垂直双指滚动" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:10 msgid "Set this to TRUE to allow vertical two-finger scrolling" msgstr "设置为真(TRUE)以启用双指垂直滚动" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:11 msgid "Enable horizontal two-finger scrolling" msgstr "启用水平双指滚动" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:12 msgid "Set this to TRUE to allow horizontal two-finger scrolling" msgstr "设置为真(TRUE)以启用双指水平滚动" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:13 msgid "Natural scrolling" msgstr "自然滚动" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:14 msgid "Set this to true to enable natural (reverse) scrolling for touchpads" msgstr "设置为 true 以为触摸板开启自然(反向)滚动" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:15 msgid "Enable touchpad" msgstr "启用触摸板" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:16 msgid "Set this to TRUE to enable all touchpads." msgstr "设置为真(TRUE)启用所有触摸板" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:17 msgid "Enabled two-finger button-click emulation" msgstr "已开启双指单击模拟" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:18 msgid "0 thru 3, 0 is inactive, 1-3 is button to emulate" msgstr "值为 0 至 3,0 为禁用,1-3 为要模拟的鼠标键" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:19 msgid "Enable three-finger button-click emulation" msgstr "开启三指单击模拟" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:20 msgid "One finger tap button" msgstr "单指拍击按钮" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:21 msgid "" "Select the button mapping for one-finger tap. Supported values are: 1: left " "mouse button 2: middle mouse button 3: right mouse button" msgstr "选择用于单指拍击的按钮映射。支持如下值:1: 左键 2: 中键 3: 右键" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:22 msgid "Two finger tap button" msgstr "双指拍击按钮" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:23 msgid "" "Select the button mapping for two-finger tap. Supported values are: 1: left " "mouse button 2: middle mouse button 3: right mouse button" msgstr "选择用于双指拍击的按钮映射。支持如下值:1: 左键 2: 中键 3: 右键" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:24 msgid "Three finger tap button" msgstr "三指拍击按钮" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:25 msgid "" "Select the button mapping for three-finger tap. Supported values are: 1: " "left mouse button 2: middle mouse button 3: right mouse button" msgstr "选择用于三指拍击的按钮映射。支持如下值:1: 左键 2: 中键 3: 右键" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:26 msgid "Touchpad button orientation" msgstr "触摸板按键方向" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:27 msgid "" "Swap left and right buttons for left-handed touchpads with 'left', 'right' " "for right-handed, 'mouse' to follow the mouse setting." msgstr "" "交换触摸板上的左右按键,左撇子使用 ‘左’ 选项,右撇子使用 ‘右’ 选项,选择 ‘鼠" "标’ 可以跟随鼠标的设置。" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:28 msgid "Motion Acceleration" msgstr "触摸板移动加速度" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:29 msgid "" "Acceleration multiplier for touchpad motion. A value of -1 is the system " "default." msgstr "触摸板运动的加速倍数。系统的默认值是 -1。" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:30 msgid "Motion Threshold" msgstr "运动阈值" #: ../data/org.ukui.peripherals-touchpad.gschema.xml.in.h:31 msgid "" "Distance in pixels the pointer must move before accelerated touchpad motion " "is activated. A value of -1 is the system default." msgstr "启动触摸板运动加速前鼠标必须移动的像素点数。系统默认的值是 -1。" #: ../data/org.ukui.SettingsDaemon.plugins.a11y-keyboard.gschema.xml.in.h:1 #: ../data/org.ukui.SettingsDaemon.plugins.a11y-settings.gschema.xml.in.h:1 #: ../data/org.ukui.SettingsDaemon.plugins.background.gschema.xml.in.h:1 #: ../data/org.ukui.SettingsDaemon.plugins.clipboard.gschema.xml.in.h:1 #: ../data/org.ukui.SettingsDaemon.plugins.datetime.gschema.xml.in.h:1 #: ../data/org.ukui.SettingsDaemon.plugins.housekeeping.gschema.xml.in.h:1 #: ../data/org.ukui.SettingsDaemon.plugins.keybindings.gschema.xml.in.h:1 #: ../data/org.ukui.SettingsDaemon.plugins.keyboard.gschema.xml.in.h:1 #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:1 #: ../data/org.ukui.SettingsDaemon.plugins.mouse.gschema.xml.in.h:1 #: ../data/org.ukui.SettingsDaemon.plugins.mpris.gschema.xml.in.h:1 #: ../data/org.ukui.SettingsDaemon.plugins.smartcard.gschema.xml.in.h:1 #: ../data/org.ukui.SettingsDaemon.plugins.sound.gschema.xml.in.h:1 #: ../data/org.ukui.SettingsDaemon.plugins.typing-break.gschema.xml.in.h:1 #: ../data/org.ukui.SettingsDaemon.plugins.xrandr.gschema.xml.in.h:1 #: ../data/org.ukui.SettingsDaemon.plugins.xrdb.gschema.xml.in.h:1 #: ../data/org.ukui.SettingsDaemon.plugins.xsettings.gschema.xml.in.h:1 msgid "Activation of this plugin" msgstr "插件激活状态" #: ../data/org.ukui.SettingsDaemon.plugins.a11y-keyboard.gschema.xml.in.h:2 #: ../data/org.ukui.SettingsDaemon.plugins.a11y-settings.gschema.xml.in.h:2 #: ../data/org.ukui.SettingsDaemon.plugins.background.gschema.xml.in.h:2 #: ../data/org.ukui.SettingsDaemon.plugins.clipboard.gschema.xml.in.h:2 #: ../data/org.ukui.SettingsDaemon.plugins.datetime.gschema.xml.in.h:2 #: ../data/org.ukui.SettingsDaemon.plugins.housekeeping.gschema.xml.in.h:2 #: ../data/org.ukui.SettingsDaemon.plugins.keybindings.gschema.xml.in.h:2 #: ../data/org.ukui.SettingsDaemon.plugins.keyboard.gschema.xml.in.h:2 #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:2 #: ../data/org.ukui.SettingsDaemon.plugins.mouse.gschema.xml.in.h:2 #: ../data/org.ukui.SettingsDaemon.plugins.mpris.gschema.xml.in.h:2 #: ../data/org.ukui.SettingsDaemon.plugins.smartcard.gschema.xml.in.h:2 #: ../data/org.ukui.SettingsDaemon.plugins.sound.gschema.xml.in.h:2 #: ../data/org.ukui.SettingsDaemon.plugins.typing-break.gschema.xml.in.h:2 #: ../data/org.ukui.SettingsDaemon.plugins.xrandr.gschema.xml.in.h:2 #: ../data/org.ukui.SettingsDaemon.plugins.xrdb.gschema.xml.in.h:2 #: ../data/org.ukui.SettingsDaemon.plugins.xsettings.gschema.xml.in.h:2 msgid "Whether this plugin would be activated by ukui-settings-daemon or not" msgstr "此插件是否由 ukui-settings-daemon 启动" #: ../data/org.ukui.SettingsDaemon.plugins.a11y-keyboard.gschema.xml.in.h:3 #: ../data/org.ukui.SettingsDaemon.plugins.a11y-settings.gschema.xml.in.h:3 #: ../data/org.ukui.SettingsDaemon.plugins.background.gschema.xml.in.h:3 #: ../data/org.ukui.SettingsDaemon.plugins.clipboard.gschema.xml.in.h:3 #: ../data/org.ukui.SettingsDaemon.plugins.datetime.gschema.xml.in.h:3 #: ../data/org.ukui.SettingsDaemon.plugins.housekeeping.gschema.xml.in.h:3 #: ../data/org.ukui.SettingsDaemon.plugins.keybindings.gschema.xml.in.h:3 #: ../data/org.ukui.SettingsDaemon.plugins.keyboard.gschema.xml.in.h:3 #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:5 #: ../data/org.ukui.SettingsDaemon.plugins.mouse.gschema.xml.in.h:3 #: ../data/org.ukui.SettingsDaemon.plugins.mpris.gschema.xml.in.h:3 #: ../data/org.ukui.SettingsDaemon.plugins.smartcard.gschema.xml.in.h:3 #: ../data/org.ukui.SettingsDaemon.plugins.sound.gschema.xml.in.h:3 #: ../data/org.ukui.SettingsDaemon.plugins.typing-break.gschema.xml.in.h:3 #: ../data/org.ukui.SettingsDaemon.plugins.xrandr.gschema.xml.in.h:3 #: ../data/org.ukui.SettingsDaemon.plugins.xrdb.gschema.xml.in.h:3 #: ../data/org.ukui.SettingsDaemon.plugins.xsettings.gschema.xml.in.h:3 msgid "Priority to use for this plugin" msgstr "插件优先级" #: ../data/org.ukui.SettingsDaemon.plugins.a11y-keyboard.gschema.xml.in.h:4 #: ../data/org.ukui.SettingsDaemon.plugins.a11y-settings.gschema.xml.in.h:4 #: ../data/org.ukui.SettingsDaemon.plugins.background.gschema.xml.in.h:4 #: ../data/org.ukui.SettingsDaemon.plugins.clipboard.gschema.xml.in.h:4 #: ../data/org.ukui.SettingsDaemon.plugins.datetime.gschema.xml.in.h:4 #: ../data/org.ukui.SettingsDaemon.plugins.housekeeping.gschema.xml.in.h:4 #: ../data/org.ukui.SettingsDaemon.plugins.keybindings.gschema.xml.in.h:4 #: ../data/org.ukui.SettingsDaemon.plugins.keyboard.gschema.xml.in.h:4 #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:6 #: ../data/org.ukui.SettingsDaemon.plugins.mouse.gschema.xml.in.h:4 #: ../data/org.ukui.SettingsDaemon.plugins.mpris.gschema.xml.in.h:4 #: ../data/org.ukui.SettingsDaemon.plugins.smartcard.gschema.xml.in.h:4 #: ../data/org.ukui.SettingsDaemon.plugins.sound.gschema.xml.in.h:4 #: ../data/org.ukui.SettingsDaemon.plugins.typing-break.gschema.xml.in.h:4 #: ../data/org.ukui.SettingsDaemon.plugins.xrandr.gschema.xml.in.h:4 #: ../data/org.ukui.SettingsDaemon.plugins.xrdb.gschema.xml.in.h:4 #: ../data/org.ukui.SettingsDaemon.plugins.xsettings.gschema.xml.in.h:4 msgid "Priority to use for this plugin in ukui-settings-daemon startup queue" msgstr "插件在 ukui-settings-daemon 中的启动优先级" #: ../data/org.ukui.SettingsDaemon.plugins.housekeeping.gschema.xml.in.h:5 msgid "Free percentage notify threshold" msgstr "触发通知的最低可用百分比" #: ../data/org.ukui.SettingsDaemon.plugins.housekeeping.gschema.xml.in.h:6 msgid "" "Percentage free space threshold for initial warning of low disk space. If " "the percentage free space drops below this, a warning will be shown." msgstr "" "触发低硬盘空间初次警告的最低可用空间百分比。如果可用空间的百分比低于该值,将" "显示一个警告" #: ../data/org.ukui.SettingsDaemon.plugins.housekeeping.gschema.xml.in.h:7 msgid "Subsequent free percentage notify threshold" msgstr "触发通知的最低后续可用空间百分比" #: ../data/org.ukui.SettingsDaemon.plugins.housekeeping.gschema.xml.in.h:8 msgid "" "Specify the percentage that the free disk space should reduce by before " "issuing a subsequent warning." msgstr "在发布一个后续警告之前,指定应减少的可用硬盘空间百分比。" #: ../data/org.ukui.SettingsDaemon.plugins.housekeeping.gschema.xml.in.h:9 msgid "Free space no notify threshold" msgstr "不触发通知的最低可用空间" #: ../data/org.ukui.SettingsDaemon.plugins.housekeeping.gschema.xml.in.h:10 msgid "" "Specify an amount in GB. If the amount of free space is more than this, no " "warning will be shown." msgstr "以 GB 为单位指定某个量。如果可用空间超过该值,将不再显示警告。" #: ../data/org.ukui.SettingsDaemon.plugins.housekeeping.gschema.xml.in.h:11 msgid "Minimum notify period for repeated warnings" msgstr "重复警告的最短间隔" #: ../data/org.ukui.SettingsDaemon.plugins.housekeeping.gschema.xml.in.h:12 msgid "" "Specify a time in minutes. Subsequent warnings for a volume will not appear " "more often than this period." msgstr "以分钟为单位指定某个时间。该周期内不会多次显示某个卷的后续警告。" #: ../data/org.ukui.SettingsDaemon.plugins.housekeeping.gschema.xml.in.h:13 msgid "Mount paths to ignore" msgstr "要忽略的挂载路径" #: ../data/org.ukui.SettingsDaemon.plugins.housekeeping.gschema.xml.in.h:14 msgid "Specify a list of mount paths to ignore when they run low on space." msgstr "指定当运行在低硬盘空间时要忽略的挂载路径清单" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:3 msgid "Show OSD notification" msgstr "выводить уведомления на экран" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:4 msgid "Whether an OSD notification is shown to notify about changes" msgstr "об изменениях уведомлять выводом показаний на экран" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:7 msgid "Volume step" msgstr "音量步进" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:8 msgid "Volume step as percentage of volume." msgstr "以音量百分比步进音量。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:9 msgid "Toggle touchpad" msgstr "触摸板开关" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:10 msgid "Binding to enable or disable the touchpad." msgstr "启用或禁用触摸板的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:11 msgid "Volume mute" msgstr "静音" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:12 msgid "Binding to mute the system volume." msgstr "使系统静音的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:13 msgid "Volume down" msgstr "音量降低" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:14 msgid "Binding to lower the system volume." msgstr "降低系统音量的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:15 msgid "Volume up" msgstr "音量升高" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:16 msgid "Binding to raise the system volume." msgstr "升高系统音量的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:17 msgid "Shut down" msgstr "выключение.конец. " #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:18 msgid "Binding to shut down." msgstr "конец связи" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:19 msgid "Open the shutdown management interfac" msgstr "打开关机管理界面" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:20 msgid "Binding to log out." msgstr "注销的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:21 msgid "Eject" msgstr "弹出" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:22 msgid "Binding to eject an optical disc." msgstr "弹出光盘的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:23 msgid "Home folder" msgstr "主文件夹" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:24 msgid "Binding to open the Home folder." msgstr "打开主文件夹的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:25 msgid "Search" msgstr "搜索" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:26 msgid "Binding to launch the search tool." msgstr "调用搜索工具的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:27 msgid "Launch email client" msgstr "启动电子邮件客户端" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:28 msgid "Binding to launch the email client." msgstr "调用电子邮件客户端的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:29 msgid "Lock screen" msgstr "锁住屏幕" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:30 msgid "Binding to lock the screen." msgstr "锁住屏幕的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:31 msgid "Open System Settings" msgstr "打开控制面板" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:108 msgid "Open Window Switch" msgstr "打开工作区" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:32 #, fuzzy msgid "Binding to open system settings." msgstr "打开主文件夹的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:33 msgid "Open File Manager" msgstr "打开文件管理器" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:34 #, fuzzy msgid "Binding to open file manager." msgstr "打开主文件夹的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:35 msgid "Launch help browser" msgstr "启动帮助浏览器" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:36 msgid "Binding to launch the help browser." msgstr "调用帮助浏览器的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:37 msgid "Launch calculator" msgstr "启动计算器" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:38 msgid "Binding to launch the calculator." msgstr "调用计算器的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:39 msgid "Launch web browser" msgstr "启动网际浏览器" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:40 msgid "Binding to launch the web browser." msgstr "调用网际浏览器的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:41 msgid "Launch media player" msgstr "启动媒体播放机" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:42 msgid "Binding to launch the media player." msgstr "调用媒体播放机的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:43 msgid "Play (or play/pause)" msgstr "播放(或播放/暂停)" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:44 msgid "Binding to start playback (or toggle play/pause)." msgstr "开始回放或切换 播放/暂停 的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:45 msgid "Pause playback" msgstr "暂停回放" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:46 msgid "Binding to pause playback." msgstr "暂停播放的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:47 msgid "Stop playback" msgstr "停止回放" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:48 msgid "Binding to stop playback." msgstr "停止回放的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:49 msgid "Previous track" msgstr "上一音轨" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:50 msgid "Binding to skip to previous track." msgstr "跳到上一音轨的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:51 msgid "Next track" msgstr "下一音轨" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:52 msgid "Binding to skip to next track." msgstr "跳到下一音轨的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:54 msgid "Binding to show the screen magnifier" msgstr "用于显示放大镜的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:56 msgid "Binding to start the screen reader" msgstr "用于显示屏幕阅读器的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:58 msgid "Binding to show the on-screen keyboard" msgstr "用于显示屏幕键盘的键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:59 msgid "Terminal" msgstr "打开终端" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:60 #, fuzzy msgid "Open mate terminal." msgstr "打开终端。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:61 msgid "Take a screenshot" msgstr "截图" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:62 msgid "Binding to take a screenshot." msgstr "截图的快捷键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:63 msgid "Take a screenshot of a window" msgstr "截取窗口的截图" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:64 msgid "Binding to take a screenshot of a window." msgstr "截取窗口截图的快捷键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:65 msgid "Take a screenshot of an area" msgstr "截取一个区域的截图" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:66 msgid "Binding to take a screenshot of an area." msgstr "截取一个区域的截图快捷键绑定。" #: ../data/org.ukui.SettingsDaemon.plugins.xrandr.gschema.xml.in.h:5 msgid "Show Displays in Notification Area" msgstr "在通知区域显示" #: ../data/org.ukui.SettingsDaemon.plugins.xrandr.gschema.xml.in.h:6 msgid "" "Whether a notification icon with display-related things should be shown in " "the panel." msgstr "是否在面板中显示一个通知图标,其中包括相关信息。" #: ../data/org.ukui.SettingsDaemon.plugins.xrandr.gschema.xml.in.h:7 msgid "Do not touch monitor configuration" msgstr "不要修改显示器配置" #: ../data/org.ukui.SettingsDaemon.plugins.xrandr.gschema.xml.in.h:8 msgid "" "Usually, ukui-settings-daemon configures internal and external monitors " "according to the turn_on_external_monitors_at_startup and " "turn_on_laptop_monitor_at_startup settings and determines an appropriate " "cloning/side-by-side mode. Setting this key to True disables this, and the " "monitor settings are not touched at all (unless there is an explicit user " "configuration)." msgstr "" "在配置内置/外接显视器时,ukui-settings-daemon 通常根据" "turn_on_external_monitors_at_startup、turn_on_laptop_monitor_at_startup 进行" "配置,并确定合适的复制/并排模式。若将此键值设为True,就会停用这一功能,显视器" "的配置文件将不作改动(除非用户显式配置;)。" #: ../data/org.ukui.SettingsDaemon.plugins.xrandr.gschema.xml.in.h:9 msgid "Turn on external monitor after system boot" msgstr "系统启动后打开外部显示器" #: ../data/org.ukui.SettingsDaemon.plugins.xrandr.gschema.xml.in.h:10 msgid "" "Turn on external monitor after system boot if user plugs in external monitor " "on system boot." msgstr "系统启动时,如果用户插入外部显示器就打开它。" #: ../data/org.ukui.SettingsDaemon.plugins.xrandr.gschema.xml.in.h:11 msgid "Turn on laptop monitor after system boot" msgstr "系统启动后打开笔记本电脑显示器" #: ../data/org.ukui.SettingsDaemon.plugins.xrandr.gschema.xml.in.h:12 msgid "" "Turn on laptop monitor after system boot if user plugs in external monitor " "on system boot." msgstr "系统启动时,如果用户插入外部显示器,打开笔记本显示器。" #: ../data/org.ukui.SettingsDaemon.plugins.xrandr.gschema.xml.in.h:13 msgid "File for default configuration for RandR" msgstr "RandR 默认配置文件" #: ../data/org.ukui.SettingsDaemon.plugins.xrandr.gschema.xml.in.h:14 msgid "" "The XRandR plugin will look for a default configuration in the file " "specified by this key. This is similar to the ~/.config/monitors.xml that " "normally gets stored in users' home directories. If a user does not have " "such a file, or has one that does not match the user's setup of monitors, " "then the file specified by this key will be used instead." msgstr "" "XRandR 插件将在本项指定的文件中寻找默认配置。通常,这类似于 获取存储在家目录" "下的~/.config/monitors.xml。如果用户没有这样的文件,或者有一个不符合用户显示" "器的设置,然后本项指定的文件将被替代。" #: ../data/ukui-settings-daemon.desktop.in.in.h:1 msgid "UKUI Settings Daemon" msgstr "UKUI 设置守护程序" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:93 msgid "Unflod Ukui Sidebar" msgstr "展开侧边栏" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:183 msgid "Open the system monitor" msgstr "打开系统监视器" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:188 msgid "Open the internet connectionr" msgstr "打开网络连接" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:220 msgid "Unflod Ukui Search" msgstr "显示全局搜索" #: ../data/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml.in.h:225 msgid "Kylin Display Switch" msgstr "打开显示器切换" #: ./org.ukui.SettingsDaemon.plugins.color.gschema.xml:16 msgid "If the night light mode is enabled" msgstr "启用夜灯模式" #: ./org.ukui.SettingsDaemon.plugins.color.gschema.xml:21 msgid "Temperature of the display when enabled" msgstr "启用时显示器的温度" #: ./org.ukui.SettingsDaemon.plugins.color.gschema.xml:26 msgid "Use the sunrise and sunset" msgstr "使用日出和日落" #: ./org.ukui.SettingsDaemon.plugins.color.gschema.xml:31 msgid "The start time" msgstr "开始时间" #: ./org.ukui.SettingsDaemon.plugins.color.gschema.xml:36 msgid "The end time" msgstr "结束时间" #: ./org.ukui.SettingsDaemon.plugins.color.gschema.xml:41 msgid "The last detected position" msgstr "最后检测到的位置坐标" #: ./org.ukui.peripherals-mouse.gschema.xml:61 msgid "Mouse wheel speed" msgstr "鼠标滚轮速度" ukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.housekeeping.gschema.xml0000644000175000017500000000402014205117202027434 0ustar fengfeng true Activation of this plugin Whether this plugin would be activated by ukui-settings-daemon or not 13 Priority to use for this plugin Priority to use for this plugin in ukui-settings-daemon startup queue 0.05 Free percentage notify threshold Percentage free space threshold for initial warning of low disk space. If the percentage free space drops below this, a warning will be shown. 0.01 Subsequent free percentage notify threshold Specify the percentage that the free disk space should reduce by before issuing a subsequent warning. 2 Free space no notify threshold Specify an amount in GB. If the amount of free space is more than this, no warning will be shown. 10 Minimum notify period for repeated warnings Specify a time in minutes. Subsequent warnings for a volume will not appear more often than this period. [] Mount paths to ignore Specify a list of mount paths to ignore when they run low on space. ukui-settings-daemon/data/mpris.ukui-settings-plugin0000644000175000017500000000463414205117202021647 0ustar fengfeng[UKUI Settings Plugin] Module=mpris IAge=0 Name=Mpris Name[am]=Mpris Name[ar]=Mpris Name[be]=Mpris Name[bg]=Mpris Name[ca]=Mpris Name[ca@valencia]=Mpris Name[cmn]=Mpris Name[cs]=Mpris Name[da]=Mpris Name[de]=MPRIS Name[el]=Mpris Name[en_AU]=Mpris Name[en_GB]=Mpris Name[es]=Mpris Name[et]=Mpris Name[fr]=Mpris Name[gl]=Mpris Name[he]=Mpris Name[hu]=Mpris Name[hy]=Mpris Name[id]=Mpris Name[it]=Mpris Name[ja]=Mpris Name[kn]=Mpris Name[ko]=엠프리스 Name[ky]=Mpris Name[lt]=Mpris Name[mr]=Mpris Name[ms]=Mpris Name[nb]=Mpris Name[nl]=Mpris Name[oc]=Mpris Name[pl]=Mpris Name[pms]=Mpris Name[pt]=Mpris Name[pt_BR]=Mpris Name[ro]=Mpris Name[ru]=Mpris Name[sk]=Mpris Name[sl]=Mpris Name[sr]=Мприс Name[sv]=Mpris Name[tr]=Mpris Name[uk]=Mpris Name[zh_CN]=Mpris Name[zh_TW]=Mpris Description=Mpris plugin Description[am]=Mpris ተሰኪ Description[ar]=ملحق Mpris Description[be]=Плагін Mpris Description[bg]=Приставката „Mpris“ Description[ca]=Connector Mpris Description[ca@valencia]=Connector Mpris Description[cmn]=Mpris 外掛程式 Description[cs]=Zásuvný modul Mpris Description[da]=Mpris-udvidelsesmodul Description[de]=MPRIS-Erweiterung Description[el]=Πρόσθετο Mpris Description[en_AU]=Mpris plugin Description[en_GB]=Mpris plug-in Description[es]=Complemento Mpris Description[et]=Mpris plugin Description[fr]=Greffon Mpris Description[gl]=Engadido Mpris Description[he]=תוסף Mpris Description[hu]=Mpris plugin Description[hy]=Mpris Կոնտակտներ Description[id]=pengaya Mpris Description[it]=Plugin Mpris Description[ja]=Mpris プラグイン Description[kn]=Mpris ಪ್ಲಗ್‌ಇನ್ Description[ko]=엠프리스 플러그인 Description[lt]=Mpris papildinys Description[mr]=Mpris प्लगइन Description[ms]=Pemalam Mpris Description[nb]=Mpris-tilleggsprogram Description[nl]=Mpris-plugin Description[oc]=Empeuton Mpris Description[pl]=Wtyczka Mpris Description[pt]=Suplemento de Mpris Description[pt_BR]=Plugin Mpris Description[ro]=Plugin Mpris Description[ru]=Модуль Mpris Description[sk]=Mpris plugin Description[sl]=Vstavek Mpris Description[sr]=Прикључак за мприса Description[sv]=Mpris insticksmodul Description[tr]=Mpris eklentisi Description[uk]=Втулка Mpris Description[ur]=Mpris دخیلہ Description[zh_CN]=Mpris 插件 Description[zh_TW]=Mpris 外掛程式 Authors=Stefano Karapetsas Copyright=Copyright © 2013 Stefano Karapetsas Website= ukui-settings-daemon/data/tablet-mode.ukui-settings-plugin0000644000175000017500000000031314205117202022700 0ustar fengfeng[UKUI Settings Plugin] Module=tablet-mode IAge=0 Name=Tablet-mode Name[zh_CN]=平板模式 Description=Tablet-mode plugin Authors=Shang Xiaoyang Copyright=Copyright (C) 2020 KylinSoft Co., Ltd. Website= ukui-settings-daemon/data/data.pri0000644000175000017500000000666314205117202016115 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-03-17T09:30:00 # #------------------------------------------------- OTHER_FILES += \ $$PWD/ukui-settings-daemon.desktop \ $$PWD/org.ukui.SettingsDaemon.service \ $$PWD/org.ukui.font-rendering.gschema.xml.in \ $$PWD/org.ukui.SettingsDaemon.plugins.a11y-settings.gschema.xml \ $$PWD/org.ukui.SettingsDaemon.plugins.a11y-keyboard.gschema.xml \ $$PWD/org.ukui.SettingsDaemon.plugins.auto-brightness.gschema.xml \ # $$PWD/org.ukui.SettingsDaemon.plugins.background.gschema.xml \ $$PWD/org.ukui.SettingsDaemon.plugins.clipboard.gschema.xml \ $$PWD/org.ukui.SettingsDaemon.plugins.color.gschema.xml \ $$PWD/org.ukui.SettingsDaemon.plugins.housekeeping.gschema.xml \ $$PWD/org.ukui.SettingsDaemon.plugins.keybindings.gschema.xml \ $$PWD/org.ukui.SettingsDaemon.plugins.keyboard.gschema.xml \ $$PWD/org.ukui.SettingsDaemon.plugins.mpris.gschema.xml \ $$PWD/org.ukui.SettingsDaemon.plugins.mouse.gschema.xml \ $$PWD/org.ukui.SettingsDaemon.plugins.media-keys.gschema.xml \ $$PWD/org.ukui.SettingsDaemon.plugins.sound.gschema.xml \ $$PWD/org.ukui.SettingsDaemon.plugins.sharing.gschema.xml \ $$PWD/org.ukui.SettingsDaemon.plugins.tablet-mode.gschema.xml \ $$PWD/org.ukui.SettingsDaemon.plugins.xinput.gschema.xml \ $$PWD/org.ukui.SettingsDaemon.plugins.xrandr.gschema.xml \ $$PWD/org.ukui.SettingsDaemon.plugins.xrdb.gschema.xml \ $$PWD/org.ukui.SettingsDaemon.plugins.xsettings.gschema.xml \ $$PWD/org.ukui.peripherals-keyboard.gschema.xml \ $$PWD/org.ukui.peripherals-mouse.gschema.xml \ $$PWD/org.ukui.peripherals-touchpad.gschema.xml \ $$PWD/org.ukui.peripherals-touchscreen.gschema.xml \ $$PWD/zh_CN.po \ # desktop ok desktop.path = /etc/xdg/autostart/ desktop.files = $$PWD/ukui-settings-daemon.desktop plugin_info.path = $$[QT_INSTALL_LIBS]/ukui-settings-daemon plugin_info.files = $$PWD/*.ukui-settings-plugin plugin_schema.path = /usr/share/glib-2.0/schemas/ plugin_schema.files = $$PWD/org.ukui.*.gschema.xml # dbus ukui_daemon_dbus.path = /usr/share/dbus-1/services/ ukui_daemon_dbus.files = $$PWD/org.ukui.SettingsDaemon.service zhCN.commands = $$system(msgfmt -o ukui-settings-daemon.mo $$PWD/zh_CN.po) QMAKE_EXTRA_TARGETS += zhCN zh_CN.path = /usr/share/locale/zh_CN/LC_MESSAGES/ zh_CN.files = $$PWD/ukui-settings-daemon.mo INSTALLS += desktop plugin_info plugin_schema ukui_daemon_dbus zh_CN DISTFILES += \ $$PWD/auto-brightness.ukui-settings-plugin \ $$PWD/a11y-settings.ukui-settings-plugin \ $$PWD/a11y-keyboard.ukui-settings-plugin \ $$PWD/background.ukui-settings-plugin \ $$PWD/clipboard.ukui-settings-plugin \ $$PWD/color.ukui-settings-plugin \ $$PWD/housekeeping.ukui-settings-plugin \ $$PWD/media-keys.ukui-settings-plugin \ $$PWD/mouse.ukui-settings-plugin \ $$PWD/mpris.ukui-settings-plugin \ $$PWD/keyboard.ukui-settings-plugin \ $$PWD/keybindings.ukui-settings-plugin \ $$PWD/sound.ukui-settings-plugin \ $$PWD/sharing.ukui-settings-plugin \ $$PWD/tablet-mode.ukui-settings-plugin \ $$PWD/xrdb.ukui-settings-plugin \ $$PWD/xrandr.ukui-settings-plugin \ $$PWD/xsettings.ukui-settings-plugin \ $$PWD/xinput.ukui-settings-plugin ukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.background.gschema.xml0000644000175000017500000000121214205117202027065 0ustar fengfeng true Activation of this plugin Whether this plugin would be activated by ukui-settings-daemon or not 5 Priority to use for this plugin Priority to use for this plugin in ukui-settings-daemon startup queue ukui-settings-daemon/data/org.ukui.font-rendering.gschema.xml0000644000175000017500000000473514205117202023301 0ustar fengfeng 96.0 DPI The resolution used for converting font sizes to pixel sizes, in dots per inch. 2160 screen height Get the height before the first screen switch. 0 screen height Get the height before the second screen switch. 'rgba' Antialiasing The type of antialiasing to use when rendering fonts. Possible values are: "none" for no antialiasing, "grayscale" for standard grayscale antialiasing, and "rgba" for subpixel antialiasing (LCD screens only). 'slight' Hinting The type of hinting to use when rendering fonts. Possible values are: "none" for no hinting, "slight" for basic, "medium" for moderate, and "full" for maximum hinting (may cause distortion of letter forms). 'rgb' RGBA order The order of subpixel elements on an LCD screen; only used when antialiasing is set to "rgba". Possible values are: "rgb" for red on left (most common), "bgr" for blue on left, "vrgb" for red on top, "vbgr" for red on bottom. ukui-settings-daemon/data/org.ukui.SettingsDaemon.plugins.clipboard.gschema.xml0000644000175000017500000000121114205117202026704 0ustar fengfeng true Activation of this plugin Whether this plugin would be activated by ukui-settings-daemon or not 16 Priority to use for this plugin Priority to use for this plugin in ukui-settings-daemon startup queue ukui-settings-daemon/data/a11y-keyboard.ukui-settings-plugin0000644000175000017500000001733214205117202023065 0ustar fengfeng[UKUI Settings Plugin] Module=a11y-keyboard IAge=0 Name=Accessibility Keyboard Name[af]=Toeganklikheidsleutelbord Name[am]=የ ፊደል ገበታ ጋር መድረሻ Name[ar]=إتاحة لوحة المفاتيح Name[as]=সহায়ক প্ৰযুক্তি বিশিষ্ট চাবিৰ ফলক Name[ast]=Accesibilidá del tecláu Name[be]=Даступная клавіятура Name[bg]=Достъпност на клавиатурата Name[bn]=সহায়ক প্রযুক্তি বিশিষ্ট কী-বোর্ড Name[bn_IN]=সহায়ক প্রযুক্তি বিশিষ্ট কি-বোর্ড Name[ca]=Teclat accessible Name[ca@valencia]=Teclat accessible Name[cmn]=鍵盤可存取性 Name[crh]=Erişilebilirlik Klavyesi Name[cs]=Zpřístupnění klávesnice Name[da]=Tilgængelighedstastatur Name[de]=Barrierefreie Tastatur Name[el]=Προσιτότητα πληκτρολογίου Name[en_AU]=Accessibility Keyboard Name[en_GB]=Accessibility Keyboard Name[es]=Accesibilidad del teclado Name[et]=Hõlbustustega klaviatuur Name[eu]=Teklatuaren erabilerraztasuna Name[fi]=Näppäimistön esteettömyys Name[fr]=Accessibilité du clavier Name[ga]=Mearchlár Inrochtaineachta Name[gl]=Accesibilidade do teclado Name[gu]=સુલભતા કિબોર્ડ Name[he]=מקלדת נגישות Name[hi]=पहुंच कुंजीपट Name[hu]=Billentyűzet akadálymentesítése Name[hy]=Մատչելի Ստեղնաշար Name[id]=Papan Tik Aksesibilitas Name[is]=Lyklaborð fyrir altækt aðgengi Name[it]=Accessibilità tastiera Name[ja]=アクセシビリティ・キーボード Name[kn]=ನಿಲುಕಣಾ ಕೀಲಿಮಣೆ Name[ko]=접근성 키보드 Name[lt]=Klaviatūros pritaikymas neįgaliesiems Name[lv]=Pieejamības tastatūra Name[mk]=Тастатура за пристапност Name[ml]=സാമീപ്യത കീബോര്‍ഡ് Name[mr]=प्रवेशीय कळफलक Name[ms]=Papan Kekunci Kebolehcapaian Name[nb]=Tastatur for tilgjengelighet Name[nl]=Toetsenbord-toegankelijkheid Name[nn]=Tastatur for tilgjenge Name[or]=ଅଭିଗମ୍ଯତା କିବୋର୍ଡ Name[pa]=ਅਸੈੱਸਬਿਲਟੀ ਕੀਬੋਰਡ Name[pl]=Dostępność klawiatury Name[pt]=Teclado de Acessbilidade Name[pt_BR]=Acessibilidade do teclado Name[ro]=Accesibilitate tastatură Name[ru]=Вспомогательные технологии клавиатуры Name[sk]=Prístupnosť klávesnice Name[sl]=Tipkovnica za dostopnost Name[sr]=Приступачност тастатуре Name[sr@latin]=Pristupačnost tastature Name[sv]=Hjälpmedelstangentbord Name[ta]=விசைப்பலகை அணுகல் Name[te]=అందుబాటు కీబోర్డు Name[th]=สิ่งอำนวยความสะดวกสำหรับแป้นพิมพ์ Name[tr]=Erişilebilirlik Klavyesi Name[uk]=Технології доступности Name[ur]=رسائی پذیری کیبورڈ Name[vi]=Bàn phím khả năng truy cập Name[zh_CN]=辅助功能键盘 Name[zh_HK]=鍵盤可存取性 Name[zh_TW]=鍵盤可存取性 Description=Accessibility keyboard plugin Description[af]=Inprop vir toeganklikheidsleutelbord Description[am]=የ ፊደል ገበታ ተሰኪ ጋር መድረሻ Description[ar]=ملحق إتاحة لوحة المفاتيح Description[as]=সহায়ক প্ৰযুক্তি বিশিষ্ট চাবিৰ ফলকৰ প্লাগ-ইন Description[ast]=Complementu d'accesibilidá del tecláu Description[be]=Плагін даступнай клавіятуры Description[bg]=Приставка за достъпност на клавиатурата Description[bn]=সহায়ক প্রযুক্তি বিশিষ্ট কী-বোর্ডের প্লাগ-ইন Description[bn_IN]=সহায়ক প্রযুক্তি বিশিষ্ট কি-বোর্ডের প্লাগ-ইন Description[ca]=Connector de l'accessibilitat de teclat Description[ca@valencia]=Connector de l'accessibilitat de teclat Description[cmn]=鍵盤可存取性引掛程式 Description[crh]=Erişilebilirlik klavyesi eklentisi Description[cs]=Zásuvný modul zpřístupnění klávesnice Description[da]=Tastaturtilgængelighedsmodul Description[de]=Modul für barrierefreie Tastatur Description[el]=Πρόσθετη λειτουργία προσιτότητας πληκτρολογίου Description[en_AU]=Accessibility keyboard plugin Description[en_GB]=Accessibility keyboard plugin Description[es]=Complemento de accesibilidad del teclado Description[et]=Hõlbustustega klaviatuuri plugin Description[eu]=Teklatuaren erabilerraztasunaren plugina Description[fi]=Näppäimistön esteettömyysliitännäinen Description[fr]=Greffon de l'accessibilité du clavier Description[ga]=Breiseán an mhéarchlár inrochtaineachta Description[gl]=Engadido de accesibilidade do teclado Description[gu]=સુલભતા કિબોર્ડ પ્લગઇન Description[he]=תוסף מקלדת נגישות Description[hi]=पहुंच कुंजीपट प्लगिन Description[hu]=Billentyűzet akadálymentesítése bővítmény Description[hy]=Ստեղնաշարի հասանելի կոնտակտներ Description[id]=Plugin papan tik aksesibilitas Description[is]=Viðbót fyrir lyklaborð með altækt aðgengi Description[it]=Plugin per l'accesso universale alla tastiera Description[ja]=アクセシビリティ・キーボードのプラグイン Description[kn]=ನಿಲುಕಣಾ ಕೀಲಿಮಣೆ ಪ್ಲಗ್ಇನ್ Description[ko]=접근성 키보드 플러그인 Description[lt]=Klaviatūros pritaikymo neįgaliesiems įskiepis Description[lv]=Pieejamības tastatūras spraudnis Description[mk]=Додаток за пристапност на тастатурата Description[ml]=സാമീപ്യത കീബോര്‍ഡ് സമ്യോജകം Description[mr]=प्रवेशीय कळफलक प्लगइन Description[ms]=Pemalam papan kekunci kebolehcapaian Description[nb]=Tillegg for tastatur for tilgjengelighet Description[nl]=Toetsenbord-toegankelijkheid-plugin Description[nn]=Tillegg for tastatur for tilgjenge Description[or]=ଅଭିଗମ୍ୟତା କିବୋର୍ଡ ପ୍ଲଗଇନ Description[pa]=ਅਸੈੱਸਬਿਲਟੀ ਕੀਬੋਰਡ ਪਲੱਗਇਨ Description[pl]=Wtyczka dostępności klawiatury Description[pt]=Suplemento do teclado de acessibilidade Description[pt_BR]=Plug-in de acessibilidade do teclado Description[ro]=Modul accesibilitate tastatură Description[ru]=Модуль вспомогательных технологий клавиатуры Description[sk]=Modul prístupnosti klávesnice Description[sl]=Vstavek tipkovnice dostopnosti Description[sr]=Додатак за приступачност тастатуре Description[sr@latin]=Dodatak za pristupačnost tastature Description[sv]=Insticksmodul för hjälpmedelstangentbord Description[ta]=விசைப்பலகை அணுகல் சொருகி Description[te]=అందుబాటు కీబోర్డు ప్లగ్ఇన్ Description[th]=ปลั๊กอินจัดการสิ่งอำนวยความสะดวกสำหรับแป้นพิมพ์ Description[tr]=Erişilebilirlik klavyesi eklentisi Description[uk]=Втулка технологій доступности набірниці Description[ur]=رسائی پذیری کیبورڈ دخیلہ Description[vi]=Phần mở rộng bàn phím khả năng truy cập Description[zh_CN]=辅助功能键盘插件 Description[zh_HK]=鍵盤可存取性引掛程式 Description[zh_TW]=鍵盤可存取性引掛程式 Authors=Jody Goldberg Copyright=Copyright © 2001 Ximian, Inc. Website= ukui-settings-daemon/data/mouse.ukui-settings-plugin0000644000175000017500000001104514205117202021637 0ustar fengfeng[UKUI Settings Plugin] Module=mouse IAge=0 Name=Mouse Name[af]=Muis Name[am]=አይጥ Name[ar]=الفأرة Name[as]=মাউছ Name[ast]=Mur Name[az]=Siçan Name[be]=Мыш Name[bg]=Мишка Name[bn]=মাউস Name[bn_IN]=মাউস Name[br]=Logodenn Name[bs]=Miš Name[ca]=Ratolí Name[ca@valencia]=Ratolí Name[cmn]=滑鼠 Name[crh]=Fare Name[cs]=Myš Name[cy]=Llygoden Name[da]=Mus Name[de]=Maus Name[dz]=མཱའུསི། Name[el]=Ποντίκι Name[en_AU]=Mouse Name[en_CA]=Mouse Name[en_GB]=Mouse Name[es]=Ratón Name[et]=Hiir Name[eu]=Sagua Name[fa]=موشی Name[fi]=Hiiri Name[fr]=Souris Name[ga]=Luch Name[gl]=Rato Name[gu]=માઉસ Name[he]=עכבר Name[hi]=माउस Name[hr]=Miš Name[hu]=Egér Name[hy]=Մկնիկ Name[id]=Mouse Name[is]=Mús Name[it]=Mouse Name[ja]=マウス Name[ka]=თაგვი Name[kk]=Тышқан Name[kn]=ಮೌಸ್ Name[ko]=마우스 Name[ku]=Mişk Name[ky]=Чычкан Name[lt]=Pelė Name[lv]=Pele Name[mai]=माउस Name[mg]=Totozy Name[mk]=Глушец Name[ml]=മൌസ് Name[mn]=Хулгана Name[mr]=माउस Name[ms]=Tetikus Name[nb]=Mus Name[nds]=Muus Name[ne]=माउस Name[nl]=Muis Name[nn]=Mus Name[nso]=Legotlwana Name[oc]=Mirga Name[or]=ମାଉସ Name[pa]=ਮਾਊਸ Name[pl]=Mysz Name[pt]=Rato Name[pt_BR]=Mouse Name[ro]=Maus Name[ru]=Мышь Name[rw]=Imbeba Name[sk]=Myš Name[sl]=Miška Name[sq]=Miu Name[sr]=Миш Name[sr@latin]=Miš Name[sv]=Mus Name[ta]=சுட்டி Name[te]=మౌస్ Name[th]=เมาส์ Name[tr]=Fare Name[uk]=Миша Name[ur]=ماؤس Name[uz]=Sichqoncha Name[vi]=Chuột Name[wa]=Sori Name[xh]=Imawusi Name[zh_CN]=鼠标 Name[zh_HK]=滑鼠 Name[zh_TW]=滑鼠 Name[zu]=Isingoso Description=Mouse plugin Description[af]=Inprop vir die muis Description[am]=የ አይጥ ተሰኪ Description[ar]=ملحق الفأرة Description[as]=মাউছ প্লাগ-ইন Description[ast]=Complementu del mur Description[be]=Плагін мышы Description[bg]=Приставка за мишката Description[bn]=মাউস প্লাগ-ইন Description[bn_IN]=মাউজ প্লাগ-ইন Description[br]=Enlugellad al logodenn Description[ca]=Connector del ratolí Description[ca@valencia]=Connector del ratolí Description[cmn]=滑鼠外掛程式 Description[crh]=Fare eklentisi Description[cs]=Zásuvný modul myši Description[da]=Musemodul Description[de]=Mausmodul Description[el]=Πρόσθετη λειτουργία ποντικιού Description[en_AU]=Mouse plugin Description[en_GB]=Mouse plugin Description[es]=Complemento del ratón Description[et]=Hiireplugin Description[eu]=Saguaren plugina Description[fi]=Hiiriliitännäinen Description[fr]=Greffon de la souris Description[ga]=Breiseán na luiche Description[gl]=Engadido do rato Description[gu]=માઉસ પ્લગઇન Description[he]=תוסף עכבר Description[hi]=माउस प्लगिन Description[hr]=Priključak miša Description[hu]=Egér bővítmény Description[hy]=Մկնիկի կոնտակտներ Description[id]=Plugin tetikus Description[is]=Músarviðbót Description[it]=Plugin per il mouse Description[ja]=マウスのプラグイン Description[kk]=Тышқан плагині Description[kn]=ಮೌಸ್ ಪ್ಲಗ್‌ಇನ್ Description[ko]=마우스 플러그인 Description[lt]=Pelės įskiepis Description[lv]=Peles spraudnis Description[mk]=Додаток за глушец Description[ml]=മൌസ് സംയോജകം Description[mr]=माऊस प्लगइन Description[ms]=Pemalam tetikus Description[nb]=Tillegg for mus Description[nds]=Muusplugin Description[nl]=Muis-plugin Description[nn]=Tillegg for mus Description[or]=ମାଉସ ପ୍ଲଗଇନ Description[pa]=ਮਾਊਂਸ ਪਲੱਗਇਨ Description[pl]=Wtyczka myszy Description[pt]=Suplemento do rato Description[pt_BR]=Plug-in de mouse Description[ro]=Modul maus Description[ru]=Модуль мыши Description[sk]=Modul myši Description[sl]=Vstavek miške Description[sr]=Додатак миша Description[sr@latin]=Dodatak za miša Description[sv]=Insticksmodul för mus Description[ta]=சொடுக்கி சொருகி Description[te]=మౌస్ ప్లగ్ఇన్ Description[th]=ปลั๊กอินจัดการเมาส์ Description[tr]=Fare eklentisi Description[uk]=Втулка миші Description[ur]=ماؤس دخیلہ Description[vi]=Phần mở rộng chuột Description[zh_CN]=鼠标插件 Description[zh_HK]=滑鼠外掛程式 Description[zh_TW]=滑鼠外掛程式 Authors= Copyright=Copyright © 2007 Website= ukui-settings-daemon/data/org.ukui.peripherals-keyboard.gschema.xml0000644000175000017500000000353314205117202024467 0ustar fengfeng true true 30 500 0 'on' possible values are "on", "off", and "custom". 400 100 '' Keyboard Bell Custom Filename File name of the bell sound to be played. true Remember NumLock state When set to true, UKUI will remember the state of the NumLock LED between sessions. false CapsLock state 'on' NumLock state The remembered state of the NumLock LED. ukui-settings-daemon/daemon/0000755000175000017500000000000014205117202015007 5ustar fengfengukui-settings-daemon/daemon/.gitignore0000644000175000017500000000002514205117202016774 0ustar fengfengukui-settings-daemon ukui-settings-daemon/daemon/plugin-manager.cpp0000644000175000017500000001423614205117202020427 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "plugin-manager.h" #include #include "global.h" #include "clib-syslog.h" #include "plugin-info.h" #include #include #include #include #include #include #include #include #include #include #include #include QList* PluginManager::mPlugin = nullptr; PluginManager* PluginManager::mPluginManager = nullptr; static bool is_schema (QString& schema); static bool register_manager(PluginManager& pm); bool sortPluginByPriority(PluginInfo* a,PluginInfo* b); PluginManager::PluginManager() { if (nullptr == mPlugin) mPlugin = new QList(); } PluginManager::~PluginManager() { //managerStop(); //delete mPlugin; //mPlugin = nullptr; } PluginManager* PluginManager::getInstance() { if (nullptr == mPluginManager) { USD_LOG(LOG_DEBUG, "ukui settings manager will be created!") mPluginManager = new PluginManager; if (!register_manager(*mPluginManager)) { USD_LOG(LOG_ERR, "register manager failed!"); return nullptr; } } return mPluginManager; } bool PluginManager::managerStart() { GDir* dir = NULL; QString schema; GError* error = NULL; const char* name = NULL; qDebug("Starting settings manager"); QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation); QString libpath = qApp->libraryPaths().at(0); QString path = libpath.mid(0,libpath.lastIndexOf('/')-4)+"/ukui-settings-daemon"; dir = g_dir_open ((char*)path.toUtf8().data(), 0, &error); if (NULL == dir) { USD_LOG(LOG_ERR, "%s", error->message); g_error_free(error); error = nullptr; return false; } while ((name = g_dir_read_name(dir))) { char* filename = NULL; if (!g_str_has_suffix(name, PLUGIN_EXT)) { continue; } filename = g_build_filename((char*)path.toUtf8().data(), name, NULL); if (g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { QString ftmp(filename); PluginInfo* info = new PluginInfo(ftmp); if (info == NULL) { continue; } if (mPlugin->contains(info)) { USD_LOG(LOG_DEBUG, "The list has contain this plugin, '%s'", ftmp.toUtf8().data()); if (info != NULL) delete info; } // check plugin's schema schema = QString("%1.plugins.%2").arg(DEFAULT_SETTINGS_PREFIX).arg(info->getPluginLocation().toUtf8().data()); if (is_schema (schema)) { USD_LOG(LOG_DEBUG, "right schema '%s'", schema.toUtf8().data()); info->setPluginSchema(schema); mPlugin->insert(0, info); } else { USD_LOG(LOG_ERR, "Ignoring unknown schema '%s'", schema.toUtf8().data()); if (info != NULL) delete info; } } g_free(filename); } g_dir_close(dir); //sort plugin qSort(mPlugin->begin(),mPlugin->end(),sortPluginByPriority); USD_LOG(LOG_DEBUG, "Now Activity plugins ..."); for (int i = 0; i < mPlugin->size(); ++i) { PluginInfo* info = mPlugin->at(i); USD_LOG(LOG_DEBUG, "start activity plugin: %s ...", info->getPluginName().toUtf8().data()); info->pluginActivate(); } USD_LOG(LOG_DEBUG, "All plugins has been activited!"); return true; } void PluginManager::managerStop() { USD_LOG(LOG_DEBUG, "Stopping settings manager"); while (!mPlugin->isEmpty()) { PluginInfo* plugin = mPlugin->takeFirst(); USD_LOG(LOG_DEBUG, "start Daectivity plugin: %s ...", plugin->getPluginName().toUtf8().data()); plugin->pluginDeactivate(); USD_LOG(LOG_DEBUG, "Daectivity plugin: %s ...ok", plugin->getPluginName().toUtf8().data()); //delete plugin; } USD_LOG(LOG_DEBUG,"Daectivity all plugin over.."); // exit main event loop QApplication::exit(0); } bool PluginManager::managerAwake() { USD_LOG(LOG_DEBUG, "Awake called") return managerStart(); } static bool is_item_in_schema (const gchar* const* items, QString& item) { while (*items) { if (g_strcmp0 (*items++, item.toLatin1().data()) == 0) { return true; } } return false; } bool is_schema (QString& schema) { return is_item_in_schema (g_settings_list_schemas(), schema); } static bool register_manager(PluginManager& pm) { QString ukuiDaemonBusName = UKUI_SETTINGS_DAEMON_DBUS_NAME; if (QDBusConnection::sessionBus().interface()->isServiceRegistered(ukuiDaemonBusName)) { return false; } QDBusConnection bus = QDBusConnection::sessionBus(); if (!bus.registerService(UKUI_SETTINGS_DAEMON_DBUS_NAME)) { USD_LOG(LOG_ERR, "error getting system bus: '%s'", bus.lastError().message().toUtf8().data()); return false; } if (!bus.registerObject(UKUI_SETTINGS_DAEMON_DBUS_PATH, (QObject*)&pm, QDBusConnection::ExportAllSlots)) { USD_LOG(LOG_ERR, "regist settings manager error: '%s'", bus.lastError().message().toUtf8().data()); return false; } USD_LOG(LOG_DEBUG, "regist settings manager successful!"); return true; } bool sortPluginByPriority(PluginInfo* a,PluginInfo* b) { return a->getPluginPriority() < b->getPluginPriority(); } ukui-settings-daemon/daemon/plugin-info.h0000644000175000017500000000446114205117202017414 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef PluginInfo_H #define PluginInfo_H #include "plugin-interface.h" #include #include #include #include #include namespace UkuiSettingsDaemon { class PluginInfo; } class PluginInfo : public QObject { Q_OBJECT public: explicit PluginInfo()=delete; PluginInfo(QString& fileName); ~PluginInfo(); bool pluginEnabled (); bool pluginActivate (); bool pluginDeactivate (); bool pluginIsactivate (); bool pluginIsAvailable (); int getPluginPriority (); QString& getPluginName (); QString& getPluginWebsite (); QString& getPluginLocation (); QString& getPluginCopyright (); QString& getPluginDescription (); QList& getPluginAuthors (); void setPluginPriority (int priority); void setPluginSchema (QString& schema); bool operator== (PluginInfo&); public Q_SLOTS: void pluginSchemaSlot (QString key); private: friend bool loadPluginModule(PluginInfo&); private: int mPriority; bool mActive; bool mEnabled; bool mAvailable; QString mFile; QString mName; QString mDesc; QString mWebsite; QString mLocation; QString mCopyright; QGSettings* mSettings; QLibrary* mModule; PluginInterface* mPlugin; QList* mAuthors; }; #endif // PluginInfo_H ukui-settings-daemon/daemon/plugin-info.cpp0000644000175000017500000002134714205117202017751 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "plugin-info.h" #include "global.h" #include "clib-syslog.h" #include #include PluginInfo::PluginInfo(QString& fileName) { int priority; char* str = NULL; GError* error = NULL; GKeyFile* pluginFile = NULL; mPriority = 0; mActive = false; mEnabled = true; mPlugin = nullptr; mModule = nullptr; mAvailable = true; mSettings = nullptr; QByteArray* bt = new QByteArray(fileName.toUtf8().data()); mFile = *bt; pluginFile = g_key_file_new(); if (!g_key_file_load_from_file(pluginFile, (char*)fileName.toUtf8().data(), G_KEY_FILE_NONE, &error)) { USD_LOG(LOG_ERR, "Bad plugin file:'%s', error:'%s'", fileName.toUtf8().data(), error->message); g_object_unref(error); error = nullptr; g_object_unref(pluginFile); return; } if (!g_key_file_has_key(pluginFile, PLUGIN_GROUP, "IAge", &error)) { USD_LOG(LOG_ERR, "IAge key does not exist in file: %s, error: '%s'", fileName.toUtf8().data(), error->message); g_object_unref(error); error = nullptr; } /* Check IAge=2 */ if (g_key_file_get_integer (pluginFile, PLUGIN_GROUP, "IAge", &error) != 0) { USD_LOG(LOG_ERR, "Wrong IAge in file: %s, error: '%s'", fileName.toUtf8().data(), error->message); g_object_unref(error); error = nullptr; } /* Get Location */ str = g_key_file_get_string (pluginFile, PLUGIN_GROUP, "Module", &error); if ((str != NULL) && (*str != '\0')) { mLocation = str; } else { g_free (str); USD_LOG(LOG_ERR, "Could not find 'Module' in %s, error: '%s'", fileName.toUtf8().data(), error->message); g_object_unref(error); error = nullptr; } /* Get Name */ str = g_key_file_get_locale_string (pluginFile, PLUGIN_GROUP, "Name", NULL, &error); if (str != NULL) { mName = str; } else { USD_LOG(LOG_ERR, "Could not find %s, error '%s'", fileName.toUtf8().data(), error->message); g_object_unref(error); error = nullptr; } /* Get Description */ str = g_key_file_get_locale_string (pluginFile, PLUGIN_GROUP, "Description", NULL, &error); if (str != NULL) { mDesc = QString(str); } else { USD_LOG(LOG_ERR, "Could not find 'Description' in %s, error: '%s'", fileName.toUtf8().data(), error->message); g_object_unref(error); error = nullptr; } /* Get Authors */ mAuthors = new QList(); char** author = g_key_file_get_string_list (pluginFile, PLUGIN_GROUP, "Authors", NULL, &error); if (nullptr != author) { for (int i = 0; author[i] != NULL; ++i) mAuthors->append(author[i]); } else { USD_LOG(LOG_ERR, "Could not find 'Authors' in %s, error: '%s'", fileName.toUtf8().data(), error->message); g_object_unref(error); error = nullptr; } g_strfreev (author); author = nullptr; /* Get Copyright */ str = g_key_file_get_string (pluginFile, PLUGIN_GROUP, "Copyright", &error); if (str != NULL) { mCopyright = str; } else { USD_LOG(LOG_ERR, "Could not find 'Copyright' in %s, error: '%s'", fileName.toUtf8().data(), error->message); g_object_unref(error); error = nullptr; } /* Get Website */ str = g_key_file_get_string (pluginFile, PLUGIN_GROUP, "Website", &error); if (str != NULL) { mWebsite = str; } else { USD_LOG(LOG_ERR, "Could not find 'Website' in %s, error: '%s'", fileName.toUtf8().data(), error->message); g_object_unref(error); error = nullptr; } /* Get Priority */ priority = g_key_file_get_integer (pluginFile, PLUGIN_GROUP, "Priority", NULL); if (priority >= PLUGIN_PRIORITY_MAX) { this->mPriority = priority; } else { this->mPriority = PLUGIN_PRIORITY_DEFAULT; } if (nullptr != error) g_object_unref(error); if (nullptr != pluginFile) g_key_file_free (pluginFile); } PluginInfo::~PluginInfo() { if (nullptr != mModule) {mModule->unload(); delete mModule; mModule = nullptr;} if (nullptr != mAuthors) {delete mAuthors; mAuthors = nullptr;} if (nullptr != mSettings) {delete mSettings; mSettings = nullptr;} } bool PluginInfo::pluginActivate() { bool res = false; if (!mAvailable) {USD_LOG(LOG_DEBUG, "plugin is not available!") return false;} if (mActive) {USD_LOG(LOG_DEBUG, "plugin has activity!") return true;} // load module if (nullptr == mPlugin) { res = loadPluginModule(*this); } if (res && (nullptr != mPlugin)) { mPlugin->activate(); mActive = true; res = true; } else { res = false; USD_LOG(LOG_ERR, "Error activating plugin '%s'", this->mName.toUtf8().data()); } return res; } bool PluginInfo::pluginDeactivate() { if (!mActive || !mAvailable) { return true; } if (nullptr != mPlugin) { mPlugin->deactivate(); } else { return false; } mActive = false; return true; } bool PluginInfo::pluginIsactivate() { return (mAvailable && mActive); } bool PluginInfo::pluginEnabled() { return (this->mEnabled); } bool PluginInfo::pluginIsAvailable() { return this->mAvailable; } QString& PluginInfo::getPluginName() { return this->mName; } QString& PluginInfo::getPluginDescription() { return this->mDesc; } QList& PluginInfo::getPluginAuthors() { return *mAuthors; } QString& PluginInfo::getPluginWebsite() { return this->mWebsite; } QString& PluginInfo::getPluginCopyright() { return this->mCopyright; } QString& PluginInfo::getPluginLocation() { return this->mLocation; } int PluginInfo::getPluginPriority() { return this->mPriority; } void PluginInfo::setPluginPriority(int priority) { this->mPriority = priority; } // FIXME:// ????? void PluginInfo::setPluginSchema(QString& schema) { int priority; mSettings = new QGSettings(schema.toUtf8()); this->mEnabled = mSettings->get("active").toBool(); priority = mSettings->get("priority").toInt(); if (priority > 0) this->mPriority = priority; if (!connect(mSettings, &QGSettings::changed, this, &PluginInfo::pluginSchemaSlot)) { USD_LOG(LOG_ERR, "plugin setting '%s', connect error!", schema.toUtf8().data()); } } bool PluginInfo::operator==(PluginInfo& oth) { return (0 == QString::compare(mName, oth.getPluginName(), Qt::CaseInsensitive)); } void PluginInfo::pluginSchemaSlot(QString) { // if configure has changed, modify PluginInfo // if configure deactivity plugin, activate() else deactivate() } bool loadPluginModule(PluginInfo& pinfo) { QString path; if (pinfo.mFile.isNull() || pinfo.mFile.isEmpty()) {USD_LOG(LOG_ERR, "Plugin file is error"); return false;} if (pinfo.mLocation.isNull() || pinfo.mLocation.isEmpty()) {USD_LOG(LOG_ERR, "Plugin location is error"); return false;} if (!pinfo.mAvailable) {USD_LOG(LOG_ERR, "Plugin is not available"); return false;} QFile file(pinfo.mFile); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return false; QStringList l = pinfo.mFile.split("/"); l.pop_back(); path = l.join("/") + "/lib" + pinfo.mLocation + ".so"; if (path.isEmpty() || path.isNull()) {USD_LOG(LOG_ERR, "error module path:'%s'", path.toUtf8().data()); return false;} pinfo.mModule = new QLibrary(path); pinfo.mModule->setLoadHints(QLibrary::ResolveAllSymbolsHint | QLibrary::ExportExternalSymbolsHint); if (!(pinfo.mModule->load())) { USD_LOG(LOG_ERR, "create module '%s' error:'%s'", path.toUtf8().data(), pinfo.mModule->errorString().toUtf8().data()); pinfo.mAvailable = false; return false; } typedef PluginInterface* (*createPlugin) (); createPlugin p = (createPlugin)pinfo.mModule->resolve("createSettingsPlugin"); if (!p) { USD_LOG(LOG_ERR, "create module class failed, error: '%s'", pinfo.mModule->errorString().toUtf8().data()); return false; } pinfo.mPlugin = (PluginInterface*)p(); return true; } ukui-settings-daemon/daemon/daemon.pro0000644000175000017500000000214114205117202016772 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-03-16T09:30:00 # #------------------------------------------------- TEMPLATE = app TARGET = ukui-settings-daemon QT += core gui dbus CONFIG += no_keywords link_prl link_pkgconfig c++11 debug CONFIG -= app_bundle DEFINES += MODULE_NAME=\\\"Daemon\\\" greaterThan(QT_MAJOR_VERSION, 4): QT += widgets include($$PWD/../common/common.pri) INCLUDEPATH += \ -I /usr/include/mate-desktop-2.0/ PKGCONFIG += \ glib-2.0\ gio-2.0\ gobject-2.0\ gmodule-2.0 \ dconf SOURCES += \ $$PWD/main.cpp\ $$PWD/plugin-info.cpp\ $$PWD/plugin-manager.cpp\ $$PWD/manager-interface.cpp HEADERS += \ $$PWD/plugin-info.h\ $$PWD/plugin-manager.h\ $$PWD/manager-interface.h \ $$PWD/global.h ukui_daemon.path = /usr/bin/ ukui_daemon.files = $$OUT_PWD/ukui-settings-daemon zh_CN.path = /usr/share/ukui-settings-daemon/daemon/res/i18n/ zh_CN.files = $$PWD/res/i18n/zh_CN.qm INSTALLS += ukui_daemon zh_CN RESOURCES += \ $$PWD/res/zh_CN.qrc ukui-settings-daemon/daemon/manager-interface.h0000644000175000017500000000463214205117202020535 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MANAGER_INTERFACE_H #define MANAGER_INTERFACE_H #include "plugin-manager.h" #include #include #include #include #include #include #include #include namespace UkuiSettingsDaemon { class PluginManagerDBus; } /* * Proxy class for interface org.ukui.SettingsDaemon */ class PluginManagerDBus: public QDBusAbstractInterface { Q_OBJECT public: static inline const char *staticInterfaceName() { return "org.ukui.SettingsDaemon"; } public: PluginManagerDBus(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr); ~PluginManagerDBus(); public Q_SLOTS: inline QDBusPendingReply managerAwake() { QList argumentList; return asyncCallWithArgumentList(QStringLiteral("managerAwake"), argumentList); } inline QDBusPendingReply managerStart() { QList argumentList; return asyncCallWithArgumentList(QStringLiteral("managerStart"), argumentList); } inline QDBusPendingReply<> managerStop() { QList argumentList; return asyncCallWithArgumentList(QStringLiteral("managerStop"), argumentList); } inline QDBusPendingReply onPluginActivated() { QList argumentList; return asyncCallWithArgumentList(QStringLiteral("onPluginActivated"), argumentList); } inline QDBusPendingReply onPluginDeactivated() { QList argumentList; return asyncCallWithArgumentList(QStringLiteral("onPluginDeactivated"), argumentList); } }; #endif ukui-settings-daemon/daemon/global.h0000644000175000017500000000307714205117202016427 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GLOBAL_H #define GLOBAL_H #include "clib-syslog.h" #define PLUGIN_PRIORITY_MAX 1 #define PLUGIN_PRIORITY_DEFAULT 100 #define PLUGIN_GROUP "UKUI Settings Plugin" #define UKUI_SETTINGS_DAEMON_DBUS_NAME "org.ukui.SettingsDaemon" #define UKUI_SETTINGS_DAEMON_DBUS_PATH "/daemon/registry" #define UKUI_SETTINGS_DAEMON_MANAGER_DBUS_PATH "/org/ukui/SettingsDaemon" #define USD_MANAGER_DBUS_PATH "/org/ukui/SettingsDaemon" #define DEFAULT_SETTINGS_PREFIX "org.ukui.SettingsDaemon" #define PLUGIN_EXT ".ukui-settings-plugin" #define UKUI_SETTINGS_PLUGINDIR "/usr/lib/ukui-settings-daemon" // plugin dir #endif // GLOBAL_H ukui-settings-daemon/daemon/res/0000755000175000017500000000000014205117202015600 5ustar fengfengukui-settings-daemon/daemon/res/i18n/0000755000175000017500000000000014205117202016357 5ustar fengfengukui-settings-daemon/daemon/res/i18n/zh_CN.ts0000644000175000017500000004602214205117202017734 0ustar fengfeng A11yKeyboardManager There was an error displaying help 显示帮助时出错 Do you want to activate Slow Keys? 您想激活慢速键吗? Do you want to deactivate Slow Keys? 您想要停用慢速键吗? You just held down the Shift key for 8 seconds. This is the shortcut for the Slow Keys feature, which affects the way your keyboard works. 您只是按下 Shift 键8秒。这是慢速键功能的快捷方式,它会影响键盘的工作方式。 Slow Keys Alert 慢速键警告 Do_n't activate 不要激活 Do_n't deactivate 不要关闭 _Activate 激活 _Deactivate 关闭 input-keyboard 输入键盘 Do you want to activate Sticky Keys? 您想激活粘滞键吗? Do you want to deactivate Sticky Keys? 您想关闭粘滞键吗? You just pressed the Shift key 5 times in a row. This is the shortcut for the Sticky Keys feature, which affects the way your keyboard works. 您只是连续按了5次 Shift 键。这是慢速键特性的快捷方式,它会影响键盘的工作方式。 You just pressed two keys at once, or pressed the Shift key 5 times in a row. This turns off the Sticky Keys feature, which affects the way your keyboard works. 您只需同时按两个键,或者连续按5次 Shift 键。这将关闭影响键盘工作方式的粘滞键功能。 Sticky Keys Alert 粘滞键警报 A11yPreferencesDialog Form 形成 Use on-screen _keyboard 使用屏幕键盘 Use screen _reader 使用屏幕阅读器 使用屏幕阅读器 Use screen _magnifier 使用屏幕放大镜 Enhance _contrast in colors 增强色彩对比度 Make _text larger and easier to read 使文字更大且更易于阅读 Press keyboard shortcuts one key at a time (Sticky Keys) 一次按下键盘快速键(Sticky 键) Ignore duplicate keypresses (Bounce Keys) 忽略重复的按键 (Bounce 键) Press and _hold keys to accept them (Slow Keys) 按住键以接受它们 (Slow 键) close 关闭 DeviceWindow DeviceWindow 设备窗口 KeyboardWidget Form 形成 LdsmDialog LdsmDialog 对话框 Low Disk Space 磁盘空间小 Ignore 忽视 Empty Trash 清空回收站 Examine 检查 The volume "%1" has only %s disk space remaining. 卷 "%1" 仅剩余 %s 硬盘空间。 The computer has only %s disk space remaining. 本计算机仅剩余 %s 硬盘空间。 You can free up disk space by emptying the Trash, removing unused programs or files, or moving files to another disk or partition. 您可以通过清空垃圾箱,删除未使用的程序或文件或将文件移动到另一个磁盘或分区来释放磁盘空间。 You can free up disk space by removing unused programs or files, or by moving files to another disk or partition. 您可以通过删除未使用的程序或文件或将文件移动到另一个磁盘或分区来释放磁盘空间。 You can free up disk space by emptying the Trash, removing unused programs or files, or moving files to an external disk. 您可以通过清空垃圾箱,删除未使用的程序或文件或将文件移动到外部磁盘来释放磁盘空间。 You can free up disk space by removing unused programs or files, or by moving files to an external disk. 您可以通过删除未使用的程序或文件或将文件移动到外部磁盘来释放磁盘空间。 Don't show any warnings again for this file system 不再为此文件系统显示任何警告 Don't show any warnings again 不要再显示任何警告 LdsmTrashEmpty Dialog 对话框 Emptying the trash 清空回收站 Empty all of the items from the trash? 删除回收站里的所有项目? If you choose to empty the trash, all items in it will be permanently lost.Please note that you can also delete them separately. 如果您选择清空回收站,里面所有的项目都将永久丢失。请注意您也可以分别删除这些项目。 cancel 取消 Empty Trash 清空回收站 QObject Error while trying to run "%1"; which is linked to the key "%2" 试图运行"%1"时出错; 链接到键"%2" Error while trying to run "%1"; which is linked to the key "%2" 尝试运行"%1"时出错; 链接到快捷键"%2" Shortcut message box 快捷键消息弹框 Yes 确定 Error activating XKB configuration. It can happen under various circumstances: • a bug in libxklavier library • a bug in X server (xkbcomp, xmodmap utilities) • X server with incompatible libxkbfile implementation X server version data: %1 %2 If you report this situation as a bug, please include: • The result of <b> xprop -root | grep XKB </b> • The result of <b> gsettings list-keys org.mate.peripherals-keyboard-xkb.kbd </b> 激活 XKB 配置时出错。 它可能在各种情况下发生: libxklavier 库中的错误 X服务器中的错误 (xkbcomp, xmodmap 实用程序) 具有不兼容的 libxkbfile 实现的 X 服务器 X服务器版本数据: %1 %2 如果您将此情况报告为错误,请包括: •<b> xprop -root | grep XKB </ b> 的结果 •<b> gsettings 列表键 org.mate.peripherals-keyboard-xkb.kbd 的结果 </ b> Close 关闭 Error 错误 Do you want to activate Slow Keys? 您想激活慢速键吗? Do you want to deactivate Slow Keys? 您想要停用慢速键吗? You just held down the Shift key for 8 seconds. This is the shortcut for the Slow Keys feature, which affects the way your keyboard works. 您只是按下 Shift 键8秒。这是慢速键功能的快捷方式,它会影响键盘的工作方式。 Do you want to activate Sticky Keys? 您想激活粘滞键吗? Do you want to deactivate Sticky Keys? 您想关闭粘滞键吗? You just pressed the Shift key 5 times in a row. This is the shortcut for the Sticky Keys feature, which affects the way your keyboard works. 您只是连续按了5次 Shift 键。这是粘滞键特性的快捷方式,它会影响键盘的工作方式。 You just pressed two keys at once, or pressed the Shift key 5 times in a row. This turns off the Sticky Keys feature, which affects the way your keyboard works. 您只需同时按两个键,或者连续按5次 Shift 键。这将关闭影响键盘工作方式的粘滞键功能。 The system detects that the HD device has been replaced.Do you need to switch to the recommended zoom (100%)? Click on the confirmation logout. 系统检测到高清设备已被更换。您是否需要切换到建议的缩放比例(100%)?点击确认后会注销生效。 Scale tips 缩放提示 Confirmation 确认 Cancel 取消 Does the system detect high clear equipment and whether to switch to recommended scaling (200%)? Click on the confirmation logout. 系统检测到高清设备,您是否切换到建议的缩放(200%)?点击确认后会注销生效。 VolumeWindow VolumeWindow 音量窗口 ukui-settings-daemon/daemon/res/zh_CN.qrc0000644000175000017500000000013414205117202017306 0ustar fengfeng i18n/zh_CN.qm ukui-settings-daemon/daemon/manager-interface.cpp0000644000175000017500000000143614205117202021067 0ustar fengfeng/* * This file was generated by qdbusxml2cpp version 0.8 * Command line was: qdbusxml2cpp ukui-settings-daemon.xml -i plugin-manager.h -p manager-interface * * qdbusxml2cpp is Copyright (C) 2019 The Qt Company Ltd. * * This is an auto-generated file. * This file may have been hand-edited. Look for HAND-EDIT comments * before re-generating it. */ #include "manager-interface.h" #include "clib-syslog.h" /* * Implementation of interface class OrgUkuiSettingsDaemonInterface */ PluginManagerDBus::PluginManagerDBus(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) { } PluginManagerDBus::~PluginManagerDBus() { // USD_LOG(LOG_DEBUG,"exit...."); } ukui-settings-daemon/daemon/plugin-manager.h0000644000175000017500000000310314205117202020063 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef PLUGIN_MANAGER_H #define PLUGIN_MANAGER_H #include "global.h" #include "plugin-info.h" #include #include #include #include #include namespace UkuiSettingsDaemon { class PluginManager; } class PluginManager : QObject { Q_OBJECT Q_CLASSINFO ("D-Bus Interface", UKUI_SETTINGS_DAEMON_DBUS_NAME) public: ~PluginManager(); static PluginManager* getInstance(); private: PluginManager(); PluginManager(PluginManager&)=delete; PluginManager& operator= (const PluginManager&)=delete; Q_SIGNALS: void exit (); public Q_SLOTS: void managerStop (); bool managerStart (); bool managerAwake (); private: static QList* mPlugin; static PluginManager* mPluginManager; }; #endif // PLUGIN_MANAGER_H ukui-settings-daemon/daemon/ukui-settings-daemon.xml0000644000175000017500000000112214205117202021601 0ustar fengfeng ukui-settings-daemon/daemon/main.cpp0000644000175000017500000001026114205117202016437 0ustar fengfeng/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- * -*- coding: utf-8 -*- * * Copyright (C) 2020 KylinSoft 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include //#include #include "clib-syslog.h" #include "plugin-manager.h" #include "manager-interface.h" #include #include #include #include #include #include #include static void print_help (); static void parse_args (int argc, char *argv[]); static void stop_daemon (); static bool no_daemon = true; static bool replace = false; PluginManager* manager = nullptr; void handler(int no) { USD_LOG(LOG_DEBUG,"catch SIGTERM signal, with exitcode %d",no); // manager->managerStop(); QApplication::exit(15); } int main (int argc, char* argv[]) { #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); #endif #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); #endif QApplication app(argc, argv); USD_LOG (LOG_DEBUG, "Activating %s plugin compilation time:[%s] [%s]",MODULE_NAME,__DATE__,__TIME__); signal(SIGTERM, &handler); QApplication::setQuitOnLastWindowClosed(false); QTranslator translator; if(translator.load(QLocale(),QLatin1String("/usr/share/ukui-settings-daemon/daemon/res/i18n/"))) { app.installTranslator(&translator); } else { qDebug() << "zh_CH translator error!"; } //translator.load("/usr/share/ukui-settings-daemon/daemon/res/i18n/zh_CN.qm"); //app.installTranslator(&translator); parse_args (argc, argv); if (replace) stop_daemon (); manager = PluginManager::getInstance(); if (!manager) { return 0; } bool res = manager->managerStart(); if (!res) { USD_LOG(LOG_INFO, "manager start error!"); return 0; } USD_LOG(LOG_INFO, "ukui-settings-daemon started!"); return app.exec(); } static void parse_args (int argc, char *argv[]) { if (argc == 1) return; for (int i = 1; i < argc; ++i) { if (0 == QString::compare(QString(argv[i]).trimmed(), QString("--replace"))) { replace = true; } else if (0 == QString::compare(QString(argv[i]).trimmed(), QString("--daemon"))) { no_daemon = false; } else { if (argc > 1) { print_help(); USD_LOG(LOG_DEBUG, " Unsupported command line arguments: '%s'", argv[i]); exit(0); } } } } static void print_help() { fprintf(stdout, "%s\n%s\n%s\n%s\n\n", \ "Useage: ukui-setting-daemon