Compare commits

..

31 Commits

Author SHA1 Message Date
Florian Müllner
8b80a70efc Bump version to 3.14.4
Update NEWS.
2015-03-23 18:41:32 +01:00
Florian Müllner
63ad42e1f6 window-x11: Fix height computation of shaded windows
Since commit 6e06648f7, we start out with the invisible frame parts
only, and then add the unconstrained rect's height (which consists of
the visible parts of both frame and client window) *unless* the window
is shaded. While we indeed don't want to add the client height in that
case, we need to explicitly include the visible frame parts now.

https://bugzilla.gnome.org/show_bug.cgi?id=746145
2015-03-23 18:40:19 +01:00
Rui Matos
6b3be51ca8 meta-background: Add a function to refresh all background instances
We need to reload the FBOs under some circumstances, this adds a way
to easily do so.

https://bugzilla.gnome.org/show_bug.cgi?id=739178
2015-03-20 17:11:30 +01:00
Samir Ribic
46d57bf0ac Updated Bosnian translation 2015-03-14 23:06:25 +00:00
Alban Browaeys
8dd7102909 MetaBackgroundActor: glsl: do not mix int and float.
Implicit conversion from int to float is not supported by
GLSL ES.

Fixes:
(gnome-shell:8954): Cogl-WARNING **: Shader compilation failed:
1:2: P0004: High precision not supported, instead compiling high precision as medium precision
4:17: S0001: Type mismatch in arithmetic operation between 'int' and 'float'
when one trigger the overview mode on Mali 400 r1p1 GPU.

https://bugzilla.gnome.org/show_bug.cgi?id=745442
2015-03-03 22:10:43 +01:00
Chris Wilson
7a57e59fcc compositor: Update composite overlay window before unredirecting
The current ordering updates the clip shape of the composite overlay
window after unredirecting the target window. This has the effect of
forcing X to clear the target window and sending an expose to the
application to repaint - causing an unsightly flash. If we update the
shape first, then unredirect, X restores the background of the root
window (sending no expose events as no one is interested) and the
background is typically NONE for the root window. Then the unredirect
paints the contents of the composite backing pixmap over top without
requiring a round trip and waiting for the client to repaint - thus no
flashing.

Fixes regression from

commit d6282716b2
Author: Jasper St. Pierre <jstpierre@mecheye.net>
Date:   Fri Dec 6 17:10:44 2013 -0500

    compositor: Simplify the unredirected window management code

Cc: Jasper St. Pierre <jstpierre@mecheye.net>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

https://bugzilla.gnome.org/show_bug.cgi?id=743858
2015-02-02 15:43:01 +01:00
Rui Matos
6772758a64 display: Fix moving grab op check
We were regarding META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN as a move.

https://bugzilla.gnome.org/show_bug.cgi?id=743254
2015-01-20 17:52:54 +01:00
Florian Müllner
08ba9c689e place: Fix workspace check when collecting relevant windows
When looking for space to place a new window, other non-minimized
windows on the same workspace should be taken into account. However
the current check does not work correctly when the placed window is
located on all workspaces, so handle that case explicitly.

https://bugzilla.gnome.org/show_bug.cgi?id=743217
2015-01-20 00:43:05 +01:00
Muhammet Kara
bdb2dac244 Updated Turkish translation 2015-01-03 08:30:58 +00:00
Florian Müllner
dd9b1ce440 Bump GLib requirement
We have depended on GTask for a while now, bump the GLib requirement
to a new enough version to include that.

https://bugzilla.gnome.org/show_bug.cgi?id=698995
2014-12-29 17:53:52 +01:00
Matej Urbančič
878f0e6443 Updated Slovenian translation 2014-12-26 19:37:02 +01:00
Florian Müllner
fc1f78e8cc Bump version to 3.14.3
Update NEWS.
2014-12-19 12:04:48 +01:00
Rui Matos
25aa942a0e monitor-manager-xrandr: Set CRTC config even if it might be redundant
This optimization breaks our use of XRRScreenResources' timestamps to
detect hotplugs in case one of the outputs is disconnected and the
remaining ones don't need any mode, position or transform adjustments.

In that scenario, when applying the new configuration, we resize the X
screen but never call XRRSetCrtcConfig() and since XRRSetScreenSize()
doesn't take a timestamp and the X server doesn't update its last set
timestamp, when we next get a RRScreenChangeNotify and update
ourselves, XRRScreenResources.timestamp will still be smaller than
XRRScreenResources.configTimestamp which makes us think we're seeing a
new hotplug. We just don't enter an endless loop because the screen
size that we keep applying is always the same and the X server
short-circuits and stops sending us RRScreenChangeNotifys.

Always calling XRRSetCrtcConfig() ensures that the last set timestamp
will be bigger than configTimestamp in the next event and thus making
us trigger the monitors-changed signal properly.

Note that the X server already does basically the same checks that
we're removing here, so doing this shouldn't be a significant
efficiency loss. See

http://cgit.freedesktop.org/xorg/xserver/tree/randr/rrcrtc.c?h=server-1.16-branch#n539

https://bugzilla.gnome.org/show_bug.cgi?id=740838
2014-12-10 19:14:58 +01:00
Owen W. Taylor
56e74b1ea8 MetaWindowActor: don't overwrite send_frame_messages_timer
If the app finished multiple frames before we sent _NET_WM_FRAME_DRAWN,
we could add the send_frame_messages_timer multiple times. In the rare
case that the app immediately closed the window, the older timeout
could potentially then run on the freed actor.

https://bugzilla.gnome.org/show_bug.cgi?id=738686
2014-12-02 11:49:06 -05:00
Owen W. Taylor
7d3204b196 Fix problems resulting in left-over queued frames
* Use -1 rather than 0 as a flag for pending queue entries; 0 is
  a valid frame_counter value from Cogl.
* Consistently handle the fact we can have more than one pending
  entry. It's app misbehavior to submit a new frame before
  _NET_WM_FRAME_DRAWN is received; but we accept such frame messages,
  so we can't just leak them.
* If we remove send_frame_message_timer, assign the current frame counter
  to pending entries.
* To try to avoid regressing on this, when sending _NET_WM_FRAME_TIMINGS
  messages, if we have stale messages, or messages with no frame drawn
  time, warn and remove them from the queue rather than just accumulating.
* Improve commenting.

https://bugzilla.gnome.org/show_bug.cgi?id=738686
2014-12-02 11:49:01 -05:00
Jasper St. Pierre
d7ff632c67 window-x11: Fix windows that set empty input shapes
Windows that set empty input shapes get n_rects of 0 when querying them
later, which makes sense, but the code that interpreted the result
translated it into a NULL input shape, which meant it was the same as
the bounding region. As such, an empty input shape would actually get
interpreted as a full input shape!

We, ourselves, set an empty input shape on tray icon windows in
gnome-shell since we would handle the picking ourselves. This meant that
we'd actually get the MetaSurfaceActorX11 when hovering over the tray
icon, instead of the ShellGTKEmbed that we capture events on and react
to.

This fixes weird tray icon behavior in gnome-shell.
2014-11-26 22:46:59 +01:00
Ray Strode
6d3e64226d Revert "screen: Set a black background for testing purposes"
This reverts commit ec8ed1dbb0.

1) It turns out to add a momentary flicker from the transition
between the login screen and user session
2) It actually isn't needed anymore since bug 733026

https://bugzilla.gnome.org/show_bug.cgi?id=740377
2014-11-20 16:22:55 -05:00
Florian Müllner
2e7b9e0dfe window-actor: Do not request unredirection when destroyed
WindowActors can outlive their corresponding window to animate unmap.
Unredirecting the actor does not make sense in that case, so make
sure to not request it.

https://bugzilla.gnome.org/show_bug.cgi?id=740133
2014-11-14 18:31:02 +01:00
Florian Müllner
08d81b6f7f Bump version to 3.14.2
Update NEWS.
2014-11-12 19:00:56 +01:00
Jasper St. Pierre
e01077914d configure: Actually make gbm optional
Whoops, I made the code work without it, but forgot to strip it from the
actual list of requires packages.

Spotted-by: Rico Tzschichholz <ricotz@ubuntu.com>
2014-11-10 14:54:31 +01:00
Jasper St. Pierre
d7cf6bed63 Make gbm optional
Now it's only required by the native backend. The cursor code is getting
quite messy, but it was already considerable messy to start with.
2014-11-10 14:54:11 +01:00
Jasper St. Pierre
d071ba8446 cursor: Clean up code flow slightly
Reverse the set of expressions so testing for gbm is at the top.
2014-11-10 14:53:19 +01:00
Jonathon Jongsma
4d08e89c16 xrandr: ignore hotplug_mode_update value
The important thing is whether this property exists or not, but the value
doesn't matter.
2014-11-05 16:36:24 -06:00
Rui Matos
21d8c4b032 monitor-manager: Don't try to match the outputs on hotplug
meta_monitor_config_match_current() only matches the number of outputs
and if the output connector, vendor, product and serial match.

This means that we can't use it to bypass doing any
work because it won't detect cases where we actually want to update
ourselves like e.g. an output being turned off either by us or by
another X client (e.g. xrandr).

https://bugzilla.gnome.org/show_bug.cgi?id=738630
2014-11-05 15:51:26 +01:00
Rui Matos
c98686da92 monitor-config: Prevent a crash applying config for a closed lid
When a laptop's lid is closed we try to build and apply a temporary
configuration that disables the laptop's display if we have other
outputs.

This isn't enough though, we must also check if at least one of these
other outputs is enabled otherwise we'll try to resize the screen to
0x0 which (rightfully) hits an assertion.

https://bugzilla.gnome.org/show_bug.cgi?id=739450
2014-10-31 17:38:29 +01:00
Florian Müllner
a19eda5ae7 Bump version to 3.14.1.5
Update NEWS.
2014-10-30 11:01:04 +00:00
Adel Gadllah
0a9bbe0109 meta-wayland-surface: Correcly scale the input region
The input region currently only gets scaled by the surface
scale while ignoring the output scale, which causes input events to not get
delivered correctly for clients on hidpi screens. So take the output scale
into account when doing so.

https://bugzilla.gnome.org/show_bug.cgi?id=739161
2014-10-27 18:13:00 +01:00
Adel Gadllah
a8eb42e43c Revert "wayland-surface: Apply the surface scale only if needed"
This commit is wrong, it assumes that the scale only applies to the one
set by the client but its not. meta_surface_actor_wayland_scale_texture
also handles the output scale. Revert the commit to fix hidpi for wayland
clients like weston-terminal.

This reverts commit 0364ea9140.

https://bugzilla.gnome.org/show_bug.cgi?id=739161
2014-10-27 18:12:52 +01:00
Dušan Kazik
9d0c9f1f42 Updated Slovak translation 2014-10-19 17:43:23 +00:00
Florian Müllner
9fa0743394 Remove unused variable 2014-10-16 11:00:51 +02:00
Jasper St. Pierre
bb79a20fac display: Fix accidental inversion from 2f9c601
Commit 2f9c601 accidentally changed the logic here, changing the grab
behavior when not using raise-on-click. Fix this.

Spotted-by: Adam Goode <adam@spicenitz.org>
2014-10-15 23:54:20 +02:00
48 changed files with 5430 additions and 6810 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

46
NEWS
View File

@@ -1,14 +1,44 @@
3.15.1
3.14.4
======
* 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]
* Fix flash on unredirection [Chris; #743858]
* Fix incompatibility with GLES2 GLSL [Alban; #745442]
* Add function to refresh all background instances [Rui; #739178]
* Fix geometry of shaded windows [Florian; #746145]
* Misc. bug fixes [Florian, Rui; #698995, #743217, #743254]
Contributors:
Cosimo Cecchi, Adel Gadllah, Carlos Garnacho, Rui Matos, Florian Müllner,
Jasper St. Pierre
Alban Browaeys, Rui Matos, Florian Müllner, Chris Wilson
Translations:
Matej Urbančič [sl], Muhammet Kara [tr], Samir Ribic [bs]
3.14.3
======
* Fix crash when trying to unredirect a destroyed window [Florian; #740133]
* Fix "flicker" during startup transition [Ray; #740377]
* Don't leave left-over frames queued [Owen; #738686]
* Set CRTC configuration even if it might be redundant [Rui; #740838]
Contributors:
Rui Matos, Florian Müllner, Jasper St. Pierre, Ray Strode, Owen W. Taylor
3.14.2
======
* Prevent crash applying monitor config for a closed lid [Rui; #739450]
* Misc. fixes [Rui, Jonathon, Jasper; #738630]
Contributors:
Jonathon Jongsma, Rui Matos, Jasper St. Pierre
3.14.1.5
========
* Fix wayland hiDPI regressions [Adel; #739161]
Contributors:
Adel Gadllah, Florian Müllner, Jasper St. Pierre
Translations:
Dušan Kazik [sk]
3.14.1
======

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], [4])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
@@ -72,7 +72,7 @@ CLUTTER_PACKAGE=clutter-1.0
MUTTER_PC_MODULES="
gtk+-3.0 >= 3.9.11
gio-unix-2.0 >= 2.25.10
gio-unix-2.0 >= 2.35.1
pango >= 1.2.0
cairo >= 1.10.0
gsettings-desktop-schemas >= 3.7.3
@@ -200,7 +200,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, [clutter-egl-1.0 libdrm libsystemd libinput gbm >= 10.3], [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"

4046
po/bs.po

File diff suppressed because it is too large Load Diff

1443
po/sk.po

File diff suppressed because it is too large Load Diff

1214
po/sl.po

File diff suppressed because it is too large Load Diff

1940
po/tr.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 \
@@ -169,6 +162,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 +222,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 += \
@@ -261,8 +255,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 +271,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 +290,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 +311,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 +392,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

@@ -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);

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)
@@ -848,45 +830,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
@@ -938,7 +948,7 @@ make_laptop_lid_config (MetaConfiguration *reference)
g_assert (multiple_outputs_are_enabled (reference));
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 +1003,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 +1015,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 &&
multiple_outputs_are_enabled (stored) &&
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 +1081,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 +1093,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 +1101,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 +1153,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 +1186,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 +1213,7 @@ ensure_at_least_one_output (MetaMonitorConfig *self,
MetaOutput *outputs,
unsigned n_outputs)
{
MetaConfiguration *config;
MetaConfiguration *ret;
MetaOutput *primary;
unsigned i;
@@ -1226,29 +1224,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 +1262,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 +1275,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 &&
multiple_outputs_are_enabled (default_config) &&
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 +1327,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 +1340,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 +1356,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))
@@ -1366,8 +1374,7 @@ turn_off_laptop_display (MetaMonitorConfig *self,
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 +1533,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

@@ -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

@@ -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

@@ -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;
};
@@ -436,6 +437,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 +771,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 +801,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,
@@ -836,26 +838,12 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
unsigned int j, n_outputs;
int width, height;
Status ok;
unsigned long old_controlled_mask;
unsigned long new_controlled_mask;
mode = crtc_info->mode;
n_outputs = crtc_info->outputs->len;
outputs = g_new (XID, n_outputs);
old_controlled_mask = 0;
for (j = 0; j < manager->n_outputs; j++)
{
MetaOutput *output;
output = &manager->outputs[j];
if (output->crtc == crtc)
old_controlled_mask |= 1UL << j;
}
new_controlled_mask = 0;
for (j = 0; j < n_outputs; j++)
{
MetaOutput *output;
@@ -864,25 +852,14 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
output->is_dirty = TRUE;
output->crtc = crtc;
new_controlled_mask |= 1UL << j;
outputs[j] = output->winsys_id;
}
if (crtc->current_mode == mode &&
crtc->rect.x == crtc_info->x &&
crtc->rect.y == crtc_info->y &&
crtc->transform == crtc_info->transform &&
old_controlled_mask == new_controlled_mask)
{
/* No change */
goto next;
}
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 +1000,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 +1069,57 @@ 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;
gboolean applied_config = FALSE;
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);
hotplug = manager_xrandr->resources->timestamp < manager_xrandr->resources->configTimestamp;
if (hotplug)
new_config = manager_xrandr->resources->timestamp >= manager_xrandr->resources->configTimestamp;
/* If this is the X server telling us we set a new configuration,
* we can simply short-cut to rebuilding our logical configuration.
*/
if (new_config)
{
/* This is a hotplug event, so go ahead and build a new configuration. */
meta_monitor_manager_on_hotplug (manager);
meta_monitor_manager_xrandr_rebuild_derived (manager);
goto out;
}
else
/* 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 something else changed -- tell the world about it. */
if (old_timestamp < manager_xrandr->resources->timestamp)
meta_monitor_manager_rebuild_derived (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);
out:
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

@@ -614,6 +614,7 @@ set_unredirected_window (MetaCompositor *compositor,
meta_window_actor_set_unredirected (window_actor, FALSE);
}
meta_shape_cow_for_window (compositor, window);
compositor->unredirected_window = window;
if (compositor->unredirected_window != NULL)
@@ -621,8 +622,6 @@ set_unredirected_window (MetaCompositor *compositor,
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (compositor->unredirected_window));
meta_window_actor_set_unredirected (window_actor, TRUE);
}
meta_shape_cow_for_window (compositor, compositor->unredirected_window);
}
void

View File

@@ -115,7 +115,7 @@ typedef enum {
#define FRAGMENT_SHADER_CODE \
"float t = 2.0 * length(position);\n" \
"t = min(t, 1.0);\n" \
"float pixel_brightness = 1 - t * vignette_sharpness;\n" \
"float pixel_brightness = 1.0 - t * vignette_sharpness;\n" \
"cogl_color_out.rgb = cogl_color_out.rgb * pixel_brightness;\n" \
typedef struct _MetaBackgroundLayer MetaBackgroundLayer;

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;
@@ -71,6 +71,8 @@ enum
G_DEFINE_TYPE (MetaBackground, meta_background, G_TYPE_OBJECT)
static GSList *all_backgrounds = NULL;
static void
free_fbos (MetaBackground *self)
{
@@ -241,28 +243,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 +263,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 +282,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);
@@ -305,6 +293,8 @@ meta_background_dispose (GObject *object)
static void
meta_background_finalize (GObject *object)
{
all_backgrounds = g_slist_remove (all_backgrounds, object);
G_OBJECT_CLASS (meta_background_parent_class)->finalize (object);
}
@@ -347,6 +337,7 @@ meta_background_init (MetaBackground *self)
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
META_TYPE_BACKGROUND,
MetaBackgroundPrivate);
all_backgrounds = g_slist_prepend (all_backgrounds, self);
}
static void
@@ -881,19 +872,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 +895,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;
@@ -913,3 +904,12 @@ meta_background_set_blend (MetaBackground *self,
free_wallpaper_texture (self);
mark_changed (self);
}
void
meta_background_refresh_all (void)
{
GSList *l;
for (l = all_backgrounds; l; l = l->next)
mark_changed (l->data);
}

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

@@ -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

@@ -100,7 +100,7 @@ struct _MetaWindowActorPrivate
guint disposed : 1;
/* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN
* client message using the most recent frame in ->frames */
* client message for one or more messages in ->frames */
guint needs_frame_drawn : 1;
guint repaint_scheduled : 1;
@@ -118,10 +118,21 @@ struct _MetaWindowActorPrivate
typedef struct _FrameData FrameData;
/* Each time the application updates the sync request counter to a new even value
* value, we queue a frame into the windows list of frames. Once we're painting
* an update "in response" to the window, we fill in frame_counter with the
* Cogl counter for that frame, and send _NET_WM_FRAME_DRAWN at the end of the
* frame. _NET_WM_FRAME_TIMINGS is sent when we get a frame_complete callback.
*
* As an exception, if a window is completely obscured, we try to throttle drawning
* to a slower frame rate. In this case, frame_counter stays -1 until
* send_frame_message_timeout() runs, at which point we send both the
* _NET_WM_FRAME_DRAWN and _NET_WM_FRAME_TIMINGS messages.
*/
struct _FrameData
{
int64_t frame_counter;
guint64 sync_request_serial;
int64_t frame_counter;
gint64 frame_drawn_time;
};
@@ -655,6 +666,30 @@ clip_shadow_under_window (MetaWindowActor *self)
return is_non_opaque (self) && priv->window->frame;
}
static void
assign_frame_counter_to_frames (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
GList *l;
/* If the window is obscured, then we're expecting to deal with sending
* frame messages in a timeout, rather than in this paint cycle.
*/
if (priv->send_frame_messages_timer != 0)
return;
for (l = priv->frames; l; l = l->next)
{
FrameData *frame = l->data;
if (frame->frame_counter == -1)
{
CoglOnscreen *onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer());
frame->frame_counter = cogl_onscreen_get_frame_counter (onscreen);
}
}
}
static void
meta_window_actor_paint (ClutterActor *actor)
{
@@ -671,6 +706,8 @@ meta_window_actor_paint (ClutterActor *actor)
{
g_source_remove (priv->send_frame_messages_timer);
priv->send_frame_messages_timer = 0;
assign_frame_counter_to_frames (self);
}
if (shadow != NULL)
@@ -873,16 +910,27 @@ send_frame_messages_timeout (gpointer data)
{
MetaWindowActor *self = (MetaWindowActor *) data;
MetaWindowActorPrivate *priv = self->priv;
FrameData *frame = g_slice_new0 (FrameData);
GList *l;
frame->sync_request_serial = priv->window->sync_request_serial;
for (l = priv->frames; l;)
{
GList *l_next = l->next;
FrameData *frame = l->data;
do_send_frame_drawn (self, frame);
do_send_frame_timings (self, frame, 0, 0);
if (frame->frame_counter == -1)
{
do_send_frame_drawn (self, frame);
do_send_frame_timings (self, frame, 0, 0);
priv->frames = g_list_delete_link (priv->frames, l);
frame_data_free (frame);
}
l = l_next;
}
priv->needs_frame_drawn = FALSE;
priv->send_frame_messages_timer = 0;
frame_data_free (frame);
return FALSE;
}
@@ -891,6 +939,10 @@ static void
queue_send_frame_messages_timeout (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
if (priv->send_frame_messages_timer != 0)
return;
MetaDisplay *display = meta_window_get_display (priv->window);
gint64 current_time = meta_compositor_monotonic_time_to_server_time (display, g_get_monotonic_time ());
MetaMonitorManager *monitor_manager = meta_monitor_manager_get ();
@@ -933,6 +985,7 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
return;
frame = g_slice_new0 (FrameData);
frame->frame_counter = -1;
priv->needs_frame_drawn = TRUE;
@@ -1155,7 +1208,7 @@ gboolean
meta_window_actor_should_unredirect (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
if (priv->surface)
if (!meta_window_actor_is_destroyed (self) && priv->surface)
return meta_surface_actor_should_unredirect (priv->surface);
else
return FALSE;
@@ -1905,24 +1958,12 @@ meta_window_actor_handle_updates (MetaWindowActor *self)
void
meta_window_actor_pre_paint (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
GList *l;
if (meta_window_actor_is_destroyed (self))
return;
meta_window_actor_handle_updates (self);
for (l = priv->frames; l != NULL; l = l->next)
{
FrameData *frame = l->data;
if (frame->frame_counter == 0)
{
CoglOnscreen *onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer());
frame->frame_counter = cogl_onscreen_get_frame_counter (onscreen);
}
}
assign_frame_counter_to_frames (self);
}
static void
@@ -1963,16 +2004,23 @@ meta_window_actor_post_paint (MetaWindowActor *self)
if (meta_window_actor_is_destroyed (self))
return;
/* This window had damage, but wasn't actually redrawn because
* it is obscured. So we should wait until timer expiration
* before sending _NET_WM_FRAME_* messages.
*/
if (priv->send_frame_messages_timer != 0)
return;
if (priv->needs_frame_drawn)
/* If the window had damage, but wasn't actually redrawn because
* it is obscured, we should wait until timer expiration before
* sending _NET_WM_FRAME_* messages.
*/
if (priv->send_frame_messages_timer == 0 &&
priv->needs_frame_drawn)
{
do_send_frame_drawn (self, priv->frames->data);
GList *l;
for (l = priv->frames; l; l = l->next)
{
FrameData *frame = l->data;
if (frame->frame_drawn_time == 0)
do_send_frame_drawn (self, frame);
}
priv->needs_frame_drawn = FALSE;
}
@@ -2057,15 +2105,20 @@ meta_window_actor_frame_complete (MetaWindowActor *self,
{
GList *l_next = l->next;
FrameData *frame = l->data;
gint64 frame_counter = cogl_frame_info_get_frame_counter (frame_info);
if (frame->frame_counter == cogl_frame_info_get_frame_counter (frame_info))
if (frame->frame_counter != -1 && frame->frame_counter <= frame_counter)
{
if (frame->frame_drawn_time != 0)
{
priv->frames = g_list_delete_link (priv->frames, l);
send_frame_timings (self, frame, frame_info, presentation_time);
frame_data_free (frame);
}
if (G_UNLIKELY (frame->frame_drawn_time == 0))
g_warning ("%s: Frame has assigned frame counter but no frame drawn time",
priv->window->desc);
if (G_UNLIKELY (frame->frame_counter < frame_counter))
g_warning ("%s: frame_complete callback never occurred for frame %" G_GINT64_FORMAT,
priv->window->desc, frame->frame_counter);
priv->frames = g_list_delete_link (priv->frames, l);
send_frame_timings (self, frame, frame_info, presentation_time);
frame_data_free (frame);
}
l = l_next;

View File

@@ -1214,7 +1214,7 @@ meta_grab_op_is_moving (MetaGrabOp op)
if (!grab_op_is_window (op))
return FALSE;
return (op & META_GRAB_OP_WINDOW_DIR_MASK) == 0;
return !meta_grab_op_is_resizing (op);
}
/**

View File

@@ -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);
}

View File

@@ -779,7 +779,8 @@ meta_window_place (MetaWindow *window,
if (w != window &&
meta_window_showing_on_its_workspace (w) &&
meta_window_located_on_workspace (w, window->workspace))
(window->on_all_workspaces ||
meta_window_located_on_workspace (w, window->workspace)))
windows = g_list_prepend (windows, w);
tmp = tmp->next;

View File

@@ -496,15 +496,6 @@ create_guard_window (Display *xdisplay, MetaScreen *screen)
return guard_window;
}
/* Set a black background on the root window so that we don't
* see confusing old copies of old windows when debugging
* and testing. */
static void
meta_screen_set_background (MetaScreen *screen)
{
XSetWindowBackground (screen->display->xdisplay, screen->xroot, 0x00000000);
}
MetaScreen*
meta_screen_new (MetaDisplay *display,
int number,
@@ -709,7 +700,6 @@ meta_screen_new (MetaDisplay *display,
reload_monitor_infos (screen);
meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
meta_screen_set_background (screen);
/* Handle creating a no_focus_window for this screen */
screen->no_focus_window =

View File

@@ -5851,7 +5851,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 +6110,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

@@ -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

@@ -57,6 +57,8 @@ struct _MetaBackground
MetaBackgroundPrivate *priv;
};
void meta_background_refresh_all (void);
GType meta_background_get_type (void);
MetaBackground *meta_background_new (MetaScreen *screen);
@@ -67,12 +69,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);

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

@@ -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

@@ -518,11 +518,10 @@ 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,

View File

@@ -32,7 +32,6 @@
#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"
@@ -266,7 +265,6 @@ pending_state_init (MetaWaylandPendingState *state)
wl_list_init (&state->frame_callback_list);
state->has_new_geometry = FALSE;
state->viewport.changed = FALSE;
}
static void
@@ -422,12 +420,6 @@ commit_pending_state (MetaWaylandSurface *surface,
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))
@@ -1689,136 +1681,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 +1707,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

View File

@@ -58,12 +58,6 @@ 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;
struct _MetaWaylandSurface
@@ -78,7 +72,6 @@ struct _MetaWaylandSurface
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;

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

@@ -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

@@ -1073,9 +1073,10 @@ meta_window_x11_move_resize_internal (MetaWindow *window,
/* Compute new frame size */
new_w = window->rect.width + borders.invisible.left + borders.invisible.right;
new_h = borders.invisible.top + borders.invisible.bottom;
if (!window->shaded)
new_h += window->rect.height;
if (window->shaded)
new_h = borders.total.top + borders.total.bottom;
else
new_h = window->rect.height + borders.invisible.top + borders.invisible.bottom;
if (new_w != window->frame->rect.width ||
new_h != window->frame->rect.height)
@@ -1684,7 +1685,7 @@ meta_window_x11_update_input_region (MetaWindow *window)
/* Translate the set of XShape rectangles that we
* get from the X server to a cairo_region. */
XRectangle *rects = NULL;
int n_rects, ordering;
int n_rects = -1, ordering;
meta_error_trap_push (window->display);
rects = XShapeGetRectangles (window->display->xdisplay,
@@ -1694,21 +1695,46 @@ meta_window_x11_update_input_region (MetaWindow *window)
&ordering);
meta_error_trap_pop (window->display);
/* XXX: The x shape extension doesn't provide a way to only test if an
* input shape has been specified, so we have to query and throw away the
* rectangles. */
if (rects)
{
if (n_rects > 1 ||
(n_rects == 1 &&
(rects[0].x != 0 ||
rects[0].y != 0 ||
rects[0].width != priv->client_rect.width ||
rects[0].height != priv->client_rect.height)))
region = region_create_from_x_rectangles (rects, n_rects);
/* XXX: The X Shape specification is quite unfortunately specified.
*
* By default, the window has a shape the same as its bounding region,
* which we consider "NULL".
*
* If the window sets an empty region, then we'll get n_rects as 0
* and rects as NULL, which we need to transform back into an empty
* region.
*
* It would be great to have a less-broken extension for this, but
* hey, it's X11!
*/
XFree (rects);
if (n_rects == -1)
{
/* We had an error. */
region = NULL;
}
else if (n_rects == 0)
{
/* Client set an empty region. */
region = cairo_region_create ();
}
else if (n_rects == 1 &&
(rects[0].x == 0 ||
rects[0].y == 0 ||
rects[0].width == priv->client_rect.width ||
rects[0].height == priv->client_rect.height))
{
/* This is the bounding region case. Keep the
* region as NULL. */
region = NULL;
}
else
{
/* Window has a custom shape. */
region = region_create_from_x_rectangles (rects, n_rects);
}
meta_XFree (rects);
}
if (region != NULL)