Compare commits

..

18 Commits

Author SHA1 Message Date
Carlos Garnacho
410b37bc53 wayland: Update focus window during DnD motion
But don't emit crossing events, since the DnD grab is in effect.

https://bugzilla.gnome.org/show_bug.cgi?id=728030
2014-09-30 17:34:32 +02:00
Carlos Garnacho
6dfdc6d6ec wayland: Add emit_crossing argument to meta_wayland_pointer_set_focus()
This is TRUE in every place it was previously called.

https://bugzilla.gnome.org/show_bug.cgi?id=728030
2014-09-30 17:34:32 +02:00
Carlos Garnacho
869d12c36d wayland: Trigger the DnD failed animation if no DnD is to happen
If there is no focus window, focus data_source or target selected,
DnD will fail and show the fancy animation.
2014-09-30 17:30:54 +02:00
Carlos Garnacho
827e0c23c5 wayland: Store whether the wl_data_source has a target selected
It will be useful to check whether DnD is going to fail or not.
2014-09-30 17:30:54 +02:00
Carlos Garnacho
9efd96be7b wayland: Unset local DnD surface if destroyed early during DnD 2014-09-30 17:30:54 +02:00
Carlos Garnacho
102d1e62a2 wayland: Keep track of the origin surface and drag point on DnD
Keeping track of the surface will be necessary in case it is destroyed
during DnD, and the coordinates will be useful when figuring out the
snap back coordinates.
2014-09-30 17:30:54 +02:00
Carlos Garnacho
aba81603b9 backend: Add "DnD failed" plumbing to the MetaCursorTracker 2014-09-30 17:30:54 +02:00
Carlos Garnacho
10c6056ce0 backend: Add "DnD failed" animation plumbing on MetaCursorRenderer
The MetaCursorRenderer is the object aware of the offsets applying to
the DnD surface, so translate the given coordinates by that.
2014-09-30 17:30:54 +02:00
Carlos Garnacho
79fdbbfe1a backend: Add "DnD failed" animation
This is currently handled by the MetaStage, when DnD is hinted to be
failed, the current overlay will be copied and used on the snap back/
fade out animation, after the animation is finished, the extra overlay
will be freed.
2014-09-30 17:30:54 +02:00
Carlos Garnacho
572727e6e8 backend: Add meta_overlay_copy()
This function will be useful to transfer an overlay so it can be
temporarily rendered differently. Will be mainly useful for DnD
animations.
2014-09-30 17:30:54 +02:00
Carlos Garnacho
1dbc9e868f detach dnd surface and pointer 2014-09-30 17:30:54 +02:00
Carlos Garnacho
a181ea3cde surface: honor wl_surface_commit()s on the DnD surface
And update the surface when this happens.
2014-09-30 17:30:54 +02:00
Carlos Garnacho
78477dd56a data-device: Update the DnD surface on drag grab updates 2014-09-30 17:30:54 +02:00
Carlos Garnacho
30cc4e1d0a data-device: Store the current drag grab
And bail out if any further start_drag() is attempted.
2014-09-30 17:30:54 +02:00
Carlos Garnacho
4b83b031bc cursor-tracker: Wrap cursor renderer's DnD surface setter 2014-09-30 17:30:54 +02:00
Jasper St. Pierre
40a85e0e99 cursor-renderer: Add setter for the DnD surface
The DnD surface will be always updated/redrawn when the cursor position
changes, and it will never go through backend-specific handling of hw
cursors, so the stage will always need updating when a drag is in effect.
2014-09-30 17:30:54 +02:00
Jasper St. Pierre
dfde1ff327 stage: Add overlay for the DnD surface
This will be rendered similarly to the pointer cursor.
2014-09-30 17:30:54 +02:00
Jasper St. Pierre
92b7daab61 wayland: Record the offset position
This is needed for DND surfaces. We should probably test to see if it's
used for cursor surfaces at all.
2014-09-30 17:30:54 +02:00
76 changed files with 4642 additions and 3833 deletions

2
.gitignore vendored
View File

@@ -66,8 +66,6 @@ src/meta-dbus-idle-monitor.[ch]
src/meta-dbus-login1.[ch]
src/gtk-shell-protocol.c
src/gtk-shell-server-protocol.h
src/scaler-protocol.c
src/scaler-server-protocol.h
src/xdg-shell-protocol.c
src/xdg-shell-server-protocol.h
src/xserver-protocol.c

38
NEWS
View File

@@ -1,41 +1,3 @@
3.15.1
======
* Use GResources for theme loading [Cosimo; #736936]
* Fix headerbar drag getting stuck on xwayland [Carlos; #738411]
* Fix wayland hiDPI regressions [Adel; #739161]
* Misc bug fixes and cleanups [Jasper, Rui, Carlos; #662962, #738630, #738888,
#738890]
Contributors:
Cosimo Cecchi, Adel Gadllah, Carlos Garnacho, Rui Matos, Florian Müllner,
Jasper St. Pierre
3.14.1
======
* Fix move-titlebar-onscreen function [Florian; #736915]
* Fix stacking of the guard window [Owen; #737233]
* Fix keycode lookup for non-default layouts [Rui; #737134]
* Fix workspaces-only-on-primary handling [Florian; #737178]
* Don't unstick sticky windows on workspace removal [Florian; #737625]
* Do not auto-minimize fullscreen windows [Jasper; #705177]
* Upload keymap to newly added keyboard devices [Rui; #737673]
* Apply keyboard repeat settings [Rui; #728055]
* Don't send pressed keys on enter [Rui; #727178]
* Fix build without wayland/native [Rico; #738225]
* Send modifiers after the key event [Rui; #738238]
* Fix unredirect heuristic [Adel; #738271]
* Do not show system chrome over fullscreen windows [Florian; #693991]
* Misc. bug fixes [Florian, Adel, Tom; #737135, #737581, #738146, #738384]
Contributors:
Tom Beckmann, Adel Gadllah, Carlos Garnacho, Rui Matos, Florian Müllner,
Jasper St. Pierre, Rico Tzschichholz, Owen W. Taylor
Translations:
Krishnababu Krothapalli [te], Мирослав Николић [sr, sr@latin],
Alexander Shopov [bg], Saibal Ray [bn_IN], Milo Casagrande [it],
Rūdolfs Mazurs [lv]
3.14.0
======
* Fix placement of popup windows on wayland [Jasper; #736812]

View File

@@ -1,8 +1,8 @@
AC_PREREQ(2.62)
m4_define([mutter_major_version], [3])
m4_define([mutter_minor_version], [15])
m4_define([mutter_micro_version], [1])
m4_define([mutter_minor_version], [14])
m4_define([mutter_micro_version], [0])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
@@ -77,7 +77,9 @@ MUTTER_PC_MODULES="
cairo >= 1.10.0
gsettings-desktop-schemas >= 3.7.3
$CLUTTER_PACKAGE >= 1.19.5
clutter-egl-1.0
cogl-1.0 >= 1.17.1
gbm >= 10.3
upower-glib >= 0.99.0
gnome-desktop-3.0
xcomposite >= 0.2
@@ -200,7 +202,7 @@ AC_SUBST(XWAYLAND_PATH)
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
PKG_CHECK_MODULES(MUTTER_NATIVE_BACKEND, [clutter-egl-1.0 libdrm libsystemd libinput gudev-1.0 gbm >= 10.3], [have_native_backend=yes], [have_native_backend=no])
PKG_CHECK_MODULES(MUTTER_NATIVE_BACKEND, [libdrm libsystemd libinput], [have_native_backend=yes], [have_native_backend=no])
if test $have_native_backend = yes; then
AC_DEFINE([HAVE_NATIVE_BACKEND],[1],[Define if you want to enable the native (KMS) backend based on systemd])
fi

View File

@@ -259,6 +259,8 @@ Overview of Theme Format Version 1
<!-- color obtained by a 0.5 alpha composite of the second color onto the first -->
<color value="blend/gtk:bg[SELECTED]/gtk:fg[SELECTED]/0.5"/>
</gradient>
<!-- image has an optional colorize="#color" attribute to give the
image a certain color -->
<image filename="foo.png" alpha="0.7"
x="10" y="30" width="width / 3" height="height / 4"/>
<gtk_arrow state="normal" shadow="in" arrow="up"

1346
po/it.po

File diff suppressed because it is too large Load Diff

1297
po/lv.po

File diff suppressed because it is too large Load Diff

View File

@@ -41,9 +41,11 @@ endif
# Some random test programs for bits of the code
testboxes_SOURCES = core/testboxes.c
testgradient_SOURCES = ui/testgradient.c
testasyncgetprop_SOURCES = x11/testasyncgetprop.c
noinst_PROGRAMS+=testboxes testasyncgetprop
noinst_PROGRAMS+=testboxes testgradient testasyncgetprop
testboxes_LDADD = $(MUTTER_LIBS) libmutter.la
testgradient_LDADD = $(MUTTER_LIBS) libmutter.la
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la

View File

@@ -6,7 +6,6 @@ lib_LTLIBRARIES = libmutter.la
SUBDIRS=compositor/plugins
EXTRA_DIST =
NULL =
AM_CPPFLAGS = \
-DCLUTTER_ENABLE_COMPOSITOR_API \
@@ -32,32 +31,26 @@ AM_CPPFLAGS = \
-DMUTTER_PKGLIBDIR=\"$(pkglibdir)\" \
-DMUTTER_PLUGIN_DIR=\"$(MUTTER_PLUGIN_DIR)\" \
-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \
-DXWAYLAND_PATH=\"$(XWAYLAND_PATH)\" \
$(NULL)
-DXWAYLAND_PATH=\"$(XWAYLAND_PATH)\"
mutter_built_sources = \
$(dbus_idle_built_sources) \
$(dbus_display_config_built_sources) \
$(dbus_login1_built_sources) \
mutter-enum-types.h \
mutter-enum-types.c \
$(NULL)
mutter-enum-types.c
if HAVE_WAYLAND
mutter_built_sources += \
gtk-shell-protocol.c \
gtk-shell-server-protocol.h \
xdg-shell-protocol.c \
xdg-shell-server-protocol.h \
scaler-protocol.c \
scaler-server-protocol.h \
$(NULL)
xdg-shell-server-protocol.h
endif
wayland_protocols = \
wayland_protocols = \
wayland/protocol/gtk-shell.xml \
wayland/protocol/xdg-shell.xml \
$(NULL)
wayland/protocol/xdg-shell.xml
libmutter_la_SOURCES = \
backends/meta-backend.c \
@@ -116,10 +109,6 @@ libmutter_la_SOURCES = \
compositor/meta-background-group.c \
compositor/meta-cullable.c \
compositor/meta-cullable.h \
compositor/meta-dnd-actor.c \
compositor/meta-dnd-actor-private.h \
compositor/meta-feedback-actor.c \
compositor/meta-feedback-actor-private.h \
compositor/meta-module.c \
compositor/meta-module.h \
compositor/meta-plugin.c \
@@ -169,6 +158,8 @@ libmutter_la_SOURCES = \
meta/errors.h \
core/frame.c \
core/frame.h \
ui/gradient.c \
meta/gradient.h \
core/meta-gesture-tracker.c \
core/meta-gesture-tracker-private.h \
core/keybindings.c \
@@ -227,8 +218,7 @@ libmutter_la_SOURCES = \
x11/window-x11-private.h \
x11/xprops.c \
x11/xprops.h \
x11/mutter-Xatomtype.h \
$(NULL)
x11/mutter-Xatomtype.h
if HAVE_WAYLAND
libmutter_la_SOURCES += \
@@ -240,10 +230,6 @@ libmutter_la_SOURCES += \
wayland/meta-xwayland.c \
wayland/meta-xwayland.h \
wayland/meta-xwayland-private.h \
wayland/meta-wayland-buffer.c \
wayland/meta-wayland-buffer.h \
wayland/meta-wayland-region.c \
wayland/meta-wayland-region.h \
wayland/meta-wayland-data-device.c \
wayland/meta-wayland-data-device.h \
wayland/meta-wayland-keyboard.c \
@@ -261,8 +247,7 @@ libmutter_la_SOURCES += \
wayland/meta-wayland-outputs.c \
wayland/meta-wayland-outputs.h \
wayland/window-wayland.c \
wayland/window-wayland.h \
$(NULL)
wayland/window-wayland.h
endif
if HAVE_NATIVE_BACKEND
@@ -278,11 +263,11 @@ libmutter_la_SOURCES += \
backends/native/meta-launcher.c \
backends/native/meta-launcher.h \
backends/native/dbus-utils.c \
backends/native/dbus-utils.h \
$(NULL)
backends/native/dbus-utils.h
endif
nodist_libmutter_la_SOURCES = $(mutter_built_sources)
nodist_libmutter_la_SOURCES = \
$(mutter_built_sources)
libmutter_la_LDFLAGS = -no-undefined
libmutter_la_LIBADD = $(MUTTER_LIBS) $(MUTTER_NATIVE_BACKEND_LIBS)
@@ -297,6 +282,7 @@ libmutterinclude_headers = \
meta/compositor.h \
meta/display.h \
meta/errors.h \
meta/gradient.h \
meta/group.h \
meta/keybindings.h \
meta/main.h \
@@ -317,8 +303,7 @@ libmutterinclude_headers = \
meta/types.h \
meta/util.h \
meta/window.h \
meta/workspace.h \
$(NULL)
meta/workspace.h
libmutterinclude_built_headers = \
meta/meta-version.h
@@ -399,15 +384,14 @@ DISTCLEANFILES = \
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libmutter.pc
EXTRA_DIST += \
$(wayland_protocols) \
libmutter.pc.in \
mutter-enum-types.h.in \
mutter-enum-types.c.in \
org.freedesktop.login1.xml \
EXTRA_DIST += \
$(wayland_protocols) \
libmutter.pc.in \
mutter-enum-types.h.in \
mutter-enum-types.c.in \
org.freedesktop.login1.xml \
org.gnome.Mutter.DisplayConfig.xml \
org.gnome.Mutter.IdleMonitor.xml \
$(NULL)
org.gnome.Mutter.IdleMonitor.xml
BUILT_SOURCES = \
$(mutter_built_sources) \

View File

@@ -29,11 +29,8 @@
typedef struct {
CoglTexture2D *texture;
int hot_x, hot_y;
#ifdef HAVE_NATIVE_BACKEND
struct gbm_bo *bo;
#endif
int hot_x, hot_y;
} MetaCursorImage;
struct _MetaCursorReference {
@@ -47,10 +44,8 @@ CoglTexture *meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor
int *hot_x,
int *hot_y);
#ifdef HAVE_NATIVE_BACKEND
struct gbm_bo *meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
int *hot_x,
int *hot_y);
#endif
#endif /* META_CURSOR_PRIVATE_H */

View File

@@ -35,13 +35,21 @@
#include "meta-stage.h"
typedef struct
{
CoglTexture *texture;
MetaRectangle current_rect;
int current_x, current_y;
} MetaCursorLayer;
struct _MetaCursorRendererPrivate
{
int current_x, current_y;
MetaRectangle current_rect;
MetaCursorLayer core_layer;
MetaCursorLayer dnd_layer;
MetaCursorReference *displayed_cursor;
gboolean handled_by_backend;
int dnd_surface_offset_x, dnd_surface_offset_y;
gboolean cursor_handled_by_backend;
};
typedef struct _MetaCursorRendererPrivate MetaCursorRendererPrivate;
@@ -59,12 +67,19 @@ queue_redraw (MetaCursorRenderer *renderer)
if (!stage)
return;
if (priv->displayed_cursor && !priv->handled_by_backend)
texture = meta_cursor_reference_get_cogl_texture (priv->displayed_cursor, NULL, NULL);
/* Pointer cursor */
if (!priv->cursor_handled_by_backend)
texture = priv->core_layer.texture;
else
texture = NULL;
meta_stage_set_cursor (META_STAGE (stage), texture, &priv->current_rect);
meta_stage_set_cursor (META_STAGE (stage), texture,
&priv->core_layer.current_rect);
/* DnD surface */
meta_stage_set_dnd_surface (META_STAGE (stage),
priv->dnd_layer.texture,
&priv->dnd_layer.current_rect);
}
static gboolean
@@ -85,46 +100,76 @@ meta_cursor_renderer_init (MetaCursorRenderer *renderer)
}
static void
update_cursor (MetaCursorRenderer *renderer)
update_layer (MetaCursorRenderer *renderer,
MetaCursorLayer *layer,
CoglTexture *texture,
int offset_x,
int offset_y)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
gboolean handled_by_backend;
gboolean should_redraw = FALSE;
layer->texture = texture;
if (priv->displayed_cursor)
if (layer->texture)
{
CoglTexture *texture;
int hot_x, hot_y;
texture = meta_cursor_reference_get_cogl_texture (priv->displayed_cursor, &hot_x, &hot_y);
priv->current_rect.x = priv->current_x - hot_x;
priv->current_rect.y = priv->current_y - hot_y;
priv->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (texture));
priv->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (texture));
layer->current_rect.x = layer->current_x + offset_x;
layer->current_rect.y = layer->current_y + offset_y;
layer->current_rect.width = cogl_texture_get_width (layer->texture);
layer->current_rect.height = cogl_texture_get_height (layer->texture);
}
else
{
priv->current_rect.x = 0;
priv->current_rect.y = 0;
priv->current_rect.width = 0;
priv->current_rect.height = 0;
layer->current_rect.x = 0;
layer->current_rect.y = 0;
layer->current_rect.width = 0;
layer->current_rect.height = 0;
}
}
static void
emit_update_cursor (MetaCursorRenderer *renderer,
gboolean force)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
gboolean handled_by_backend, should_redraw = FALSE;
handled_by_backend = META_CURSOR_RENDERER_GET_CLASS (renderer)->update_cursor (renderer);
if (handled_by_backend != priv->handled_by_backend)
if (handled_by_backend != priv->cursor_handled_by_backend)
{
priv->handled_by_backend = handled_by_backend;
priv->cursor_handled_by_backend = handled_by_backend;
should_redraw = TRUE;
}
if (!handled_by_backend)
if (force || !handled_by_backend || priv->dnd_layer.texture)
should_redraw = TRUE;
if (should_redraw)
queue_redraw (renderer);
}
static void
update_cursor (MetaCursorRenderer *renderer)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
CoglTexture *texture;
int hot_x, hot_y;
/* Cursor layer */
if (priv->displayed_cursor)
{
texture = meta_cursor_reference_get_cogl_texture (priv->displayed_cursor,
&hot_x, &hot_y);
}
else
{
texture = NULL;
hot_x = 0;
hot_y = 0;
}
update_layer (renderer, &priv->core_layer, texture, -hot_x, -hot_y);
emit_update_cursor (renderer, FALSE);
}
MetaCursorRenderer *
meta_cursor_renderer_new (void)
{
@@ -144,6 +189,23 @@ meta_cursor_renderer_set_cursor (MetaCursorRenderer *renderer,
update_cursor (renderer);
}
void
meta_cursor_renderer_set_dnd_surface (MetaCursorRenderer *renderer,
CoglTexture *texture,
int offset_x,
int offset_y)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
g_assert (meta_is_wayland_compositor ());
priv->dnd_surface_offset_x = offset_x;
priv->dnd_surface_offset_y = offset_y;
update_layer (renderer, &priv->dnd_layer, texture, offset_x, offset_y);
emit_update_cursor (renderer, TRUE);
}
void
meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
int x, int y)
@@ -152,12 +214,46 @@ meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
g_assert (meta_is_wayland_compositor ());
priv->current_x = x;
priv->current_y = y;
priv->core_layer.current_x = x;
priv->core_layer.current_y = y;
update_cursor (renderer);
}
void
meta_cursor_renderer_set_dnd_surface_position (MetaCursorRenderer *renderer,
int x,
int y)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
g_assert (meta_is_wayland_compositor ());
priv->dnd_layer.current_x = x;
priv->dnd_layer.current_y = y;
update_layer (renderer, &priv->dnd_layer, priv->dnd_layer.texture,
priv->dnd_surface_offset_x, priv->dnd_surface_offset_y);
emit_update_cursor (renderer, FALSE);
}
void
meta_cursor_renderer_dnd_failed (MetaCursorRenderer *renderer,
int dest_x,
int dest_y)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
MetaBackend *backend = meta_get_backend ();
ClutterActor *stage = meta_backend_get_stage (backend);
g_assert (meta_is_wayland_compositor ());
if (priv->dnd_layer.texture)
meta_stage_dnd_failed (META_STAGE (stage),
dest_x + priv->dnd_surface_offset_x,
dest_y + priv->dnd_surface_offset_y);
}
MetaCursorReference *
meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer)
{
@@ -171,5 +267,5 @@ meta_cursor_renderer_get_rect (MetaCursorRenderer *renderer)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
return &priv->current_rect;
return &priv->core_layer.current_rect;
}

View File

@@ -67,4 +67,14 @@ void meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
MetaCursorReference * meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer);
const MetaRectangle * meta_cursor_renderer_get_rect (MetaCursorRenderer *renderer);
void meta_cursor_renderer_set_dnd_surface (MetaCursorRenderer *renderer,
CoglTexture *texture,
int offset_x,
int offset_y);
void meta_cursor_renderer_set_dnd_surface_position (MetaCursorRenderer *renderer,
int x, int y);
void meta_cursor_renderer_dnd_failed (MetaCursorRenderer *renderer,
int dest_x, int dest_y);
#endif /* META_CURSOR_RENDERER_H */

View File

@@ -62,10 +62,20 @@ void meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker,
void meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker);
void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
MetaCursorReference *cursor);
void meta_cursor_tracker_set_dnd_surface (MetaCursorTracker *tracker,
CoglTexture *texture,
int offset_x,
int offset_y);
void meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
int new_x,
int new_y);
void meta_cursor_tracker_update_dnd_surface_position (MetaCursorTracker *tracker,
int new_x,
int new_y);
void meta_cursor_tracker_dnd_failed (MetaCursorTracker *tracker,
int dest_x,
int dest_y);
MetaCursorReference * meta_cursor_tracker_get_displayed_cursor (MetaCursorTracker *tracker);

View File

@@ -27,9 +27,7 @@
* pointer abstraction"
*/
#include "config.h"
#include "meta-cursor-tracker-private.h"
#include <config.h>
#include <string.h>
#include <meta/main.h>
#include <meta/util.h>
@@ -40,10 +38,11 @@
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <X11/extensions/Xfixes.h>
#include "meta-backend-private.h"
#include "meta-cursor-private.h"
#include "meta-cursor-tracker-private.h"
G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);
@@ -359,6 +358,28 @@ meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
sync_cursor (tracker);
}
void
meta_cursor_tracker_set_dnd_surface (MetaCursorTracker *tracker,
CoglTexture *texture,
int offset_x,
int offset_y)
{
g_assert (meta_is_wayland_compositor ());
meta_cursor_renderer_set_dnd_surface (tracker->renderer, texture,
offset_x, offset_y);
}
void
meta_cursor_tracker_dnd_failed (MetaCursorTracker *tracker,
int dest_x,
int dest_y)
{
g_assert (meta_is_wayland_compositor ());
meta_cursor_renderer_dnd_failed (tracker->renderer, dest_x, dest_y);
}
void
meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
int new_x,
@@ -369,6 +390,17 @@ meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
meta_cursor_renderer_set_position (tracker->renderer, new_x, new_y);
}
void
meta_cursor_tracker_update_dnd_surface_position (MetaCursorTracker *tracker,
int new_x,
int new_y)
{
g_assert (meta_is_wayland_compositor ());
meta_cursor_renderer_set_dnd_surface_position (tracker->renderer,
new_x, new_y);
}
static void
get_pointer_position_gdk (int *x,
int *y,

View File

@@ -56,11 +56,8 @@ static void
meta_cursor_image_free (MetaCursorImage *image)
{
cogl_object_unref (image->texture);
#ifdef HAVE_NATIVE_BACKEND
if (image->bo)
gbm_bo_destroy (image->bo);
#endif
}
static void
@@ -142,10 +139,10 @@ load_cursor_on_client (MetaCursor cursor)
meta_prefs_get_cursor_size ());
}
#ifdef HAVE_NATIVE_BACKEND
static void
get_hardware_cursor_size (uint64_t *cursor_width, uint64_t *cursor_height)
{
#ifdef HAVE_NATIVE_BACKEND
MetaBackend *meta_backend = meta_get_backend ();
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
@@ -154,12 +151,11 @@ get_hardware_cursor_size (uint64_t *cursor_width, uint64_t *cursor_height)
meta_cursor_renderer_native_get_cursor_size (META_CURSOR_RENDERER_NATIVE (renderer), cursor_width, cursor_height);
return;
}
#endif
g_assert_not_reached ();
}
#endif
#ifdef HAVE_NATIVE_BACKEND
static void
meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm,
MetaCursorImage *image,
@@ -197,35 +193,37 @@ meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm,
else
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
}
#endif
#ifdef HAVE_NATIVE_BACKEND
static struct gbm_device *
get_gbm_device (void)
{
#ifdef HAVE_NATIVE_BACKEND
MetaBackend *meta_backend = meta_get_backend ();
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
if (META_IS_CURSOR_RENDERER_NATIVE (renderer))
return meta_cursor_renderer_native_get_gbm_device (META_CURSOR_RENDERER_NATIVE (renderer));
else
return NULL;
}
#endif
return NULL;
}
static void
meta_cursor_image_load_from_xcursor_image (MetaCursorImage *image,
XcursorImage *xc_image)
{
uint width, height, rowstride;
CoglPixelFormat cogl_format;
uint32_t gbm_format;
ClutterBackend *clutter_backend;
CoglContext *cogl_context;
struct gbm_device *gbm;
width = xc_image->width;
height = xc_image->height;
rowstride = width * 4;
gbm_format = GBM_FORMAT_ARGB8888;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
#else
@@ -244,15 +242,13 @@ meta_cursor_image_load_from_xcursor_image (MetaCursorImage *image,
(uint8_t *) xc_image->pixels,
NULL);
#ifdef HAVE_NATIVE_BACKEND
struct gbm_device *gbm = get_gbm_device ();
gbm = get_gbm_device ();
if (gbm)
meta_cursor_image_load_gbm_buffer (gbm,
image,
(uint8_t *) xc_image->pixels,
width, height, rowstride,
GBM_FORMAT_ARGB8888);
#endif
gbm_format);
}
MetaCursorReference *
@@ -281,8 +277,14 @@ meta_cursor_image_load_from_buffer (MetaCursorImage *image,
int hot_x,
int hot_y)
{
struct gbm_device *gbm = get_gbm_device ();
ClutterBackend *backend;
CoglContext *cogl_context;
struct wl_shm_buffer *shm_buffer;
uint32_t gbm_format;
uint64_t cursor_width, cursor_height;
uint width, height;
image->hot_x = hot_x;
image->hot_y = hot_y;
@@ -292,19 +294,13 @@ meta_cursor_image_load_from_buffer (MetaCursorImage *image,
image->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL);
#ifdef HAVE_NATIVE_BACKEND
struct gbm_device *gbm = get_gbm_device ();
if (gbm)
width = cogl_texture_get_width (COGL_TEXTURE (image->texture));
height = cogl_texture_get_height (COGL_TEXTURE (image->texture));
shm_buffer = wl_shm_buffer_get (buffer);
if (shm_buffer)
{
uint32_t gbm_format;
uint64_t cursor_width, cursor_height;
uint width, height;
width = cogl_texture_get_width (COGL_TEXTURE (image->texture));
height = cogl_texture_get_height (COGL_TEXTURE (image->texture));
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (buffer);
if (shm_buffer)
if (gbm)
{
int rowstride = wl_shm_buffer_get_stride (shm_buffer);
@@ -336,7 +332,10 @@ meta_cursor_image_load_from_buffer (MetaCursorImage *image,
width, height, rowstride,
gbm_format);
}
else
}
else
{
if (gbm)
{
/* HW cursors have a predefined size (at least 64x64), which usually is bigger than cursor theme
size, so themed cursors must be padded with transparent pixels to fill the
@@ -357,7 +356,6 @@ meta_cursor_image_load_from_buffer (MetaCursorImage *image,
meta_warning ("Importing HW cursor from wl_buffer failed\n");
}
}
#endif
}
MetaCursorReference *
@@ -387,7 +385,6 @@ meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor,
return COGL_TEXTURE (cursor->image.texture);
}
#ifdef HAVE_NATIVE_BACKEND
struct gbm_bo *
meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
int *hot_x,
@@ -399,7 +396,6 @@ meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
*hot_y = cursor->image.hot_y;
return cursor->image.bo;
}
#endif
MetaCursor
meta_cursor_reference_get_meta_cursor (MetaCursorReference *cursor)

View File

@@ -67,7 +67,6 @@ typedef struct {
} MetaOutputConfig;
typedef struct {
guint refcount;
MetaOutputKey *keys;
MetaOutputConfig *outputs;
unsigned int n_outputs;
@@ -78,6 +77,7 @@ struct _MetaMonitorConfig {
GHashTable *configs;
MetaConfiguration *current;
gboolean current_is_stored;
gboolean current_is_for_laptop_lid;
MetaConfiguration *previous;
@@ -124,29 +124,11 @@ config_clear (MetaConfiguration *config)
g_free (config->outputs);
}
static MetaConfiguration *
config_ref (MetaConfiguration *config)
{
config->refcount++;
return config;
}
static void
config_unref (MetaConfiguration *config)
config_free (gpointer config)
{
if (--config->refcount == 0)
{
config_clear (config);
g_slice_free (MetaConfiguration, config);
}
}
static MetaConfiguration *
config_new (void)
{
MetaConfiguration *config = g_slice_new0 (MetaConfiguration);
config->refcount = 1;
return config;
config_clear (config);
g_slice_free (MetaConfiguration, config);
}
static unsigned long
@@ -238,7 +220,7 @@ meta_monitor_config_init (MetaMonitorConfig *self)
const char *filename;
char *path;
self->configs = g_hash_table_new_full (config_hash, config_equal, NULL, (GDestroyNotify) config_unref);
self->configs = g_hash_table_new_full (config_hash, config_equal, NULL, config_free);
filename = g_getenv ("MUTTER_MONITOR_FILENAME");
if (filename == NULL)
@@ -814,6 +796,27 @@ make_config_key (MetaConfiguration *key,
key->n_outputs = o;
}
gboolean
meta_monitor_config_match_current (MetaMonitorConfig *self,
MetaMonitorManager *manager)
{
MetaOutput *outputs;
unsigned n_outputs;
MetaConfiguration key;
gboolean ok;
if (self->current == NULL)
return FALSE;
outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
make_config_key (&key, outputs, n_outputs, -1);
ok = config_equal (&key, self->current);
config_clear (&key);
return ok;
}
gboolean
meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager)
{
@@ -848,45 +851,73 @@ meta_monitor_config_get_stored (MetaMonitorConfig *self,
return stored;
}
static void
set_current (MetaMonitorConfig *self,
MetaConfiguration *config)
{
g_clear_pointer (&self->previous, (GDestroyNotify) config_unref);
self->previous = self->current;
self->current = config_ref (config);
}
static gboolean
apply_configuration (MetaMonitorConfig *self,
MetaConfiguration *config,
MetaMonitorManager *manager)
MetaMonitorManager *manager,
gboolean stored)
{
GPtrArray *crtcs, *outputs;
gboolean ret = FALSE;
crtcs = g_ptr_array_new_full (config->n_outputs, (GDestroyNotify)meta_crtc_info_free);
outputs = g_ptr_array_new_full (config->n_outputs, (GDestroyNotify)meta_output_info_free);
if (!meta_monitor_config_assign_crtcs (config, manager, crtcs, outputs))
goto out;
{
g_ptr_array_unref (crtcs);
g_ptr_array_unref (outputs);
if (!stored)
config_free (config);
return FALSE;
}
meta_monitor_manager_apply_configuration (manager,
(MetaCRTCInfo**)crtcs->pdata, crtcs->len,
(MetaOutputInfo**)outputs->pdata, outputs->len);
set_current (self, config);
/* Stored (persistent) configurations override the previous one always.
Also, we clear the previous configuration if the current one (which is
about to become previous) is stored, or if the current one has
different outputs.
*/
if (stored ||
(self->current && self->current_is_stored))
{
if (self->previous)
config_free (self->previous);
self->previous = NULL;
}
else
{
/* Despite the name, config_equal() only checks the set of outputs,
not their modes
*/
if (self->current && config_equal (self->current, config))
{
self->previous = self->current;
}
else
{
if (self->current)
config_free (self->current);
self->previous = NULL;
}
}
self->current = config;
self->current_is_stored = stored;
/* If true, we'll be overridden at the end of this call
* inside turn_off_laptop_display / apply_configuration_with_lid */
inside turn_off_laptop_display()
*/
self->current_is_for_laptop_lid = FALSE;
ret = TRUE;
if (self->current == self->previous)
self->previous = NULL;
out:
g_ptr_array_unref (crtcs);
g_ptr_array_unref (outputs);
return ret;
return TRUE;
}
static gboolean
@@ -914,19 +945,6 @@ laptop_display_is_on (MetaConfiguration *config)
return FALSE;
}
static gboolean
multiple_outputs_are_enabled (MetaConfiguration *config)
{
unsigned int i, enabled;
enabled = 0;
for (i = 0; i < config->n_outputs; i++)
if (config->outputs[i].enabled)
enabled++;
return enabled > 1;
}
static MetaConfiguration *
make_laptop_lid_config (MetaConfiguration *reference)
{
@@ -936,9 +954,9 @@ make_laptop_lid_config (MetaConfiguration *reference)
int x_after, y_after;
int x_offset, y_offset;
g_assert (multiple_outputs_are_enabled (reference));
g_assert (reference->n_outputs > 1);
new = config_new ();
new = g_slice_new0 (MetaConfiguration);
new->n_outputs = reference->n_outputs;
new->keys = g_new0 (MetaOutputKey, reference->n_outputs);
new->outputs = g_new0 (MetaOutputConfig, reference->n_outputs);
@@ -993,32 +1011,6 @@ make_laptop_lid_config (MetaConfiguration *reference)
return new;
}
static gboolean
apply_configuration_with_lid (MetaMonitorConfig *self,
MetaConfiguration *config,
MetaMonitorManager *manager)
{
if (self->lid_is_closed &&
multiple_outputs_are_enabled (config) &&
laptop_display_is_on (config))
{
MetaConfiguration *laptop_lid_config = make_laptop_lid_config (config);
if (apply_configuration (self, laptop_lid_config, manager))
{
self->current_is_for_laptop_lid = TRUE;
config_unref (laptop_lid_config);
return TRUE;
}
else
{
config_unref (laptop_lid_config);
return FALSE;
}
}
else
return apply_configuration (self, config, manager);
}
gboolean
meta_monitor_config_apply_stored (MetaMonitorConfig *self,
MetaMonitorManager *manager)
@@ -1031,7 +1023,23 @@ meta_monitor_config_apply_stored (MetaMonitorConfig *self,
stored = meta_monitor_config_get_stored (self, outputs, n_outputs);
if (stored)
return apply_configuration_with_lid (self, stored, manager);
{
if (self->lid_is_closed &&
stored->n_outputs > 1 &&
laptop_display_is_on (stored))
{
if (apply_configuration (self, make_laptop_lid_config (stored),
manager, FALSE))
{
self->current_is_for_laptop_lid = TRUE;
return TRUE;
}
else
return FALSE;
}
else
return apply_configuration (self, stored, manager, TRUE);
}
else
return FALSE;
}
@@ -1081,21 +1089,6 @@ find_primary_output (MetaOutput *outputs,
return best;
}
static void
init_config_from_preferred_mode (MetaOutputConfig *config,
MetaOutput *output)
{
config->enabled = TRUE;
config->rect.x = 0;
config->rect.y = 0;
config->rect.width = output->preferred_mode->width;
config->rect.height = output->preferred_mode->height;
config->refresh_rate = output->preferred_mode->refresh_rate;
config->transform = META_MONITOR_TRANSFORM_NORMAL;
config->is_primary = FALSE;
config->is_presentation = FALSE;
}
static MetaConfiguration *
make_default_config (MetaMonitorConfig *self,
MetaOutput *outputs,
@@ -1108,7 +1101,7 @@ make_default_config (MetaMonitorConfig *self,
MetaConfiguration *ret;
MetaOutput *primary;
ret = config_new ();
ret = g_slice_new (MetaConfiguration);
make_config_key (ret, outputs, n_outputs, -1);
ret->outputs = g_new0 (MetaOutputConfig, n_outputs);
@@ -1116,8 +1109,15 @@ make_default_config (MetaMonitorConfig *self,
nothing else to do */
if (n_outputs == 1)
{
init_config_from_preferred_mode (&ret->outputs[0], &outputs[0]);
ret->outputs[0].enabled = TRUE;
ret->outputs[0].rect.x = 0;
ret->outputs[0].rect.y = 0;
ret->outputs[0].rect.width = outputs[0].preferred_mode->width;
ret->outputs[0].rect.height = outputs[0].preferred_mode->height;
ret->outputs[0].refresh_rate = outputs[0].preferred_mode->refresh_rate;
ret->outputs[0].transform = META_MONITOR_TRANSFORM_NORMAL;
ret->outputs[0].is_primary = TRUE;
return ret;
}
@@ -1161,7 +1161,15 @@ make_default_config (MetaMonitorConfig *self,
}
else
{
init_config_from_preferred_mode (&ret->outputs[j], &outputs[0]);
ret->outputs[j].enabled = TRUE;
ret->outputs[j].rect.x = 0;
ret->outputs[j].rect.y = 0;
ret->outputs[j].rect.width = outputs[0].preferred_mode->width;
ret->outputs[j].rect.height = outputs[0].preferred_mode->height;
ret->outputs[j].refresh_rate = outputs[0].preferred_mode->refresh_rate;
ret->outputs[j].transform = META_MONITOR_TRANSFORM_NORMAL;
ret->outputs[j].is_primary = FALSE;
ret->outputs[j].is_presentation = FALSE;
}
}
@@ -1186,24 +1194,22 @@ make_default_config (MetaMonitorConfig *self,
x = primary->preferred_mode->width;
for (i = 0; i < n_outputs; i++)
{
gboolean is_primary = (&outputs[i] == primary);
MetaOutput *output = &outputs[i];
init_config_from_preferred_mode (&ret->outputs[i], &outputs[i]);
ret->outputs[i].is_primary = is_primary;
if (is_primary)
{
ret->outputs[i].rect.x = 0;
}
else
{
ret->outputs[i].rect.x = x;
x += ret->outputs[i].rect.width;
}
ret->outputs[i].enabled = TRUE;
ret->outputs[i].rect.x = (output == primary) ? 0 : x;
ret->outputs[i].rect.y = 0;
ret->outputs[i].rect.width = output->preferred_mode->width;
ret->outputs[i].rect.height = output->preferred_mode->height;
ret->outputs[i].refresh_rate = output->preferred_mode->refresh_rate;
ret->outputs[i].transform = META_MONITOR_TRANSFORM_NORMAL;
ret->outputs[i].is_primary = (output == primary);
/* Disable outputs that would go beyond framebuffer limits */
if (ret->outputs[i].rect.x + ret->outputs[i].rect.width > max_width)
ret->outputs[i].enabled = FALSE;
else if (output != primary)
x += output->preferred_mode->width;
}
return ret;
@@ -1215,7 +1221,7 @@ ensure_at_least_one_output (MetaMonitorConfig *self,
MetaOutput *outputs,
unsigned n_outputs)
{
MetaConfiguration *config;
MetaConfiguration *ret;
MetaOutput *primary;
unsigned i;
@@ -1226,29 +1232,34 @@ ensure_at_least_one_output (MetaMonitorConfig *self,
/* Oh no, we don't! Activate the primary one and disable everything else */
config = config_new ();
make_config_key (config, outputs, n_outputs, -1);
config->outputs = g_new0 (MetaOutputConfig, n_outputs);
ret = g_slice_new (MetaConfiguration);
make_config_key (ret, outputs, n_outputs, -1);
ret->outputs = g_new0 (MetaOutputConfig, n_outputs);
primary = find_primary_output (outputs, n_outputs);
for (i = 0; i < n_outputs; i++)
{
gboolean is_primary = (&outputs[i] == primary);
MetaOutput *output = &outputs[i];
if (is_primary)
if (output == primary)
{
init_config_from_preferred_mode (&config->outputs[i], &outputs[0]);
config->outputs[i].is_primary = TRUE;
ret->outputs[i].enabled = TRUE;
ret->outputs[i].rect.x = 0;
ret->outputs[i].rect.y = 0;
ret->outputs[i].rect.width = output->preferred_mode->width;
ret->outputs[i].rect.height = output->preferred_mode->height;
ret->outputs[i].refresh_rate = output->preferred_mode->refresh_rate;
ret->outputs[i].transform = META_MONITOR_TRANSFORM_NORMAL;
ret->outputs[i].is_primary = TRUE;
}
else
{
config->outputs[i].enabled = FALSE;
ret->outputs[i].enabled = FALSE;
}
}
apply_configuration (self, config, manager);
config_unref (config);
apply_configuration (self, ret, manager, FALSE);
return FALSE;
}
@@ -1259,7 +1270,7 @@ meta_monitor_config_make_default (MetaMonitorConfig *self,
MetaOutput *outputs;
MetaConfiguration *default_config;
unsigned n_outputs;
gboolean ok = FALSE;
gboolean ok;
int max_width, max_height;
outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
@@ -1272,11 +1283,22 @@ meta_monitor_config_make_default (MetaMonitorConfig *self,
}
default_config = make_default_config (self, outputs, n_outputs, max_width, max_height);
if (default_config != NULL)
{
ok = apply_configuration_with_lid (self, default_config, manager);
config_unref (default_config);
if (self->lid_is_closed &&
default_config->n_outputs > 1 &&
laptop_display_is_on (default_config))
{
ok = apply_configuration (self, make_laptop_lid_config (default_config),
manager, FALSE);
config_free (default_config);
}
else
ok = apply_configuration (self, default_config, manager, FALSE);
}
else
ok = FALSE;
if (!ok)
{
@@ -1313,7 +1335,7 @@ meta_monitor_config_update_current (MetaMonitorConfig *self,
outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
current = config_new ();
current = g_slice_new (MetaConfiguration);
current->n_outputs = n_outputs;
current->outputs = g_new0 (MetaOutputConfig, n_outputs);
current->keys = g_new0 (MetaOutputKey, n_outputs);
@@ -1326,11 +1348,15 @@ meta_monitor_config_update_current (MetaMonitorConfig *self,
if (self->current && config_equal_full (current, self->current))
{
config_unref (current);
config_free (current);
return;
}
set_current (self, current);
if (self->current && !self->current_is_stored)
config_free (self->current);
self->current = current;
self->current_is_stored = FALSE;
}
void
@@ -1338,17 +1364,7 @@ meta_monitor_config_restore_previous (MetaMonitorConfig *self,
MetaMonitorManager *manager)
{
if (self->previous)
{
/* The user chose to restore the previous configuration. In this
* case, restore the previous configuration. */
MetaConfiguration *prev_config = config_ref (self->previous);
apply_configuration (self, prev_config, manager);
config_unref (prev_config);
/* After this, self->previous contains the rejected configuration.
* Since it was rejected, nuke it. */
g_clear_pointer (&self->previous, (GDestroyNotify) config_unref);
}
apply_configuration (self, self->previous, manager, FALSE);
else
{
if (!meta_monitor_config_apply_stored (self, manager))
@@ -1362,12 +1378,11 @@ turn_off_laptop_display (MetaMonitorConfig *self,
{
MetaConfiguration *new;
if (!multiple_outputs_are_enabled (self->current))
if (self->current->n_outputs == 1)
return;
new = make_laptop_lid_config (self->current);
apply_configuration (self, new, manager);
config_unref (new);
apply_configuration (self, new, manager, FALSE);
self->current_is_for_laptop_lid = TRUE;
}
@@ -1526,7 +1541,16 @@ meta_monitor_config_save (MetaMonitorConfig *self)
void
meta_monitor_config_make_persistent (MetaMonitorConfig *self)
{
g_hash_table_replace (self->configs, self->current, config_ref (self->current));
if (self->current_is_stored)
return;
self->current_is_stored = TRUE;
g_hash_table_replace (self->configs, self->current, self->current);
if (self->previous)
config_free (self->previous);
self->previous = NULL;
meta_monitor_config_save (self);
}

View File

@@ -36,6 +36,9 @@ GType meta_monitor_config_get_type (void) G_GNUC_CONST;
MetaMonitorConfig *meta_monitor_config_new (void);
gboolean meta_monitor_config_match_current (MetaMonitorConfig *config,
MetaMonitorManager *manager);
gboolean meta_monitor_config_apply_stored (MetaMonitorConfig *config,
MetaMonitorManager *manager);

View File

@@ -58,6 +58,14 @@ meta_monitor_manager_init (MetaMonitorManager *manager)
{
}
static void
read_current_config (MetaMonitorManager *manager)
{
manager->serial++;
META_MONITOR_MANAGER_GET_CLASS (manager)->read_current (manager);
}
/*
* make_logical_config:
*
@@ -190,7 +198,7 @@ meta_monitor_manager_constructed (GObject *object)
manager->config = meta_monitor_config_new ();
meta_monitor_manager_read_current_config (manager);
read_current_config (manager);
if (!meta_monitor_config_apply_stored (manager->config, manager))
meta_monitor_config_make_default (manager->config, manager);
@@ -203,7 +211,24 @@ meta_monitor_manager_constructed (GObject *object)
so this is not needed.
*/
if (META_IS_MONITOR_MANAGER_XRANDR (manager))
meta_monitor_manager_read_current_config (manager);
{
MetaOutput *old_outputs;
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
unsigned int n_old_outputs, n_old_modes;
old_outputs = manager->outputs;
n_old_outputs = manager->n_outputs;
old_modes = manager->modes;
n_old_modes = manager->n_modes;
old_crtcs = manager->crtcs;
read_current_config (manager);
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
g_free (old_crtcs);
}
make_logical_config (manager);
initialize_dbus_interface (manager);
@@ -211,7 +236,7 @@ meta_monitor_manager_constructed (GObject *object)
manager->in_init = FALSE;
}
static void
void
meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
int n_old_outputs)
{
@@ -234,7 +259,7 @@ meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
g_free (old_outputs);
}
static void
void
meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
int n_old_modes)
{
@@ -1137,31 +1162,6 @@ meta_monitor_manager_get_screen_limits (MetaMonitorManager *manager,
*height = manager->max_screen_height;
}
void
meta_monitor_manager_read_current_config (MetaMonitorManager *manager)
{
MetaOutput *old_outputs;
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
unsigned int n_old_outputs, n_old_modes;
/* Some implementations of read_current use the existing information
* we have available, so don't free the old configuration until after
* read_current finishes. */
old_outputs = manager->outputs;
n_old_outputs = manager->n_outputs;
old_modes = manager->modes;
n_old_modes = manager->n_modes;
old_crtcs = manager->crtcs;
manager->serial++;
META_MONITOR_MANAGER_GET_CLASS (manager)->read_current (manager);
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
g_free (old_crtcs);
}
void
meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager)
{
@@ -1179,22 +1179,3 @@ meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager)
g_free (old_monitor_infos);
}
void
meta_monitor_manager_on_hotplug (MetaMonitorManager *manager)
{
gboolean applied_config = FALSE;
/* If the monitor has hotplug_mode_update (which is used by VMs), don't bother
* applying our stored configuration, because it's likely the user just resizing
* the window.
*/
if (!meta_monitor_manager_has_hotplug_mode_update (manager))
{
if (meta_monitor_config_apply_stored (manager->config, manager))
applied_config = TRUE;
}
/* If we haven't applied any configuration, apply the default configuration. */
if (!applied_config)
meta_monitor_config_make_default (manager->config, manager);
}

View File

@@ -339,9 +339,11 @@ void meta_monitor_manager_confirm_configuration (MetaMonitorManag
void meta_crtc_info_free (MetaCRTCInfo *info);
void meta_output_info_free (MetaOutputInfo *info);
void meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
int n_old_outputs);
void meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
int n_old_modes);
gboolean meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager);
void meta_monitor_manager_read_current_config (MetaMonitorManager *manager);
void meta_monitor_manager_on_hotplug (MetaMonitorManager *manager);
/* Returns true if transform causes width and height to be inverted
This is true for the odd transforms in the enum */

View File

@@ -28,6 +28,8 @@
#include <meta/meta-backend.h>
#include <meta/util.h>
#define DRAG_FAILED_MSECS 500
typedef struct {
gboolean enabled;
@@ -39,8 +41,20 @@ typedef struct {
gboolean previous_is_valid;
} MetaOverlay;
typedef struct {
MetaStage *stage;
MetaOverlay overlay;
ClutterTimeline *timeline;
int orig_x;
int orig_y;
int dest_x;
int dest_y;
} MetaDragFailedAnimation;
struct _MetaStagePrivate {
MetaOverlay dnd_overlay;
MetaOverlay cursor_overlay;
GList *drag_failed_animations;
};
typedef struct _MetaStagePrivate MetaStagePrivate;
@@ -54,6 +68,15 @@ meta_overlay_init (MetaOverlay *overlay)
overlay->pipeline = cogl_pipeline_new (ctx);
}
static void
meta_overlay_copy (MetaOverlay *src,
MetaOverlay *dst)
{
*dst = *src;
dst->pipeline = cogl_pipeline_copy (src->pipeline);
dst->texture = src->texture;
}
static void
meta_overlay_free (MetaOverlay *overlay)
{
@@ -112,6 +135,7 @@ meta_stage_finalize (GObject *object)
MetaStage *stage = META_STAGE (object);
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
meta_overlay_free (&priv->dnd_overlay);
meta_overlay_free (&priv->cursor_overlay);
}
@@ -120,9 +144,18 @@ meta_stage_paint (ClutterActor *actor)
{
MetaStage *stage = META_STAGE (actor);
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
MetaDragFailedAnimation *animation;
GList *l;
CLUTTER_ACTOR_CLASS (meta_stage_parent_class)->paint (actor);
for (l = priv->drag_failed_animations; l; l = l->next)
{
animation = l->data;
meta_overlay_paint (&animation->overlay);
}
meta_overlay_paint (&priv->dnd_overlay);
meta_overlay_paint (&priv->cursor_overlay);
}
@@ -142,6 +175,7 @@ meta_stage_init (MetaStage *stage)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
meta_overlay_init (&priv->dnd_overlay);
meta_overlay_init (&priv->cursor_overlay);
clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), FALSE);
@@ -183,6 +217,19 @@ queue_redraw_for_overlay (MetaStage *stage,
}
}
void
meta_stage_set_dnd_surface (MetaStage *stage,
CoglTexture *texture,
MetaRectangle *rect)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
g_assert (meta_is_wayland_compositor ());
meta_overlay_set (&priv->dnd_overlay, texture, rect);
queue_redraw_for_overlay (stage, &priv->dnd_overlay);
}
void
meta_stage_set_cursor (MetaStage *stage,
CoglTexture *texture,
@@ -195,3 +242,84 @@ meta_stage_set_cursor (MetaStage *stage,
meta_overlay_set (&priv->cursor_overlay, texture, rect);
queue_redraw_for_overlay (stage, &priv->cursor_overlay);
}
static void
drag_failed_animation_frame_cb (ClutterTimeline *timeline,
guint pos,
gpointer user_data)
{
MetaDragFailedAnimation *data = user_data;
gdouble progress = clutter_timeline_get_progress (timeline);
CoglColor color;
cogl_color_init_from_4f (&color, 0, 0, 0, 1 - progress);
cogl_pipeline_set_layer_combine_constant (data->overlay.pipeline, 0, &color);
data->overlay.current_rect.x = data->orig_x + ((data->dest_x - data->orig_x) * progress);
data->overlay.current_rect.y = data->orig_y + ((data->dest_y - data->orig_y) * progress);
queue_redraw_for_overlay (data->stage, &data->overlay);
}
static void
meta_drag_failed_animation_free (MetaDragFailedAnimation *data)
{
MetaStage *stage = data->stage;
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
priv->drag_failed_animations =
g_list_remove (priv->drag_failed_animations, data);
g_object_unref (data->timeline);
meta_overlay_free (&data->overlay);
g_slice_free (MetaDragFailedAnimation, data);
}
static MetaDragFailedAnimation *
meta_drag_failed_animation_new (MetaStage *stage,
int dest_x,
int dest_y)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
MetaDragFailedAnimation *data;
data = g_slice_new0 (MetaDragFailedAnimation);
data->stage = stage;
data->orig_x = priv->dnd_overlay.current_rect.x;
data->orig_y = priv->dnd_overlay.current_rect.y;
data->dest_x = dest_x;
data->dest_y = dest_y;
meta_overlay_copy (&priv->dnd_overlay, &data->overlay);
data->timeline = clutter_timeline_new (DRAG_FAILED_MSECS);
clutter_timeline_set_progress_mode (data->timeline, CLUTTER_EASE_OUT_CUBIC);
g_signal_connect (data->timeline, "new-frame",
G_CALLBACK (drag_failed_animation_frame_cb), data);
g_signal_connect_swapped (data->timeline, "completed",
G_CALLBACK (meta_drag_failed_animation_free), data);
priv->drag_failed_animations =
g_list_prepend (priv->drag_failed_animations, data);
cogl_pipeline_set_layer_combine (data->overlay.pipeline, 0,
"RGBA = MODULATE (TEXTURE, CONSTANT[A])",
NULL);
return data;
}
void
meta_stage_dnd_failed (MetaStage *stage,
int dest_x,
int dest_y)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
MetaDragFailedAnimation *data;
g_assert (meta_is_wayland_compositor ());
if (!priv->dnd_overlay.enabled)
return;
data = meta_drag_failed_animation_new (stage, dest_x, dest_y);
clutter_timeline_start (data->timeline);
}

View File

@@ -51,9 +51,18 @@ GType meta_stage_get_type (void) G_GNUC_CONST;
ClutterActor *meta_stage_new (void);
void meta_stage_set_dnd_surface (MetaStage *stage,
CoglTexture *texture,
MetaRectangle *rect);
void meta_stage_set_cursor (MetaStage *stage,
CoglTexture *texture,
MetaRectangle *rect);
void meta_stage_dnd_failed (MetaStage *stage,
int dest_x,
int dest_y);
G_END_DECLS
#endif /* META_STAGE_H */

View File

@@ -36,24 +36,11 @@
struct _MetaBackendNativePrivate
{
MetaLauncher *launcher;
GSettings *keyboard_settings;
};
typedef struct _MetaBackendNativePrivate MetaBackendNativePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MetaBackendNative, meta_backend_native, META_TYPE_BACKEND);
static void
meta_backend_native_finalize (GObject *object)
{
MetaBackendNative *native = META_BACKEND_NATIVE (object);
MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
g_clear_object (&priv->keyboard_settings);
G_OBJECT_CLASS (meta_backend_native_parent_class)->finalize (object);
}
/*
* The pointer constrain code is mostly a rip-off of the XRandR code from Xorg.
* (from xserver/randr/rrcrtc.c, RRConstrainCursorHarder)
@@ -155,46 +142,15 @@ pointer_constrain_callback (ClutterInputDevice *device,
constrain_all_screen_monitors(device, monitors, n_monitors, new_x, new_y);
}
static void
set_keyboard_repeat (MetaBackendNative *native)
{
MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
ClutterDeviceManager *manager = clutter_device_manager_get_default ();
gboolean repeat;
unsigned int delay, interval;
repeat = g_settings_get_boolean (priv->keyboard_settings, "repeat");
delay = g_settings_get_uint (priv->keyboard_settings, "delay");
interval = g_settings_get_uint (priv->keyboard_settings, "repeat-interval");
clutter_evdev_set_keyboard_repeat (manager, repeat, delay, interval);
}
static void
keyboard_settings_changed (GSettings *settings,
const char *key,
gpointer data)
{
MetaBackendNative *native = data;
set_keyboard_repeat (native);
}
static void
meta_backend_native_post_init (MetaBackend *backend)
{
MetaBackendNative *native = META_BACKEND_NATIVE (backend);
MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
ClutterDeviceManager *manager = clutter_device_manager_get_default ();
META_BACKEND_CLASS (meta_backend_native_parent_class)->post_init (backend);
clutter_evdev_set_pointer_constrain_callback (manager, pointer_constrain_callback,
NULL, NULL);
priv->keyboard_settings = g_settings_new ("org.gnome.settings-daemon.peripherals.keyboard");
g_signal_connect (priv->keyboard_settings, "changed",
G_CALLBACK (keyboard_settings_changed), native);
set_keyboard_repeat (native);
}
static MetaIdleMonitor *
@@ -280,9 +236,6 @@ static void
meta_backend_native_class_init (MetaBackendNativeClass *klass)
{
MetaBackendClass *backend_class = META_BACKEND_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_backend_native_finalize;
backend_class->post_init = meta_backend_native_post_init;
backend_class->create_idle_monitor = meta_backend_native_create_idle_monitor;
@@ -318,7 +271,7 @@ meta_activate_vt (int vt, GError **error)
* meta_activate_session:
*
* Tells mutter to activate the session. When mutter is a
* display server, this tells logind to switch over to
* Wayland compositor, this tells logind to switch over to
* the new session.
*/
gboolean

View File

@@ -24,7 +24,6 @@
#include "config.h"
#include "meta-monitor-manager-kms.h"
#include "meta-monitor-config.h"
#include <string.h>
#include <stdlib.h>
@@ -41,8 +40,6 @@
#include <meta/errors.h>
#include "edid.h"
#include <gudev/gudev.h>
typedef struct {
drmModeConnector *connector;
@@ -71,8 +68,6 @@ struct _MetaMonitorManagerKms
unsigned int n_encoders;
drmModeEncoder *current_encoder;
GUdevClient *udev;
};
struct _MetaMonitorManagerKmsClass
@@ -898,23 +893,6 @@ meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager,
drmModeCrtcSetGamma (manager_kms->fd, crtc->crtc_id, size, red, green, blue);
}
static void
on_uevent (GUdevClient *client,
const char *action,
GUdevDevice *device,
gpointer user_data)
{
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (user_data);
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
if (!g_udev_device_get_property_as_boolean (device, "HOTPLUG"))
return;
meta_monitor_manager_read_current_config (manager);
meta_monitor_manager_on_hotplug (manager);
}
static void
meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
{
@@ -929,21 +907,6 @@ meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
cogl_renderer = cogl_display_get_renderer (cogl_display);
manager_kms->fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
const char *subsystems[2] = { "drm", NULL };
manager_kms->udev = g_udev_client_new (subsystems);
g_signal_connect (manager_kms->udev, "uevent",
G_CALLBACK (on_uevent), manager_kms);
}
static void
meta_monitor_manager_kms_dispose (GObject *object)
{
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object);
g_clear_object (&manager_kms->udev);
G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->dispose (object);
}
static void
@@ -962,7 +925,6 @@ meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass)
MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = meta_monitor_manager_kms_dispose;
object_class->finalize = meta_monitor_manager_kms_finalize;
manager_class->read_current = meta_monitor_manager_kms_read_current;

View File

@@ -65,14 +65,9 @@ struct _MetaBackendX11Private
uint8_t xkb_error_base;
struct xkb_keymap *keymap;
gchar *keymap_layouts;
gchar *keymap_variants;
gchar *keymap_options;
};
typedef struct _MetaBackendX11Private MetaBackendX11Private;
static void apply_keymap (MetaBackendX11 *x11);
G_DEFINE_TYPE_WITH_PRIVATE (MetaBackendX11, meta_backend_x11, META_TYPE_BACKEND);
static void
@@ -331,17 +326,6 @@ take_touch_grab (MetaBackend *backend)
False, &mask, 1, &mods);
}
static void
on_device_added (ClutterDeviceManager *device_manager,
ClutterInputDevice *device,
gpointer user_data)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (user_data);
if (clutter_input_device_get_device_type (device) == CLUTTER_KEYBOARD_DEVICE)
apply_keymap (x11);
}
static void
meta_backend_x11_post_init (MetaBackend *backend)
{
@@ -392,9 +376,6 @@ meta_backend_x11_post_init (MetaBackend *backend)
meta_fatal ("X server doesn't have the XKB extension, version %d.%d or newer\n",
XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION);
g_signal_connect_object (clutter_device_manager_get_default (), "device-added",
G_CALLBACK (on_device_added), backend, 0);
META_BACKEND_CLASS (meta_backend_x11_parent_class)->post_init (backend);
}
@@ -579,22 +560,21 @@ upload_xkb_description (Display *xdisplay,
}
static void
apply_keymap (MetaBackendX11 *x11)
meta_backend_x11_set_keymap (MetaBackend *backend,
const char *layouts,
const char *variants,
const char *options)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
XkbRF_RulesRec *xkb_rules;
XkbRF_VarDefsRec xkb_var_defs = { 0 };
gchar *rules_file_path;
if (!priv->keymap_layouts ||
!priv->keymap_variants ||
!priv->keymap_options)
return;
get_xkbrf_var_defs (priv->xdisplay,
priv->keymap_layouts,
priv->keymap_variants,
priv->keymap_options,
layouts,
variants,
options,
&rules_file_path,
&xkb_var_defs);
@@ -618,25 +598,6 @@ apply_keymap (MetaBackendX11 *x11)
g_free (rules_file_path);
}
static void
meta_backend_x11_set_keymap (MetaBackend *backend,
const char *layouts,
const char *variants,
const char *options)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
g_free (priv->keymap_layouts);
priv->keymap_layouts = g_strdup (layouts);
g_free (priv->keymap_variants);
priv->keymap_variants = g_strdup (variants);
g_free (priv->keymap_options);
priv->keymap_options = g_strdup (options);
apply_keymap (x11);
}
static struct xkb_keymap *
meta_backend_x11_get_keymap (MetaBackend *backend)
{

View File

@@ -26,8 +26,6 @@
#include "meta-cursor-renderer-x11.h"
#include <X11/extensions/Xfixes.h>
#include "meta-backend-x11.h"
#include "meta-stage.h"

View File

@@ -57,6 +57,7 @@ struct _MetaMonitorManagerXrandr
Display *xdisplay;
XRRScreenResources *resources;
int time;
int rr_event_base;
int rr_error_base;
};
@@ -139,30 +140,6 @@ meta_monitor_transform_from_xrandr_all (Rotation rotation)
return ret;
}
static gboolean
output_get_property_exists (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output, const char *propname)
{
gboolean exists = FALSE;
Atom atom, actual_type;
int actual_format;
unsigned long nitems, bytes_after;
unsigned char *buffer;
atom = XInternAtom (manager_xrandr->xdisplay, propname, False);
XRRGetOutputProperty (manager_xrandr->xdisplay,
(XID)output->winsys_id,
atom,
0, G_MAXLONG, False, False, AnyPropertyType,
&actual_type, &actual_format,
&nitems, &bytes_after, &buffer);
exists = (actual_type != None);
XFree (buffer);
return exists;
}
static gboolean
output_get_boolean_property (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output, const char *propname)
@@ -353,7 +330,7 @@ static gboolean
output_get_hotplug_mode_update (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output)
{
return output_get_property_exists (manager_xrandr, output, "hotplug_mode_update");
return output_get_boolean_property (manager_xrandr, output, "hotplug_mode_update");
}
static char *
@@ -436,6 +413,7 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
return;
manager_xrandr->resources = resources;
manager_xrandr->time = resources->configTimestamp;
manager->n_outputs = resources->noutput;
manager->n_crtcs = resources->ncrtc;
manager->n_modes = resources->nmode;
@@ -769,7 +747,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
XRRSetCrtcConfig (manager_xrandr->xdisplay,
manager_xrandr->resources,
(XID)crtc->crtc_id,
CurrentTime,
manager_xrandr->time,
0, 0,
None,
RR_Rotate_0,
@@ -799,7 +777,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
XRRSetCrtcConfig (manager_xrandr->xdisplay,
manager_xrandr->resources,
(XID)crtc->crtc_id,
CurrentTime,
manager_xrandr->time,
0, 0,
None,
RR_Rotate_0,
@@ -882,7 +860,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
ok = XRRSetCrtcConfig (manager_xrandr->xdisplay,
manager_xrandr->resources,
(XID)crtc->crtc_id,
CurrentTime,
manager_xrandr->time,
crtc_info->x, crtc_info->y,
(XID)mode->mode_id,
meta_monitor_transform_to_xrandr (crtc_info->transform),
@@ -1023,6 +1001,16 @@ meta_monitor_manager_xrandr_set_crtc_gamma (MetaMonitorManager *manager,
XRRFreeGamma (gamma);
}
static void
meta_monitor_manager_xrandr_rebuild_derived (MetaMonitorManager *manager)
{
/* This will be a no-op if the change was from our side, as
we already called it in the DBus method handler */
meta_monitor_config_update_current (manager->config, manager);
meta_monitor_manager_rebuild_derived (manager);
}
static void
meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr)
{
@@ -1082,30 +1070,63 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
XEvent *event)
{
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
gboolean hotplug;
Time old_timestamp;
MetaOutput *old_outputs;
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
unsigned int n_old_outputs, n_old_modes;
gboolean new_config;
if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
return FALSE;
XRRUpdateConfiguration (event);
old_timestamp = manager_xrandr->resources->timestamp;
/* Save the old structures, so they stay valid during the update */
old_outputs = manager->outputs;
n_old_outputs = manager->n_outputs;
old_modes = manager->modes;
n_old_modes = manager->n_modes;
old_crtcs = manager->crtcs;
meta_monitor_manager_read_current_config (manager);
manager->serial++;
meta_monitor_manager_xrandr_read_current (manager);
new_config = manager_xrandr->resources->timestamp >=
manager_xrandr->resources->configTimestamp;
if (meta_monitor_manager_has_hotplug_mode_update (manager))
hotplug = manager_xrandr->resources->timestamp < manager_xrandr->resources->configTimestamp;
if (hotplug)
{
/* This is a hotplug event, so go ahead and build a new configuration. */
meta_monitor_manager_on_hotplug (manager);
/* Check if the current intended configuration is a result of an
XRandR call. Otherwise, hotplug_mode_update tells us to get
a new preferred mode on hotplug events to handle dynamic
guest resizing. */
if (new_config)
meta_monitor_manager_xrandr_rebuild_derived (manager);
else
meta_monitor_config_make_default (manager->config, manager);
}
else
{
/* If something else changed -- tell the world about it. */
if (old_timestamp < manager_xrandr->resources->timestamp)
meta_monitor_manager_rebuild_derived (manager);
/* Check if the current intended configuration has the same outputs
as the new real one, or if the event is a result of an XRandR call.
If so, we can go straight to rebuild the logical config and tell
the outside world.
Otherwise, this event was caused by hotplug, so give a chance to
MetaMonitorConfig.
Note that we need to check both the timestamps and the list of
outputs, because the X server might emit spurious events with new
configTimestamps (bug 702804), and the driver may have changed
the EDID for some other reason (old qxl and vbox drivers). */
if (new_config || meta_monitor_config_match_current (manager->config, manager))
meta_monitor_manager_xrandr_rebuild_derived (manager);
else if (!meta_monitor_config_apply_stored (manager->config, manager))
meta_monitor_config_make_default (manager->config, manager);
}
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
g_free (old_crtcs);
return TRUE;
}

View File

@@ -23,7 +23,7 @@ struct _MetaCompositor
guint server_time_is_monotonic_time : 1;
guint no_mipmaps : 1;
ClutterActor *stage, *window_group, *top_window_group, *feedback_group;
ClutterActor *stage, *window_group, *top_window_group;
ClutterActor *background_actor;
GList *windows;
Window output;

View File

@@ -185,19 +185,6 @@ meta_get_top_window_group_for_screen (MetaScreen *screen)
return compositor->top_window_group;
}
/**
* meta_get_feedback_group_for_screen:
* @screen: a #MetaScreen
*
* Returns: (transfer none): The feedback group corresponding to @screen
*/
ClutterActor *
meta_get_feedback_group_for_screen (MetaScreen *screen)
{
MetaCompositor *compositor = get_compositor_for_screen (screen);
return compositor->feedback_group;
}
/**
* meta_get_window_actors:
* @screen: a #MetaScreen
@@ -491,11 +478,9 @@ meta_compositor_manage (MetaCompositor *compositor)
compositor->window_group = meta_window_group_new (screen);
compositor->top_window_group = meta_window_group_new (screen);
compositor->feedback_group = meta_window_group_new (screen);
clutter_actor_add_child (compositor->stage, compositor->window_group);
clutter_actor_add_child (compositor->stage, compositor->top_window_group);
clutter_actor_add_child (compositor->stage, compositor->feedback_group);
if (meta_is_wayland_compositor ())
{

View File

@@ -708,7 +708,6 @@ on_background_changed (MetaBackground *background,
MetaBackgroundActor *self)
{
invalidate_pipeline (self, CHANGED_BACKGROUND);
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
void

View File

@@ -53,7 +53,7 @@ struct _MetaBackgroundImageCacheClass
struct _MetaBackgroundImage
{
GObject parent_instance;
GFile *file;
char *filename;
MetaBackgroundImageCache *cache;
gboolean in_cache;
gboolean loaded;
@@ -70,7 +70,7 @@ G_DEFINE_TYPE (MetaBackgroundImageCache, meta_background_image_cache, G_TYPE_OBJ
static void
meta_background_image_cache_init (MetaBackgroundImageCache *cache)
{
cache->images = g_hash_table_new (g_file_hash, (GEqualFunc) g_file_equal);
cache->images = g_hash_table_new (g_str_hash, g_str_equal);
}
static void
@@ -124,17 +124,9 @@ load_file (GTask *task,
{
GError *error = NULL;
GdkPixbuf *pixbuf;
GFileInputStream *stream;
stream = g_file_read (image->file, NULL, &error);
if (stream == NULL)
{
g_task_return_error (task, error);
return;
}
pixbuf = gdk_pixbuf_new_from_stream (G_INPUT_STREAM (stream), NULL, &error);
g_object_unref (stream);
pixbuf = gdk_pixbuf_new_from_file (image->filename,
&error);
if (pixbuf == NULL)
{
@@ -164,11 +156,9 @@ file_loaded (GObject *source_object,
if (pixbuf == NULL)
{
char *uri = g_file_get_uri (image->file);
g_warning ("Failed to load background '%s': %s",
uri, error->message);
image->filename, error->message);
g_clear_error (&error);
g_free (uri);
goto out;
}
@@ -205,7 +195,7 @@ out:
/**
* meta_background_image_cache_load:
* @cache: a #MetaBackgroundImageCache
* @file: #GFile to load
* @filename: filename to load
*
* Loads an image to use as a background, or returns a reference to an
* image that is already in the process of loading or loaded. In either
@@ -219,23 +209,23 @@ out:
*/
MetaBackgroundImage *
meta_background_image_cache_load (MetaBackgroundImageCache *cache,
GFile *file)
const char *filename)
{
MetaBackgroundImage *image;
GTask *task;
g_return_val_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache), NULL);
g_return_val_if_fail (file != NULL, NULL);
g_return_val_if_fail (filename != NULL, NULL);
image = g_hash_table_lookup (cache->images, file);
image = g_hash_table_lookup (cache->images, filename);
if (image != NULL)
return g_object_ref (image);
image = g_object_new (META_TYPE_BACKGROUND_IMAGE, NULL);
image->cache = cache;
image->in_cache = TRUE;
image->file = g_object_ref (file);
g_hash_table_insert (cache->images, image->file, image);
image->filename = g_strdup (filename);
g_hash_table_insert (cache->images, image->filename, image);
task = g_task_new (image, NULL, file_loaded, NULL);
@@ -248,25 +238,25 @@ meta_background_image_cache_load (MetaBackgroundImageCache *cache,
/**
* meta_background_image_cache_purge:
* @cache: a #MetaBackgroundImageCache
* @file: file to remove from the cache
* @filename: filename to remove from the cache
*
* Remove an entry from the cache; this would be used if monitoring
* showed that the file changed.
*/
void
meta_background_image_cache_purge (MetaBackgroundImageCache *cache,
GFile *file)
const char *filename)
{
MetaBackgroundImage *image;
g_return_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache));
g_return_if_fail (file != NULL);
g_return_if_fail (filename != NULL);
image = g_hash_table_lookup (cache->images, file);
image = g_hash_table_lookup (cache->images, filename);
if (image == NULL)
return;
g_hash_table_remove (cache->images, image->file);
g_hash_table_remove (cache->images, image->filename);
image->in_cache = FALSE;
}
@@ -283,12 +273,12 @@ meta_background_image_finalize (GObject *object)
MetaBackgroundImage *image = META_BACKGROUND_IMAGE (object);
if (image->in_cache)
g_hash_table_remove (image->cache->images, image->file);
g_hash_table_remove (image->cache->images, image->filename);
if (image->texture)
cogl_object_unref (image->texture);
if (image->file)
g_object_unref (image->file);
if (image->filename)
g_free (image->filename);
G_OBJECT_CLASS (meta_background_image_parent_class)->finalize (object);
}

View File

@@ -50,9 +50,9 @@ struct _MetaBackgroundPrivate
ClutterColor color;
ClutterColor second_color;
GFile *file1;
char *filename1;
MetaBackgroundImage *background_image1;
GFile *file2;
char *filename2;
MetaBackgroundImage *background_image2;
CoglTexture *color_texture;
@@ -241,28 +241,16 @@ on_background_loaded (MetaBackgroundImage *image,
mark_changed (self);
}
static gboolean
file_equal0 (GFile *file1,
GFile *file2)
{
if (file1 == file2)
return TRUE;
if ((file1 == NULL) || (file2 == NULL))
return FALSE;
return g_file_equal (file1, file2);
}
static void
set_file (MetaBackground *self,
GFile **filep,
MetaBackgroundImage **imagep,
GFile *file)
set_filename (MetaBackground *self,
char **filenamep,
MetaBackgroundImage **imagep,
const char *filename)
{
if (!file_equal0 (*filep, file))
if (g_strcmp0 (filename, *filenamep) != 0)
{
g_clear_object (filep);
g_free (*filenamep);
*filenamep = g_strdup (filename);
if (*imagep)
{
@@ -273,12 +261,10 @@ set_file (MetaBackground *self,
*imagep = NULL;
}
if (file)
if (filename)
{
MetaBackgroundImageCache *cache = meta_background_image_cache_get_default ();
*filep = g_object_ref (file);
*imagep = meta_background_image_cache_load (cache, file);
*imagep = meta_background_image_cache_load (cache, filename);
g_signal_connect (*imagep, "loaded",
G_CALLBACK (on_background_loaded), self);
}
@@ -294,8 +280,8 @@ meta_background_dispose (GObject *object)
free_color_texture (self);
free_wallpaper_texture (self);
set_file (self, &priv->file1, &priv->background_image1, NULL);
set_file (self, &priv->file2, &priv->background_image2, NULL);
set_filename (self, &priv->filename1, &priv->background_image1, NULL);
set_filename (self, &priv->filename2, &priv->background_image2, NULL);
set_screen (self, NULL);
@@ -881,19 +867,19 @@ meta_background_set_gradient (MetaBackground *self,
}
void
meta_background_set_file (MetaBackground *self,
GFile *file,
GDesktopBackgroundStyle style)
meta_background_set_filename (MetaBackground *self,
const char *filename,
GDesktopBackgroundStyle style)
{
g_return_if_fail (META_IS_BACKGROUND (self));
meta_background_set_blend (self, file, NULL, 0.0, style);
meta_background_set_blend (self, filename, NULL, 0.0, style);
}
void
meta_background_set_blend (MetaBackground *self,
GFile *file1,
GFile *file2,
const char *filename1,
const char *filename2,
double blend_factor,
GDesktopBackgroundStyle style)
{
@@ -904,8 +890,8 @@ meta_background_set_blend (MetaBackground *self,
priv = self->priv;
set_file (self, &priv->file1, &priv->background_image1, file1);
set_file (self, &priv->file2, &priv->background_image2, file2);
set_filename (self, &priv->filename1, &priv->background_image1, filename1);
set_filename (self, &priv->filename2, &priv->background_image2, filename2);
priv->blend_factor = blend_factor;
priv->style = style;

View File

@@ -1,64 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* meta-dnd-actor-private.h: Actor for painting the DnD surface
*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef META_DND_ACTOR_PRIVATE_H
#define META_DND_ACTOR_PRIVATE_H
#include "meta-feedback-actor-private.h"
/**
* MetaDnDActor:
*
* This class handles the rendering of the DnD surface
*/
#define META_TYPE_DND_ACTOR (meta_dnd_actor_get_type ())
#define META_DND_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_DND_ACTOR, MetaDnDActor))
#define META_DND_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_DND_ACTOR, MetaDnDActorClass))
#define META_IS_DND_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_DND_ACTOR))
#define META_IS_DND_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_DND_ACTOR))
#define META_DND_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_DND_ACTOR, MetaDnDActorClass))
typedef struct _MetaDnDActor MetaDnDActor;
typedef struct _MetaDnDActorClass MetaDnDActorClass;
struct _MetaDnDActorClass
{
/*< private >*/
MetaFeedbackActorClass parent_class;
};
struct _MetaDnDActor
{
MetaFeedbackActor parent;
};
GType meta_dnd_actor_get_type (void);
ClutterActor *meta_dnd_actor_new (ClutterActor *drag_origin,
int start_x,
int start_y);
void meta_dnd_actor_drag_finish (MetaDnDActor *self,
gboolean success);
#endif /* META_DND_ACTOR_PRIVATE_H */

View File

@@ -1,231 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
/**
* SECTION:meta-dnd-actor
* @title: MetaDnDActor
* @short_description: Actor for painting the drag and drop surface
*
*/
#include <config.h>
#include <clutter/clutter.h>
#include "meta-dnd-actor-private.h"
#define DRAG_FAILED_DURATION 500
enum {
PROP_DRAG_ORIGIN = 1,
PROP_DRAG_START_X,
PROP_DRAG_START_Y
};
typedef struct _MetaDnDActorPrivate MetaDnDActorPrivate;
struct _MetaDnDActorPrivate
{
ClutterActor *drag_origin;
int drag_start_x;
int drag_start_y;
};
G_DEFINE_TYPE_WITH_PRIVATE (MetaDnDActor, meta_dnd_actor, META_TYPE_FEEDBACK_ACTOR)
static void
meta_dnd_actor_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaDnDActor *self = META_DND_ACTOR (object);
MetaDnDActorPrivate *priv = meta_dnd_actor_get_instance_private (self);
switch (prop_id)
{
case PROP_DRAG_ORIGIN:
priv->drag_origin = g_value_get_object (value);
break;
case PROP_DRAG_START_X:
priv->drag_start_x = g_value_get_int (value);
break;
case PROP_DRAG_START_Y:
priv->drag_start_y = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_dnd_actor_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaDnDActor *self = META_DND_ACTOR (object);
MetaDnDActorPrivate *priv = meta_dnd_actor_get_instance_private (self);
switch (prop_id)
{
case PROP_DRAG_ORIGIN:
g_value_set_object (value, priv->drag_origin);
break;
case PROP_DRAG_START_X:
g_value_set_int (value, priv->drag_start_x);
break;
case PROP_DRAG_START_Y:
g_value_set_int (value, priv->drag_start_y);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_dnd_actor_class_init (MetaDnDActorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
object_class->set_property = meta_dnd_actor_set_property;
object_class->get_property = meta_dnd_actor_get_property;
pspec = g_param_spec_object ("drag-origin",
"Drag origin",
"The origin of the DnD operation",
CLUTTER_TYPE_ACTOR,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (object_class,
PROP_DRAG_ORIGIN,
pspec);
pspec = g_param_spec_int ("drag-start-x",
"Drag start X",
"The X axis of the drag start point",
0, G_MAXINT, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (object_class,
PROP_DRAG_START_X,
pspec);
pspec = g_param_spec_int ("drag-start-y",
"Drag start Y",
"The Y axis of the drag start point",
0, G_MAXINT, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (object_class,
PROP_DRAG_START_Y,
pspec);
}
static void
meta_dnd_actor_init (MetaDnDActor *self)
{
}
/**
* meta_dnd_actor_new:
*
* Creates a new actor to draw the current drag and drop surface.
*
* Return value: the newly created background actor
*/
ClutterActor *
meta_dnd_actor_new (ClutterActor *drag_origin,
int drag_start_x,
int drag_start_y)
{
MetaDnDActor *self;
self = g_object_new (META_TYPE_DND_ACTOR,
"drag-origin", drag_origin,
"drag-start-x", drag_start_x,
"drag-start-y", drag_start_y,
NULL);
return CLUTTER_ACTOR (self);
}
static void
drag_failed_complete (ClutterTimeline *timeline,
gboolean is_finished,
gpointer user_data)
{
ClutterActor *self = user_data;
clutter_actor_remove_all_children (self);
clutter_actor_destroy (self);
}
void
meta_dnd_actor_drag_finish (MetaDnDActor *self,
gboolean success)
{
MetaDnDActorPrivate *priv;
ClutterActor *actor;
g_return_if_fail (META_IS_DND_ACTOR (self));
actor = CLUTTER_ACTOR (self);
priv = meta_dnd_actor_get_instance_private (self);
if (success)
{
clutter_actor_remove_all_children (CLUTTER_ACTOR (self));
clutter_actor_destroy (CLUTTER_ACTOR (self));
}
else
{
ClutterTransition *transition;
clutter_actor_save_easing_state (actor);
clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
clutter_actor_set_easing_duration (actor, DRAG_FAILED_DURATION);
clutter_actor_set_opacity (actor, 0);
if (CLUTTER_ACTOR_IS_VISIBLE (priv->drag_origin))
{
int anchor_x, anchor_y;
ClutterPoint dest;
clutter_actor_get_transformed_position (priv->drag_origin,
&dest.x, &dest.y);
meta_feedback_actor_get_anchor (META_FEEDBACK_ACTOR (self),
&anchor_x, &anchor_y);
dest.x += priv->drag_start_x - anchor_x;
dest.y += priv->drag_start_y - anchor_y;
clutter_actor_set_position (actor, dest.x, dest.y);
}
transition = clutter_actor_get_transition (actor, "opacity");
g_signal_connect (transition, "stopped",
G_CALLBACK (drag_failed_complete), self);
clutter_actor_restore_easing_state (actor);
}
}

View File

@@ -1,74 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* meta-feedback-actor-private.h: Actor for painting user interaction feedback
*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef META_FEEDBACK_ACTOR_PRIVATE_H
#define META_FEEDBACK_ACTOR_PRIVATE_H
#include <clutter/clutter.h>
/**
* MetaFeedbackActor:
*
* This class handles the rendering of user interaction feedback
*/
#define META_TYPE_FEEDBACK_ACTOR (meta_feedback_actor_get_type ())
#define META_FEEDBACK_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_FEEDBACK_ACTOR, MetaFeedbackActor))
#define META_FEEDBACK_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_FEEDBACK_ACTOR, MetaFeedbackActorClass))
#define META_IS_FEEDBACK_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_FEEDBACK_ACTOR))
#define META_IS_FEEDBACK_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_FEEDBACK_ACTOR))
#define META_FEEDBACK_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_FEEDBACK_ACTOR, MetaFeedbackActorClass))
typedef struct _MetaFeedbackActor MetaFeedbackActor;
typedef struct _MetaFeedbackActorClass MetaFeedbackActorClass;
struct _MetaFeedbackActorClass
{
/*< private >*/
ClutterActorClass parent_class;
};
struct _MetaFeedbackActor
{
ClutterActor parent;
};
GType meta_feedback_actor_get_type (void);
ClutterActor *meta_feedback_actor_new (int anchor_x,
int anchor_y);
void meta_feedback_actor_set_anchor (MetaFeedbackActor *actor,
int anchor_x,
int anchor_y);
void meta_feedback_actor_get_anchor (MetaFeedbackActor *actor,
int *anchor_x,
int *anchor_y);
void meta_feedback_actor_set_position (MetaFeedbackActor *self,
int x,
int y);
void meta_feedback_actor_update (MetaFeedbackActor *self,
const ClutterEvent *event);
#endif /* META_FEEDBACK_ACTOR_PRIVATE_H */

View File

@@ -1,249 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
/**
* SECTION:meta-feedback-actor
* @title: MetaFeedbackActor
* @short_description: Actor for painting user interaction feedback
*/
#include <config.h>
#include "display-private.h"
#include "compositor-private.h"
#include "meta-feedback-actor-private.h"
enum {
PROP_ANCHOR_X = 1,
PROP_ANCHOR_Y
};
typedef struct _MetaFeedbackActorPrivate MetaFeedbackActorPrivate;
struct _MetaFeedbackActorPrivate
{
int anchor_x;
int anchor_y;
int pos_x;
int pos_y;
};
G_DEFINE_TYPE_WITH_PRIVATE (MetaFeedbackActor, meta_feedback_actor, CLUTTER_TYPE_ACTOR)
static void
meta_feedback_actor_constructed (GObject *object)
{
MetaDisplay *display;
display = meta_get_display ();
clutter_actor_add_child (display->compositor->feedback_group,
CLUTTER_ACTOR (object));
}
static void
meta_feedback_actor_update_position (MetaFeedbackActor *self)
{
MetaFeedbackActorPrivate *priv = meta_feedback_actor_get_instance_private (self);
clutter_actor_set_position (CLUTTER_ACTOR (self),
priv->pos_x - priv->anchor_x,
priv->pos_y - priv->anchor_y);
}
static void
meta_feedback_actor_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaFeedbackActor *self = META_FEEDBACK_ACTOR (object);
MetaFeedbackActorPrivate *priv = meta_feedback_actor_get_instance_private (self);
switch (prop_id)
{
case PROP_ANCHOR_X:
priv->anchor_x = g_value_get_int (value);
meta_feedback_actor_update_position (self);
break;
case PROP_ANCHOR_Y:
priv->anchor_y = g_value_get_int (value);
meta_feedback_actor_update_position (self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_feedback_actor_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaFeedbackActor *self = META_FEEDBACK_ACTOR (object);
MetaFeedbackActorPrivate *priv = meta_feedback_actor_get_instance_private (self);
switch (prop_id)
{
case PROP_ANCHOR_X:
g_value_set_int (value, priv->anchor_x);
break;
case PROP_ANCHOR_Y:
g_value_set_int (value, priv->anchor_y);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_feedback_actor_class_init (MetaFeedbackActorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
object_class->constructed = meta_feedback_actor_constructed;
object_class->set_property = meta_feedback_actor_set_property;
object_class->get_property = meta_feedback_actor_get_property;
pspec = g_param_spec_int ("anchor-x",
"Anchor X",
"The X axis of the anchor point",
0, G_MAXINT, 0,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_ANCHOR_X,
pspec);
pspec = g_param_spec_int ("anchor-y",
"Anchor Y",
"The Y axis of the anchor point",
0, G_MAXINT, 0,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_ANCHOR_Y,
pspec);
}
static void
meta_feedback_actor_init (MetaFeedbackActor *self)
{
clutter_actor_set_reactive (CLUTTER_ACTOR (self), FALSE);
}
/**
* meta_feedback_actor_new:
*
* Creates a new actor to draw the current drag and drop surface.
*
* Return value: the newly created background actor
*/
ClutterActor *
meta_feedback_actor_new (int anchor_x,
int anchor_y)
{
MetaFeedbackActor *self;
self = g_object_new (META_TYPE_FEEDBACK_ACTOR,
"anchor-x", anchor_x,
"anchor-y", anchor_y,
NULL);
return CLUTTER_ACTOR (self);
}
void
meta_feedback_actor_set_anchor (MetaFeedbackActor *self,
int anchor_x,
int anchor_y)
{
MetaFeedbackActorPrivate *priv;
g_return_if_fail (META_IS_FEEDBACK_ACTOR (self));
priv = meta_feedback_actor_get_instance_private (self);
if (priv->anchor_x == anchor_x && priv->anchor_y == anchor_y)
return;
if (priv->anchor_x != anchor_y)
{
priv->anchor_x = anchor_x;
g_object_notify (G_OBJECT (self), "anchor-x");
}
if (priv->anchor_y != anchor_y)
{
priv->anchor_y = anchor_y;
g_object_notify (G_OBJECT (self), "anchor-y");
}
meta_feedback_actor_update_position (self);
}
void
meta_feedback_actor_get_anchor (MetaFeedbackActor *self,
int *anchor_x,
int *anchor_y)
{
MetaFeedbackActorPrivate *priv;
g_return_if_fail (META_IS_FEEDBACK_ACTOR (self));
priv = meta_feedback_actor_get_instance_private (self);
if (anchor_x)
*anchor_x = priv->anchor_x;
if (anchor_y)
*anchor_y = priv->anchor_y;
}
void
meta_feedback_actor_set_position (MetaFeedbackActor *self,
int x,
int y)
{
MetaFeedbackActorPrivate *priv;
g_return_if_fail (META_IS_FEEDBACK_ACTOR (self));
priv = meta_feedback_actor_get_instance_private (self);
priv->pos_x = x;
priv->pos_y = y;
meta_feedback_actor_update_position (self);
}
void
meta_feedback_actor_update (MetaFeedbackActor *self,
const ClutterEvent *event)
{
ClutterPoint point;
g_return_if_fail (META_IS_FEEDBACK_ACTOR (self));
g_return_if_fail (event != NULL);
clutter_event_get_position (event, &point);
meta_feedback_actor_set_position (self, point.x, point.y);
}

View File

@@ -34,9 +34,4 @@ void meta_shaped_texture_set_texture (MetaShapedTexture *stex,
CoglTexture *texture);
gboolean meta_shaped_texture_is_obscured (MetaShapedTexture *self);
void meta_shaped_texture_set_viewport (MetaShapedTexture *stex,
cairo_rectangle_int_t *src_rect,
int dest_width,
int dest_height);
#endif

View File

@@ -85,12 +85,7 @@ struct _MetaShapedTexturePrivate
cairo_region_t *clip_region;
cairo_region_t *unobscured_region;
/* Viewport stuff */
cairo_rectangle_int_t viewport_src_rect;
guint viewport_dest_width, viewport_dest_height;
guint tex_width, tex_height;
guint dest_width, dest_height;
guint create_mipmaps : 1;
};
@@ -141,7 +136,7 @@ set_unobscured_region (MetaShapedTexture *self,
g_clear_pointer (&priv->unobscured_region, (GDestroyNotify) cairo_region_destroy);
if (unobscured_region)
{
cairo_rectangle_int_t bounds = { 0, 0, priv->dest_width, priv->dest_height };
cairo_rectangle_int_t bounds = { 0, 0, priv->tex_width, priv->tex_height };
priv->unobscured_region = cairo_region_copy (unobscured_region);
cairo_region_intersect_rectangle (priv->unobscured_region, &bounds);
}
@@ -217,45 +212,24 @@ get_unblended_pipeline (CoglContext *ctx)
return cogl_pipeline_copy (template);
}
static void
scale_coords_by_src (cairo_rectangle_int_t *coords,
int dest_width, int dest_height,
cairo_rectangle_int_t *src_rect)
{
if (src_rect->width == 0 && src_rect->height == 0)
return;
coords->x = ((coords->x / dest_width) * src_rect->width) + src_rect->x;
coords->y = ((coords->y / dest_height) * src_rect->height) + src_rect->y;
coords->width = ((coords->width / dest_width) * src_rect->width);
coords->height = ((coords->height / dest_height) * src_rect->height);
}
static void
paint_clipped_rectangle (CoglFramebuffer *fb,
CoglPipeline *pipeline,
cairo_rectangle_int_t *rect,
ClutterActorBox *alloc,
cairo_rectangle_int_t *src_rect)
ClutterActorBox *alloc)
{
cairo_rectangle_int_t pixel_coords;
float coords[8];
float x1, y1, x2, y2;
float dest_width = alloc->x2 - alloc->x1;
float dest_height = alloc->y2 - alloc->y1;
x1 = rect->x;
y1 = rect->y;
x2 = rect->x + rect->width;
y2 = rect->y + rect->height;
pixel_coords = *rect;
scale_coords_by_src (&pixel_coords, dest_width, dest_height, src_rect);
coords[0] = pixel_coords.x / dest_width;
coords[1] = pixel_coords.y / dest_height;
coords[2] = (pixel_coords.x + pixel_coords.width) / dest_width;
coords[3] = (pixel_coords.y + pixel_coords.height) / dest_height;
coords[0] = rect->x / (alloc->x2 - alloc->x1);
coords[1] = rect->y / (alloc->y2 - alloc->y1);
coords[2] = (rect->x + rect->width) / (alloc->x2 - alloc->x1);
coords[3] = (rect->y + rect->height) / (alloc->y2 - alloc->y1);
coords[4] = coords[0];
coords[5] = coords[1];
@@ -267,32 +241,6 @@ paint_clipped_rectangle (CoglFramebuffer *fb,
&coords[0], 8);
}
static void
update_size (MetaShapedTexture *stex)
{
MetaShapedTexturePrivate *priv = stex->priv;
guint dest_width, dest_height;
if (priv->viewport_dest_width > 0)
dest_width = priv->viewport_dest_width;
else
dest_width = priv->tex_width;
if (priv->viewport_dest_height > 0)
dest_height = priv->viewport_dest_height;
else
dest_height = priv->tex_height;
if (priv->dest_width != dest_width ||
priv->dest_height != dest_height)
{
priv->dest_width = dest_width;
priv->dest_height = dest_height;
clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
g_signal_emit (stex, signals[SIZE_CHANGED], 0);
}
}
static void
set_cogl_texture (MetaShapedTexture *stex,
CoglTexture *cogl_tex)
@@ -326,7 +274,8 @@ set_cogl_texture (MetaShapedTexture *stex,
{
priv->tex_width = width;
priv->tex_height = height;
update_size (stex);
clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
g_signal_emit (stex, signals[SIZE_CHANGED], 0);
}
/* NB: We don't queue a redraw of the actor here because we don't
@@ -343,7 +292,7 @@ meta_shaped_texture_paint (ClutterActor *actor)
{
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
MetaShapedTexturePrivate *priv = stex->priv;
guint dest_width, dest_height;
guint tex_width, tex_height;
guchar opacity;
CoglContext *ctx;
CoglFramebuffer *fb;
@@ -380,13 +329,13 @@ meta_shaped_texture_paint (ClutterActor *actor)
if (paint_tex == NULL)
return;
dest_width = priv->dest_width;
dest_height = priv->dest_height;
tex_width = priv->tex_width;
tex_height = priv->tex_height;
if (dest_width == 0 || dest_height == 0) /* no contents yet */
if (tex_width == 0 || tex_height == 0) /* no contents yet */
return;
cairo_rectangle_int_t tex_rect = { 0, 0, dest_width, dest_height };
cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height };
/* Use nearest-pixel interpolation if the texture is unscaled. This
* improves performance, especially with software rendering.
@@ -469,7 +418,7 @@ meta_shaped_texture_paint (ClutterActor *actor)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
paint_clipped_rectangle (fb, opaque_pipeline, &rect, &alloc, &priv->viewport_src_rect);
paint_clipped_rectangle (fb, opaque_pipeline, &rect, &alloc);
}
cogl_object_unref (opaque_pipeline);
@@ -524,13 +473,16 @@ meta_shaped_texture_paint (ClutterActor *actor)
if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect))
continue;
paint_clipped_rectangle (fb, blended_pipeline, &rect, &alloc, &priv->viewport_src_rect);
paint_clipped_rectangle (fb, blended_pipeline, &rect, &alloc);
}
}
else
{
/* 3) blended_region is NULL. Do a full paint. */
paint_clipped_rectangle (fb, blended_pipeline, &tex_rect, &alloc, &priv->viewport_src_rect);
cogl_framebuffer_draw_rectangle (fb, blended_pipeline,
0, 0,
alloc.x2 - alloc.x1,
alloc.y2 - alloc.y1);
}
cogl_object_unref (blended_pipeline);
@@ -553,10 +505,10 @@ meta_shaped_texture_get_preferred_width (ClutterActor *self,
priv = META_SHAPED_TEXTURE (self)->priv;
if (min_width_p)
*min_width_p = priv->dest_width;
*min_width_p = priv->tex_width;
if (natural_width_p)
*natural_width_p = priv->dest_width;
*natural_width_p = priv->tex_width;
}
static void
@@ -572,10 +524,10 @@ meta_shaped_texture_get_preferred_height (ClutterActor *self,
priv = META_SHAPED_TEXTURE (self)->priv;
if (min_height_p)
*min_height_p = priv->dest_height;
*min_height_p = priv->tex_height;
if (natural_height_p)
*natural_height_p = priv->dest_height;
*natural_height_p = priv->tex_height;
}
static cairo_region_t *
@@ -810,22 +762,6 @@ meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex,
priv->opaque_region = NULL;
}
void
meta_shaped_texture_set_viewport (MetaShapedTexture *stex,
cairo_rectangle_int_t *src_rect,
int dest_width,
int dest_height)
{
MetaShapedTexturePrivate *priv = stex->priv;
priv->viewport_src_rect = *src_rect;
priv->viewport_dest_width = dest_width;
priv->viewport_dest_height = dest_height;
update_size (stex);
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
}
/**
* meta_shaped_texture_get_image:
* @stex: A #MetaShapedTexture

View File

@@ -193,8 +193,8 @@ meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor,
MetaRectangle window_rect;
meta_window_get_frame_rect (priv->window, &window_rect);
if (x == 0 &&
y == 0 &&
if (window_rect.x == x &&
window_rect.y == y &&
window_rect.width == width &&
window_rect.height == height)
priv->full_damage_frames_count++;
@@ -383,7 +383,6 @@ window_decorated_notify (MetaWindow *window,
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (user_data);
detach_pixmap (self);
free_damage (self);
create_damage (self);
}

View File

@@ -65,8 +65,6 @@ meta_surface_actor_pick (ClutterActor *actor,
CoglContext *ctx;
CoglFramebuffer *fb;
CoglColor cogl_color;
ClutterActorIter iter;
ClutterActor *child;
n_rects = cairo_region_num_rectangles (priv->input_region);
rectangles = g_alloca (sizeof (float) * 4 * n_rects);
@@ -93,11 +91,6 @@ meta_surface_actor_pick (ClutterActor *actor,
cogl_pipeline_set_color (pipeline, &cogl_color);
cogl_framebuffer_draw_rectangles (fb, pipeline, rectangles, n_rects);
cogl_object_unref (pipeline);
clutter_actor_iter_init (&iter, actor);
while (clutter_actor_iter_next (&iter, &child))
clutter_actor_paint (child);
}
}
@@ -235,16 +228,6 @@ meta_surface_actor_set_opaque_region (MetaSurfaceActor *self,
meta_shaped_texture_set_opaque_region (priv->texture, region);
}
void
meta_surface_actor_set_viewport (MetaSurfaceActor *self,
cairo_rectangle_int_t *src_rect,
int dest_width,
int dest_height)
{
MetaSurfaceActorPrivate *priv = self->priv;
meta_shaped_texture_set_viewport (priv->texture, src_rect, dest_width, dest_height);
}
static gboolean
is_frozen (MetaSurfaceActor *self)
{

View File

@@ -61,11 +61,6 @@ void meta_surface_actor_set_input_region (MetaSurfaceActor *self,
void meta_surface_actor_set_opaque_region (MetaSurfaceActor *self,
cairo_region_t *region);
void meta_surface_actor_set_viewport (MetaSurfaceActor *self,
cairo_rectangle_int_t *src_rect,
int dest_width,
int dest_height);
void meta_surface_actor_process_damage (MetaSurfaceActor *actor,
int x, int y, int width, int height);
void meta_surface_actor_pre_paint (MetaSurfaceActor *actor);

View File

@@ -295,7 +295,7 @@ on_monitors_changed (MetaScreen *screen,
{
MetaDefaultPlugin *self = META_DEFAULT_PLUGIN (plugin);
int i, n;
GRand *rand = g_rand_new_with_seed (123456);
GRand *rand = g_rand_new_with_seed (12345);
clutter_actor_destroy_all_children (self->priv->background_group);

View File

@@ -1007,7 +1007,7 @@ meta_display_list_windows (MetaDisplay *display,
{
MetaWindow *window = value;
if (!META_IS_WINDOW (window) || window->unmanaging)
if (!META_IS_WINDOW (window))
continue;
if (!window->override_redirect ||
@@ -1020,7 +1020,7 @@ meta_display_list_windows (MetaDisplay *display,
{
MetaWindow *window = value;
if (!META_IS_WINDOW (window) || window->unmanaging)
if (!META_IS_WINDOW (window))
continue;
if (!window->override_redirect ||
@@ -1965,7 +1965,7 @@ meta_display_end_grab_op (MetaDisplay *display,
* beginning of the grab_op.
*/
if (!meta_prefs_get_raise_on_click () &&
!display->grab_threshold_movement_reached)
display->grab_threshold_movement_reached)
meta_window_raise (display->grab_window);
meta_window_grab_op_ended (grab_window, grab_op);
@@ -2440,22 +2440,13 @@ meta_display_get_tab_list (MetaDisplay *display,
mru_list = workspace ? workspace->mru_list : global_mru_list;
/* Windows sellout mode - MRU order. Collect unminimized windows
* then minimized so minimized windows aren't in the way so much.
/* Windows sellout mode - MRU order.
*/
for (tmp = mru_list; tmp; tmp = tmp->next)
{
MetaWindow *window = tmp->data;
if (!window->minimized && IN_TAB_CHAIN (window, type))
tab_list = g_list_prepend (tab_list, window);
}
for (tmp = mru_list; tmp; tmp = tmp->next)
{
MetaWindow *window = tmp->data;
if (window->minimized && IN_TAB_CHAIN (window, type))
if (IN_TAB_CHAIN (window, type))
tab_list = g_list_prepend (tab_list, window);
}

View File

@@ -28,7 +28,6 @@
#include "display-private.h"
#include "window-private.h"
#include "backends/x11/meta-backend-x11.h"
#include "backends/meta-cursor-tracker-private.h"
#ifdef HAVE_NATIVE_BACKEND
#include "backends/native/meta-backend-native.h"
@@ -36,6 +35,7 @@
#endif
#ifdef HAVE_WAYLAND
#include "backends/meta-cursor-tracker-private.h"
#include "wayland/meta-wayland-private.h"
#endif
#include "meta-surface-actor.h"
@@ -151,6 +151,23 @@ sequence_is_pointer_emulated (MetaDisplay *display,
return FALSE;
}
static void
meta_display_update_pointer_emulating_sequence (MetaDisplay *display,
const ClutterEvent *event)
{
ClutterEventSequence *sequence;
sequence = clutter_event_get_event_sequence (event);
if (event->type == CLUTTER_TOUCH_BEGIN &&
!display->pointer_emulating_sequence &&
sequence_is_pointer_emulated (display, event))
display->pointer_emulating_sequence = sequence;
else if (event->type == CLUTTER_TOUCH_END &&
display->pointer_emulating_sequence == sequence)
display->pointer_emulating_sequence = NULL;
}
static gboolean
meta_display_handle_event (MetaDisplay *display,
const ClutterEvent *event)
@@ -159,15 +176,8 @@ meta_display_handle_event (MetaDisplay *display,
gboolean bypass_clutter = FALSE;
G_GNUC_UNUSED gboolean bypass_wayland = FALSE;
MetaGestureTracker *tracker;
ClutterEventSequence *sequence;
sequence = clutter_event_get_event_sequence (event);
/* Set the pointer emulating sequence on touch begin, if eligible */
if (event->type == CLUTTER_TOUCH_BEGIN &&
!display->pointer_emulating_sequence &&
sequence_is_pointer_emulated (display, event))
display->pointer_emulating_sequence = sequence;
meta_display_update_pointer_emulating_sequence (display, event);
#ifdef HAVE_WAYLAND
MetaWaylandCompositor *compositor = NULL;
@@ -304,11 +314,6 @@ meta_display_handle_event (MetaDisplay *display,
}
#endif
/* Unset the pointer emulating sequence after its end event is processed */
if (event->type == CLUTTER_TOUCH_END &&
display->pointer_emulating_sequence == sequence)
display->pointer_emulating_sequence = NULL;
display->current_time = CurrentTime;
return bypass_clutter;
}

View File

@@ -1660,14 +1660,13 @@ meta_window_ungrab_all_keys (MetaWindow *window, guint32 timestamp)
}
void
meta_display_freeze_keyboard (MetaDisplay *display, guint32 timestamp)
meta_display_freeze_keyboard (MetaDisplay *display, Window window, guint32 timestamp)
{
MetaBackend *backend = meta_get_backend ();
if (!META_IS_BACKEND_X11 (backend))
return;
Window window = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend));
grab_keyboard (window, timestamp, XIGrabModeSync);
}
@@ -2956,6 +2955,10 @@ do_choose_window (MetaDisplay *display,
meta_topic (META_DEBUG_KEYBINDINGS,
"Tab list = %u\n", type);
/* reverse direction if shift is down */
if (event->modifier_state & CLUTTER_SHIFT_MASK)
backward = !backward;
window = meta_display_get_tab_next (display,
type,
screen->active_workspace,

View File

@@ -3021,32 +3021,38 @@ static gboolean
check_fullscreen_func (gpointer data)
{
MetaScreen *screen = data;
MetaWindow *window;
GSList *windows;
GSList *tmp;
GSList *fullscreen_monitors = NULL;
GSList *obscured_monitors = NULL;
gboolean in_fullscreen_changed = FALSE;
int i;
screen->check_fullscreen_later = 0;
/* We consider a monitor in fullscreen if it contains a fullscreen window;
* however we make an exception for maximized windows above the fullscreen
* one, as in that case window+chrome fully obscure the fullscreen window.
*/
for (window = meta_stack_get_top (screen->stack);
window;
window = meta_stack_get_below (screen->stack, window, FALSE))
windows = meta_display_list_windows (screen->display,
META_LIST_INCLUDE_OVERRIDE_REDIRECT);
for (tmp = windows; tmp != NULL; tmp = tmp->next)
{
MetaWindow *window = tmp->data;
gboolean covers_monitors = FALSE;
if (window->screen != screen || window->hidden)
continue;
if (window->fullscreen)
{
covers_monitors = TRUE;
}
else if (window->override_redirect)
/* The checks for determining a fullscreen window's layer are quite
* elaborate, and we do a poor job at keeping it dynamically up-to-date.
* (It depends, for example, on whether the focus window is on the
* same monitor as the fullscreen window.) But because we minimize
* fullscreen windows not in LAYER_FULLSCREEN (see below), if the
* layer is stale here, it's really bad, so just force recomputation for
* here. This is expensive, but hopefully this function won't be
* called too often.
*/
meta_window_update_layer (window);
if (window->override_redirect)
{
/* We want to handle the case where an application is creating an
* override-redirect window the size of the screen (monitor) and treat
@@ -3056,14 +3062,10 @@ check_fullscreen_func (gpointer data)
if (meta_window_is_monitor_sized (window))
covers_monitors = TRUE;
}
else if (window->maximized_horizontally &&
window->maximized_vertically)
else
{
int monitor_index = meta_window_get_monitor (window);
/* + 1 to avoid NULL */
gpointer monitor_p = GINT_TO_POINTER(monitor_index + 1);
if (!g_slist_find (obscured_monitors, monitor_p))
obscured_monitors = g_slist_prepend (obscured_monitors, monitor_p);
if (window->layer == META_LAYER_FULLSCREEN)
covers_monitors = TRUE;
}
if (covers_monitors)
@@ -3077,16 +3079,30 @@ check_fullscreen_func (gpointer data)
{
/* + 1 to avoid NULL */
gpointer monitor_p = GINT_TO_POINTER(monitors[j] + 1);
if (!g_slist_find (fullscreen_monitors, monitor_p) &&
!g_slist_find (obscured_monitors, monitor_p))
if (!g_slist_find (fullscreen_monitors, monitor_p))
fullscreen_monitors = g_slist_prepend (fullscreen_monitors, monitor_p);
}
g_free (monitors);
}
/* If we find a window that is fullscreen but not in the FULLSCREEN
* layer, it means that we've kicked it out of the layer because
* we've focused another window on the same monitor. In this case
* it would be confusing to keep the window fullscreen and visible,
* so minimize it. We can't do the same thing for override-redirect
* windows, so we just hope the application does the right thing.
*/
if (!covers_monitors && window->fullscreen)
{
meta_window_minimize (window);
meta_topic (META_DEBUG_WINDOW_OPS,
"Minimizing %s: was fullscreen but in a lower layer\n",
window->desc);
}
}
g_slist_free (obscured_monitors);
g_slist_free (windows);
for (i = 0; i < screen->n_monitor_infos; i++)
{

View File

@@ -2622,9 +2622,6 @@ meta_window_maximize_internal (MetaWindow *window,
meta_window_recalc_features (window);
set_net_wm_state (window);
if (window->monitor->in_fullscreen)
meta_screen_queue_check_fullscreen (window->screen);
g_object_freeze_notify (G_OBJECT (window));
g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_MAXIMIZED_HORIZONTALLY]);
g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_MAXIMIZED_VERTICALLY]);
@@ -3069,8 +3066,6 @@ meta_window_unmaximize_internal (MetaWindow *window,
meta_window_recalc_features (window);
set_net_wm_state (window);
if (!window->monitor->in_fullscreen)
meta_screen_queue_check_fullscreen (window->screen);
}
g_object_freeze_notify (G_OBJECT (window));
@@ -4657,32 +4652,6 @@ meta_window_appears_focused_changed (MetaWindow *window)
meta_frame_queue_draw (window->frame);
}
static gboolean
should_propagate_focus_appearance (MetaWindow *window)
{
/* Parents of attached modal dialogs should appear focused. */
if (meta_window_is_attached_dialog (window))
return TRUE;
/* Parents of these sorts of override-redirect windows should
* appear focused. */
switch (window->type)
{
case META_WINDOW_DROPDOWN_MENU:
case META_WINDOW_POPUP_MENU:
case META_WINDOW_COMBO:
case META_WINDOW_TOOLTIP:
case META_WINDOW_NOTIFICATION:
case META_WINDOW_DND:
case META_WINDOW_OVERRIDE_OTHER:
return TRUE;
default:
break;
}
return FALSE;
}
/**
* meta_window_propagate_focus_appearance:
* @window: the window to start propagating from
@@ -4706,7 +4675,7 @@ meta_window_propagate_focus_appearance (MetaWindow *window,
child = window;
parent = meta_window_get_transient_for (child);
while (parent && (!focused || should_propagate_focus_appearance (child)))
while (parent && (!focused || meta_window_is_attached_dialog (child)))
{
gboolean child_focus_state_changed;
@@ -5851,7 +5820,7 @@ update_resize (MetaWindow *window,
int new_w, new_h;
int gravity;
MetaRectangle old;
double remaining = 0;
double remaining;
MetaMaximizeFlags new_unmaximize;
window->display->grab_latest_motion_x = x;
@@ -6110,8 +6079,10 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window,
case CLUTTER_BUTTON_RELEASE:
if (event->button.button == 1 ||
event->button.button == (unsigned int) meta_prefs_get_mouse_button_resize ())
end_grab_op (window, event);
{
end_grab_op (window, event);
return FALSE;
}
return TRUE;
case CLUTTER_TOUCH_BEGIN:

View File

@@ -180,6 +180,13 @@ meta_workspace_new (MetaScreen *screen)
workspace->windows = NULL;
workspace->mru_list = NULL;
/* make sure sticky windows are in our mru_list */
windows = meta_display_list_windows (screen->display, META_LIST_SORTED);
for (l = windows; l; l = l->next)
if (meta_window_located_on_workspace (l->data, workspace))
meta_workspace_add_window (workspace, l->data);
g_slist_free (windows);
workspace->work_areas_invalid = TRUE;
workspace->work_area_monitor = NULL;
workspace->work_area_screen.x = 0;
@@ -198,13 +205,6 @@ meta_workspace_new (MetaScreen *screen)
workspace->showing_desktop = FALSE;
/* make sure sticky windows are in our mru_list */
windows = meta_display_list_windows (screen->display, META_LIST_SORTED);
for (l = windows; l; l = l->next)
if (meta_window_located_on_workspace (l->data, workspace))
meta_workspace_add_window (workspace, l->data);
g_slist_free (windows);
return workspace;
}

View File

@@ -37,7 +37,6 @@ Window meta_get_overlay_window (MetaScreen *screen);
GList *meta_get_window_actors (MetaScreen *screen);
ClutterActor *meta_get_window_group_for_screen (MetaScreen *screen);
ClutterActor *meta_get_top_window_group_for_screen (MetaScreen *screen);
ClutterActor *meta_get_feedback_group_for_screen (MetaScreen *screen);
void meta_disable_unredirect_for_screen (MetaScreen *screen);
void meta_enable_unredirect_for_screen (MetaScreen *screen);

View File

@@ -173,6 +173,7 @@ void meta_display_unmanage_screen (MetaDisplay *display,
void meta_display_clear_mouse_mode (MetaDisplay *display);
void meta_display_freeze_keyboard (MetaDisplay *display,
Window window,
guint32 timestamp);
void meta_display_ungrab_keyboard (MetaDisplay *display,
guint32 timestamp);

71
src/meta/gradient.h Normal file
View File

@@ -0,0 +1,71 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter gradient rendering */
/*
* Copyright (C) 2001 Havoc Pennington, 99% copied from wrlib in
* WindowMaker, Copyright (C) 1997-2000 Dan Pascu and Alfredo Kojima
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>. */
#ifndef META_GRADIENT_H
#define META_GRADIENT_H
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gdk/gdk.h>
/**
* MetaGradientType:
* @META_GRADIENT_VERTICAL: Vertical gradient
* @META_GRADIENT_HORIZONTAL: Horizontal gradient
* @META_GRADIENT_DIAGONAL: Diagonal gradient
* @META_GRADIENT_LAST: Marks the end of the #MetaGradientType enumeration
*
*/
typedef enum
{
META_GRADIENT_VERTICAL,
META_GRADIENT_HORIZONTAL,
META_GRADIENT_DIAGONAL,
META_GRADIENT_LAST
} MetaGradientType;
GdkPixbuf* meta_gradient_create_simple (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to,
MetaGradientType style);
GdkPixbuf* meta_gradient_create_multi (int width,
int height,
const GdkRGBA *colors,
int n_colors,
MetaGradientType style);
GdkPixbuf* meta_gradient_create_interwoven (int width,
int height,
const GdkRGBA colors1[2],
int thickness1,
const GdkRGBA colors2[2],
int thickness2);
/* Generate an alpha gradient and multiply it with the existing alpha
* channel of the given pixbuf
*/
void meta_gradient_add_alpha (GdkPixbuf *pixbuf,
const guchar *alphas,
int n_alphas,
MetaGradientType type);
#endif

View File

@@ -69,8 +69,8 @@ MetaBackgroundImageCache *meta_background_image_cache_get_default (void);
GType meta_background_image_cache_get_type (void);
MetaBackgroundImage *meta_background_image_cache_load (MetaBackgroundImageCache *cache,
GFile *file);
const char *filename);
void meta_background_image_cache_purge (MetaBackgroundImageCache *cache,
GFile *file);
const char *filename);
#endif /* __META_BACKGROUND_IMAGE_H__ */

View File

@@ -67,12 +67,12 @@ void meta_background_set_gradient (MetaBackground *self,
GDesktopBackgroundShading shading_direction,
ClutterColor *color,
ClutterColor *second_color);
void meta_background_set_file (MetaBackground *self,
GFile *file,
void meta_background_set_filename (MetaBackground *self,
const char *filename,
GDesktopBackgroundStyle style);
void meta_background_set_blend (MetaBackground *self,
GFile *file1,
GFile *file2,
const char *filename1,
const char *filename2,
double blend_factor,
GDesktopBackgroundStyle style);

View File

@@ -573,7 +573,6 @@ meta_frames_manage_window (MetaFrames *frames,
frame->title = NULL;
frame->shape_applied = FALSE;
frame->prelit_control = META_FRAME_CONTROL_NONE;
frame->button_state = META_BUTTON_STATE_NORMAL;
meta_core_grab_buttons (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);

902
src/ui/gradient.c Normal file
View File

@@ -0,0 +1,902 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2001 Havoc Pennington, 99% copied from wrlib in
* WindowMaker, Copyright (C) 1997-2000 Dan Pascu and Alfredo Kojima
* Copyright (C) 2005 Elijah Newren
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>. */
/**
* SECTION:gradient
* @title: Gradients
* @short_description: Metacity gradient rendering
*/
#include <meta/gradient.h>
#include <meta/util.h>
#include <string.h>
/* This is all Alfredo's and Dan's usual very nice WindowMaker code,
* slightly GTK-ized
*/
static GdkPixbuf* meta_gradient_create_horizontal (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to);
static GdkPixbuf* meta_gradient_create_vertical (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to);
static GdkPixbuf* meta_gradient_create_diagonal (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to);
static GdkPixbuf* meta_gradient_create_multi_horizontal (int width,
int height,
const GdkRGBA *colors,
int count);
static GdkPixbuf* meta_gradient_create_multi_vertical (int width,
int height,
const GdkRGBA *colors,
int count);
static GdkPixbuf* meta_gradient_create_multi_diagonal (int width,
int height,
const GdkRGBA *colors,
int count);
/* Used as the destroy notification function for gdk_pixbuf_new() */
static void
free_buffer (guchar *pixels, gpointer data)
{
g_free (pixels);
}
static GdkPixbuf*
blank_pixbuf (int width, int height)
{
guchar *buf;
int rowstride;
g_return_val_if_fail (width > 0, NULL);
g_return_val_if_fail (height > 0, NULL);
/* Always align rows to 32-bit boundaries */
rowstride = 4 * ((4 * width + 4) / 4);
buf = g_try_malloc (height * rowstride);
if (!buf)
return NULL;
return gdk_pixbuf_new_from_data (buf, GDK_COLORSPACE_RGB,
TRUE, 8,
width, height, rowstride,
free_buffer, NULL);
}
/**
* meta_gradient_create_simple:
* @width: Width in pixels
* @height: Height in pixels
* @from: Starting color
* @to: Ending color
* @style: Gradient style
*
* Returns: (transfer full): A new linear gradient
*/
GdkPixbuf*
meta_gradient_create_simple (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to,
MetaGradientType style)
{
switch (style)
{
case META_GRADIENT_HORIZONTAL:
return meta_gradient_create_horizontal (width, height,
from, to);
case META_GRADIENT_VERTICAL:
return meta_gradient_create_vertical (width, height,
from, to);
case META_GRADIENT_DIAGONAL:
return meta_gradient_create_diagonal (width, height,
from, to);
case META_GRADIENT_LAST:
break;
}
g_assert_not_reached ();
return NULL;
}
/**
* meta_gradient_create_multi:
* @width: Width in pixels
* @height: Height in pixels
* @colors: (array length=n_colors): Array of colors
* @n_colors: Number of colors
* @style: Gradient style
*
* Returns: (transfer full): A new multi-step linear gradient
*/
GdkPixbuf*
meta_gradient_create_multi (int width,
int height,
const GdkRGBA *colors,
int n_colors,
MetaGradientType style)
{
if (n_colors > 2)
{
switch (style)
{
case META_GRADIENT_HORIZONTAL:
return meta_gradient_create_multi_horizontal (width, height, colors, n_colors);
case META_GRADIENT_VERTICAL:
return meta_gradient_create_multi_vertical (width, height, colors, n_colors);
case META_GRADIENT_DIAGONAL:
return meta_gradient_create_multi_diagonal (width, height, colors, n_colors);
case META_GRADIENT_LAST:
g_assert_not_reached ();
break;
}
}
else if (n_colors > 1)
{
return meta_gradient_create_simple (width, height, &colors[0], &colors[1],
style);
}
else if (n_colors > 0)
{
return meta_gradient_create_simple (width, height, &colors[0], &colors[0],
style);
}
g_assert_not_reached ();
return NULL;
}
/**
* meta_gradient_create_interwoven: (skip)
* @width: Width in pixels
* @height: Height in pixels
* @colors1: Array of colors
* @thickness1: Thickness
* @colors2: Array of colors
* @thickness2: Thickness
*
* Interwoven essentially means we have two vertical gradients,
* cut into horizontal strips of the given thickness, and then the strips
* are alternated. I'm not sure what it's good for, just copied since
* WindowMaker had it.
*/
GdkPixbuf*
meta_gradient_create_interwoven (int width,
int height,
const GdkRGBA colors1[2],
int thickness1,
const GdkRGBA colors2[2],
int thickness2)
{
int i, j, k, l, ll;
long r1, g1, b1, a1, dr1, dg1, db1, da1;
long r2, g2, b2, a2, dr2, dg2, db2, da2;
GdkPixbuf *pixbuf;
unsigned char *ptr;
unsigned char *pixels;
int rowstride;
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
r1 = (long)(colors1[0].red*0xffffff);
g1 = (long)(colors1[0].green*0xffffff);
b1 = (long)(colors1[0].blue*0xffffff);
a1 = (long)(colors1[0].alpha*0xffffff);
r2 = (long)(colors2[0].red*0xffffff);
g2 = (long)(colors2[0].green*0xffffff);
b2 = (long)(colors2[0].blue*0xffffff);
a2 = (long)(colors2[0].alpha*0xffffff);
dr1 = ((colors1[1].red-colors1[0].red)*0xffffff)/(int)height;
dg1 = ((colors1[1].green-colors1[0].green)*0xffffff)/(int)height;
db1 = ((colors1[1].blue-colors1[0].blue)*0xffffff)/(int)height;
da1 = ((colors1[1].alpha-colors1[0].alpha)*0xffffff)/(int)height;
dr2 = ((colors2[1].red-colors2[0].red)*0xffffff)/(int)height;
dg2 = ((colors2[1].green-colors2[0].green)*0xffffff)/(int)height;
db2 = ((colors2[1].blue-colors2[0].blue)*0xffffff)/(int)height;
da2 = ((colors2[1].alpha-colors2[0].alpha)*0xffffff)/(int)height;
for (i=0,k=0,l=0,ll=thickness1; i<height; i++)
{
ptr = pixels + i * rowstride;
if (k == 0)
{
ptr[0] = (unsigned char) (r1>>16);
ptr[1] = (unsigned char) (g1>>16);
ptr[2] = (unsigned char) (b1>>16);
ptr[3] = (unsigned char) (a1>>16);
}
else
{
ptr[0] = (unsigned char) (r2>>16);
ptr[1] = (unsigned char) (g2>>16);
ptr[2] = (unsigned char) (b2>>16);
ptr[3] = (unsigned char) (a2>>16);
}
for (j=1; j <= width/2; j *= 2)
memcpy (&(ptr[j*4]), ptr, j*4);
memcpy (&(ptr[j*4]), ptr, (width - j)*4);
if (++l == ll)
{
if (k == 0)
{
k = 1;
ll = thickness2;
}
else
{
k = 0;
ll = thickness1;
}
l = 0;
}
r1+=dr1;
g1+=dg1;
b1+=db1;
a1+=da1;
r2+=dr2;
g2+=dg2;
b2+=db2;
a2+=da2;
}
return pixbuf;
}
/*
*----------------------------------------------------------------------
* meta_gradient_create_horizontal--
* Renders a horizontal linear gradient of the specified size in the
* GdkPixbuf format with a border of the specified type.
*
* Returns:
* A 24bit GdkPixbuf with the gradient (no alpha channel).
*
* Side effects:
* None
*----------------------------------------------------------------------
*/
static GdkPixbuf*
meta_gradient_create_horizontal (int width, int height,
const GdkRGBA *from,
const GdkRGBA *to)
{
int i;
long r, g, b, a, dr, dg, db, da;
GdkPixbuf *pixbuf;
unsigned char *ptr;
unsigned char *pixels;
int r0, g0, b0, a0;
int rf, gf, bf, af;
int rowstride;
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
ptr = pixels;
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
r0 = (guchar) (from->red * 0xff);
g0 = (guchar) (from->green * 0xff);
b0 = (guchar) (from->blue * 0xff);
a0 = (guchar) (from->alpha * 0xff);
rf = (guchar) (to->red * 0xff);
gf = (guchar) (to->green * 0xff);
bf = (guchar) (to->blue * 0xff);
af = (guchar) (to->alpha * 0xff);
r = r0 << 16;
g = g0 << 16;
b = b0 << 16;
a = a0 << 16;
dr = ((rf-r0)<<16)/(int)width;
dg = ((gf-g0)<<16)/(int)width;
db = ((bf-b0)<<16)/(int)width;
da = ((af-a0)<<16)/(int)width;
/* render the first line */
for (i=0; i<width; i++)
{
*(ptr++) = (unsigned char)(r>>16);
*(ptr++) = (unsigned char)(g>>16);
*(ptr++) = (unsigned char)(b>>16);
*(ptr++) = (unsigned char)(a>>16);
r += dr;
g += dg;
b += db;
a += da;
}
/* copy the first line to the other lines */
for (i=1; i<height; i++)
{
memcpy (&(pixels[i*rowstride]), pixels, rowstride);
}
return pixbuf;
}
/*
*----------------------------------------------------------------------
* meta_gradient_create_vertical--
* Renders a vertical linear gradient of the specified size in the
* GdkPixbuf format with a border of the specified type.
*
* Returns:
* A 24bit GdkPixbuf with the gradient (no alpha channel).
*
* Side effects:
* None
*----------------------------------------------------------------------
*/
static GdkPixbuf*
meta_gradient_create_vertical (int width, int height,
const GdkRGBA *from,
const GdkRGBA *to)
{
int i, j;
long r, g, b, a, dr, dg, db, da;
GdkPixbuf *pixbuf;
unsigned char *ptr;
int r0, g0, b0, a0;
int rf, gf, bf, af;
int rowstride;
unsigned char *pixels;
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
r0 = (guchar) (from->red * 0xff);
g0 = (guchar) (from->green * 0xff);
b0 = (guchar) (from->blue * 0xff);
a0 = (guchar) (from->alpha * 0xff);
rf = (guchar) (to->red * 0xff);
gf = (guchar) (to->green * 0xff);
bf = (guchar) (to->blue * 0xff);
af = (guchar) (to->alpha * 0xff);
r = r0<<16;
g = g0<<16;
b = b0<<16;
a = a0<<16;
dr = ((rf-r0)<<16)/(int)height;
dg = ((gf-g0)<<16)/(int)height;
db = ((bf-b0)<<16)/(int)height;
da = ((af-a0)<<16)/(int)height;
for (i=0; i<height; i++)
{
ptr = pixels + i * rowstride;
ptr[0] = (unsigned char)(r>>16);
ptr[1] = (unsigned char)(g>>16);
ptr[2] = (unsigned char)(b>>16);
ptr[3] = (unsigned char)(a>>16);
for (j=1; j <= width/2; j *= 2)
memcpy (&(ptr[j*4]), ptr, j*4);
memcpy (&(ptr[j*4]), ptr, (width - j)*4);
r+=dr;
g+=dg;
b+=db;
a+=da;
}
return pixbuf;
}
/*
*----------------------------------------------------------------------
* meta_gradient_create_diagonal--
* Renders a diagonal linear gradient of the specified size in the
* GdkPixbuf format with a border of the specified type.
*
* Returns:
* A 24bit GdkPixbuf with the gradient (no alpha channel).
*
* Side effects:
* None
*----------------------------------------------------------------------
*/
static GdkPixbuf*
meta_gradient_create_diagonal (int width, int height,
const GdkRGBA *from,
const GdkRGBA *to)
{
GdkPixbuf *pixbuf, *tmp;
int j;
float a, offset;
unsigned char *ptr;
unsigned char *pixels;
int rowstride;
if (width == 1)
return meta_gradient_create_vertical (width, height, from, to);
else if (height == 1)
return meta_gradient_create_horizontal (width, height, from, to);
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
tmp = meta_gradient_create_horizontal (2*width-1, 1, from, to);
if (!tmp)
{
g_object_unref (G_OBJECT (pixbuf));
return NULL;
}
ptr = gdk_pixbuf_get_pixels (tmp);
a = ((float)(width - 1))/((float)(height - 1));
width = width * 4;
/* copy the first line to the other lines with corresponding offset */
for (j=0, offset=0.0; j<rowstride*height; j += rowstride)
{
memcpy (&(pixels[j]), &ptr[4*(int)offset], width);
offset += a;
}
g_object_unref (G_OBJECT (tmp));
return pixbuf;
}
static GdkPixbuf*
meta_gradient_create_multi_horizontal (int width, int height,
const GdkRGBA *colors,
int count)
{
int i, j, k;
long r, g, b, a, dr, dg, db, da;
GdkPixbuf *pixbuf;
unsigned char *ptr;
unsigned char *pixels;
int width2;
int rowstride;
g_return_val_if_fail (count > 2, NULL);
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
ptr = pixels;
if (count > width)
count = width;
if (count > 1)
width2 = width/(count-1);
else
width2 = width;
k = 0;
r = (long)(colors[0].red * 0xffffff);
g = (long)(colors[0].green * 0xffffff);
b = (long)(colors[0].blue * 0xffffff);
a = (long)(colors[0].alpha * 0xffffff);
/* render the first line */
for (i=1; i<count; i++)
{
dr = (int)((colors[i].red - colors[i-1].red) *0xffffff)/(int)width2;
dg = (int)((colors[i].green - colors[i-1].green)*0xffffff)/(int)width2;
db = (int)((colors[i].blue - colors[i-1].blue) *0xffffff)/(int)width2;
da = (int)((colors[i].alpha - colors[i-1].alpha) *0xffffff)/(int)width2;
for (j=0; j<width2; j++)
{
*ptr++ = (unsigned char)(r>>16);
*ptr++ = (unsigned char)(g>>16);
*ptr++ = (unsigned char)(b>>16);
*ptr++ = (unsigned char)(a>>16);
r += dr;
g += dg;
b += db;
a += da;
k++;
}
r = (long)(colors[i].red * 0xffffff);
g = (long)(colors[i].green * 0xffffff);
b = (long)(colors[i].blue * 0xffffff);
a = (long)(colors[i].alpha * 0xffffff);
}
for (j=k; j<width; j++)
{
*ptr++ = (unsigned char)(r>>16);
*ptr++ = (unsigned char)(g>>16);
*ptr++ = (unsigned char)(b>>16);
*ptr++ = (unsigned char)(a>>16);
}
/* copy the first line to the other lines */
for (i=1; i<height; i++)
{
memcpy (&(pixels[i*rowstride]), pixels, rowstride);
}
return pixbuf;
}
static GdkPixbuf*
meta_gradient_create_multi_vertical (int width, int height,
const GdkRGBA *colors,
int count)
{
int i, j, k;
long r, g, b, a, dr, dg, db, da;
GdkPixbuf *pixbuf;
unsigned char *ptr, *tmp, *pixels;
int height2;
int x;
int rowstride;
g_return_val_if_fail (count > 2, NULL);
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
ptr = pixels;
if (count > height)
count = height;
if (count > 1)
height2 = height/(count-1);
else
height2 = height;
k = 0;
r = (long)(colors[0].red * 0xffffff);
g = (long)(colors[0].green * 0xffffff);
b = (long)(colors[0].blue * 0xffffff);
a = (long)(colors[0].alpha * 0xffffff);
for (i=1; i<count; i++)
{
dr = (int)((colors[i].red - colors[i-1].red) *0xffffff)/(int)height2;
dg = (int)((colors[i].green - colors[i-1].green)*0xffffff)/(int)height2;
db = (int)((colors[i].blue - colors[i-1].blue) *0xffffff)/(int)height2;
da = (int)((colors[i].alpha - colors[i-1].alpha) *0xffffff)/(int)height2;
for (j=0; j<height2; j++)
{
ptr[0] = (unsigned char)(r>>16);
ptr[1] = (unsigned char)(g>>16);
ptr[2] = (unsigned char)(b>>16);
ptr[3] = (unsigned char)(a>>16);
for (x=1; x <= width/2; x *= 2)
memcpy (&(ptr[x*4]), ptr, x*4);
memcpy (&(ptr[x*4]), ptr, (width - x)*4);
ptr += rowstride;
r += dr;
g += dg;
b += db;
a += da;
k++;
}
r = (long)(colors[i].red * 0xffffff);
g = (long)(colors[i].green * 0xffffff);
b = (long)(colors[i].blue * 0xffffff);
a = (long)(colors[i].alpha * 0xffffff);
}
if (k<height)
{
tmp = ptr;
ptr[0] = (unsigned char) (r>>16);
ptr[1] = (unsigned char) (g>>16);
ptr[2] = (unsigned char) (b>>16);
ptr[3] = (unsigned char) (a>>16);
for (x=1; x <= width/2; x *= 2)
memcpy (&(ptr[x*4]), ptr, x*4);
memcpy (&(ptr[x*4]), ptr, (width - x)*4);
ptr += rowstride;
for (j=k+1; j<height; j++)
{
memcpy (ptr, tmp, rowstride);
ptr += rowstride;
}
}
return pixbuf;
}
static GdkPixbuf*
meta_gradient_create_multi_diagonal (int width, int height,
const GdkRGBA *colors,
int count)
{
GdkPixbuf *pixbuf, *tmp;
float a, offset;
int j;
unsigned char *ptr;
unsigned char *pixels;
int rowstride;
g_return_val_if_fail (count > 2, NULL);
if (width == 1)
return meta_gradient_create_multi_vertical (width, height, colors, count);
else if (height == 1)
return meta_gradient_create_multi_horizontal (width, height, colors, count);
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
if (count > width)
count = width;
if (count > height)
count = height;
if (count > 2)
tmp = meta_gradient_create_multi_horizontal (2*width-1, 1, colors, count);
else
/* wrlib multiplies these colors by 256 before passing them in, but
* I think it's a bug in wrlib, so changed here. I could be wrong
* though, if we notice two-color multi diagonals not working.
*/
tmp = meta_gradient_create_horizontal (2*width-1, 1,
&colors[0], &colors[1]);
if (!tmp)
{
g_object_unref (G_OBJECT (pixbuf));
return NULL;
}
ptr = gdk_pixbuf_get_pixels (tmp);
a = ((float)(width - 1))/((float)(height - 1));
width = width * 3;
/* copy the first line to the other lines with corresponding offset */
for (j=0, offset=0; j<rowstride*height; j += rowstride)
{
memcpy (&(pixels[j]), &ptr[3*(int)offset], width);
offset += a;
}
g_object_unref (G_OBJECT (tmp));
return pixbuf;
}
static void
simple_multiply_alpha (GdkPixbuf *pixbuf,
guchar alpha)
{
guchar *pixels;
int rowstride;
int height;
int row;
g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
if (alpha == 255)
return;
g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
row = 0;
while (row < height)
{
guchar *p;
guchar *end;
p = pixels + row * rowstride;
end = p + rowstride;
while (p != end)
{
p += 3; /* skip RGB */
/* multiply the two alpha channels. not sure this is right.
* but some end cases are that if the pixbuf contains 255,
* then it should be modified to contain "alpha"; if the
* pixbuf contains 0, it should remain 0.
*/
/* ((*p / 255.0) * (alpha / 255.0)) * 255; */
*p = (guchar) (((int) *p * (int) alpha) / (int) 255);
++p; /* skip A */
}
++row;
}
}
static void
meta_gradient_add_alpha_horizontal (GdkPixbuf *pixbuf,
const unsigned char *alphas,
int n_alphas)
{
int i, j;
long a, da;
unsigned char *p;
unsigned char *pixels;
int width2;
int rowstride;
int width, height;
unsigned char *gradient;
unsigned char *gradient_p;
unsigned char *gradient_end;
g_return_if_fail (n_alphas > 0);
if (n_alphas == 1)
{
/* Optimize this */
simple_multiply_alpha (pixbuf, alphas[0]);
return;
}
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
gradient = g_new (unsigned char, width);
gradient_end = gradient + width;
if (n_alphas > width)
n_alphas = width;
if (n_alphas > 1)
width2 = width / (n_alphas - 1);
else
width2 = width;
a = alphas[0] << 8;
gradient_p = gradient;
/* render the gradient into an array */
for (i = 1; i < n_alphas; i++)
{
da = (((int)(alphas[i] - (int) alphas[i-1])) << 8) / (int) width2;
for (j = 0; j < width2; j++)
{
*gradient_p++ = (a >> 8);
a += da;
}
a = alphas[i] << 8;
}
/* get leftover pixels */
while (gradient_p != gradient_end)
{
*gradient_p++ = a >> 8;
}
/* Now for each line of the pixbuf, fill in with the gradient */
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
p = pixels;
i = 0;
while (i < height)
{
unsigned char *row_end = p + rowstride;
gradient_p = gradient;
p += 3;
while (gradient_p != gradient_end)
{
/* multiply the two alpha channels. not sure this is right.
* but some end cases are that if the pixbuf contains 255,
* then it should be modified to contain "alpha"; if the
* pixbuf contains 0, it should remain 0.
*/
/* ((*p / 255.0) * (alpha / 255.0)) * 255; */
*p = (guchar) (((int) *p * (int) *gradient_p) / (int) 255);
p += 4;
++gradient_p;
}
p = row_end;
++i;
}
g_free (gradient);
}
void
meta_gradient_add_alpha (GdkPixbuf *pixbuf,
const guchar *alphas,
int n_alphas,
MetaGradientType type)
{
g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
g_return_if_fail (gdk_pixbuf_get_has_alpha (pixbuf));
g_return_if_fail (n_alphas > 0);
switch (type)
{
case META_GRADIENT_HORIZONTAL:
meta_gradient_add_alpha_horizontal (pixbuf, alphas, n_alphas);
break;
case META_GRADIENT_VERTICAL:
g_printerr ("metacity: vertical alpha channel gradient not implemented yet\n");
break;
case META_GRADIENT_DIAGONAL:
g_printerr ("metacity: diagonal alpha channel gradient not implemented yet\n");
break;
case META_GRADIENT_LAST:
g_assert_not_reached ();
break;
}
}

315
src/ui/testgradient.c Normal file
View File

@@ -0,0 +1,315 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter gradient test program */
/*
* Copyright (C) 2002 Havoc Pennington
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>. */
#include <meta/gradient.h>
#include <gtk/gtk.h>
typedef void (* RenderGradientFunc) (cairo_t *cr,
int width,
int height);
static void
draw_checkerboard (cairo_t *cr,
int width,
int height)
{
gint i, j, xcount, ycount;
GdkRGBA color1, color2;
#define CHECK_SIZE 10
#define SPACING 2
color1.red = 30000. / 65535.;
color1.green = 30000. / 65535.;
color1.blue = 30000. / 65535.;
color1.alpha = 1.0;
color2.red = 50000. / 65535.;
color2.green = 50000. / 65535.;
color2.blue = 50000. / 65535.;
color2.alpha = 1.0;
xcount = 0;
i = SPACING;
while (i < width)
{
j = SPACING;
ycount = xcount % 2; /* start with even/odd depending on row */
while (j < height)
{
if (ycount % 2)
gdk_cairo_set_source_rgba (cr, &color1);
else
gdk_cairo_set_source_rgba (cr, &color2);
/* If we're outside event->area, this will do nothing.
* It might be mildly more efficient if we handled
* the clipping ourselves, but again we're feeling lazy.
*/
cairo_rectangle (cr, i, j, CHECK_SIZE, CHECK_SIZE);
cairo_fill (cr);
j += CHECK_SIZE + SPACING;
++ycount;
}
i += CHECK_SIZE + SPACING;
++xcount;
}
}
static void
render_simple (cairo_t *cr,
int width, int height,
MetaGradientType type,
gboolean with_alpha)
{
GdkPixbuf *pixbuf;
GdkRGBA from, to;
gdk_rgba_parse (&from, "blue");
gdk_rgba_parse (&to, "green");
pixbuf = meta_gradient_create_simple (width, height,
&from, &to,
type);
if (with_alpha)
{
const unsigned char alphas[] = { 0xff, 0xaa, 0x2f, 0x0, 0xcc, 0xff, 0xff };
if (!gdk_pixbuf_get_has_alpha (pixbuf))
{
GdkPixbuf *new_pixbuf;
new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
g_object_unref (G_OBJECT (pixbuf));
pixbuf = new_pixbuf;
}
meta_gradient_add_alpha (pixbuf,
alphas, G_N_ELEMENTS (alphas),
META_GRADIENT_HORIZONTAL);
draw_checkerboard (cr , width, height);
}
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
g_object_unref (G_OBJECT (pixbuf));
}
static void
render_vertical_func (cairo_t *cr,
int width, int height)
{
render_simple (cr, width, height, META_GRADIENT_VERTICAL, FALSE);
}
static void
render_horizontal_func (cairo_t *cr,
int width, int height)
{
render_simple (cr, width, height, META_GRADIENT_HORIZONTAL, FALSE);
}
static void
render_diagonal_func (cairo_t *cr,
int width, int height)
{
render_simple (cr, width, height, META_GRADIENT_DIAGONAL, FALSE);
}
static void
render_diagonal_alpha_func (cairo_t *cr,
int width, int height)
{
render_simple (cr, width, height, META_GRADIENT_DIAGONAL, TRUE);
}
static void
render_multi (cairo_t *cr,
int width, int height,
MetaGradientType type)
{
GdkPixbuf *pixbuf;
#define N_COLORS 5
GdkRGBA colors[N_COLORS];
gdk_rgba_parse (&colors[0], "red");
gdk_rgba_parse (&colors[1], "blue");
gdk_rgba_parse (&colors[2], "orange");
gdk_rgba_parse (&colors[3], "pink");
gdk_rgba_parse (&colors[4], "green");
pixbuf = meta_gradient_create_multi (width, height,
colors, N_COLORS,
type);
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
g_object_unref (G_OBJECT (pixbuf));
#undef N_COLORS
}
static void
render_vertical_multi_func (cairo_t *cr,
int width, int height)
{
render_multi (cr, width, height, META_GRADIENT_VERTICAL);
}
static void
render_horizontal_multi_func (cairo_t *cr,
int width, int height)
{
render_multi (cr, width, height, META_GRADIENT_HORIZONTAL);
}
static void
render_diagonal_multi_func (cairo_t *cr,
int width, int height)
{
render_multi (cr, width, height, META_GRADIENT_DIAGONAL);
}
static void
render_interwoven_func (cairo_t *cr,
int width, int height)
{
GdkPixbuf *pixbuf;
#define N_COLORS 4
GdkRGBA colors[N_COLORS];
gdk_rgba_parse (&colors[0], "red");
gdk_rgba_parse (&colors[1], "blue");
gdk_rgba_parse (&colors[2], "pink");
gdk_rgba_parse (&colors[3], "green");
pixbuf = meta_gradient_create_interwoven (width, height,
colors, height / 10,
colors + 2, height / 14);
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
g_object_unref (G_OBJECT (pixbuf));
}
static gboolean
draw_callback (GtkWidget *widget,
cairo_t *cr,
gpointer data)
{
RenderGradientFunc func = data;
GtkStyleContext *style;
GdkRGBA color;
style = gtk_widget_get_style_context (widget);
gtk_style_context_save (style);
gtk_style_context_set_state (style, gtk_widget_get_state_flags (widget));
gtk_style_context_lookup_color (style, "foreground-color", &color);
gtk_style_context_restore (style);
gdk_cairo_set_source_rgba (cr, &color);
(* func) (cr,
gtk_widget_get_allocated_width (widget),
gtk_widget_get_allocated_height (widget));
return FALSE;
}
static GtkWidget*
create_gradient_window (const char *title,
RenderGradientFunc func)
{
GtkWidget *window;
GtkWidget *drawing_area;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), title);
drawing_area = gtk_drawing_area_new ();
gtk_widget_set_size_request (drawing_area, 1, 1);
gtk_window_set_default_size (GTK_WINDOW (window), 175, 175);
g_signal_connect (G_OBJECT (drawing_area),
"draw",
G_CALLBACK (draw_callback),
func);
gtk_container_add (GTK_CONTAINER (window), drawing_area);
gtk_widget_show_all (window);
return window;
}
static void
meta_gradient_test (void)
{
create_gradient_window ("Simple vertical",
render_vertical_func);
create_gradient_window ("Simple horizontal",
render_horizontal_func);
create_gradient_window ("Simple diagonal",
render_diagonal_func);
create_gradient_window ("Multi vertical",
render_vertical_multi_func);
create_gradient_window ("Multi horizontal",
render_horizontal_multi_func);
create_gradient_window ("Multi diagonal",
render_diagonal_multi_func);
create_gradient_window ("Interwoven",
render_interwoven_func);
create_gradient_window ("Simple diagonal with horizontal multi alpha",
render_diagonal_alpha_func);
}
int
main (int argc, char **argv)
{
gtk_init (&argc, &argv);
meta_gradient_test ();
gtk_main ();
return 0;
}

View File

@@ -774,6 +774,9 @@ parse_alpha (const char *str,
n_alphas = i;
/* FIXME allow specifying horizontal/vertical/diagonal in theme format,
* once we implement vertical/diagonal in gradient.c
*/
spec = meta_alpha_gradient_spec_new (META_GRADIENT_HORIZONTAL,
n_alphas);
@@ -2147,9 +2150,11 @@ parse_draw_op_element (GMarkupParseContext *context,
const char *width;
const char *height;
const char *alpha;
const char *colorize;
const char *fill_type;
MetaAlphaGradientSpec *alpha_spec;
GdkPixbuf *pixbuf;
MetaColorSpec *colorize_spec = NULL;
MetaImageFillType fill_type_val;
int h, w, c;
int pixbuf_width, pixbuf_height, pixbuf_n_channels, pixbuf_rowstride;
@@ -2160,6 +2165,7 @@ parse_draw_op_element (GMarkupParseContext *context,
"!x", &x, "!y", &y,
"!width", &width, "!height", &height,
"alpha", &alpha, "!filename", &filename,
"colorize", &colorize,
"fill_type", &fill_type,
NULL))
return;
@@ -2205,6 +2211,18 @@ parse_draw_op_element (GMarkupParseContext *context,
return;
}
if (colorize)
{
colorize_spec = parse_color (info->theme, colorize, error);
if (colorize_spec == NULL)
{
add_context_to_error (error, context);
g_object_unref (G_OBJECT (pixbuf));
return;
}
}
alpha_spec = NULL;
if (alpha && !parse_alpha (alpha, &alpha_spec, context, error))
{
@@ -2215,6 +2233,7 @@ parse_draw_op_element (GMarkupParseContext *context,
op = meta_draw_op_new (META_DRAW_IMAGE);
op->data.image.pixbuf = pixbuf;
op->data.image.colorize_spec = colorize_spec;
op->data.image.x = meta_draw_spec_new (info->theme, x, NULL);
op->data.image.y = meta_draw_spec_new (info->theme, y, NULL);

View File

@@ -23,6 +23,7 @@
#define META_THEME_PRIVATE_H
#include <meta/boxes.h>
#include <meta/gradient.h>
#include <meta/theme.h>
#include <meta/common.h>
#include <gtk/gtk.h>
@@ -272,14 +273,6 @@ typedef enum
META_IMAGE_FILL_TILE
} MetaImageFillType;
typedef enum
{
META_GRADIENT_VERTICAL,
META_GRADIENT_HORIZONTAL,
META_GRADIENT_DIAGONAL,
META_GRADIENT_LAST
} MetaGradientType;
typedef enum
{
META_COLOR_SPEC_BASIC,
@@ -545,6 +538,7 @@ struct _MetaDrawOp
} gradient;
struct {
MetaColorSpec *colorize_spec;
MetaAlphaGradientSpec *alpha_spec;
GdkPixbuf *pixbuf;
MetaDrawSpec *x;
@@ -552,6 +546,8 @@ struct _MetaDrawOp
MetaDrawSpec *width;
MetaDrawSpec *height;
guint32 colorize_cache_pixel;
GdkPixbuf *colorize_cache_pixbuf;
MetaImageFillType fill_type;
unsigned int vertical_stripes : 1;
unsigned int horizontal_stripes : 1;
@@ -976,12 +972,8 @@ gboolean meta_draw_op_list_contains (MetaDrawOpList *op_list,
MetaGradientSpec* meta_gradient_spec_new (MetaGradientType type);
void meta_gradient_spec_free (MetaGradientSpec *desc);
void meta_gradient_spec_render (const MetaGradientSpec *spec,
const MetaAlphaGradientSpec *alpha_spec,
cairo_t *cr,
GtkStyleContext *style,
int x,
int y,
GdkPixbuf* meta_gradient_spec_render (const MetaGradientSpec *desc,
GtkStyleContext *gtk_style,
int width,
int height);
gboolean meta_gradient_spec_validate (MetaGradientSpec *spec,

View File

@@ -38,6 +38,7 @@
#include "theme-private.h"
#include "frames.h" /* for META_TYPE_FRAMES */
#include "util-private.h"
#include <meta/gradient.h>
#include <meta/prefs.h>
#include <gtk/gtk.h>
#include <string.h>
@@ -74,6 +75,84 @@ static void hls_to_rgb (gdouble *h,
*/
static MetaTheme *meta_current_theme = NULL;
static GdkPixbuf *
colorize_pixbuf (GdkPixbuf *orig,
GdkRGBA *new_color)
{
GdkPixbuf *pixbuf;
double intensity;
int x, y;
const guchar *src;
guchar *dest;
int orig_rowstride;
int dest_rowstride;
int width, height;
gboolean has_alpha;
const guchar *src_pixels;
guchar *dest_pixels;
pixbuf = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (orig), gdk_pixbuf_get_has_alpha (orig),
gdk_pixbuf_get_bits_per_sample (orig),
gdk_pixbuf_get_width (orig), gdk_pixbuf_get_height (orig));
if (pixbuf == NULL)
return NULL;
orig_rowstride = gdk_pixbuf_get_rowstride (orig);
dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
has_alpha = gdk_pixbuf_get_has_alpha (orig);
src_pixels = gdk_pixbuf_get_pixels (orig);
dest_pixels = gdk_pixbuf_get_pixels (pixbuf);
for (y = 0; y < height; y++)
{
src = src_pixels + y * orig_rowstride;
dest = dest_pixels + y * dest_rowstride;
for (x = 0; x < width; x++)
{
double dr, dg, db;
intensity = INTENSITY (src[0], src[1], src[2]) / 255.0;
if (intensity <= 0.5)
{
/* Go from black at intensity = 0.0 to new_color at intensity = 0.5 */
dr = new_color->red * intensity * 2.0;
dg = new_color->green * intensity * 2.0;
db = new_color->blue * intensity * 2.0;
}
else
{
/* Go from new_color at intensity = 0.5 to white at intensity = 1.0 */
dr = new_color->red + (1.0 - new_color->red) * (intensity - 0.5) * 2.0;
dg = new_color->green + (1.0 - new_color->green) * (intensity - 0.5) * 2.0;
db = new_color->blue + (1.0 - new_color->blue) * (intensity - 0.5) * 2.0;
}
dest[0] = CLAMP_UCHAR (255 * dr);
dest[1] = CLAMP_UCHAR (255 * dg);
dest[2] = CLAMP_UCHAR (255 * db);
if (has_alpha)
{
dest[3] = src[3];
src += 4;
dest += 4;
}
else
{
src += 3;
dest += 3;
}
}
}
return pixbuf;
}
static void
color_composite (const GdkRGBA *bg,
const GdkRGBA *fg,
@@ -931,84 +1010,42 @@ meta_gradient_spec_free (MetaGradientSpec *spec)
g_free (spec);
}
static cairo_pattern_t *
meta_gradient_spec_pattern (const MetaGradientSpec *spec,
const MetaAlphaGradientSpec *alpha_spec,
GtkStyleContext *style)
GdkPixbuf*
meta_gradient_spec_render (const MetaGradientSpec *spec,
GtkStyleContext *style,
int width,
int height)
{
cairo_pattern_t *pattern;
int n_colors;
GSList *l;
GdkRGBA *colors;
GSList *tmp;
int i;
if (spec->type == META_GRADIENT_HORIZONTAL)
pattern = cairo_pattern_create_linear (0, 0, 1, 0);
if (spec->type == META_GRADIENT_VERTICAL)
pattern = cairo_pattern_create_linear (0, 0, 0, 1);
else if (spec->type == META_GRADIENT_DIAGONAL)
pattern = cairo_pattern_create_linear (0, 0, 1, 1);
else
g_assert_not_reached ();
GdkPixbuf *pixbuf;
n_colors = g_slist_length (spec->color_specs);
if (n_colors == 0)
return NULL;
if (alpha_spec != NULL)
g_assert (n_colors == alpha_spec->n_alphas);
colors = g_new (GdkRGBA, n_colors);
i = 0;
for (l = spec->color_specs; l != NULL; l = l->next)
tmp = spec->color_specs;
while (tmp != NULL)
{
MetaColorSpec *color_spec = l->data;
GdkRGBA color;
meta_color_spec_render (tmp->data, style, &colors[i]);
meta_color_spec_render (color_spec, style, &color);
if (alpha_spec != NULL)
color.alpha *= alpha_spec->alphas[i];
cairo_pattern_add_color_stop_rgba (pattern,
i / (float) n_colors,
color.red,
color.green,
color.blue,
color.alpha);
tmp = tmp->next;
++i;
}
return pattern;
}
pixbuf = meta_gradient_create_multi (width, height,
colors, n_colors,
spec->type);
void
meta_gradient_spec_render (const MetaGradientSpec *spec,
const MetaAlphaGradientSpec *alpha_spec,
cairo_t *cr,
GtkStyleContext *style,
int x,
int y,
int width,
int height)
{
cairo_pattern_t *pattern;
g_free (colors);
cairo_save (cr);
pattern = meta_gradient_spec_pattern (spec, alpha_spec, style);
if (pattern == NULL)
return;
cairo_rectangle (cr, x, y, width, height);
cairo_translate (cr, x, y);
cairo_scale (cr, width, height);
cairo_set_source (cr, pattern);
cairo_fill (cr);
cairo_pattern_destroy (pattern);
cairo_restore (cr);
return pixbuf;
}
gboolean
@@ -3015,6 +3052,12 @@ meta_draw_op_free (MetaDrawOp *op)
if (op->data.image.pixbuf)
g_object_unref (G_OBJECT (op->data.image.pixbuf));
if (op->data.image.colorize_spec)
meta_color_spec_free (op->data.image.colorize_spec);
if (op->data.image.colorize_cache_pixbuf)
g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf));
meta_draw_spec_free (op->data.image.x);
meta_draw_spec_free (op->data.image.y);
meta_draw_spec_free (op->data.image.width);
@@ -3089,6 +3132,413 @@ meta_draw_op_free (MetaDrawOp *op)
g_free (op);
}
static GdkPixbuf*
apply_alpha (GdkPixbuf *pixbuf,
MetaAlphaGradientSpec *spec,
gboolean force_copy)
{
GdkPixbuf *new_pixbuf;
gboolean needs_alpha;
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
needs_alpha = spec && (spec->n_alphas > 1 ||
spec->alphas[0] != 0xff);
if (!needs_alpha)
return pixbuf;
if (!gdk_pixbuf_get_has_alpha (pixbuf))
{
new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
g_object_unref (G_OBJECT (pixbuf));
pixbuf = new_pixbuf;
}
else if (force_copy)
{
new_pixbuf = gdk_pixbuf_copy (pixbuf);
g_object_unref (G_OBJECT (pixbuf));
pixbuf = new_pixbuf;
}
g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
meta_gradient_add_alpha (pixbuf, spec->alphas, spec->n_alphas, spec->type);
return pixbuf;
}
static GdkPixbuf*
pixbuf_tile (GdkPixbuf *tile,
int width,
int height)
{
GdkPixbuf *pixbuf;
int tile_width;
int tile_height;
int i, j;
tile_width = gdk_pixbuf_get_width (tile);
tile_height = gdk_pixbuf_get_height (tile);
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
gdk_pixbuf_get_has_alpha (tile),
8, width, height);
i = 0;
while (i < width)
{
j = 0;
while (j < height)
{
int w, h;
w = MIN (tile_width, width - i);
h = MIN (tile_height, height - j);
gdk_pixbuf_copy_area (tile,
0, 0,
w, h,
pixbuf,
i, j);
j += tile_height;
}
i += tile_width;
}
return pixbuf;
}
static GdkPixbuf *
replicate_rows (GdkPixbuf *src,
int src_x,
int src_y,
int width,
int height)
{
unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
* n_channels);
unsigned char *dest_pixels;
GdkPixbuf *result;
unsigned int dest_rowstride;
int i;
result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
width, height);
dest_rowstride = gdk_pixbuf_get_rowstride (result);
dest_pixels = gdk_pixbuf_get_pixels (result);
for (i = 0; i < height; i++)
memcpy (dest_pixels + dest_rowstride * i, pixels, n_channels * width);
return result;
}
static GdkPixbuf *
replicate_cols (GdkPixbuf *src,
int src_x,
int src_y,
int width,
int height)
{
unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
* n_channels);
unsigned char *dest_pixels;
GdkPixbuf *result;
unsigned int dest_rowstride;
int i, j;
result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
width, height);
dest_rowstride = gdk_pixbuf_get_rowstride (result);
dest_pixels = gdk_pixbuf_get_pixels (result);
for (i = 0; i < height; i++)
{
unsigned char *p = dest_pixels + dest_rowstride * i;
unsigned char *q = pixels + src_rowstride * i;
unsigned char r = *(q++);
unsigned char g = *(q++);
unsigned char b = *(q++);
if (n_channels == 4)
{
unsigned char a;
a = *(q++);
for (j = 0; j < width; j++)
{
*(p++) = r;
*(p++) = g;
*(p++) = b;
*(p++) = a;
}
}
else
{
for (j = 0; j < width; j++)
{
*(p++) = r;
*(p++) = g;
*(p++) = b;
}
}
}
return result;
}
static GdkPixbuf*
scale_and_alpha_pixbuf (GdkPixbuf *src,
MetaAlphaGradientSpec *alpha_spec,
MetaImageFillType fill_type,
int width,
int height,
gboolean vertical_stripes,
gboolean horizontal_stripes)
{
GdkPixbuf *pixbuf;
GdkPixbuf *temp_pixbuf;
pixbuf = NULL;
pixbuf = src;
if (gdk_pixbuf_get_width (pixbuf) == width &&
gdk_pixbuf_get_height (pixbuf) == height)
{
g_object_ref (G_OBJECT (pixbuf));
}
else
{
if (fill_type == META_IMAGE_FILL_TILE)
{
pixbuf = pixbuf_tile (pixbuf, width, height);
}
else
{
int src_h, src_w, dest_h, dest_w;
src_h = gdk_pixbuf_get_height (src);
src_w = gdk_pixbuf_get_width (src);
/* prefer to replicate_cols if possible, as that
* is faster (no memory reads)
*/
if (horizontal_stripes)
{
dest_w = gdk_pixbuf_get_width (src);
dest_h = height;
}
else if (vertical_stripes)
{
dest_w = width;
dest_h = gdk_pixbuf_get_height (src);
}
else
{
dest_w = width;
dest_h = height;
}
if (dest_w == src_w && dest_h == src_h)
{
temp_pixbuf = src;
g_object_ref (G_OBJECT (temp_pixbuf));
}
else
{
temp_pixbuf = gdk_pixbuf_scale_simple (src,
dest_w, dest_h,
GDK_INTERP_BILINEAR);
}
/* prefer to replicate_cols if possible, as that
* is faster (no memory reads)
*/
if (horizontal_stripes)
{
pixbuf = replicate_cols (temp_pixbuf, 0, 0, width, height);
g_object_unref (G_OBJECT (temp_pixbuf));
}
else if (vertical_stripes)
{
pixbuf = replicate_rows (temp_pixbuf, 0, 0, width, height);
g_object_unref (G_OBJECT (temp_pixbuf));
}
else
{
pixbuf = temp_pixbuf;
}
}
}
if (pixbuf)
pixbuf = apply_alpha (pixbuf, alpha_spec, pixbuf == src);
return pixbuf;
}
static GdkPixbuf*
draw_op_as_pixbuf (const MetaDrawOp *op,
GtkStyleContext *context,
const MetaDrawInfo *info,
int width,
int height)
{
/* Try to get the op as a pixbuf, assuming w/h in the op
* matches the width/height passed in. return NULL
* if the op can't be converted to an equivalent pixbuf.
*/
GdkPixbuf *pixbuf;
pixbuf = NULL;
switch (op->type)
{
case META_DRAW_TINT:
{
GdkRGBA color;
guint32 rgba;
gboolean has_alpha;
meta_color_spec_render (op->data.rectangle.color_spec,
context,
&color);
has_alpha =
op->data.tint.alpha_spec &&
(op->data.tint.alpha_spec->n_alphas > 1 ||
op->data.tint.alpha_spec->alphas[0] != 0xff);
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
has_alpha,
8, width, height);
if (!has_alpha)
{
rgba = GDK_COLOR_RGBA (color);
gdk_pixbuf_fill (pixbuf, rgba);
}
else if (op->data.tint.alpha_spec->n_alphas == 1)
{
rgba = GDK_COLOR_RGBA (color);
rgba &= ~0xff;
rgba |= op->data.tint.alpha_spec->alphas[0];
gdk_pixbuf_fill (pixbuf, rgba);
}
else
{
rgba = GDK_COLOR_RGBA (color);
gdk_pixbuf_fill (pixbuf, rgba);
meta_gradient_add_alpha (pixbuf,
op->data.tint.alpha_spec->alphas,
op->data.tint.alpha_spec->n_alphas,
op->data.tint.alpha_spec->type);
}
}
break;
case META_DRAW_GRADIENT:
{
pixbuf = meta_gradient_spec_render (op->data.gradient.gradient_spec,
context, width, height);
pixbuf = apply_alpha (pixbuf,
op->data.gradient.alpha_spec,
FALSE);
}
break;
case META_DRAW_IMAGE:
{
if (op->data.image.colorize_spec)
{
GdkRGBA color;
meta_color_spec_render (op->data.image.colorize_spec,
context, &color);
if (op->data.image.colorize_cache_pixbuf == NULL ||
op->data.image.colorize_cache_pixel != GDK_COLOR_RGB (color))
{
if (op->data.image.colorize_cache_pixbuf)
g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf));
/* const cast here */
((MetaDrawOp*)op)->data.image.colorize_cache_pixbuf =
colorize_pixbuf (op->data.image.pixbuf,
&color);
((MetaDrawOp*)op)->data.image.colorize_cache_pixel =
GDK_COLOR_RGB (color);
}
if (op->data.image.colorize_cache_pixbuf)
{
pixbuf = scale_and_alpha_pixbuf (op->data.image.colorize_cache_pixbuf,
op->data.image.alpha_spec,
op->data.image.fill_type,
width, height,
op->data.image.vertical_stripes,
op->data.image.horizontal_stripes);
}
}
else
{
pixbuf = scale_and_alpha_pixbuf (op->data.image.pixbuf,
op->data.image.alpha_spec,
op->data.image.fill_type,
width, height,
op->data.image.vertical_stripes,
op->data.image.horizontal_stripes);
}
break;
}
case META_DRAW_ICON:
if (info->mini_icon &&
width <= gdk_pixbuf_get_width (info->mini_icon) &&
height <= gdk_pixbuf_get_height (info->mini_icon))
pixbuf = scale_and_alpha_pixbuf (info->mini_icon,
op->data.icon.alpha_spec,
op->data.icon.fill_type,
width, height,
FALSE, FALSE);
else if (info->icon)
pixbuf = scale_and_alpha_pixbuf (info->icon,
op->data.icon.alpha_spec,
op->data.icon.fill_type,
width, height,
FALSE, FALSE);
break;
case META_DRAW_LINE:
case META_DRAW_RECTANGLE:
case META_DRAW_ARC:
case META_DRAW_CLIP:
case META_DRAW_GTK_ARROW:
case META_DRAW_GTK_BOX:
case META_DRAW_GTK_VLINE:
case META_DRAW_TITLE:
case META_DRAW_OP_LIST:
case META_DRAW_TILE:
break;
}
return pixbuf;
}
static void
fill_env (MetaPositionExprEnv *env,
const MetaDrawInfo *info,
@@ -3128,86 +3578,6 @@ fill_env (MetaPositionExprEnv *env,
env->theme = meta_current_theme;
}
static cairo_pattern_t *
meta_alpha_gradient_spec_pattern (const MetaAlphaGradientSpec *alpha_spec)
{
/* Hardcoded in theme-parser.c */
g_assert (alpha_spec->type == META_GRADIENT_HORIZONTAL);
int n_alphas = alpha_spec->n_alphas;
if (n_alphas == 0)
return NULL;
else if (n_alphas == 1)
return cairo_pattern_create_rgba (0, 0, 0, alpha_spec->alphas[0]);
else
{
cairo_pattern_t *pattern = cairo_pattern_create_linear (0, 0, 1, 0);
int i;
for (i = 0; i < n_alphas; i++)
cairo_pattern_add_color_stop_rgba (pattern,
i / (float) n_alphas,
0, 0, 0, alpha_spec->alphas[i]);
return pattern;
}
}
static void
draw_image (cairo_t *cr,
GdkPixbuf *src,
MetaImageFillType fill_type,
MetaAlphaGradientSpec *alpha_spec,
int x,
int y,
int width,
int height)
{
cairo_save (cr);
cairo_rectangle (cr, x, y, width, height);
if (fill_type == META_IMAGE_FILL_TILE)
{
gdk_cairo_set_source_pixbuf (cr, src, 0, 0);
cairo_pattern_set_extend (cairo_get_source (cr),
CAIRO_EXTEND_REPEAT);
}
else
{
float pixbuf_width, pixbuf_height;
pixbuf_width = gdk_pixbuf_get_width (src);
pixbuf_height = gdk_pixbuf_get_height (src);
cairo_save (cr);
cairo_translate (cr, x, y);
cairo_scale (cr,
pixbuf_width / width,
pixbuf_height / height);
gdk_cairo_set_source_pixbuf (cr, src, 0, 0);
cairo_restore (cr);
}
if (alpha_spec)
{
cairo_translate (cr, x, y);
cairo_scale (cr, width, height);
cairo_pattern_t *pattern = meta_alpha_gradient_spec_pattern (alpha_spec);
cairo_mask (cr, pattern);
cairo_pattern_destroy (pattern);
}
else
{
cairo_fill (cr);
}
cairo_restore (cr);
}
/* This code was originally rendering anti-aliased using X primitives, and
* now has been switched to draw anti-aliased using cairo. In general, the
@@ -3231,6 +3601,7 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
GdkRGBA color;
cairo_save (cr);
gtk_style_context_save (style_gtk);
cairo_set_line_width (cr, 1.0);
@@ -3388,63 +3759,94 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
case META_DRAW_TINT:
{
int rx, ry, rwidth, rheight;
gboolean needs_alpha;
needs_alpha = op->data.tint.alpha_spec &&
(op->data.tint.alpha_spec->n_alphas > 1 ||
op->data.tint.alpha_spec->alphas[0] != 0xff);
rx = parse_x_position_unchecked (op->data.tint.x, env);
ry = parse_y_position_unchecked (op->data.tint.y, env);
rwidth = parse_size_unchecked (op->data.tint.width, env);
rheight = parse_size_unchecked (op->data.tint.height, env);
meta_color_spec_render (op->data.tint.color_spec,
style_gtk, &color);
if (!needs_alpha)
{
meta_color_spec_render (op->data.tint.color_spec,
style_gtk, &color);
gdk_cairo_set_source_rgba (cr, &color);
if (op->data.tint.alpha_spec &&
op->data.tint.alpha_spec->n_alphas == 1)
color.alpha = op->data.tint.alpha_spec->alphas[0];
cairo_rectangle (cr, rx, ry, rwidth, rheight);
cairo_fill (cr);
}
else
{
GdkPixbuf *pixbuf;
gdk_cairo_set_source_rgba (cr, &color);
pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
rwidth, rheight);
cairo_rectangle (cr, rx, ry, rwidth, rheight);
cairo_fill (cr);
if (pixbuf)
{
gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
cairo_paint (cr);
g_object_unref (G_OBJECT (pixbuf));
}
}
}
break;
case META_DRAW_GRADIENT:
{
int rx, ry, rwidth, rheight;
GdkPixbuf *pixbuf;
rx = parse_x_position_unchecked (op->data.gradient.x, env);
ry = parse_y_position_unchecked (op->data.gradient.y, env);
rwidth = parse_size_unchecked (op->data.gradient.width, env);
rheight = parse_size_unchecked (op->data.gradient.height, env);
meta_gradient_spec_render (op->data.gradient.gradient_spec,
op->data.gradient.alpha_spec,
cr, style_gtk,
rx, ry, rwidth, rheight);
pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
rwidth, rheight);
if (pixbuf)
{
gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
cairo_paint (cr);
g_object_unref (G_OBJECT (pixbuf));
}
}
break;
case META_DRAW_IMAGE:
{
int rx, ry, rwidth, rheight;
GdkPixbuf *pixbuf;
if (op->data.image.pixbuf == NULL)
break;
env->object_width = gdk_pixbuf_get_width (op->data.image.pixbuf);
env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf);
rx = parse_x_position_unchecked (op->data.image.x, env);
ry = parse_y_position_unchecked (op->data.image.y, env);
if (op->data.image.pixbuf)
{
env->object_width = gdk_pixbuf_get_width (op->data.image.pixbuf);
env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf);
}
rwidth = parse_size_unchecked (op->data.image.width, env);
rheight = parse_size_unchecked (op->data.image.height, env);
draw_image (cr,
op->data.image.pixbuf,
op->data.image.fill_type,
op->data.image.alpha_spec,
rx, ry, rwidth, rheight);
pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
rwidth, rheight);
if (pixbuf)
{
rx = parse_x_position_unchecked (op->data.image.x, env);
ry = parse_y_position_unchecked (op->data.image.y, env);
gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
cairo_paint (cr);
g_object_unref (G_OBJECT (pixbuf));
}
}
break;
@@ -3514,27 +3916,24 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
case META_DRAW_ICON:
{
int rx, ry, rwidth, rheight;
GdkPixbuf *src;
GdkPixbuf *pixbuf;
rwidth = parse_size_unchecked (op->data.icon.width, env);
rheight = parse_size_unchecked (op->data.icon.height, env);
if (info->mini_icon &&
rwidth < gdk_pixbuf_get_width (info->mini_icon) &&
rheight < gdk_pixbuf_get_height (info->mini_icon))
src = info->mini_icon;
else if (info->icon)
src = info->icon;
else
break;
pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
rwidth, rheight);
rx = parse_x_position_unchecked (op->data.icon.x, env);
ry = parse_y_position_unchecked (op->data.icon.y, env);
if (pixbuf)
{
rx = parse_x_position_unchecked (op->data.icon.x, env);
ry = parse_y_position_unchecked (op->data.icon.y, env);
draw_image (cr, src,
op->data.icon.fill_type,
op->data.icon.alpha_spec,
rx, ry, rwidth, rheight);
gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
cairo_paint (cr);
g_object_unref (G_OBJECT (pixbuf));
}
}
break;
@@ -3654,6 +4053,7 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
}
cairo_restore (cr);
gtk_style_context_restore (style_gtk);
}
void

View File

@@ -1,137 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Endless Mobile
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#include "config.h"
#include "meta-wayland-buffer.h"
#include <clutter/clutter.h>
#include <cogl/cogl-wayland-server.h>
#include <meta/util.h>
static void
meta_wayland_buffer_destroy_handler (struct wl_listener *listener,
void *data)
{
MetaWaylandBuffer *buffer =
wl_container_of (listener, buffer, destroy_listener);
wl_signal_emit (&buffer->destroy_signal, buffer);
g_slice_free (MetaWaylandBuffer, buffer);
}
void
meta_wayland_buffer_ref (MetaWaylandBuffer *buffer)
{
buffer->ref_count++;
}
void
meta_wayland_buffer_unref (MetaWaylandBuffer *buffer)
{
buffer->ref_count--;
if (buffer->ref_count == 0)
{
g_clear_pointer (&buffer->texture, cogl_object_unref);
wl_resource_queue_event (buffer->resource, WL_BUFFER_RELEASE);
}
}
MetaWaylandBuffer *
meta_wayland_buffer_from_resource (struct wl_resource *resource)
{
MetaWaylandBuffer *buffer;
struct wl_listener *listener;
listener =
wl_resource_get_destroy_listener (resource,
meta_wayland_buffer_destroy_handler);
if (listener)
{
buffer = wl_container_of (listener, buffer, destroy_listener);
}
else
{
buffer = g_slice_new0 (MetaWaylandBuffer);
buffer->resource = resource;
wl_signal_init (&buffer->destroy_signal);
buffer->destroy_listener.notify = meta_wayland_buffer_destroy_handler;
wl_resource_add_destroy_listener (resource, &buffer->destroy_listener);
}
return buffer;
}
CoglTexture *
meta_wayland_buffer_ensure_texture (MetaWaylandBuffer *buffer)
{
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
CoglError *catch_error = NULL;
CoglTexture *texture;
if (buffer->texture)
goto out;
texture = COGL_TEXTURE (cogl_wayland_texture_2d_new_from_buffer (ctx,
buffer->resource,
&catch_error));
if (!texture)
{
cogl_error_free (catch_error);
meta_fatal ("Could not import pending buffer, ignoring commit\n");
}
buffer->texture = texture;
out:
return buffer->texture;
}
void
meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
cairo_region_t *region)
{
struct wl_shm_buffer *shm_buffer;
shm_buffer = wl_shm_buffer_get (buffer->resource);
if (shm_buffer)
{
int i, n_rectangles;
n_rectangles = cairo_region_num_rectangles (region);
for (i = 0; i < n_rectangles; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
cogl_wayland_texture_set_region_from_shm_buffer (buffer->texture,
rect.x, rect.y, rect.width, rect.height,
shm_buffer,
rect.x, rect.y, 0, NULL);
}
}
}

View File

@@ -1,51 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Endless Mobile
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#ifndef META_WAYLAND_BUFFER_H
#define META_WAYLAND_BUFFER_H
#include <cogl/cogl.h>
#include <cairo.h>
#include <wayland-server.h>
#include "meta-wayland-types.h"
struct _MetaWaylandBuffer
{
struct wl_resource *resource;
struct wl_signal destroy_signal;
struct wl_listener destroy_listener;
CoglTexture *texture;
uint32_t ref_count;
};
MetaWaylandBuffer * meta_wayland_buffer_from_resource (struct wl_resource *resource);
void meta_wayland_buffer_ref (MetaWaylandBuffer *buffer);
void meta_wayland_buffer_unref (MetaWaylandBuffer *buffer);
CoglTexture * meta_wayland_buffer_ensure_texture (MetaWaylandBuffer *buffer);
void meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
cairo_region_t *region);
#endif /* META_WAYLAND_BUFFER_H */

View File

@@ -34,7 +34,7 @@
#include "meta-wayland-seat.h"
#include "meta-wayland-pointer.h"
#include "meta-wayland-private.h"
#include "meta-dnd-actor-private.h"
#include "meta-cursor-tracker-private.h"
typedef struct
{
@@ -183,8 +183,6 @@ struct _MetaWaylandDragGrab {
MetaWaylandDataSource *drag_data_source;
struct wl_listener drag_data_source_listener;
ClutterActor *feedback_actor;
MetaWaylandSurface *drag_origin;
struct wl_listener drag_origin_listener;
@@ -214,6 +212,8 @@ drag_grab_focus (MetaWaylandPointerGrab *grab,
if (drag_grab->drag_focus == surface)
return;
meta_wayland_pointer_set_focus (&seat->pointer, surface, FALSE);
if (drag_grab->drag_focus_data_device)
{
wl_data_device_send_leave (drag_grab->drag_focus_data_device);
@@ -253,6 +253,40 @@ drag_grab_focus (MetaWaylandPointerGrab *grab,
wl_resource_add_destroy_listener (data_device_resource, &drag_grab->drag_focus_listener);
}
static void
drag_grab_update_dnd_surface_position (MetaWaylandDragGrab *drag_grab)
{
MetaWaylandSeat *seat = drag_grab->seat;
ClutterPoint pos;
clutter_input_device_get_coords (seat->pointer.device, NULL, &pos);
meta_cursor_tracker_update_dnd_surface_position (seat->pointer.cursor_tracker,
(int) pos.x, (int) pos.y);
}
static void
drag_grab_update_dnd_surface (MetaWaylandDragGrab *drag_grab)
{
MetaWaylandSurface *surface = drag_grab->drag_surface;
MetaWaylandSeat *seat = drag_grab->seat;
CoglTexture *texture = NULL;
int offset_x, offset_y;
if (surface)
{
if (surface->buffer)
texture = surface->buffer->texture;
offset_x = surface->offset_x;
offset_y = surface->offset_y;
}
else
offset_x = offset_y = 0;
meta_cursor_tracker_set_dnd_surface (seat->pointer.cursor_tracker,
texture, offset_x, offset_y);
}
static void
drag_grab_motion (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
@@ -260,6 +294,8 @@ drag_grab_motion (MetaWaylandPointerGrab *grab,
MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab;
wl_fixed_t sx, sy;
drag_grab_update_dnd_surface_position (drag_grab);
if (drag_grab->drag_focus_data_device)
{
meta_wayland_pointer_get_relative_coordinates (grab->pointer,
@@ -269,10 +305,29 @@ drag_grab_motion (MetaWaylandPointerGrab *grab,
clutter_event_get_time (event),
sx, sy);
}
}
if (drag_grab->drag_surface)
meta_feedback_actor_update (META_FEEDBACK_ACTOR (drag_grab->feedback_actor),
event);
static void
data_device_dnd_failed (MetaWaylandDragGrab *drag_grab)
{
MetaWaylandSurface *surface = drag_grab->drag_origin;
MetaWaylandSeat *seat = drag_grab->seat;
ClutterPoint dest;
if (drag_grab->drag_origin &&
!meta_window_is_hidden (surface->window))
{
/* Find out the snap back position */
clutter_actor_get_transformed_position (CLUTTER_ACTOR (meta_surface_actor_get_texture (surface->surface_actor)),
&dest.x, &dest.y);
dest.x += drag_grab->drag_start_x;
dest.y += drag_grab->drag_start_y;
}
else
clutter_input_device_get_coords (seat->pointer.device, NULL, &dest);
meta_cursor_tracker_dnd_failed (seat->pointer.cursor_tracker,
dest.x, dest.y);
}
static void
@@ -296,15 +351,10 @@ data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
wl_list_remove (&drag_grab->drag_data_source_listener.link);
}
if (drag_grab->feedback_actor)
{
clutter_actor_remove_all_children (drag_grab->feedback_actor);
clutter_actor_destroy (drag_grab->feedback_actor);
}
drag_grab->seat->data_device.current_grab = NULL;
drag_grab_focus (&drag_grab->generic, NULL);
drag_grab_update_dnd_surface (drag_grab);
meta_wayland_pointer_end_grab (drag_grab->generic.pointer);
g_slice_free (MetaWaylandDragGrab, drag_grab);
@@ -321,19 +371,11 @@ drag_grab_button (MetaWaylandPointerGrab *grab,
if (drag_grab->generic.pointer->grab_button == clutter_event_get_button (event) &&
event_type == CLUTTER_BUTTON_RELEASE)
{
gboolean success = FALSE;
if (drag_grab->drag_focus_data_device &&
drag_grab->drag_data_source->has_target)
{
wl_data_device_send_drop (drag_grab->drag_focus_data_device);
success = TRUE;
}
/* Finish drag and let actor self-destruct */
meta_dnd_actor_drag_finish (META_DND_ACTOR (drag_grab->feedback_actor),
success);
drag_grab->feedback_actor = NULL;
wl_data_device_send_drop (drag_grab->drag_focus_data_device);
else
data_device_dnd_failed (drag_grab);
}
if (seat->pointer.button_count == 0 &&
@@ -374,9 +416,7 @@ destroy_data_device_icon (struct wl_listener *listener, void *data)
wl_container_of (listener, drag_grab, drag_data_source_listener);
drag_grab->drag_surface = NULL;
if (drag_grab->feedback_actor)
clutter_actor_remove_all_children (drag_grab->feedback_actor);
drag_grab_update_dnd_surface (drag_grab);
}
static void
@@ -443,23 +483,12 @@ data_device_start_drag (struct wl_client *client,
drag_grab->drag_icon_listener.notify = destroy_data_device_icon;
wl_resource_add_destroy_listener (icon_resource,
&drag_grab->drag_icon_listener);
drag_grab->feedback_actor = meta_dnd_actor_new (CLUTTER_ACTOR (drag_grab->drag_origin->surface_actor),
drag_grab->drag_start_x,
drag_grab->drag_start_y);
meta_feedback_actor_set_anchor (META_FEEDBACK_ACTOR (drag_grab->feedback_actor),
-drag_grab->drag_surface->offset_x,
-drag_grab->drag_surface->offset_y);
clutter_actor_add_child (drag_grab->feedback_actor,
CLUTTER_ACTOR (drag_grab->drag_surface->surface_actor));
clutter_input_device_get_coords (seat->pointer.device, NULL, &pos);
meta_feedback_actor_set_position (META_FEEDBACK_ACTOR (drag_grab->feedback_actor),
pos.x, pos.y);
}
meta_wayland_pointer_set_focus (&seat->pointer, NULL);
meta_wayland_pointer_set_focus (&seat->pointer, NULL, TRUE);
meta_wayland_pointer_start_grab (&seat->pointer, (MetaWaylandPointerGrab*)drag_grab);
drag_grab_update_dnd_surface_position (drag_grab);
drag_grab_update_dnd_surface (drag_grab);
}
static void
@@ -655,17 +684,6 @@ meta_wayland_data_device_is_dnd_surface (MetaWaylandDataDevice *data_device,
void
meta_wayland_data_device_update_dnd_surface (MetaWaylandDataDevice *data_device)
{
MetaWaylandDragGrab *drag_grab;
if (!data_device->current_grab)
return;
drag_grab = data_device->current_grab;
if (!drag_grab->feedback_actor || !drag_grab->drag_surface)
return;
meta_feedback_actor_set_anchor (META_FEEDBACK_ACTOR (drag_grab->feedback_actor),
-drag_grab->drag_surface->offset_x,
-drag_grab->drag_surface->offset_y);
if (data_device->current_grab)
drag_grab_update_dnd_surface (data_device->current_grab);
}

View File

@@ -383,6 +383,8 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
keyboard->focus_surface_listener.notify = keyboard_handle_focus_surface_destroy;
wl_array_init (&keyboard->pressed_keys);
keyboard->xkb_info.keymap_fd = -1;
keyboard->settings = g_settings_new ("org.gnome.settings-daemon.peripherals.keyboard");
@@ -415,12 +417,47 @@ meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard)
meta_wayland_xkb_info_destroy (&keyboard->xkb_info);
/* XXX: What about keyboard->resource_list? */
wl_array_release (&keyboard->pressed_keys);
g_object_unref (keyboard->settings);
keyboard->display = NULL;
}
static void
update_pressed_keys (struct wl_array *keys,
uint32_t evdev_code,
gboolean is_press)
{
uint32_t *end = (void *) ((char *) keys->data + keys->size);
uint32_t *k;
if (is_press)
{
/* Make sure we don't already have this key. */
for (k = keys->data; k < end; k++)
if (*k == evdev_code)
return;
/* Otherwise add the key to the list of pressed keys */
k = wl_array_add (keys, sizeof (*k));
*k = evdev_code;
}
else
{
/* Remove the key from the array */
for (k = keys->data; k < end; k++)
if (*k == evdev_code)
{
*k = *(end - 1);
keys->size -= sizeof (*k);
return;
}
g_warning ("unexpected key release event for key 0x%x", evdev_code);
}
}
static guint
evdev_code (const ClutterKeyEvent *event)
{
@@ -434,10 +471,18 @@ meta_wayland_keyboard_update (MetaWaylandKeyboard *keyboard,
const ClutterKeyEvent *event)
{
gboolean is_press = event->type == CLUTTER_KEY_PRESS;
struct xkb_state *state = keyboard->xkb_info.state;
enum xkb_state_component changed_state;
keyboard->mods_changed = xkb_state_update_key (keyboard->xkb_info.state,
event->hardware_keycode,
is_press ? XKB_KEY_DOWN : XKB_KEY_UP);
update_pressed_keys (&keyboard->pressed_keys, evdev_code (event), is_press);
changed_state = xkb_state_update_key (state,
event->hardware_keycode,
is_press ? XKB_KEY_DOWN : XKB_KEY_UP);
if (changed_state == 0)
return;
notify_modifiers (keyboard);
}
gboolean
@@ -463,12 +508,6 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
else
meta_verbose ("No wayland surface is focused, continuing normal operation\n");
if (keyboard->mods_changed != 0)
{
notify_modifiers (keyboard);
keyboard->mods_changed = 0;
}
return handled;
}
@@ -499,27 +538,8 @@ static void
broadcast_focus (MetaWaylandKeyboard *keyboard,
struct wl_resource *resource)
{
struct wl_array fake_keys;
struct xkb_state *state = keyboard->xkb_info.state;
/* We never want to send pressed keys to wayland clients on
* enter. The protocol says that we should send them, presumably so
* that clients can trigger their own key repeat routine in case
* they are given focus and a key is physically pressed.
*
* Unfortunately this causes some clients, in particular Xwayland,
* to register key events that they really shouldn't handle,
* e.g. on an Alt+Tab keybinding, where Alt is released before Tab,
* clients would see Tab being pressed on enter followed by a key
* release event for Tab, meaning that Tab would be processed by
* the client when it really shouldn't.
*
* Since the use case for the pressed keys array on enter seems weak
* to us, we'll just fake that there are no pressed keys instead
* which should be spec compliant even if it might not be true.
*/
wl_array_init (&fake_keys);
wl_keyboard_send_modifiers (resource, keyboard->focus_serial,
xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED),
xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED),
@@ -527,7 +547,7 @@ broadcast_focus (MetaWaylandKeyboard *keyboard,
xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE));
wl_keyboard_send_enter (resource, keyboard->focus_serial,
keyboard->focus_surface->resource,
&fake_keys);
&keyboard->pressed_keys);
}
void

View File

@@ -69,8 +69,9 @@ struct _MetaWaylandKeyboard
struct wl_listener focus_surface_listener;
uint32_t focus_serial;
struct wl_array pressed_keys;
MetaWaylandXkbInfo xkb_info;
enum xkb_state_component mods_changed;
GSettings *settings;
};

View File

@@ -75,14 +75,6 @@ compute_scale (MetaOutput *output)
output->crtc->rect.width >= SMALLEST_4K_WIDTH)
goto out;
/* Somebody encoded the aspect ratio (16/9 or 16/10)
* instead of the physical size */
if ((output->width_mm == 160 && output->height_mm == 90) ||
(output->width_mm == 160 && output->height_mm == 100) ||
(output->width_mm == 16 && output->height_mm == 9) ||
(output->width_mm == 16 && output->height_mm == 10))
goto out;
if (output->width_mm > 0 && output->height_mm > 0)
{
double dpi_x, dpi_y;

View File

@@ -48,7 +48,6 @@
#include "meta-wayland-pointer.h"
#include "meta-wayland-private.h"
#include "meta-wayland-buffer.h"
#include "meta-cursor.h"
#include "meta-cursor-tracker-private.h"
#include "meta-surface-actor-wayland.h"
@@ -96,7 +95,7 @@ pointer_handle_focus_surface_destroy (struct wl_listener *listener, void *data)
{
MetaWaylandPointer *pointer = wl_container_of (listener, pointer, focus_surface_listener);
meta_wayland_pointer_set_focus (pointer, NULL);
meta_wayland_pointer_set_focus (pointer, NULL, TRUE);
}
static void
@@ -108,7 +107,7 @@ default_grab_focus (MetaWaylandPointerGrab *grab,
if (pointer->button_count > 0)
return;
meta_wayland_pointer_set_focus (pointer, surface);
meta_wayland_pointer_set_focus (pointer, surface, TRUE);
}
static void
@@ -179,7 +178,7 @@ default_grab_button (MetaWaylandPointerGrab *grab,
}
if (pointer->button_count == 0 && event_type == CLUTTER_BUTTON_RELEASE)
meta_wayland_pointer_set_focus (pointer, pointer->current);
meta_wayland_pointer_set_focus (pointer, pointer->current, TRUE);
}
static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = {
@@ -219,7 +218,7 @@ meta_wayland_pointer_init (MetaWaylandPointer *pointer,
void
meta_wayland_pointer_release (MetaWaylandPointer *pointer)
{
meta_wayland_pointer_set_focus (pointer, NULL);
meta_wayland_pointer_set_focus (pointer, NULL, TRUE);
set_cursor_surface (pointer, NULL);
pointer->display = NULL;
@@ -273,8 +272,11 @@ sync_focus_surface (MetaWaylandPointer *pointer)
g_assert_not_reached ();
}
const MetaWaylandPointerGrabInterface *interface = pointer->grab->interface;
interface->focus (pointer->grab, focus_surface);
if (focus_surface != pointer->focus_surface)
{
const MetaWaylandPointerGrabInterface *interface = pointer->grab->interface;
interface->focus (pointer->grab, focus_surface);
}
}
static void
@@ -306,6 +308,9 @@ repick_for_event (MetaWaylandPointer *pointer,
else
pointer->current = NULL;
if (pointer->cursor_tracker && pointer->current == NULL)
meta_cursor_tracker_unset_window_cursor (pointer->cursor_tracker);
sync_focus_surface (pointer);
}
@@ -475,7 +480,8 @@ broadcast_focus (MetaWaylandPointer *pointer,
void
meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface)
MetaWaylandSurface *surface,
gboolean emit_crossing)
{
if (pointer->display == NULL)
return;
@@ -495,9 +501,12 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
struct wl_display *display = wl_client_get_display (client);
uint32_t serial = wl_display_next_serial (display);
wl_resource_for_each (resource, l)
if (emit_crossing)
{
wl_pointer_send_leave (resource, serial, pointer->focus_surface->resource);
wl_resource_for_each (resource, l)
{
wl_pointer_send_leave (resource, serial, pointer->focus_surface->resource);
}
}
move_resources (&pointer->resource_list, &pointer->focus_resource_list);
@@ -518,18 +527,17 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
clutter_input_device_get_coords (pointer->device, NULL, &pos);
if (pointer->focus_surface->window)
meta_window_handle_enter (pointer->focus_surface->window,
/* XXX -- can we reliably get a timestamp for setting focus? */
clutter_get_current_event_time (),
pos.x, pos.y);
meta_window_handle_enter (pointer->focus_surface->window,
/* XXX -- can we reliably get a timestamp for setting focus? */
clutter_get_current_event_time (),
pos.x, pos.y);
move_resources_for_client (&pointer->focus_resource_list,
&pointer->resource_list,
wl_resource_get_client (pointer->focus_surface->resource));
l = &pointer->focus_resource_list;
if (!wl_list_empty (l))
if (emit_crossing && !wl_list_empty (l))
{
struct wl_client *client = wl_resource_get_client (pointer->focus_surface->resource);
struct wl_display *display = wl_client_get_display (client);
@@ -541,8 +549,6 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
}
}
}
meta_wayland_pointer_update_cursor_surface (pointer);
}
void
@@ -567,8 +573,6 @@ meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer)
pointer->grab = &pointer->default_grab;
interface = pointer->grab->interface;
interface->focus (pointer->grab, pointer->current);
meta_wayland_pointer_update_cursor_surface (pointer);
}
typedef struct {
@@ -595,9 +599,9 @@ popup_grab_focus (MetaWaylandPointerGrab *grab,
/* Popup grabs are in owner-events mode (ie, events for the same client
are reported as normal) */
if (surface && wl_resource_get_client (surface->resource) == popup_grab->grab_client)
meta_wayland_pointer_set_focus (grab->pointer, surface);
meta_wayland_pointer_set_focus (grab->pointer, surface, TRUE);
else
meta_wayland_pointer_set_focus (grab->pointer, NULL);
meta_wayland_pointer_set_focus (grab->pointer, NULL, TRUE);
}
static void
@@ -718,10 +722,10 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
popup->grab = grab;
popup->surface = surface;
popup->surface_destroy_listener.notify = on_popup_surface_destroy;
if (surface->xdg_popup)
wl_resource_add_destroy_listener (surface->xdg_popup, &popup->surface_destroy_listener);
else if (surface->wl_shell_surface)
wl_resource_add_destroy_listener (surface->wl_shell_surface, &popup->surface_destroy_listener);
if (surface->xdg_popup.resource)
wl_resource_add_destroy_listener (surface->xdg_popup.resource, &popup->surface_destroy_listener);
else if (surface->wl_shell_surface.resource)
wl_resource_add_destroy_listener (surface->wl_shell_surface.resource, &popup->surface_destroy_listener);
wl_list_insert (&grab->all_popups, &popup->link);
return TRUE;
@@ -753,32 +757,25 @@ meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer,
void
meta_wayland_pointer_update_cursor_surface (MetaWaylandPointer *pointer)
{
MetaCursorReference *cursor;
if (pointer->cursor_tracker == NULL)
return;
if (pointer->current)
if (pointer->cursor_surface && pointer->cursor_surface->buffer)
{
MetaCursorReference *cursor;
if (pointer->cursor_surface && pointer->cursor_surface->buffer)
{
struct wl_resource *buffer = pointer->cursor_surface->buffer->resource;
cursor = meta_cursor_reference_from_buffer (buffer,
pointer->hotspot_x,
pointer->hotspot_y);
}
else
cursor = NULL;
meta_cursor_tracker_set_window_cursor (pointer->cursor_tracker, cursor);
if (cursor)
meta_cursor_reference_unref (cursor);
struct wl_resource *buffer = pointer->cursor_surface->buffer->resource;
cursor = meta_cursor_reference_from_buffer (buffer,
pointer->hotspot_x,
pointer->hotspot_y);
}
else
{
meta_cursor_tracker_unset_window_cursor (pointer->cursor_tracker);
}
cursor = NULL;
meta_cursor_tracker_set_window_cursor (pointer->cursor_tracker, cursor);
if (cursor)
meta_cursor_reference_unref (cursor);
}
static void

View File

@@ -86,7 +86,8 @@ gboolean meta_wayland_pointer_handle_event (MetaWaylandPointer *pointer,
const ClutterEvent *event);
void meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface);
MetaWaylandSurface *surface,
gboolean emit_crossing);
void meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
MetaWaylandPointerGrab *grab);

View File

@@ -24,6 +24,7 @@
#include <clutter/clutter.h>
#include <glib.h>
#include <cairo.h>
#include "window-private.h"
#include <meta/meta-cursor-tracker.h>
@@ -33,6 +34,19 @@
#include "meta-wayland-surface.h"
#include "meta-wayland-seat.h"
typedef struct
{
struct wl_resource *resource;
cairo_region_t *region;
} MetaWaylandRegion;
typedef struct
{
GSource source;
GPollFD pfd;
struct wl_display *display;
} WaylandEventSource;
typedef struct
{
struct wl_list link;
@@ -57,6 +71,7 @@ struct _MetaWaylandCompositor
{
struct wl_display *wayland_display;
const char *display_name;
ClutterActor *stage;
GHashTable *outputs;
struct wl_list frame_callbacks;
@@ -65,4 +80,8 @@ struct _MetaWaylandCompositor
MetaWaylandSeat *seat;
};
MetaWaylandBuffer * meta_wayland_buffer_from_resource (struct wl_resource *resource);
void meta_wayland_buffer_ref (MetaWaylandBuffer *buffer);
void meta_wayland_buffer_unref (MetaWaylandBuffer *buffer);
#endif /* META_WAYLAND_PRIVATE_H */

View File

@@ -1,105 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Endless Mobile
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#include "config.h"
#include "meta-wayland-region.h"
struct _MetaWaylandRegion
{
struct wl_resource *resource;
cairo_region_t *region;
};
static void
wl_region_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
wl_region_add (struct wl_client *client,
struct wl_resource *resource,
gint32 x,
gint32 y,
gint32 width,
gint32 height)
{
MetaWaylandRegion *region = wl_resource_get_user_data (resource);
cairo_rectangle_int_t rectangle = { x, y, width, height };
cairo_region_union_rectangle (region->region, &rectangle);
}
static void
wl_region_subtract (struct wl_client *client,
struct wl_resource *resource,
gint32 x,
gint32 y,
gint32 width,
gint32 height)
{
MetaWaylandRegion *region = wl_resource_get_user_data (resource);
cairo_rectangle_int_t rectangle = { x, y, width, height };
cairo_region_subtract_rectangle (region->region, &rectangle);
}
static const struct wl_region_interface meta_wayland_wl_region_interface = {
wl_region_destroy,
wl_region_add,
wl_region_subtract
};
static void
wl_region_destructor (struct wl_resource *resource)
{
MetaWaylandRegion *region = wl_resource_get_user_data (resource);
cairo_region_destroy (region->region);
g_slice_free (MetaWaylandRegion, region);
}
MetaWaylandRegion *
meta_wayland_region_create (MetaWaylandCompositor *compositor,
struct wl_client *client,
struct wl_resource *compositor_resource,
guint32 id)
{
MetaWaylandRegion *region = g_slice_new0 (MetaWaylandRegion);
region->resource = wl_resource_create (client, &wl_region_interface, wl_resource_get_version (compositor_resource), id);
wl_resource_set_implementation (region->resource, &meta_wayland_wl_region_interface, region, wl_region_destructor);
region->region = cairo_region_create ();
return region;
}
cairo_region_t *
meta_wayland_region_peek_cairo_region (MetaWaylandRegion *region)
{
return region->region;
}

View File

@@ -1,40 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Endless Mobile
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#ifndef META_WAYLAND_REGION_H
#define META_WAYLAND_REGION_H
#include <glib.h>
#include <cairo.h>
#include <wayland-server.h>
#include "meta-wayland-types.h"
MetaWaylandRegion * meta_wayland_region_create (MetaWaylandCompositor *compositor,
struct wl_client *client,
struct wl_resource *compositor_resource,
guint32 id);
cairo_region_t * meta_wayland_region_peek_cairo_region (MetaWaylandRegion *region);
#endif /* META_WAYLAND_REGION_H */

View File

@@ -20,24 +20,29 @@
* 02111-1307, USA.
*/
#include "config.h"
#include "meta-wayland-surface.h"
#include <config.h>
#include <clutter/clutter.h>
#include <clutter/wayland/clutter-wayland-compositor.h>
#include <clutter/wayland/clutter-wayland-surface.h>
#include <cogl/cogl-wayland-server.h>
#include <glib.h>
#include <sys/time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <wayland-server.h>
#include "gtk-shell-server-protocol.h"
#include "xdg-shell-server-protocol.h"
#include "scaler-server-protocol.h"
#include "meta-wayland-private.h"
#include "meta-xwayland-private.h"
#include "meta-wayland-buffer.h"
#include "meta-wayland-region.h"
#include "meta-wayland-seat.h"
#include "meta-wayland-keyboard.h"
#include "meta-wayland-pointer.h"
@@ -47,6 +52,9 @@
#include "display-private.h"
#include "window-private.h"
#include "window-wayland.h"
#include <meta/types.h>
#include <meta/main.h>
#include "frame.h"
#include "meta-surface-actor.h"
#include "meta-surface-actor-wayland.h"
@@ -98,38 +106,67 @@ static void
surface_process_damage (MetaWaylandSurface *surface,
cairo_region_t *region)
{
int i, n_rectangles;
cairo_rectangle_int_t buffer_rect;
int scale = surface->scale;
int i, n_rectangles;
CoglTexture *texture;
struct wl_shm_buffer *shm_buffer;
/* Damage without a buffer makes no sense so ignore that, otherwise we would crash */
if (!surface->buffer)
return;
texture = surface->buffer->texture;
buffer_rect.x = 0;
buffer_rect.y = 0;
buffer_rect.width = cogl_texture_get_width (surface->buffer->texture);
buffer_rect.height = cogl_texture_get_height (surface->buffer->texture);
/* The region will get destroyed after this call anyway so we can
* just modify it here to avoid a copy. */
just modify it here to avoid a copy */
cairo_region_intersect_rectangle (region, &buffer_rect);
/* First update the buffer. */
meta_wayland_buffer_process_damage (surface->buffer, region);
/* Now damage the actor. */
/* XXX: Should this be a signal / callback on MetaWaylandBuffer instead? */
n_rectangles = cairo_region_num_rectangles (region);
shm_buffer = wl_shm_buffer_get (surface->buffer->resource);
for (i = 0; i < n_rectangles; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
if (shm_buffer)
cogl_wayland_texture_set_region_from_shm_buffer (texture, rect.x, rect.y, rect.width, rect.height, shm_buffer, rect.x, rect.y, 0, NULL);
meta_surface_actor_process_damage (surface->surface_actor,
rect.x * scale, rect.y * scale, rect.width * scale, rect.height * scale);
}
}
static void
ensure_buffer_texture (MetaWaylandBuffer *buffer)
{
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
CoglError *catch_error = NULL;
CoglTexture *texture;
if (buffer->texture)
return;
texture = COGL_TEXTURE (cogl_wayland_texture_2d_new_from_buffer (ctx,
buffer->resource,
&catch_error));
if (!texture)
{
cogl_error_free (catch_error);
meta_warning ("Could not import pending buffer, ignoring commit\n");
return;
}
buffer->texture = texture;
}
static void
cursor_surface_commit (MetaWaylandSurface *surface,
MetaWaylandPendingState *pending)
@@ -266,7 +303,6 @@ pending_state_init (MetaWaylandPendingState *state)
wl_list_init (&state->frame_callback_list);
state->has_new_geometry = FALSE;
state->viewport.changed = FALSE;
}
static void
@@ -389,8 +425,8 @@ commit_pending_state (MetaWaylandSurface *surface,
if (pending->buffer)
{
CoglTexture *texture = meta_wayland_buffer_ensure_texture (pending->buffer);
meta_surface_actor_wayland_set_texture (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor), texture);
ensure_buffer_texture (pending->buffer);
meta_surface_actor_wayland_set_texture (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor), pending->buffer->texture);
}
}
@@ -410,35 +446,28 @@ commit_pending_state (MetaWaylandSurface *surface,
}
if (pending->input_region)
{
pending->input_region = scale_region (pending->input_region,
meta_surface_actor_wayland_get_scale (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor)));
pending->input_region = scale_region (pending->input_region, surface->scale);
meta_surface_actor_set_input_region (surface->surface_actor, pending->input_region);
}
/* scale surface texture */
meta_surface_actor_wayland_scale_texture (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
/* wl_surface.frame */
wl_list_insert_list (&compositor->frame_callbacks, &pending->frame_callback_list);
wl_list_init (&pending->frame_callback_list);
if (pending->viewport.changed)
meta_surface_actor_set_viewport (surface->surface_actor,
&pending->viewport.src_rect,
pending->viewport.dest_width,
pending->viewport.dest_height);
if (surface == compositor->seat->pointer.cursor_surface)
cursor_surface_commit (surface, pending);
else if (meta_wayland_data_device_is_dnd_surface (&compositor->seat->data_device, surface))
dnd_surface_commit (surface, pending);
else if (surface->window)
toplevel_surface_commit (surface, pending);
else if (surface->wl_subsurface)
else if (surface->subsurface.resource)
subsurface_surface_commit (surface, pending);
g_list_foreach (surface->subsurfaces, parent_surface_committed, NULL);
/* scale surface texture */
meta_surface_actor_wayland_scale_texture (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
/* wl_surface.frame */
wl_list_insert_list (&compositor->frame_callbacks, &pending->frame_callback_list);
wl_list_init (&pending->frame_callback_list);
pending_state_reset (pending);
}
@@ -549,8 +578,7 @@ wl_surface_set_opaque_region (struct wl_client *client,
if (region_resource)
{
MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
cairo_region_t *cr_region = meta_wayland_region_peek_cairo_region (region);
surface->pending.opaque_region = cairo_region_copy (cr_region);
surface->pending.opaque_region = cairo_region_copy (region->region);
}
}
@@ -569,8 +597,7 @@ wl_surface_set_input_region (struct wl_client *client,
if (region_resource)
{
MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
cairo_region_t *cr_region = meta_wayland_region_peek_cairo_region (region);
surface->pending.input_region = cairo_region_copy (cr_region);
surface->pending.input_region = cairo_region_copy (region->region);
}
}
@@ -627,7 +654,7 @@ surface_should_be_reactive (MetaWaylandSurface *surface)
return TRUE;
/* If we're a subsurface, we should be reactive */
if (surface->wl_subsurface)
if (surface->subsurface.resource)
return TRUE;
return FALSE;
@@ -707,6 +734,33 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor,
return surface;
}
static void
destroy_surface_extension (MetaWaylandSurfaceExtension *extension)
{
extension->resource = NULL;
}
static gboolean
create_surface_extension (MetaWaylandSurfaceExtension *extension,
const struct wl_interface *interface,
const void *implementation,
wl_resource_destroy_func_t destructor,
MetaWaylandSurface *surface,
struct wl_resource *master_resource,
guint32 id)
{
struct wl_client *client;
if (extension->resource != NULL)
return FALSE;
client = wl_resource_get_client (surface->resource);
extension->resource = wl_resource_create (client, interface, wl_resource_get_version (master_resource), id);
wl_resource_set_implementation (extension->resource, implementation, surface, destructor);
return TRUE;
}
static void
xdg_shell_use_unstable_version (struct wl_client *client,
struct wl_resource *resource,
@@ -733,7 +787,7 @@ xdg_surface_destructor (struct wl_resource *resource)
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
destroy_window (surface);
surface->xdg_surface = NULL;
destroy_surface_extension (&surface->xdg_surface);
}
static void
@@ -971,7 +1025,11 @@ xdg_shell_get_xdg_surface (struct wl_client *client,
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWindow *window;
if (surface->xdg_surface != NULL)
if (!create_surface_extension (&surface->xdg_surface,
&xdg_surface_interface,
&meta_wayland_xdg_surface_interface,
xdg_surface_destructor,
surface, resource, id))
{
wl_resource_post_error (surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
@@ -979,9 +1037,6 @@ xdg_shell_get_xdg_surface (struct wl_client *client,
return;
}
surface->xdg_surface = wl_resource_create (client, &xdg_surface_interface, wl_resource_get_version (resource), id);
wl_resource_set_implementation (surface->xdg_surface, &meta_wayland_xdg_surface_interface, surface, xdg_surface_destructor);
surface->xdg_shell_resource = resource;
window = meta_window_wayland_new (meta_get_display (), surface);
@@ -994,7 +1049,7 @@ xdg_popup_destructor (struct wl_resource *resource)
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
destroy_window (surface);
surface->xdg_popup = NULL;
destroy_surface_extension (&surface->xdg_popup);
}
static void
@@ -1024,12 +1079,15 @@ xdg_shell_get_xdg_popup (struct wl_client *client,
MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource);
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
MetaWindow *window;
MetaDisplay *display = meta_get_display ();
if (parent_surf == NULL || parent_surf->window == NULL)
return;
if (surface->xdg_popup != NULL)
if (!create_surface_extension (&surface->xdg_popup,
&xdg_popup_interface,
&meta_wayland_xdg_popup_interface,
xdg_popup_destructor,
surface, resource, id))
{
wl_resource_post_error (surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
@@ -1037,12 +1095,9 @@ xdg_shell_get_xdg_popup (struct wl_client *client,
return;
}
surface->xdg_popup = wl_resource_create (client, &xdg_popup_interface, wl_resource_get_version (resource), id);
wl_resource_set_implementation (surface->xdg_popup, &meta_wayland_xdg_popup_interface, surface, xdg_popup_destructor);
surface->xdg_shell_resource = resource;
window = meta_window_wayland_new (display, surface);
window = meta_window_wayland_new (meta_get_display (), surface);
meta_window_move_frame (window, FALSE,
parent_surf->window->rect.x + x,
parent_surf->window->rect.y + y);
@@ -1053,7 +1108,6 @@ xdg_shell_get_xdg_popup (struct wl_client *client,
meta_wayland_surface_set_window (surface, window);
meta_window_focus (window, meta_display_get_current_time (display));
meta_wayland_pointer_start_popup_grab (&seat->pointer, surface);
}
@@ -1087,7 +1141,7 @@ wl_shell_surface_destructor (struct wl_resource *resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
surface->wl_shell_surface = NULL;
destroy_surface_extension (&surface->wl_shell_surface);
}
static void
@@ -1295,7 +1349,11 @@ wl_shell_get_shell_surface (struct wl_client *client,
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWindow *window;
if (surface->wl_shell_surface != NULL)
if (!create_surface_extension (&surface->wl_shell_surface,
&wl_shell_surface_interface,
&meta_wayland_wl_shell_surface_interface,
wl_shell_surface_destructor,
surface, resource, id))
{
wl_resource_post_error (surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
@@ -1303,9 +1361,6 @@ wl_shell_get_shell_surface (struct wl_client *client,
return;
}
surface->wl_shell_surface = wl_resource_create (client, &wl_shell_surface_interface, wl_resource_get_version (resource), id);
wl_resource_set_implementation (surface->wl_shell_surface, &meta_wayland_wl_shell_surface_interface, surface, wl_shell_surface_destructor);
window = meta_window_wayland_new (meta_get_display (), surface);
meta_wayland_surface_set_window (surface, window);
}
@@ -1331,7 +1386,7 @@ gtk_surface_destructor (struct wl_resource *resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
surface->gtk_surface = NULL;
destroy_surface_extension (&surface->gtk_surface);
}
static void
@@ -1374,16 +1429,17 @@ get_gtk_surface (struct wl_client *client,
{
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
if (surface->gtk_surface != NULL)
if (!create_surface_extension (&surface->gtk_surface,
&gtk_surface_interface,
&meta_wayland_gtk_surface_interface,
gtk_surface_destructor,
surface, resource, id))
{
wl_resource_post_error (surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"gtk_shell::get_gtk_surface already requested");
return;
}
surface->gtk_surface = wl_resource_create (client, &gtk_surface_interface, wl_resource_get_version (resource), id);
wl_resource_set_implementation (surface->gtk_surface, &meta_wayland_gtk_surface_interface, surface, gtk_surface_destructor);
}
static const struct gtk_shell_interface meta_wayland_gtk_shell_interface = {
@@ -1484,7 +1540,7 @@ wl_subsurface_destructor (struct wl_resource *resource)
}
pending_state_destroy (&surface->sub.pending);
surface->wl_subsurface = NULL;
destroy_surface_extension (&surface->subsurface);
}
static void
@@ -1610,7 +1666,7 @@ wl_subsurface_set_desync (struct wl_client *client,
surface->sub.synchronous = FALSE;
}
static const struct wl_subsurface_interface meta_wayland_wl_subsurface_interface = {
static const struct wl_subsurface_interface meta_wayland_subsurface_interface = {
wl_subsurface_destroy,
wl_subsurface_set_position,
wl_subsurface_place_above,
@@ -1648,7 +1704,11 @@ wl_subcompositor_get_subsurface (struct wl_client *client,
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWaylandSurface *parent = wl_resource_get_user_data (parent_resource);
if (surface->wl_subsurface != NULL)
if (!create_surface_extension (&surface->subsurface,
&wl_subsurface_interface,
&meta_wayland_subsurface_interface,
wl_subsurface_destructor,
surface, resource, id))
{
wl_resource_post_error (surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
@@ -1656,9 +1716,6 @@ wl_subcompositor_get_subsurface (struct wl_client *client,
return;
}
surface->wl_subsurface = wl_resource_create (client, &wl_subsurface_interface, wl_resource_get_version (resource), id);
wl_resource_set_implementation (surface->wl_subsurface, &meta_wayland_wl_subsurface_interface, surface, wl_subsurface_destructor);
pending_state_init (&surface->sub.pending);
surface->sub.synchronous = TRUE;
surface->sub.parent = parent;
@@ -1689,136 +1746,6 @@ bind_subcompositor (struct wl_client *client,
wl_resource_set_implementation (resource, &meta_wayland_subcompositor_interface, data, NULL);
}
static void
destroy_wl_viewport (struct wl_resource *resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
surface->has_viewport = FALSE;
surface->pending.viewport.changed = TRUE;
}
static void
wl_viewport_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
viewport_set_src (struct wl_resource *resource,
wl_fixed_t src_x,
wl_fixed_t src_y,
wl_fixed_t src_width,
wl_fixed_t src_height)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
surface->pending.viewport.src_rect.x = wl_fixed_to_int (src_x);
surface->pending.viewport.src_rect.y = wl_fixed_to_int (src_y);
surface->pending.viewport.src_rect.width = wl_fixed_to_int (src_width);
surface->pending.viewport.src_rect.height = wl_fixed_to_int (src_height);
surface->pending.viewport.changed = TRUE;
}
static void
viewport_set_dest (struct wl_resource *resource,
int dst_width,
int dst_height)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
surface->pending.viewport.dest_width = dst_width;
surface->pending.viewport.dest_height = dst_height;
surface->pending.viewport.changed = TRUE;
}
static void
wl_viewport_set (struct wl_client *client,
struct wl_resource *resource,
wl_fixed_t src_x,
wl_fixed_t src_y,
wl_fixed_t src_width,
wl_fixed_t src_height,
int dst_width,
int dst_height)
{
viewport_set_src (resource, src_x, src_y, src_width, src_height);
viewport_set_dest (resource, dst_width, dst_height);
}
static void
wl_viewport_set_source (struct wl_client *client,
struct wl_resource *resource,
wl_fixed_t src_x,
wl_fixed_t src_y,
wl_fixed_t src_width,
wl_fixed_t src_height)
{
viewport_set_src (resource, src_x, src_y, src_width, src_height);
}
static void
wl_viewport_set_destination (struct wl_client *client,
struct wl_resource *resource,
int dst_width,
int dst_height)
{
viewport_set_dest (resource, dst_width, dst_height);
}
static const struct wl_viewport_interface meta_wayland_viewport_interface = {
wl_viewport_destroy,
wl_viewport_set,
wl_viewport_set_source,
wl_viewport_set_destination,
};
static void
wl_scaler_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
wl_scaler_get_viewport (struct wl_client *client,
struct wl_resource *master_resource,
uint32_t viewport_id,
struct wl_resource *surface_resource)
{
struct wl_resource *resource;
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
if (surface->has_viewport)
{
wl_resource_post_error (master_resource,
WL_SCALER_ERROR_VIEWPORT_EXISTS,
"viewport already exists on surface");
return;
}
resource = wl_resource_create (client, &wl_viewport_interface, wl_resource_get_version (master_resource), viewport_id);
wl_resource_set_implementation (resource, &meta_wayland_viewport_interface, surface, destroy_wl_viewport);
surface->has_viewport = TRUE;
}
static const struct wl_scaler_interface meta_wayland_scaler_interface = {
wl_scaler_destroy,
wl_scaler_get_viewport,
};
static void
bind_scaler (struct wl_client *client,
void *data,
guint32 version,
guint32 id)
{
struct wl_resource *resource;
resource = wl_resource_create (client, &wl_scaler_interface, version, id);
wl_resource_set_implementation (resource, &meta_wayland_scaler_interface, data, NULL);
}
void
meta_wayland_shell_init (MetaWaylandCompositor *compositor)
{
@@ -1845,12 +1772,6 @@ meta_wayland_shell_init (MetaWaylandCompositor *compositor)
META_WL_SUBCOMPOSITOR_VERSION,
compositor, bind_subcompositor) == NULL)
g_error ("Failed to register a global wl-subcompositor object");
if (wl_global_create (compositor->wayland_display,
&wl_scaler_interface,
META_WL_SCALER_VERSION,
compositor, bind_scaler) == NULL)
g_error ("Failed to register a global wl-subcompositor object");
}
static void
@@ -1886,9 +1807,9 @@ meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
int new_height,
MetaWaylandSerial *sent_serial)
{
if (surface->xdg_surface)
if (surface->xdg_surface.resource)
{
struct wl_client *client = wl_resource_get_client (surface->xdg_surface);
struct wl_client *client = wl_resource_get_client (surface->xdg_surface.resource);
struct wl_display *display = wl_client_get_display (client);
uint32_t serial = wl_display_next_serial (display);
struct wl_array states;
@@ -1902,7 +1823,7 @@ meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
new_width /= surface->scale;
new_height /= surface->scale;
xdg_surface_send_configure (surface->xdg_surface, new_width, new_height, &states, serial);
xdg_surface_send_configure (surface->xdg_surface.resource, new_width, new_height, &states, serial);
wl_array_release (&states);
@@ -1912,13 +1833,13 @@ meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
sent_serial->value = serial;
}
}
else if (surface->xdg_popup)
else if (surface->xdg_popup.resource)
{
/* This can happen if the popup window loses or receives focus.
* Just ignore it. */
}
else if (surface->wl_shell_surface)
wl_shell_surface_send_configure (surface->wl_shell_surface,
else if (surface->wl_shell_surface.resource)
wl_shell_surface_send_configure (surface->wl_shell_surface.resource,
0, new_width, new_height);
else
g_assert_not_reached ();
@@ -1930,15 +1851,15 @@ meta_wayland_surface_ping (MetaWaylandSurface *surface,
{
if (surface->xdg_shell_resource)
xdg_shell_send_ping (surface->xdg_shell_resource, serial);
else if (surface->wl_shell_surface)
wl_shell_surface_send_ping (surface->wl_shell_surface, serial);
else if (surface->wl_shell_surface.resource)
wl_shell_surface_send_ping (surface->wl_shell_surface.resource, serial);
}
void
meta_wayland_surface_delete (MetaWaylandSurface *surface)
{
if (surface->xdg_surface)
xdg_surface_send_close (surface->xdg_surface);
if (surface->xdg_surface.resource)
xdg_surface_send_close (surface->xdg_surface.resource);
}
void
@@ -1948,8 +1869,8 @@ meta_wayland_surface_popup_done (MetaWaylandSurface *surface)
struct wl_display *display = wl_client_get_display (client);
uint32_t serial = wl_display_next_serial (display);
if (surface->xdg_popup)
xdg_popup_send_popup_done (surface->xdg_popup, serial);
else if (surface->wl_shell_surface)
wl_shell_surface_send_popup_done (surface->wl_shell_surface);
if (surface->xdg_popup.resource)
xdg_popup_send_popup_done (surface->xdg_popup.resource, serial);
else if (surface->wl_shell_surface.resource)
wl_shell_surface_send_popup_done (surface->wl_shell_surface.resource);
}

View File

@@ -36,6 +36,16 @@ struct _MetaWaylandSerial {
uint32_t value;
};
struct _MetaWaylandBuffer
{
struct wl_resource *resource;
struct wl_signal destroy_signal;
struct wl_listener destroy_listener;
CoglTexture *texture;
uint32_t ref_count;
};
typedef struct
{
/* wl_surface.attach */
@@ -58,44 +68,32 @@ typedef struct
MetaRectangle new_geometry;
gboolean has_new_geometry;
struct {
gboolean changed;
cairo_rectangle_int_t src_rect;
int32_t dest_width, dest_height;
} viewport;
} MetaWaylandPendingState;
typedef struct
{
struct wl_resource *resource;
} MetaWaylandSurfaceExtension;
struct _MetaWaylandSurface
{
/* Generic stuff */
struct wl_resource *resource;
MetaWaylandCompositor *compositor;
MetaSurfaceActor *surface_actor;
MetaWindow *window;
struct wl_resource *xdg_shell_resource;
MetaWaylandSurfaceExtension xdg_surface;
MetaWaylandSurfaceExtension xdg_popup;
MetaWaylandSurfaceExtension wl_shell_surface;
MetaWaylandSurfaceExtension gtk_surface;
MetaWaylandSurfaceExtension subsurface;
int scale;
MetaWaylandBuffer *buffer;
struct wl_listener buffer_destroy_listener;
int scale;
int32_t offset_x, offset_y;
GList *subsurfaces;
gboolean has_viewport;
/* All the pending state that wl_surface.commit will apply. */
MetaWaylandPendingState pending;
/* Extension resources. */
struct wl_resource *xdg_surface;
struct wl_resource *xdg_popup;
struct wl_resource *wl_shell_surface;
struct wl_resource *gtk_surface;
struct wl_resource *wl_subsurface;
/* xdg_surface stuff */
struct wl_resource *xdg_shell_resource;
MetaWaylandSerial acked_configure_serial;
gboolean has_set_geometry;
/* wl_subsurface stuff. */
struct {
MetaWaylandSurface *parent;
struct wl_listener parent_destroy_listener;
@@ -116,6 +114,15 @@ struct _MetaWaylandSurface
gboolean pending_pos;
GSList *pending_placement_ops;
} sub;
int32_t offset_x, offset_y;
gboolean has_set_geometry;
/* All the pending state that wl_surface.commit will apply. */
MetaWaylandPendingState pending;
MetaWaylandSerial acked_configure_serial;
};
void meta_wayland_shell_init (MetaWaylandCompositor *compositor);

View File

@@ -32,7 +32,7 @@ typedef struct _MetaWaylandDataSource MetaWaylandDataSource;
typedef struct _MetaWaylandDataDevice MetaWaylandDataDevice;
typedef struct _MetaWaylandBuffer MetaWaylandBuffer;
typedef struct _MetaWaylandRegion MetaWaylandRegion;
typedef struct _MetaWaylandBufferReference MetaWaylandBufferReference;
typedef struct _MetaWaylandSurface MetaWaylandSurface;

View File

@@ -44,6 +44,5 @@
#define META_XSERVER_VERSION 1
#define META_GTK_SHELL_VERSION 1
#define META_WL_SUBCOMPOSITOR_VERSION 1
#define META_WL_SCALER_VERSION 2
#endif

View File

@@ -19,26 +19,40 @@
* 02111-1307, USA.
*/
#include "config.h"
#include "meta-wayland.h"
#include <config.h>
#include <clutter/clutter.h>
#include <clutter/wayland/clutter-wayland-compositor.h>
#include <clutter/wayland/clutter-wayland-surface.h>
#include <glib.h>
#include <sys/time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <wayland-server.h>
#include <meta/meta-backend.h>
#include "meta-wayland-private.h"
#include "meta-xwayland-private.h"
#include "meta-wayland-region.h"
#include "meta-window-actor-private.h"
#include "meta-wayland-seat.h"
#include "meta-wayland-keyboard.h"
#include "meta-wayland-pointer.h"
#include "meta-wayland-outputs.h"
#include "meta-wayland-data-device.h"
#include "meta-cursor-tracker-private.h"
#include "display-private.h"
#include "window-private.h"
#include <meta/types.h>
#include <meta/main.h>
#include "frame.h"
static MetaWaylandCompositor _meta_wayland_compositor;
@@ -56,13 +70,6 @@ get_time (void)
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
typedef struct
{
GSource source;
GPollFD pfd;
struct wl_display *display;
} WaylandEventSource;
static gboolean
wayland_event_source_prepare (GSource *base, int *timeout)
{
@@ -119,6 +126,61 @@ wayland_event_source_new (struct wl_display *display)
return &source->source;
}
static void
meta_wayland_buffer_destroy_handler (struct wl_listener *listener,
void *data)
{
MetaWaylandBuffer *buffer =
wl_container_of (listener, buffer, destroy_listener);
wl_signal_emit (&buffer->destroy_signal, buffer);
g_slice_free (MetaWaylandBuffer, buffer);
}
void
meta_wayland_buffer_ref (MetaWaylandBuffer *buffer)
{
buffer->ref_count++;
}
void
meta_wayland_buffer_unref (MetaWaylandBuffer *buffer)
{
buffer->ref_count--;
if (buffer->ref_count == 0)
{
g_clear_pointer (&buffer->texture, cogl_object_unref);
wl_resource_queue_event (buffer->resource, WL_BUFFER_RELEASE);
}
}
MetaWaylandBuffer *
meta_wayland_buffer_from_resource (struct wl_resource *resource)
{
MetaWaylandBuffer *buffer;
struct wl_listener *listener;
listener =
wl_resource_get_destroy_listener (resource,
meta_wayland_buffer_destroy_handler);
if (listener)
{
buffer = wl_container_of (listener, buffer, destroy_listener);
}
else
{
buffer = g_slice_new0 (MetaWaylandBuffer);
buffer->resource = resource;
wl_signal_init (&buffer->destroy_signal);
buffer->destroy_listener.notify = meta_wayland_buffer_destroy_handler;
wl_resource_add_destroy_listener (resource, &buffer->destroy_listener);
}
return buffer;
}
void
meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
MetaWindow *window)
@@ -140,23 +202,91 @@ wl_compositor_create_surface (struct wl_client *client,
guint32 id)
{
MetaWaylandCompositor *compositor = wl_resource_get_user_data (resource);
meta_wayland_surface_create (compositor, client, resource, id);
}
static void
wl_compositor_create_region (struct wl_client *client,
struct wl_resource *resource,
uint32_t id)
wl_region_destroy (struct wl_client *client,
struct wl_resource *resource)
{
MetaWaylandCompositor *compositor = wl_resource_get_user_data (resource);
meta_wayland_region_create (compositor, client, resource, id);
wl_resource_destroy (resource);
}
const static struct wl_compositor_interface meta_wayland_wl_compositor_interface = {
static void
wl_region_add (struct wl_client *client,
struct wl_resource *resource,
gint32 x,
gint32 y,
gint32 width,
gint32 height)
{
MetaWaylandRegion *region = wl_resource_get_user_data (resource);
cairo_rectangle_int_t rectangle = { x, y, width, height };
cairo_region_union_rectangle (region->region, &rectangle);
}
static void
wl_region_subtract (struct wl_client *client,
struct wl_resource *resource,
gint32 x,
gint32 y,
gint32 width,
gint32 height)
{
MetaWaylandRegion *region = wl_resource_get_user_data (resource);
cairo_rectangle_int_t rectangle = { x, y, width, height };
cairo_region_subtract_rectangle (region->region, &rectangle);
}
static const struct wl_region_interface meta_wayland_region_interface = {
wl_region_destroy,
wl_region_add,
wl_region_subtract
};
static void
meta_wayland_region_resource_destroy_cb (struct wl_resource *resource)
{
MetaWaylandRegion *region = wl_resource_get_user_data (resource);
cairo_region_destroy (region->region);
g_slice_free (MetaWaylandRegion, region);
}
static void
wl_compositor_create_region (struct wl_client *client,
struct wl_resource *compositor_resource,
uint32_t id)
{
MetaWaylandRegion *region = g_slice_new0 (MetaWaylandRegion);
region->resource = wl_resource_create (client, &wl_region_interface, wl_resource_get_version (compositor_resource), id);
wl_resource_set_implementation (region->resource, &meta_wayland_region_interface, region, meta_wayland_region_resource_destroy_cb);
region->region = cairo_region_create ();
}
const static struct wl_compositor_interface meta_wayland_compositor_interface = {
wl_compositor_create_surface,
wl_compositor_create_region
};
void
meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor)
{
while (!wl_list_empty (&compositor->frame_callbacks))
{
MetaWaylandFrameCallback *callback =
wl_container_of (compositor->frame_callbacks.next, callback, link);
wl_callback_send_done (callback->resource, get_time ());
wl_resource_destroy (callback->resource);
}
}
static void
compositor_bind (struct wl_client *client,
void *data,
@@ -167,7 +297,7 @@ compositor_bind (struct wl_client *client,
struct wl_resource *resource;
resource = wl_resource_create (client, &wl_compositor_interface, version, id);
wl_resource_set_implementation (resource, &meta_wayland_wl_compositor_interface, compositor, NULL);
wl_resource_set_implementation (resource, &meta_wayland_compositor_interface, compositor, NULL);
}
/**
@@ -186,19 +316,6 @@ meta_wayland_compositor_update (MetaWaylandCompositor *compositor,
meta_wayland_seat_update (compositor->seat, event);
}
void
meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor)
{
while (!wl_list_empty (&compositor->frame_callbacks))
{
MetaWaylandFrameCallback *callback =
wl_container_of (compositor->frame_callbacks.next, callback, link);
wl_callback_send_done (callback->resource, get_time ());
wl_resource_destroy (callback->resource);
}
}
/**
* meta_wayland_compositor_handle_event:
* @compositor: the #MetaWaylandCompositor instance
@@ -268,6 +385,7 @@ meta_wayland_pre_clutter_init (void)
meta_wayland_compositor_init (compositor);
/* Set up our logging. */
wl_log_set_handler_server (meta_wayland_log_func);
compositor->wayland_display = wl_display_create ();
@@ -283,6 +401,12 @@ meta_wayland_init (void)
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
GSource *wayland_event_source;
if (!wl_global_create (compositor->wayland_display,
&wl_compositor_interface,
META_WL_COMPOSITOR_VERSION,
compositor, compositor_bind))
g_error ("Failed to register the global wl_compositor");
wayland_event_source = wayland_event_source_new (compositor->wayland_display);
/* XXX: Here we are setting the wayland event source to have a
@@ -290,16 +414,13 @@ meta_wayland_init (void)
* much more likely to get confused being told about surface changes
* relating to X clients when we don't know what's happened to them
* according to the X protocol.
*/
*
* At some point we could perhaps try and get the X protocol proxied
* over the wayland protocol so that we don't have to worry about
* synchronizing the two command streams. */
g_source_set_priority (wayland_event_source, GDK_PRIORITY_EVENTS + 1);
g_source_attach (wayland_event_source, NULL);
if (!wl_global_create (compositor->wayland_display,
&wl_compositor_interface,
META_WL_COMPOSITOR_VERSION,
compositor, compositor_bind))
g_error ("Failed to register the global wl_compositor");
wl_display_init_shm (compositor->wayland_display);
meta_wayland_outputs_init (compositor);
@@ -307,10 +428,21 @@ meta_wayland_init (void)
meta_wayland_shell_init (compositor);
meta_wayland_seat_init (compositor);
/* FIXME: find the first free name instead */
compositor->display_name = wl_display_add_socket_auto (compositor->wayland_display);
if (compositor->display_name == NULL)
g_error ("Failed to create socket");
/* XXX: It's important that we only try and start xwayland after we
* have initialized EGL because EGL implements the "wl_drm"
* interface which xwayland requires to determine what drm device
* name it should use.
*
* By waiting until we've shown the stage above we ensure that the
* underlying GL resources for the surface have also been allocated
* and so EGL must be initialized by this point.
*/
if (!meta_xwayland_start (&compositor->xwayland_manager, compositor->wayland_display))
g_error ("Failed to start X Wayland");

View File

@@ -23,8 +23,6 @@
#ifndef META_WAYLAND_H
#define META_WAYLAND_H
#include <clutter/clutter.h>
#include <meta/types.h>
#include "meta-wayland-types.h"
void meta_wayland_pre_clutter_init (void);

View File

@@ -1,210 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="scaler">
<copyright>
Copyright © 2013-2014 Collabora, Ltd.
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</copyright>
<interface name="wl_scaler" version="2">
<description summary="surface cropping and scaling">
The global interface exposing surface cropping and scaling
capabilities is used to instantiate an interface extension for a
wl_surface object. This extended interface will then allow
cropping and scaling the surface contents, effectively
disconnecting the direct relationship between the buffer and the
surface size.
</description>
<request name="destroy" type="destructor">
<description summary="unbind from the cropping and scaling interface">
Informs the server that the client will not be using this
protocol object anymore. This does not affect any other objects,
wl_viewport objects included.
</description>
</request>
<enum name="error">
<entry name="viewport_exists" value="0"
summary="the surface already has a viewport object associated"/>
</enum>
<request name="get_viewport">
<description summary="extend surface interface for crop and scale">
Instantiate an interface extension for the given wl_surface to
crop and scale its content. If the given wl_surface already has
a wl_viewport object associated, the viewport_exists
protocol error is raised.
</description>
<arg name="id" type="new_id" interface="wl_viewport"
summary="the new viewport interface id"/>
<arg name="surface" type="object" interface="wl_surface"
summary="the surface"/>
</request>
</interface>
<interface name="wl_viewport" version="2">
<description summary="crop and scale interface to a wl_surface">
An additional interface to a wl_surface object, which allows the
client to specify the cropping and scaling of the surface
contents.
This interface allows to define the source rectangle (src_x,
src_y, src_width, src_height) from where to take the wl_buffer
contents, and scale that to destination size (dst_width,
dst_height). This state is double-buffered, and is applied on the
next wl_surface.commit.
The two parts of crop and scale state are independent: the source
rectangle, and the destination size. Initially both are unset, that
is, no scaling is applied. The whole of the current wl_buffer is
used as the source, and the surface size is as defined in
wl_surface.attach.
If the destination size is set, it causes the surface size to become
dst_width, dst_height. The source (rectangle) is scaled to exactly
this size. This overrides whatever the attached wl_buffer size is,
unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
has no content and therefore no size. Otherwise, the size is always
at least 1x1 in surface coordinates.
If the source rectangle is set, it defines what area of the
wl_buffer is taken as the source. If the source rectangle is set and
the destination size is not set, the surface size becomes the source
rectangle size rounded up to the nearest integer. If the source size
is already exactly integers, this results in cropping without scaling.
The coordinate transformations from buffer pixel coordinates up to
the surface-local coordinates happen in the following order:
1. buffer_transform (wl_surface.set_buffer_transform)
2. buffer_scale (wl_surface.set_buffer_scale)
3. crop and scale (wl_viewport.set*)
This means, that the source rectangle coordinates of crop and scale
are given in the coordinates after the buffer transform and scale,
i.e. in the coordinates that would be the surface-local coordinates
if the crop and scale was not applied.
If the source rectangle is partially or completely outside of the
wl_buffer, then the surface contents are undefined (not void), and
the surface size is still dst_width, dst_height.
The x, y arguments of wl_surface.attach are applied as normal to
the surface. They indicate how many pixels to remove from the
surface size from the left and the top. In other words, they are
still in the surface-local coordinate system, just like dst_width
and dst_height are.
If the wl_surface associated with the wl_viewport is destroyed,
the wl_viewport object becomes inert.
If the wl_viewport object is destroyed, the crop and scale
state is removed from the wl_surface. The change will be applied
on the next wl_surface.commit.
</description>
<request name="destroy" type="destructor">
<description summary="remove scaling and cropping from the surface">
The associated wl_surface's crop and scale state is removed.
The change is applied on the next wl_surface.commit.
</description>
</request>
<enum name="error">
<entry name="bad_value" value="0"
summary="negative or zero values in width or height"/>
</enum>
<request name="set">
<description summary="set the crop and scale state">
Set both source rectangle and destination size of the associated
wl_surface. See wl_viewport for the description, and relation to
the wl_buffer size.
The bad_value protocol error is raised if src_width or
src_height is negative, or if dst_width or dst_height is not
positive.
The crop and scale state is double-buffered state, and will be
applied on the next wl_surface.commit.
Arguments dst_x and dst_y do not exist here, use the x and y
arguments to wl_surface.attach. The x, y, dst_width, and dst_height
define the surface-local coordinate system irrespective of the
attached wl_buffer size.
</description>
<arg name="src_x" type="fixed" summary="source rectangle x"/>
<arg name="src_y" type="fixed" summary="source rectangle y"/>
<arg name="src_width" type="fixed" summary="source rectangle width"/>
<arg name="src_height" type="fixed" summary="source rectangle height"/>
<arg name="dst_width" type="int" summary="surface width"/>
<arg name="dst_height" type="int" summary="surface height"/>
</request>
<request name="set_source" since="2">
<description summary="set the source rectangle for cropping">
Set the source rectangle of the associated wl_surface. See
wl_viewport for the description, and relation to the wl_buffer
size.
If width is -1.0 and height is -1.0, the destination size is unset
instead. Any other pair of values for width and height that
contains zero or negative values raises the bad_value protocol
error.
The crop and scale state is double-buffered state, and will be
applied on the next wl_surface.commit.
</description>
<arg name="x" type="fixed" summary="source rectangle x"/>
<arg name="y" type="fixed" summary="source rectangle y"/>
<arg name="width" type="fixed" summary="source rectangle width"/>
<arg name="height" type="fixed" summary="source rectangle height"/>
</request>
<request name="set_destination" since="2">
<description summary="set the surface size for scaling">
Set the destination size of the associated wl_surface. See
wl_viewport for the description, and relation to the wl_buffer
size.
If width is -1 and height is -1, the destination size is unset
instead. Any other pair of values for width and height that
contains zero or negative values raises the bad_value protocol
error.
The crop and scale state is double-buffered state, and will be
applied on the next wl_surface.commit.
Arguments x and y do not exist here, use the x and y arguments to
wl_surface.attach. The x, y, width, and height define the
surface-local coordinate system irrespective of the attached
wl_buffer size.
</description>
<arg name="width" type="int" summary="surface width"/>
<arg name="height" type="int" summary="surface height"/>
</request>
</interface>
</protocol>

View File

@@ -509,6 +509,8 @@ meta_window_x11_manage (MetaWindow *window)
meta_icon_cache_init (&priv->icon_cache);
meta_display_register_x_window (display, &window->xwindow, window);
meta_window_x11_update_shape_region (window);
meta_window_x11_update_input_region (window);
/* assign the window to its group, or create a new group if needed */
window->group = NULL;
@@ -566,9 +568,6 @@ meta_window_x11_manage (MetaWindow *window)
meta_window_client_rect_to_frame_rect (window, &rect, &rect);
meta_window_move_resize_internal (window, flags, gravity, rect);
}
meta_window_x11_update_shape_region (window);
meta_window_x11_update_input_region (window);
}
static void