diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2013-01-18 22:38:16 -0600 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2013-01-18 22:38:16 -0600 |
commit | 54928e863500dda7674b5a6d425a77065095b6d3 (patch) | |
tree | 728c4bc62671724bd70cdf6f96a6838540b1cf79 | |
parent | 9af7bd1f0b11b37110f72e2fba0d75910d991270 (diff) | |
download | tdelibs-54928e863500dda7674b5a6d425a77065095b6d3.tar.gz tdelibs-54928e863500dda7674b5a6d425a77065095b6d3.zip |
Add control daemon for CPU governor and display brightness
This allows kpowersave-nohal to function properly as a normal user
-rw-r--r-- | CMakeLists.txt | 13 | ||||
-rw-r--r-- | tdecore/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tdecore/hwlibdaemons/CMakeLists.txt | 13 | ||||
-rw-r--r-- | tdecore/hwlibdaemons/dbus/CMakeLists.txt | 37 | ||||
-rw-r--r-- | tdecore/hwlibdaemons/dbus/org.trinitydesktop.hardwarecontrol.conf | 38 | ||||
-rw-r--r-- | tdecore/hwlibdaemons/dbus/org.trinitydesktop.hardwarecontrol.service.cmake | 4 | ||||
-rw-r--r-- | tdecore/hwlibdaemons/dbus/tde_dbus_hardwarecontrol.c | 327 | ||||
-rw-r--r-- | tdecore/tdehardwaredevices.cpp | 71 | ||||
-rw-r--r-- | tdeui/kiconview.h | 2 |
9 files changed, 503 insertions, 3 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 37a05bf5c..f20b54c41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -770,6 +770,19 @@ if( WITH_PCRE ) endif( ) +##### set DBUS file locations ################## + +if( NOT DEFINED DBUS_SYSTEM_CONF_DIRECTORY ) + set (DBUS_SYSTEM_CONF_DIRECTORY "/etc/dbus-1/system.d/" ) + message( STATUS "Using " ${DBUS_SYSTEM_CONF_DIRECTORY} " for DBUS configuration files" ) +endif( NOT DEFINED DBUS_SYSTEM_CONF_DIRECTORY ) + +if( NOT DEFINED DBUS_SERVICE_DIRECTORY ) + set (DBUS_SERVICE_DIRECTORY "/usr/share/dbus-1/system-services/" ) + message( STATUS "Using " ${DBUS_SERVICE_DIRECTORY} " for DBUS service files" ) +endif( NOT DEFINED DBUS_SERVICE_DIRECTORY ) + + if( WITH_NETWORK_MANAGER_BACKEND ) ##### check for dbus-1 ########################### pkg_search_module( DBUS dbus-1 ) diff --git a/tdecore/CMakeLists.txt b/tdecore/CMakeLists.txt index f0ea3b5b4..2adc73c52 100644 --- a/tdecore/CMakeLists.txt +++ b/tdecore/CMakeLists.txt @@ -13,6 +13,7 @@ add_subdirectory( malloc ) add_subdirectory( network ) add_subdirectory( kconfig_compiler ) add_subdirectory( hwlibdata ) +add_subdirectory( hwlibdaemons ) if( NOT DBUS_SYSTEM_BUS ) set( DBUS_SYSTEM_BUS "unix:path=/var/run/dbus/system_bus_socket" CACHE INTERNAL "" FORCE ) diff --git a/tdecore/hwlibdaemons/CMakeLists.txt b/tdecore/hwlibdaemons/CMakeLists.txt new file mode 100644 index 000000000..edc853c95 --- /dev/null +++ b/tdecore/hwlibdaemons/CMakeLists.txt @@ -0,0 +1,13 @@ +################################################# +# +# (C) 2012 Timothy Pearson +# kb9vqf (AT) pearsoncomputing.net +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + + +add_subdirectory( dbus ) diff --git a/tdecore/hwlibdaemons/dbus/CMakeLists.txt b/tdecore/hwlibdaemons/dbus/CMakeLists.txt new file mode 100644 index 000000000..4d1f4618a --- /dev/null +++ b/tdecore/hwlibdaemons/dbus/CMakeLists.txt @@ -0,0 +1,37 @@ +################################################# +# +# (C) 2012 Timothy Pearson +# kb9vqf (AT) pearsoncomputing.net +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +include_directories( + ${DBUS_INCLUDE_DIRS} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} +) + +##### tde_dbus_hardwarecontrol ################## + +tde_add_executable( tde_dbus_hardwarecontrol + SOURCES tde_dbus_hardwarecontrol.c + LINK ${DBUS_LIBRARIES} + DESTINATION ${BIN_INSTALL_DIR} +) + +##### other data ################################ + +configure_file( org.trinitydesktop.hardwarecontrol.service.cmake org.trinitydesktop.hardwarecontrol.service @ONLY ) + +install( FILES + org.trinitydesktop.hardwarecontrol.conf + DESTINATION ${DBUS_SYSTEM_CONF_DIRECTORY} ) + +install( FILES + ${CMAKE_CURRENT_BINARY_DIR}/org.trinitydesktop.hardwarecontrol.service + DESTINATION ${DBUS_SERVICE_DIRECTORY} ) diff --git a/tdecore/hwlibdaemons/dbus/org.trinitydesktop.hardwarecontrol.conf b/tdecore/hwlibdaemons/dbus/org.trinitydesktop.hardwarecontrol.conf new file mode 100644 index 000000000..a649b969f --- /dev/null +++ b/tdecore/hwlibdaemons/dbus/org.trinitydesktop.hardwarecontrol.conf @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- --> + +<!DOCTYPE busconfig PUBLIC + "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> +<busconfig> + <!-- Only root can own the service --> + <policy user="root"> + <allow own="org.trinitydesktop.hardwarecontrol"/> + </policy> + + <policy at_console="true"> + <!-- Users with physical access to the machine are allowed access --> + <allow send_destination="org.trinitydesktop.hardwarecontrol" + send_interface="org.freedesktop.DBus.Introspectable"/> + + <allow send_destination="org.trinitydesktop.hardwarecontrol" + send_interface="org.freedesktop.DBus.Properties"/> + <allow send_destination="org.trinitydesktop.hardwarecontrol.CPUGovernor" + send_interface="org.freedesktop.DBus.Properties"/> + <allow send_destination="org.trinitydesktop.hardwarecontrol.Brightness" + send_interface="org.freedesktop.DBus.Properties"/> + + <allow send_destination="org.trinitydesktop.hardwarecontrol" + send_interface="org.trinitydesktop.hardwarecontrol"/> + <allow send_destination="org.trinitydesktop.hardwarecontrol" + send_interface="org.trinitydesktop.hardwarecontrol.CPUGovernor"/> + <allow send_destination="org.trinitydesktop.hardwarecontrol" + send_interface="org.trinitydesktop.hardwarecontrol.Brightness"/> + </policy> + + <policy context="default"> + <!-- Everyone else is denied access --> + <deny own="org.trinitydesktop.hardwarecontrol"/> + + <deny send_destination="org.trinitydesktop.hardwarecontrol"/> + </policy> +</busconfig> diff --git a/tdecore/hwlibdaemons/dbus/org.trinitydesktop.hardwarecontrol.service.cmake b/tdecore/hwlibdaemons/dbus/org.trinitydesktop.hardwarecontrol.service.cmake new file mode 100644 index 000000000..3be2ebeee --- /dev/null +++ b/tdecore/hwlibdaemons/dbus/org.trinitydesktop.hardwarecontrol.service.cmake @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.trinitydesktop.hardwarecontrol +Exec=@BIN_INSTALL_DIR@/tde_dbus_hardwarecontrol +User=root
\ No newline at end of file diff --git a/tdecore/hwlibdaemons/dbus/tde_dbus_hardwarecontrol.c b/tdecore/hwlibdaemons/dbus/tde_dbus_hardwarecontrol.c new file mode 100644 index 000000000..f7e707522 --- /dev/null +++ b/tdecore/hwlibdaemons/dbus/tde_dbus_hardwarecontrol.c @@ -0,0 +1,327 @@ +#define DBUS_API_SUBJECT_TO_CHANGE +#include <dbus/dbus.h> +#include <stdbool.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void reply_Bool(DBusMessage* msg, DBusConnection* conn, int value) { + DBusMessage* reply; + DBusMessageIter args; + const char* member = dbus_message_get_member(msg); + dbus_uint32_t serial = 0; + + // create a reply from the message + reply = dbus_message_new_method_return(msg); + + // add the arguments to the reply + dbus_message_iter_init_append(reply, &args); + if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &value)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_message_iter_append_basic failed\n", member); + return; + } + + // send the reply && flush the connection + if (!dbus_connection_send(conn, reply, &serial)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_connection_send failed\n", member); + return; + } + dbus_connection_flush(conn); + + // free the reply + dbus_message_unref(reply); +} + +void reply_CanSetGivenPath(DBusMessage* msg, DBusConnection* conn, const char* param) { + DBusMessage* reply; + DBusMessageIter args; + const char* member = dbus_message_get_member(msg); + dbus_uint32_t serial = 0; + int writable = false; + + // check if path is writable + int rval = access (param, W_OK); + if (rval == 0) { + writable = true; + } + + // create a reply from the message + reply = dbus_message_new_method_return(msg); + + // add the arguments to the reply + dbus_message_iter_init_append(reply, &args); + if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &writable)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_message_iter_append_basic failed\n", member); + return; + } + + // send the reply && flush the connection + if (!dbus_connection_send(conn, reply, &serial)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_connection_send failed\n", member); + return; + } + dbus_connection_flush(conn); + + // free the reply + dbus_message_unref(reply); +} + +void reply_SetGivenPath(DBusMessage* msg, DBusConnection* conn, const char* param, const char* contents) { + DBusMessage* reply; + DBusMessageIter args; + const char* member = dbus_message_get_member(msg); + dbus_uint32_t serial = 0; + int writable = false; + int written = false; + + // check if path is writable + int rval = access (param, W_OK); + if (rval == 0) { + writable = true; + } + + if (writable) { + FILE *node = fopen(param, "w"); + if (node != NULL) { + if (fputs(contents, node) != EOF) { + written = true; + } + if (fclose(node) == EOF) { + // Error! + } + } + } + + // create a reply from the message + reply = dbus_message_new_method_return(msg); + + // add the arguments to the reply + dbus_message_iter_init_append(reply, &args); + if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &written)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_message_iter_append_basic failed\n", member); + return; + } + + // send the reply && flush the connection + if (!dbus_connection_send(conn, reply, &serial)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_connection_send failed\n", member); + return; + } + dbus_connection_flush(conn); + + // free the reply + dbus_message_unref(reply); +} + +void reply_CanSetCPUGovernor(DBusMessage* msg, DBusConnection* conn) { + DBusMessageIter args; + const char* member = dbus_message_get_member(msg); + dbus_int32_t cpunum; + char path[256]; + + // read the arguments + if (!dbus_message_iter_init(msg, &args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: no argument supplied\n", member); + } + else if (DBUS_TYPE_INT32 != dbus_message_iter_get_arg_type(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: argument not 32-bit integer\n", member); + } + else { + dbus_message_iter_get_basic(&args, &cpunum); + } + + snprintf(path, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor", cpunum); + reply_CanSetGivenPath(msg, conn, path); +} + +void reply_SetCPUGovernor(DBusMessage* msg, DBusConnection* conn) { + DBusMessageIter args; + const char* member = dbus_message_get_member(msg); + dbus_int32_t cpunum = -1; + char* governor = NULL; + char path[256]; + + // read the arguments + if (!dbus_message_iter_init(msg, &args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: no arguments supplied\n", member); + } + else if (DBUS_TYPE_INT32 != dbus_message_iter_get_arg_type(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: first argument not 32-bit integer\n", member); + } + else { + dbus_message_iter_get_basic(&args, &cpunum); + } + + if (!dbus_message_iter_next(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: second argument not supplied\n", member); + } + else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: second argument not string\n", member); + } + else { + dbus_message_iter_get_basic(&args, &governor); + } + + snprintf(path, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor", cpunum); + if ((cpunum>-1) && governor) { + reply_SetGivenPath(msg, conn, path, governor); + } + else { + reply_Bool(msg, conn, false); + } +} + +void reply_CanSetBrightness(DBusMessage* msg, DBusConnection* conn) { + DBusMessageIter args; + const char* member = dbus_message_get_member(msg); + char* rawpath; + char* safepath; + char path[256]; + + // read the arguments + if (!dbus_message_iter_init(msg, &args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: no argument supplied\n", member); + } + else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: argument not string\n", member); + } + else { + dbus_message_iter_get_basic(&args, &rawpath); + } + + safepath = realpath(rawpath, NULL); + + if (safepath && + (strstr(safepath, "/sys/devices") == safepath) && + (strstr(safepath, "/brightness") == (safepath+strlen(safepath)-strlen("/brightness"))) + ) { + reply_CanSetGivenPath(msg, conn, safepath); + } + else { + reply_Bool(msg, conn, false); + } + + free(safepath); +} + +void reply_SetBrightness(DBusMessage* msg, DBusConnection* conn) { + DBusMessageIter args; + const char* member = dbus_message_get_member(msg); + char* rawpath; + char* safepath; + char* brightness; + char path[256]; + + // read the arguments + if (!dbus_message_iter_init(msg, &args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: no arguments supplied\n", member); + } + else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: first argument not string\n", member); + } + else { + dbus_message_iter_get_basic(&args, &rawpath); + } + + if (!dbus_message_iter_next(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: second argument not supplied\n", member); + } + else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: second argument not string\n", member); + } + else { + dbus_message_iter_get_basic(&args, &brightness); + } + + safepath = realpath(rawpath, NULL); + + if (safepath && brightness && + (strstr(safepath, "/sys/devices") == safepath) && + (strstr(safepath, "/brightness") == (safepath+strlen(safepath)-strlen("/brightness"))) + ) { + reply_SetGivenPath(msg, conn, safepath, brightness); + } + else { + reply_Bool(msg, conn, false); + } + + free(safepath); +} + +void listen() { + DBusMessage* msg; + DBusMessage* reply; + DBusMessageIter args; + DBusConnection* conn; + DBusError err; + int ret; + char* param; + + fprintf(stderr, "[tde_dbus_hardwarecontrol] Listening...\n"); + + // initialise the error structure + dbus_error_init(&err); + + // connect to the bus and check for errors + conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] Connection failed with error '%s'\n", err.message); + dbus_error_free(&err); + } + if (NULL == conn) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] No connection, exiting!\n"); + exit(1); + } + + // request our name on the bus and check for errors + ret = dbus_bus_request_name(conn, "org.trinitydesktop.hardwarecontrol", DBUS_NAME_FLAG_REPLACE_EXISTING , &err); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] Name request failed with error '%s'\n", err.message); + dbus_error_free(&err); + } + if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] Not primary owner (%d), exiting!\n", ret); + exit(1); + } + + // loop, testing for new messages + while (true) { + // non blocking read of the next available message + dbus_connection_read_write(conn, 1000); // block for up to 1 second + msg = dbus_connection_pop_message(conn); + + // loop again if we haven't got a message + if (NULL == msg) { + continue; + } + + // check this is a method call for the right interface & method + if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.CPUGovernor", "CanSetCPUGovernor")) { + reply_CanSetCPUGovernor(msg, conn); + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.CPUGovernor", "SetCPUGovernor")) { + reply_SetCPUGovernor(msg, conn); + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.Brightness", "CanSetBrightness")) { + reply_CanSetBrightness(msg, conn); + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.Brightness", "SetBrightness")) { + reply_SetBrightness(msg, conn); + } + else { + fprintf(stderr, "[tde_dbus_hardwarecontrol] Unknown method '%s' called on interface '%s', ignoring\n", dbus_message_get_member(msg), dbus_message_get_interface(msg)); + } + + // free the message + dbus_message_unref(msg); + } + + // close the connection + dbus_connection_close(conn); +} + +int main(int argc, char** argv) { + listen(); + return 0; +} diff --git a/tdecore/tdehardwaredevices.cpp b/tdecore/tdehardwaredevices.cpp index b69c40d45..f9c2859c2 100644 --- a/tdecore/tdehardwaredevices.cpp +++ b/tdecore/tdehardwaredevices.cpp @@ -977,7 +977,25 @@ bool TDECPUDevice::canSetGovernor() { return TRUE; } else { +#ifdef WITH_UPOWER + TQT_DBusConnection dbusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SystemBus); + if (dbusConn.isConnected()) { + TQT_DBusProxy hardwareControl("org.trinitydesktop.hardwarecontrol", "/org/trinitydesktop/hardwarecontrol", "org.trinitydesktop.hardwarecontrol,CPUGovernor", dbusConn); + + // can set brightness? + TQValueList<TQT_DBusData> params; + params << TQT_DBusData::fromInt32(coreNumber()); + TQT_DBusMessage reply = hardwareControl.sendWithReply("CanSetCPUGovernor", params); + if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1) { + return reply[0].toVariant().value.toBool(); + } + } + else { + return FALSE; + } +#else // WITH_UPOWER return FALSE; +#endif// WITH_UPOWER } } @@ -989,6 +1007,22 @@ void TDECPUDevice::setGovernor(TQString gv) { stream << gv.lower(); file.close(); } +#ifdef WITH_UPOWER + else { + TQT_DBusConnection dbusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SystemBus); + if (dbusConn.isConnected()) { + TQT_DBusProxy hardwareControl("org.trinitydesktop.hardwarecontrol", "/org/trinitydesktop/hardwarecontrol", "org.trinitydesktop.hardwarecontrol.CPUGovernor", dbusConn); + + // set brightness + TQValueList<TQT_DBusData> params; + params << TQT_DBusData::fromInt32(coreNumber()) << TQT_DBusData::fromString(gv.lower()); + hardwareControl.sendWithReply("SetCPUGovernor", params); + } + else { + return; + } + } +#endif // WITH_UPOWER // Force update of the device information object KGlobal::hardwareDevices()->processModifiedCPUs(); @@ -1629,7 +1663,25 @@ bool TDEBacklightDevice::canSetBrightness() { return TRUE; } else { +#ifdef WITH_UPOWER + TQT_DBusConnection dbusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SystemBus); + if (dbusConn.isConnected()) { + TQT_DBusProxy hardwareControl("org.trinitydesktop.hardwarecontrol", "/org/trinitydesktop/hardwarecontrol", "org.trinitydesktop.hardwarecontrol,Brightness", dbusConn); + + // can set brightness? + TQValueList<TQT_DBusData> params; + params << TQT_DBusData::fromString(brightnessnode); + TQT_DBusMessage reply = hardwareControl.sendWithReply("CanSetBrightness", params); + if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1) { + return reply[0].toVariant().value.toBool(); + } + } + else { + return FALSE; + } +#else // WITH_UPOWER return FALSE; +#endif// WITH_UPOWER } } @@ -1639,14 +1691,29 @@ int TDEBacklightDevice::rawBrightness() { void TDEBacklightDevice::setRawBrightness(int br) { TQString brightnessnode = systemPath() + "/brightness"; + TQString brightnessCommand = TQString("%1").arg(br); TQFile file( brightnessnode ); if ( file.open( IO_WriteOnly ) ) { - TQString brightnessCommand; - brightnessCommand = TQString("%1").arg(br); TQTextStream stream( &file ); stream << brightnessCommand; file.close(); } +#ifdef WITH_UPOWER + else { + TQT_DBusConnection dbusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SystemBus); + if (dbusConn.isConnected()) { + TQT_DBusProxy hardwareControl("org.trinitydesktop.hardwarecontrol", "/org/trinitydesktop/hardwarecontrol", "org.trinitydesktop.hardwarecontrol.Brightness", dbusConn); + + // set brightness + TQValueList<TQT_DBusData> params; + params << TQT_DBusData::fromString(brightnessnode) << TQT_DBusData::fromString(brightnessCommand); + hardwareControl.sendWithReply("SetBrightness", params); + } + else { + return; + } + } +#endif // WITH_UPOWER } TDEMonitorDevice::TDEMonitorDevice(TDEGenericDeviceType::TDEGenericDeviceType dt, TQString dn) : TDEGenericDevice(dt, dn) { diff --git a/tdeui/kiconview.h b/tdeui/kiconview.h index 5b1149f7b..8f0544b88 100644 --- a/tdeui/kiconview.h +++ b/tdeui/kiconview.h @@ -33,7 +33,7 @@ * There is a new signal executed(). It gets connected to either * TQIconView::clicked() or TQIconView::doubleClicked() depending on the KDE * wide Single Click/Double Click settings. It is strongly recommended that - * you use this signal instead of the above mentioned. This way you don´t + * you use this signal instead of the above mentioned. This way you don�t * need to care about the current settings. * If you want to get informed when the user selects something connect to the * TQIconView::selectionChanged() signal. |