Git commit 617b08f5f6652bb9d918abc963954723caca59d2 by Lukas Sommer. Committed on 09/11/2011 at 23:27. Pushed by sommer into branch 'master'.
Make mouse coursor size configurable Enable systemsettings to change the size of the mouse cursor. FEATURE: 90444 FIXED-IN: 4.8 REVIEW: 101701 GUI: DIGEST: M +18 -6 kcontrol/input/xcursor/cursortheme.cpp M +22 -6 kcontrol/input/xcursor/cursortheme.h M +2 -2 kcontrol/input/xcursor/legacytheme.h M +6 -12 kcontrol/input/xcursor/previewwidget.cpp M +1 -1 kcontrol/input/xcursor/previewwidget.h M +166 -31 kcontrol/input/xcursor/themepage.cpp M +32 -3 kcontrol/input/xcursor/themepage.h M +33 -7 kcontrol/input/xcursor/themepage.ui M +68 -4 kcontrol/input/xcursor/xcursortheme.cpp M +6 -3 kcontrol/input/xcursor/xcursortheme.h http://commits.kde.org/kde-workspace/617b08f5f6652bb9d918abc963954723caca59d2 diff --git a/kcontrol/input/xcursor/cursortheme.cpp b/kcontrol/input/xcursor/cursortheme.cpp index 92abea5..2c8c260 100644 --- a/kcontrol/input/xcursor/cursortheme.cpp +++ b/kcontrol/input/xcursor/cursortheme.cpp @@ -110,24 +110,36 @@ QPixmap CursorTheme::createIcon() const int cursorSize = nominalCursorSize(iconSize); QSize size = QSize(iconSize, iconSize); + QPixmap pixmap = createIcon(cursorSize); + + if (!pixmap.isNull()) + { + // Scale the pixmap if it's larger than the preferred icon size + if (pixmap.width() > size.width() || pixmap.height() > size.height()) + pixmap = pixmap.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } + + return pixmap; +} + + +QPixmap CursorTheme::createIcon(int size) const +{ QPixmap pixmap; - QImage image = loadImage(sample(), cursorSize); + QImage image = loadImage(sample(), size); if (image.isNull() && sample() != "left_ptr") - image = loadImage("left_ptr", cursorSize); + image = loadImage("left_ptr", size); if (!image.isNull()) { - // Scale the image if it's larger than the preferred icon size - if (image.width() > size.width() || image.height() > size.height()) - image = image.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation); - pixmap = QPixmap::fromImage(image); } return pixmap; } + void CursorTheme::setCursorName(QCursor &cursor, const QString &name) const { #ifdef HAVE_XFIXES diff --git a/kcontrol/input/xcursor/cursortheme.h b/kcontrol/input/xcursor/cursortheme.h index 586ccba..672239b 100644 --- a/kcontrol/input/xcursor/cursortheme.h +++ b/kcontrol/input/xcursor/cursortheme.h @@ -62,6 +62,11 @@ class CursorTheme const QString sample() const { return m_sample; } const QString name() const { return m_name; } const QString path() const { return m_path; } + /** @returns A list of the available sizes in this cursor theme, + @warning This list may be empty if the engine doesn't support + the recognition of the size. */ + const QList<int> availableSizes() const + { return m_availableSizes; } bool isWritable() const { return m_writable; } bool isHidden() const { return m_hidden; } QPixmap icon() const; @@ -72,16 +77,27 @@ class CursorTheme /// Loads the cursor image @p name, with the nominal size @p size. /// The image should be autocropped to the smallest possible size. /// If the theme doesn't have the cursor @p name, it should return a null image. - virtual QImage loadImage(const QString &name, int size = -1) const = 0; + virtual QImage loadImage(const QString &name, int size = 0) const = 0; /// Convenience function. Default implementation calls /// QPixmap::fromImage(loadImage()); - virtual QPixmap loadPixmap(const QString &name, int size = -1) const; + virtual QPixmap loadPixmap(const QString &name, int size = 0) const; /// Loads the cursor @p name, with the nominal size @p size. /// If the theme doesn't have the cursor @p name, it should return /// the default cursor from the active theme instead. - virtual QCursor loadCursor(const QString &name, int size = -1) const = 0; + virtual QCursor loadCursor(const QString &name, int size = 0) const = 0; + + /** Creates the icon returned by @ref icon(). Don't use this function + directly but use @ref icon() instead, because @ref icon() caches + the icon. + @returns A pixmap with a cursor (usually left_ptr) that can + be used as icon for this theme. The size is adopted to + standard icon sizes.*/ + virtual QPixmap createIcon() const; + /** @returns A pixmap with a cursor (usually left_ptr) that can + be used as icon for this theme. */ + virtual QPixmap createIcon(int size) const; protected: void setTitle( const QString &title ) { m_title = title; } @@ -89,13 +105,12 @@ class CursorTheme void setSample( const QString &sample ) { m_sample = sample; } inline void setName( const QString &name ); void setPath( const QString &path ) { m_path = path; } + void setAvailableSizes( const QList<int> &availableSizes ) + { m_availableSizes = availableSizes; } void setIcon( const QPixmap &icon ) { m_icon = icon; } void setIsWritable( bool val ) { m_writable = val; } void setIsHidden( bool val ) { m_hidden = val; } - /// Creates the icon returned by @ref icon(). - virtual QPixmap createIcon() const; - /// Convenience function for cropping an image. QImage autoCropImage( const QImage &image ) const; @@ -105,6 +120,7 @@ class CursorTheme QString m_title; QString m_description; QString m_path; + QList<int> m_availableSizes; QString m_sample; mutable QPixmap m_icon; bool m_writable:1; diff --git a/kcontrol/input/xcursor/legacytheme.h b/kcontrol/input/xcursor/legacytheme.h index 846bf9b..bd3c33d 100644 --- a/kcontrol/input/xcursor/legacytheme.h +++ b/kcontrol/input/xcursor/legacytheme.h @@ -41,8 +41,8 @@ class LegacyTheme : public CursorTheme LegacyTheme(); virtual ~LegacyTheme(); - QImage loadImage(const QString &name, int size = -1) const; - QCursor loadCursor(const QString &name, int size = - 1) const; + QImage loadImage(const QString &name, int size = 0) const; + QCursor loadCursor(const QString &name, int size = 0) const; protected: LegacyTheme(const QString &title, const QString &description = QString()) diff --git a/kcontrol/input/xcursor/previewwidget.cpp b/kcontrol/input/xcursor/previewwidget.cpp index 3c264fc..aff149b 100644 --- a/kcontrol/input/xcursor/previewwidget.cpp +++ b/kcontrol/input/xcursor/previewwidget.cpp @@ -50,7 +50,6 @@ namespace { }; const int numCursors = 9; // The number of cursors from the above list to be previewed - const int previewSize = 24; // The nominal cursor size to be used in the preview widget const int cursorSpacing = 20; // Spacing between preview cursors const int widgetMinWidth = 10; // The minimum width of the preview widget const int widgetMinHeight = 48; // The minimum height of the preview widget @@ -60,7 +59,7 @@ namespace { class PreviewCursor { public: - PreviewCursor( const CursorTheme *theme, const QString &name ); + PreviewCursor( const CursorTheme *theme, const QString &name, int size ); ~PreviewCursor() {} const QPixmap &pixmap() const { return m_pixmap; } @@ -81,23 +80,18 @@ class PreviewCursor }; -PreviewCursor::PreviewCursor(const CursorTheme *theme, const QString &name) +PreviewCursor::PreviewCursor(const CursorTheme *theme, const QString &name, int size) { // Create the preview pixmap - QImage image = theme->loadImage(name, previewSize); + QImage image = theme->loadImage(name, size); if (image.isNull()) return; - int maxSize = previewSize * 2; - if (image.height() > maxSize || image.width() > maxSize) - image = image.scaled(maxSize, maxSize, Qt::KeepAspectRatio, - Qt::SmoothTransformation); - m_pixmap = QPixmap::fromImage(image); // Load the cursor - m_cursor = theme->loadCursor(name, previewSize); + m_cursor = theme->loadCursor(name, size); // ### perhaps we should tag the cursor so it doesn't get // replaced when a new theme is applied } @@ -168,7 +162,7 @@ void PreviewWidget::layoutItems() } -void PreviewWidget::setTheme(const CursorTheme *theme) +void PreviewWidget::setTheme(const CursorTheme *theme, const int size) { qDeleteAll(list); list.clear(); @@ -176,7 +170,7 @@ void PreviewWidget::setTheme(const CursorTheme *theme) if (theme) { for (int i = 0; i < numCursors; i++) - list << new PreviewCursor(theme, cursor_names[i]); + list << new PreviewCursor(theme, cursor_names[i], size); needLayout = true; updateGeometry(); diff --git a/kcontrol/input/xcursor/previewwidget.h b/kcontrol/input/xcursor/previewwidget.h index f4d2c4e..4a11e2d 100644 --- a/kcontrol/input/xcursor/previewwidget.h +++ b/kcontrol/input/xcursor/previewwidget.h @@ -30,7 +30,7 @@ class PreviewWidget : public QWidget PreviewWidget(QWidget *parent); ~PreviewWidget(); - void setTheme(const CursorTheme *theme); + void setTheme(const CursorTheme *theme, const int size); void setUseLables(bool); QSize sizeHint() const; diff --git a/kcontrol/input/xcursor/themepage.cpp b/kcontrol/input/xcursor/themepage.cpp index 6c9f29a..0f678ed 100644 --- a/kcontrol/input/xcursor/themepage.cpp +++ b/kcontrol/input/xcursor/themepage.cpp @@ -73,6 +73,7 @@ ThemePage::ThemePage(QWidget *parent) proxy->setFilterCaseSensitivity(Qt::CaseSensitive); proxy->sort(NameColumn, Qt::AscendingOrder); + // Get the icon size for QListView int size = style()->pixelMetric(QStyle::PM_LargeIconSize); view->setModel(proxy); @@ -85,6 +86,16 @@ ThemePage::ThemePage(QWidget *parent) SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(selectionChanged())); + // Make sure we find out about size changes + connect(sizeComboBox, + SIGNAL(currentIndexChanged(int)), + SLOT(sizeChanged())); + + // Make sure we find out about user activity + connect(sizeComboBox, + SIGNAL(activated(int)), + SLOT(preferredSizeChanged())); + // Disable the install button if we can't install new themes to ~/.icons, // or Xcursor isn't set up to look for cursor themes there. if (!model->searchPaths().contains(QDir::homePath() + "/.icons") || !iconsIsWritable()) { @@ -113,6 +124,114 @@ bool ThemePage::iconsIsWritable() const } +void ThemePage::updateSizeComboBox() +{ + // clear the combo box + sizeComboBox->clear(); + + // refill the combo box and adopt its icon size + QModelIndex selected = selectedIndex(); + int maxIconWidth = 0; + int maxIconHeight = 0; + if (selected.isValid()) + { + const CursorTheme *theme = proxy->theme(selected); + const QList<int> sizes = theme->availableSizes(); + QIcon m_icon; + if (sizes.size() > 1) // only refill the combobox if there is more that 1 size + { + int i; + QList<int> comboBoxList; + QPixmap m_pixmap; + + // insert the items + m_pixmap = theme->createIcon(0); + if (m_pixmap.width() > maxIconWidth) + maxIconWidth = m_pixmap.width(); + if (m_pixmap.height() > maxIconHeight) + maxIconHeight = m_pixmap.height(); + sizeComboBox->addItem( + QIcon(m_pixmap), + i18nc("@item:inlistbox size", "resolution dependent"), + 0); + comboBoxList << 0; + foreach (i, sizes) + { + m_pixmap = theme->createIcon(i); + if (m_pixmap.width() > maxIconWidth) + maxIconWidth = m_pixmap.width(); + if (m_pixmap.height() > maxIconHeight) + maxIconHeight = m_pixmap.height(); + sizeComboBox->addItem(QIcon(m_pixmap), QString::number(i), i); + comboBoxList << i; + }; + + // select an item + int selectItem = comboBoxList.indexOf(preferredSize); + if (selectItem < 0) // preferredSize not available for this theme + { + /* Search the value next to preferredSize. The first entry (0) + is ignored. (If preferredSize would have been 0, then we + would had found it yet. As preferredSize is not 0, we won't + default to "automatic size".)*/ + int j; + int distance; + int smallestDistance; + selectItem = 1; + j = comboBoxList.value(selectItem); + smallestDistance = j < preferredSize ? preferredSize - j : j - preferredSize; + for (int i = 2; i < comboBoxList.size(); ++i) + { + j = comboBoxList.value(i); + distance = j < preferredSize ? preferredSize - j : j - preferredSize; + if (distance < smallestDistance || (distance == smallestDistance && j > preferredSize)) + { + smallestDistance = distance; + selectItem = i; + }; + } + }; + sizeComboBox->setCurrentIndex(selectItem); + }; + }; + sizeComboBox->setIconSize(QSize(maxIconWidth, maxIconHeight)); + + // enable or disable the combobox + KConfig c("kcminputrc"); + KConfigGroup cg(&c, "Mouse"); + if (cg.isEntryImmutable("cursorSize")) { + sizeComboBox->setEnabled(false); + sizeLabel->setEnabled(false); + } else { + sizeComboBox->setEnabled(sizeComboBox->count() > 0); + sizeLabel->setEnabled(sizeComboBox->count() > 0); + }; +} + + +int ThemePage::selectedSize() const +{ + if (sizeComboBox->isEnabled() && sizeComboBox->currentIndex() >= 0) + return sizeComboBox->itemData(sizeComboBox->currentIndex(), Qt::UserRole).toInt(); + return 0; +} + + +void ThemePage::updatePreview() +{ + QModelIndex selected = selectedIndex(); + + if (selected.isValid()) { + const CursorTheme *theme = proxy->theme(selected); + preview->setTheme(theme, selectedSize()); + removeButton->setEnabled(theme->isWritable()); + } else { + preview->setTheme(NULL, 0); + removeButton->setEnabled(false); + }; +} + + bool ThemePage::haveXfixes() { bool result = false; @@ -131,12 +250,15 @@ bool ThemePage::haveXfixes() } -bool ThemePage::applyTheme(const CursorTheme *theme) +bool ThemePage::applyTheme(const CursorTheme *theme, const int size) { // Require the Xcursor version that shipped with X11R6.9 or greater, since // in previous versions the Xfixes code wasn't enabled due to a bug in the // build system (freedesktop bug #975). #if HAVE_XFIXES && XFIXES_MAJOR >= 2 && XCURSOR_LIB_VERSION >= 10105 + if (!theme) + return false; + if (!haveXfixes()) return false; @@ -173,7 +295,7 @@ bool ThemePage::applyTheme(const CursorTheme *theme) foreach (const QString &name, names) { - QCursor cursor = theme->loadCursor(name); + QCursor cursor = theme->loadCursor(name, size); XFixesChangeCursorByName(x11Info().display(), cursor.handle(), QFile::encodeName(name)); } @@ -187,17 +309,20 @@ bool ThemePage::applyTheme(const CursorTheme *theme) void ThemePage::save() { - if (appliedIndex == selectedIndex() || !selectedIndex().isValid()) - return; - - const CursorTheme *theme = proxy->theme(selectedIndex()); + const CursorTheme *theme = selectedIndex().isValid() ? proxy->theme(selectedIndex()) : NULL; + const int size = selectedSize(); KConfig config("kcminputrc"); KConfigGroup c(&config, "Mouse"); - c.writeEntry("cursorTheme", theme->name()); + if (theme) + { + c.writeEntry("cursorTheme", theme->name()); + }; + c.writeEntry("cursorSize", size); + preferredSize = size; c.sync(); - if (!applyTheme(theme)) + if (!applyTheme(theme, size)) { KMessageBox::information(this, i18n("You have to restart KDE for these changes to take effect."), @@ -205,6 +330,7 @@ void ThemePage::save() } appliedIndex = selectedIndex(); + appliedSize = size; } @@ -233,16 +359,26 @@ void ThemePage::load() removeButton->setEnabled(false); } + // Load cursor size + int size = cg.readEntry("cursorSize", 0); + if (size <= 0) + preferredSize = 0; + else + preferredSize = size; + updateSizeComboBox(); // This handles also the kiosk mode + + appliedSize = size; + const CursorTheme *theme = proxy->theme(appliedIndex); if (appliedIndex.isValid()) { // Select the current theme - selectRow(appliedIndex); + view->setCurrentIndex(appliedIndex); view->scrollTo(appliedIndex, QListView::PositionAtCenter); // Update the preview widget as well - preview->setTheme(theme); + preview->setTheme(theme, size); } if (!theme || !theme->isWritable()) @@ -255,33 +391,17 @@ void ThemePage::defaults() view->selectionModel()->clear(); QModelIndex defaultIndex = proxy->findIndex("Oxygen_Black"); view->setCurrentIndex(defaultIndex); -} - - -void ThemePage::selectRow(int row) const -{ - // Create a selection that stretches across all columns - QModelIndex from = proxy->index(row, 0); - QModelIndex to = proxy->index(row, model->columnCount() - 1); - QItemSelection selection(from, to); - - view->selectionModel()->select(selection, QItemSelectionModel::Select); + preferredSize = 0; + updateSizeComboBox(); } void ThemePage::selectionChanged() { - QModelIndex selected = selectedIndex(); + updateSizeComboBox(); + updatePreview(); - if (selected.isValid()) - { - const CursorTheme *theme = proxy->theme(selected); - preview->setTheme(theme); - removeButton->setEnabled(theme->isWritable()); - } else - preview->setTheme(NULL); - - emit changed(appliedIndex != selected); + emit changed(appliedIndex != selectedIndex()); } QModelIndex ThemePage::selectedIndex() const @@ -293,6 +413,21 @@ QModelIndex ThemePage::selectedIndex() const return QModelIndex(); } +void ThemePage::sizeChanged() +{ + updatePreview(); + emit changed(selectedSize() != appliedSize); +} + +void ThemePage::preferredSizeChanged() +{ + int index = sizeComboBox->currentIndex(); + if (index >= 0) + preferredSize = sizeComboBox->itemData(index, Qt::UserRole).toInt(); + else + preferredSize = 0; +} + void ThemePage::getNewClicked() { KNS3::DownloadDialog dialog("xcursor.knsrc", this); diff --git a/kcontrol/input/xcursor/themepage.h b/kcontrol/input/xcursor/themepage.h index 38ca893..3b21dd9 100644 --- a/kcontrol/input/xcursor/themepage.h +++ b/kcontrol/input/xcursor/themepage.h @@ -48,21 +48,50 @@ class ThemePage : public QWidget, private Ui::ThemePage private slots: void selectionChanged(); + /** Updates the preview. If the size has changed, it also emits changed() */ + void sizeChanged(); + /** Sets #preferredSize to the item that is currently selected in sizeComboBox. + If none is selected, it is set to 0. */ + void preferredSizeChanged(); + /** Updates the size combo box. It loads the size list of the selected cursor + theme with the corresponding icons and chooses an appropriate entry. It + enables the combo box and the label if the theme provides more than one + size, otherwise it disables it. If the size setting is looked in kiosk + mode, it stays always disabled. */ + void updateSizeComboBox(); void getNewClicked(); void installClicked(); void removeClicked(); private: - void selectRow(int) const; - void selectRow(const QModelIndex &index) const { selectRow(index.row()); } + /** @returns 0 if in the UI "automatic size" is selected, otherwise + returns the custom size. */ + int selectedSize() const; + /** Holds the last size that was choosen by the user. Example: The user chooses + theme1 which provides the sizes 24 and 36. He chooses 36. preferredSize gets + set to 36. Now, he switchs to theme2 which provides the sizes 30 and 40. + preferredSize still is 36, so the UI will default to 40, which is next to 36. + Now, he chooses theme3 which provides the sizes 34 and 44. preferredSize is + still 36, so the UI defaults to 34. Now the user changes manually to 44. This + will also change preferredSize. */ + int preferredSize; + void updatePreview(); QModelIndex selectedIndex() const; bool installThemes(const QString &file); - bool applyTheme(const CursorTheme *theme); + /** Applies a given theme, using XFixes, XCursor and KGlobalSettings. + @param theme The cursor theme to be applied. It is save to pass 0 here + (will result in \e false as return value). + @param size The size hint that is used to select the cursor size. + @returns If the changes could be applied. Will return \e false if \e theme is + 0 or if the XFixes and XCursor libraries aren't available in the required + version, otherwise returns \e true. */ + bool applyTheme(const CursorTheme *theme, const int size); bool iconsIsWritable() const; CursorThemeModel *model; SortProxyModel *proxy; + int appliedSize; // This index refers to the CursorThemeModel, not the proxy or the view QPersistentModelIndex appliedIndex; }; diff --git a/kcontrol/input/xcursor/themepage.ui b/kcontrol/input/xcursor/themepage.ui index 2e38054..be73663 100644 --- a/kcontrol/input/xcursor/themepage.ui +++ b/kcontrol/input/xcursor/themepage.ui @@ -6,19 +6,19 @@ <rect> <x>0</x> <y>0</y> - <width>542</width> + <width>541</width> <height>360</height> </rect> </property> <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0" colspan="4"> + <item row="0" column="0" colspan="2"> <widget class="QLabel" name="label"> <property name="text"> <string>Select the cursor theme you want to use (hover preview to test cursor):</string> </property> </widget> </item> - <item row="1" column="0" colspan="4"> + <item row="1" column="0" rowspan="3" colspan="2"> <widget class="PreviewWidget" name="preview" native="true"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> @@ -34,7 +34,7 @@ </property> </widget> </item> - <item row="2" column="0" rowspan="5" colspan="3"> + <item row="4" column="0" rowspan="5" colspan="2"> <widget class="QListView" name="view"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> @@ -50,7 +50,7 @@ </property> </widget> </item> - <item row="2" column="3"> + <item row="4" column="2"> <widget class="KPushButton" name="installKnsButton"> <property name="toolTip"> <string>Get new color schemes from the Internet</string> @@ -60,20 +60,46 @@ </property> </widget> </item> - <item row="3" column="3"> + <item row="5" column="2"> <widget class="KPushButton" name="installButton"> <property name="text"> <string>Install From File...</string> </property> </widget> </item> - <item row="4" column="3"> + <item row="6" column="2"> <widget class="KPushButton" name="removeButton"> <property name="text"> <string>Remove Theme</string> </property> </widget> </item> + <item row="2" column="2"> + <widget class="QComboBox" name="sizeComboBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="sizeAdjustPolicy"> + <enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum> + </property> + <property name="iconSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="sizeLabel"> + <property name="text"> + <string comment="@label:listbox cursor size">Size:</string> + </property> + </widget> + </item> </layout> </widget> <customwidgets> diff --git a/kcontrol/input/xcursor/xcursortheme.cpp b/kcontrol/input/xcursor/xcursortheme.cpp index 2ecb9ba..2fc7504 100644 --- a/kcontrol/input/xcursor/xcursortheme.cpp +++ b/kcontrol/input/xcursor/xcursortheme.cpp @@ -45,6 +45,39 @@ XCursorTheme::XCursorTheme(const QDir &themeDir) if (themeDir.exists("index.theme")) parseIndexFile(); + + QString cursorFile = path() + "/cursors/left_ptr"; + QList<int> sizeList; + XcursorImages *images = XcursorFilenameLoadAllImages(qPrintable(cursorFile)); + if (images) + { + for (int i = 0; i < images->nimage; ++i) + { + if (!sizeList.contains(images->images[i]->size)) + sizeList.append(images->images[i]->size); + }; + XcursorImagesDestroy(images); + qSort(sizeList.begin(), sizeList.end()); + m_availableSizes = sizeList; + }; + if (!sizeList.isEmpty()) + { + QString sizeListString = QString::number(sizeList.takeFirst()); + while (!sizeList.isEmpty()) + { + sizeListString.append(", "); + sizeListString.append(QString::number(sizeList.takeFirst())); + }; + QString tempString = i18nc( + "@info/plain The argument is the list of available sizes (in pixel). Example: " + "'Available sizes: 24' or 'Available sizes: 24, 36, 48'", + "(Available sizes: %1)", + sizeListString); + if (m_description.isEmpty()) + m_description = tempString; + else + m_description = m_description + ' ' + tempString; + }; } @@ -116,10 +149,41 @@ XcursorImages *XCursorTheme::xcLoadImages(const QString &image, int size) const } +int XCursorTheme::autodetectCursorSize() const +{ + /* This code is basically borrowed from display.c of the XCursor library + We can't use "int XcursorGetDefaultSize(Display *dpy)" because if + previously the cursor size was set to a custom value, it would return + this custom value. */ + int size = 0; + int dpi = 0; + Display *dpy = QX11Info::display(); + // The string "v" is owned and will be destroyed by Xlib + char *v = XGetDefault(dpy, "Xft", "dpi"); + if (v) + dpi = atoi(v); + if (dpi) + size = dpi * 16 / 72; + if (size == 0) + { + int dim; + if (DisplayHeight(dpy, DefaultScreen(dpy)) < + DisplayWidth(dpy, DefaultScreen(dpy))) + { + dim = DisplayHeight(dpy, DefaultScreen(dpy)); + } else { + dim = DisplayWidth(dpy, DefaultScreen(dpy)); + }; + size = dim / 48; + } + return size; +} + + QCursor XCursorTheme::loadCursor(const QString &name, int size) const { - if (size == -1) - size = XcursorGetDefaultSize(QX11Info::display()); + if (size <= 0) + size = autodetectCursorSize(); // Load the cursor images XcursorImages *images = xcLoadImages(name, size); @@ -143,8 +207,8 @@ QCursor XCursorTheme::loadCursor(const QString &name, int size) const QImage XCursorTheme::loadImage(const QString &name, int size) const { - if (size == -1) - size = XcursorGetDefaultSize(QX11Info::display()); + if (size <= 0) + size = autodetectCursorSize(); // Load the image XcursorImage *xcimage = xcLoadImage(name, size); diff --git a/kcontrol/input/xcursor/xcursortheme.h b/kcontrol/input/xcursor/xcursortheme.h index b474086..b4b6c53 100644 --- a/kcontrol/input/xcursor/xcursortheme.h +++ b/kcontrol/input/xcursor/xcursortheme.h @@ -45,9 +45,9 @@ class XCursorTheme : public LegacyTheme XCursorTheme(const QDir &dir); virtual ~XCursorTheme() {} - const QStringList inherits() const { return m_inherits; } - QImage loadImage(const QString &name, int size = -1) const; - QCursor loadCursor(const QString &name, int size = -1) const; + const QStringList inherits() const { return m_inherits; } + QImage loadImage(const QString &name, int size = 0) const; + QCursor loadCursor(const QString &name, int size = 0) const; protected: XCursorTheme(const QString &title, const QString &desc) @@ -59,6 +59,9 @@ class XCursorTheme : public LegacyTheme XcursorImages *xcLoadImages(const QString &name, int size) const; void parseIndexFile(); QString findAlternative(const QString &name) const; + /** Returns the size that the XCursor library would use if no + cursor size is given. This depends mainly on Xft.dpi. */ + int autodetectCursorSize() const; QStringList m_inherits; static QHash<QString, QString> alternatives;