Compare commits

...

14 Commits

Author SHA1 Message Date
Georges Basile Stavracas Neto
5a4ade857a Port ClutterText to ClutterPaintNode
The port to use ClutterPaintNodes basically mirrors what
it currently does, with the major benefit of not depending
on cogl_get_draw_framebuffer() anymore.

There are various factors that influence the number of
subnodes:

 * The background color adds a color subnode;
 * The selection adds a clip subnode, and a color subnode,
   or a color and a text subnode;

The simplest case is when the text does not overflow and
has no background color nor selection. In that case, the
render tree is simply:

    [ Dummy ]
        ↓
    [ Text ]

In contrast, the most complex case is when drawing the text
with selection, in which case the render tree looks like:

    [ Dummy ]
        ↓
    [ Clip ]
        ↓
    [ Text ] → [ Clip ]
                  ↓
               [ Color ] → [ Text ]

Since the selection may have another text color, the selected
text must be rendered again, but clipped to only cover the
selection rectangle. This is suboptimal, but it's what the
current code already does anyway.
2018-09-28 21:38:12 -03:00
Georges Basile Stavracas Neto
cc75fc88ee clutter/paint-nodes: Use texture position to draw pango layout
When painting a ClutterText, there are two different aspects that
should be taken into account:

 1. The allocated size of the actor; and
 2. The reported size of the PangoLayout, which may be smaller or
    bigger than (1)

When (2) is bigger than (1), ClutterText has to clip the text to
only draw at the visible contents over the actor surface. In
addition to that, ClutterText also tracks the cursor position,
which makes clipping a bit more complicated.

The current ClutterTextNode.draw() implementation assumes that
the (1) also represents (2), which is not true. This makes
clipping not work.

Fix that by assuming that the position to draw the PangoLayout
is passed as the second rectangle, and the actor size is the
first one.
2018-09-27 17:06:38 -03:00
Olivier Fourdan
68ec9ac017 wayland: No xdg-output events without a logical monitor
To avoid a known race condition in the wl_output protocol documented in
https://phabricator.freedesktop.org/T7722, mutter delays the `wl_output`
destruction but nullify the `logical_monitor` associated with the
`wl_output` and the binding routine `bind_output()` makes sure not to
send wl_output events if the `logical_monitor` is `NULL` (see commit
1923db97).

The binding routine for `xdg_output` however does not check for such a
condition, hence if the output configuration changes while a client is
binding to xdg-output (typically Xwayland at startup), mutter would
crash while trying to access the `logical_monitor` which was nullified
by the change in configuration.

Just like `bind_output()` does for wl_output, do not send xdg-output
events if there is no `logical_monitor` yet.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/194
2018-09-25 15:14:18 +02:00
Carlos Garnacho
8dcac664fa core: Preserve focus across decoration changes
Changes in window decoration result in the window being reparented
in and out its frame. This in turn causes unmap/map events, and
XI_FocusOut if the window happened to be focused.

In order to preserve the focused window across the decoration change,
add a flag so that the focus may be restored on MapNotify.

Closes: #273
2018-09-24 13:44:53 +00:00
Olivier Fourdan
2fb3db7659 compositor: Skip windows not visible to the compositor
The compositor will automatically unredirect the top most window which
is fully visible on screen. When unredirecting windows, it also shapes
the compositor overlay window (COW) so that other redirected windows
still shows correctly.

The function `get_top_visible_window_actor()` however will simply walks
down the window list, so if a window is placed on a layer above and
unredirected, then iconified by the client, it will still be picked up
by `get_top_visible_window_actor()` and he compositor will reckon it's
still unredirected while not in a visible state anymore, thus leaving a
black area on screen.

Make sure we skip the windows not known to the compositor while picking
the top visible window actor to avoid this issue.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/306
2018-09-21 18:50:06 +02:00
Jonas Ådahl
7d82cdeea3 window/wayland: Freeze updates until shown
Not until the window is shown do we know what monitor it's on, thus the
size, so freeze updates (shape etc) until the window is shown.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/229
2018-09-19 15:39:54 +00:00
Jonas Ådahl
e2e7296612 window: Move out 'updates frozen' state into implementations
Implementation of said state was just related to X11, so move it into
window-x11.c. The Wayland path always fell back on the returning TRUE,
so just do that for now.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/229
2018-09-19 15:39:54 +00:00
Tony Novak
8685de9607 input-settings: detect trackball using udev ID_INPUT_TRACKBALL
Previously, trackballs were detected based on the presence of the
substring "trackball" in the device name. This had the downside of
missing devices, such as the Kensington Expert Mouse, which don't have
"trackball" in their names.

Rather than depending on the device name, use the ID_INPUT_TRACKBALL
property from udev to determine whether or not to treat a device as a
trackball.

This adds a new function, `is_trackball_device`, to MetaInputEvents, and
eliminates the `meta_input_device_is_trackball` function.

Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/258
2018-09-19 08:48:27 +00:00
Sam Spilsbury
a8a3c1017f actor: Also recompute paint volume if we recently dropped effects
Otherwise we'll be stuck with the same paint volume on the last
frame of the given effect, which could be wrong.
2018-09-18 19:39:12 +00:00
Sam Spilsbury
5d19aee23a actor: Always use get_paint_volume override for active effects
If an effect is active and it overrides the paint volume, we should
always recompute the paint volume when requested and not use the
cache, since the paint volume override can change from call to
call depending on what phase of painting we are in. For instance,
if we are part way through painting effects and request the
paint volume, the paint volume should only go up to the current
effect, but in a later call to compute repaint regions, the
paint volume needs to expand to accomadate the effect.

This still involves a lot of recomputation in the case of effects -
in a later clutter version it would be worth adding an API to
allow effects to explicitly recompute and return a new the paint
volume up to the current effect as opposed to recomputing
the cached one.
2018-09-18 19:39:12 +00:00
Sam Spilsbury
4270eef16e actor: Fix logic error in determining terminal effect for paint volume
Previously we were checking l->data != NULL || (l->data != NULL &&
l->data != priv->current_effect). This would continue the loop even
if l->data == priv->current_effect, since l->data != NULL, which was
not the intention of that loop.

We also don't need to check that l->data != NULL before checking if
it does not match the current_effect, since we already checked
that current_effect was non-NULL before entering the loop.
2018-09-18 19:39:12 +00:00
Olivier Fourdan
b443bd42ac window: unmanage dialog when clearing transient_for
On Wayland, xdg-foreign would leave a modal dialog managed even after
the imported surface is destroyed.

This is sub-optimal and this breaks the atomic relationship one would
expect between the parent and its modal dialog.

Make sure we unmanage the dialog if transient_for is unset even for
Wayland native windows.

Related: https://gitlab.gnome.org/GNOME/mutter/issues/174
Related: https://gitlab.gnome.org/GNOME/mutter/issues/221
2018-09-14 11:11:31 +02:00
Ting-Wei Lan
267503b5f3 build: Fix non-wayland builds 2018-09-11 16:19:19 +00:00
Florian Müllner
a3d9f987c8 input-settings-x11: Push error trap
Pops are lonely without push, so add one for a happy error trap.

https://gitlab.gnome.org/GNOME/mutter/issues/294
2018-09-07 19:42:37 +02:00
18 changed files with 272 additions and 104 deletions

View File

@@ -841,6 +841,7 @@ struct _ClutterActorPrivate
guint needs_x_expand : 1;
guint needs_y_expand : 1;
guint needs_paint_volume_update : 1;
guint had_effects_on_last_paint_volume_update : 1;
};
enum
@@ -17485,7 +17486,7 @@ _clutter_actor_get_paint_volume_real (ClutterActor *self,
*/
effects = _clutter_meta_group_peek_metas (priv->effects);
for (l = effects;
l != NULL || (l != NULL && l->data != priv->current_effect);
l != NULL && l->data != priv->current_effect;
l = l->next)
{
if (!_clutter_effect_get_paint_volume (l->data, pv))
@@ -17521,6 +17522,32 @@ _clutter_actor_get_paint_volume_real (ClutterActor *self,
return TRUE;
}
static gboolean
_clutter_actor_has_active_paint_volume_override_effects (ClutterActor *self)
{
const GList *l;
if (self->priv->effects == NULL)
return FALSE;
/* We just need to all effects current effect to see
* if anyone wants to override the paint volume. If so, then
* we need to recompute, since the paint volume returned can
* change from call to call. */
for (l = _clutter_meta_group_peek_metas (self->priv->effects);
l != NULL;
l = l->next)
{
ClutterEffect *effect = l->data;
if (clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)) &&
_clutter_effect_has_custom_paint_volume (effect))
return TRUE;
}
return FALSE;
}
/* The public clutter_actor_get_paint_volume API returns a const
* pointer since we return a pointer directly to the cached
* PaintVolume associated with the actor and don't want the user to
@@ -17531,17 +17558,33 @@ _clutter_actor_get_paint_volume_real (ClutterActor *self,
static ClutterPaintVolume *
_clutter_actor_get_paint_volume_mutable (ClutterActor *self)
{
gboolean has_paint_volume_override_effects;
ClutterActorPrivate *priv;
priv = self->priv;
has_paint_volume_override_effects = _clutter_actor_has_active_paint_volume_override_effects (self);
if (priv->paint_volume_valid)
{
if (!priv->needs_paint_volume_update)
/* If effects are applied, the actor paint volume
* needs to be recomputed on each paint, since those
* paint volumes could change over the duration of the
* effect.
*
* We also need to update the paint volume if we went
* from having effects to not having effects on the last
* paint volume update. */
if (!priv->needs_paint_volume_update &&
priv->current_effect == NULL &&
!has_paint_volume_override_effects &&
!priv->had_effects_on_last_paint_volume_update)
return &priv->paint_volume;
clutter_paint_volume_free (&priv->paint_volume);
}
priv->had_effects_on_last_paint_volume_update = has_paint_volume_override_effects;
if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
{
priv->paint_volume_valid = TRUE;

View File

@@ -9,6 +9,7 @@ gboolean _clutter_effect_pre_paint (ClutterEffect
void _clutter_effect_post_paint (ClutterEffect *effect);
gboolean _clutter_effect_get_paint_volume (ClutterEffect *effect,
ClutterPaintVolume *volume);
gboolean _clutter_effect_has_custom_paint_volume (ClutterEffect *effect);
void _clutter_effect_paint (ClutterEffect *effect,
ClutterEffectPaintFlags flags);
void _clutter_effect_pick (ClutterEffect *effect,

View File

@@ -308,6 +308,14 @@ _clutter_effect_get_paint_volume (ClutterEffect *effect,
return CLUTTER_EFFECT_GET_CLASS (effect)->get_paint_volume (effect, volume);
}
gboolean
_clutter_effect_has_custom_paint_volume (ClutterEffect *effect)
{
g_return_val_if_fail (CLUTTER_IS_EFFECT (effect), FALSE);
return CLUTTER_EFFECT_GET_CLASS (effect)->get_paint_volume != clutter_effect_real_get_paint_volume;
}
/**
* clutter_effect_queue_repaint:
* @effect: A #ClutterEffect which needs redrawing

View File

@@ -820,8 +820,8 @@ clutter_text_node_draw (ClutterPaintNode *node)
}
cogl_pango_render_layout (tnode->layout,
op->op.texrect[0],
op->op.texrect[1],
op->op.texrect[4],
op->op.texrect[5],
&tnode->color,
0);

View File

@@ -1746,7 +1746,8 @@ add_selection_rectangle_to_path (ClutterText *text,
/* Draws the selected text, its background, and the cursor */
static void
selection_paint (ClutterText *self)
paint_selection (ClutterText *self,
ClutterPaintNode *node)
{
ClutterTextPrivate *priv = self->priv;
ClutterActor *actor = CLUTTER_ACTOR (self);
@@ -1758,33 +1759,59 @@ selection_paint (ClutterText *self)
if (priv->position == priv->selection_bound)
{
g_autoptr(ClutterPaintNode) cursor_node = NULL;
/* No selection, just draw the cursor */
if (priv->cursor_color_set)
color = &priv->cursor_color;
else
color = &priv->text_color;
cogl_set_source_color4ub (color->red,
color->green,
color->blue,
paint_opacity * color->alpha / 255);
cursor_node = clutter_color_node_new (&(ClutterColor) {
color->red,
color->green,
color->blue,
paint_opacity * color->alpha / 255,
});
clutter_paint_node_set_name (cursor_node, "ClutterText.selection-background");
clutter_paint_node_add_child (node, cursor_node);
cogl_rectangle (priv->cursor_rect.origin.x,
priv->cursor_rect.origin.y,
priv->cursor_rect.origin.x + priv->cursor_rect.size.width,
priv->cursor_rect.origin.y + priv->cursor_rect.size.height);
clutter_paint_node_add_rectangle (cursor_node,
&(ClutterActorBox) {
priv->cursor_rect.origin.x,
priv->cursor_rect.origin.y,
priv->cursor_rect.origin.x + priv->cursor_rect.size.width,
priv->cursor_rect.origin.y + priv->cursor_rect.size.height
});
}
else
{
/* Paint selection background first */
g_autoptr(ClutterPaintNode) selection_background_node = NULL;
g_autoptr(ClutterPaintNode) selection_text_node = NULL;
g_autoptr(ClutterPaintNode) selection_clip_node = NULL;
PangoLayout *layout = clutter_text_get_layout (self);
ClutterActorBox alloc = { 0, };
CoglPath *selection_path = cogl_path_new ();
CoglColor cogl_color = { 0, };
CoglFramebuffer *fb;
fb = cogl_get_draw_framebuffer ();
if (G_UNLIKELY (fb == NULL))
return;
clutter_text_foreach_selection_rectangle (self,
add_selection_rectangle_to_path,
selection_path);
/* Clip against both the actor allocation - we don't want to draw
* the selection rectangle outside the actor - and the selection
* path - we don't want to render the text over the unselected
* text either.
*/
selection_clip_node = clutter_clip_node_new ();
clutter_paint_node_set_name (selection_clip_node, "ClutterText.clip-selection");
clutter_paint_node_add_child (node, selection_clip_node);
clutter_actor_get_allocation_box (CLUTTER_ACTOR (self), &alloc);
clutter_actor_box_set_origin (&alloc, 0, 0);
clutter_paint_node_add_rectangle (selection_clip_node, &alloc);
clutter_paint_node_add_path (selection_clip_node, selection_path);
/* Paint selection background */
if (priv->selection_color_set)
@@ -1794,35 +1821,40 @@ selection_paint (ClutterText *self)
else
color = &priv->text_color;
cogl_set_source_color4ub (color->red,
color->green,
color->blue,
paint_opacity * color->alpha / 255);
selection_background_node = clutter_color_node_new (&(ClutterColor) {
color->red,
color->green,
color->blue,
paint_opacity * color->alpha / 255,
});
clutter_paint_node_set_name (selection_background_node, "ClutterText.selection-background");
clutter_paint_node_add_child (selection_clip_node, selection_background_node);
clutter_text_foreach_selection_rectangle (self,
add_selection_rectangle_to_path,
selection_path);
cogl_path_fill (selection_path);
clutter_paint_node_add_path (selection_background_node, selection_path);
/* Paint selected text */
cogl_framebuffer_push_path_clip (fb, selection_path);
cogl_object_unref (selection_path);
if (priv->selected_text_color_set)
color = &priv->selected_text_color;
else
color = &priv->text_color;
cogl_color_init_from_4ub (&cogl_color,
color->red,
color->green,
color->blue,
paint_opacity * color->alpha / 255);
selection_text_node = clutter_text_node_new (layout,
&(ClutterColor) {
color->red,
color->green,
color->blue,
paint_opacity * color->alpha / 255,
});
cogl_pango_render_layout (layout, priv->text_x, 0, &cogl_color, 0);
clutter_paint_node_set_name (selection_text_node, "ClutterText.selection-text");
clutter_paint_node_add_child (selection_clip_node, selection_text_node);
cogl_framebuffer_pop_clip (fb);
clutter_paint_node_add_texture_rectangle (selection_text_node,
&alloc,
priv->text_x, priv->text_y,
1, 1);
cogl_object_unref (selection_path);
}
}
@@ -2373,26 +2405,43 @@ clutter_text_compute_layout_offsets (ClutterText *self,
#define TEXT_PADDING 2
static void
clutter_text_paint (ClutterActor *self)
static inline ClutterPaintNode *
create_clip_node (ClutterPaintNode *node,
float width,
float height)
{
g_autoptr(ClutterPaintNode) clip_node = NULL;
clip_node = clutter_clip_node_new ();
clutter_paint_node_set_name (clip_node, "ClutterText.clip");
clutter_paint_node_add_child (node, clip_node);
clutter_paint_node_add_rectangle (clip_node,
&(ClutterActorBox) {
0, 0,
width, height,
});
return g_steal_pointer (&clip_node);
}
static void
clutter_text_paint_node (ClutterActor *self,
ClutterPaintNode *node)
{
g_autoptr(ClutterPaintNode) text_node = NULL;
ClutterText *text = CLUTTER_TEXT (self);
ClutterTextPrivate *priv = text->priv;
CoglFramebuffer *fb;
PangoLayout *layout;
ClutterActorBox alloc = { 0, };
CoglColor color = { 0, };
guint8 real_opacity;
gint text_x = priv->text_x;
gint text_y = priv->text_y;
gboolean clip_set = FALSE;
gboolean bg_color_set = FALSE;
guint n_chars;
float alloc_width;
float alloc_height;
fb = cogl_get_draw_framebuffer ();
/* Note that if anything in this paint method changes it needs to be
reflected in the get_paint_volume implementation which is tightly
tied to the workings of this function */
@@ -2405,6 +2454,7 @@ clutter_text_paint (ClutterActor *self)
g_object_get (self, "background-color-set", &bg_color_set, NULL);
if (bg_color_set)
{
g_autoptr(ClutterPaintNode) background_color_node = NULL;
ClutterColor bg_color;
clutter_actor_get_background_color (self, &bg_color);
@@ -2412,11 +2462,11 @@ clutter_text_paint (ClutterActor *self)
* bg_color.alpha
/ 255;
cogl_set_source_color4ub (bg_color.red,
bg_color.green,
bg_color.blue,
bg_color.alpha);
cogl_rectangle (0, 0, alloc_width, alloc_height);
background_color_node = clutter_color_node_new (&bg_color);
clutter_paint_node_set_name (background_color_node, "ClutterText.background-color");
clutter_paint_node_add_child (node, background_color_node);
clutter_paint_node_add_rectangle (background_color_node, &alloc);
}
/* don't bother painting an empty text actor, unless it's
@@ -2469,8 +2519,7 @@ clutter_text_paint (ClutterActor *self)
pango_layout_get_extents (layout, NULL, &logical_rect);
cogl_framebuffer_push_rectangle_clip (fb, 0, 0, alloc_width, alloc_height);
clip_set = TRUE;
node = create_clip_node (node, alloc_width, alloc_height);
actor_width = alloc_width - 2 * TEXT_PADDING;
text_width = logical_rect.width / PANGO_SCALE;
@@ -2513,12 +2562,8 @@ clutter_text_paint (ClutterActor *self)
pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
/* don't clip if the layout managed to fit inside our allocation */
if (logical_rect.width > alloc_width ||
logical_rect.height > alloc_height)
{
cogl_framebuffer_push_rectangle_clip (fb, 0, 0, alloc_width, alloc_height);
clip_set = TRUE;
}
if (logical_rect.width > alloc_width || logical_rect.height > alloc_height)
node = create_clip_node (node, alloc_width, alloc_height);
clutter_text_compute_layout_offsets (text, layout, &alloc, &text_x, &text_y);
}
@@ -2541,17 +2586,25 @@ clutter_text_paint (ClutterActor *self)
CLUTTER_NOTE (PAINT, "painting text (text: '%s')",
clutter_text_buffer_get_text (get_buffer (text)));
cogl_color_init_from_4ub (&color,
priv->text_color.red,
priv->text_color.green,
priv->text_color.blue,
real_opacity);
cogl_pango_render_layout (layout, priv->text_x, priv->text_y, &color, 0);
text_node = clutter_text_node_new (layout,
&(ClutterColor) {
priv->text_color.red,
priv->text_color.green,
priv->text_color.blue,
real_opacity
});
selection_paint (text);
clutter_paint_node_set_name (text_node, "ClutterText.text");
clutter_paint_node_add_child (node, text_node);
if (clip_set)
cogl_framebuffer_pop_clip (fb);
clutter_actor_box_set_origin (&alloc, 0, 0);
clutter_paint_node_add_texture_rectangle (text_node,
&alloc,
priv->text_x,
priv->text_y,
1, 1);
paint_selection (text, node);
}
static void
@@ -3548,7 +3601,7 @@ clutter_text_class_init (ClutterTextClass *klass)
gobject_class->dispose = clutter_text_dispose;
gobject_class->finalize = clutter_text_finalize;
actor_class->paint = clutter_text_paint;
actor_class->paint_node = clutter_text_paint_node;
actor_class->get_paint_volume = clutter_text_get_paint_volume;
actor_class->get_preferred_width = clutter_text_get_preferred_width;
actor_class->get_preferred_height = clutter_text_get_preferred_height;

View File

@@ -115,6 +115,8 @@ struct _MetaInputSettingsClass
GDesktopStylusButtonAction tertiary);
gboolean (* has_two_finger_scroll) (MetaInputSettings *settings,
ClutterInputDevice *device);
gboolean (* is_trackball_device) (MetaInputSettings *settings,
ClutterInputDevice *device);
};
GSettings * meta_input_settings_get_tablet_settings (MetaInputSettings *settings,
@@ -141,6 +143,4 @@ WacomDevice * meta_input_settings_get_tablet_wacom_device (MetaInputSettings *se
ClutterInputDevice *device);
#endif
gboolean meta_input_device_is_trackball (ClutterInputDevice *device);
#endif /* META_INPUT_SETTINGS_PRIVATE_H */

View File

@@ -709,22 +709,6 @@ update_touchpad_send_events (MetaInputSettings *input_settings,
}
}
gboolean
meta_input_device_is_trackball (ClutterInputDevice *device)
{
gboolean is_trackball;
char *name;
if (clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_MASTER)
return FALSE;
name = g_ascii_strdown (clutter_input_device_get_device_name (device), -1);
is_trackball = strstr (name, "trackball") != NULL;
g_free (name);
return is_trackball;
}
static void
update_trackball_scroll_button (MetaInputSettings *input_settings,
ClutterInputDevice *device)
@@ -733,11 +717,12 @@ update_trackball_scroll_button (MetaInputSettings *input_settings,
MetaInputSettingsPrivate *priv;
guint button;
if (device && !meta_input_device_is_trackball (device))
return;
priv = meta_input_settings_get_instance_private (input_settings);
input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
if (device && !input_settings_class->is_trackball_device (input_settings, device))
return;
/* This key is 'i' in the schema but it also specifies a minimum
* range of 0 so the cast here is safe. */
button = (guint) g_settings_get_int (priv->trackball_settings, "scroll-wheel-emulation-button");
@@ -756,7 +741,7 @@ update_trackball_scroll_button (MetaInputSettings *input_settings,
{
device = devices->data;
if (meta_input_device_is_trackball (device))
if (input_settings_class->is_trackball_device (input_settings, device))
input_settings_class->set_scroll_button (input_settings, device, button);
devices = devices->next;

View File

@@ -398,9 +398,10 @@ is_mouse_device (ClutterInputDevice *device)
}
static gboolean
is_trackball_device (ClutterInputDevice *device)
meta_input_settings_native_is_trackball_device (MetaInputSettings *settings,
ClutterInputDevice *device)
{
return meta_input_device_is_trackball (device);
return has_udev_property (device, "ID_INPUT_TRACKBALL");
}
static void
@@ -419,7 +420,7 @@ meta_input_settings_native_set_trackball_accel_profile (MetaInputSettings
ClutterInputDevice *device,
GDesktopPointerAccelProfile profile)
{
if (!is_trackball_device (device))
if (!meta_input_settings_native_is_trackball_device (settings, device))
return;
set_device_accel_profile (device, profile);
@@ -588,6 +589,7 @@ meta_input_settings_native_class_init (MetaInputSettingsNativeClass *klass)
input_settings_class->set_stylus_button_map = meta_input_settings_native_set_stylus_button_map;
input_settings_class->has_two_finger_scroll = meta_input_settings_native_has_two_finger_scroll;
input_settings_class->is_trackball_device = meta_input_settings_native_is_trackball_device;
}
static void

View File

@@ -500,10 +500,10 @@ is_mouse (MetaInputSettings *settings,
}
static gboolean
is_trackball (MetaInputSettings *settings,
ClutterInputDevice *device)
meta_input_settings_x11_is_trackball_device (MetaInputSettings *settings,
ClutterInputDevice *device)
{
return meta_input_device_is_trackball (device);
return has_udev_property (settings, device, "ID_INPUT_TRACKBALL");
}
static void
@@ -566,7 +566,7 @@ meta_input_settings_x11_set_trackball_accel_profile (MetaInputSettings
ClutterInputDevice *device,
GDesktopPointerAccelProfile profile)
{
if (!is_trackball (settings, device))
if (!meta_input_settings_x11_is_trackball_device (settings, device))
return;
set_device_accel_profile (device, profile);
@@ -782,6 +782,7 @@ meta_input_settings_x11_set_stylus_button_map (MetaInputSettings *setti
return;
/* Grab the puke bucket! */
meta_x11_error_trap_push (display->x11_display);
xdev = device_ensure_xdevice (device);
if (xdev)
{
@@ -851,6 +852,7 @@ meta_input_settings_x11_class_init (MetaInputSettingsX11Class *klass)
input_settings_class->set_stylus_button_map = meta_input_settings_x11_set_stylus_button_map;
input_settings_class->has_two_finger_scroll = meta_input_settings_x11_has_two_finger_scroll;
input_settings_class->is_trackball_device = meta_input_settings_x11_is_trackball_device;
}
static void

View File

@@ -804,6 +804,7 @@ meta_compositor_hide_window (MetaCompositor *compositor,
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
meta_window_actor_hide (window_actor, effect);
meta_stack_tracker_queue_sync_stack (compositor->display->stack_tracker);
}
void
@@ -951,6 +952,9 @@ get_top_visible_window_actor (MetaCompositor *compositor)
MetaRectangle buffer_rect;
MetaRectangle display_rect = { 0 };
if (!window->visible_to_compositor)
continue;
meta_window_get_buffer_rect (window, &buffer_rect);
meta_display_get_size (compositor->display,
&display_rect.width, &display_rect.height);

View File

@@ -52,6 +52,7 @@
#include "meta-idle-monitor-dbus.h"
#include "meta-cursor-tracker-private.h"
#include <meta/meta-backend.h>
#include "backends/meta-cursor-sprite-xcursor.h"
#include "backends/meta-logical-monitor.h"
#include "backends/native/meta-backend-native.h"
#include "backends/x11/meta-backend-x11.h"

View File

@@ -109,6 +109,12 @@ meta_window_ensure_frame (MetaWindow *window)
/* FIXME handle this error */
meta_x11_error_trap_pop (x11_display);
/* Ensure focus is restored after the unmap/map events triggered
* by XReparentWindow().
*/
if (meta_window_has_focus (window))
window->restore_focus_on_map = TRUE;
/* stick frame to the window */
window->frame = frame;
@@ -201,6 +207,12 @@ meta_window_destroy_frame (MetaWindow *window)
meta_ui_frame_unmanage (frame->ui_frame);
/* Ensure focus is restored after the unmap/map events triggered
* by XReparentWindow().
*/
if (meta_window_has_focus (window))
window->restore_focus_on_map = TRUE;
meta_x11_display_unregister_x_window (x11_display, frame->xwindow);
window->frame = NULL;

View File

@@ -415,6 +415,9 @@ struct _MetaWindow
/* whether or not the window is from a program running on another machine */
guint is_remote : 1;
/* whether focus should be restored on map */
guint restore_focus_on_map : 1;
/* if non-NULL, the bounds of the window frame */
cairo_region_t *frame_bounds;
@@ -565,6 +568,7 @@ struct _MetaWindowClass
gboolean (*shortcuts_inhibited) (MetaWindow *window,
ClutterInputDevice *source);
gboolean (*is_stackable) (MetaWindow *window);
gboolean (*are_updates_frozen) (MetaWindow *window);
};
/* These differ from window->has_foo_func in that they consider

View File

@@ -3743,14 +3743,7 @@ meta_window_activate_with_workspace (MetaWindow *window,
gboolean
meta_window_updates_are_frozen (MetaWindow *window)
{
if (window->extended_sync_request_counter &&
window->sync_request_serial % 2 == 1)
return TRUE;
if (window->sync_request_serial < window->sync_request_wait_serial)
return TRUE;
return FALSE;
return META_WINDOW_GET_CLASS (window)->are_updates_frozen (window);
}
static void
@@ -4660,6 +4653,9 @@ meta_window_focus (MetaWindow *window,
g_return_if_fail (!window->override_redirect);
/* This is a oneshot flag */
window->restore_focus_on_map = FALSE;
meta_topic (META_DEBUG_FOCUS,
"Setting input focus to window %s, input: %d take_focus: %d\n",
window->desc, window->input, window->take_focus);
@@ -7987,7 +7983,15 @@ meta_window_set_transient_for (MetaWindow *window,
}
}
}
else if (window->attached && parent == NULL)
{
guint32 timestamp;
timestamp =
meta_display_get_current_time_roundtrip (window->display);
meta_window_unmanage (window, timestamp);
return;
}
/* We know this won't create a reference cycle because we check for loops */
g_clear_object (&window->transient_for);
window->transient_for = parent ? g_object_ref (parent) : NULL;

View File

@@ -591,6 +591,9 @@ meta_xdg_output_manager_get_xdg_output (struct wl_client *client,
wayland_output->xdg_output_resources =
g_list_prepend (wayland_output->xdg_output_resources, xdg_output_resource);
if (!wayland_output->logical_monitor)
return;
send_xdg_output_events (xdg_output_resource,
wayland_output,
wayland_output->logical_monitor,

View File

@@ -57,6 +57,8 @@ struct _MetaWindowWayland
int last_sent_y;
int last_sent_width;
int last_sent_height;
gboolean has_been_shown;
};
struct _MetaWindowWaylandClass
@@ -538,6 +540,19 @@ appears_focused_changed (GObject *object,
surface_state_changed (window);
}
static void
on_window_shown (MetaWindow *window)
{
MetaWindowWayland *wl_window = META_WINDOW_WAYLAND (window);
gboolean has_been_shown;
has_been_shown = wl_window->has_been_shown;
wl_window->has_been_shown = TRUE;
if (!has_been_shown)
meta_compositor_sync_updates_frozen (window->display->compositor, window);
}
static void
meta_window_wayland_init (MetaWindowWayland *wl_window)
{
@@ -547,6 +562,8 @@ meta_window_wayland_init (MetaWindowWayland *wl_window)
g_signal_connect (window, "notify::appears-focused",
G_CALLBACK (appears_focused_changed), NULL);
g_signal_connect (window, "shown",
G_CALLBACK (on_window_shown), NULL);
}
static void
@@ -573,6 +590,14 @@ meta_window_wayland_is_stackable (MetaWindow *window)
return meta_wayland_surface_get_buffer (window->surface) != NULL;
}
static gboolean
meta_window_wayland_are_updates_frozen (MetaWindow *window)
{
MetaWindowWayland *wl_window = META_WINDOW_WAYLAND (window);
return !wl_window->has_been_shown;
}
static void
meta_window_wayland_class_init (MetaWindowWaylandClass *klass)
{
@@ -593,6 +618,7 @@ meta_window_wayland_class_init (MetaWindowWaylandClass *klass)
window_class->force_restore_shortcuts = meta_window_wayland_force_restore_shortcuts;
window_class->shortcuts_inhibited = meta_window_wayland_shortcuts_inhibited;
window_class->is_stackable = meta_window_wayland_is_stackable;
window_class->are_updates_frozen = meta_window_wayland_are_updates_frozen;
}
MetaWindow *

View File

@@ -1374,6 +1374,12 @@ handle_other_xevent (MetaX11Display *x11_display,
window = meta_window_x11_new (display, event->xmap.window,
FALSE, META_COMP_EFFECT_CREATE);
}
else if (window && window->restore_focus_on_map)
{
meta_window_focus (window,
meta_display_get_current_time_roundtrip (display));
}
break;
case MapRequest:
if (window == NULL)

View File

@@ -1577,6 +1577,19 @@ meta_window_x11_is_stackable (MetaWindow *window)
return !window->override_redirect;
}
static gboolean
meta_window_x11_are_updates_frozen (MetaWindow *window)
{
if (window->extended_sync_request_counter &&
window->sync_request_serial % 2 == 1)
return TRUE;
if (window->sync_request_serial < window->sync_request_wait_serial)
return TRUE;
return FALSE;
}
static void
meta_window_x11_class_init (MetaWindowX11Class *klass)
{
@@ -1601,6 +1614,7 @@ meta_window_x11_class_init (MetaWindowX11Class *klass)
window_class->force_restore_shortcuts = meta_window_x11_force_restore_shortcuts;
window_class->shortcuts_inhibited = meta_window_x11_shortcuts_inhibited;
window_class->is_stackable = meta_window_x11_is_stackable;
window_class->are_updates_frozen = meta_window_x11_are_updates_frozen;
}
void