wayland: Support setting cursors

And a handful unrelated cleanups.  Still doesn't really have an answer
for cursor themes.
This commit is contained in:
Kristian Høgsberg 2011-02-09 14:48:29 -05:00
parent 546069f434
commit 3ef3433511
14 changed files with 217 additions and 161 deletions

View File

@ -356,7 +356,7 @@ if test "x$enable_wayland_backend" == "xyes"; then
GIO_PACKAGE=gio-unix-2.0
GDK_WINDOWING="$GDK_WINDOWING
#define GDK_WINDOWING_WAYLAND"
WAYLAND_PACKAGES="wayland-client xkbcommon"
WAYLAND_PACKAGES="wayland-client xkbcommon wayland-egl"
AM_CONDITIONAL(USE_WAYLAND, true)
else
AM_CONDITIONAL(USE_WAYLAND, false)

View File

@ -29,7 +29,6 @@ libgdk_wayland_la_SOURCES = \
gdkdisplaymanager-wayland.c \
gdkdnd-wayland.c \
gdkeventsource.c \
gdkeventsource.h \
gdkkeys-wayland.c \
gdkscreen-wayland.c \
gdkscreen-wayland.h \

View File

@ -36,6 +36,8 @@
#include "gdkwayland.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <sys/mman.h>
#define GDK_TYPE_WAYLAND_CURSOR (_gdk_wayland_cursor_get_type ())
#define GDK_WAYLAND_CURSOR(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_CURSOR, GdkWaylandCursor))
#define GDK_WAYLAND_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WAYLAND_CURSOR, GdkWaylandCursorClass))
@ -51,6 +53,9 @@ struct _GdkWaylandCursor
GdkCursor cursor;
gchar *name;
guint serial;
int x, y, width, height, size;
void *map;
struct wl_buffer *buffer;
};
struct _GdkWaylandCursorClass
@ -78,6 +83,17 @@ gdk_wayland_cursor_get_image (GdkCursor *cursor)
return NULL;
}
struct wl_buffer *
_gdk_wayland_cursor_get_buffer (GdkCursor *cursor, int *x, int *y)
{
GdkWaylandCursor *wayland_cursor = GDK_WAYLAND_CURSOR (cursor);
*x = wayland_cursor->x;
*y = wayland_cursor->y;
return wayland_cursor->buffer;
}
static void
_gdk_wayland_cursor_class_init (GdkWaylandCursorClass *wayland_cursor_class)
{
@ -94,20 +110,171 @@ _gdk_wayland_cursor_init (GdkWaylandCursor *cursor)
{
}
GdkCursor*
static void
set_pixbuf (GdkWaylandCursor *cursor, GdkPixbuf *pixbuf)
{
int stride, i, n_channels;
unsigned char *pixels, *end, *argb_pixels, *s, *d;
stride = gdk_pixbuf_get_rowstride(pixbuf);
pixels = gdk_pixbuf_get_pixels(pixbuf);
n_channels = gdk_pixbuf_get_n_channels(pixbuf);
argb_pixels = cursor->map;
#define MULT(_d,c,a,t) \
do { t = c * a + 0x7f; _d = ((t >> 8) + t) >> 8; } while (0)
if (n_channels == 4)
{
for (i = 0; i < cursor->height; i++)
{
s = pixels + i * stride;
end = s + cursor->width * 4;
d = argb_pixels + i * cursor->width * 4;
while (s < end)
{
unsigned int t;
MULT(d[0], s[2], s[3], t);
MULT(d[1], s[1], s[3], t);
MULT(d[2], s[0], s[3], t);
d[3] = s[3];
s += 4;
d += 4;
}
}
}
else if (n_channels == 3)
{
for (i = 0; i < cursor->height; i++)
{
s = pixels + i * stride;
end = s + cursor->width * 3;
d = argb_pixels + i * cursor->width * 4;
while (s < end)
{
d[0] = s[2];
d[1] = s[1];
d[2] = s[0];
d[3] = 0xff;
s += 3;
d += 4;
}
}
}
}
static GdkCursor *
create_cursor(GdkDisplayWayland *display, GdkPixbuf *pixbuf, int x, int y)
{
GdkWaylandCursor *cursor;
struct wl_visual *visual;
int stride, fd;
char *filename;
GError *error = NULL;
cursor = g_object_new (GDK_TYPE_WAYLAND_CURSOR,
"cursor-type", GDK_CURSOR_IS_PIXMAP,
"display", display,
NULL);
cursor->name = NULL;
cursor->serial = theme_serial;
cursor->x = x;
cursor->y = y;
cursor->width = gdk_pixbuf_get_width (pixbuf);
cursor->height = gdk_pixbuf_get_height (pixbuf);
stride = cursor->width * 4;
cursor->size = stride * cursor->height;
fd = g_file_open_tmp("wayland-shm-XXXXXX", &filename, &error);
if (fd < 0) {
fprintf(stderr, "g_file_open_tmp failed: %s\n", error->message);
g_error_free (error);
return NULL;
}
unlink (filename);
g_free (filename);
if (ftruncate(fd, cursor->size) < 0) {
fprintf(stderr, "ftruncate failed: %m\n");
close(fd);
return NULL;
}
cursor->map = mmap(NULL, cursor->size,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (cursor->map == MAP_FAILED) {
fprintf(stderr, "mmap failed: %m\n");
close(fd);
return NULL;
}
set_pixbuf (cursor, pixbuf);
visual = wl_display_get_premultiplied_argb_visual(display->wl_display);
cursor->buffer = wl_shm_create_buffer(display->shm,
fd,
cursor->width,
cursor->height,
stride, visual);
close(fd);
return GDK_CURSOR (cursor);
}
#define DATADIR "/usr/share/wayland"
static const struct {
GdkCursorType type;
const char *filename;
int hotspot_x, hotspot_y;
} cursor_definitions[] = {
{ GDK_XTERM, DATADIR "/xterm.png", 15, 15 },
{ GDK_BOTTOM_RIGHT_CORNER, DATADIR "/bottom_right_corner.png", 28, 28 }
};
GdkCursor *
_gdk_wayland_display_get_cursor_for_type (GdkDisplay *display,
GdkCursorType cursor_type)
{
GdkWaylandCursor *private;
GdkDisplayWayland *wayland_display;
GdkPixbuf *pixbuf;
GError *error = NULL;
int i;
private = g_object_new (GDK_TYPE_WAYLAND_CURSOR,
"cursor-type", GDK_CURSOR_IS_PIXMAP,
"display", display,
NULL);
private->name = NULL;
private->serial = theme_serial;
for (i = 0; i < G_N_ELEMENTS (cursor_definitions); i++)
{
if (cursor_definitions[i].type == cursor_type)
break;
}
return GDK_CURSOR (private);
if (i == G_N_ELEMENTS (cursor_definitions))
return NULL;
wayland_display = GDK_DISPLAY_WAYLAND (display);
if (!wayland_display->cursors)
wayland_display->cursors =
g_new0 (GdkCursor *, G_N_ELEMENTS(cursor_definitions));
if (wayland_display->cursors[i])
return g_object_ref (wayland_display->cursors[i]);
pixbuf = gdk_pixbuf_new_from_file(cursor_definitions[i].filename, &error);
if (error != NULL)
{
g_error_free(error);
return NULL;
}
wayland_display->cursors[i] =
create_cursor(wayland_display, pixbuf,
cursor_definitions[i].hotspot_x,
cursor_definitions[i].hotspot_y);
g_object_unref (pixbuf);
return g_object_ref (wayland_display->cursors[i]);
}
GdkCursor*

View File

@ -131,6 +131,19 @@ gdk_device_core_set_window_cursor (GdkDevice *device,
GdkWindow *window,
GdkCursor *cursor)
{
GdkWaylandDevice *wd = GDK_DEVICE_CORE(device)->device;
struct wl_buffer *buffer;
int x, y;
if (cursor)
{
buffer = _gdk_wayland_cursor_get_buffer(cursor, &x, &y);
wl_input_device_attach(wd->device, wd->time, buffer, x, y);
}
else
{
wl_input_device_attach(wd->device, wd->time, NULL, 0, 0);
}
}
static void

View File

@ -46,6 +46,7 @@ struct _GdkWaylandDevice
GdkWindow *keyboard_focus;
struct wl_input_device *device;
int32_t x, y, surface_x, surface_y;
uint32_t time;
};
struct _GdkDeviceCore

View File

@ -26,9 +26,9 @@
#include "gdkdevice-wayland.h"
#include "gdkkeysyms.h"
#include "gdkprivate-wayland.h"
#include "gdkeventsource.h"
#include <X11/extensions/XKBcommon.h>
#include <X11/keysym.h>
static void gdk_device_manager_core_finalize (GObject *object);
@ -59,6 +59,7 @@ input_handle_motion(void *data, struct wl_input_device *input_device,
event = gdk_event_new (GDK_NOTHING);
device->time = time;
device->x = x;
device->y = y;
device->surface_x = sx;
@ -89,6 +90,7 @@ input_handle_button(void *data, struct wl_input_device *input_device,
fprintf (stderr, "button event %d, state %d\n", button, state);
device->time = time;
event = gdk_event_new (state ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE);
event->button.window = g_object_ref (device->pointer_focus);
gdk_event_set_device (event, device->pointer);
@ -120,6 +122,7 @@ input_handle_key(void *data, struct wl_input_device *input_device,
struct xkb_desc *xkb;
GdkKeymap *keymap;
device->time = time;
event = gdk_event_new (state ? GDK_KEY_PRESS : GDK_KEY_RELEASE);
event->key.window = g_object_ref (device->keyboard_focus);
gdk_event_set_device (event, device->keyboard);
@ -134,7 +137,7 @@ input_handle_key(void *data, struct wl_input_device *input_device,
code = key + xkb->min_key_code;
level = 0;
if (device->modifiers & ShiftMask &&
if (device->modifiers & XKB_COMMON_SHIFT_MASK &&
XkbKeyGroupWidth(xkb, code, 0) > 1)
level = 1;
@ -216,6 +219,7 @@ input_handle_pointer_focus(void *data,
GdkWaylandDevice *device = data;
GdkEvent *event;
device->time = time;
if (device->pointer_focus)
{
event = gdk_event_new (GDK_LEAVE_NOTIFY);
@ -300,6 +304,7 @@ input_handle_keyboard_focus(void *data,
fprintf (stderr, "keyboard focus surface %p\n", surface);
device->time = time;
if (device->keyboard_focus)
{
event = gdk_event_new (GDK_FOCUS_CHANGE);

View File

@ -17,10 +17,10 @@
* Boston, MA 02111-1307, USA.
*/
#define EGL_EGLEXT_PROTOTYPES 1
#include "config.h"
#include <wayland-egl.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
@ -31,7 +31,6 @@
#include "gdkwayland.h"
#include "gdkdisplay.h"
#include "gdkdisplay-wayland.h"
#include "gdkeventsource.h"
#include "gdkscreen.h"
#include "gdkscreen-wayland.h"
#include "gdkinternals.h"
@ -40,8 +39,6 @@
#include "gdkdevicemanager-wayland.h"
#include "gdkkeysprivate.h"
#include <wayland-egl.h>
typedef struct _GdkEventTypeWayland GdkEventTypeWayland;
struct _GdkEventTypeWayland
@ -183,6 +180,8 @@ gdk_display_handle_global(struct wl_display *display, uint32_t id,
if (strcmp(interface, "compositor") == 0) {
display_wayland->compositor = wl_compositor_create(display, id);
} else if (strcmp(interface, "shm") == 0) {
display_wayland->shm = wl_shm_create(display, id);
} else if (strcmp(interface, "shell") == 0) {
display_wayland->shell = wl_shell_create(display, id);
wl_shell_add_listener(display_wayland->shell,
@ -212,7 +211,7 @@ gdk_display_init_egl(GdkDisplay *display)
};
display_wayland->egl_display =
eglGetDisplay((EGLNativeDisplayType) display_wayland->native_display);
eglGetDisplay(display_wayland->native_display);
if (!eglInitialize(display_wayland->egl_display, &major, &minor)) {
fprintf(stderr, "failed to initialize display\n");
return FALSE;
@ -300,8 +299,7 @@ _gdk_wayland_display_open (const gchar *display_name)
gdk_input_init (display);
g_signal_emit_by_name (display, "opened");
g_signal_emit_by_name (gdk_display_manager_get(),
"display_opened", display);
g_signal_emit_by_name (gdk_display_manager_get(), "display_opened", display);
return display;
}
@ -343,18 +341,6 @@ gdk_wayland_display_finalize (GObject *object)
if (display_wayland->keymap)
g_object_unref (display_wayland->keymap);
/* Atom Hashtable */
g_hash_table_destroy (display_wayland->atom_from_virtual);
g_hash_table_destroy (display_wayland->atom_to_virtual);
/* list of filters for client messages */
g_list_foreach (display_wayland->client_filters, (GFunc) g_free, NULL);
g_list_free (display_wayland->client_filters);
/* List of event window extraction functions */
g_slist_foreach (display_wayland->event_types, (GFunc)g_free, NULL);
g_slist_free (display_wayland->event_types);
/* input GdkDevice list */
g_list_foreach (display_wayland->input_devices, (GFunc) g_object_unref, NULL);
g_list_free (display_wayland->input_devices);
@ -370,9 +356,6 @@ gdk_wayland_display_finalize (GObject *object)
g_free (display_wayland->startup_notification_id);
/* X ID hashtable */
g_hash_table_destroy (display_wayland->xid_ht);
G_OBJECT_CLASS (_gdk_display_wayland_parent_class)->finalize (object);
}
@ -464,9 +447,7 @@ gdk_wayland_display_get_default_group (GdkDisplay *display)
static gboolean
gdk_wayland_display_supports_selection_notification (GdkDisplay *display)
{
GdkDisplayWayland *display_wayland = GDK_DISPLAY_WAYLAND (display);
return display_wayland->have_xfixes;
return TRUE;
}
static gboolean
@ -495,13 +476,13 @@ gdk_wayland_display_store_clipboard (GdkDisplay *display,
static gboolean
gdk_wayland_display_supports_shapes (GdkDisplay *display)
{
return GDK_DISPLAY_WAYLAND (display)->have_shapes;
return TRUE;
}
static gboolean
gdk_wayland_display_supports_input_shapes (GdkDisplay *display)
{
return GDK_DISPLAY_WAYLAND (display)->have_input_shapes;
return TRUE;
}
static gboolean

View File

@ -26,6 +26,7 @@
#include <stdint.h>
#include <wayland-client.h>
#include <wayland-egl.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GL/gl.h>
@ -60,61 +61,12 @@ struct _GdkDisplayWayland
gint grab_count;
/* Keyboard related information */
gint xkb_event_type;
gboolean use_xkb;
/* Whether we were able to turn on detectable-autorepeat using
* XkbSetDetectableAutorepeat. If FALSE, we'll fall back
* to checking the next event with XPending(). */
gboolean have_xkb_autorepeat;
GdkKeymap *keymap;
guint keymap_serial;
gboolean have_xfixes;
gint xfixes_event_base;
gboolean have_xcomposite;
gboolean have_xdamage;
gint xdamage_event_base;
gboolean have_randr13;
gint xrandr_event_base;
/* If the SECURITY extension is in place, whether this client holds
* a trusted authorization and so is allowed to make various requests
* (grabs, properties etc.) Otherwise always TRUE. */
gboolean trusted_client;
/* drag and drop information */
GdkDragContext *current_dest_drag;
/* data needed for MOTIF DnD */
Window motif_drag_window;
GdkWindow *motif_drag_gdk_window;
GList **motif_target_lists;
gint motif_n_target_lists;
/* Mapping to/from virtual atoms */
GHashTable *atom_from_virtual;
GHashTable *atom_to_virtual;
/* list of filters for client messages */
GList *client_filters;
/* List of functions to go from extension event => X window */
GSList *event_types;
/* X ID hashtable */
GHashTable *xid_ht;
/* translation queue */
GQueue *translate_queue;
/* Input device */
/* input GdkDevice list */
GList *input_devices;
@ -127,16 +79,6 @@ struct _GdkDisplayWayland
/* Time of most recent user interaction. */
gulong user_time;
/* Sets of atoms for DND */
guint base_dnd_atoms_precached : 1;
guint xdnd_atoms_precached : 1;
guint motif_atoms_precached : 1;
guint use_sync : 1;
guint have_shapes : 1;
guint have_input_shapes : 1;
gint shape_event_base;
/* The offscreen window that has the pointer in it (if any) */
GdkWindow *active_offscreen_window;
@ -144,6 +86,7 @@ struct _GdkDisplayWayland
struct wl_display *wl_display;
struct wl_egl_display *native_display;
struct wl_compositor *compositor;
struct wl_shm *shm;
struct wl_shell *shell;
struct wl_output *output;
struct wl_input_device *input_device;
@ -152,6 +95,8 @@ struct _GdkDisplayWayland
EGLContext egl_context;
cairo_device_t *cairo_device;
GdkCursor **cursors;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
PFNEGLCREATEIMAGEKHRPROC create_image;
PFNEGLDESTROYIMAGEKHRPROC destroy_image;
@ -163,8 +108,6 @@ struct _GdkDisplayWaylandClass
};
GType _gdk_display_wayland_get_type (void);
GdkScreen *_gdk_wayland_display_screen_for_xrootwin (GdkDisplay *display,
Window xrootwin);
G_END_DECLS

View File

@ -19,8 +19,8 @@
#include "config.h"
#include "gdkeventsource.h"
#include "gdkinternals.h"
#include "gdkprivate-wayland.h"
typedef struct _GdkWaylandEventSource {
GSource source;

View File

@ -1,44 +0,0 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GDK_EVENT_SOURCE_H__
#define __GDK_EVENT_SOURCE_H__
#include "gdkprivate-wayland.h"
G_BEGIN_DECLS
typedef struct _GdkEventSource GdkEventSource;
G_GNUC_INTERNAL
GSource * gdk_event_source_new (GdkDisplay *display);
G_GNUC_INTERNAL
void gdk_event_source_select_events (GdkEventSource *source,
Window window,
GdkEventMask event_mask,
unsigned int extra_x_mask);
G_GNUC_INTERNAL
void _gdk_deliver_event (GdkDisplay *display, GdkEvent *event);
G_END_DECLS
#endif /* __GDK_EVENT_SOURCE_H__ */

View File

@ -67,6 +67,10 @@ void _gdk_wayland_display_get_maximal_cursor_size (GdkDisplay *display,
gboolean _gdk_wayland_display_supports_cursor_alpha (GdkDisplay *display);
gboolean _gdk_wayland_display_supports_cursor_color (GdkDisplay *display);
struct wl_buffer *_gdk_wayland_cursor_get_buffer (GdkCursor *cursor,
int *x,
int *y);
GdkDragProtocol _gdk_wayland_window_get_drag_protocol (GdkWindow *window,
GdkWindow **target);

View File

@ -53,8 +53,6 @@ struct _GdkScreenWayland
int width_mm, height_mm;
/* Window manager */
long last_wmspec_check_time;
Window wmspec_check_window;
char *window_manager_name;
/* TRUE if wmspec_check_window has changed since last
* fetch of _NET_SUPPORTED
@ -99,7 +97,6 @@ struct _GdkScreenWaylandClass
struct _GdkWaylandMonitor
{
GdkRectangle geometry;
XID output;
int width_mm;
int height_mm;
char * output_name;
@ -117,7 +114,6 @@ init_monitor_geometry (GdkWaylandMonitor *monitor,
monitor->geometry.width = width;
monitor->geometry.height = height;
monitor->output = None;
monitor->width_mm = -1;
monitor->height_mm = -1;
monitor->output_name = NULL;
@ -173,8 +169,6 @@ gdk_wayland_screen_dispose (GObject *object)
_gdk_window_destroy (screen_wayland->root_window, TRUE);
G_OBJECT_CLASS (_gdk_screen_wayland_parent_class)->dispose (object);
screen_wayland->wmspec_check_window = None;
}
static void
@ -511,7 +505,6 @@ _gdk_wayland_screen_new (GdkDisplay *display)
screen_wayland = GDK_SCREEN_WAYLAND (screen);
screen_wayland->display = display;
screen_wayland->wmspec_check_window = None;
/* we want this to be always non-null */
screen_wayland->window_manager_name = g_strdup ("unknown");

View File

@ -34,7 +34,6 @@
#include "gdkwindow-wayland.h"
#include "gdkdeviceprivate.h"
#include "gdkdevice-wayland.h"
#include "gdkeventsource.h"
#include <stdlib.h>
#include <stdio.h>

View File

@ -32,6 +32,7 @@
#include <stdint.h>
#include <wayland-client.h>
#include <wayland-egl.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GL/gl.h>
@ -82,12 +83,6 @@ struct _GdkToplevelWayland
/* Time of most recent user interaction. */
gulong user_time;
/* We use an extra X window for toplevel windows that we XSetInputFocus()
* to in order to avoid getting keyboard events redirected to subwindows
* that might not even be part of this app
*/
Window focus_window;
};
GType _gdk_window_impl_wayland_get_type (void);