~ci-train-bot/mir/mir-ubuntu-artful-2983

« back to all changes in this revision

Viewing changes to src/miral/xcursor_loader.cpp

  • Committer: Bileto Bot
  • Date: 2017-10-11 12:39:42 UTC
  • mfrom: (1160.3102.82 mir-1.0)
  • Revision ID: ci-train-bot@canonical.com-20171011123942-bp7v1xqsab8cmbop
* New upstream release 1.0.0(https://launchpad.net/mir/+milestone/1.0.0)
  - ABI summary:
    . mirclient ABI unchanged at 9
    . miral ABI introduced at 2
    . mirserver ABI bumped to 45
    . mircommon ABI unchanged at 7
    . mirplatform ABI unchanged at 61
    . mirprotobuf ABI unchanged at 3
    . mirplatformgraphics ABI unchanged at 13
    . mirclientplatform ABI unchanged at 5
    . mirinputplatform ABI unchanged at 7
    . mircore ABI unchanged at 1
  - Enhancements:
    . Update licences to (L)GPL3 or (L)GPL2.
    . Initial support for Wayland clients
    . [mir_demo_client_display_config] add orientation changing
    . RPC: Don't require the server ACK client's buffer-release requests.
    . Added libmirclientcpp to Mir source package
    . Added libmiral to Mir source package
    . Various small improvements to miral-shell example
    . [libmiral, miral-shell] handle display reconfiguration better and allow
      shells to customize maximized placements.
    . Enable CommandLineOptions to be processed before server initialization
  - Bugs fixed:
    . Fix handling of invalid display configuration. (LP: #1643446)
    . Move full responsibility for buffer IPC into frontend. (LP: #1395421)
    . Don't destroy an IPC "closure" object when it may yet be used
      (LP: #1672960)
    . [mesa-kms] Respect display orientation when painting cursor.
      (LP: #1610078)
    . Respect cursor hotspot when hosted on Mir. (LP: #1705284)
    . mcl::BufferVault: Fix lock inversion.
    . Handle mir_event_type_close_window in examples (LP: #1706004),
      (LP: #1705439)
    . Drop BufferStream::suitable_for_cursor()
    . Only notify resize events for valid surfaces (LP: #1643446)
    . Don't leak DRM fds in platform-eglstream probe.
    . Remove obsolete & broken example code. (LP: #1663130)
    . Move buffer-release IPC to a dedicated IPC thread. (LP: #1395421)
    . [NestedServerWithTwoDisplays] Look for the last of a series of
      synthetic events to ensure that the queue is drained before the test
      exits. (LP: #1709666)
    . floating window manager allows resizing maximized windows (LP: #1704776)
    . [miral-shell] doesn't work with breeze X cursor theme (LP: #1699084)
    . [miral-shell] Don't allow splashscreen to be occluded (LP: #1705973)
    . [miral-shell] Update maximized windows on display changes (LP: #1705695)
    . Make racy DragAndDrop test reliable. (LP: #1704780)
    . [libmiral] Define default window settings in one place and clamp the
      actual values to avoid ldiv0. (LP: #1717061)
    . [miral-kiosk] Apply fullscreen logic when hidden windows are restored.
      (LP: #1717910)
    . [mir-on-x11] Less annoying clipping of Mir-on-X11 window when it exceeds
      display bounds. (LP: #1668599)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2014 Canonical Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify it
 
5
 * under the terms of the GNU General Public License version 2 or 3 as
 
6
 * published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
 * GNU General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Authored by: Robert Carr <robert.carr@canonical.com>
 
17
 */
 
18
 
 
19
#include "xcursor_loader.h"
 
20
 
 
21
#include <mir/graphics/cursor_image.h>
 
22
 
 
23
#include <boost/throw_exception.hpp>
 
24
#include <stdexcept>
 
25
 
 
26
#include <string.h>
 
27
 
 
28
#include <mir_toolkit/cursors.h>
 
29
 
 
30
// Unfortunately this can not be compiled as C++...so we can not namespace
 
31
// these symbols. In order to differentiate from internal symbols
 
32
//  we refer to them via their _ prefixed version, i.e. _XcursorImage
 
33
extern "C"
 
34
{
 
35
#include "xcursor.h"
 
36
}
 
37
 
 
38
namespace mg = mir::graphics;
 
39
namespace mi = mir::input;
 
40
namespace geom = mir::geometry;
 
41
 
 
42
namespace
 
43
{
 
44
class XCursorImage : public mg::CursorImage
 
45
{
 
46
public:
 
47
    XCursorImage(_XcursorImage *image, std::shared_ptr<_XcursorImages> const& save_resource)
 
48
        : image(image),
 
49
          save_resource(save_resource)
 
50
    {
 
51
    }
 
52
 
 
53
    ~XCursorImage()
 
54
    {
 
55
    }
 
56
 
 
57
    void const* as_argb_8888() const override
 
58
    {
 
59
        return image->pixels;
 
60
    }
 
61
    geom::Size size() const override
 
62
    {
 
63
        return {image->width, image->height};
 
64
    }
 
65
    geom::Displacement hotspot() const override
 
66
    {
 
67
        return {image->xhot, image->yhot};
 
68
    }
 
69
 
 
70
private:
 
71
    _XcursorImage *image;
 
72
    std::shared_ptr<_XcursorImages> const save_resource;
 
73
};
 
74
 
 
75
std::string const
 
76
xcursor_name_for_mir_cursor(std::string const& mir_cursor_name)
 
77
{
 
78
    if (mir_cursor_name == mir_default_cursor_name)
 
79
    {
 
80
        return "arrow";
 
81
    }
 
82
    else if (mir_cursor_name == mir_arrow_cursor_name)
 
83
    {
 
84
        return "arrow";
 
85
    }
 
86
    else if (mir_cursor_name == mir_busy_cursor_name)
 
87
    {
 
88
        return "watch";
 
89
    }
 
90
    else if (mir_cursor_name == mir_caret_cursor_name)
 
91
    {
 
92
        return "xterm"; // Yep
 
93
    }
 
94
    else if (mir_cursor_name == mir_pointing_hand_cursor_name)
 
95
    {
 
96
        return "hand2";
 
97
    }
 
98
    else if (mir_cursor_name == mir_open_hand_cursor_name)
 
99
    {
 
100
        return "hand";
 
101
    }
 
102
    else if (mir_cursor_name == mir_closed_hand_cursor_name)
 
103
    {
 
104
        return "grabbing";
 
105
    }
 
106
    else if (mir_cursor_name == mir_horizontal_resize_cursor_name)
 
107
    {
 
108
        return "h_double_arrow";
 
109
    }
 
110
    else if (mir_cursor_name == mir_vertical_resize_cursor_name)
 
111
    {
 
112
        return "v_double_arrow";
 
113
    }
 
114
    else if (mir_cursor_name == mir_diagonal_resize_bottom_to_top_cursor_name)
 
115
    {
 
116
        return "top_right_corner";
 
117
    }
 
118
    else if (mir_cursor_name == mir_diagonal_resize_top_to_bottom_cursor_name)
 
119
    {
 
120
        return "bottom_right_corner";
 
121
    }
 
122
    else if (mir_cursor_name == mir_omnidirectional_resize_cursor_name)
 
123
    {
 
124
        return "fleur";
 
125
    }
 
126
    else if (mir_cursor_name == mir_vsplit_resize_cursor_name)
 
127
    {
 
128
        return "v_double_arrow";
 
129
    }
 
130
    else if (mir_cursor_name == mir_hsplit_resize_cursor_name)
 
131
    {
 
132
        return "h_double_arrow";
 
133
    }
 
134
    else if (mir_cursor_name == mir_crosshair_cursor_name)
 
135
    {
 
136
        return "crosshair";
 
137
    }
 
138
    else
 
139
    {
 
140
        return mir_cursor_name;
 
141
    }
 
142
}
 
143
}
 
144
 
 
145
miral::XCursorLoader::XCursorLoader()
 
146
{
 
147
    load_cursor_theme("default");
 
148
}
 
149
 
 
150
miral::XCursorLoader::XCursorLoader(std::string const& theme)
 
151
{
 
152
    load_cursor_theme(theme);
 
153
}
 
154
 
 
155
// Each XcursorImages represents images for the different sizes of a given symbolic cursor.
 
156
void miral::XCursorLoader::load_appropriately_sized_image(_XcursorImages *images)
 
157
{
 
158
    // We would rather take this lock in load_cursor_theme but the Xcursor lib style
 
159
    // makes it difficult to use our standard 'pass the lg around to _locked members' pattern
 
160
    std::lock_guard<std::mutex> lg(guard);
 
161
 
 
162
    // We have to save all the images as XCursor expects us to free them.
 
163
    // This contains the actual image data though, so we need to ensure they stay alive
 
164
    // with the lifetime of the mg::CursorImage instance which refers to them.
 
165
    auto saved_xcursor_library_resource = std::shared_ptr<_XcursorImages>(images, [](_XcursorImages *images)
 
166
        {
 
167
            XcursorImagesDestroy(images);
 
168
        });
 
169
 
 
170
    for (int i = 0; i < images->nimage; i++)
 
171
    {
 
172
        _XcursorImage *candidate = images->images[i];
 
173
        if (candidate->width == mi::default_cursor_size.width.as_uint32_t() &&
 
174
            candidate->height == mi::default_cursor_size.height.as_uint32_t())
 
175
        {
 
176
            loaded_images[std::string(images->name)] = std::make_shared<XCursorImage>(candidate, saved_xcursor_library_resource);
 
177
            return;
 
178
        }
 
179
    }
 
180
 
 
181
    loaded_images[std::string(images->name)] = std::make_shared<XCursorImage>(images->images[0], saved_xcursor_library_resource);
 
182
}
 
183
 
 
184
void miral::XCursorLoader::load_cursor_theme(std::string const& theme_name)
 
185
{
 
186
    // Cursors are named by their square dimension...called the nominal size in XCursor terminology, so we just look up by width.
 
187
    // Later we verify the actual size.
 
188
    xcursor_load_theme(theme_name.c_str(), mi::default_cursor_size.width.as_uint32_t(),
 
189
        [](XcursorImages* images, void *this_ptr)  -> void
 
190
        {
 
191
            // Can't use lambda capture as this lambda is thunked to a C function ptr
 
192
            auto p = static_cast<miral::XCursorLoader*>(this_ptr);
 
193
            p->load_appropriately_sized_image(images);
 
194
        }, this);
 
195
}
 
196
 
 
197
std::shared_ptr<mg::CursorImage> miral::XCursorLoader::image(
 
198
    std::string const& cursor_name,
 
199
    geom::Size const& /*size*/)
 
200
{
 
201
    auto xcursor_name = xcursor_name_for_mir_cursor(cursor_name);
 
202
 
 
203
    std::lock_guard<std::mutex> lg(guard);
 
204
 
 
205
    auto it = loaded_images.find(xcursor_name);
 
206
    if (it != loaded_images.end())
 
207
        return it->second;
 
208
 
 
209
    // Fall back
 
210
    it = loaded_images.find("arrow");
 
211
    if (it != loaded_images.end())
 
212
        return it->second;
 
213
 
 
214
    return nullptr;
 
215
}