add more spacing
[personal-kdebase.git] / workspace / kcontrol / input / xcursor / xcursortheme.cpp
bloba987487bb7263d03443e2740eb4e0c7ca4053cbc
1 /*
2 * Copyright © 2006-2007 Fredrik Höglund <fredrik@kde.org>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License version 2 or at your option version 3 as published
7 * by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; see the file COPYING. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
20 #include <KLocale>
21 #include <KConfig>
22 #include <KConfigGroup>
24 #include <QCursor>
25 #include <QImage>
26 #include <QDir>
27 #include <QX11Info>
29 #include <X11/Xlib.h>
30 #include <X11/Xcursor/Xcursor.h>
32 #include "xcursortheme.h"
35 // Static variable holding alternative names for some cursors
36 QHash<QString, QString> XCursorTheme::alternatives;
38 XCursorTheme::XCursorTheme(const QDir &themeDir)
39 : LegacyTheme(themeDir.dirName(), i18n("No description available"))
41 // Directory information
42 setName(themeDir.dirName());
43 setPath(themeDir.path());
44 setIsWritable(QFileInfo(themeDir.path()).isWritable()); // ### perhaps this shouldn't be cached
46 if (themeDir.exists("index.theme"))
47 parseIndexFile();
51 void XCursorTheme::parseIndexFile()
53 KConfig config(path() + "/index.theme", KConfig::NoGlobals);
54 KConfigGroup cg(&config, "Icon Theme");
56 m_title = cg.readEntry("Name", m_title);
57 m_description = cg.readEntry("Comment", m_description);
58 m_sample = cg.readEntry("Example", m_sample);
59 m_hidden = cg.readEntry("Hidden", false);
60 m_inherits = cg.readEntry("Inherits", QStringList());
64 QString XCursorTheme::findAlternative(const QString &name) const
66 if (alternatives.isEmpty())
68 alternatives.reserve(18);
70 // Qt uses non-standard names for some core cursors.
71 // If Xcursor fails to load the cursor, Qt creates it with the correct name using the
72 // core protcol instead (which in turn calls Xcursor). We emulate that process here.
73 // Note that there's a core cursor called cross, but it's not the one Qt expects.
74 alternatives.insert("cross", "crosshair");
75 alternatives.insert("up_arrow", "center_ptr");
76 alternatives.insert("wait", "watch");
77 alternatives.insert("ibeam", "xterm");
78 alternatives.insert("size_all", "fleur");
79 alternatives.insert("pointing_hand", "hand2");
81 // Precomputed MD5 hashes for the hardcoded bitmap cursors in Qt and KDE.
82 // Note that the MD5 hash for left_ptr_watch is for the KDE version of that cursor.
83 alternatives.insert("size_ver", "00008160000006810000408080010102");
84 alternatives.insert("size_hor", "028006030e0e7ebffc7f7070c0600140");
85 alternatives.insert("size_bdiag", "c7088f0f3e6c8088236ef8e1e3e70000");
86 alternatives.insert("size_fdiag", "fcf1c3c7cd4491d801f1e1c78f100000");
87 alternatives.insert("whats_this", "d9ce0ab605698f320427677b458ad60b");
88 alternatives.insert("split_h", "14fef782d02440884392942c11205230");
89 alternatives.insert("split_v", "2870a09082c103050810ffdffffe0204");
90 alternatives.insert("forbidden", "03b6e0fcb3499374a867c041f52298f0");
91 alternatives.insert("left_ptr_watch", "3ecb610c1bf2410f44200f48c40d3599");
92 alternatives.insert("hand2", "e29285e634086352946a0e7090d73106");
93 alternatives.insert("openhand", "9141b49c8149039304290b508d208c40");
94 alternatives.insert("closedhand", "05e88622050804100c20044008402080");
97 return alternatives.value(name, QString());
101 XcursorImage *XCursorTheme::xcLoadImage(const QString &image, int size) const
103 QByteArray cursorName = QFile::encodeName(image);
104 QByteArray themeName = QFile::encodeName(name());
106 return XcursorLibraryLoadImage(cursorName, themeName, size);
110 XcursorImages *XCursorTheme::xcLoadImages(const QString &image, int size) const
112 QByteArray cursorName = QFile::encodeName(image);
113 QByteArray themeName = QFile::encodeName(name());
115 return XcursorLibraryLoadImages(cursorName, themeName, size);
119 QCursor XCursorTheme::loadCursor(const QString &name, int size) const
121 if (size == -1)
122 size = XcursorGetDefaultSize(QX11Info::display());
124 // Load the cursor images
125 XcursorImages *images = xcLoadImages(name, size);
127 if (!images)
128 images = xcLoadImages(findAlternative(name), size);
130 // Fall back to a legacy cursor
131 if (!images)
132 return LegacyTheme::loadCursor(name);
134 // Create the cursor
135 Cursor handle = XcursorImagesLoadCursor(QX11Info::display(), images);
136 QCursor cursor = QCursor(Qt::HANDLE(handle)); // QCursor takes ownership of the handle
137 XcursorImagesDestroy(images);
139 setCursorName(cursor, name);
140 return cursor;
144 QImage XCursorTheme::loadImage(const QString &name, int size) const
146 if (size == -1)
147 size = XcursorGetDefaultSize(QX11Info::display());
149 // Load the image
150 XcursorImage *xcimage = xcLoadImage(name, size);
152 if (!xcimage)
153 xcimage = xcLoadImage(findAlternative(name), size);
155 // Fall back to a legacy cursor
156 if (!xcimage)
157 return LegacyTheme::loadImage(name);
159 // Convert the XcursorImage to a QImage, and auto-crop it
160 QImage image((uchar *)xcimage->pixels, xcimage->width, xcimage->height,
161 QImage::Format_ARGB32_Premultiplied );
163 image = autoCropImage(image);
164 XcursorImageDestroy(xcimage);
166 return image;