Compare commits
17 Commits
wip/carlos
...
wip/waylan
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ef00e3fc0b | ||
![]() |
e0df9eee28 | ||
![]() |
4492845528 | ||
![]() |
c334fd5288 | ||
![]() |
83f61daf95 | ||
![]() |
a474608954 | ||
![]() |
67457dc25c | ||
![]() |
9cff36bf30 | ||
![]() |
8708d038be | ||
![]() |
f59d92a246 | ||
![]() |
b7983201d7 | ||
![]() |
99a6a1f881 | ||
![]() |
3b3c6d08b6 | ||
![]() |
26f452d522 | ||
![]() |
76fccc069d | ||
![]() |
156365b609 | ||
![]() |
bd6536dec3 |
@@ -2,7 +2,7 @@ AC_PREREQ(2.50)
|
|||||||
|
|
||||||
m4_define([mutter_major_version], [3])
|
m4_define([mutter_major_version], [3])
|
||||||
m4_define([mutter_minor_version], [9])
|
m4_define([mutter_minor_version], [9])
|
||||||
m4_define([mutter_micro_version], [90])
|
m4_define([mutter_micro_version], [91])
|
||||||
|
|
||||||
m4_define([mutter_version],
|
m4_define([mutter_version],
|
||||||
[mutter_major_version.mutter_minor_version.mutter_micro_version])
|
[mutter_major_version.mutter_minor_version.mutter_micro_version])
|
||||||
|
@@ -134,6 +134,7 @@ libmutter_wayland_la_SOURCES = \
|
|||||||
core/meta-xrandr-shared.h \
|
core/meta-xrandr-shared.h \
|
||||||
core/monitor.c \
|
core/monitor.c \
|
||||||
core/monitor-config.c \
|
core/monitor-config.c \
|
||||||
|
core/monitor-kms.c \
|
||||||
core/monitor-private.h \
|
core/monitor-private.h \
|
||||||
core/monitor-xrandr.c \
|
core/monitor-xrandr.c \
|
||||||
core/mutter-Xatomtype.h \
|
core/mutter-Xatomtype.h \
|
||||||
|
@@ -236,7 +236,7 @@ set_cogl_texture (MetaShapedTexture *stex,
|
|||||||
if (priv->texture)
|
if (priv->texture)
|
||||||
cogl_object_unref (priv->texture);
|
cogl_object_unref (priv->texture);
|
||||||
|
|
||||||
priv->texture = cogl_tex;
|
priv->texture = cogl_object_ref (cogl_tex);
|
||||||
|
|
||||||
if (cogl_tex != NULL)
|
if (cogl_tex != NULL)
|
||||||
{
|
{
|
||||||
@@ -870,26 +870,7 @@ meta_shaped_texture_attach_wayland_buffer (MetaShapedTexture *stex,
|
|||||||
g_return_if_fail (priv->wayland.surface->buffer_ref.buffer == buffer);
|
g_return_if_fail (priv->wayland.surface->buffer_ref.buffer == buffer);
|
||||||
|
|
||||||
if (buffer)
|
if (buffer)
|
||||||
{
|
set_cogl_texture (stex, buffer->texture);
|
||||||
CoglContext *ctx =
|
|
||||||
clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
|
||||||
CoglError *catch_error = NULL;
|
|
||||||
CoglTexture *texture =
|
|
||||||
COGL_TEXTURE (cogl_wayland_texture_2d_new_from_buffer (ctx,
|
|
||||||
buffer->resource,
|
|
||||||
&catch_error));
|
|
||||||
if (!texture)
|
|
||||||
{
|
|
||||||
cogl_error_free (catch_error);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buffer->width = cogl_texture_get_width (texture);
|
|
||||||
buffer->height = cogl_texture_get_height (texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
set_cogl_texture (stex, texture);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
set_cogl_texture (stex, NULL);
|
set_cogl_texture (stex, NULL);
|
||||||
|
|
||||||
|
@@ -35,7 +35,8 @@ typedef enum
|
|||||||
META_DO_GRAVITY_ADJUST = 1 << 1,
|
META_DO_GRAVITY_ADJUST = 1 << 1,
|
||||||
META_IS_USER_ACTION = 1 << 2,
|
META_IS_USER_ACTION = 1 << 2,
|
||||||
META_IS_MOVE_ACTION = 1 << 3,
|
META_IS_MOVE_ACTION = 1 << 3,
|
||||||
META_IS_RESIZE_ACTION = 1 << 4
|
META_IS_RESIZE_ACTION = 1 << 4,
|
||||||
|
META_IS_WAYLAND_RESIZE = 1 << 5
|
||||||
} MetaMoveResizeFlags;
|
} MetaMoveResizeFlags;
|
||||||
|
|
||||||
void meta_window_constrain (MetaWindow *window,
|
void meta_window_constrain (MetaWindow *window,
|
||||||
|
@@ -39,6 +39,7 @@
|
|||||||
#include "keybindings-private.h"
|
#include "keybindings-private.h"
|
||||||
#include <meta/prefs.h>
|
#include <meta/prefs.h>
|
||||||
#include <meta/barrier.h>
|
#include <meta/barrier.h>
|
||||||
|
#include <clutter/clutter.h>
|
||||||
|
|
||||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||||
#include <libsn/sn.h>
|
#include <libsn/sn.h>
|
||||||
@@ -188,7 +189,7 @@ struct _MetaDisplay
|
|||||||
MetaWindow* autoraise_window;
|
MetaWindow* autoraise_window;
|
||||||
|
|
||||||
/* Alt+click button grabs */
|
/* Alt+click button grabs */
|
||||||
unsigned int window_grab_modifiers;
|
ClutterModifierType window_grab_modifiers;
|
||||||
|
|
||||||
/* current window operation */
|
/* current window operation */
|
||||||
MetaGrabOp grab_op;
|
MetaGrabOp grab_op;
|
||||||
@@ -476,9 +477,12 @@ gboolean meta_display_modifiers_accelerator_activate (MetaDisplay *display);
|
|||||||
/* In above-tab-keycode.c */
|
/* In above-tab-keycode.c */
|
||||||
guint meta_display_get_above_tab_keycode (MetaDisplay *display);
|
guint meta_display_get_above_tab_keycode (MetaDisplay *display);
|
||||||
|
|
||||||
gboolean meta_display_handle_event (MetaDisplay *display,
|
gboolean meta_display_handle_xevent (MetaDisplay *display,
|
||||||
XEvent *event);
|
XEvent *event);
|
||||||
|
|
||||||
|
gboolean meta_display_handle_event (MetaDisplay *display,
|
||||||
|
const ClutterEvent *event);
|
||||||
|
|
||||||
#ifdef HAVE_XI23
|
#ifdef HAVE_XI23
|
||||||
gboolean meta_display_process_barrier_event (MetaDisplay *display,
|
gboolean meta_display_process_barrier_event (MetaDisplay *display,
|
||||||
XIBarrierEvent *event);
|
XIBarrierEvent *event);
|
||||||
|
@@ -177,7 +177,9 @@ static void meta_spew_event (MetaDisplay *display,
|
|||||||
XEvent *event);
|
XEvent *event);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static gboolean event_callback (XEvent *event,
|
static gboolean xevent_callback (XEvent *event,
|
||||||
|
gpointer data);
|
||||||
|
static gboolean event_callback (const ClutterEvent *event,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
static Window event_get_modified_window (MetaDisplay *display,
|
static Window event_get_modified_window (MetaDisplay *display,
|
||||||
XEvent *event);
|
XEvent *event);
|
||||||
@@ -604,8 +606,9 @@ meta_display_open (void)
|
|||||||
|
|
||||||
/* Get events */
|
/* Get events */
|
||||||
meta_ui_add_event_func (the_display->xdisplay,
|
meta_ui_add_event_func (the_display->xdisplay,
|
||||||
event_callback,
|
xevent_callback,
|
||||||
the_display);
|
the_display);
|
||||||
|
clutter_event_add_filter (event_callback, the_display);
|
||||||
|
|
||||||
the_display->xids = g_hash_table_new (meta_unsigned_long_hash,
|
the_display->xids = g_hash_table_new (meta_unsigned_long_hash,
|
||||||
meta_unsigned_long_equal);
|
meta_unsigned_long_equal);
|
||||||
@@ -1125,8 +1128,9 @@ meta_display_close (MetaDisplay *display,
|
|||||||
|
|
||||||
/* Stop caring about events */
|
/* Stop caring about events */
|
||||||
meta_ui_remove_event_func (display->xdisplay,
|
meta_ui_remove_event_func (display->xdisplay,
|
||||||
event_callback,
|
xevent_callback,
|
||||||
display);
|
display);
|
||||||
|
clutter_event_remove_filter (event_callback, display);
|
||||||
|
|
||||||
/* Free all screens */
|
/* Free all screens */
|
||||||
tmp = display->screens;
|
tmp = display->screens;
|
||||||
@@ -2179,8 +2183,42 @@ handle_window_focus_event (MetaDisplay *display,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
reload_xkb_rules (MetaScreen *screen)
|
||||||
|
{
|
||||||
|
MetaWaylandCompositor *compositor;
|
||||||
|
char **names;
|
||||||
|
int n_names;
|
||||||
|
gboolean ok;
|
||||||
|
const char *rules, *model, *layout, *variant, *options;
|
||||||
|
|
||||||
|
compositor = meta_wayland_compositor_get_default ();
|
||||||
|
|
||||||
|
ok = meta_prop_get_latin1_list (screen->display, screen->xroot,
|
||||||
|
screen->display->atom__XKB_RULES_NAMES,
|
||||||
|
&names, &n_names);
|
||||||
|
if (!ok)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (n_names != 5)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
rules = names[0];
|
||||||
|
model = names[1];
|
||||||
|
layout = names[2];
|
||||||
|
variant = names[3];
|
||||||
|
options = names[4];
|
||||||
|
|
||||||
|
meta_wayland_keyboard_set_keymap_names (&compositor->seat->keyboard,
|
||||||
|
rules, model, layout, variant, options,
|
||||||
|
META_WAYLAND_KEYBOARD_SKIP_XCLIENTS);
|
||||||
|
|
||||||
|
out:
|
||||||
|
g_strfreev (names);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* meta_display_handle_event:
|
* meta_display_handle_xevent:
|
||||||
* @display: The MetaDisplay that events are coming from
|
* @display: The MetaDisplay that events are coming from
|
||||||
* @event: The event that just happened
|
* @event: The event that just happened
|
||||||
*
|
*
|
||||||
@@ -2193,7 +2231,7 @@ handle_window_focus_event (MetaDisplay *display,
|
|||||||
* dealing with all the kinds of events that might turn up.
|
* dealing with all the kinds of events that might turn up.
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
meta_display_handle_event (MetaDisplay *display,
|
meta_display_handle_xevent (MetaDisplay *display,
|
||||||
XEvent *event)
|
XEvent *event)
|
||||||
{
|
{
|
||||||
MetaWindow *window;
|
MetaWindow *window;
|
||||||
@@ -2352,7 +2390,6 @@ meta_display_handle_event (MetaDisplay *display,
|
|||||||
|
|
||||||
if (input_event != NULL)
|
if (input_event != NULL)
|
||||||
{
|
{
|
||||||
XIDeviceEvent *device_event = (XIDeviceEvent *) input_event;
|
|
||||||
XIEnterEvent *enter_event = (XIEnterEvent *) input_event;
|
XIEnterEvent *enter_event = (XIEnterEvent *) input_event;
|
||||||
|
|
||||||
if (window && !window->override_redirect &&
|
if (window && !window->override_redirect &&
|
||||||
@@ -2389,205 +2426,6 @@ meta_display_handle_event (MetaDisplay *display,
|
|||||||
if (meta_display_process_key_event (display, window, (XIDeviceEvent *) input_event))
|
if (meta_display_process_key_event (display, window, (XIDeviceEvent *) input_event))
|
||||||
filter_out_event = bypass_compositor = TRUE;
|
filter_out_event = bypass_compositor = TRUE;
|
||||||
break;
|
break;
|
||||||
case XI_ButtonPress:
|
|
||||||
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
|
|
||||||
break;
|
|
||||||
|
|
||||||
display->overlay_key_only_pressed = FALSE;
|
|
||||||
|
|
||||||
if (device_event->detail == 4 || device_event->detail == 5)
|
|
||||||
/* Scrollwheel event, do nothing and deliver event to compositor below */
|
|
||||||
break;
|
|
||||||
|
|
||||||
if ((window &&
|
|
||||||
meta_grab_op_is_mouse (display->grab_op) &&
|
|
||||||
display->grab_button != device_event->detail &&
|
|
||||||
display->grab_window == window) ||
|
|
||||||
grab_op_is_keyboard (display->grab_op))
|
|
||||||
{
|
|
||||||
meta_topic (META_DEBUG_WINDOW_OPS,
|
|
||||||
"Ending grab op %u on window %s due to button press\n",
|
|
||||||
display->grab_op,
|
|
||||||
(display->grab_window ?
|
|
||||||
display->grab_window->desc :
|
|
||||||
"none"));
|
|
||||||
if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op))
|
|
||||||
{
|
|
||||||
MetaScreen *screen;
|
|
||||||
meta_topic (META_DEBUG_WINDOW_OPS,
|
|
||||||
"Syncing to old stack positions.\n");
|
|
||||||
screen =
|
|
||||||
meta_display_screen_for_root (display, device_event->event);
|
|
||||||
|
|
||||||
if (screen!=NULL)
|
|
||||||
meta_stack_set_positions (screen->stack,
|
|
||||||
display->grab_old_window_stacking);
|
|
||||||
}
|
|
||||||
meta_display_end_grab_op (display,
|
|
||||||
device_event->time);
|
|
||||||
}
|
|
||||||
else if (window && display->grab_op == META_GRAB_OP_NONE)
|
|
||||||
{
|
|
||||||
gboolean begin_move = FALSE;
|
|
||||||
unsigned int grab_mask;
|
|
||||||
gboolean unmodified;
|
|
||||||
|
|
||||||
grab_mask = display->window_grab_modifiers;
|
|
||||||
if (g_getenv ("MUTTER_DEBUG_BUTTON_GRABS"))
|
|
||||||
grab_mask |= ControlMask;
|
|
||||||
|
|
||||||
/* Two possible sources of an unmodified event; one is a
|
|
||||||
* client that's letting button presses pass through to the
|
|
||||||
* frame, the other is our focus_window_grab on unmodified
|
|
||||||
* button 1. So for all such events we focus the window.
|
|
||||||
*/
|
|
||||||
unmodified = (device_event->mods.effective & grab_mask) == 0;
|
|
||||||
|
|
||||||
if (unmodified ||
|
|
||||||
device_event->detail == 1)
|
|
||||||
{
|
|
||||||
/* don't focus if frame received, will be lowered in
|
|
||||||
* frames.c or special-cased if the click was on a
|
|
||||||
* minimize/close button.
|
|
||||||
*/
|
|
||||||
if (!frame_was_receiver)
|
|
||||||
{
|
|
||||||
if (meta_prefs_get_raise_on_click ())
|
|
||||||
meta_window_raise (window);
|
|
||||||
else
|
|
||||||
meta_topic (META_DEBUG_FOCUS,
|
|
||||||
"Not raising window on click due to don't-raise-on-click option\n");
|
|
||||||
|
|
||||||
/* Don't focus panels--they must explicitly request focus.
|
|
||||||
* See bug 160470
|
|
||||||
*/
|
|
||||||
if (window->type != META_WINDOW_DOCK)
|
|
||||||
{
|
|
||||||
meta_topic (META_DEBUG_FOCUS,
|
|
||||||
"Focusing %s due to unmodified button %u press (display.c)\n",
|
|
||||||
window->desc, device_event->detail);
|
|
||||||
meta_window_focus (window, device_event->time);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
/* However, do allow terminals to lose focus due to new
|
|
||||||
* window mappings after the user clicks on a panel.
|
|
||||||
*/
|
|
||||||
display->allow_terminal_deactivation = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* you can move on alt-click but not on
|
|
||||||
* the click-to-focus
|
|
||||||
*/
|
|
||||||
if (!unmodified)
|
|
||||||
begin_move = TRUE;
|
|
||||||
}
|
|
||||||
else if (!unmodified && device_event->detail == meta_prefs_get_mouse_button_resize())
|
|
||||||
{
|
|
||||||
if (window->has_resize_func)
|
|
||||||
{
|
|
||||||
gboolean north, south;
|
|
||||||
gboolean west, east;
|
|
||||||
int root_x, root_y;
|
|
||||||
MetaGrabOp op;
|
|
||||||
|
|
||||||
meta_window_get_position (window, &root_x, &root_y);
|
|
||||||
|
|
||||||
west = device_event->root_x < (root_x + 1 * window->rect.width / 3);
|
|
||||||
east = device_event->root_x > (root_x + 2 * window->rect.width / 3);
|
|
||||||
north = device_event->root_y < (root_y + 1 * window->rect.height / 3);
|
|
||||||
south = device_event->root_y > (root_y + 2 * window->rect.height / 3);
|
|
||||||
|
|
||||||
if (north && west)
|
|
||||||
op = META_GRAB_OP_RESIZING_NW;
|
|
||||||
else if (north && east)
|
|
||||||
op = META_GRAB_OP_RESIZING_NE;
|
|
||||||
else if (south && west)
|
|
||||||
op = META_GRAB_OP_RESIZING_SW;
|
|
||||||
else if (south && east)
|
|
||||||
op = META_GRAB_OP_RESIZING_SE;
|
|
||||||
else if (north)
|
|
||||||
op = META_GRAB_OP_RESIZING_N;
|
|
||||||
else if (west)
|
|
||||||
op = META_GRAB_OP_RESIZING_W;
|
|
||||||
else if (east)
|
|
||||||
op = META_GRAB_OP_RESIZING_E;
|
|
||||||
else if (south)
|
|
||||||
op = META_GRAB_OP_RESIZING_S;
|
|
||||||
else /* Middle region is no-op to avoid user triggering wrong action */
|
|
||||||
op = META_GRAB_OP_NONE;
|
|
||||||
|
|
||||||
if (op != META_GRAB_OP_NONE)
|
|
||||||
meta_display_begin_grab_op (display,
|
|
||||||
window->screen,
|
|
||||||
window,
|
|
||||||
op,
|
|
||||||
TRUE,
|
|
||||||
FALSE,
|
|
||||||
device_event->detail,
|
|
||||||
0,
|
|
||||||
device_event->time,
|
|
||||||
device_event->root_x,
|
|
||||||
device_event->root_y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (device_event->detail == meta_prefs_get_mouse_button_menu())
|
|
||||||
{
|
|
||||||
if (meta_prefs_get_raise_on_click ())
|
|
||||||
meta_window_raise (window);
|
|
||||||
meta_window_show_menu (window,
|
|
||||||
device_event->root_x,
|
|
||||||
device_event->root_y,
|
|
||||||
device_event->detail,
|
|
||||||
device_event->time);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!frame_was_receiver && unmodified)
|
|
||||||
{
|
|
||||||
/* This is from our synchronous grab since
|
|
||||||
* it has no modifiers and was on the client window
|
|
||||||
*/
|
|
||||||
|
|
||||||
meta_verbose ("Allowing events time %u\n",
|
|
||||||
(unsigned int)device_event->time);
|
|
||||||
|
|
||||||
XIAllowEvents (display->xdisplay, device_event->deviceid,
|
|
||||||
XIReplayDevice, device_event->time);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (begin_move && window->has_move_func)
|
|
||||||
{
|
|
||||||
meta_display_begin_grab_op (display,
|
|
||||||
window->screen,
|
|
||||||
window,
|
|
||||||
META_GRAB_OP_MOVING,
|
|
||||||
TRUE,
|
|
||||||
FALSE,
|
|
||||||
device_event->detail,
|
|
||||||
0,
|
|
||||||
device_event->time,
|
|
||||||
device_event->root_x,
|
|
||||||
device_event->root_y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case XI_ButtonRelease:
|
|
||||||
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
|
|
||||||
break;
|
|
||||||
|
|
||||||
display->overlay_key_only_pressed = FALSE;
|
|
||||||
|
|
||||||
if (display->grab_window == window &&
|
|
||||||
meta_grab_op_is_mouse (display->grab_op))
|
|
||||||
meta_window_handle_mouse_grab_op_event (window, device_event);
|
|
||||||
break;
|
|
||||||
case XI_Motion:
|
|
||||||
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (display->grab_window == window &&
|
|
||||||
meta_grab_op_is_mouse (display->grab_op))
|
|
||||||
meta_window_handle_mouse_grab_op_event (window, device_event);
|
|
||||||
break;
|
|
||||||
case XI_Enter:
|
case XI_Enter:
|
||||||
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
|
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
|
||||||
break;
|
break;
|
||||||
@@ -2951,6 +2789,10 @@ meta_display_handle_event (MetaDisplay *display,
|
|||||||
else if (event->xproperty.atom ==
|
else if (event->xproperty.atom ==
|
||||||
display->atom__NET_DESKTOP_NAMES)
|
display->atom__NET_DESKTOP_NAMES)
|
||||||
meta_screen_update_workspace_names (screen);
|
meta_screen_update_workspace_names (screen);
|
||||||
|
else if (meta_is_wayland_compositor () &&
|
||||||
|
event->xproperty.atom ==
|
||||||
|
display->atom__XKB_RULES_NAMES)
|
||||||
|
reload_xkb_rules (screen);
|
||||||
#if 0
|
#if 0
|
||||||
else if (event->xproperty.atom ==
|
else if (event->xproperty.atom ==
|
||||||
display->atom__NET_RESTACK_WINDOW)
|
display->atom__NET_RESTACK_WINDOW)
|
||||||
@@ -3169,7 +3011,7 @@ meta_display_handle_event (MetaDisplay *display,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
event_callback (XEvent *event,
|
xevent_callback (XEvent *event,
|
||||||
gpointer data)
|
gpointer data)
|
||||||
{
|
{
|
||||||
MetaDisplay *display = data;
|
MetaDisplay *display = data;
|
||||||
@@ -3186,9 +3028,272 @@ event_callback (XEvent *event,
|
|||||||
translation altogether by directly using the Clutter events */
|
translation altogether by directly using the Clutter events */
|
||||||
if (meta_is_wayland_compositor () &&
|
if (meta_is_wayland_compositor () &&
|
||||||
event->type == GenericEvent &&
|
event->type == GenericEvent &&
|
||||||
event->xcookie.evtype == XI_Motion)
|
(event->xcookie.evtype == XI_KeyPress ||
|
||||||
|
event->xcookie.evtype == XI_KeyRelease))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
return meta_display_handle_xevent (display, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MetaWindow *
|
||||||
|
get_window_for_actor (ClutterActor *actor,
|
||||||
|
gboolean *frame_was_receiver)
|
||||||
|
{
|
||||||
|
/* Look for any ancestor that is a MetaWindowActor to determine
|
||||||
|
which window the actor's event belongs to */
|
||||||
|
|
||||||
|
*frame_was_receiver = TRUE;
|
||||||
|
|
||||||
|
while (actor)
|
||||||
|
{
|
||||||
|
if (META_IS_WINDOW_ACTOR (actor))
|
||||||
|
return meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor));
|
||||||
|
|
||||||
|
/* If the frame is the receiver then the source will directly be
|
||||||
|
the MetaWindowActor, otherwise it will be a child of a
|
||||||
|
MetaWindowActor so if we make it here then the event isn't
|
||||||
|
referring to the frame. */
|
||||||
|
*frame_was_receiver = FALSE;
|
||||||
|
|
||||||
|
actor = clutter_actor_get_parent (actor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_display_handle_event (MetaDisplay *display,
|
||||||
|
const ClutterEvent *event)
|
||||||
|
{
|
||||||
|
MetaWindow *window;
|
||||||
|
gboolean frame_was_receiver;
|
||||||
|
|
||||||
|
window = get_window_for_actor (event->any.source, &frame_was_receiver);
|
||||||
|
|
||||||
|
switch (event->type)
|
||||||
|
{
|
||||||
|
case CLUTTER_BUTTON_PRESS:
|
||||||
|
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
|
||||||
|
break;
|
||||||
|
|
||||||
|
display->overlay_key_only_pressed = FALSE;
|
||||||
|
|
||||||
|
if ((window &&
|
||||||
|
meta_grab_op_is_mouse (display->grab_op) &&
|
||||||
|
display->grab_button != (int) event->button.button &&
|
||||||
|
display->grab_window == window) ||
|
||||||
|
grab_op_is_keyboard (display->grab_op))
|
||||||
|
{
|
||||||
|
meta_topic (META_DEBUG_WINDOW_OPS,
|
||||||
|
"Ending grab op %u on window %s due to button press\n",
|
||||||
|
display->grab_op,
|
||||||
|
(display->grab_window ?
|
||||||
|
display->grab_window->desc :
|
||||||
|
"none"));
|
||||||
|
if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op))
|
||||||
|
{
|
||||||
|
meta_topic (META_DEBUG_WINDOW_OPS,
|
||||||
|
"Syncing to old stack positions.\n");
|
||||||
|
|
||||||
|
/* XXX: I'm not sure if this is the right thing to do.
|
||||||
|
The pre-Wayland code was only calling
|
||||||
|
meta_stack_set_positions if the modified window was a
|
||||||
|
root window */
|
||||||
|
if (CLUTTER_ACTOR (event->any.stage) == event->any.source &&
|
||||||
|
window &&
|
||||||
|
window->screen)
|
||||||
|
meta_stack_set_positions (window->screen->stack,
|
||||||
|
display->grab_old_window_stacking);
|
||||||
|
}
|
||||||
|
meta_display_end_grab_op (display,
|
||||||
|
event->any.time);
|
||||||
|
}
|
||||||
|
else if (window && display->grab_op == META_GRAB_OP_NONE)
|
||||||
|
{
|
||||||
|
gboolean begin_move = FALSE;
|
||||||
|
ClutterModifierType grab_mask;
|
||||||
|
gboolean unmodified;
|
||||||
|
|
||||||
|
grab_mask = display->window_grab_modifiers;
|
||||||
|
if (g_getenv ("MUTTER_DEBUG_BUTTON_GRABS"))
|
||||||
|
grab_mask |= CLUTTER_CONTROL_MASK;
|
||||||
|
|
||||||
|
/* Two possible sources of an unmodified event; one is a
|
||||||
|
* client that's letting button presses pass through to the
|
||||||
|
* frame, the other is our focus_window_grab on unmodified
|
||||||
|
* button 1. So for all such events we focus the window.
|
||||||
|
*/
|
||||||
|
unmodified = (clutter_event_get_state (event) & grab_mask) == 0;
|
||||||
|
|
||||||
|
if (unmodified ||
|
||||||
|
event->button.button == 1)
|
||||||
|
{
|
||||||
|
/* don't focus if frame received, will be lowered in
|
||||||
|
* frames.c or special-cased if the click was on a
|
||||||
|
* minimize/close button.
|
||||||
|
*/
|
||||||
|
if (!frame_was_receiver)
|
||||||
|
{
|
||||||
|
if (meta_prefs_get_raise_on_click ())
|
||||||
|
meta_window_raise (window);
|
||||||
|
else
|
||||||
|
meta_topic (META_DEBUG_FOCUS,
|
||||||
|
"Not raising window on click due "
|
||||||
|
"to don't-raise-on-click option\n");
|
||||||
|
|
||||||
|
/* Don't focus panels--they must explicitly request focus.
|
||||||
|
* See bug 160470
|
||||||
|
*/
|
||||||
|
if (window->type != META_WINDOW_DOCK)
|
||||||
|
{
|
||||||
|
meta_topic (META_DEBUG_FOCUS,
|
||||||
|
"Focusing %s due to unmodified button %u "
|
||||||
|
"press (display.c)\n",
|
||||||
|
window->desc, event->button.button);
|
||||||
|
meta_window_focus (window, event->any.time);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* However, do allow terminals to lose focus due to new
|
||||||
|
* window mappings after the user clicks on a panel.
|
||||||
|
*/
|
||||||
|
display->allow_terminal_deactivation = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* you can move on alt-click but not on
|
||||||
|
* the click-to-focus
|
||||||
|
*/
|
||||||
|
if (!unmodified)
|
||||||
|
begin_move = TRUE;
|
||||||
|
}
|
||||||
|
else if (!unmodified &&
|
||||||
|
((int) event->button.button ==
|
||||||
|
meta_prefs_get_mouse_button_resize ()))
|
||||||
|
{
|
||||||
|
if (window->has_resize_func)
|
||||||
|
{
|
||||||
|
gboolean north, south;
|
||||||
|
gboolean west, east;
|
||||||
|
int root_x, root_y;
|
||||||
|
MetaGrabOp op;
|
||||||
|
|
||||||
|
meta_window_get_position (window, &root_x, &root_y);
|
||||||
|
|
||||||
|
west = (event->button.x <
|
||||||
|
(root_x + 1 * window->rect.width / 3));
|
||||||
|
east = (event->button.x >
|
||||||
|
(root_x + 2 * window->rect.width / 3));
|
||||||
|
north = (event->button.y <
|
||||||
|
(root_y + 1 * window->rect.height / 3));
|
||||||
|
south = (event->button.y >
|
||||||
|
(root_y + 2 * window->rect.height / 3));
|
||||||
|
|
||||||
|
if (north && west)
|
||||||
|
op = META_GRAB_OP_RESIZING_NW;
|
||||||
|
else if (north && east)
|
||||||
|
op = META_GRAB_OP_RESIZING_NE;
|
||||||
|
else if (south && west)
|
||||||
|
op = META_GRAB_OP_RESIZING_SW;
|
||||||
|
else if (south && east)
|
||||||
|
op = META_GRAB_OP_RESIZING_SE;
|
||||||
|
else if (north)
|
||||||
|
op = META_GRAB_OP_RESIZING_N;
|
||||||
|
else if (west)
|
||||||
|
op = META_GRAB_OP_RESIZING_W;
|
||||||
|
else if (east)
|
||||||
|
op = META_GRAB_OP_RESIZING_E;
|
||||||
|
else if (south)
|
||||||
|
op = META_GRAB_OP_RESIZING_S;
|
||||||
|
else
|
||||||
|
/* Middle region is no-op to avoid user triggering
|
||||||
|
wrong action */
|
||||||
|
op = META_GRAB_OP_NONE;
|
||||||
|
|
||||||
|
if (op != META_GRAB_OP_NONE)
|
||||||
|
meta_display_begin_grab_op (display,
|
||||||
|
window->screen,
|
||||||
|
window,
|
||||||
|
op,
|
||||||
|
TRUE,
|
||||||
|
FALSE,
|
||||||
|
event->button.button,
|
||||||
|
0,
|
||||||
|
event->any.time,
|
||||||
|
event->button.x,
|
||||||
|
event->button.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((int) event->button.button ==
|
||||||
|
meta_prefs_get_mouse_button_menu ())
|
||||||
|
{
|
||||||
|
if (meta_prefs_get_raise_on_click ())
|
||||||
|
meta_window_raise (window);
|
||||||
|
meta_window_show_menu (window,
|
||||||
|
event->button.x,
|
||||||
|
event->button.y,
|
||||||
|
event->button.button,
|
||||||
|
event->any.time);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!frame_was_receiver && unmodified)
|
||||||
|
{
|
||||||
|
/* This is from our synchronous grab since
|
||||||
|
* it has no modifiers and was on the client window
|
||||||
|
*/
|
||||||
|
|
||||||
|
meta_verbose ("Allowing events time %u\n",
|
||||||
|
(unsigned int) event->any.time);
|
||||||
|
|
||||||
|
clutter_input_device_set_enabled (event->button.device, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (begin_move && window->has_move_func)
|
||||||
|
{
|
||||||
|
meta_display_begin_grab_op (display,
|
||||||
|
window->screen,
|
||||||
|
window,
|
||||||
|
META_GRAB_OP_MOVING,
|
||||||
|
TRUE,
|
||||||
|
FALSE,
|
||||||
|
event->button.button,
|
||||||
|
0,
|
||||||
|
event->any.time,
|
||||||
|
event->button.x,
|
||||||
|
event->button.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CLUTTER_BUTTON_RELEASE:
|
||||||
|
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
|
||||||
|
break;
|
||||||
|
|
||||||
|
display->overlay_key_only_pressed = FALSE;
|
||||||
|
|
||||||
|
if (display->grab_window == window &&
|
||||||
|
meta_grab_op_is_mouse (display->grab_op))
|
||||||
|
meta_window_handle_mouse_grab_op_event (window, event);
|
||||||
|
break;
|
||||||
|
case CLUTTER_MOTION:
|
||||||
|
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (display->grab_window == window &&
|
||||||
|
meta_grab_op_is_mouse (display->grab_op))
|
||||||
|
meta_window_handle_mouse_grab_op_event (window, event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
event_callback (const ClutterEvent *event,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
MetaDisplay *display = data;
|
||||||
|
|
||||||
return meta_display_handle_event (display, event);
|
return meta_display_handle_event (display, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5984,7 +6089,7 @@ meta_display_get_xinput_opcode (MetaDisplay *display)
|
|||||||
gboolean
|
gboolean
|
||||||
meta_display_supports_extended_barriers (MetaDisplay *display)
|
meta_display_supports_extended_barriers (MetaDisplay *display)
|
||||||
{
|
{
|
||||||
return META_DISPLAY_HAS_XINPUT_23 (display);
|
return META_DISPLAY_HAS_XINPUT_23 (display) && !meta_is_wayland_compositor ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -2065,22 +2065,22 @@ meta_display_process_key_event (MetaDisplay *display,
|
|||||||
gboolean handled;
|
gboolean handled;
|
||||||
const char *str;
|
const char *str;
|
||||||
MetaScreen *screen;
|
MetaScreen *screen;
|
||||||
|
gboolean was_current_time;
|
||||||
|
|
||||||
/* if key event was on root window, we have a shortcut */
|
/* We only ever have one screen */
|
||||||
screen = meta_display_screen_for_root (display, event->event);
|
screen = display->screens->data;
|
||||||
|
|
||||||
/* else round-trip to server */
|
|
||||||
if (screen == NULL)
|
|
||||||
screen = meta_display_screen_for_xwindow (display, event->event);
|
|
||||||
|
|
||||||
if (screen == NULL)
|
|
||||||
return FALSE; /* event window is destroyed */
|
|
||||||
|
|
||||||
/* ignore key events on popup menus and such. */
|
/* ignore key events on popup menus and such. */
|
||||||
if (meta_ui_window_is_widget (screen->ui, event->event))
|
if (meta_ui_window_is_widget (screen->ui, event->event))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* window may be NULL */
|
if (display->current_time == CurrentTime)
|
||||||
|
{
|
||||||
|
display->current_time = event->time;
|
||||||
|
was_current_time = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
was_current_time = FALSE;
|
||||||
|
|
||||||
keysym = XKeycodeToKeysym (display->xdisplay, event->detail, 0);
|
keysym = XKeycodeToKeysym (display->xdisplay, event->detail, 0);
|
||||||
|
|
||||||
@@ -2098,11 +2098,11 @@ meta_display_process_key_event (MetaDisplay *display,
|
|||||||
{
|
{
|
||||||
handled = process_overlay_key (display, screen, event, keysym);
|
handled = process_overlay_key (display, screen, event, keysym);
|
||||||
if (handled)
|
if (handled)
|
||||||
return TRUE;
|
goto out;
|
||||||
|
|
||||||
handled = process_iso_next_group (display, screen, event, keysym);
|
handled = process_iso_next_group (display, screen, event, keysym);
|
||||||
if (handled)
|
if (handled)
|
||||||
return TRUE;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
XIAllowEvents (display->xdisplay, event->deviceid,
|
XIAllowEvents (display->xdisplay, event->deviceid,
|
||||||
@@ -2112,7 +2112,11 @@ meta_display_process_key_event (MetaDisplay *display,
|
|||||||
if (all_keys_grabbed)
|
if (all_keys_grabbed)
|
||||||
{
|
{
|
||||||
if (display->grab_op == META_GRAB_OP_NONE)
|
if (display->grab_op == META_GRAB_OP_NONE)
|
||||||
return TRUE;
|
{
|
||||||
|
handled = TRUE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* If we get here we have a global grab, because
|
/* If we get here we have a global grab, because
|
||||||
* we're in some special keyboard mode such as window move
|
* we're in some special keyboard mode such as window move
|
||||||
* mode.
|
* mode.
|
||||||
@@ -2191,14 +2195,20 @@ meta_display_process_key_event (MetaDisplay *display,
|
|||||||
meta_display_end_grab_op (display, event->time);
|
meta_display_end_grab_op (display, event->time);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
handled = TRUE;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do the normal keybindings */
|
/* Do the normal keybindings */
|
||||||
return process_event (display->key_bindings,
|
handled = process_event (display->key_bindings,
|
||||||
display->n_key_bindings,
|
display->n_key_bindings,
|
||||||
display, screen, window, event, keysym,
|
display, screen, window, event, keysym,
|
||||||
!all_keys_grabbed && window);
|
!all_keys_grabbed && window);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (was_current_time)
|
||||||
|
display->current_time = CurrentTime;
|
||||||
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@@ -249,6 +249,17 @@ meta_get_option_context (void)
|
|||||||
bindtextdomain (GETTEXT_PACKAGE, MUTTER_LOCALEDIR);
|
bindtextdomain (GETTEXT_PACKAGE, MUTTER_LOCALEDIR);
|
||||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||||
|
|
||||||
|
/* We must set the variables here, because Clutter creates the backend
|
||||||
|
when the first call is made.
|
||||||
|
|
||||||
|
We consider running from mutter-launch equivalent to running from bare metal.
|
||||||
|
*/
|
||||||
|
if (getenv ("WESTON_LAUNCHER_SOCK"))
|
||||||
|
{
|
||||||
|
g_setenv ("CLUTTER_BACKEND", "eglnative", TRUE);
|
||||||
|
g_setenv ("CLUTTER_INPUT_BACKEND", "evdev", TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
ctx = g_option_context_new (NULL);
|
ctx = g_option_context_new (NULL);
|
||||||
g_option_context_add_main_entries (ctx, meta_options, GETTEXT_PACKAGE);
|
g_option_context_add_main_entries (ctx, meta_options, GETTEXT_PACKAGE);
|
||||||
g_option_context_add_group (ctx, clutter_get_option_group_without_init ());
|
g_option_context_add_group (ctx, clutter_get_option_group_without_init ());
|
||||||
@@ -386,6 +397,9 @@ meta_init (void)
|
|||||||
g_strerror (errno));
|
g_strerror (errno));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (getenv ("MUTTER_SLEEP_INIT"))
|
||||||
|
sleep (60);
|
||||||
|
|
||||||
g_unix_signal_add (SIGTERM, on_sigterm, NULL);
|
g_unix_signal_add (SIGTERM, on_sigterm, NULL);
|
||||||
|
|
||||||
if (g_getenv ("MUTTER_VERBOSE"))
|
if (g_getenv ("MUTTER_VERBOSE"))
|
||||||
|
858
src/core/monitor-kms.c
Normal file
858
src/core/monitor-kms.c
Normal file
@@ -0,0 +1,858 @@
|
|||||||
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Author: Giovanni Campagna <gcampagn@redhat.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <clutter/clutter.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <xf86drm.h>
|
||||||
|
#include <xf86drmMode.h>
|
||||||
|
|
||||||
|
#include <meta/main.h>
|
||||||
|
#include <meta/errors.h>
|
||||||
|
#include "monitor-private.h"
|
||||||
|
#include "edid.h"
|
||||||
|
|
||||||
|
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
drmModeConnector *connector;
|
||||||
|
|
||||||
|
unsigned n_encoders;
|
||||||
|
drmModeEncoderPtr *encoders;
|
||||||
|
drmModeEncoderPtr current_encoder;
|
||||||
|
|
||||||
|
/* bitmasks of encoder position in the resources array */
|
||||||
|
uint32_t encoder_mask;
|
||||||
|
uint32_t enc_clone_mask;
|
||||||
|
|
||||||
|
uint32_t dpms_prop_id;
|
||||||
|
uint32_t edid_blob_id;
|
||||||
|
uint32_t has_dpms_prop : 1;
|
||||||
|
uint32_t has_edid_blob : 1;
|
||||||
|
} MetaOutputKms;
|
||||||
|
|
||||||
|
struct _MetaMonitorManagerKms
|
||||||
|
{
|
||||||
|
MetaMonitorManager parent_instance;
|
||||||
|
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
drmModeConnector **connectors;
|
||||||
|
unsigned int n_connectors;
|
||||||
|
|
||||||
|
drmModeEncoder **encoders;
|
||||||
|
unsigned int n_encoders;
|
||||||
|
|
||||||
|
drmModeEncoder *current_encoder;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _MetaMonitorManagerKmsClass
|
||||||
|
{
|
||||||
|
MetaMonitorManagerClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (MetaMonitorManagerKms, meta_monitor_manager_kms, META_TYPE_MONITOR_MANAGER);
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_outputs (const void *one,
|
||||||
|
const void *two)
|
||||||
|
{
|
||||||
|
const MetaOutput *o_one = one, *o_two = two;
|
||||||
|
|
||||||
|
return strcmp (o_one->name, o_two->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
make_output_name (drmModeConnector *connector)
|
||||||
|
{
|
||||||
|
static const char * const connector_type_names[] = {
|
||||||
|
"unknown", "VGA", "DVII", "DVID", "DVID", "Composite",
|
||||||
|
"SVIDEO", "LVDS", "Component", "9PinDIN", "DisplayPort",
|
||||||
|
"HDMIA", "HDMIB", "TV", "eDP"
|
||||||
|
};
|
||||||
|
const char *connector_type_name;
|
||||||
|
|
||||||
|
if (connector->connector_type >= 0 &&
|
||||||
|
connector->connector_type < G_N_ELEMENTS (connector_type_names))
|
||||||
|
connector_type_name = connector_type_names[connector->connector_type];
|
||||||
|
else
|
||||||
|
connector_type_name = "unknown";
|
||||||
|
|
||||||
|
return g_strdup_printf ("%s%d", connector_type_name, connector->connector_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_output_destroy_notify (MetaOutput *output)
|
||||||
|
{
|
||||||
|
MetaOutputKms *output_kms;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
output_kms = output->driver_private;
|
||||||
|
|
||||||
|
for (i = 0; i < output_kms->n_encoders; i++)
|
||||||
|
drmModeFreeEncoder (output_kms->encoders[i]);
|
||||||
|
|
||||||
|
g_slice_free (MetaOutputKms, output_kms);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_monitor_mode_destroy_notify (MetaMonitorMode *output)
|
||||||
|
{
|
||||||
|
g_slice_free (drmModeModeInfo, output->driver_private);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
drm_mode_equal (gconstpointer one,
|
||||||
|
gconstpointer two)
|
||||||
|
{
|
||||||
|
return memcmp (one, two, sizeof (drmModeModeInfo)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint
|
||||||
|
drm_mode_hash (gconstpointer ptr)
|
||||||
|
{
|
||||||
|
const drmModeModeInfo *mode = ptr;
|
||||||
|
guint hash = 0;
|
||||||
|
|
||||||
|
hash ^= mode->clock;
|
||||||
|
hash ^= mode->hdisplay ^ mode->hsync_start ^ mode->hsync_end;
|
||||||
|
hash ^= mode->vdisplay ^ mode->vsync_start ^ mode->vsync_end;
|
||||||
|
hash ^= mode->vrefresh;
|
||||||
|
hash ^= mode->flags ^ mode->type;
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
find_properties (MetaMonitorManagerKms *manager_kms,
|
||||||
|
MetaOutputKms *output_kms)
|
||||||
|
{
|
||||||
|
drmModePropertyPtr prop;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < output_kms->connector->count_props; i++)
|
||||||
|
{
|
||||||
|
prop = drmModeGetProperty (manager_kms->fd, output_kms->connector->props[i]);
|
||||||
|
if (!prop)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((prop->flags & DRM_MODE_PROP_ENUM) &&
|
||||||
|
strcmp(prop->name, "DPMS") == 0)
|
||||||
|
{
|
||||||
|
output_kms->dpms_prop_id = prop->prop_id;
|
||||||
|
output_kms->has_dpms_prop = TRUE;
|
||||||
|
drmModeFreeProperty(prop);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((prop->flags & DRM_MODE_PROP_BLOB) &&
|
||||||
|
strcmp (prop->name, "EDID") == 0)
|
||||||
|
{
|
||||||
|
output_kms->edid_blob_id = output_kms->connector->prop_values[i];
|
||||||
|
output_kms->has_edid_blob = TRUE;
|
||||||
|
drmModeFreeProperty(prop);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeFreeProperty(prop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GBytes *
|
||||||
|
read_output_edid (MetaMonitorManagerKms *manager_kms,
|
||||||
|
MetaOutput *output)
|
||||||
|
{
|
||||||
|
MetaOutputKms *output_kms = output->driver_private;
|
||||||
|
drmModePropertyBlobPtr edid_blob = NULL;
|
||||||
|
|
||||||
|
if (!output_kms->has_edid_blob)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
edid_blob = drmModeGetPropertyBlob (manager_kms->fd, output_kms->edid_blob_id);
|
||||||
|
if (!edid_blob)
|
||||||
|
{
|
||||||
|
meta_warning ("Failed to read EDID of output %s: %s\n", output->name, strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edid_blob->length > 0 && edid_blob->length % 128 == 0)
|
||||||
|
return g_bytes_new_with_free_func (edid_blob->data, edid_blob->length,
|
||||||
|
(GDestroyNotify)drmModeFreePropertyBlob, edid_blob);
|
||||||
|
else
|
||||||
|
drmModeFreePropertyBlob (edid_blob);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
|
||||||
|
{
|
||||||
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||||
|
drmModeRes *resources;
|
||||||
|
GHashTable *modes;
|
||||||
|
GHashTableIter iter;
|
||||||
|
drmModeModeInfo *mode;
|
||||||
|
unsigned int i, j, k;
|
||||||
|
unsigned int n_actual_outputs;
|
||||||
|
int width, height;
|
||||||
|
|
||||||
|
resources = drmModeGetResources(manager_kms->fd);
|
||||||
|
modes = g_hash_table_new (drm_mode_hash, drm_mode_equal);
|
||||||
|
|
||||||
|
manager->max_screen_width = resources->max_width;
|
||||||
|
manager->max_screen_height = resources->max_height;
|
||||||
|
|
||||||
|
manager->power_save_mode = META_POWER_SAVE_ON;
|
||||||
|
|
||||||
|
manager_kms->n_connectors = resources->count_connectors;
|
||||||
|
manager_kms->connectors = g_new (drmModeConnector *, manager_kms->n_connectors);
|
||||||
|
for (i = 0; i < manager_kms->n_connectors; i++)
|
||||||
|
{
|
||||||
|
drmModeConnector *connector;
|
||||||
|
|
||||||
|
connector = drmModeGetConnector (manager_kms->fd, resources->connectors[i]);
|
||||||
|
manager_kms->connectors[i] = connector;
|
||||||
|
|
||||||
|
if (connector->connection == DRM_MODE_CONNECTED)
|
||||||
|
{
|
||||||
|
/* Collect all modes for this connector */
|
||||||
|
for (j = 0; j < (unsigned)connector->count_modes; j++)
|
||||||
|
g_hash_table_add (modes, &connector->modes[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
manager_kms->n_encoders = resources->count_encoders;
|
||||||
|
manager_kms->encoders = g_new (drmModeEncoder *, manager_kms->n_encoders);
|
||||||
|
for (i = 0; i < manager_kms->n_encoders; i++)
|
||||||
|
{
|
||||||
|
manager_kms->encoders[i] = drmModeGetEncoder (manager_kms->fd,
|
||||||
|
resources->encoders[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
manager->n_modes = g_hash_table_size (modes);
|
||||||
|
manager->modes = g_new0 (MetaMonitorMode, manager->n_modes);
|
||||||
|
g_hash_table_iter_init (&iter, modes);
|
||||||
|
i = 0;
|
||||||
|
while (g_hash_table_iter_next (&iter, NULL, (gpointer)&mode))
|
||||||
|
{
|
||||||
|
MetaMonitorMode *meta_mode;
|
||||||
|
|
||||||
|
meta_mode = &manager->modes[i];
|
||||||
|
|
||||||
|
meta_mode->mode_id = i;
|
||||||
|
meta_mode->name = g_strndup (mode->name, DRM_DISPLAY_MODE_LEN);
|
||||||
|
meta_mode->width = mode->hdisplay;
|
||||||
|
meta_mode->height = mode->vdisplay;
|
||||||
|
meta_mode->refresh_rate = (1000 * mode->clock /
|
||||||
|
((float)mode->htotal * mode->vtotal));
|
||||||
|
|
||||||
|
meta_mode->driver_private = g_slice_dup (drmModeModeInfo, mode);
|
||||||
|
meta_mode->driver_notify = (GDestroyNotify)meta_monitor_mode_destroy_notify;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
g_hash_table_destroy (modes);
|
||||||
|
|
||||||
|
manager->n_crtcs = resources->count_crtcs;
|
||||||
|
manager->crtcs = g_new0 (MetaCRTC, manager->n_crtcs);
|
||||||
|
width = 0; height = 0;
|
||||||
|
for (i = 0; i < (unsigned)resources->count_crtcs; i++)
|
||||||
|
{
|
||||||
|
drmModeCrtc *crtc;
|
||||||
|
MetaCRTC *meta_crtc;
|
||||||
|
|
||||||
|
crtc = drmModeGetCrtc (manager_kms->fd, resources->crtcs[i]);
|
||||||
|
|
||||||
|
meta_crtc = &manager->crtcs[i];
|
||||||
|
|
||||||
|
meta_crtc->crtc_id = crtc->crtc_id;
|
||||||
|
meta_crtc->rect.x = crtc->x;
|
||||||
|
meta_crtc->rect.y = crtc->y;
|
||||||
|
meta_crtc->rect.width = crtc->width;
|
||||||
|
meta_crtc->rect.height = crtc->height;
|
||||||
|
meta_crtc->is_dirty = FALSE;
|
||||||
|
meta_crtc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||||
|
/* FIXME: implement! */
|
||||||
|
meta_crtc->all_transforms = 1 << WL_OUTPUT_TRANSFORM_NORMAL;
|
||||||
|
|
||||||
|
if (crtc->mode_valid)
|
||||||
|
{
|
||||||
|
for (j = 0; j < manager->n_modes; j++)
|
||||||
|
{
|
||||||
|
if (drm_mode_equal (&crtc->mode, manager->modes[j].driver_private))
|
||||||
|
{
|
||||||
|
meta_crtc->current_mode = &manager->modes[j];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
width = MAX (width, meta_crtc->rect.x + meta_crtc->rect.width);
|
||||||
|
height = MAX (height, meta_crtc->rect.y + meta_crtc->rect.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeFreeCrtc (crtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
manager->screen_width = width;
|
||||||
|
manager->screen_height = height;
|
||||||
|
|
||||||
|
manager->outputs = g_new0 (MetaOutput, manager_kms->n_connectors);
|
||||||
|
n_actual_outputs = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < manager_kms->n_connectors; i++)
|
||||||
|
{
|
||||||
|
MetaOutput *meta_output;
|
||||||
|
MetaOutputKms *output_kms;
|
||||||
|
drmModeConnector *connector;
|
||||||
|
GArray *crtcs;
|
||||||
|
unsigned int crtc_mask;
|
||||||
|
GBytes *edid;
|
||||||
|
|
||||||
|
connector = manager_kms->connectors[i];
|
||||||
|
meta_output = &manager->outputs[n_actual_outputs];
|
||||||
|
|
||||||
|
if (connector->connection == DRM_MODE_CONNECTED)
|
||||||
|
{
|
||||||
|
meta_output->driver_private = output_kms = g_slice_new0 (MetaOutputKms);
|
||||||
|
meta_output->driver_notify = (GDestroyNotify)meta_output_destroy_notify;
|
||||||
|
|
||||||
|
meta_output->output_id = connector->connector_id;
|
||||||
|
meta_output->name = make_output_name (connector);
|
||||||
|
meta_output->width_mm = connector->mmWidth;
|
||||||
|
meta_output->height_mm = connector->mmHeight;
|
||||||
|
|
||||||
|
if (connector->subpixel == DRM_MODE_SUBPIXEL_UNKNOWN)
|
||||||
|
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
||||||
|
else if (connector->subpixel == DRM_MODE_SUBPIXEL_NONE)
|
||||||
|
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_NONE;
|
||||||
|
else
|
||||||
|
meta_output->subpixel_order = connector->subpixel;
|
||||||
|
|
||||||
|
meta_output->n_modes = connector->count_modes;
|
||||||
|
meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes);
|
||||||
|
for (j = 0; j < meta_output->n_modes; j++)
|
||||||
|
{
|
||||||
|
for (k = 0; k < manager->n_modes; k++)
|
||||||
|
{
|
||||||
|
if (drm_mode_equal (&connector->modes[j], manager->modes[k].driver_private))
|
||||||
|
{
|
||||||
|
meta_output->modes[j] = &manager->modes[k];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
meta_output->preferred_mode = meta_output->modes[0];
|
||||||
|
|
||||||
|
output_kms->connector = connector;
|
||||||
|
output_kms->n_encoders = connector->count_encoders;
|
||||||
|
output_kms->encoders = g_new0 (drmModeEncoderPtr, output_kms->n_encoders);
|
||||||
|
|
||||||
|
crtc_mask = 0x7F;
|
||||||
|
for (j = 0; j < output_kms->n_encoders; j++)
|
||||||
|
{
|
||||||
|
output_kms->encoders[j] = drmModeGetEncoder (manager_kms->fd, connector->encoders[j]);
|
||||||
|
|
||||||
|
crtc_mask &= output_kms->encoders[j]->possible_crtcs;
|
||||||
|
|
||||||
|
if (output_kms->encoders[j]->encoder_id == connector->encoder_id)
|
||||||
|
output_kms->current_encoder = output_kms->encoders[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
crtcs = g_array_new (FALSE, FALSE, sizeof (MetaCRTC*));
|
||||||
|
|
||||||
|
for (j = 0; j < manager->n_crtcs; j++)
|
||||||
|
{
|
||||||
|
if (crtc_mask & (1 << j))
|
||||||
|
{
|
||||||
|
MetaCRTC *crtc = &manager->crtcs[j];
|
||||||
|
g_array_append_val (crtcs, crtc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
meta_output->n_possible_crtcs = crtcs->len;
|
||||||
|
meta_output->possible_crtcs = (void*)g_array_free (crtcs, FALSE);
|
||||||
|
|
||||||
|
if (output_kms->current_encoder && output_kms->current_encoder->crtc_id != 0)
|
||||||
|
{
|
||||||
|
for (j = 0; j < manager->n_crtcs; j++)
|
||||||
|
{
|
||||||
|
if (manager->crtcs[j].crtc_id == output_kms->current_encoder->crtc_id)
|
||||||
|
{
|
||||||
|
meta_output->crtc = &manager->crtcs[j];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
meta_output->crtc = NULL;
|
||||||
|
|
||||||
|
meta_output->is_primary = FALSE;
|
||||||
|
meta_output->is_presentation = FALSE;
|
||||||
|
|
||||||
|
find_properties (manager_kms, output_kms);
|
||||||
|
|
||||||
|
edid = read_output_edid (manager_kms, meta_output);
|
||||||
|
if (edid)
|
||||||
|
{
|
||||||
|
MonitorInfo *parsed_edid;
|
||||||
|
gsize len;
|
||||||
|
|
||||||
|
parsed_edid = decode_edid (g_bytes_get_data (edid, &len));
|
||||||
|
if (parsed_edid)
|
||||||
|
{
|
||||||
|
meta_output->vendor = g_strndup (parsed_edid->manufacturer_code, 4);
|
||||||
|
meta_output->product = g_strndup (parsed_edid->dsc_product_name, 14);
|
||||||
|
meta_output->serial = g_strndup (parsed_edid->dsc_serial_number, 14);
|
||||||
|
|
||||||
|
g_free (parsed_edid);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_bytes_unref (edid);
|
||||||
|
}
|
||||||
|
if (!meta_output->vendor)
|
||||||
|
{
|
||||||
|
meta_output->vendor = g_strdup ("unknown");
|
||||||
|
meta_output->product = g_strdup ("unknown");
|
||||||
|
meta_output->serial = g_strdup ("unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: backlight is a very driver specific thing unfortunately,
|
||||||
|
every DDX does its own thing, and the dumb KMS API does not include it.
|
||||||
|
|
||||||
|
For example, xf86-video-intel has a list of paths to probe in /sys/class/backlight
|
||||||
|
(one for each major HW maker, and then some).
|
||||||
|
We can't do the same because we're not root.
|
||||||
|
It might be best to leave backlight out of the story and rely on the setuid
|
||||||
|
helper in gnome-settings-daemon.
|
||||||
|
*/
|
||||||
|
meta_output->backlight_min = 0;
|
||||||
|
meta_output->backlight_max = 0;
|
||||||
|
meta_output->backlight = -1;
|
||||||
|
|
||||||
|
n_actual_outputs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
manager->n_outputs = n_actual_outputs;
|
||||||
|
manager->outputs = g_renew (MetaOutput, manager->outputs, manager->n_outputs);
|
||||||
|
|
||||||
|
/* Sort the outputs for easier handling in MetaMonitorConfig */
|
||||||
|
qsort (manager->outputs, manager->n_outputs, sizeof (MetaOutput), compare_outputs);
|
||||||
|
|
||||||
|
/* Now fix the clones.
|
||||||
|
Code mostly inspired by xf86-video-modesetting. */
|
||||||
|
|
||||||
|
/* XXX: intel hardware doesn't usually have clones, but we only have intel
|
||||||
|
cards, so this code was never tested! */
|
||||||
|
for (i = 0; i < manager->n_outputs; i++)
|
||||||
|
{
|
||||||
|
MetaOutput *meta_output;
|
||||||
|
MetaOutputKms *output_kms;
|
||||||
|
|
||||||
|
meta_output = &manager->outputs[i];
|
||||||
|
output_kms = meta_output->driver_private;
|
||||||
|
|
||||||
|
output_kms->enc_clone_mask = 0xff;
|
||||||
|
output_kms->encoder_mask = 0;
|
||||||
|
|
||||||
|
for (j = 0; j < output_kms->n_encoders; j++)
|
||||||
|
{
|
||||||
|
for (k = 0; k < manager_kms->n_encoders; k++)
|
||||||
|
{
|
||||||
|
if (output_kms->encoders[j]->encoder_id == manager_kms->encoders[k]->encoder_id)
|
||||||
|
{
|
||||||
|
output_kms->encoder_mask |= (1 << k);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output_kms->enc_clone_mask &= output_kms->encoders[j]->possible_clones;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < manager->n_outputs; i++)
|
||||||
|
{
|
||||||
|
MetaOutput *meta_output;
|
||||||
|
MetaOutputKms *output_kms;
|
||||||
|
|
||||||
|
meta_output = &manager->outputs[i];
|
||||||
|
output_kms = meta_output->driver_private;
|
||||||
|
|
||||||
|
if (output_kms->enc_clone_mask == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (j = 0; j < manager->n_outputs; j++)
|
||||||
|
{
|
||||||
|
MetaOutput *meta_clone;
|
||||||
|
MetaOutputKms *clone_kms;
|
||||||
|
|
||||||
|
meta_clone = &manager->outputs[i];
|
||||||
|
clone_kms = meta_clone->driver_private;
|
||||||
|
|
||||||
|
if (meta_clone == meta_output)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (clone_kms->encoder_mask == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (clone_kms->encoder_mask == output_kms->enc_clone_mask)
|
||||||
|
{
|
||||||
|
meta_output->n_possible_clones++;
|
||||||
|
meta_output->possible_clones = g_renew (MetaOutput *,
|
||||||
|
meta_output->possible_clones,
|
||||||
|
meta_output->n_possible_clones);
|
||||||
|
meta_output->possible_clones[meta_output->n_possible_clones - 1] = meta_clone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeFreeResources (resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GBytes *
|
||||||
|
meta_monitor_manager_kms_read_edid (MetaMonitorManager *manager,
|
||||||
|
MetaOutput *output)
|
||||||
|
{
|
||||||
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||||
|
|
||||||
|
return read_output_edid (manager_kms, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
|
||||||
|
MetaPowerSave mode)
|
||||||
|
{
|
||||||
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||||
|
uint64_t state;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case META_POWER_SAVE_ON:
|
||||||
|
state = DRM_MODE_DPMS_ON;
|
||||||
|
break;
|
||||||
|
case META_POWER_SAVE_STANDBY:
|
||||||
|
state = DRM_MODE_DPMS_STANDBY;
|
||||||
|
break;
|
||||||
|
case META_POWER_SAVE_SUSPEND:
|
||||||
|
state = DRM_MODE_DPMS_SUSPEND;
|
||||||
|
break;
|
||||||
|
case META_POWER_SAVE_OFF:
|
||||||
|
state = DRM_MODE_DPMS_SUSPEND;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < manager->n_outputs; i++)
|
||||||
|
{
|
||||||
|
MetaOutput *meta_output;
|
||||||
|
MetaOutputKms *output_kms;
|
||||||
|
|
||||||
|
meta_output = &manager->outputs[i];
|
||||||
|
output_kms = meta_output->driver_private;
|
||||||
|
|
||||||
|
if (output_kms->has_dpms_prop)
|
||||||
|
{
|
||||||
|
int ok = drmModeConnectorSetProperty(manager_kms->fd, meta_output->output_id,
|
||||||
|
output_kms->dpms_prop_id, state);
|
||||||
|
|
||||||
|
if (ok < 0)
|
||||||
|
meta_warning ("Failed to set power save mode for output %s: %s\n",
|
||||||
|
meta_output->name, strerror (errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
crtc_free (CoglKmsCrtc *crtc)
|
||||||
|
{
|
||||||
|
g_free (crtc->connectors);
|
||||||
|
g_slice_free (CoglKmsCrtc, crtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager,
|
||||||
|
MetaCRTCInfo **crtcs,
|
||||||
|
unsigned int n_crtcs,
|
||||||
|
MetaOutputInfo **outputs,
|
||||||
|
unsigned int n_outputs)
|
||||||
|
{
|
||||||
|
ClutterBackend *backend;
|
||||||
|
CoglContext *cogl_context;
|
||||||
|
CoglDisplay *cogl_display;
|
||||||
|
unsigned i;
|
||||||
|
GPtrArray *cogl_crtcs;
|
||||||
|
int screen_width, screen_height;
|
||||||
|
gboolean ok;
|
||||||
|
GError *error;
|
||||||
|
|
||||||
|
cogl_crtcs = g_ptr_array_new_full (manager->n_crtcs, (GDestroyNotify)crtc_free);
|
||||||
|
screen_width = 0; screen_height = 0;
|
||||||
|
for (i = 0; i < n_crtcs; i++)
|
||||||
|
{
|
||||||
|
MetaCRTCInfo *crtc_info = crtcs[i];
|
||||||
|
MetaCRTC *crtc = crtc_info->crtc;
|
||||||
|
CoglKmsCrtc *cogl_crtc;
|
||||||
|
|
||||||
|
crtc->is_dirty = TRUE;
|
||||||
|
|
||||||
|
cogl_crtc = g_slice_new0 (CoglKmsCrtc);
|
||||||
|
g_ptr_array_add (cogl_crtcs, cogl_crtc);
|
||||||
|
|
||||||
|
if (crtc_info->mode == NULL)
|
||||||
|
{
|
||||||
|
cogl_crtc->id = crtc->crtc_id;
|
||||||
|
cogl_crtc->x = 0;
|
||||||
|
cogl_crtc->y = 0;
|
||||||
|
cogl_crtc->count = 0;
|
||||||
|
memset (&cogl_crtc->mode, 0, sizeof (drmModeModeInfo));
|
||||||
|
cogl_crtc->connectors = NULL;
|
||||||
|
cogl_crtc->count = 0;
|
||||||
|
|
||||||
|
crtc->rect.x = 0;
|
||||||
|
crtc->rect.y = 0;
|
||||||
|
crtc->rect.width = 0;
|
||||||
|
crtc->rect.height = 0;
|
||||||
|
crtc->current_mode = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MetaMonitorMode *mode;
|
||||||
|
uint32_t *outputs;
|
||||||
|
unsigned int j, n_outputs;
|
||||||
|
int width, height;
|
||||||
|
|
||||||
|
mode = crtc_info->mode;
|
||||||
|
|
||||||
|
cogl_crtc->id = crtc->crtc_id;
|
||||||
|
cogl_crtc->x = crtc_info->x;
|
||||||
|
cogl_crtc->y = crtc_info->y;
|
||||||
|
cogl_crtc->count = n_outputs = crtc_info->outputs->len;
|
||||||
|
cogl_crtc->connectors = outputs = g_new (uint32_t, n_outputs);
|
||||||
|
|
||||||
|
for (j = 0; j < n_outputs; j++)
|
||||||
|
{
|
||||||
|
MetaOutput *output = ((MetaOutput**)crtc_info->outputs->pdata)[j];
|
||||||
|
|
||||||
|
outputs[j] = output->output_id;
|
||||||
|
|
||||||
|
output->is_dirty = TRUE;
|
||||||
|
output->crtc = crtc;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (&cogl_crtc->mode, crtc_info->mode->driver_private,
|
||||||
|
sizeof (drmModeModeInfo));
|
||||||
|
|
||||||
|
if (meta_monitor_transform_is_rotated (crtc_info->transform))
|
||||||
|
{
|
||||||
|
width = mode->height;
|
||||||
|
height = mode->width;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
width = mode->width;
|
||||||
|
height = mode->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
screen_width = MAX (screen_width, crtc_info->x + width);
|
||||||
|
screen_height = MAX (screen_height, crtc_info->y + height);
|
||||||
|
|
||||||
|
crtc->rect.x = crtc_info->x;
|
||||||
|
crtc->rect.y = crtc_info->y;
|
||||||
|
crtc->rect.width = width;
|
||||||
|
crtc->rect.height = height;
|
||||||
|
crtc->current_mode = mode;
|
||||||
|
crtc->transform = crtc_info->transform;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable CRTCs not mentioned in the list */
|
||||||
|
for (i = 0; i < manager->n_crtcs; i++)
|
||||||
|
{
|
||||||
|
MetaCRTC *crtc = &manager->crtcs[i];
|
||||||
|
CoglKmsCrtc *cogl_crtc;
|
||||||
|
|
||||||
|
crtc->logical_monitor = NULL;
|
||||||
|
|
||||||
|
if (crtc->is_dirty)
|
||||||
|
{
|
||||||
|
crtc->is_dirty = FALSE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cogl_crtc = g_slice_new0 (CoglKmsCrtc);
|
||||||
|
g_ptr_array_add (cogl_crtcs, cogl_crtc);
|
||||||
|
|
||||||
|
cogl_crtc->id = crtc->crtc_id;
|
||||||
|
cogl_crtc->x = 0;
|
||||||
|
cogl_crtc->y = 0;
|
||||||
|
cogl_crtc->count = 0;
|
||||||
|
memset (&cogl_crtc->mode, 0, sizeof (drmModeModeInfo));
|
||||||
|
cogl_crtc->connectors = NULL;
|
||||||
|
cogl_crtc->count = 0;
|
||||||
|
|
||||||
|
crtc->rect.x = 0;
|
||||||
|
crtc->rect.y = 0;
|
||||||
|
crtc->rect.width = 0;
|
||||||
|
crtc->rect.height = 0;
|
||||||
|
crtc->current_mode = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
backend = clutter_get_default_backend ();
|
||||||
|
cogl_context = clutter_backend_get_cogl_context (backend);
|
||||||
|
cogl_display = cogl_context_get_display (cogl_context);
|
||||||
|
|
||||||
|
error = NULL;
|
||||||
|
ok = cogl_kms_display_set_layout (cogl_display, screen_width, screen_height,
|
||||||
|
(CoglKmsCrtc**)cogl_crtcs->pdata, cogl_crtcs->len, &error);
|
||||||
|
g_ptr_array_unref (cogl_crtcs);
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
meta_warning ("Applying display configuration failed: %s\n", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < n_outputs; i++)
|
||||||
|
{
|
||||||
|
MetaOutputInfo *output_info = outputs[i];
|
||||||
|
MetaOutput *output = output_info->output;
|
||||||
|
|
||||||
|
output->is_primary = output_info->is_primary;
|
||||||
|
output->is_presentation = output_info->is_presentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable outputs not mentioned in the list */
|
||||||
|
for (i = 0; i < manager->n_outputs; i++)
|
||||||
|
{
|
||||||
|
MetaOutput *output = &manager->outputs[i];
|
||||||
|
|
||||||
|
if (output->is_dirty)
|
||||||
|
{
|
||||||
|
output->is_dirty = FALSE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
output->crtc = NULL;
|
||||||
|
output->is_primary = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
manager->screen_width = screen_width;
|
||||||
|
manager->screen_height = screen_height;
|
||||||
|
|
||||||
|
meta_monitor_manager_rebuild_derived (manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_monitor_manager_kms_get_crtc_gamma (MetaMonitorManager *manager,
|
||||||
|
MetaCRTC *crtc,
|
||||||
|
gsize *size,
|
||||||
|
unsigned short **red,
|
||||||
|
unsigned short **green,
|
||||||
|
unsigned short **blue)
|
||||||
|
{
|
||||||
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||||
|
drmModeCrtc *kms_crtc;
|
||||||
|
|
||||||
|
kms_crtc = drmModeGetCrtc (manager_kms->fd, crtc->crtc_id);
|
||||||
|
|
||||||
|
*size = kms_crtc->gamma_size;
|
||||||
|
*red = g_new (unsigned short, *size);
|
||||||
|
*green = g_new (unsigned short, *size);
|
||||||
|
*blue = g_new (unsigned short, *size);
|
||||||
|
|
||||||
|
drmModeCrtcGetGamma (manager_kms->fd, crtc->crtc_id, *size, *red, *green, *blue);
|
||||||
|
|
||||||
|
drmModeFreeCrtc (kms_crtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager,
|
||||||
|
MetaCRTC *crtc,
|
||||||
|
gsize size,
|
||||||
|
unsigned short *red,
|
||||||
|
unsigned short *green,
|
||||||
|
unsigned short *blue)
|
||||||
|
{
|
||||||
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||||
|
|
||||||
|
drmModeCrtcSetGamma (manager_kms->fd, crtc->crtc_id, size, red, green, blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
|
||||||
|
{
|
||||||
|
ClutterBackend *backend;
|
||||||
|
CoglContext *cogl_context;
|
||||||
|
CoglDisplay *cogl_display;
|
||||||
|
CoglRenderer *cogl_renderer;
|
||||||
|
|
||||||
|
backend = clutter_get_default_backend ();
|
||||||
|
cogl_context = clutter_backend_get_cogl_context (backend);
|
||||||
|
cogl_display = cogl_context_get_display (cogl_context);
|
||||||
|
cogl_renderer = cogl_display_get_renderer (cogl_display);
|
||||||
|
|
||||||
|
manager_kms->fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_monitor_manager_kms_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object);
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for (i = 0; i < manager_kms->n_encoders; i++)
|
||||||
|
drmModeFreeEncoder (manager_kms->encoders[i]);
|
||||||
|
for (i = 0; i < manager_kms->n_connectors; i++)
|
||||||
|
drmModeFreeConnector (manager_kms->connectors[i]);
|
||||||
|
|
||||||
|
g_free (manager_kms->encoders);
|
||||||
|
g_free (manager_kms->connectors);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
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->finalize = meta_monitor_manager_kms_finalize;
|
||||||
|
|
||||||
|
manager_class->read_current = meta_monitor_manager_kms_read_current;
|
||||||
|
manager_class->read_edid = meta_monitor_manager_kms_read_edid;
|
||||||
|
manager_class->apply_configuration = meta_monitor_manager_kms_apply_configuration;
|
||||||
|
manager_class->set_power_save_mode = meta_monitor_manager_kms_set_power_save_mode;
|
||||||
|
manager_class->get_crtc_gamma = meta_monitor_manager_kms_get_crtc_gamma;
|
||||||
|
manager_class->set_crtc_gamma = meta_monitor_manager_kms_set_crtc_gamma;
|
||||||
|
}
|
||||||
|
|
@@ -116,6 +116,9 @@ struct _MetaOutput
|
|||||||
*/
|
*/
|
||||||
gboolean is_primary;
|
gboolean is_primary;
|
||||||
gboolean is_presentation;
|
gboolean is_presentation;
|
||||||
|
|
||||||
|
gpointer driver_private;
|
||||||
|
GDestroyNotify driver_notify;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _MetaCRTC
|
struct _MetaCRTC
|
||||||
@@ -139,10 +142,14 @@ struct _MetaMonitorMode
|
|||||||
{
|
{
|
||||||
/* The low-level ID of this mode, used to apply back configuration */
|
/* The low-level ID of this mode, used to apply back configuration */
|
||||||
glong mode_id;
|
glong mode_id;
|
||||||
|
char *name;
|
||||||
|
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
float refresh_rate;
|
float refresh_rate;
|
||||||
|
|
||||||
|
gpointer driver_private;
|
||||||
|
GDestroyNotify driver_notify;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -351,6 +358,18 @@ typedef struct _MetaMonitorManagerXrandr MetaMonitorManagerXrandr;
|
|||||||
|
|
||||||
GType meta_monitor_manager_xrandr_get_type (void);
|
GType meta_monitor_manager_xrandr_get_type (void);
|
||||||
|
|
||||||
|
#define META_TYPE_MONITOR_MANAGER_KMS (meta_monitor_manager_kms_get_type ())
|
||||||
|
#define META_MONITOR_MANAGER_KMS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKms))
|
||||||
|
#define META_MONITOR_MANAGER_KMS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKmsClass))
|
||||||
|
#define META_IS_MONITOR_MANAGER_KMS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_KMS))
|
||||||
|
#define META_IS_MONITOR_MANAGER_KMS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_KMS))
|
||||||
|
#define META_MONITOR_MANAGER_KMS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKmsClass))
|
||||||
|
|
||||||
|
typedef struct _MetaMonitorManagerKmsClass MetaMonitorManagerKmsClass;
|
||||||
|
typedef struct _MetaMonitorManagerKms MetaMonitorManagerKms;
|
||||||
|
|
||||||
|
GType meta_monitor_manager_kms_get_type (void);
|
||||||
|
|
||||||
#define META_TYPE_MONITOR_CONFIG (meta_monitor_config_get_type ())
|
#define META_TYPE_MONITOR_CONFIG (meta_monitor_config_get_type ())
|
||||||
#define META_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfig))
|
#define META_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfig))
|
||||||
#define META_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass))
|
#define META_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass))
|
||||||
@@ -383,6 +402,8 @@ void meta_output_info_free (MetaOutputInfo *info);
|
|||||||
|
|
||||||
void meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
|
void meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
|
||||||
int n_old_outputs);
|
int n_old_outputs);
|
||||||
|
void meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
|
||||||
|
int n_old_modes);
|
||||||
|
|
||||||
/* Returns true if transform causes width and height to be inverted
|
/* Returns true if transform causes width and height to be inverted
|
||||||
This is true for the odd transforms in the enum */
|
This is true for the odd transforms in the enum */
|
||||||
|
@@ -977,7 +977,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager,
|
|||||||
MetaOutput *old_outputs;
|
MetaOutput *old_outputs;
|
||||||
MetaCRTC *old_crtcs;
|
MetaCRTC *old_crtcs;
|
||||||
MetaMonitorMode *old_modes;
|
MetaMonitorMode *old_modes;
|
||||||
int n_old_outputs;
|
unsigned int n_old_outputs, n_old_modes;
|
||||||
|
|
||||||
if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
|
if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -988,6 +988,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager,
|
|||||||
old_outputs = manager->outputs;
|
old_outputs = manager->outputs;
|
||||||
n_old_outputs = manager->n_outputs;
|
n_old_outputs = manager->n_outputs;
|
||||||
old_modes = manager->modes;
|
old_modes = manager->modes;
|
||||||
|
n_old_modes = manager->n_modes;
|
||||||
old_crtcs = manager->crtcs;
|
old_crtcs = manager->crtcs;
|
||||||
|
|
||||||
manager->serial++;
|
manager->serial++;
|
||||||
@@ -1022,7 +1023,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager,
|
|||||||
}
|
}
|
||||||
|
|
||||||
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
|
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
|
||||||
g_free (old_modes);
|
meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
|
||||||
g_free (old_crtcs);
|
g_free (old_crtcs);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@@ -36,6 +36,7 @@
|
|||||||
#include <meta/util.h>
|
#include <meta/util.h>
|
||||||
#include <meta/errors.h>
|
#include <meta/errors.h>
|
||||||
#include "monitor-private.h"
|
#include "monitor-private.h"
|
||||||
|
#include "meta-wayland-private.h"
|
||||||
|
|
||||||
#include "meta-dbus-xrandr.h"
|
#include "meta-dbus-xrandr.h"
|
||||||
|
|
||||||
@@ -358,7 +359,16 @@ static GType
|
|||||||
get_default_backend (void)
|
get_default_backend (void)
|
||||||
{
|
{
|
||||||
if (meta_is_wayland_compositor ())
|
if (meta_is_wayland_compositor ())
|
||||||
return META_TYPE_MONITOR_MANAGER; /* FIXME: KMS */
|
{
|
||||||
|
MetaWaylandCompositor *compositor;
|
||||||
|
|
||||||
|
compositor = meta_wayland_compositor_get_default ();
|
||||||
|
|
||||||
|
if (meta_wayland_compositor_is_native (compositor))
|
||||||
|
return META_TYPE_MONITOR_MANAGER_KMS;
|
||||||
|
else
|
||||||
|
return META_TYPE_MONITOR_MANAGER;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return META_TYPE_MONITOR_MANAGER_XRANDR;
|
return META_TYPE_MONITOR_MANAGER_XRANDR;
|
||||||
}
|
}
|
||||||
@@ -407,17 +417,18 @@ meta_monitor_manager_constructed (GObject *object)
|
|||||||
MetaOutput *old_outputs;
|
MetaOutput *old_outputs;
|
||||||
MetaCRTC *old_crtcs;
|
MetaCRTC *old_crtcs;
|
||||||
MetaMonitorMode *old_modes;
|
MetaMonitorMode *old_modes;
|
||||||
int n_old_outputs;
|
unsigned int n_old_outputs, n_old_modes;
|
||||||
|
|
||||||
old_outputs = manager->outputs;
|
old_outputs = manager->outputs;
|
||||||
n_old_outputs = manager->n_outputs;
|
n_old_outputs = manager->n_outputs;
|
||||||
old_modes = manager->modes;
|
old_modes = manager->modes;
|
||||||
|
n_old_modes = manager->n_modes;
|
||||||
old_crtcs = manager->crtcs;
|
old_crtcs = manager->crtcs;
|
||||||
|
|
||||||
read_current_config (manager);
|
read_current_config (manager);
|
||||||
|
|
||||||
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
|
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
|
||||||
g_free (old_modes);
|
meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
|
||||||
g_free (old_crtcs);
|
g_free (old_crtcs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,19 +473,39 @@ meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
|
|||||||
g_free (old_outputs[i].modes);
|
g_free (old_outputs[i].modes);
|
||||||
g_free (old_outputs[i].possible_crtcs);
|
g_free (old_outputs[i].possible_crtcs);
|
||||||
g_free (old_outputs[i].possible_clones);
|
g_free (old_outputs[i].possible_clones);
|
||||||
|
|
||||||
|
if (old_outputs[i].driver_notify)
|
||||||
|
old_outputs[i].driver_notify (&old_outputs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free (old_outputs);
|
g_free (old_outputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
|
||||||
|
int n_old_modes)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < n_old_modes; i++)
|
||||||
|
{
|
||||||
|
g_free (old_modes[i].name);
|
||||||
|
|
||||||
|
if (old_modes[i].driver_notify)
|
||||||
|
old_modes[i].driver_notify (&old_modes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (old_modes);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
meta_monitor_manager_finalize (GObject *object)
|
meta_monitor_manager_finalize (GObject *object)
|
||||||
{
|
{
|
||||||
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
|
||||||
|
|
||||||
meta_monitor_manager_free_output_array (manager->outputs, manager->n_outputs);
|
meta_monitor_manager_free_output_array (manager->outputs, manager->n_outputs);
|
||||||
|
meta_monitor_manager_free_mode_array (manager->modes, manager->n_modes);
|
||||||
g_free (manager->monitor_infos);
|
g_free (manager->monitor_infos);
|
||||||
g_free (manager->modes);
|
|
||||||
g_free (manager->crtcs);
|
g_free (manager->crtcs);
|
||||||
|
|
||||||
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object);
|
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object);
|
||||||
|
@@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <meta/util.h>
|
||||||
|
#include <meta/main.h>
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
|
|
||||||
@@ -531,6 +533,12 @@ die_callback (SmcConn smc_conn, SmPointer client_data)
|
|||||||
* Anything that wants us to go away outside of session management
|
* Anything that wants us to go away outside of session management
|
||||||
* can use kill().
|
* can use kill().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* All of that is true - unless we're a wayland compositor. In which
|
||||||
|
* case the X server won't go down until we do, so we must die first.
|
||||||
|
*/
|
||||||
|
if (meta_is_wayland_compositor ())
|
||||||
|
meta_quit (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@@ -44,6 +44,7 @@
|
|||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||||
|
#include <clutter/clutter.h>
|
||||||
#include "meta-wayland-types.h"
|
#include "meta-wayland-types.h"
|
||||||
|
|
||||||
typedef struct _MetaWindowQueue MetaWindowQueue;
|
typedef struct _MetaWindowQueue MetaWindowQueue;
|
||||||
@@ -127,6 +128,7 @@ struct _MetaWindow
|
|||||||
Window xtransient_for;
|
Window xtransient_for;
|
||||||
Window xgroup_leader;
|
Window xgroup_leader;
|
||||||
Window xclient_leader;
|
Window xclient_leader;
|
||||||
|
MetaWindow *transient_for;
|
||||||
|
|
||||||
/* Initial workspace property */
|
/* Initial workspace property */
|
||||||
int initial_workspace;
|
int initial_workspace;
|
||||||
@@ -403,6 +405,12 @@ struct _MetaWindow
|
|||||||
*/
|
*/
|
||||||
MetaRectangle rect;
|
MetaRectangle rect;
|
||||||
|
|
||||||
|
/* The size we want the window to be (i.e. what we last asked
|
||||||
|
* the client to configure).
|
||||||
|
* This is only used for wayland clients.
|
||||||
|
*/
|
||||||
|
MetaRectangle expected_rect;
|
||||||
|
|
||||||
gboolean has_custom_frame_extents;
|
gboolean has_custom_frame_extents;
|
||||||
GtkBorder custom_frame_extents;
|
GtkBorder custom_frame_extents;
|
||||||
|
|
||||||
@@ -600,6 +608,11 @@ void meta_window_move_resize_request(MetaWindow *window,
|
|||||||
int y,
|
int y,
|
||||||
int width,
|
int width,
|
||||||
int height);
|
int height);
|
||||||
|
void meta_window_move_resize_wayland (MetaWindow *window,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int dx,
|
||||||
|
int dy);
|
||||||
gboolean meta_window_configure_request (MetaWindow *window,
|
gboolean meta_window_configure_request (MetaWindow *window,
|
||||||
XEvent *event);
|
XEvent *event);
|
||||||
gboolean meta_window_property_notify (MetaWindow *window,
|
gboolean meta_window_property_notify (MetaWindow *window,
|
||||||
@@ -631,7 +644,7 @@ void meta_window_update_sync_request_counter (MetaWindow *window,
|
|||||||
#endif /* HAVE_XSYNC */
|
#endif /* HAVE_XSYNC */
|
||||||
|
|
||||||
void meta_window_handle_mouse_grab_op_event (MetaWindow *window,
|
void meta_window_handle_mouse_grab_op_event (MetaWindow *window,
|
||||||
XIDeviceEvent *xev);
|
const ClutterEvent *event);
|
||||||
|
|
||||||
GList* meta_window_get_workspaces (MetaWindow *window);
|
GList* meta_window_get_workspaces (MetaWindow *window);
|
||||||
|
|
||||||
@@ -716,4 +729,7 @@ void meta_window_set_gtk_dbus_properties (MetaWindow *window,
|
|||||||
const char *application_object_path,
|
const char *application_object_path,
|
||||||
const char *window_object_path);
|
const char *window_object_path);
|
||||||
|
|
||||||
|
void meta_window_set_transient_for (MetaWindow *window,
|
||||||
|
MetaWindow *parent);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1554,9 +1554,6 @@ reload_transient_for (MetaWindow *window,
|
|||||||
if (transient_for == window->xtransient_for)
|
if (transient_for == window->xtransient_for)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (meta_window_appears_focused (window) && window->xtransient_for != None)
|
|
||||||
meta_window_propagate_focus_appearance (window, FALSE);
|
|
||||||
|
|
||||||
old_transient_for = window->xtransient_for;
|
old_transient_for = window->xtransient_for;
|
||||||
window->xtransient_for = transient_for;
|
window->xtransient_for = transient_for;
|
||||||
|
|
||||||
@@ -1569,48 +1566,16 @@ reload_transient_for (MetaWindow *window,
|
|||||||
else
|
else
|
||||||
meta_verbose ("Window %s is not transient\n", window->desc);
|
meta_verbose ("Window %s is not transient\n", window->desc);
|
||||||
|
|
||||||
/* may now be a dialog */
|
if (window->transient_parent_is_root_window || window->xtransient_for == None)
|
||||||
meta_window_recalc_window_type (window);
|
meta_window_set_transient_for (window, NULL);
|
||||||
|
else
|
||||||
if (!window->constructing)
|
|
||||||
{
|
{
|
||||||
/* If the window attaches, detaches, or changes attached
|
parent = meta_display_lookup_x_window (window->display,
|
||||||
* parents, we need to destroy the MetaWindow and let a new one
|
window->xtransient_for);
|
||||||
* be created (which happens as a side effect of
|
meta_window_set_transient_for (window, parent);
|
||||||
* meta_window_unmanage()). The condition below is correct
|
|
||||||
* because we know window->xtransient_for has changed.
|
|
||||||
*/
|
|
||||||
if (window->attached || meta_window_should_attach_to_parent (window))
|
|
||||||
{
|
|
||||||
guint32 timestamp;
|
|
||||||
|
|
||||||
window->xtransient_for = old_transient_for;
|
|
||||||
timestamp = meta_display_get_current_time_roundtrip (window->display);
|
|
||||||
meta_window_unmanage (window, timestamp);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update stacking constraints */
|
|
||||||
if (!window->override_redirect)
|
|
||||||
meta_stack_update_transient (window->screen->stack, window);
|
|
||||||
|
|
||||||
/* possibly change its group. We treat being a window's transient as
|
|
||||||
* equivalent to making it your group leader, to work around shortcomings
|
|
||||||
* in programs such as xmms-- see #328211.
|
|
||||||
*/
|
|
||||||
if (window->xtransient_for != None &&
|
|
||||||
window->xgroup_leader != None &&
|
|
||||||
window->xtransient_for != window->xgroup_leader)
|
|
||||||
meta_window_group_leader_changed (window);
|
|
||||||
|
|
||||||
if (!window->constructing && !window->override_redirect)
|
|
||||||
meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
|
|
||||||
|
|
||||||
if (meta_window_appears_focused (window) && window->xtransient_for != None)
|
|
||||||
meta_window_propagate_focus_appearance (window, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
reload_gtk_theme_variant (MetaWindow *window,
|
reload_gtk_theme_variant (MetaWindow *window,
|
||||||
MetaPropValue *value,
|
MetaPropValue *value,
|
||||||
|
@@ -63,6 +63,7 @@
|
|||||||
#include <X11/extensions/Xcomposite.h>
|
#include <X11/extensions/Xcomposite.h>
|
||||||
|
|
||||||
#include "meta-wayland-private.h"
|
#include "meta-wayland-private.h"
|
||||||
|
#include "meta/compositor-mutter.h"
|
||||||
|
|
||||||
/* Windows that unmaximize to a size bigger than that fraction of the workarea
|
/* Windows that unmaximize to a size bigger than that fraction of the workarea
|
||||||
* will be scaled down to that size (while maintaining aspect ratio).
|
* will be scaled down to that size (while maintaining aspect ratio).
|
||||||
@@ -239,6 +240,9 @@ meta_window_finalize (GObject *object)
|
|||||||
if (window->opaque_region)
|
if (window->opaque_region)
|
||||||
cairo_region_destroy (window->opaque_region);
|
cairo_region_destroy (window->opaque_region);
|
||||||
|
|
||||||
|
if (window->transient_for)
|
||||||
|
g_object_unref (window->transient_for);
|
||||||
|
|
||||||
meta_icon_cache_free (&window->icon_cache);
|
meta_icon_cache_free (&window->icon_cache);
|
||||||
|
|
||||||
g_free (window->sm_client_id);
|
g_free (window->sm_client_id);
|
||||||
@@ -1114,11 +1118,6 @@ meta_window_new_shared (MetaDisplay *display,
|
|||||||
* can use this time as a fallback.
|
* can use this time as a fallback.
|
||||||
*/
|
*/
|
||||||
if (!window->override_redirect && !window->net_wm_user_time_set) {
|
if (!window->override_redirect && !window->net_wm_user_time_set) {
|
||||||
MetaWindow *parent = NULL;
|
|
||||||
if (window->xtransient_for)
|
|
||||||
parent = meta_display_lookup_x_window (window->display,
|
|
||||||
window->xtransient_for);
|
|
||||||
|
|
||||||
/* First, maybe the app was launched with startup notification using an
|
/* First, maybe the app was launched with startup notification using an
|
||||||
* obsolete version of the spec; use that timestamp if it exists.
|
* obsolete version of the spec; use that timestamp if it exists.
|
||||||
*/
|
*/
|
||||||
@@ -1127,8 +1126,8 @@ meta_window_new_shared (MetaDisplay *display,
|
|||||||
* being recorded as a fallback for potential transients
|
* being recorded as a fallback for potential transients
|
||||||
*/
|
*/
|
||||||
window->net_wm_user_time = window->initial_timestamp;
|
window->net_wm_user_time = window->initial_timestamp;
|
||||||
else if (parent != NULL)
|
else if (window->transient_for != NULL)
|
||||||
meta_window_set_user_time(window, parent->net_wm_user_time);
|
meta_window_set_user_time(window, window->transient_for->net_wm_user_time);
|
||||||
else
|
else
|
||||||
/* NOTE: Do NOT toggle net_wm_user_time_set to true; this is just
|
/* NOTE: Do NOT toggle net_wm_user_time_set to true; this is just
|
||||||
* being recorded as a fallback for potential transients
|
* being recorded as a fallback for potential transients
|
||||||
@@ -1218,21 +1217,16 @@ meta_window_new_shared (MetaDisplay *display,
|
|||||||
if (!window->override_redirect)
|
if (!window->override_redirect)
|
||||||
{
|
{
|
||||||
if (window->workspace == NULL &&
|
if (window->workspace == NULL &&
|
||||||
window->xtransient_for != None)
|
window->transient_for != NULL)
|
||||||
{
|
{
|
||||||
/* Try putting dialog on parent's workspace */
|
/* Try putting dialog on parent's workspace */
|
||||||
MetaWindow *parent;
|
if (window->transient_for->workspace)
|
||||||
|
|
||||||
parent = meta_display_lookup_x_window (window->display,
|
|
||||||
window->xtransient_for);
|
|
||||||
|
|
||||||
if (parent && parent->workspace)
|
|
||||||
{
|
{
|
||||||
meta_topic (META_DEBUG_PLACEMENT,
|
meta_topic (META_DEBUG_PLACEMENT,
|
||||||
"Putting window %s on same workspace as parent %s\n",
|
"Putting window %s on same workspace as parent %s\n",
|
||||||
window->desc, parent->desc);
|
window->desc, window->transient_for->desc);
|
||||||
|
|
||||||
if (parent->on_all_workspaces_requested)
|
if (window->transient_for->on_all_workspaces_requested)
|
||||||
{
|
{
|
||||||
window->on_all_workspaces_requested = TRUE;
|
window->on_all_workspaces_requested = TRUE;
|
||||||
window->on_all_workspaces = TRUE;
|
window->on_all_workspaces = TRUE;
|
||||||
@@ -1240,7 +1234,7 @@ meta_window_new_shared (MetaDisplay *display,
|
|||||||
|
|
||||||
/* this will implicitly add to the appropriate MRU lists
|
/* this will implicitly add to the appropriate MRU lists
|
||||||
*/
|
*/
|
||||||
meta_workspace_add_window (parent->workspace, window);
|
meta_workspace_add_window (window->transient_for->workspace, window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4456,14 +4450,14 @@ window_activate (MetaWindow *window,
|
|||||||
/* For non-transient windows, we just set up a pulsing indicator,
|
/* For non-transient windows, we just set up a pulsing indicator,
|
||||||
rather than move windows or workspaces.
|
rather than move windows or workspaces.
|
||||||
See http://bugzilla.gnome.org/show_bug.cgi?id=482354 */
|
See http://bugzilla.gnome.org/show_bug.cgi?id=482354 */
|
||||||
if (window->xtransient_for == None &&
|
if (window->transient_for == NULL &&
|
||||||
!meta_window_located_on_workspace (window, workspace))
|
!meta_window_located_on_workspace (window, workspace))
|
||||||
{
|
{
|
||||||
meta_window_set_demands_attention (window);
|
meta_window_set_demands_attention (window);
|
||||||
/* We've marked it as demanding, don't need to do anything else. */
|
/* We've marked it as demanding, don't need to do anything else. */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (window->xtransient_for != None)
|
else if (window->transient_for != NULL)
|
||||||
{
|
{
|
||||||
/* Move transients to current workspace - preference dialogs should appear over
|
/* Move transients to current workspace - preference dialogs should appear over
|
||||||
the source window. */
|
the source window. */
|
||||||
@@ -5001,6 +4995,7 @@ meta_window_move_resize_internal (MetaWindow *window,
|
|||||||
* 2 | A not-resize-only ConfigureRequest/net_moveresize_window request
|
* 2 | A not-resize-only ConfigureRequest/net_moveresize_window request
|
||||||
* 3 | meta_window_move
|
* 3 | meta_window_move
|
||||||
* 3 | meta_window_move_resize
|
* 3 | meta_window_move_resize
|
||||||
|
* 4 | meta_window_move_resize_wayland
|
||||||
*
|
*
|
||||||
* For each of the cases, root_x_nw and root_y_nw must be treated as follows:
|
* For each of the cases, root_x_nw and root_y_nw must be treated as follows:
|
||||||
*
|
*
|
||||||
@@ -5011,8 +5006,12 @@ meta_window_move_resize_internal (MetaWindow *window,
|
|||||||
* coordinates are relative to some corner or side of the outer
|
* coordinates are relative to some corner or side of the outer
|
||||||
* window (except for the case of StaticGravity) and we want to
|
* window (except for the case of StaticGravity) and we want to
|
||||||
* know the location of the upper left corner of the inner window.
|
* know the location of the upper left corner of the inner window.
|
||||||
* (3) These values are already the desired positon of the NW corner
|
* (3) These values are already the desired position of the NW corner
|
||||||
* of the inner window
|
* of the inner window
|
||||||
|
* (4) These values are already the desired position of the NW corner
|
||||||
|
* of the inner window (which is also the outer window, because
|
||||||
|
* we don't decorate wayland clients), and the client has acknowledged
|
||||||
|
* the window size change.
|
||||||
*/
|
*/
|
||||||
XWindowChanges values;
|
XWindowChanges values;
|
||||||
unsigned int mask;
|
unsigned int mask;
|
||||||
@@ -5028,6 +5027,7 @@ meta_window_move_resize_internal (MetaWindow *window,
|
|||||||
gboolean is_configure_request;
|
gboolean is_configure_request;
|
||||||
gboolean do_gravity_adjust;
|
gboolean do_gravity_adjust;
|
||||||
gboolean is_user_action;
|
gboolean is_user_action;
|
||||||
|
gboolean is_wayland_resize;
|
||||||
gboolean did_placement;
|
gboolean did_placement;
|
||||||
gboolean configure_frame_first;
|
gboolean configure_frame_first;
|
||||||
gboolean use_static_gravity;
|
gboolean use_static_gravity;
|
||||||
@@ -5044,9 +5044,12 @@ meta_window_move_resize_internal (MetaWindow *window,
|
|||||||
is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0;
|
is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0;
|
||||||
do_gravity_adjust = (flags & META_DO_GRAVITY_ADJUST) != 0;
|
do_gravity_adjust = (flags & META_DO_GRAVITY_ADJUST) != 0;
|
||||||
is_user_action = (flags & META_IS_USER_ACTION) != 0;
|
is_user_action = (flags & META_IS_USER_ACTION) != 0;
|
||||||
|
is_wayland_resize = (flags & META_IS_WAYLAND_RESIZE) != 0;
|
||||||
|
|
||||||
/* The action has to be a move or a resize or both... */
|
/* The action has to be a move, a resize or the wayland client
|
||||||
g_assert (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION));
|
* acking our choice of size.
|
||||||
|
*/
|
||||||
|
g_assert (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION | META_IS_WAYLAND_RESIZE));
|
||||||
|
|
||||||
/* We don't need it in the idle queue anymore. */
|
/* We don't need it in the idle queue anymore. */
|
||||||
meta_window_unqueue (window, META_QUEUE_MOVE_RESIZE);
|
meta_window_unqueue (window, META_QUEUE_MOVE_RESIZE);
|
||||||
@@ -5104,18 +5107,112 @@ meta_window_move_resize_internal (MetaWindow *window,
|
|||||||
|
|
||||||
did_placement = !window->placed && window->calc_placement;
|
did_placement = !window->placed && window->calc_placement;
|
||||||
|
|
||||||
|
if (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION))
|
||||||
|
{
|
||||||
meta_window_constrain (window,
|
meta_window_constrain (window,
|
||||||
window->frame ? &borders : NULL,
|
window->frame ? &borders : NULL,
|
||||||
flags,
|
flags,
|
||||||
gravity,
|
gravity,
|
||||||
&old_rect,
|
&old_rect,
|
||||||
&new_rect);
|
&new_rect);
|
||||||
|
}
|
||||||
|
|
||||||
w = new_rect.width;
|
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
|
||||||
h = new_rect.height;
|
{
|
||||||
|
g_assert (window->frame == NULL);
|
||||||
|
|
||||||
|
/* For wayland clients, the size is completely determined by the client,
|
||||||
|
* and while this allows to avoid some trickery with frames and the resulting
|
||||||
|
* lagging, we also need to insist a bit when the constraints would apply
|
||||||
|
* a different size than the client decides.
|
||||||
|
*
|
||||||
|
* Note that this is not generally a problem for normal toplevel windows (the
|
||||||
|
* constraints don't see the size hints, or just change the position), but
|
||||||
|
* it can be for maximized or fullscreen.
|
||||||
|
*
|
||||||
|
*/
|
||||||
root_x_nw = new_rect.x;
|
root_x_nw = new_rect.x;
|
||||||
root_y_nw = new_rect.y;
|
root_y_nw = new_rect.y;
|
||||||
|
|
||||||
|
/* First, save where we would like the client to be. This is used by the next
|
||||||
|
* attach to determine if the client is really moving/resizing or not.
|
||||||
|
*/
|
||||||
|
window->expected_rect = new_rect;
|
||||||
|
|
||||||
|
if (is_wayland_resize)
|
||||||
|
{
|
||||||
|
/* This is a call to wl_surface_commit(), ignore the new_rect and
|
||||||
|
* update the real client size to match the buffer size.
|
||||||
|
*/
|
||||||
|
|
||||||
|
window->rect.width = w;
|
||||||
|
window->rect.height = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_rect.width != window->rect.width ||
|
||||||
|
new_rect.height != window->rect.height)
|
||||||
|
{
|
||||||
|
/* We need to resize the client. Resizing is in two parts:
|
||||||
|
* some of the movement happens immediately, and some happens as part
|
||||||
|
* of the resizing (through dx/dy in wl_surface_attach).
|
||||||
|
*
|
||||||
|
* To do so, we need to compute the resize from the point of the view
|
||||||
|
* of the client, and then adjust the immediate resize to match.
|
||||||
|
*
|
||||||
|
* dx/dy are the values we expect from the new attach(), while deltax/
|
||||||
|
* deltay reflect the overall movement.
|
||||||
|
*/
|
||||||
|
MetaRectangle client_rect;
|
||||||
|
int dx, dy;
|
||||||
|
int deltax, deltay;
|
||||||
|
|
||||||
|
meta_rectangle_resize_with_gravity (&old_rect,
|
||||||
|
&client_rect,
|
||||||
|
gravity,
|
||||||
|
new_rect.width,
|
||||||
|
new_rect.height);
|
||||||
|
|
||||||
|
deltax = new_rect.x - old_rect.x;
|
||||||
|
deltay = new_rect.y - old_rect.y;
|
||||||
|
dx = client_rect.x - old_rect.x;
|
||||||
|
dy = client_rect.y - old_rect.y;
|
||||||
|
|
||||||
|
if ((deltax - dx) != 0 ||
|
||||||
|
(deltay - dy) != 0)
|
||||||
|
need_move_client = TRUE;
|
||||||
|
|
||||||
|
window->rect.x += (deltax - dx);
|
||||||
|
window->rect.y += (deltay - dy);
|
||||||
|
|
||||||
|
need_resize_client = TRUE;
|
||||||
|
meta_wayland_surface_configure_notify (window->surface,
|
||||||
|
new_rect.width,
|
||||||
|
new_rect.height,
|
||||||
|
(dx != 0 ? WL_SHELL_SURFACE_RESIZE_LEFT : 0) |
|
||||||
|
(dy != 0 ? WL_SHELL_SURFACE_RESIZE_TOP : 0));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* No resize happening, we can just move the window and live with it. */
|
||||||
|
if (window->rect.x != new_rect.x ||
|
||||||
|
window->rect.y != new_rect.y)
|
||||||
|
need_move_client = TRUE;
|
||||||
|
|
||||||
|
window->rect.x = new_rect.x;
|
||||||
|
window->rect.y = new_rect.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Everything else is the old X11 code, including weird gravities,
|
||||||
|
* the interaction with frames and the synthetic configure notifies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
root_x_nw = new_rect.x;
|
||||||
|
root_y_nw = new_rect.y;
|
||||||
|
w = new_rect.width;
|
||||||
|
h = new_rect.height;
|
||||||
|
|
||||||
if (w != window->rect.width ||
|
if (w != window->rect.width ||
|
||||||
h != window->rect.height)
|
h != window->rect.height)
|
||||||
need_resize_client = TRUE;
|
need_resize_client = TRUE;
|
||||||
@@ -5407,6 +5504,7 @@ meta_window_move_resize_internal (MetaWindow *window,
|
|||||||
|
|
||||||
if (need_configure_notify)
|
if (need_configure_notify)
|
||||||
send_configure_notify (window);
|
send_configure_notify (window);
|
||||||
|
}
|
||||||
|
|
||||||
if (!window->placed && window->force_save_user_rect && !window->fullscreen)
|
if (!window->placed && window->force_save_user_rect && !window->fullscreen)
|
||||||
force_save_user_window_placement (window);
|
force_save_user_window_placement (window);
|
||||||
@@ -5415,7 +5513,7 @@ meta_window_move_resize_internal (MetaWindow *window,
|
|||||||
|
|
||||||
if (need_move_frame || need_resize_frame ||
|
if (need_move_frame || need_resize_frame ||
|
||||||
need_move_client || need_resize_client ||
|
need_move_client || need_resize_client ||
|
||||||
did_placement)
|
did_placement || is_wayland_resize)
|
||||||
{
|
{
|
||||||
int newx, newy;
|
int newx, newy;
|
||||||
meta_window_get_position (window, &newx, &newy);
|
meta_window_get_position (window, &newx, &newy);
|
||||||
@@ -5485,6 +5583,37 @@ meta_window_resize (MetaWindow *window,
|
|||||||
x, y, w, h);
|
x, y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* meta_window_move_resize_wayland:
|
||||||
|
*
|
||||||
|
* Complete a resize operation from a wayland client.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
meta_window_move_resize_wayland (MetaWindow *window,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int dx,
|
||||||
|
int dy)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
MetaMoveResizeFlags flags;
|
||||||
|
|
||||||
|
flags = META_IS_WAYLAND_RESIZE;
|
||||||
|
|
||||||
|
meta_window_get_position (window, &x, &y);
|
||||||
|
x += dx; y += dy;
|
||||||
|
|
||||||
|
if (x != window->expected_rect.x || y != window->expected_rect.y)
|
||||||
|
flags |= META_IS_MOVE_ACTION;
|
||||||
|
if (width != window->expected_rect.width ||
|
||||||
|
height != window->expected_rect.height)
|
||||||
|
flags |= META_IS_RESIZE_ACTION;
|
||||||
|
|
||||||
|
meta_window_move_resize_internal (window, flags, NorthWestGravity,
|
||||||
|
x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* meta_window_move:
|
* meta_window_move:
|
||||||
* @window: a #MetaWindow
|
* @window: a #MetaWindow
|
||||||
@@ -5995,7 +6124,7 @@ get_modal_transient (MetaWindow *window)
|
|||||||
{
|
{
|
||||||
MetaWindow *transient = tmp->data;
|
MetaWindow *transient = tmp->data;
|
||||||
|
|
||||||
if (transient->xtransient_for == modal_transient->xwindow &&
|
if (transient->transient_for == modal_transient &&
|
||||||
transient->wm_state_modal)
|
transient->wm_state_modal)
|
||||||
{
|
{
|
||||||
modal_transient = transient;
|
modal_transient = transient;
|
||||||
@@ -8365,7 +8494,7 @@ recalc_window_type (MetaWindow *window)
|
|||||||
XFree (atom_name);
|
XFree (atom_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (window->xtransient_for != None)
|
else if (window->transient_for != NULL)
|
||||||
{
|
{
|
||||||
window->type = META_WINDOW_DIALOG;
|
window->type = META_WINDOW_DIALOG;
|
||||||
}
|
}
|
||||||
@@ -8708,8 +8837,7 @@ recalc_window_features (MetaWindow *window)
|
|||||||
case META_WINDOW_MODAL_DIALOG:
|
case META_WINDOW_MODAL_DIALOG:
|
||||||
/* only skip taskbar if we have a real transient parent
|
/* only skip taskbar if we have a real transient parent
|
||||||
(and ignore the application hints) */
|
(and ignore the application hints) */
|
||||||
if (window->xtransient_for != None &&
|
if (window->transient_for != NULL)
|
||||||
window->xtransient_for != window->screen->xroot)
|
|
||||||
window->skip_taskbar = TRUE;
|
window->skip_taskbar = TRUE;
|
||||||
else
|
else
|
||||||
window->skip_taskbar = FALSE;
|
window->skip_taskbar = FALSE;
|
||||||
@@ -9765,97 +9893,21 @@ update_resize (MetaWindow *window,
|
|||||||
g_get_current_time (&window->display->grab_last_moveresize_time);
|
g_get_current_time (&window->display->grab_last_moveresize_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
Window window;
|
|
||||||
int count;
|
|
||||||
guint32 last_time;
|
|
||||||
} EventScannerData;
|
|
||||||
|
|
||||||
static Bool
|
|
||||||
find_last_time_predicate (Display *display,
|
|
||||||
XEvent *ev,
|
|
||||||
XPointer arg)
|
|
||||||
{
|
|
||||||
EventScannerData *esd = (void*) arg;
|
|
||||||
XIEvent *xev;
|
|
||||||
|
|
||||||
if (ev->type != GenericEvent)
|
|
||||||
return False;
|
|
||||||
|
|
||||||
/* We are peeking into events not yet handled by GDK,
|
|
||||||
* Allocate cookie events here so we can handle XI2.
|
|
||||||
*
|
|
||||||
* GDK will handle later these events, and eventually
|
|
||||||
* free the cookie data itself.
|
|
||||||
*/
|
|
||||||
XGetEventData (display, &ev->xcookie);
|
|
||||||
xev = (XIEvent *) ev->xcookie.data;
|
|
||||||
|
|
||||||
if (xev->evtype != XI_Motion)
|
|
||||||
return False;
|
|
||||||
|
|
||||||
if (esd->window != ((XIDeviceEvent *) xev)->event)
|
|
||||||
return False;
|
|
||||||
|
|
||||||
esd->count += 1;
|
|
||||||
esd->last_time = xev->time;
|
|
||||||
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
check_use_this_motion_notify (MetaWindow *window,
|
check_use_this_motion_notify (MetaWindow *window,
|
||||||
XIDeviceEvent *xev)
|
const ClutterEvent *event)
|
||||||
{
|
{
|
||||||
EventScannerData esd;
|
/* XXX: Previously this code would walk through the X event queue
|
||||||
XEvent useless;
|
and filter out motion events that are followed by a later motion
|
||||||
|
event. There currently isn't any API to do the equivalent
|
||||||
/* This code is copied from Owen's GDK code. */
|
procedure with the Clutter event queue so this function does
|
||||||
|
nothing. Clutter does its own motion event squashing so it may be
|
||||||
if (window->display->grab_motion_notify_time != 0)
|
the case that this function isn't necessary. If it turns out that
|
||||||
{
|
we do need additional motion event squashing we could add some
|
||||||
/* == is really the right test, but I'm all for paranoia */
|
extra API to the Clutter event queue and implement this function
|
||||||
if (window->display->grab_motion_notify_time <=
|
properly. */
|
||||||
xev->time)
|
|
||||||
{
|
|
||||||
meta_topic (META_DEBUG_RESIZING,
|
|
||||||
"Arrived at event with time %u (waiting for %u), using it\n",
|
|
||||||
(unsigned int)xev->time,
|
|
||||||
window->display->grab_motion_notify_time);
|
|
||||||
window->display->grab_motion_notify_time = 0;
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return FALSE; /* haven't reached the saved timestamp yet */
|
|
||||||
}
|
|
||||||
|
|
||||||
esd.window = xev->event;
|
|
||||||
esd.count = 0;
|
|
||||||
esd.last_time = 0;
|
|
||||||
|
|
||||||
/* "useless" isn't filled in because the predicate never returns True */
|
|
||||||
XCheckIfEvent (window->display->xdisplay,
|
|
||||||
&useless,
|
|
||||||
find_last_time_predicate,
|
|
||||||
(XPointer) &esd);
|
|
||||||
|
|
||||||
if (esd.count > 0)
|
|
||||||
meta_topic (META_DEBUG_RESIZING,
|
|
||||||
"Will skip %d motion events and use the event with time %u\n",
|
|
||||||
esd.count, (unsigned int) esd.last_time);
|
|
||||||
|
|
||||||
if (esd.last_time == 0)
|
|
||||||
return TRUE;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Save this timestamp, and ignore all motion notify
|
|
||||||
* until we get to the one with this stamp.
|
|
||||||
*/
|
|
||||||
window->display->grab_motion_notify_time = esd.last_time;
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
update_tile_mode (MetaWindow *window)
|
update_tile_mode (MetaWindow *window)
|
||||||
@@ -9929,14 +9981,20 @@ meta_window_update_sync_request_counter (MetaWindow *window,
|
|||||||
|
|
||||||
void
|
void
|
||||||
meta_window_handle_mouse_grab_op_event (MetaWindow *window,
|
meta_window_handle_mouse_grab_op_event (MetaWindow *window,
|
||||||
XIDeviceEvent *xev)
|
const ClutterEvent *event)
|
||||||
{
|
{
|
||||||
switch (xev->evtype)
|
gboolean is_window_root = (event->any.stage != NULL &&
|
||||||
|
window &&
|
||||||
|
window->screen &&
|
||||||
|
CLUTTER_ACTOR (event->any.stage) ==
|
||||||
|
meta_get_stage_for_screen (window->screen));
|
||||||
|
|
||||||
|
switch (event->type)
|
||||||
{
|
{
|
||||||
case XI_ButtonRelease:
|
case CLUTTER_BUTTON_RELEASE:
|
||||||
meta_display_check_threshold_reached (window->display,
|
meta_display_check_threshold_reached (window->display,
|
||||||
xev->root_x,
|
event->button.x,
|
||||||
xev->root_y);
|
event->button.y);
|
||||||
/* If the user was snap moving then ignore the button release
|
/* If the user was snap moving then ignore the button release
|
||||||
* because they may have let go of shift before releasing the
|
* because they may have let go of shift before releasing the
|
||||||
* mouse button and they almost certainly do not want a
|
* mouse button and they almost certainly do not want a
|
||||||
@@ -9948,19 +10006,21 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window,
|
|||||||
{
|
{
|
||||||
if (window->tile_mode != META_TILE_NONE)
|
if (window->tile_mode != META_TILE_NONE)
|
||||||
meta_window_tile (window);
|
meta_window_tile (window);
|
||||||
else if (xev->root == window->screen->xroot)
|
else if (is_window_root)
|
||||||
update_move (window,
|
update_move (window,
|
||||||
xev->mods.effective & ShiftMask,
|
clutter_event_get_state (event) &
|
||||||
xev->root_x,
|
CLUTTER_SHIFT_MASK,
|
||||||
xev->root_y);
|
event->button.x,
|
||||||
|
event->button.y);
|
||||||
}
|
}
|
||||||
else if (meta_grab_op_is_resizing (window->display->grab_op))
|
else if (meta_grab_op_is_resizing (window->display->grab_op))
|
||||||
{
|
{
|
||||||
if (xev->root == window->screen->xroot)
|
if (is_window_root)
|
||||||
update_resize (window,
|
update_resize (window,
|
||||||
xev->mods.effective & ShiftMask,
|
clutter_event_get_state (event) &
|
||||||
xev->root_x,
|
CLUTTER_SHIFT_MASK,
|
||||||
xev->root_y,
|
event->button.x,
|
||||||
|
event->button.y,
|
||||||
TRUE);
|
TRUE);
|
||||||
|
|
||||||
/* If a tiled window has been dragged free with a
|
/* If a tiled window has been dragged free with a
|
||||||
@@ -9974,35 +10034,35 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
meta_display_end_grab_op (window->display, xev->time);
|
meta_display_end_grab_op (window->display, event->any.time);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case XI_Motion:
|
case CLUTTER_MOTION:
|
||||||
meta_display_check_threshold_reached (window->display,
|
meta_display_check_threshold_reached (window->display,
|
||||||
xev->root_x,
|
event->motion.x,
|
||||||
xev->root_y);
|
event->motion.y);
|
||||||
if (meta_grab_op_is_moving (window->display->grab_op))
|
if (meta_grab_op_is_moving (window->display->grab_op))
|
||||||
{
|
{
|
||||||
if (xev->root == window->screen->xroot)
|
if (is_window_root)
|
||||||
{
|
{
|
||||||
if (check_use_this_motion_notify (window,
|
if (check_use_this_motion_notify (window, event))
|
||||||
xev))
|
|
||||||
update_move (window,
|
update_move (window,
|
||||||
xev->mods.effective & ShiftMask,
|
clutter_event_get_state (event) &
|
||||||
xev->root_x,
|
CLUTTER_SHIFT_MASK,
|
||||||
xev->root_y);
|
event->motion.x,
|
||||||
|
event->motion.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (meta_grab_op_is_resizing (window->display->grab_op))
|
else if (meta_grab_op_is_resizing (window->display->grab_op))
|
||||||
{
|
{
|
||||||
if (xev->root == window->screen->xroot)
|
if (is_window_root)
|
||||||
{
|
{
|
||||||
if (check_use_this_motion_notify (window,
|
if (check_use_this_motion_notify (window, event))
|
||||||
xev))
|
|
||||||
update_resize (window,
|
update_resize (window,
|
||||||
xev->mods.effective & ShiftMask,
|
clutter_event_get_state (event) &
|
||||||
xev->root_x,
|
CLUTTER_SHIFT_MASK,
|
||||||
xev->root_y,
|
event->motion.x,
|
||||||
|
event->motion.y,
|
||||||
FALSE);
|
FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10313,11 +10373,10 @@ meta_window_foreach_ancestor (MetaWindow *window,
|
|||||||
w = window;
|
w = window;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (w->xtransient_for == None ||
|
if (w->transient_for == NULL)
|
||||||
w->transient_parent_is_root_window)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
w = meta_display_lookup_x_window (w->display, w->xtransient_for);
|
w = w->transient_for;
|
||||||
}
|
}
|
||||||
while (w && (* func) (w, user_data));
|
while (w && (* func) (w, user_data));
|
||||||
}
|
}
|
||||||
@@ -11140,7 +11199,9 @@ meta_window_get_transient_for (MetaWindow *window)
|
|||||||
{
|
{
|
||||||
g_return_val_if_fail (META_IS_WINDOW (window), NULL);
|
g_return_val_if_fail (META_IS_WINDOW (window), NULL);
|
||||||
|
|
||||||
if (window->xtransient_for)
|
if (window->transient_for)
|
||||||
|
return window->transient_for;
|
||||||
|
else if (window->xtransient_for)
|
||||||
return meta_display_lookup_x_window (window->display,
|
return meta_display_lookup_x_window (window->display,
|
||||||
window->xtransient_for);
|
window->xtransient_for);
|
||||||
else
|
else
|
||||||
@@ -11545,3 +11606,55 @@ meta_window_set_gtk_dbus_properties (MetaWindow *window,
|
|||||||
|
|
||||||
g_object_thaw_notify (G_OBJECT (window));
|
g_object_thaw_notify (G_OBJECT (window));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_window_set_transient_for (MetaWindow *window,
|
||||||
|
MetaWindow *parent)
|
||||||
|
{
|
||||||
|
if (meta_window_appears_focused (window) && window->transient_for != None)
|
||||||
|
meta_window_propagate_focus_appearance (window, FALSE);
|
||||||
|
|
||||||
|
/* may now be a dialog */
|
||||||
|
meta_window_recalc_window_type (window);
|
||||||
|
|
||||||
|
if (!window->constructing)
|
||||||
|
{
|
||||||
|
/* If the window attaches, detaches, or changes attached
|
||||||
|
* parents, we need to destroy the MetaWindow and let a new one
|
||||||
|
* be created (which happens as a side effect of
|
||||||
|
* meta_window_unmanage()). The condition below is correct
|
||||||
|
* because we know window->transient_for has changed.
|
||||||
|
*/
|
||||||
|
if (window->attached || meta_window_should_attach_to_parent (window))
|
||||||
|
{
|
||||||
|
guint32 timestamp;
|
||||||
|
|
||||||
|
timestamp = meta_display_get_current_time_roundtrip (window->display);
|
||||||
|
meta_window_unmanage (window, timestamp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update stacking constraints */
|
||||||
|
if (!window->override_redirect)
|
||||||
|
meta_stack_update_transient (window->screen->stack, window);
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/* possibly change its group. We treat being a window's transient as
|
||||||
|
* equivalent to making it your group leader, to work around shortcomings
|
||||||
|
* in programs such as xmms-- see #328211.
|
||||||
|
*/
|
||||||
|
if (window->xtransient_for != None &&
|
||||||
|
window->xgroup_leader != None &&
|
||||||
|
window->xtransient_for != window->xgroup_leader)
|
||||||
|
meta_window_group_leader_changed (window);
|
||||||
|
|
||||||
|
if (!window->constructing && !window->override_redirect)
|
||||||
|
meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
|
||||||
|
|
||||||
|
if (meta_window_appears_focused (window) && window->transient_for != None)
|
||||||
|
meta_window_propagate_focus_appearance (window, TRUE);
|
||||||
|
}
|
||||||
|
@@ -536,6 +536,81 @@ meta_prop_get_utf8_list (MetaDisplay *display,
|
|||||||
return utf8_list_from_results (&results, str_p, n_str_p);
|
return utf8_list_from_results (&results, str_p, n_str_p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* this one freakishly returns g_malloc memory */
|
||||||
|
static gboolean
|
||||||
|
latin1_list_from_results (GetPropertyResults *results,
|
||||||
|
char ***str_p,
|
||||||
|
int *n_str_p)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int n_strings;
|
||||||
|
char **retval;
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
*str_p = NULL;
|
||||||
|
*n_str_p = 0;
|
||||||
|
|
||||||
|
if (!validate_or_free_results (results, 8, XA_STRING, FALSE))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* I'm not sure this is right, but I'm guessing the
|
||||||
|
* property is nul-separated
|
||||||
|
*/
|
||||||
|
i = 0;
|
||||||
|
n_strings = 0;
|
||||||
|
while (i < (int) results->n_items)
|
||||||
|
{
|
||||||
|
if (results->prop[i] == '\0')
|
||||||
|
++n_strings;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (results->prop[results->n_items - 1] != '\0')
|
||||||
|
++n_strings;
|
||||||
|
|
||||||
|
/* we're guaranteed that results->prop has a nul on the end
|
||||||
|
* by XGetWindowProperty
|
||||||
|
*/
|
||||||
|
|
||||||
|
retval = g_new0 (char*, n_strings + 1);
|
||||||
|
|
||||||
|
p = (char *)results->prop;
|
||||||
|
i = 0;
|
||||||
|
while (i < n_strings)
|
||||||
|
{
|
||||||
|
retval[i] = g_strdup (p);
|
||||||
|
|
||||||
|
p = p + strlen (p) + 1;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
*str_p = retval;
|
||||||
|
*n_str_p = i;
|
||||||
|
|
||||||
|
meta_XFree (results->prop);
|
||||||
|
results->prop = NULL;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_prop_get_latin1_list (MetaDisplay *display,
|
||||||
|
Window xwindow,
|
||||||
|
Atom xatom,
|
||||||
|
char ***str_p,
|
||||||
|
int *n_str_p)
|
||||||
|
{
|
||||||
|
GetPropertyResults results;
|
||||||
|
|
||||||
|
*str_p = NULL;
|
||||||
|
|
||||||
|
if (!get_property (display, xwindow, xatom,
|
||||||
|
XA_STRING, &results))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return latin1_list_from_results (&results, str_p, n_str_p);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_prop_set_utf8_string_hint (MetaDisplay *display,
|
meta_prop_set_utf8_string_hint (MetaDisplay *display,
|
||||||
Window xwindow,
|
Window xwindow,
|
||||||
|
@@ -102,6 +102,11 @@ gboolean meta_prop_get_utf8_list (MetaDisplay *display,
|
|||||||
Atom xatom,
|
Atom xatom,
|
||||||
char ***str_p,
|
char ***str_p,
|
||||||
int *n_str_p);
|
int *n_str_p);
|
||||||
|
gboolean meta_prop_get_latin1_list (MetaDisplay *display,
|
||||||
|
Window xwindow,
|
||||||
|
Atom xatom,
|
||||||
|
char ***str_p,
|
||||||
|
int *n_str_p);
|
||||||
void meta_prop_set_utf8_string_hint
|
void meta_prop_set_utf8_string_hint
|
||||||
(MetaDisplay *display,
|
(MetaDisplay *display,
|
||||||
Window xwindow,
|
Window xwindow,
|
||||||
|
@@ -81,6 +81,7 @@ item(TIMESTAMP)
|
|||||||
item(VERSION)
|
item(VERSION)
|
||||||
item(ATOM_PAIR)
|
item(ATOM_PAIR)
|
||||||
item(BACKLIGHT)
|
item(BACKLIGHT)
|
||||||
|
item(_XKB_RULES_NAMES)
|
||||||
|
|
||||||
/* Oddities: These are used, and we need atoms for them,
|
/* Oddities: These are used, and we need atoms for them,
|
||||||
* but when we need all _NET_WM hints (i.e. when we're making
|
* but when we need all _NET_WM hints (i.e. when we're making
|
||||||
|
@@ -106,11 +106,49 @@ create_anonymous_file (off_t size,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
meta_wayland_xkb_info_new_keymap (MetaWaylandXkbInfo *xkb_info)
|
inform_clients_of_new_keymap (MetaWaylandKeyboard *keyboard,
|
||||||
|
int flags)
|
||||||
{
|
{
|
||||||
|
MetaWaylandCompositor *compositor;
|
||||||
|
struct wl_client *xclient;
|
||||||
|
struct wl_resource *keyboard_resource;
|
||||||
|
|
||||||
|
compositor = meta_wayland_compositor_get_default ();
|
||||||
|
xclient = compositor->xwayland_client;
|
||||||
|
|
||||||
|
wl_resource_for_each (keyboard_resource, &keyboard->resource_list)
|
||||||
|
{
|
||||||
|
if ((flags & META_WAYLAND_KEYBOARD_SKIP_XCLIENTS) &&
|
||||||
|
wl_resource_get_client (keyboard_resource) == xclient)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
wl_keyboard_send_keymap (keyboard_resource,
|
||||||
|
WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
|
||||||
|
keyboard->xkb_info.keymap_fd,
|
||||||
|
keyboard->xkb_info.keymap_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_keyboard_take_keymap (MetaWaylandKeyboard *keyboard,
|
||||||
|
struct xkb_keymap *keymap,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
MetaWaylandXkbInfo *xkb_info = &keyboard->xkb_info;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
char *keymap_str;
|
char *keymap_str;
|
||||||
|
size_t previous_size;
|
||||||
|
|
||||||
|
if (keymap == NULL)
|
||||||
|
{
|
||||||
|
g_warning ("Attempting to set null keymap (compilation probably failed)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xkb_info->keymap)
|
||||||
|
xkb_keymap_unref (xkb_info->keymap);
|
||||||
|
xkb_info->keymap = keymap;
|
||||||
|
|
||||||
xkb_info->shift_mod =
|
xkb_info->shift_mod =
|
||||||
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_SHIFT);
|
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_SHIFT);
|
||||||
@@ -129,21 +167,28 @@ meta_wayland_xkb_info_new_keymap (MetaWaylandXkbInfo *xkb_info)
|
|||||||
keymap_str = xkb_map_get_as_string (xkb_info->keymap);
|
keymap_str = xkb_map_get_as_string (xkb_info->keymap);
|
||||||
if (keymap_str == NULL)
|
if (keymap_str == NULL)
|
||||||
{
|
{
|
||||||
g_warning ("failed to get string version of keymap\n");
|
g_warning ("failed to get string version of keymap");
|
||||||
return FALSE;
|
return;
|
||||||
}
|
}
|
||||||
|
previous_size = xkb_info->keymap_size;
|
||||||
xkb_info->keymap_size = strlen (keymap_str) + 1;
|
xkb_info->keymap_size = strlen (keymap_str) + 1;
|
||||||
|
|
||||||
|
if (xkb_info->keymap_fd >= 0)
|
||||||
|
close (xkb_info->keymap_fd);
|
||||||
|
|
||||||
xkb_info->keymap_fd = create_anonymous_file (xkb_info->keymap_size, &error);
|
xkb_info->keymap_fd = create_anonymous_file (xkb_info->keymap_size, &error);
|
||||||
if (xkb_info->keymap_fd < 0)
|
if (xkb_info->keymap_fd < 0)
|
||||||
{
|
{
|
||||||
g_warning ("creating a keymap file for %lu bytes failed: %s\n",
|
g_warning ("creating a keymap file for %lu bytes failed: %s",
|
||||||
(unsigned long) xkb_info->keymap_size,
|
(unsigned long) xkb_info->keymap_size,
|
||||||
error->message);
|
error->message);
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
goto err_keymap_str;
|
goto err_keymap_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (xkb_info->keymap_area)
|
||||||
|
munmap (xkb_info->keymap_area, previous_size);
|
||||||
|
|
||||||
xkb_info->keymap_area = mmap (NULL, xkb_info->keymap_size,
|
xkb_info->keymap_area = mmap (NULL, xkb_info->keymap_size,
|
||||||
PROT_READ | PROT_WRITE,
|
PROT_READ | PROT_WRITE,
|
||||||
MAP_SHARED, xkb_info->keymap_fd, 0);
|
MAP_SHARED, xkb_info->keymap_fd, 0);
|
||||||
@@ -156,41 +201,24 @@ meta_wayland_xkb_info_new_keymap (MetaWaylandXkbInfo *xkb_info)
|
|||||||
strcpy (xkb_info->keymap_area, keymap_str);
|
strcpy (xkb_info->keymap_area, keymap_str);
|
||||||
free (keymap_str);
|
free (keymap_str);
|
||||||
|
|
||||||
return TRUE;
|
if (keyboard->is_evdev)
|
||||||
|
{
|
||||||
|
ClutterDeviceManager *manager;
|
||||||
|
|
||||||
|
manager = clutter_device_manager_get_default ();
|
||||||
|
clutter_evdev_set_keyboard_map (manager, xkb_info->keymap);
|
||||||
|
}
|
||||||
|
|
||||||
|
inform_clients_of_new_keymap (keyboard, flags);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
err_dev_zero:
|
err_dev_zero:
|
||||||
close (xkb_info->keymap_fd);
|
close (xkb_info->keymap_fd);
|
||||||
xkb_info->keymap_fd = -1;
|
xkb_info->keymap_fd = -1;
|
||||||
err_keymap_str:
|
err_keymap_str:
|
||||||
free (keymap_str);
|
free (keymap_str);
|
||||||
return FALSE;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
meta_wayland_keyboard_build_global_keymap (struct xkb_context *xkb_context,
|
|
||||||
struct xkb_rule_names *xkb_names,
|
|
||||||
MetaWaylandXkbInfo *xkb_info)
|
|
||||||
{
|
|
||||||
xkb_info->keymap = xkb_map_new_from_names (xkb_context,
|
|
||||||
xkb_names,
|
|
||||||
0 /* flags */);
|
|
||||||
if (xkb_info->keymap == NULL)
|
|
||||||
{
|
|
||||||
g_warning ("failed to compile global XKB keymap\n"
|
|
||||||
" tried rules %s, model %s, layout %s, variant %s, "
|
|
||||||
"options %s\n",
|
|
||||||
xkb_names->rules,
|
|
||||||
xkb_names->model,
|
|
||||||
xkb_names->layout,
|
|
||||||
xkb_names->variant,
|
|
||||||
xkb_names->options);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!meta_wayland_xkb_info_new_keymap (xkb_info))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -202,7 +230,7 @@ lose_keyboard_focus (struct wl_listener *listener, void *data)
|
|||||||
keyboard->focus_resource = NULL;
|
keyboard->focus_resource = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
default_grab_key (MetaWaylandKeyboardGrab *grab,
|
default_grab_key (MetaWaylandKeyboardGrab *grab,
|
||||||
uint32_t time, uint32_t key, uint32_t state)
|
uint32_t time, uint32_t key, uint32_t state)
|
||||||
{
|
{
|
||||||
@@ -218,6 +246,8 @@ default_grab_key (MetaWaylandKeyboardGrab *grab,
|
|||||||
serial = wl_display_next_serial (display);
|
serial = wl_display_next_serial (display);
|
||||||
wl_keyboard_send_key (resource, serial, time, key, state);
|
wl_keyboard_send_key (resource, serial, time, key, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return resource != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct wl_resource *
|
static struct wl_resource *
|
||||||
@@ -274,12 +304,14 @@ static const MetaWaylandKeyboardGrabInterface
|
|||||||
default_grab_modifiers,
|
default_grab_modifiers,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
modal_key (MetaWaylandKeyboardGrab *grab,
|
modal_key (MetaWaylandKeyboardGrab *grab,
|
||||||
uint32_t time,
|
uint32_t time,
|
||||||
uint32_t key,
|
uint32_t key,
|
||||||
uint32_t state)
|
uint32_t state)
|
||||||
{
|
{
|
||||||
|
/* FALSE means: let the event through to clutter */
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -302,9 +334,8 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
|
|||||||
struct wl_display *display,
|
struct wl_display *display,
|
||||||
gboolean is_evdev)
|
gboolean is_evdev)
|
||||||
{
|
{
|
||||||
ClutterDeviceManager *manager;
|
|
||||||
|
|
||||||
memset (keyboard, 0, sizeof *keyboard);
|
memset (keyboard, 0, sizeof *keyboard);
|
||||||
|
keyboard->xkb_info.keymap_fd = -1;
|
||||||
|
|
||||||
wl_list_init (&keyboard->resource_list);
|
wl_list_init (&keyboard->resource_list);
|
||||||
wl_array_init (&keyboard->keys);
|
wl_array_init (&keyboard->keys);
|
||||||
@@ -317,24 +348,15 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
|
|||||||
keyboard->display = display;
|
keyboard->display = display;
|
||||||
|
|
||||||
keyboard->xkb_context = xkb_context_new (0 /* flags */);
|
keyboard->xkb_context = xkb_context_new (0 /* flags */);
|
||||||
|
|
||||||
meta_wayland_keyboard_build_global_keymap (keyboard->xkb_context,
|
|
||||||
&keyboard->xkb_names,
|
|
||||||
&keyboard->xkb_info);
|
|
||||||
|
|
||||||
keyboard->is_evdev = is_evdev;
|
keyboard->is_evdev = is_evdev;
|
||||||
if (is_evdev)
|
|
||||||
{
|
|
||||||
manager = clutter_device_manager_get_default ();
|
|
||||||
|
|
||||||
clutter_evdev_set_keyboard_map (manager, keyboard->xkb_info.keymap);
|
/* Compute a default until gnome-settings-daemon starts and sets
|
||||||
keyboard->xkb_state = clutter_evdev_get_keyboard_state (manager);
|
the appropriate values
|
||||||
xkb_state_ref (keyboard->xkb_state);
|
*/
|
||||||
}
|
meta_wayland_keyboard_set_keymap_names (keyboard,
|
||||||
else
|
"evdev",
|
||||||
{
|
"pc105",
|
||||||
keyboard->xkb_state = xkb_state_new (keyboard->xkb_info.keymap);
|
"us", "", "", 0);
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -351,52 +373,6 @@ meta_wayland_xkb_info_destroy (MetaWaylandXkbInfo *xkb_info)
|
|||||||
close (xkb_info->keymap_fd);
|
close (xkb_info->keymap_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
update_state_from_clutter (MetaWaylandKeyboard *keyboard,
|
|
||||||
ClutterModifierType modifier_state)
|
|
||||||
{
|
|
||||||
uint32_t depressed_mods = 0;
|
|
||||||
uint32_t locked_mods = 0;
|
|
||||||
|
|
||||||
if ((modifier_state & CLUTTER_SHIFT_MASK) &&
|
|
||||||
keyboard->xkb_info.shift_mod != XKB_MOD_INVALID)
|
|
||||||
depressed_mods |= (1 << keyboard->xkb_info.shift_mod);
|
|
||||||
|
|
||||||
if ((modifier_state & CLUTTER_LOCK_MASK) &&
|
|
||||||
keyboard->xkb_info.caps_mod != XKB_MOD_INVALID)
|
|
||||||
locked_mods |= (1 << keyboard->xkb_info.caps_mod);
|
|
||||||
|
|
||||||
if ((modifier_state & CLUTTER_CONTROL_MASK) &&
|
|
||||||
keyboard->xkb_info.ctrl_mod != XKB_MOD_INVALID)
|
|
||||||
depressed_mods |= (1 << keyboard->xkb_info.ctrl_mod);
|
|
||||||
|
|
||||||
if ((modifier_state & CLUTTER_MOD1_MASK) &&
|
|
||||||
keyboard->xkb_info.alt_mod != XKB_MOD_INVALID)
|
|
||||||
depressed_mods |= (1 << keyboard->xkb_info.alt_mod);
|
|
||||||
|
|
||||||
if ((modifier_state & CLUTTER_MOD2_MASK) &&
|
|
||||||
keyboard->xkb_info.mod2_mod != XKB_MOD_INVALID)
|
|
||||||
depressed_mods |= (1 << keyboard->xkb_info.mod2_mod);
|
|
||||||
|
|
||||||
if ((modifier_state & CLUTTER_MOD3_MASK) &&
|
|
||||||
keyboard->xkb_info.mod3_mod != XKB_MOD_INVALID)
|
|
||||||
depressed_mods |= (1 << keyboard->xkb_info.mod3_mod);
|
|
||||||
|
|
||||||
if ((modifier_state & CLUTTER_SUPER_MASK) &&
|
|
||||||
keyboard->xkb_info.super_mod != XKB_MOD_INVALID)
|
|
||||||
depressed_mods |= (1 << keyboard->xkb_info.super_mod);
|
|
||||||
|
|
||||||
if ((modifier_state & CLUTTER_MOD5_MASK) &&
|
|
||||||
keyboard->xkb_info.mod5_mod != XKB_MOD_INVALID)
|
|
||||||
depressed_mods |= (1 << keyboard->xkb_info.mod5_mod);
|
|
||||||
|
|
||||||
xkb_state_update_mask (keyboard->xkb_state,
|
|
||||||
depressed_mods,
|
|
||||||
0,
|
|
||||||
locked_mods,
|
|
||||||
0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
state_equal (MetaWaylandXkbState *one,
|
state_equal (MetaWaylandXkbState *one,
|
||||||
MetaWaylandXkbState *two)
|
MetaWaylandXkbState *two)
|
||||||
@@ -410,24 +386,19 @@ state_equal (MetaWaylandXkbState *one,
|
|||||||
static void
|
static void
|
||||||
set_modifiers (MetaWaylandKeyboard *keyboard,
|
set_modifiers (MetaWaylandKeyboard *keyboard,
|
||||||
guint32 serial,
|
guint32 serial,
|
||||||
ClutterModifierType modifier_state)
|
ClutterEvent *event)
|
||||||
{
|
{
|
||||||
MetaWaylandKeyboardGrab *grab = keyboard->grab;
|
MetaWaylandKeyboardGrab *grab = keyboard->grab;
|
||||||
MetaWaylandXkbState new_state;
|
MetaWaylandXkbState new_state;
|
||||||
|
guint effective_state;
|
||||||
|
|
||||||
/* In the evdev case, the state is shared with the clutter backend, so
|
clutter_event_get_state_full (event,
|
||||||
we don't need to update it */
|
NULL,
|
||||||
if (!keyboard->is_evdev)
|
&new_state.mods_depressed,
|
||||||
update_state_from_clutter (keyboard, modifier_state);
|
&new_state.mods_latched,
|
||||||
|
&new_state.mods_locked,
|
||||||
new_state.mods_depressed = xkb_state_serialize_mods (keyboard->xkb_state,
|
&effective_state);
|
||||||
XKB_STATE_MODS_DEPRESSED);
|
new_state.group = (effective_state >> 13) & 0x3;
|
||||||
new_state.mods_latched = xkb_state_serialize_mods (keyboard->xkb_state,
|
|
||||||
XKB_STATE_MODS_LATCHED);
|
|
||||||
new_state.mods_locked = xkb_state_serialize_mods (keyboard->xkb_state,
|
|
||||||
XKB_STATE_MODS_LOCKED);
|
|
||||||
new_state.group = xkb_state_serialize_layout (keyboard->xkb_state,
|
|
||||||
XKB_STATE_LAYOUT_EFFECTIVE);
|
|
||||||
|
|
||||||
if (state_equal (&keyboard->modifier_state, &new_state))
|
if (state_equal (&keyboard->modifier_state, &new_state))
|
||||||
return;
|
return;
|
||||||
@@ -442,36 +413,101 @@ set_modifiers (MetaWaylandKeyboard *keyboard,
|
|||||||
new_state.group);
|
new_state.group);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
#define N_BUTTONS 5
|
||||||
meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
|
||||||
const ClutterKeyEvent *event)
|
static gboolean
|
||||||
|
process_keybinding (MetaWaylandKeyboard *keyboard,
|
||||||
|
const ClutterEvent *event)
|
||||||
{
|
{
|
||||||
gboolean state = event->type == CLUTTER_KEY_PRESS;
|
MetaWaylandSurface *surface;
|
||||||
guint evdev_code;
|
XGenericEventCookie generic_event;
|
||||||
uint32_t serial;
|
XIDeviceEvent device_event;
|
||||||
|
unsigned char button_mask[(N_BUTTONS + 7) / 8] = { 0 };
|
||||||
|
MetaDisplay *display = meta_get_display ();
|
||||||
|
ClutterModifierType button_state;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* We can't do anything with the event if we can't get an evdev
|
if (!display) /* not initialized yet */
|
||||||
keycode for it */
|
return FALSE;
|
||||||
if (event->device == NULL ||
|
|
||||||
!clutter_input_device_keycode_to_evdev (event->device,
|
|
||||||
event->hardware_keycode,
|
|
||||||
&evdev_code))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* We want to ignore events that are sent because of auto-repeat. In
|
generic_event.type = GenericEvent;
|
||||||
the Clutter event stream these appear as a single key press
|
generic_event.serial = 0;
|
||||||
event. We can detect that because the key will already have been
|
generic_event.send_event = False;
|
||||||
pressed */
|
generic_event.display = display->xdisplay;
|
||||||
if (state)
|
generic_event.extension = display->xinput_opcode;
|
||||||
|
if (clutter_event_type (event) == CLUTTER_KEY_PRESS)
|
||||||
|
generic_event.evtype = XI_KeyPress;
|
||||||
|
else
|
||||||
|
generic_event.evtype = XI_KeyRelease;
|
||||||
|
/* Mutter assumes the data for the event is already retrieved by GDK
|
||||||
|
* so we don't need the cookie */
|
||||||
|
generic_event.cookie = 0;
|
||||||
|
generic_event.data = &device_event;
|
||||||
|
|
||||||
|
memcpy (&device_event, &generic_event, sizeof (XGenericEvent));
|
||||||
|
|
||||||
|
/* Can't use clutter_event_get_time() here, because evdev timestamps
|
||||||
|
have nothing to do with X timestamps */
|
||||||
|
device_event.time = meta_display_get_current_time_roundtrip (display);
|
||||||
|
device_event.deviceid = clutter_event_get_device_id (event);
|
||||||
|
device_event.sourceid = 0; /* not used, not sure what this should be */
|
||||||
|
device_event.detail = clutter_event_get_key_code (event);
|
||||||
|
device_event.root = DefaultRootWindow (display->xdisplay);
|
||||||
|
device_event.flags = 0;
|
||||||
|
|
||||||
|
surface = keyboard->focus;
|
||||||
|
if (surface)
|
||||||
|
device_event.event = surface->window ? surface->window->xwindow : device_event.root;
|
||||||
|
else
|
||||||
|
device_event.event = device_event.root;
|
||||||
|
|
||||||
|
/* Mutter doesn't really know about the sub-windows. This assumes it
|
||||||
|
doesn't care either */
|
||||||
|
device_event.child = device_event.event;
|
||||||
|
device_event.root_x = 0;
|
||||||
|
device_event.root_y = 0;
|
||||||
|
|
||||||
|
clutter_event_get_state_full (event,
|
||||||
|
&button_state,
|
||||||
|
(ClutterModifierType*)&device_event.mods.base,
|
||||||
|
(ClutterModifierType*)&device_event.mods.latched,
|
||||||
|
(ClutterModifierType*)&device_event.mods.locked,
|
||||||
|
(ClutterModifierType*)&device_event.mods.effective);
|
||||||
|
device_event.mods.effective &= ~button_state;
|
||||||
|
memset (&device_event.group, 0, sizeof (device_event.group));
|
||||||
|
device_event.group.effective = (device_event.mods.effective >> 13) & 0x3;
|
||||||
|
|
||||||
|
for (i = 0; i < N_BUTTONS; i++)
|
||||||
|
if ((button_state & (CLUTTER_BUTTON1_MASK << i)))
|
||||||
|
XISetMask (button_mask, i + 1);
|
||||||
|
device_event.buttons.mask_len = N_BUTTONS + 1;
|
||||||
|
device_event.buttons.mask = button_mask;
|
||||||
|
|
||||||
|
device_event.valuators.mask_len = 0;
|
||||||
|
device_event.valuators.mask = NULL;
|
||||||
|
device_event.valuators.values = NULL;
|
||||||
|
|
||||||
|
return meta_display_process_key_event (display, surface ? surface->window : NULL, &device_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
update_pressed_keys (MetaWaylandKeyboard *keyboard,
|
||||||
|
uint32_t evdev_code,
|
||||||
|
gboolean is_press)
|
||||||
|
{
|
||||||
|
if (is_press)
|
||||||
{
|
{
|
||||||
uint32_t *end = (void *) ((char *) keyboard->keys.data +
|
uint32_t *end = (void *) ((char *) keyboard->keys.data +
|
||||||
keyboard->keys.size);
|
keyboard->keys.size);
|
||||||
uint32_t *k;
|
uint32_t *k;
|
||||||
|
|
||||||
/* Ignore the event if the key is already down */
|
/* We want to ignore events that are sent because of auto-repeat. In
|
||||||
|
the Clutter event stream these appear as a single key press
|
||||||
|
event. We can detect that because the key will already have been
|
||||||
|
pressed */
|
||||||
for (k = keyboard->keys.data; k < end; k++)
|
for (k = keyboard->keys.data; k < end; k++)
|
||||||
if (*k == evdev_code)
|
if (*k == evdev_code)
|
||||||
return;
|
return TRUE;
|
||||||
|
|
||||||
/* Otherwise add the key to the list of pressed keys */
|
/* Otherwise add the key to the list of pressed keys */
|
||||||
k = wl_array_add (&keyboard->keys, sizeof (*k));
|
k = wl_array_add (&keyboard->keys, sizeof (*k));
|
||||||
@@ -494,19 +530,61 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_warning ("unexpected key release event for key 0x%x", evdev_code);
|
g_warning ("unexpected key release event for key 0x%x", evdev_code);
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
found:
|
found:
|
||||||
(void) 0;
|
(void) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
gboolean
|
||||||
|
meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
||||||
|
const ClutterKeyEvent *event)
|
||||||
|
{
|
||||||
|
gboolean is_press = event->type == CLUTTER_KEY_PRESS;
|
||||||
|
guint xkb_keycode, evdev_code;
|
||||||
|
uint32_t serial;
|
||||||
|
gboolean autorepeat;
|
||||||
|
gboolean handled;
|
||||||
|
|
||||||
|
xkb_keycode = event->hardware_keycode;
|
||||||
|
if (event->device == NULL ||
|
||||||
|
!clutter_input_device_keycode_to_evdev (event->device,
|
||||||
|
xkb_keycode, &evdev_code))
|
||||||
|
evdev_code = xkb_keycode - 8; /* What everyone is doing in practice... */
|
||||||
|
|
||||||
|
autorepeat = update_pressed_keys (keyboard, evdev_code, is_press);
|
||||||
|
|
||||||
|
meta_verbose ("Handling key %s%s event code %d\n",
|
||||||
|
is_press ? "press" : "release",
|
||||||
|
autorepeat ? " (autorepeat)" : "",
|
||||||
|
xkb_keycode);
|
||||||
|
|
||||||
|
/* Give a chance to process keybindings */
|
||||||
|
if (process_keybinding (keyboard, (ClutterEvent*) event))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
meta_verbose ("Keybindings ignored the previous event\n");
|
||||||
|
|
||||||
|
if (autorepeat)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
serial = wl_display_next_serial (keyboard->display);
|
serial = wl_display_next_serial (keyboard->display);
|
||||||
|
|
||||||
set_modifiers (keyboard, serial, event->modifier_state);
|
set_modifiers (keyboard, serial, (ClutterEvent*)event);
|
||||||
|
|
||||||
keyboard->grab->interface->key (keyboard->grab,
|
handled = keyboard->grab->interface->key (keyboard->grab,
|
||||||
event->time,
|
event->time,
|
||||||
evdev_code,
|
evdev_code,
|
||||||
state);
|
is_press);
|
||||||
|
|
||||||
|
if (handled)
|
||||||
|
meta_verbose ("Sent event to wayland client\n");
|
||||||
|
else
|
||||||
|
meta_verbose ("No wayland surface is focused, continuing normal operation\n");
|
||||||
|
|
||||||
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -589,15 +667,8 @@ meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard)
|
|||||||
void
|
void
|
||||||
meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard)
|
meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard)
|
||||||
{
|
{
|
||||||
g_free ((char *) keyboard->xkb_names.rules);
|
|
||||||
g_free ((char *) keyboard->xkb_names.model);
|
|
||||||
g_free ((char *) keyboard->xkb_names.layout);
|
|
||||||
g_free ((char *) keyboard->xkb_names.variant);
|
|
||||||
g_free ((char *) keyboard->xkb_names.options);
|
|
||||||
|
|
||||||
meta_wayland_xkb_info_destroy (&keyboard->xkb_info);
|
meta_wayland_xkb_info_destroy (&keyboard->xkb_info);
|
||||||
xkb_context_unref (keyboard->xkb_context);
|
xkb_context_unref (keyboard->xkb_context);
|
||||||
xkb_state_unref (keyboard->xkb_state);
|
|
||||||
|
|
||||||
/* XXX: What about keyboard->resource_list? */
|
/* XXX: What about keyboard->resource_list? */
|
||||||
if (keyboard->focus_resource)
|
if (keyboard->focus_resource)
|
||||||
@@ -615,6 +686,8 @@ meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard,
|
|||||||
uint32_t *k;
|
uint32_t *k;
|
||||||
uint32_t serial;
|
uint32_t serial;
|
||||||
|
|
||||||
|
meta_verbose ("Asked to acquire modal keyboard grab, timestamp %d\n", timestamp);
|
||||||
|
|
||||||
if (keyboard->grab != &keyboard->default_grab)
|
if (keyboard->grab != &keyboard->default_grab)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
@@ -627,15 +700,19 @@ meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard,
|
|||||||
0, 0, 0, 0);
|
0, 0, 0, 0);
|
||||||
|
|
||||||
for (k = keyboard->keys.data; k < end; k++)
|
for (k = keyboard->keys.data; k < end; k++)
|
||||||
|
{
|
||||||
keyboard->grab->interface->key (keyboard->grab,
|
keyboard->grab->interface->key (keyboard->grab,
|
||||||
timestamp,
|
timestamp,
|
||||||
*k, 0);
|
*k, 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
grab = g_slice_new0 (MetaWaylandKeyboardGrab);
|
grab = g_slice_new0 (MetaWaylandKeyboardGrab);
|
||||||
grab->interface = &modal_grab;
|
grab->interface = &modal_grab;
|
||||||
meta_wayland_keyboard_start_grab (keyboard, grab);
|
meta_wayland_keyboard_start_grab (keyboard, grab);
|
||||||
|
|
||||||
|
meta_verbose ("Acquired modal keyboard grab, timestamp %d\n", timestamp);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,8 +745,37 @@ meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard,
|
|||||||
keyboard->modifier_state.group);
|
keyboard->modifier_state.group);
|
||||||
|
|
||||||
for (k = keyboard->keys.data; k < end; k++)
|
for (k = keyboard->keys.data; k < end; k++)
|
||||||
|
{
|
||||||
keyboard->grab->interface->key (keyboard->grab,
|
keyboard->grab->interface->key (keyboard->grab,
|
||||||
timestamp,
|
timestamp,
|
||||||
*k, 1);
|
*k, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
meta_verbose ("Released modal keyboard grab, timestamp %d\n", timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_keyboard_set_keymap_names (MetaWaylandKeyboard *keyboard,
|
||||||
|
const char *rules,
|
||||||
|
const char *model,
|
||||||
|
const char *layout,
|
||||||
|
const char *variant,
|
||||||
|
const char *options,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
struct xkb_rule_names xkb_names;
|
||||||
|
|
||||||
|
xkb_names.rules = rules;
|
||||||
|
xkb_names.model = model;
|
||||||
|
xkb_names.layout = layout;
|
||||||
|
xkb_names.variant = variant;
|
||||||
|
xkb_names.options = options;
|
||||||
|
|
||||||
|
meta_wayland_keyboard_take_keymap (keyboard,
|
||||||
|
xkb_keymap_new_from_names (keyboard->xkb_context,
|
||||||
|
&xkb_names,
|
||||||
|
0 /* flags */),
|
||||||
|
flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -50,7 +50,7 @@
|
|||||||
|
|
||||||
struct _MetaWaylandKeyboardGrabInterface
|
struct _MetaWaylandKeyboardGrabInterface
|
||||||
{
|
{
|
||||||
void (*key) (MetaWaylandKeyboardGrab * grab, uint32_t time,
|
gboolean (*key) (MetaWaylandKeyboardGrab * grab, uint32_t time,
|
||||||
uint32_t key, uint32_t state);
|
uint32_t key, uint32_t state);
|
||||||
void (*modifiers) (MetaWaylandKeyboardGrab * grab, uint32_t serial,
|
void (*modifiers) (MetaWaylandKeyboardGrab * grab, uint32_t serial,
|
||||||
uint32_t mods_depressed, uint32_t mods_latched,
|
uint32_t mods_depressed, uint32_t mods_latched,
|
||||||
@@ -111,11 +111,8 @@ struct _MetaWaylandKeyboard
|
|||||||
struct wl_display *display;
|
struct wl_display *display;
|
||||||
|
|
||||||
struct xkb_context *xkb_context;
|
struct xkb_context *xkb_context;
|
||||||
struct xkb_state *xkb_state;
|
|
||||||
gboolean is_evdev;
|
gboolean is_evdev;
|
||||||
|
|
||||||
MetaWaylandXkbInfo xkb_info;
|
MetaWaylandXkbInfo xkb_info;
|
||||||
struct xkb_rule_names xkb_names;
|
|
||||||
|
|
||||||
MetaWaylandKeyboardGrab input_method_grab;
|
MetaWaylandKeyboardGrab input_method_grab;
|
||||||
struct wl_resource *input_method_resource;
|
struct wl_resource *input_method_resource;
|
||||||
@@ -126,7 +123,19 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
|
|||||||
struct wl_display *display,
|
struct wl_display *display,
|
||||||
gboolean is_evdev);
|
gboolean is_evdev);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
META_WAYLAND_KEYBOARD_SKIP_XCLIENTS = 1,
|
||||||
|
} MetaWaylandKeyboardSetKeymapFlags;
|
||||||
|
|
||||||
void
|
void
|
||||||
|
meta_wayland_keyboard_set_keymap_names (MetaWaylandKeyboard *keyboard,
|
||||||
|
const char *rules,
|
||||||
|
const char *model,
|
||||||
|
const char *layout,
|
||||||
|
const char *variant,
|
||||||
|
const char *options,
|
||||||
|
int flags);
|
||||||
|
gboolean
|
||||||
meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
||||||
const ClutterKeyEvent *event);
|
const ClutterKeyEvent *event);
|
||||||
|
|
||||||
|
@@ -43,6 +43,9 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <clutter/clutter.h>
|
||||||
|
#include <clutter/evdev/clutter-evdev.h>
|
||||||
|
|
||||||
#include "meta-wayland-pointer.h"
|
#include "meta-wayland-pointer.h"
|
||||||
#include "meta-wayland-private.h"
|
#include "meta-wayland-private.h"
|
||||||
|
|
||||||
@@ -120,9 +123,114 @@ static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = {
|
|||||||
default_grab_button
|
default_grab_button
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
/*
|
||||||
meta_wayland_pointer_init (MetaWaylandPointer *pointer)
|
* The pointer constrain code is mostly a rip-off of the XRandR code from Xorg.
|
||||||
|
* (from xserver/randr/rrcrtc.c, RRConstrainCursorHarder)
|
||||||
|
*
|
||||||
|
* Copyright © 2006 Keith Packard
|
||||||
|
* Copyright 2010 Red Hat, Inc
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
check_all_screen_monitors(MetaMonitorInfo *monitors,
|
||||||
|
unsigned n_monitors,
|
||||||
|
float x,
|
||||||
|
float y)
|
||||||
{
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < n_monitors; i++)
|
||||||
|
{
|
||||||
|
MetaMonitorInfo *monitor = &monitors[i];
|
||||||
|
int left, right, top, bottom;
|
||||||
|
|
||||||
|
left = monitor->rect.x;
|
||||||
|
right = left + monitor->rect.width;
|
||||||
|
top = monitor->rect.y;
|
||||||
|
bottom = left + monitor->rect.height;
|
||||||
|
|
||||||
|
if ((x >= left) && (x < right) && (y >= top) && (y < bottom))
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
constrain_all_screen_monitors (ClutterInputDevice *device,
|
||||||
|
MetaMonitorInfo *monitors,
|
||||||
|
unsigned n_monitors,
|
||||||
|
float *x,
|
||||||
|
float *y)
|
||||||
|
{
|
||||||
|
ClutterPoint current;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
clutter_input_device_get_coords (device, NULL, ¤t);
|
||||||
|
|
||||||
|
/* if we're trying to escape, clamp to the CRTC we're coming from */
|
||||||
|
for (i = 0; i < n_monitors; i++)
|
||||||
|
{
|
||||||
|
MetaMonitorInfo *monitor = &monitors[i];
|
||||||
|
int left, right, top, bottom;
|
||||||
|
float nx, ny;
|
||||||
|
|
||||||
|
left = monitor->rect.x;
|
||||||
|
right = left + monitor->rect.width;
|
||||||
|
top = monitor->rect.y;
|
||||||
|
bottom = left + monitor->rect.height;
|
||||||
|
|
||||||
|
nx = current.x;
|
||||||
|
ny = current.y;
|
||||||
|
|
||||||
|
if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom))
|
||||||
|
{
|
||||||
|
if (*x < left)
|
||||||
|
*x = left;
|
||||||
|
if (*x >= right)
|
||||||
|
*x = right - 1;
|
||||||
|
if (*y < top)
|
||||||
|
*y = top;
|
||||||
|
if (*y >= bottom)
|
||||||
|
*y = bottom - 1;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pointer_constrain_callback (ClutterInputDevice *device,
|
||||||
|
float *new_x,
|
||||||
|
float *new_y,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
MetaMonitorManager *monitor_manager;
|
||||||
|
MetaMonitorInfo *monitors;
|
||||||
|
unsigned int n_monitors;
|
||||||
|
gboolean ret;
|
||||||
|
|
||||||
|
monitor_manager = meta_monitor_manager_get ();
|
||||||
|
monitors = meta_monitor_manager_get_monitor_infos (monitor_manager, &n_monitors);
|
||||||
|
|
||||||
|
/* if we're moving inside a monitor, we're fine */
|
||||||
|
ret = check_all_screen_monitors(monitors, n_monitors, *new_x, *new_y);
|
||||||
|
if (ret == TRUE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* if we're trying to escape, clamp to the CRTC we're coming from */
|
||||||
|
constrain_all_screen_monitors(device, monitors, n_monitors, new_x, new_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_pointer_init (MetaWaylandPointer *pointer,
|
||||||
|
gboolean is_native)
|
||||||
|
{
|
||||||
|
ClutterDeviceManager *manager;
|
||||||
|
ClutterInputDevice *device;
|
||||||
|
ClutterPoint current;
|
||||||
|
|
||||||
memset (pointer, 0, sizeof *pointer);
|
memset (pointer, 0, sizeof *pointer);
|
||||||
wl_list_init (&pointer->resource_list);
|
wl_list_init (&pointer->resource_list);
|
||||||
pointer->focus_listener.notify = lose_pointer_focus;
|
pointer->focus_listener.notify = lose_pointer_focus;
|
||||||
@@ -131,9 +239,16 @@ meta_wayland_pointer_init (MetaWaylandPointer *pointer)
|
|||||||
pointer->grab = &pointer->default_grab;
|
pointer->grab = &pointer->default_grab;
|
||||||
wl_signal_init (&pointer->focus_signal);
|
wl_signal_init (&pointer->focus_signal);
|
||||||
|
|
||||||
/* FIXME: Pick better co-ords. */
|
manager = clutter_device_manager_get_default ();
|
||||||
pointer->x = wl_fixed_from_int (100);
|
device = clutter_device_manager_get_core_device (manager, CLUTTER_POINTER_DEVICE);
|
||||||
pointer->y = wl_fixed_from_int (100);
|
|
||||||
|
if (is_native)
|
||||||
|
clutter_evdev_set_pointer_constrain_callback (manager, pointer_constrain_callback,
|
||||||
|
pointer, NULL);
|
||||||
|
|
||||||
|
clutter_input_device_get_coords (device, NULL, ¤t);
|
||||||
|
pointer->x = wl_fixed_from_double (current.x);
|
||||||
|
pointer->y = wl_fixed_from_double (current.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@@ -60,7 +60,7 @@ struct _MetaWaylandPointer
|
|||||||
guint32 grab_serial;
|
guint32 grab_serial;
|
||||||
guint32 grab_time;
|
guint32 grab_time;
|
||||||
|
|
||||||
wl_fixed_t x, y;
|
wl_fixed_t x, y; /* TODO: remove, use ClutterInputDevice instead */
|
||||||
MetaWaylandSurface *current;
|
MetaWaylandSurface *current;
|
||||||
struct wl_listener current_listener;
|
struct wl_listener current_listener;
|
||||||
wl_fixed_t current_x, current_y;
|
wl_fixed_t current_x, current_y;
|
||||||
@@ -69,7 +69,8 @@ struct _MetaWaylandPointer
|
|||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_wayland_pointer_init (MetaWaylandPointer *pointer);
|
meta_wayland_pointer_init (MetaWaylandPointer *pointer,
|
||||||
|
gboolean is_native);
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_wayland_pointer_release (MetaWaylandPointer *pointer);
|
meta_wayland_pointer_release (MetaWaylandPointer *pointer);
|
||||||
|
@@ -104,6 +104,7 @@ void meta_wayland_compositor_set_input_focus (MetaWaylandComp
|
|||||||
MetaWindow *window);
|
MetaWindow *window);
|
||||||
|
|
||||||
MetaLauncher *meta_wayland_compositor_get_launcher (MetaWaylandCompositor *compositor);
|
MetaLauncher *meta_wayland_compositor_get_launcher (MetaWaylandCompositor *compositor);
|
||||||
|
gboolean meta_wayland_compositor_is_native (MetaWaylandCompositor *compositor);
|
||||||
|
|
||||||
MetaWaylandBuffer * meta_wayland_buffer_from_resource (struct wl_resource *resource);
|
MetaWaylandBuffer * meta_wayland_buffer_from_resource (struct wl_resource *resource);
|
||||||
|
|
||||||
|
@@ -284,7 +284,7 @@ meta_wayland_seat_new (struct wl_display *display,
|
|||||||
wl_list_init (&seat->drag_resource_list);
|
wl_list_init (&seat->drag_resource_list);
|
||||||
wl_signal_init (&seat->drag_icon_signal);
|
wl_signal_init (&seat->drag_icon_signal);
|
||||||
|
|
||||||
meta_wayland_pointer_init (&seat->pointer);
|
meta_wayland_pointer_init (&seat->pointer, is_native);
|
||||||
|
|
||||||
meta_wayland_keyboard_init (&seat->keyboard, display, is_native);
|
meta_wayland_keyboard_init (&seat->keyboard, display, is_native);
|
||||||
|
|
||||||
@@ -357,9 +357,8 @@ handle_button_event (MetaWaylandSeat *seat,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state)
|
/* FIXME: Handle in display.c */
|
||||||
{
|
if (state && pointer->button_count == 1)
|
||||||
if (pointer->button_count == 0)
|
|
||||||
{
|
{
|
||||||
MetaWaylandSurface *surface = pointer->current;
|
MetaWaylandSurface *surface = pointer->current;
|
||||||
|
|
||||||
@@ -377,11 +376,6 @@ handle_button_event (MetaWaylandSeat *seat,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer->button_count++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
pointer->button_count--;
|
|
||||||
|
|
||||||
pointer->grab->interface->button (pointer->grab, event->time, button, state);
|
pointer->grab->interface->button (pointer->grab, event->time, button, state);
|
||||||
|
|
||||||
if (pointer->button_count == 1)
|
if (pointer->button_count == 1)
|
||||||
@@ -430,10 +424,34 @@ handle_scroll_event (MetaWaylandSeat *seat,
|
|||||||
value);
|
value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static int
|
||||||
|
count_buttons (const ClutterEvent *event)
|
||||||
|
{
|
||||||
|
static gint maskmap[5] =
|
||||||
|
{
|
||||||
|
CLUTTER_BUTTON1_MASK, CLUTTER_BUTTON2_MASK, CLUTTER_BUTTON3_MASK,
|
||||||
|
CLUTTER_BUTTON4_MASK, CLUTTER_BUTTON5_MASK
|
||||||
|
};
|
||||||
|
ClutterModifierType mod_mask;
|
||||||
|
int i, count;
|
||||||
|
|
||||||
|
mod_mask = clutter_event_get_state (event);
|
||||||
|
count = 0;
|
||||||
|
for (i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
if (mod_mask & maskmap[i])
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
|
meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
|
||||||
const ClutterEvent *event)
|
const ClutterEvent *event)
|
||||||
{
|
{
|
||||||
|
seat->pointer.button_count = count_buttons (event);
|
||||||
|
|
||||||
switch (event->type)
|
switch (event->type)
|
||||||
{
|
{
|
||||||
case CLUTTER_MOTION:
|
case CLUTTER_MOTION:
|
||||||
@@ -449,9 +467,8 @@ meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
|
|||||||
|
|
||||||
case CLUTTER_KEY_PRESS:
|
case CLUTTER_KEY_PRESS:
|
||||||
case CLUTTER_KEY_RELEASE:
|
case CLUTTER_KEY_RELEASE:
|
||||||
meta_wayland_keyboard_handle_event (&seat->keyboard,
|
return meta_wayland_keyboard_handle_event (&seat->keyboard,
|
||||||
(const ClutterKeyEvent *) event);
|
(const ClutterKeyEvent *) event);
|
||||||
break;
|
|
||||||
|
|
||||||
case CLUTTER_SCROLL:
|
case CLUTTER_SCROLL:
|
||||||
handle_scroll_event (seat, (const ClutterScrollEvent *) event);
|
handle_scroll_event (seat, (const ClutterScrollEvent *) event);
|
||||||
@@ -460,6 +477,8 @@ meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@@ -90,7 +90,7 @@ MetaWaylandSeat *
|
|||||||
meta_wayland_seat_new (struct wl_display *display,
|
meta_wayland_seat_new (struct wl_display *display,
|
||||||
gboolean is_native);
|
gboolean is_native);
|
||||||
|
|
||||||
void
|
gboolean
|
||||||
meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
|
meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
|
||||||
const ClutterEvent *event);
|
const ClutterEvent *event);
|
||||||
|
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
#include <clutter/clutter.h>
|
#include <clutter/clutter.h>
|
||||||
#include <clutter/wayland/clutter-wayland-compositor.h>
|
#include <clutter/wayland/clutter-wayland-compositor.h>
|
||||||
#include <clutter/wayland/clutter-wayland-surface.h>
|
#include <clutter/wayland/clutter-wayland-surface.h>
|
||||||
|
#include <cogl/cogl-wayland-server.h>
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
@@ -64,8 +65,9 @@ static void
|
|||||||
surface_process_damage (MetaWaylandSurface *surface,
|
surface_process_damage (MetaWaylandSurface *surface,
|
||||||
cairo_region_t *region)
|
cairo_region_t *region)
|
||||||
{
|
{
|
||||||
if (surface->window &&
|
g_assert (surface->window);
|
||||||
surface->buffer_ref.buffer)
|
|
||||||
|
if (surface->buffer_ref.buffer)
|
||||||
{
|
{
|
||||||
MetaWindowActor *window_actor =
|
MetaWindowActor *window_actor =
|
||||||
META_WINDOW_ACTOR (meta_window_get_compositor_private (surface->window));
|
META_WINDOW_ACTOR (meta_window_get_compositor_private (surface->window));
|
||||||
@@ -111,7 +113,7 @@ static void
|
|||||||
meta_wayland_surface_attach (struct wl_client *wayland_client,
|
meta_wayland_surface_attach (struct wl_client *wayland_client,
|
||||||
struct wl_resource *wayland_surface_resource,
|
struct wl_resource *wayland_surface_resource,
|
||||||
struct wl_resource *wayland_buffer_resource,
|
struct wl_resource *wayland_buffer_resource,
|
||||||
gint32 sx, gint32 sy)
|
gint32 dx, gint32 dy)
|
||||||
{
|
{
|
||||||
MetaWaylandSurface *surface =
|
MetaWaylandSurface *surface =
|
||||||
wl_resource_get_user_data (wayland_surface_resource);
|
wl_resource_get_user_data (wayland_surface_resource);
|
||||||
@@ -130,8 +132,8 @@ meta_wayland_surface_attach (struct wl_client *wayland_client,
|
|||||||
if (surface->pending.buffer)
|
if (surface->pending.buffer)
|
||||||
wl_list_remove (&surface->pending.buffer_destroy_listener.link);
|
wl_list_remove (&surface->pending.buffer_destroy_listener.link);
|
||||||
|
|
||||||
surface->pending.sx = sx;
|
surface->pending.dx = dx;
|
||||||
surface->pending.sy = sy;
|
surface->pending.dy = dy;
|
||||||
surface->pending.buffer = buffer;
|
surface->pending.buffer = buffer;
|
||||||
surface->pending.newly_attached = TRUE;
|
surface->pending.newly_attached = TRUE;
|
||||||
|
|
||||||
@@ -247,36 +249,86 @@ meta_wayland_surface_commit (struct wl_client *client,
|
|||||||
if (surface->pending.newly_attached &&
|
if (surface->pending.newly_attached &&
|
||||||
surface->buffer_ref.buffer != surface->pending.buffer)
|
surface->buffer_ref.buffer != surface->pending.buffer)
|
||||||
{
|
{
|
||||||
|
MetaWaylandBuffer *buffer = surface->pending.buffer;
|
||||||
|
CoglContext *ctx =
|
||||||
|
clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||||
|
CoglError *catch_error = NULL;
|
||||||
|
CoglTexture *texture =
|
||||||
|
COGL_TEXTURE (cogl_wayland_texture_2d_new_from_buffer (ctx,
|
||||||
|
buffer->resource,
|
||||||
|
&catch_error));
|
||||||
|
if (!texture)
|
||||||
|
{
|
||||||
|
cogl_error_free (catch_error);
|
||||||
|
meta_warning ("Could not import pending buffer, ignoring commit\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer->texture = texture;
|
||||||
|
buffer->width = cogl_texture_get_width (texture);
|
||||||
|
buffer->height = cogl_texture_get_height (texture);
|
||||||
|
}
|
||||||
|
|
||||||
/* Note: we set this before informing any window-actor since the
|
/* Note: we set this before informing any window-actor since the
|
||||||
* window actor will expect to find the new buffer within the
|
* window actor will expect to find the new buffer within the
|
||||||
* surface. */
|
* surface. */
|
||||||
meta_wayland_buffer_reference (&surface->buffer_ref,
|
meta_wayland_buffer_reference (&surface->buffer_ref,
|
||||||
surface->pending.buffer);
|
surface->pending.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!surface->buffer_ref.buffer)
|
||||||
|
{
|
||||||
|
meta_warning ("Commit without a buffer? Ignoring\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (surface->initial_state)
|
||||||
|
{
|
||||||
|
MetaDisplay *display = meta_get_display ();
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
|
||||||
|
width = surface->buffer_ref.buffer->width;
|
||||||
|
height = surface->buffer_ref.buffer->height;
|
||||||
|
|
||||||
|
/* This will free and clear initial_state */
|
||||||
|
surface->window = meta_window_new_for_wayland (display, width, height, surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (surface == compositor->seat->sprite)
|
||||||
|
meta_wayland_seat_update_sprite (compositor->seat);
|
||||||
|
else if (surface->window)
|
||||||
|
{
|
||||||
|
MetaWindow *window = surface->window;
|
||||||
|
|
||||||
if (surface->pending.buffer)
|
if (surface->pending.buffer)
|
||||||
{
|
{
|
||||||
MetaWaylandBuffer *buffer = surface->pending.buffer;
|
MetaWaylandBuffer *buffer = surface->pending.buffer;
|
||||||
|
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
||||||
|
|
||||||
if (surface->window)
|
|
||||||
{
|
|
||||||
MetaWindow *window = surface->window;
|
|
||||||
MetaWindowActor *window_actor =
|
|
||||||
META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
|
||||||
MetaRectangle rect;
|
|
||||||
|
|
||||||
meta_window_get_input_rect (surface->window, &rect);
|
|
||||||
|
|
||||||
if (window_actor)
|
|
||||||
meta_window_actor_attach_wayland_buffer (window_actor, buffer);
|
meta_window_actor_attach_wayland_buffer (window_actor, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX: we resize X based surfaces according to X events */
|
/* We resize X based surfaces according to X events */
|
||||||
if (surface->xid == 0 &&
|
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
|
||||||
(buffer->width != rect.width || buffer->height != rect.height))
|
{
|
||||||
meta_window_resize (surface->window, FALSE, buffer->width, buffer->height);
|
int new_width;
|
||||||
}
|
int new_height;
|
||||||
else if (surface == compositor->seat->sprite)
|
|
||||||
meta_wayland_seat_update_sprite (compositor->seat);
|
new_width = surface->buffer_ref.buffer->width;
|
||||||
|
new_height = surface->buffer_ref.buffer->height;
|
||||||
|
if (new_width != window->rect.width ||
|
||||||
|
new_height != window->rect.height ||
|
||||||
|
surface->pending.dx != 0 ||
|
||||||
|
surface->pending.dy != 0)
|
||||||
|
meta_window_move_resize_wayland (surface->window, new_width, new_height,
|
||||||
|
surface->pending.dx, surface->pending.dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
meta_window_set_opaque_region (surface->window, surface->pending.opaque_region);
|
||||||
|
meta_window_set_input_region (surface->window, surface->pending.input_region);
|
||||||
|
surface_process_damage (surface, surface->pending.damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (surface->pending.buffer)
|
if (surface->pending.buffer)
|
||||||
@@ -284,20 +336,11 @@ meta_wayland_surface_commit (struct wl_client *client,
|
|||||||
wl_list_remove (&surface->pending.buffer_destroy_listener.link);
|
wl_list_remove (&surface->pending.buffer_destroy_listener.link);
|
||||||
surface->pending.buffer = NULL;
|
surface->pending.buffer = NULL;
|
||||||
}
|
}
|
||||||
surface->pending.sx = 0;
|
surface->pending.dx = 0;
|
||||||
surface->pending.sy = 0;
|
surface->pending.dy = 0;
|
||||||
surface->pending.newly_attached = FALSE;
|
surface->pending.newly_attached = FALSE;
|
||||||
|
|
||||||
if (surface->window)
|
|
||||||
{
|
|
||||||
meta_window_set_opaque_region (surface->window, surface->pending.opaque_region);
|
|
||||||
g_clear_pointer (&surface->pending.opaque_region, cairo_region_destroy);
|
g_clear_pointer (&surface->pending.opaque_region, cairo_region_destroy);
|
||||||
|
|
||||||
meta_window_set_input_region (surface->window, surface->pending.input_region);
|
|
||||||
g_clear_pointer (&surface->pending.input_region, cairo_region_destroy);
|
g_clear_pointer (&surface->pending.input_region, cairo_region_destroy);
|
||||||
}
|
|
||||||
|
|
||||||
surface_process_damage (surface, surface->pending.damage);
|
|
||||||
empty_region (surface->pending.damage);
|
empty_region (surface->pending.damage);
|
||||||
|
|
||||||
/* wl_surface.frame */
|
/* wl_surface.frame */
|
||||||
@@ -632,34 +675,6 @@ shell_surface_resize (struct wl_client *client,
|
|||||||
g_warning ("TODO: support shell_surface_resize request");
|
g_warning ("TODO: support shell_surface_resize request");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
ensure_surface_window (MetaWaylandSurface *surface)
|
|
||||||
{
|
|
||||||
MetaDisplay *display = meta_get_display ();
|
|
||||||
|
|
||||||
if (!surface->window)
|
|
||||||
{
|
|
||||||
int width, height;
|
|
||||||
|
|
||||||
if (surface->buffer_ref.buffer)
|
|
||||||
{
|
|
||||||
MetaWaylandBuffer *buffer = surface->buffer_ref.buffer;
|
|
||||||
width = buffer->width;
|
|
||||||
height = buffer->width;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
width = 0;
|
|
||||||
height = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
surface->window =
|
|
||||||
meta_window_new_for_wayland (display, width, height, surface);
|
|
||||||
|
|
||||||
meta_window_calc_showing (surface->window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
shell_surface_set_toplevel (struct wl_client *client,
|
shell_surface_set_toplevel (struct wl_client *client,
|
||||||
struct wl_resource *resource)
|
struct wl_resource *resource)
|
||||||
@@ -672,9 +687,19 @@ shell_surface_set_toplevel (struct wl_client *client,
|
|||||||
if (client == compositor->xwayland_client)
|
if (client == compositor->xwayland_client)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ensure_surface_window (surface);
|
if (surface->window)
|
||||||
|
{
|
||||||
|
if (surface->window->fullscreen)
|
||||||
meta_window_unmake_fullscreen (surface->window);
|
meta_window_unmake_fullscreen (surface->window);
|
||||||
|
if (meta_window_get_maximized (surface->window) != 0)
|
||||||
|
meta_window_unmaximize (surface->window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ensure_initial_state (surface);
|
||||||
|
|
||||||
|
surface->initial_state->initial_type = META_WAYLAND_SURFACE_TOPLEVEL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -687,13 +712,22 @@ shell_surface_set_transient (struct wl_client *client,
|
|||||||
{
|
{
|
||||||
MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
|
MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
|
||||||
MetaWaylandSurface *surface = shell_surface->surface;
|
MetaWaylandSurface *surface = shell_surface->surface;
|
||||||
|
MetaWaylandSurface *parent_surface = wl_resource_get_user_data (parent);
|
||||||
MetaWaylandCompositor *compositor = surface->compositor;
|
MetaWaylandCompositor *compositor = surface->compositor;
|
||||||
|
|
||||||
/* NB: Surfaces from xwayland become managed based on X events. */
|
/* NB: Surfaces from xwayland become managed based on X events. */
|
||||||
if (client == compositor->xwayland_client)
|
if (client == compositor->xwayland_client)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ensure_surface_window (surface);
|
if (surface->window)
|
||||||
|
meta_window_set_transient_for (surface->window, parent_surface->window);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ensure_initial_state (surface);
|
||||||
|
|
||||||
|
surface->initial_state->initial_type = META_WAYLAND_SURFACE_TOPLEVEL;
|
||||||
|
surface->initial_state->transient_for = parent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -711,9 +745,14 @@ shell_surface_set_fullscreen (struct wl_client *client,
|
|||||||
if (client == compositor->xwayland_client)
|
if (client == compositor->xwayland_client)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ensure_surface_window (surface);
|
if (surface->window)
|
||||||
|
|
||||||
meta_window_make_fullscreen (surface->window);
|
meta_window_make_fullscreen (surface->window);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ensure_initial_state (surface);
|
||||||
|
|
||||||
|
surface->initial_state->initial_type = META_WAYLAND_SURFACE_FULLSCREEN;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -733,7 +772,22 @@ shell_surface_set_maximized (struct wl_client *client,
|
|||||||
struct wl_resource *resource,
|
struct wl_resource *resource,
|
||||||
struct wl_resource *output)
|
struct wl_resource *output)
|
||||||
{
|
{
|
||||||
g_warning ("TODO: support shell_surface_set_maximized request");
|
MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
|
||||||
|
MetaWaylandSurface *surface = shell_surface->surface;
|
||||||
|
MetaWaylandCompositor *compositor = surface->compositor;
|
||||||
|
|
||||||
|
/* NB: Surfaces from xwayland become managed based on X events. */
|
||||||
|
if (client == compositor->xwayland_client)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (surface->window)
|
||||||
|
meta_window_maximize (surface->window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ensure_initial_state (surface);
|
||||||
|
|
||||||
|
surface->initial_state->initial_type = META_WAYLAND_SURFACE_MAXIMIZED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -813,7 +867,7 @@ destroy_surface_extension (struct wl_resource *resource)
|
|||||||
g_free (extension);
|
g_free (extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static MetaWaylandSurfaceExtension *
|
||||||
create_surface_extension (struct wl_client *client,
|
create_surface_extension (struct wl_client *client,
|
||||||
struct wl_resource *master_resource,
|
struct wl_resource *master_resource,
|
||||||
guint32 id,
|
guint32 id,
|
||||||
@@ -834,6 +888,8 @@ create_surface_extension (struct wl_client *client,
|
|||||||
extension->surface_destroy_listener.notify = extension_handle_surface_destroy;
|
extension->surface_destroy_listener.notify = extension_handle_surface_destroy;
|
||||||
wl_resource_add_destroy_listener (surface->resource,
|
wl_resource_add_destroy_listener (surface->resource,
|
||||||
&extension->surface_destroy_listener);
|
&extension->surface_destroy_listener);
|
||||||
|
|
||||||
|
return extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -844,7 +900,7 @@ get_shell_surface (struct wl_client *client,
|
|||||||
{
|
{
|
||||||
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
||||||
|
|
||||||
if (surface->has_shell_surface)
|
if (surface->shell_surface)
|
||||||
{
|
{
|
||||||
wl_resource_post_error (surface_resource,
|
wl_resource_post_error (surface_resource,
|
||||||
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
||||||
@@ -852,10 +908,9 @@ get_shell_surface (struct wl_client *client,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
create_surface_extension (client, resource, id, surface,
|
surface->shell_surface = create_surface_extension (client, resource, id, surface,
|
||||||
&wl_shell_surface_interface,
|
&wl_shell_surface_interface,
|
||||||
&meta_wayland_shell_surface_interface);
|
&meta_wayland_shell_surface_interface);
|
||||||
surface->has_shell_surface = TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_shell_interface meta_wayland_shell_interface =
|
static const struct wl_shell_interface meta_wayland_shell_interface =
|
||||||
@@ -946,7 +1001,7 @@ get_gtk_surface (struct wl_client *client,
|
|||||||
{
|
{
|
||||||
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
||||||
|
|
||||||
if (surface->has_gtk_surface)
|
if (surface->gtk_surface)
|
||||||
{
|
{
|
||||||
wl_resource_post_error (surface_resource,
|
wl_resource_post_error (surface_resource,
|
||||||
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
||||||
@@ -954,10 +1009,9 @@ get_gtk_surface (struct wl_client *client,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
create_surface_extension (client, resource, id, surface,
|
surface->gtk_surface = create_surface_extension (client, resource, id, surface,
|
||||||
>k_surface_interface,
|
>k_surface_interface,
|
||||||
&meta_wayland_gtk_surface_interface);
|
&meta_wayland_gtk_surface_interface);
|
||||||
surface->has_gtk_surface = TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct gtk_shell_interface meta_wayland_gtk_shell_interface =
|
static const struct gtk_shell_interface meta_wayland_gtk_shell_interface =
|
||||||
@@ -1003,6 +1057,29 @@ meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface,
|
|||||||
if (initial == NULL)
|
if (initial == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Note that we poke at the bits directly here, because we're
|
||||||
|
in the middle of meta_window_new_shared() */
|
||||||
|
switch (initial->initial_type)
|
||||||
|
{
|
||||||
|
case META_WAYLAND_SURFACE_TOPLEVEL:
|
||||||
|
break;
|
||||||
|
case META_WAYLAND_SURFACE_FULLSCREEN:
|
||||||
|
window->fullscreen = TRUE;
|
||||||
|
break;
|
||||||
|
case META_WAYLAND_SURFACE_MAXIMIZED:
|
||||||
|
window->maximized_horizontally = window->maximized_vertically = TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initial->transient_for)
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *parent = wl_resource_get_user_data (initial->transient_for);
|
||||||
|
if (parent)
|
||||||
|
window->transient_for = g_object_ref (parent->window);
|
||||||
|
}
|
||||||
|
|
||||||
if (initial->title)
|
if (initial->title)
|
||||||
meta_window_set_title (window, initial->title);
|
meta_window_set_title (window, initial->title);
|
||||||
|
|
||||||
@@ -1045,3 +1122,14 @@ free_initial_state (MetaWaylandSurfaceInitialState *initial)
|
|||||||
|
|
||||||
g_slice_free (MetaWaylandSurfaceInitialState, initial);
|
g_slice_free (MetaWaylandSurfaceInitialState, initial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
|
||||||
|
int new_width,
|
||||||
|
int new_height,
|
||||||
|
int edges)
|
||||||
|
{
|
||||||
|
if (surface->shell_surface)
|
||||||
|
wl_shell_surface_send_configure (surface->shell_surface->resource,
|
||||||
|
edges, new_width, new_height);
|
||||||
|
}
|
||||||
|
@@ -36,6 +36,7 @@ struct _MetaWaylandBuffer
|
|||||||
struct wl_signal destroy_signal;
|
struct wl_signal destroy_signal;
|
||||||
struct wl_listener destroy_listener;
|
struct wl_listener destroy_listener;
|
||||||
|
|
||||||
|
CoglTexture *texture;
|
||||||
int32_t width, height;
|
int32_t width, height;
|
||||||
uint32_t busy_count;
|
uint32_t busy_count;
|
||||||
};
|
};
|
||||||
@@ -52,8 +53,8 @@ typedef struct
|
|||||||
gboolean newly_attached;
|
gboolean newly_attached;
|
||||||
MetaWaylandBuffer *buffer;
|
MetaWaylandBuffer *buffer;
|
||||||
struct wl_listener buffer_destroy_listener;
|
struct wl_listener buffer_destroy_listener;
|
||||||
int32_t sx;
|
int32_t dx;
|
||||||
int32_t sy;
|
int32_t dy;
|
||||||
|
|
||||||
/* wl_surface.damage */
|
/* wl_surface.damage */
|
||||||
cairo_region_t *damage;
|
cairo_region_t *damage;
|
||||||
@@ -65,8 +66,17 @@ typedef struct
|
|||||||
struct wl_list frame_callback_list;
|
struct wl_list frame_callback_list;
|
||||||
} MetaWaylandDoubleBufferedState;
|
} MetaWaylandDoubleBufferedState;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
META_WAYLAND_SURFACE_TOPLEVEL = 0,
|
||||||
|
META_WAYLAND_SURFACE_MAXIMIZED,
|
||||||
|
META_WAYLAND_SURFACE_FULLSCREEN
|
||||||
|
} MetaWaylandSurfaceType;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
MetaWaylandSurfaceType initial_type;
|
||||||
|
struct wl_resource *transient_for;
|
||||||
|
|
||||||
char *title;
|
char *title;
|
||||||
char *wm_class;
|
char *wm_class;
|
||||||
|
|
||||||
@@ -78,17 +88,21 @@ typedef struct
|
|||||||
char *gtk_window_object_path;
|
char *gtk_window_object_path;
|
||||||
} MetaWaylandSurfaceInitialState;
|
} MetaWaylandSurfaceInitialState;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *surface;
|
||||||
|
struct wl_resource *resource;
|
||||||
|
struct wl_listener surface_destroy_listener;
|
||||||
|
} MetaWaylandSurfaceExtension;
|
||||||
|
|
||||||
struct _MetaWaylandSurface
|
struct _MetaWaylandSurface
|
||||||
{
|
{
|
||||||
struct wl_resource *resource;
|
struct wl_resource *resource;
|
||||||
MetaWaylandCompositor *compositor;
|
MetaWaylandCompositor *compositor;
|
||||||
guint32 xid;
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
MetaWaylandBufferReference buffer_ref;
|
MetaWaylandBufferReference buffer_ref;
|
||||||
MetaWindow *window;
|
MetaWindow *window;
|
||||||
gboolean has_shell_surface;
|
MetaWaylandSurfaceExtension *shell_surface;
|
||||||
gboolean has_gtk_surface;
|
MetaWaylandSurfaceExtension *gtk_surface;
|
||||||
|
|
||||||
/* All the pending state, that wl_surface.commit will apply. */
|
/* All the pending state, that wl_surface.commit will apply. */
|
||||||
MetaWaylandDoubleBufferedState pending;
|
MetaWaylandDoubleBufferedState pending;
|
||||||
@@ -98,13 +112,6 @@ struct _MetaWaylandSurface
|
|||||||
MetaWaylandSurfaceInitialState *initial_state;
|
MetaWaylandSurfaceInitialState *initial_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
MetaWaylandSurface *surface;
|
|
||||||
struct wl_resource *resource;
|
|
||||||
struct wl_listener surface_destroy_listener;
|
|
||||||
} MetaWaylandSurfaceExtension;
|
|
||||||
|
|
||||||
void meta_wayland_init_shell (MetaWaylandCompositor *compositor);
|
void meta_wayland_init_shell (MetaWaylandCompositor *compositor);
|
||||||
|
|
||||||
MetaWaylandSurface *meta_wayland_surface_create (MetaWaylandCompositor *compositor,
|
MetaWaylandSurface *meta_wayland_surface_create (MetaWaylandCompositor *compositor,
|
||||||
@@ -116,4 +123,9 @@ void meta_wayland_surface_free (MetaWaylandSurface *surface)
|
|||||||
void meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface,
|
void meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface,
|
||||||
MetaWindow *window);
|
MetaWindow *window);
|
||||||
|
|
||||||
|
void meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int edges);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -32,6 +32,8 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <wayland-server.h>
|
#include <wayland-server.h>
|
||||||
|
|
||||||
@@ -185,6 +187,7 @@ meta_wayland_buffer_reference (MetaWaylandBufferReference *ref,
|
|||||||
|
|
||||||
if (ref->buffer->busy_count == 0)
|
if (ref->buffer->busy_count == 0)
|
||||||
{
|
{
|
||||||
|
g_clear_pointer (&ref->buffer->texture, cogl_object_unref);
|
||||||
g_assert (wl_resource_get_client (ref->buffer->resource));
|
g_assert (wl_resource_get_client (ref->buffer->resource));
|
||||||
wl_resource_queue_event (ref->buffer->resource, WL_BUFFER_RELEASE);
|
wl_resource_queue_event (ref->buffer->resource, WL_BUFFER_RELEASE);
|
||||||
}
|
}
|
||||||
@@ -530,117 +533,6 @@ stage_destroy_cb (void)
|
|||||||
|
|
||||||
#define N_BUTTONS 5
|
#define N_BUTTONS 5
|
||||||
|
|
||||||
static void
|
|
||||||
synthesize_motion_event (MetaWaylandCompositor *compositor,
|
|
||||||
const ClutterEvent *event)
|
|
||||||
{
|
|
||||||
/* We want to synthesize X events for mouse motion events so that we
|
|
||||||
don't have to rely on the X server's window position being
|
|
||||||
synched with the surface position. See the comment in
|
|
||||||
event_callback() in display.c */
|
|
||||||
MetaWaylandSeat *seat = compositor->seat;
|
|
||||||
MetaWaylandPointer *pointer = &seat->pointer;
|
|
||||||
MetaWaylandSurface *surface;
|
|
||||||
XGenericEventCookie generic_event;
|
|
||||||
XIDeviceEvent device_event;
|
|
||||||
unsigned char button_mask[(N_BUTTONS + 7) / 8] = { 0 };
|
|
||||||
MetaDisplay *display = meta_get_display ();
|
|
||||||
ClutterModifierType state;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
generic_event.type = GenericEvent;
|
|
||||||
generic_event.serial = 0;
|
|
||||||
generic_event.send_event = False;
|
|
||||||
generic_event.display = display->xdisplay;
|
|
||||||
generic_event.extension = display->xinput_opcode;
|
|
||||||
generic_event.evtype = XI_Motion;
|
|
||||||
/* Mutter assumes the data for the event is already retrieved by GDK
|
|
||||||
* so we don't need the cookie */
|
|
||||||
generic_event.cookie = 0;
|
|
||||||
generic_event.data = &device_event;
|
|
||||||
|
|
||||||
memcpy (&device_event, &generic_event, sizeof (XGenericEvent));
|
|
||||||
|
|
||||||
device_event.time = clutter_event_get_time (event);
|
|
||||||
device_event.deviceid = clutter_event_get_device_id (event);
|
|
||||||
device_event.sourceid = 0; /* not used, not sure what this should be */
|
|
||||||
device_event.detail = 0;
|
|
||||||
device_event.root = DefaultRootWindow (display->xdisplay);
|
|
||||||
device_event.flags = 0 /* not used for motion events */;
|
|
||||||
|
|
||||||
if (compositor->implicit_grab_surface)
|
|
||||||
surface = compositor->implicit_grab_surface;
|
|
||||||
else
|
|
||||||
surface = pointer->current;
|
|
||||||
|
|
||||||
if (surface == pointer->current)
|
|
||||||
{
|
|
||||||
device_event.event_x = wl_fixed_to_int (pointer->current_x);
|
|
||||||
device_event.event_y = wl_fixed_to_int (pointer->current_y);
|
|
||||||
}
|
|
||||||
else if (surface && surface->window)
|
|
||||||
{
|
|
||||||
ClutterActor *window_actor =
|
|
||||||
CLUTTER_ACTOR (meta_window_get_compositor_private (surface->window));
|
|
||||||
|
|
||||||
if (window_actor)
|
|
||||||
{
|
|
||||||
float ax, ay;
|
|
||||||
|
|
||||||
clutter_actor_transform_stage_point (window_actor,
|
|
||||||
wl_fixed_to_double (pointer->x),
|
|
||||||
wl_fixed_to_double (pointer->y),
|
|
||||||
&ax, &ay);
|
|
||||||
|
|
||||||
device_event.event_x = ax;
|
|
||||||
device_event.event_y = ay;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
device_event.event_x = wl_fixed_to_double (pointer->x);
|
|
||||||
device_event.event_y = wl_fixed_to_double (pointer->y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
device_event.event_x = wl_fixed_to_double (pointer->x);
|
|
||||||
device_event.event_y = wl_fixed_to_double (pointer->y);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (surface && surface->xid != None)
|
|
||||||
device_event.event = surface->xid;
|
|
||||||
else
|
|
||||||
device_event.event = device_event.root;
|
|
||||||
|
|
||||||
/* Mutter doesn't really know about the sub-windows. This assumes it
|
|
||||||
doesn't care either */
|
|
||||||
device_event.child = device_event.event;
|
|
||||||
device_event.root_x = wl_fixed_to_double (pointer->x);
|
|
||||||
device_event.root_y = wl_fixed_to_double (pointer->y);
|
|
||||||
|
|
||||||
state = clutter_event_get_state (event);
|
|
||||||
|
|
||||||
for (i = 0; i < N_BUTTONS; i++)
|
|
||||||
if ((state & (CLUTTER_BUTTON1_MASK << i)))
|
|
||||||
XISetMask (button_mask, i + 1);
|
|
||||||
device_event.buttons.mask_len = N_BUTTONS + 1;
|
|
||||||
device_event.buttons.mask = button_mask;
|
|
||||||
|
|
||||||
device_event.valuators.mask_len = 0;
|
|
||||||
device_event.valuators.mask = NULL;
|
|
||||||
device_event.valuators.values = NULL;
|
|
||||||
|
|
||||||
memset (&device_event.mods, 0, sizeof (device_event.mods));
|
|
||||||
device_event.mods.effective =
|
|
||||||
state & (CLUTTER_MODIFIER_MASK &
|
|
||||||
~(((CLUTTER_BUTTON1_MASK << N_BUTTONS) - 1) ^
|
|
||||||
(CLUTTER_BUTTON1_MASK - 1)));
|
|
||||||
|
|
||||||
memset (&device_event.group, 0, sizeof (device_event.group));
|
|
||||||
|
|
||||||
meta_display_handle_event (display, (XEvent *) &generic_event);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
reset_idletimes (const ClutterEvent *event)
|
reset_idletimes (const ClutterEvent *event)
|
||||||
{
|
{
|
||||||
@@ -667,10 +559,10 @@ reset_idletimes (const ClutterEvent *event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
event_cb (ClutterActor *stage,
|
event_filter_cb (const ClutterEvent *event,
|
||||||
const ClutterEvent *event,
|
gpointer user_data)
|
||||||
MetaWaylandCompositor *compositor)
|
|
||||||
{
|
{
|
||||||
|
MetaWaylandCompositor *compositor = user_data;
|
||||||
MetaWaylandSeat *seat = compositor->seat;
|
MetaWaylandSeat *seat = compositor->seat;
|
||||||
MetaWaylandPointer *pointer = &seat->pointer;
|
MetaWaylandPointer *pointer = &seat->pointer;
|
||||||
MetaWaylandSurface *surface;
|
MetaWaylandSurface *surface;
|
||||||
@@ -678,7 +570,8 @@ event_cb (ClutterActor *stage,
|
|||||||
|
|
||||||
reset_idletimes (event);
|
reset_idletimes (event);
|
||||||
|
|
||||||
meta_wayland_seat_handle_event (compositor->seat, event);
|
if (meta_wayland_seat_handle_event (compositor->seat, event))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
/* HACK: for now, the surfaces from Wayland clients aren't
|
/* HACK: for now, the surfaces from Wayland clients aren't
|
||||||
integrated into Mutter's event handling and Mutter won't give them
|
integrated into Mutter's event handling and Mutter won't give them
|
||||||
@@ -708,7 +601,8 @@ event_cb (ClutterActor *stage,
|
|||||||
if (pointer->current == NULL)
|
if (pointer->current == NULL)
|
||||||
meta_cursor_tracker_revert_root (seat->cursor_tracker);
|
meta_cursor_tracker_revert_root (seat->cursor_tracker);
|
||||||
|
|
||||||
meta_cursor_tracker_queue_redraw (seat->cursor_tracker, stage);
|
meta_cursor_tracker_queue_redraw (seat->cursor_tracker,
|
||||||
|
CLUTTER_ACTOR (event->any.stage));
|
||||||
}
|
}
|
||||||
|
|
||||||
display = meta_get_display ();
|
display = meta_get_display ();
|
||||||
@@ -732,67 +626,11 @@ event_cb (ClutterActor *stage,
|
|||||||
compositor->implicit_grab_surface = NULL;
|
compositor->implicit_grab_surface = NULL;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
case CLUTTER_MOTION:
|
|
||||||
synthesize_motion_event (compositor, event);
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
event_emission_hook_cb (GSignalInvocationHint *ihint,
|
|
||||||
guint n_param_values,
|
|
||||||
const GValue *param_values,
|
|
||||||
gpointer data)
|
|
||||||
{
|
|
||||||
MetaWaylandCompositor *compositor = data;
|
|
||||||
ClutterActor *actor;
|
|
||||||
ClutterEvent *event;
|
|
||||||
|
|
||||||
g_return_val_if_fail (n_param_values == 2, FALSE);
|
|
||||||
|
|
||||||
actor = g_value_get_object (param_values + 0);
|
|
||||||
event = g_value_get_boxed (param_values + 1);
|
|
||||||
|
|
||||||
if (actor == NULL)
|
|
||||||
return TRUE /* stay connected */;
|
|
||||||
|
|
||||||
/* If this event belongs to the corresponding grab for this event
|
|
||||||
* type then the captured-event signal won't be emitted so we have
|
|
||||||
* to manually forward it on */
|
|
||||||
|
|
||||||
switch (event->type)
|
|
||||||
{
|
|
||||||
/* Pointer events */
|
|
||||||
case CLUTTER_MOTION:
|
|
||||||
case CLUTTER_ENTER:
|
|
||||||
case CLUTTER_LEAVE:
|
|
||||||
case CLUTTER_BUTTON_PRESS:
|
|
||||||
case CLUTTER_BUTTON_RELEASE:
|
|
||||||
case CLUTTER_SCROLL:
|
|
||||||
if (actor == clutter_get_pointer_grab ())
|
|
||||||
event_cb (clutter_actor_get_stage (actor),
|
|
||||||
event,
|
|
||||||
compositor);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Keyboard events */
|
|
||||||
case CLUTTER_KEY_PRESS:
|
|
||||||
case CLUTTER_KEY_RELEASE:
|
|
||||||
if (actor == clutter_get_keyboard_grab ())
|
|
||||||
event_cb (clutter_actor_get_stage (actor),
|
|
||||||
event,
|
|
||||||
compositor);
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE /* stay connected */;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_monitors_changed (MetaMonitorManager *monitors,
|
on_monitors_changed (MetaMonitorManager *monitors,
|
||||||
MetaWaylandCompositor *compositor)
|
MetaWaylandCompositor *compositor)
|
||||||
@@ -800,15 +638,44 @@ on_monitors_changed (MetaMonitorManager *monitors,
|
|||||||
compositor->outputs = meta_wayland_compositor_update_outputs (compositor, monitors);
|
compositor->outputs = meta_wayland_compositor_update_outputs (compositor, monitors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_gnome_env (const char *name,
|
||||||
|
const char *value)
|
||||||
|
{
|
||||||
|
GDBusConnection *session_bus;
|
||||||
|
GError *error;
|
||||||
|
|
||||||
|
setenv (name, value, TRUE);
|
||||||
|
|
||||||
|
session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
|
||||||
|
g_assert (session_bus);
|
||||||
|
|
||||||
|
error = NULL;
|
||||||
|
g_dbus_connection_call_sync (session_bus,
|
||||||
|
"org.gnome.SessionManager",
|
||||||
|
"/org/gnome/SessionManager",
|
||||||
|
"org.gnome.SessionManager",
|
||||||
|
"Setenv",
|
||||||
|
g_variant_new ("(ss)", name, value),
|
||||||
|
NULL,
|
||||||
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
-1, NULL, &error);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
meta_warning ("Failed to set environment variable %s for gnome-session: %s\n", name, error->message);
|
||||||
|
g_clear_error (&error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_wayland_init (void)
|
meta_wayland_init (void)
|
||||||
{
|
{
|
||||||
MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
|
MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
|
||||||
guint event_signal;
|
|
||||||
MetaMonitorManager *monitors;
|
MetaMonitorManager *monitors;
|
||||||
ClutterBackend *backend;
|
ClutterBackend *backend;
|
||||||
CoglContext *cogl_context;
|
CoglContext *cogl_context;
|
||||||
CoglRenderer *cogl_renderer;
|
CoglRenderer *cogl_renderer;
|
||||||
|
char *display_name;
|
||||||
|
|
||||||
memset (compositor, 0, sizeof (MetaWaylandCompositor));
|
memset (compositor, 0, sizeof (MetaWaylandCompositor));
|
||||||
|
|
||||||
@@ -851,6 +718,9 @@ meta_wayland_init (void)
|
|||||||
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
|
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
|
||||||
g_error ("Failed to initialize Clutter");
|
g_error ("Failed to initialize Clutter");
|
||||||
|
|
||||||
|
unsetenv ("CLUTTER_BACKEND");
|
||||||
|
unsetenv ("CLUTTER_INPUT_BACKEND");
|
||||||
|
|
||||||
backend = clutter_get_default_backend ();
|
backend = clutter_get_default_backend ();
|
||||||
cogl_context = clutter_backend_get_cogl_context (backend);
|
cogl_context = clutter_backend_get_cogl_context (backend);
|
||||||
cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (cogl_context));
|
cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (cogl_context));
|
||||||
@@ -891,20 +761,7 @@ meta_wayland_init (void)
|
|||||||
compositor->seat = meta_wayland_seat_new (compositor->wayland_display,
|
compositor->seat = meta_wayland_seat_new (compositor->wayland_display,
|
||||||
compositor->drm_fd >= 0);
|
compositor->drm_fd >= 0);
|
||||||
|
|
||||||
g_signal_connect (compositor->stage,
|
clutter_event_add_filter (event_filter_cb, compositor);
|
||||||
"captured-event",
|
|
||||||
G_CALLBACK (event_cb),
|
|
||||||
compositor);
|
|
||||||
/* If something sets a grab on an actor then the captured event
|
|
||||||
* signal won't get emitted but we still want to see these events so
|
|
||||||
* we can update the cursor position. To make sure we see all events
|
|
||||||
* we also install an emission hook on the event signal */
|
|
||||||
event_signal = g_signal_lookup ("event", CLUTTER_TYPE_STAGE);
|
|
||||||
g_signal_add_emission_hook (event_signal,
|
|
||||||
0 /* detail */,
|
|
||||||
event_emission_hook_cb,
|
|
||||||
compositor, /* hook_data */
|
|
||||||
NULL /* data_destroy */);
|
|
||||||
|
|
||||||
meta_wayland_init_shell (compositor);
|
meta_wayland_init_shell (compositor);
|
||||||
|
|
||||||
@@ -926,7 +783,11 @@ meta_wayland_init (void)
|
|||||||
if (!meta_xwayland_start (compositor))
|
if (!meta_xwayland_start (compositor))
|
||||||
g_error ("Failed to start X Wayland");
|
g_error ("Failed to start X Wayland");
|
||||||
|
|
||||||
putenv (g_strdup_printf ("DISPLAY=:%d", compositor->xwayland_display_index));
|
display_name = g_strdup_printf (":%d", compositor->xwayland_display_index);
|
||||||
|
set_gnome_env ("DISPLAY", display_name);
|
||||||
|
g_free (display_name);
|
||||||
|
|
||||||
|
set_gnome_env ("WAYLAND_DISPLAY", "wayland-0");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -936,6 +797,8 @@ meta_wayland_finalize (void)
|
|||||||
|
|
||||||
compositor = meta_wayland_compositor_get_default ();
|
compositor = meta_wayland_compositor_get_default ();
|
||||||
|
|
||||||
|
clutter_event_remove_filter (event_filter_cb, compositor);
|
||||||
|
|
||||||
meta_xwayland_stop (compositor);
|
meta_xwayland_stop (compositor);
|
||||||
g_clear_object (&compositor->launcher);
|
g_clear_object (&compositor->launcher);
|
||||||
}
|
}
|
||||||
@@ -945,3 +808,9 @@ meta_wayland_compositor_get_launcher (MetaWaylandCompositor *compositor)
|
|||||||
{
|
{
|
||||||
return compositor->launcher;
|
return compositor->launcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_wayland_compositor_is_native (MetaWaylandCompositor *compositor)
|
||||||
|
{
|
||||||
|
return compositor->drm_fd >= 0;
|
||||||
|
}
|
||||||
|
@@ -45,10 +45,6 @@ xserver_set_window_id (struct wl_client *client,
|
|||||||
MetaDisplay *display = meta_get_display ();
|
MetaDisplay *display = meta_get_display ();
|
||||||
MetaWindow *window;
|
MetaWindow *window;
|
||||||
|
|
||||||
g_return_if_fail (surface->xid == None);
|
|
||||||
|
|
||||||
surface->xid = xid;
|
|
||||||
|
|
||||||
window = meta_display_lookup_x_window (display, xid);
|
window = meta_display_lookup_x_window (display, xid);
|
||||||
if (window)
|
if (window)
|
||||||
{
|
{
|
||||||
@@ -269,7 +265,7 @@ bind_to_unix_socket (int display)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
uncloexec_and_setpgid (gpointer user_data)
|
uncloexec (gpointer user_data)
|
||||||
{
|
{
|
||||||
int fd = GPOINTER_TO_INT (user_data);
|
int fd = GPOINTER_TO_INT (user_data);
|
||||||
|
|
||||||
@@ -278,10 +274,6 @@ uncloexec_and_setpgid (gpointer user_data)
|
|||||||
int flags = fcntl (fd, F_GETFD);
|
int flags = fcntl (fd, F_GETFD);
|
||||||
if (flags != -1)
|
if (flags != -1)
|
||||||
fcntl (fd, F_SETFD, flags & ~FD_CLOEXEC);
|
fcntl (fd, F_SETFD, flags & ~FD_CLOEXEC);
|
||||||
|
|
||||||
/* Put this process in a background process group, so that Ctrl-C
|
|
||||||
goes to mutter only */
|
|
||||||
setpgid (0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -401,7 +393,7 @@ meta_xwayland_start (MetaWaylandCompositor *compositor)
|
|||||||
G_SPAWN_DO_NOT_REAP_CHILD |
|
G_SPAWN_DO_NOT_REAP_CHILD |
|
||||||
G_SPAWN_STDOUT_TO_DEV_NULL |
|
G_SPAWN_STDOUT_TO_DEV_NULL |
|
||||||
G_SPAWN_STDERR_TO_DEV_NULL,
|
G_SPAWN_STDERR_TO_DEV_NULL,
|
||||||
uncloexec_and_setpgid,
|
uncloexec,
|
||||||
GINT_TO_POINTER (sp[1]),
|
GINT_TO_POINTER (sp[1]),
|
||||||
&pid,
|
&pid,
|
||||||
&error))
|
&error))
|
||||||
|
Reference in New Issue
Block a user