Compare commits
37 Commits
Author | SHA1 | Date | |
---|---|---|---|
63e31af476 | |||
718a89eb2f | |||
a43ca7b5b1 | |||
af00ca534a | |||
4b2b431700 | |||
2c1a6b6a12 | |||
b3544f8ec1 | |||
df384965c3 | |||
700d367937 | |||
7c5989c978 | |||
8819d9ce66 | |||
b63413e5b0 | |||
cd1e1d4bf1 | |||
9710c013c5 | |||
05f8d79323 | |||
f2546dfeea | |||
47e339b46e | |||
016b8f5b4a | |||
b3821c4f90 | |||
29e5c6c363 | |||
e1704acda4 | |||
60cbb41f42 | |||
d88c8d9ced | |||
60ab11ecbf | |||
34516aeab6 | |||
a37f632b1b | |||
8a6542c242 | |||
7e12000d97 | |||
23f086da8a | |||
4c2c1c4dd2 | |||
545f298921 | |||
64295e8cd7 | |||
722d4c6c17 | |||
cc8462969d | |||
989bb6ebb1 | |||
1dbda68839 | |||
a460f88b31 |
12
NEWS
12
NEWS
@ -1,3 +1,15 @@
|
||||
3.15.1
|
||||
======
|
||||
* Use GResources for theme loading [Cosimo; #736936]
|
||||
* Fix headerbar drag getting stuck on xwayland [Carlos; #738411]
|
||||
* Fix wayland hiDPI regressions [Adel; #739161]
|
||||
* Misc bug fixes and cleanups [Jasper, Rui, Carlos; #662962, #738630, #738888,
|
||||
#738890]
|
||||
|
||||
Contributors:
|
||||
Cosimo Cecchi, Adel Gadllah, Carlos Garnacho, Rui Matos, Florian Müllner,
|
||||
Jasper St. Pierre
|
||||
|
||||
3.14.1
|
||||
======
|
||||
* Fix move-titlebar-onscreen function [Florian; #736915]
|
||||
|
@ -1,7 +1,7 @@
|
||||
AC_PREREQ(2.62)
|
||||
|
||||
m4_define([mutter_major_version], [3])
|
||||
m4_define([mutter_minor_version], [14])
|
||||
m4_define([mutter_minor_version], [15])
|
||||
m4_define([mutter_micro_version], [1])
|
||||
|
||||
m4_define([mutter_version],
|
||||
@ -78,7 +78,6 @@ MUTTER_PC_MODULES="
|
||||
gsettings-desktop-schemas >= 3.7.3
|
||||
$CLUTTER_PACKAGE >= 1.19.5
|
||||
cogl-1.0 >= 1.17.1
|
||||
gbm >= 10.3
|
||||
upower-glib >= 0.99.0
|
||||
gnome-desktop-3.0
|
||||
xcomposite >= 0.2
|
||||
@ -201,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], [have_native_backend=yes], [have_native_backend=no])
|
||||
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])
|
||||
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
|
||||
|
@ -259,8 +259,6 @@ 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"
|
||||
|
@ -41,11 +41,9 @@ 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 testgradient testasyncgetprop
|
||||
noinst_PROGRAMS+=testboxes testasyncgetprop
|
||||
|
||||
testboxes_LDADD = $(MUTTER_LIBS) libmutter.la
|
||||
testgradient_LDADD = $(MUTTER_LIBS) libmutter.la
|
||||
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la
|
||||
|
@ -162,8 +162,6 @@ 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 \
|
||||
@ -290,7 +288,6 @@ libmutterinclude_headers = \
|
||||
meta/compositor.h \
|
||||
meta/display.h \
|
||||
meta/errors.h \
|
||||
meta/gradient.h \
|
||||
meta/group.h \
|
||||
meta/keybindings.h \
|
||||
meta/main.h \
|
||||
|
@ -29,8 +29,11 @@
|
||||
|
||||
typedef struct {
|
||||
CoglTexture2D *texture;
|
||||
struct gbm_bo *bo;
|
||||
int hot_x, hot_y;
|
||||
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
struct gbm_bo *bo;
|
||||
#endif
|
||||
} MetaCursorImage;
|
||||
|
||||
struct _MetaCursorReference {
|
||||
@ -44,8 +47,10 @@ CoglTexture *meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor
|
||||
int *hot_x,
|
||||
int *hot_y);
|
||||
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
struct gbm_bo *meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
|
||||
int *hot_x,
|
||||
int *hot_y);
|
||||
#endif
|
||||
|
||||
#endif /* META_CURSOR_PRIVATE_H */
|
||||
|
@ -56,8 +56,11 @@ static void
|
||||
meta_cursor_image_free (MetaCursorImage *image)
|
||||
{
|
||||
cogl_object_unref (image->texture);
|
||||
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
if (image->bo)
|
||||
gbm_bo_destroy (image->bo);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
@ -139,10 +142,10 @@ load_cursor_on_client (MetaCursor cursor)
|
||||
meta_prefs_get_cursor_size ());
|
||||
}
|
||||
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
static void
|
||||
get_hardware_cursor_size (uint64_t *cursor_width, uint64_t *cursor_height)
|
||||
{
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
MetaBackend *meta_backend = meta_get_backend ();
|
||||
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
|
||||
|
||||
@ -151,11 +154,12 @@ get_hardware_cursor_size (uint64_t *cursor_width, uint64_t *cursor_height)
|
||||
meta_cursor_renderer_native_get_cursor_size (META_CURSOR_RENDERER_NATIVE (renderer), cursor_width, cursor_height);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
static void
|
||||
meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm,
|
||||
MetaCursorImage *image,
|
||||
@ -193,20 +197,21 @@ meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm,
|
||||
else
|
||||
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
static struct gbm_device *
|
||||
get_gbm_device (void)
|
||||
{
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
MetaBackend *meta_backend = meta_get_backend ();
|
||||
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
|
||||
|
||||
if (META_IS_CURSOR_RENDERER_NATIVE (renderer))
|
||||
return meta_cursor_renderer_native_get_gbm_device (META_CURSOR_RENDERER_NATIVE (renderer));
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
meta_cursor_image_load_from_xcursor_image (MetaCursorImage *image,
|
||||
@ -214,16 +219,13 @@ meta_cursor_image_load_from_xcursor_image (MetaCursorImage *image,
|
||||
{
|
||||
uint width, height, rowstride;
|
||||
CoglPixelFormat cogl_format;
|
||||
uint32_t gbm_format;
|
||||
ClutterBackend *clutter_backend;
|
||||
CoglContext *cogl_context;
|
||||
struct gbm_device *gbm;
|
||||
|
||||
width = xc_image->width;
|
||||
height = xc_image->height;
|
||||
rowstride = width * 4;
|
||||
|
||||
gbm_format = GBM_FORMAT_ARGB8888;
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
|
||||
#else
|
||||
@ -242,13 +244,15 @@ meta_cursor_image_load_from_xcursor_image (MetaCursorImage *image,
|
||||
(uint8_t *) xc_image->pixels,
|
||||
NULL);
|
||||
|
||||
gbm = get_gbm_device ();
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
struct gbm_device *gbm = get_gbm_device ();
|
||||
if (gbm)
|
||||
meta_cursor_image_load_gbm_buffer (gbm,
|
||||
image,
|
||||
(uint8_t *) xc_image->pixels,
|
||||
width, height, rowstride,
|
||||
gbm_format);
|
||||
GBM_FORMAT_ARGB8888);
|
||||
#endif
|
||||
}
|
||||
|
||||
MetaCursorReference *
|
||||
@ -277,14 +281,8 @@ meta_cursor_image_load_from_buffer (MetaCursorImage *image,
|
||||
int hot_x,
|
||||
int hot_y)
|
||||
{
|
||||
struct gbm_device *gbm = get_gbm_device ();
|
||||
|
||||
ClutterBackend *backend;
|
||||
CoglContext *cogl_context;
|
||||
struct wl_shm_buffer *shm_buffer;
|
||||
uint32_t gbm_format;
|
||||
uint64_t cursor_width, cursor_height;
|
||||
uint width, height;
|
||||
|
||||
image->hot_x = hot_x;
|
||||
image->hot_y = hot_y;
|
||||
@ -294,13 +292,19 @@ meta_cursor_image_load_from_buffer (MetaCursorImage *image,
|
||||
|
||||
image->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL);
|
||||
|
||||
width = cogl_texture_get_width (COGL_TEXTURE (image->texture));
|
||||
height = cogl_texture_get_height (COGL_TEXTURE (image->texture));
|
||||
|
||||
shm_buffer = wl_shm_buffer_get (buffer);
|
||||
if (shm_buffer)
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
struct gbm_device *gbm = get_gbm_device ();
|
||||
if (gbm)
|
||||
{
|
||||
if (gbm)
|
||||
uint32_t gbm_format;
|
||||
uint64_t cursor_width, cursor_height;
|
||||
uint width, height;
|
||||
|
||||
width = cogl_texture_get_width (COGL_TEXTURE (image->texture));
|
||||
height = cogl_texture_get_height (COGL_TEXTURE (image->texture));
|
||||
|
||||
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (buffer);
|
||||
if (shm_buffer)
|
||||
{
|
||||
int rowstride = wl_shm_buffer_get_stride (shm_buffer);
|
||||
|
||||
@ -332,10 +336,7 @@ meta_cursor_image_load_from_buffer (MetaCursorImage *image,
|
||||
width, height, rowstride,
|
||||
gbm_format);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gbm)
|
||||
else
|
||||
{
|
||||
/* HW cursors have a predefined size (at least 64x64), which usually is bigger than cursor theme
|
||||
size, so themed cursors must be padded with transparent pixels to fill the
|
||||
@ -356,6 +357,7 @@ meta_cursor_image_load_from_buffer (MetaCursorImage *image,
|
||||
meta_warning ("Importing HW cursor from wl_buffer failed\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
MetaCursorReference *
|
||||
@ -385,6 +387,7 @@ meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor,
|
||||
return COGL_TEXTURE (cursor->image.texture);
|
||||
}
|
||||
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
struct gbm_bo *
|
||||
meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
|
||||
int *hot_x,
|
||||
@ -396,6 +399,7 @@ meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
|
||||
*hot_y = cursor->image.hot_y;
|
||||
return cursor->image.bo;
|
||||
}
|
||||
#endif
|
||||
|
||||
MetaCursor
|
||||
meta_cursor_reference_get_meta_cursor (MetaCursorReference *cursor)
|
||||
|
@ -67,6 +67,7 @@ typedef struct {
|
||||
} MetaOutputConfig;
|
||||
|
||||
typedef struct {
|
||||
guint refcount;
|
||||
MetaOutputKey *keys;
|
||||
MetaOutputConfig *outputs;
|
||||
unsigned int n_outputs;
|
||||
@ -77,7 +78,6 @@ struct _MetaMonitorConfig {
|
||||
|
||||
GHashTable *configs;
|
||||
MetaConfiguration *current;
|
||||
gboolean current_is_stored;
|
||||
gboolean current_is_for_laptop_lid;
|
||||
MetaConfiguration *previous;
|
||||
|
||||
@ -124,11 +124,29 @@ config_clear (MetaConfiguration *config)
|
||||
g_free (config->outputs);
|
||||
}
|
||||
|
||||
static void
|
||||
config_free (gpointer config)
|
||||
static MetaConfiguration *
|
||||
config_ref (MetaConfiguration *config)
|
||||
{
|
||||
config_clear (config);
|
||||
g_slice_free (MetaConfiguration, config);
|
||||
config->refcount++;
|
||||
return config;
|
||||
}
|
||||
|
||||
static void
|
||||
config_unref (MetaConfiguration *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;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
@ -220,7 +238,7 @@ meta_monitor_config_init (MetaMonitorConfig *self)
|
||||
const char *filename;
|
||||
char *path;
|
||||
|
||||
self->configs = g_hash_table_new_full (config_hash, config_equal, NULL, config_free);
|
||||
self->configs = g_hash_table_new_full (config_hash, config_equal, NULL, (GDestroyNotify) config_unref);
|
||||
|
||||
filename = g_getenv ("MUTTER_MONITOR_FILENAME");
|
||||
if (filename == NULL)
|
||||
@ -796,27 +814,6 @@ make_config_key (MetaConfiguration *key,
|
||||
key->n_outputs = o;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_monitor_config_match_current (MetaMonitorConfig *self,
|
||||
MetaMonitorManager *manager)
|
||||
{
|
||||
MetaOutput *outputs;
|
||||
unsigned n_outputs;
|
||||
MetaConfiguration key;
|
||||
gboolean ok;
|
||||
|
||||
if (self->current == NULL)
|
||||
return FALSE;
|
||||
|
||||
outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
|
||||
|
||||
make_config_key (&key, outputs, n_outputs, -1);
|
||||
ok = config_equal (&key, self->current);
|
||||
|
||||
config_clear (&key);
|
||||
return ok;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager)
|
||||
{
|
||||
@ -851,73 +848,45 @@ 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,
|
||||
gboolean stored)
|
||||
MetaMonitorManager *manager)
|
||||
{
|
||||
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))
|
||||
{
|
||||
g_ptr_array_unref (crtcs);
|
||||
g_ptr_array_unref (outputs);
|
||||
if (!stored)
|
||||
config_free (config);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
goto out;
|
||||
|
||||
meta_monitor_manager_apply_configuration (manager,
|
||||
(MetaCRTCInfo**)crtcs->pdata, crtcs->len,
|
||||
(MetaOutputInfo**)outputs->pdata, outputs->len);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
set_current (self, config);
|
||||
|
||||
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()
|
||||
*/
|
||||
* inside turn_off_laptop_display / apply_configuration_with_lid */
|
||||
self->current_is_for_laptop_lid = FALSE;
|
||||
|
||||
if (self->current == self->previous)
|
||||
self->previous = NULL;
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
g_ptr_array_unref (crtcs);
|
||||
g_ptr_array_unref (outputs);
|
||||
return TRUE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -956,7 +925,7 @@ make_laptop_lid_config (MetaConfiguration *reference)
|
||||
|
||||
g_assert (reference->n_outputs > 1);
|
||||
|
||||
new = g_slice_new0 (MetaConfiguration);
|
||||
new = config_new ();
|
||||
new->n_outputs = reference->n_outputs;
|
||||
new->keys = g_new0 (MetaOutputKey, reference->n_outputs);
|
||||
new->outputs = g_new0 (MetaOutputConfig, reference->n_outputs);
|
||||
@ -1011,6 +980,32 @@ 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 &&
|
||||
config->n_outputs > 1 &&
|
||||
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)
|
||||
@ -1023,23 +1018,7 @@ meta_monitor_config_apply_stored (MetaMonitorConfig *self,
|
||||
stored = meta_monitor_config_get_stored (self, outputs, n_outputs);
|
||||
|
||||
if (stored)
|
||||
{
|
||||
if (self->lid_is_closed &&
|
||||
stored->n_outputs > 1 &&
|
||||
laptop_display_is_on (stored))
|
||||
{
|
||||
if (apply_configuration (self, make_laptop_lid_config (stored),
|
||||
manager, FALSE))
|
||||
{
|
||||
self->current_is_for_laptop_lid = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
return apply_configuration (self, stored, manager, TRUE);
|
||||
}
|
||||
return apply_configuration_with_lid (self, stored, manager);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
@ -1101,7 +1080,7 @@ make_default_config (MetaMonitorConfig *self,
|
||||
MetaConfiguration *ret;
|
||||
MetaOutput *primary;
|
||||
|
||||
ret = g_slice_new (MetaConfiguration);
|
||||
ret = config_new ();
|
||||
make_config_key (ret, outputs, n_outputs, -1);
|
||||
ret->outputs = g_new0 (MetaOutputConfig, n_outputs);
|
||||
|
||||
@ -1221,7 +1200,7 @@ ensure_at_least_one_output (MetaMonitorConfig *self,
|
||||
MetaOutput *outputs,
|
||||
unsigned n_outputs)
|
||||
{
|
||||
MetaConfiguration *ret;
|
||||
MetaConfiguration *config;
|
||||
MetaOutput *primary;
|
||||
unsigned i;
|
||||
|
||||
@ -1232,9 +1211,9 @@ ensure_at_least_one_output (MetaMonitorConfig *self,
|
||||
|
||||
/* Oh no, we don't! Activate the primary one and disable everything else */
|
||||
|
||||
ret = g_slice_new (MetaConfiguration);
|
||||
make_config_key (ret, outputs, n_outputs, -1);
|
||||
ret->outputs = g_new0 (MetaOutputConfig, n_outputs);
|
||||
config = config_new ();
|
||||
make_config_key (config, outputs, n_outputs, -1);
|
||||
config->outputs = g_new0 (MetaOutputConfig, n_outputs);
|
||||
|
||||
primary = find_primary_output (outputs, n_outputs);
|
||||
|
||||
@ -1244,22 +1223,23 @@ ensure_at_least_one_output (MetaMonitorConfig *self,
|
||||
|
||||
if (output == primary)
|
||||
{
|
||||
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;
|
||||
config->outputs[i].enabled = TRUE;
|
||||
config->outputs[i].rect.x = 0;
|
||||
config->outputs[i].rect.y = 0;
|
||||
config->outputs[i].rect.width = output->preferred_mode->width;
|
||||
config->outputs[i].rect.height = output->preferred_mode->height;
|
||||
config->outputs[i].refresh_rate = output->preferred_mode->refresh_rate;
|
||||
config->outputs[i].transform = META_MONITOR_TRANSFORM_NORMAL;
|
||||
config->outputs[i].is_primary = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret->outputs[i].enabled = FALSE;
|
||||
config->outputs[i].enabled = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
apply_configuration (self, ret, manager, FALSE);
|
||||
apply_configuration (self, config, manager);
|
||||
config_unref (config);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -1270,7 +1250,7 @@ meta_monitor_config_make_default (MetaMonitorConfig *self,
|
||||
MetaOutput *outputs;
|
||||
MetaConfiguration *default_config;
|
||||
unsigned n_outputs;
|
||||
gboolean ok;
|
||||
gboolean ok = FALSE;
|
||||
int max_width, max_height;
|
||||
|
||||
outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
|
||||
@ -1283,22 +1263,11 @@ meta_monitor_config_make_default (MetaMonitorConfig *self,
|
||||
}
|
||||
|
||||
default_config = make_default_config (self, outputs, n_outputs, max_width, max_height);
|
||||
|
||||
if (default_config != NULL)
|
||||
{
|
||||
if (self->lid_is_closed &&
|
||||
default_config->n_outputs > 1 &&
|
||||
laptop_display_is_on (default_config))
|
||||
{
|
||||
ok = apply_configuration (self, make_laptop_lid_config (default_config),
|
||||
manager, FALSE);
|
||||
config_free (default_config);
|
||||
}
|
||||
else
|
||||
ok = apply_configuration (self, default_config, manager, FALSE);
|
||||
ok = apply_configuration_with_lid (self, default_config, manager);
|
||||
config_unref (default_config);
|
||||
}
|
||||
else
|
||||
ok = FALSE;
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
@ -1335,7 +1304,7 @@ meta_monitor_config_update_current (MetaMonitorConfig *self,
|
||||
|
||||
outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
|
||||
|
||||
current = g_slice_new (MetaConfiguration);
|
||||
current = config_new ();
|
||||
current->n_outputs = n_outputs;
|
||||
current->outputs = g_new0 (MetaOutputConfig, n_outputs);
|
||||
current->keys = g_new0 (MetaOutputKey, n_outputs);
|
||||
@ -1348,15 +1317,11 @@ meta_monitor_config_update_current (MetaMonitorConfig *self,
|
||||
|
||||
if (self->current && config_equal_full (current, self->current))
|
||||
{
|
||||
config_free (current);
|
||||
config_unref (current);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->current && !self->current_is_stored)
|
||||
config_free (self->current);
|
||||
|
||||
self->current = current;
|
||||
self->current_is_stored = FALSE;
|
||||
set_current (self, current);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1364,7 +1329,17 @@ meta_monitor_config_restore_previous (MetaMonitorConfig *self,
|
||||
MetaMonitorManager *manager)
|
||||
{
|
||||
if (self->previous)
|
||||
apply_configuration (self, self->previous, manager, FALSE);
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!meta_monitor_config_apply_stored (self, manager))
|
||||
@ -1382,7 +1357,8 @@ turn_off_laptop_display (MetaMonitorConfig *self,
|
||||
return;
|
||||
|
||||
new = make_laptop_lid_config (self->current);
|
||||
apply_configuration (self, new, manager, FALSE);
|
||||
apply_configuration (self, new, manager);
|
||||
config_unref (new);
|
||||
self->current_is_for_laptop_lid = TRUE;
|
||||
}
|
||||
|
||||
@ -1541,16 +1517,7 @@ meta_monitor_config_save (MetaMonitorConfig *self)
|
||||
void
|
||||
meta_monitor_config_make_persistent (MetaMonitorConfig *self)
|
||||
{
|
||||
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;
|
||||
|
||||
g_hash_table_replace (self->configs, self->current, config_ref (self->current));
|
||||
meta_monitor_config_save (self);
|
||||
}
|
||||
|
||||
|
@ -36,9 +36,6 @@ GType meta_monitor_config_get_type (void) G_GNUC_CONST;
|
||||
|
||||
MetaMonitorConfig *meta_monitor_config_new (void);
|
||||
|
||||
gboolean meta_monitor_config_match_current (MetaMonitorConfig *config,
|
||||
MetaMonitorManager *manager);
|
||||
|
||||
gboolean meta_monitor_config_apply_stored (MetaMonitorConfig *config,
|
||||
MetaMonitorManager *manager);
|
||||
|
||||
|
@ -58,14 +58,6 @@ 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:
|
||||
*
|
||||
@ -198,7 +190,7 @@ meta_monitor_manager_constructed (GObject *object)
|
||||
|
||||
manager->config = meta_monitor_config_new ();
|
||||
|
||||
read_current_config (manager);
|
||||
meta_monitor_manager_read_current_config (manager);
|
||||
|
||||
if (!meta_monitor_config_apply_stored (manager->config, manager))
|
||||
meta_monitor_config_make_default (manager->config, manager);
|
||||
@ -211,24 +203,7 @@ meta_monitor_manager_constructed (GObject *object)
|
||||
so this is not needed.
|
||||
*/
|
||||
if (META_IS_MONITOR_MANAGER_XRANDR (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);
|
||||
}
|
||||
meta_monitor_manager_read_current_config (manager);
|
||||
|
||||
make_logical_config (manager);
|
||||
initialize_dbus_interface (manager);
|
||||
@ -236,7 +211,7 @@ meta_monitor_manager_constructed (GObject *object)
|
||||
manager->in_init = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
|
||||
int n_old_outputs)
|
||||
{
|
||||
@ -259,7 +234,7 @@ meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
|
||||
g_free (old_outputs);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
|
||||
int n_old_modes)
|
||||
{
|
||||
@ -1162,6 +1137,31 @@ 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,3 +1179,22 @@ 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);
|
||||
}
|
||||
|
@ -339,11 +339,9 @@ 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 */
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-monitor-manager-kms.h"
|
||||
#include "meta-monitor-config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@ -40,6 +41,8 @@
|
||||
#include <meta/errors.h>
|
||||
#include "edid.h"
|
||||
|
||||
#include <gudev/gudev.h>
|
||||
|
||||
typedef struct {
|
||||
drmModeConnector *connector;
|
||||
|
||||
@ -68,6 +71,8 @@ struct _MetaMonitorManagerKms
|
||||
unsigned int n_encoders;
|
||||
|
||||
drmModeEncoder *current_encoder;
|
||||
|
||||
GUdevClient *udev;
|
||||
};
|
||||
|
||||
struct _MetaMonitorManagerKmsClass
|
||||
@ -893,6 +898,23 @@ 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)
|
||||
{
|
||||
@ -907,6 +929,21 @@ 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
|
||||
@ -925,6 +962,7 @@ 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;
|
||||
|
@ -57,7 +57,6 @@ struct _MetaMonitorManagerXrandr
|
||||
|
||||
Display *xdisplay;
|
||||
XRRScreenResources *resources;
|
||||
int time;
|
||||
int rr_event_base;
|
||||
int rr_error_base;
|
||||
};
|
||||
@ -413,7 +412,6 @@ 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;
|
||||
@ -747,7 +745,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
|
||||
XRRSetCrtcConfig (manager_xrandr->xdisplay,
|
||||
manager_xrandr->resources,
|
||||
(XID)crtc->crtc_id,
|
||||
manager_xrandr->time,
|
||||
CurrentTime,
|
||||
0, 0,
|
||||
None,
|
||||
RR_Rotate_0,
|
||||
@ -777,7 +775,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
|
||||
XRRSetCrtcConfig (manager_xrandr->xdisplay,
|
||||
manager_xrandr->resources,
|
||||
(XID)crtc->crtc_id,
|
||||
manager_xrandr->time,
|
||||
CurrentTime,
|
||||
0, 0,
|
||||
None,
|
||||
RR_Rotate_0,
|
||||
@ -860,7 +858,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
|
||||
ok = XRRSetCrtcConfig (manager_xrandr->xdisplay,
|
||||
manager_xrandr->resources,
|
||||
(XID)crtc->crtc_id,
|
||||
manager_xrandr->time,
|
||||
CurrentTime,
|
||||
crtc_info->x, crtc_info->y,
|
||||
(XID)mode->mode_id,
|
||||
meta_monitor_transform_to_xrandr (crtc_info->transform),
|
||||
@ -1001,16 +999,6 @@ 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)
|
||||
{
|
||||
@ -1070,57 +1058,30 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
|
||||
XEvent *event)
|
||||
{
|
||||
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
|
||||
MetaOutput *old_outputs;
|
||||
MetaCRTC *old_crtcs;
|
||||
MetaMonitorMode *old_modes;
|
||||
unsigned int n_old_outputs, n_old_modes;
|
||||
gboolean new_config;
|
||||
gboolean applied_config = FALSE;
|
||||
gboolean hotplug;
|
||||
Time old_timestamp;
|
||||
|
||||
if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
|
||||
return FALSE;
|
||||
|
||||
XRRUpdateConfiguration (event);
|
||||
|
||||
/* 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;
|
||||
old_timestamp = manager_xrandr->resources->timestamp;
|
||||
|
||||
manager->serial++;
|
||||
meta_monitor_manager_xrandr_read_current (manager);
|
||||
meta_monitor_manager_read_current_config (manager);
|
||||
|
||||
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 || meta_monitor_config_match_current (manager->config, manager))
|
||||
hotplug = manager_xrandr->resources->timestamp < manager_xrandr->resources->configTimestamp;
|
||||
if (hotplug)
|
||||
{
|
||||
meta_monitor_manager_xrandr_rebuild_derived (manager);
|
||||
goto out;
|
||||
/* This is a hotplug event, so go ahead and build a new configuration. */
|
||||
meta_monitor_manager_on_hotplug (manager);
|
||||
}
|
||||
|
||||
/* 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))
|
||||
else
|
||||
{
|
||||
if (meta_monitor_config_apply_stored (manager->config, manager))
|
||||
applied_config = TRUE;
|
||||
/* If something else changed -- tell the world about it. */
|
||||
if (old_timestamp < manager_xrandr->resources->timestamp)
|
||||
meta_monitor_manager_rebuild_derived (manager);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ struct _MetaBackgroundImageCacheClass
|
||||
struct _MetaBackgroundImage
|
||||
{
|
||||
GObject parent_instance;
|
||||
char *filename;
|
||||
GFile *file;
|
||||
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_str_hash, g_str_equal);
|
||||
cache->images = g_hash_table_new (g_file_hash, (GEqualFunc) g_file_equal);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -124,9 +124,17 @@ load_file (GTask *task,
|
||||
{
|
||||
GError *error = NULL;
|
||||
GdkPixbuf *pixbuf;
|
||||
GFileInputStream *stream;
|
||||
|
||||
pixbuf = gdk_pixbuf_new_from_file (image->filename,
|
||||
&error);
|
||||
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);
|
||||
|
||||
if (pixbuf == NULL)
|
||||
{
|
||||
@ -156,9 +164,11 @@ file_loaded (GObject *source_object,
|
||||
|
||||
if (pixbuf == NULL)
|
||||
{
|
||||
char *uri = g_file_get_uri (image->file);
|
||||
g_warning ("Failed to load background '%s': %s",
|
||||
image->filename, error->message);
|
||||
uri, error->message);
|
||||
g_clear_error (&error);
|
||||
g_free (uri);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -195,7 +205,7 @@ out:
|
||||
/**
|
||||
* meta_background_image_cache_load:
|
||||
* @cache: a #MetaBackgroundImageCache
|
||||
* @filename: filename to load
|
||||
* @file: #GFile 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
|
||||
@ -209,23 +219,23 @@ out:
|
||||
*/
|
||||
MetaBackgroundImage *
|
||||
meta_background_image_cache_load (MetaBackgroundImageCache *cache,
|
||||
const char *filename)
|
||||
GFile *file)
|
||||
{
|
||||
MetaBackgroundImage *image;
|
||||
GTask *task;
|
||||
|
||||
g_return_val_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache), NULL);
|
||||
g_return_val_if_fail (filename != NULL, NULL);
|
||||
g_return_val_if_fail (file != NULL, NULL);
|
||||
|
||||
image = g_hash_table_lookup (cache->images, filename);
|
||||
image = g_hash_table_lookup (cache->images, file);
|
||||
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->filename = g_strdup (filename);
|
||||
g_hash_table_insert (cache->images, image->filename, image);
|
||||
image->file = g_object_ref (file);
|
||||
g_hash_table_insert (cache->images, image->file, image);
|
||||
|
||||
task = g_task_new (image, NULL, file_loaded, NULL);
|
||||
|
||||
@ -238,25 +248,25 @@ meta_background_image_cache_load (MetaBackgroundImageCache *cache,
|
||||
/**
|
||||
* meta_background_image_cache_purge:
|
||||
* @cache: a #MetaBackgroundImageCache
|
||||
* @filename: filename to remove from the cache
|
||||
* @file: file 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,
|
||||
const char *filename)
|
||||
GFile *file)
|
||||
{
|
||||
MetaBackgroundImage *image;
|
||||
|
||||
g_return_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache));
|
||||
g_return_if_fail (filename != NULL);
|
||||
g_return_if_fail (file != NULL);
|
||||
|
||||
image = g_hash_table_lookup (cache->images, filename);
|
||||
image = g_hash_table_lookup (cache->images, file);
|
||||
if (image == NULL)
|
||||
return;
|
||||
|
||||
g_hash_table_remove (cache->images, image->filename);
|
||||
g_hash_table_remove (cache->images, image->file);
|
||||
image->in_cache = FALSE;
|
||||
}
|
||||
|
||||
@ -273,12 +283,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->filename);
|
||||
g_hash_table_remove (image->cache->images, image->file);
|
||||
|
||||
if (image->texture)
|
||||
cogl_object_unref (image->texture);
|
||||
if (image->filename)
|
||||
g_free (image->filename);
|
||||
if (image->file)
|
||||
g_object_unref (image->file);
|
||||
|
||||
G_OBJECT_CLASS (meta_background_image_parent_class)->finalize (object);
|
||||
}
|
||||
|
@ -50,9 +50,9 @@ struct _MetaBackgroundPrivate
|
||||
ClutterColor color;
|
||||
ClutterColor second_color;
|
||||
|
||||
char *filename1;
|
||||
GFile *file1;
|
||||
MetaBackgroundImage *background_image1;
|
||||
char *filename2;
|
||||
GFile *file2;
|
||||
MetaBackgroundImage *background_image2;
|
||||
|
||||
CoglTexture *color_texture;
|
||||
@ -241,16 +241,28 @@ on_background_loaded (MetaBackgroundImage *image,
|
||||
mark_changed (self);
|
||||
}
|
||||
|
||||
static void
|
||||
set_filename (MetaBackground *self,
|
||||
char **filenamep,
|
||||
MetaBackgroundImage **imagep,
|
||||
const char *filename)
|
||||
static gboolean
|
||||
file_equal0 (GFile *file1,
|
||||
GFile *file2)
|
||||
{
|
||||
if (g_strcmp0 (filename, *filenamep) != 0)
|
||||
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)
|
||||
{
|
||||
if (!file_equal0 (*filep, file))
|
||||
{
|
||||
g_free (*filenamep);
|
||||
*filenamep = g_strdup (filename);
|
||||
g_clear_object (filep);
|
||||
|
||||
if (*imagep)
|
||||
{
|
||||
@ -261,10 +273,12 @@ set_filename (MetaBackground *self,
|
||||
*imagep = NULL;
|
||||
}
|
||||
|
||||
if (filename)
|
||||
if (file)
|
||||
{
|
||||
MetaBackgroundImageCache *cache = meta_background_image_cache_get_default ();
|
||||
*imagep = meta_background_image_cache_load (cache, filename);
|
||||
|
||||
*filep = g_object_ref (file);
|
||||
*imagep = meta_background_image_cache_load (cache, file);
|
||||
g_signal_connect (*imagep, "loaded",
|
||||
G_CALLBACK (on_background_loaded), self);
|
||||
}
|
||||
@ -280,8 +294,8 @@ meta_background_dispose (GObject *object)
|
||||
free_color_texture (self);
|
||||
free_wallpaper_texture (self);
|
||||
|
||||
set_filename (self, &priv->filename1, &priv->background_image1, NULL);
|
||||
set_filename (self, &priv->filename2, &priv->background_image2, NULL);
|
||||
set_file (self, &priv->file1, &priv->background_image1, NULL);
|
||||
set_file (self, &priv->file2, &priv->background_image2, NULL);
|
||||
|
||||
set_screen (self, NULL);
|
||||
|
||||
@ -867,19 +881,19 @@ meta_background_set_gradient (MetaBackground *self,
|
||||
}
|
||||
|
||||
void
|
||||
meta_background_set_filename (MetaBackground *self,
|
||||
const char *filename,
|
||||
GDesktopBackgroundStyle style)
|
||||
meta_background_set_file (MetaBackground *self,
|
||||
GFile *file,
|
||||
GDesktopBackgroundStyle style)
|
||||
{
|
||||
g_return_if_fail (META_IS_BACKGROUND (self));
|
||||
|
||||
meta_background_set_blend (self, filename, NULL, 0.0, style);
|
||||
meta_background_set_blend (self, file, NULL, 0.0, style);
|
||||
}
|
||||
|
||||
void
|
||||
meta_background_set_blend (MetaBackground *self,
|
||||
const char *filename1,
|
||||
const char *filename2,
|
||||
GFile *file1,
|
||||
GFile *file2,
|
||||
double blend_factor,
|
||||
GDesktopBackgroundStyle style)
|
||||
{
|
||||
@ -890,8 +904,8 @@ meta_background_set_blend (MetaBackground *self,
|
||||
|
||||
priv = self->priv;
|
||||
|
||||
set_filename (self, &priv->filename1, &priv->background_image1, filename1);
|
||||
set_filename (self, &priv->filename2, &priv->background_image2, filename2);
|
||||
set_file (self, &priv->file1, &priv->background_image1, file1);
|
||||
set_file (self, &priv->file2, &priv->background_image2, file2);
|
||||
|
||||
priv->blend_factor = blend_factor;
|
||||
priv->style = style;
|
||||
|
@ -65,6 +65,8 @@ 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);
|
||||
@ -91,6 +93,11 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1965,7 +1965,7 @@ meta_display_end_grab_op (MetaDisplay *display,
|
||||
* beginning of the grab_op.
|
||||
*/
|
||||
if (!meta_prefs_get_raise_on_click () &&
|
||||
display->grab_threshold_movement_reached)
|
||||
!display->grab_threshold_movement_reached)
|
||||
meta_window_raise (display->grab_window);
|
||||
|
||||
meta_window_grab_op_ended (grab_window, grab_op);
|
||||
|
@ -151,23 +151,6 @@ 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)
|
||||
@ -176,8 +159,15 @@ meta_display_handle_event (MetaDisplay *display,
|
||||
gboolean bypass_clutter = FALSE;
|
||||
G_GNUC_UNUSED gboolean bypass_wayland = FALSE;
|
||||
MetaGestureTracker *tracker;
|
||||
ClutterEventSequence *sequence;
|
||||
|
||||
meta_display_update_pointer_emulating_sequence (display, event);
|
||||
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;
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
MetaWaylandCompositor *compositor = NULL;
|
||||
@ -314,6 +304,11 @@ 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;
|
||||
}
|
||||
|
@ -1660,13 +1660,14 @@ meta_window_ungrab_all_keys (MetaWindow *window, guint32 timestamp)
|
||||
}
|
||||
|
||||
void
|
||||
meta_display_freeze_keyboard (MetaDisplay *display, Window window, guint32 timestamp)
|
||||
meta_display_freeze_keyboard (MetaDisplay *display, 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);
|
||||
}
|
||||
|
||||
|
@ -3022,7 +3022,6 @@ check_fullscreen_func (gpointer data)
|
||||
{
|
||||
MetaScreen *screen = data;
|
||||
MetaWindow *window;
|
||||
GSList *tmp;
|
||||
GSList *fullscreen_monitors = NULL;
|
||||
GSList *obscured_monitors = NULL;
|
||||
gboolean in_fullscreen_changed = FALSE;
|
||||
|
@ -5851,7 +5851,7 @@ update_resize (MetaWindow *window,
|
||||
int new_w, new_h;
|
||||
int gravity;
|
||||
MetaRectangle old;
|
||||
double remaining;
|
||||
double remaining = 0;
|
||||
MetaMaximizeFlags new_unmaximize;
|
||||
|
||||
window->display->grab_latest_motion_x = x;
|
||||
@ -6110,10 +6110,8 @@ 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);
|
||||
return FALSE;
|
||||
}
|
||||
end_grab_op (window, event);
|
||||
|
||||
return TRUE;
|
||||
|
||||
case CLUTTER_TOUCH_BEGIN:
|
||||
|
@ -173,7 +173,6 @@ 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);
|
||||
|
@ -1,71 +0,0 @@
|
||||
/* -*- 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
|
@ -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,
|
||||
const char *filename);
|
||||
GFile *file);
|
||||
void meta_background_image_cache_purge (MetaBackgroundImageCache *cache,
|
||||
const char *filename);
|
||||
GFile *file);
|
||||
|
||||
#endif /* __META_BACKGROUND_IMAGE_H__ */
|
||||
|
@ -67,12 +67,12 @@ void meta_background_set_gradient (MetaBackground *self,
|
||||
GDesktopBackgroundShading shading_direction,
|
||||
ClutterColor *color,
|
||||
ClutterColor *second_color);
|
||||
void meta_background_set_filename (MetaBackground *self,
|
||||
const char *filename,
|
||||
void meta_background_set_file (MetaBackground *self,
|
||||
GFile *file,
|
||||
GDesktopBackgroundStyle style);
|
||||
void meta_background_set_blend (MetaBackground *self,
|
||||
const char *filename1,
|
||||
const char *filename2,
|
||||
GFile *file1,
|
||||
GFile *file2,
|
||||
double blend_factor,
|
||||
GDesktopBackgroundStyle style);
|
||||
|
||||
|
@ -1,902 +0,0 @@
|
||||
/* -*- 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;
|
||||
}
|
||||
}
|
@ -1,315 +0,0 @@
|
||||
/* -*- 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;
|
||||
}
|
||||
|
@ -774,9 +774,6 @@ 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);
|
||||
|
||||
@ -2150,11 +2147,9 @@ 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;
|
||||
@ -2165,7 +2160,6 @@ 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;
|
||||
@ -2211,18 +2205,6 @@ 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))
|
||||
{
|
||||
@ -2233,7 +2215,6 @@ 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);
|
||||
|
@ -23,7 +23,6 @@
|
||||
#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>
|
||||
@ -273,6 +272,14 @@ 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,
|
||||
@ -538,7 +545,6 @@ struct _MetaDrawOp
|
||||
} gradient;
|
||||
|
||||
struct {
|
||||
MetaColorSpec *colorize_spec;
|
||||
MetaAlphaGradientSpec *alpha_spec;
|
||||
GdkPixbuf *pixbuf;
|
||||
MetaDrawSpec *x;
|
||||
@ -546,8 +552,6 @@ 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;
|
||||
@ -972,8 +976,12 @@ gboolean meta_draw_op_list_contains (MetaDrawOpList *op_list,
|
||||
|
||||
MetaGradientSpec* meta_gradient_spec_new (MetaGradientType type);
|
||||
void meta_gradient_spec_free (MetaGradientSpec *desc);
|
||||
GdkPixbuf* meta_gradient_spec_render (const MetaGradientSpec *desc,
|
||||
GtkStyleContext *gtk_style,
|
||||
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);
|
||||
gboolean meta_gradient_spec_validate (MetaGradientSpec *spec,
|
||||
|
760
src/ui/theme.c
760
src/ui/theme.c
@ -38,7 +38,6 @@
|
||||
#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>
|
||||
@ -75,84 +74,6 @@ 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,
|
||||
@ -1010,42 +931,84 @@ meta_gradient_spec_free (MetaGradientSpec *spec)
|
||||
g_free (spec);
|
||||
}
|
||||
|
||||
GdkPixbuf*
|
||||
meta_gradient_spec_render (const MetaGradientSpec *spec,
|
||||
GtkStyleContext *style,
|
||||
int width,
|
||||
int height)
|
||||
static cairo_pattern_t *
|
||||
meta_gradient_spec_pattern (const MetaGradientSpec *spec,
|
||||
const MetaAlphaGradientSpec *alpha_spec,
|
||||
GtkStyleContext *style)
|
||||
{
|
||||
cairo_pattern_t *pattern;
|
||||
int n_colors;
|
||||
GdkRGBA *colors;
|
||||
GSList *tmp;
|
||||
GSList *l;
|
||||
int i;
|
||||
GdkPixbuf *pixbuf;
|
||||
|
||||
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 ();
|
||||
|
||||
n_colors = g_slist_length (spec->color_specs);
|
||||
|
||||
if (n_colors == 0)
|
||||
return NULL;
|
||||
|
||||
colors = g_new (GdkRGBA, n_colors);
|
||||
if (alpha_spec != NULL)
|
||||
g_assert (n_colors == alpha_spec->n_alphas);
|
||||
|
||||
i = 0;
|
||||
tmp = spec->color_specs;
|
||||
while (tmp != NULL)
|
||||
for (l = spec->color_specs; l != NULL; l = l->next)
|
||||
{
|
||||
meta_color_spec_render (tmp->data, style, &colors[i]);
|
||||
MetaColorSpec *color_spec = l->data;
|
||||
GdkRGBA color;
|
||||
|
||||
tmp = tmp->next;
|
||||
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);
|
||||
++i;
|
||||
}
|
||||
|
||||
pixbuf = meta_gradient_create_multi (width, height,
|
||||
colors, n_colors,
|
||||
spec->type);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
g_free (colors);
|
||||
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;
|
||||
|
||||
return pixbuf;
|
||||
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);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@ -3052,12 +3015,6 @@ 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);
|
||||
@ -3132,413 +3089,6 @@ 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,
|
||||
@ -3578,6 +3128,86 @@ 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
|
||||
@ -3601,7 +3231,6 @@ 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);
|
||||
|
||||
@ -3759,94 +3388,63 @@ 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);
|
||||
|
||||
if (!needs_alpha)
|
||||
{
|
||||
meta_color_spec_render (op->data.tint.color_spec,
|
||||
style_gtk, &color);
|
||||
gdk_cairo_set_source_rgba (cr, &color);
|
||||
meta_color_spec_render (op->data.tint.color_spec,
|
||||
style_gtk, &color);
|
||||
|
||||
cairo_rectangle (cr, rx, ry, rwidth, rheight);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
if (op->data.tint.alpha_spec &&
|
||||
op->data.tint.alpha_spec->n_alphas == 1)
|
||||
color.alpha = op->data.tint.alpha_spec->alphas[0];
|
||||
|
||||
pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
|
||||
rwidth, rheight);
|
||||
gdk_cairo_set_source_rgba (cr, &color);
|
||||
|
||||
if (pixbuf)
|
||||
{
|
||||
gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
|
||||
cairo_paint (cr);
|
||||
|
||||
g_object_unref (G_OBJECT (pixbuf));
|
||||
}
|
||||
}
|
||||
cairo_rectangle (cr, rx, ry, rwidth, rheight);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
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);
|
||||
|
||||
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));
|
||||
}
|
||||
meta_gradient_spec_render (op->data.gradient.gradient_spec,
|
||||
op->data.gradient.alpha_spec,
|
||||
cr, style_gtk,
|
||||
rx, ry, rwidth, rheight);
|
||||
}
|
||||
break;
|
||||
|
||||
case META_DRAW_IMAGE:
|
||||
{
|
||||
int rx, ry, rwidth, rheight;
|
||||
GdkPixbuf *pixbuf;
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
|
||||
rwidth = parse_size_unchecked (op->data.image.width, env);
|
||||
rheight = parse_size_unchecked (op->data.image.height, env);
|
||||
|
||||
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));
|
||||
}
|
||||
draw_image (cr,
|
||||
op->data.image.pixbuf,
|
||||
op->data.image.fill_type,
|
||||
op->data.image.alpha_spec,
|
||||
rx, ry, rwidth, rheight);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -3916,24 +3514,27 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
|
||||
case META_DRAW_ICON:
|
||||
{
|
||||
int rx, ry, rwidth, rheight;
|
||||
GdkPixbuf *pixbuf;
|
||||
GdkPixbuf *src;
|
||||
|
||||
rwidth = parse_size_unchecked (op->data.icon.width, env);
|
||||
rheight = parse_size_unchecked (op->data.icon.height, env);
|
||||
|
||||
pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
|
||||
rwidth, rheight);
|
||||
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;
|
||||
|
||||
if (pixbuf)
|
||||
{
|
||||
rx = parse_x_position_unchecked (op->data.icon.x, env);
|
||||
ry = parse_y_position_unchecked (op->data.icon.y, env);
|
||||
rx = parse_x_position_unchecked (op->data.icon.x, env);
|
||||
ry = parse_y_position_unchecked (op->data.icon.y, env);
|
||||
|
||||
gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
|
||||
cairo_paint (cr);
|
||||
|
||||
g_object_unref (G_OBJECT (pixbuf));
|
||||
}
|
||||
draw_image (cr, src,
|
||||
op->data.icon.fill_type,
|
||||
op->data.icon.alpha_spec,
|
||||
rx, ry, rwidth, rheight);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -4053,7 +3654,6 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
gtk_style_context_restore (style_gtk);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -518,10 +518,11 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
|
||||
|
||||
clutter_input_device_get_coords (pointer->device, NULL, &pos);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
move_resources_for_client (&pointer->focus_resource_list,
|
||||
&pointer->resource_list,
|
||||
|
@ -393,10 +393,7 @@ commit_pending_state (MetaWaylandSurface *surface,
|
||||
}
|
||||
|
||||
if (pending->scale > 0)
|
||||
{
|
||||
surface->scale = pending->scale;
|
||||
meta_surface_actor_wayland_scale_texture (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
|
||||
}
|
||||
surface->scale = pending->scale;
|
||||
|
||||
if (!cairo_region_is_empty (pending->damage))
|
||||
surface_process_damage (surface, pending->damage);
|
||||
@ -411,10 +408,14 @@ commit_pending_state (MetaWaylandSurface *surface,
|
||||
}
|
||||
if (pending->input_region)
|
||||
{
|
||||
pending->input_region = scale_region (pending->input_region, surface->scale);
|
||||
pending->input_region = scale_region (pending->input_region,
|
||||
meta_surface_actor_wayland_get_scale (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor)));
|
||||
meta_surface_actor_set_input_region (surface->surface_actor, pending->input_region);
|
||||
}
|
||||
|
||||
/* scale surface texture */
|
||||
meta_surface_actor_wayland_scale_texture (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
|
||||
|
||||
/* wl_surface.frame */
|
||||
wl_list_insert_list (&compositor->frame_callbacks, &pending->frame_callback_list);
|
||||
wl_list_init (&pending->frame_callback_list);
|
||||
|
Reference in New Issue
Block a user