Compare commits

..

1 Commits

Author SHA1 Message Date
Jasper St. Pierre
2afbf369af double-buffer place_above/place_below 2014-01-15 20:05:31 -05:00
81 changed files with 8345 additions and 6097 deletions

3
.gitignore vendored
View File

@@ -79,10 +79,13 @@ src/meta-dbus-xrandr.[ch]
src/meta-dbus-idle-monitor.[ch]
src/mutter-plugins.pc
src/wayland/gtk-shell-protocol.c
src/wayland/gtk-shell-client-protocol.h
src/wayland/gtk-shell-server-protocol.h
src/wayland/xdg-shell-protocol.c
src/wayland/xdg-shell-client-protocol.h
src/wayland/xdg-shell-server-protocol.h
src/wayland/xserver-protocol.c
src/wayland/xserver-client-protocol.h
src/wayland/xserver-server-protocol.h
doc/reference/*.args
doc/reference/*.bak

36
NEWS
View File

@@ -1,39 +1,3 @@
3.11.90
=======
* Fix double-scaling on high DPI resolutions [Adel; #723931]
* Make tile previews a compositor effect [Stefano, Florian; #665758]
* Misc. bug fixes and cleanups [Ryan, Giovanni, Jasper, Adel; #722530, #724257,
#724258, #720631, #724364, #724472]
Contributors:
Giovanni Campagna, Marek Chalupa, Stefano Facchini, Adel Gadllah,
Ryan Lortie, Florian Müllner, Jasper St. Pierre, Rico Tzschichholz
3.11.5
======
* Fix CSD titlebars being placed off-screen [Jasper; #719772]
* Add support for subsurfaces [Jonas; #705502]
* Expose MetaWindow:skip-taskbar property [Florian; #723307]
* Fix legacy tray icons showing up blank [Adel; #721596]
* Fix configuration of cloned monitors [Adel; #710610]
* Misc bug fixes and cleanups [Jasper, Adel, Marek, Jonas; #720631, #723468,
#720818, #723563, #723564]
Contributors:
Jonas Ådahl, Marek Ch, Adel Gadllah, Florian Müllner, Jasper St. Pierre
3.11.4
======
* Don't leave focus on windows that are being unmanaged [Owen; #711618]
* Reduce server grabs [Daniel Drake; #721345, #721709]
* Improve heuristic to determine display output name [Cosimo Cecchi; #721674]
* Atomically unmaximize both directions [Jasper; #722108]
* Misc bug fixes [Debarshi, Andika, Florian; #721517, #721674, #722347]
Contributors:
Cosimo Cecchi, Daniel Drake, Florian Müllner, Debarshi Ray, Jasper St. Pierre,
Andika Triwidada, Owen W. Taylor
3.11.3
======
* Fix focus issues with external OSKs[Jasper; #715030]

View File

@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Run this to generate all the initial makefiles, etc.
srcdir=`dirname $0`

View File

@@ -3,7 +3,7 @@ AC_CONFIG_MACRO_DIR([m4])
m4_define([mutter_major_version], [3])
m4_define([mutter_minor_version], [11])
m4_define([mutter_micro_version], [90])
m4_define([mutter_micro_version], [3])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
@@ -78,7 +78,7 @@ MUTTER_PC_MODULES="
cairo >= 1.10.0
gsettings-desktop-schemas >= 3.7.3
xcomposite >= 0.2 xfixes xrender xdamage xi >= 1.6.0
$CLUTTER_PACKAGE >= 1.17.5
$CLUTTER_PACKAGE >= 1.17.1
cogl-1.0 >= 1.17.1
upower-glib >= 0.99.0
gnome-desktop-3.0
@@ -212,6 +212,9 @@ fi
MUTTER_PC_MODULES="$MUTTER_PC_MODULES xcursor"
# We always build with wayland enabled
AC_DEFINE(HAVE_WAYLAND, , [Building with Wayland support])
AC_PATH_PROG([WAYLAND_SCANNER],[wayland-scanner],[no])
AS_IF([test "x$WAYLAND_SCANNER" = "xno"],
AC_MSG_ERROR([Could not find wayland-scanner in your PATH, required for parsing wayland extension protocols]))

View File

@@ -96,6 +96,8 @@ meta_compositor_hide_window
meta_compositor_switch_workspace
meta_compositor_maximize_window
meta_compositor_unmaximize_window
meta_compositor_window_mapped
meta_compositor_window_unmapped
meta_compositor_sync_window_geometry
meta_compositor_set_updates_frozen
meta_compositor_queue_frame_drawn

View File

@@ -43,7 +43,7 @@
Use this enum to check the protocol version, and it will be updated
automatically.
</description>
<entry name="current" value="2" summary="Always the latest version"/>
<entry name="current" value="1" summary="Always the latest version"/>
</enum>
@@ -84,28 +84,6 @@
<arg name="y" type="int"/>
<arg name="flags" type="uint"/>
</request>
<event name="ping">
<description summary="check if the client is alive">
The ping event asks the client if it's still alive. Pass the
serial specified in the event back to the compositor by sending
a "pong" request back with the specified serial.
Compositors can use this to determine if the client is still
alive. It's unspecified what will happen if the client doesn't
respond to the ping request, or in what timeframe. Clients should
try to respond in a reasonable amount of time.
</description>
<arg name="serial" type="uint" summary="pass this to the callback"/>
</event>
<request name="pong">
<description summary="respond to a ping event">
A client must respond to a ping event with a pong request or
the client may be deemed unresponsive.
</description>
<arg name="serial" type="uint" summary="serial of the ping event"/>
</request>
</interface>
<interface name="xdg_surface" version="1">
@@ -146,32 +124,6 @@
<arg name="parent" type="object" interface="wl_surface" allow-null="true"/>
</request>
<request name="set_margin">
<description summary="set the visible frame boundaries">
This tells the compositor what the visible size of the window
should be, so it can use it to determine what borders to use for
constrainment and alignment.
CSD often has invisible areas for decoration purposes, like drop
shadows. These "shadow" drawings need to be subtracted out of the
normal boundaries of the window when computing where to place
windows (e.g. to set this window so it's centered on top of another,
or to put it to the left or right of the screen.)
This value should change as little as possible at runtime, to
prevent flicker.
This value is also ignored when the window is maximized or
fullscreen, and assumed to be 0.
If never called, this value is assumed to be 0.
</description>
<arg name="left_margin" type="int"/>
<arg name="right_margin" type="int"/>
<arg name="top_margin" type="int"/>
<arg name="bottom_margin" type="int"/>
</request>
<request name="set_title">
<description summary="set surface title">
Set a short title for the surface.
@@ -198,6 +150,22 @@
<arg name="app_id" type="string"/>
</request>
<request name="pong">
<description summary="respond to a ping event">
A client must respond to a ping event with a pong request or
the client may be deemed unresponsive.
</description>
<arg name="serial" type="uint" summary="serial of the ping event"/>
</request>
<event name="ping">
<description summary="ping client">
Ping a client to check if it is receiving events and sending
requests. A client is expected to reply with a pong request.
</description>
<arg name="serial" type="uint"/>
</event>
<request name="move">
<description summary="start an interactive move">
Start a pointer-driven move of the surface.
@@ -249,6 +217,12 @@
ignore it if it doesn't resize, pick a smaller size (to
satisfy aspect ratio or resize in steps of NxM pixels).
The edges parameter provides a hint about how the surface
was resized. The client may use this information to decide
how to adjust its content to the new size (e.g. a scrolling
area might adjust its content position to leave the viewable
content unmoved). Valid edge values are from resize_edge enum.
The client is free to dismiss all but the last configure
event it received.
@@ -256,6 +230,7 @@
in surface local coordinates.
</description>
<arg name="edges" type="uint"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
</event>
@@ -385,38 +360,18 @@
</description>
</request>
<event name="activated">
<description summary="surface was activated">
The activated_set event is sent when this surface has been
activated, which means that the surface has user attention.
Window decorations should be updated accordingly. You should
not use this event for anything but the style of decorations
you display, use wl_keyboard.enter and wl_keyboard.leave for
determining keyboard focus.
<event name="focused_set">
<description summary="surface was focused">
The focused_set event is sent when this surface has been
activated. Window decorations should be updated accordingly.
</description>
</event>
<event name="deactivated">
<description summary="surface was deactivated">
The deactivate event is sent when this surface has been
deactivated, which means that the surface lost user attention.
Window decorations should be updated accordingly. You should
not use this event for anything but the style of decorations
you display, use wl_keyboard.enter and wl_keyboard.leave for
determining keyboard focus.
</description>
</event>
<event name="delete">
<description summary="surface wants to be closed">
The delete event is sent by the compositor when the user
wants the surface to be closed. This should be equivalent to
the user clicking the close button in client-side decorations,
if your application has any...
This is only a request that the user intends to close your
window. The client may choose to ignore this request, or show
a dialog to ask the user to save their data...
<event name="focused_unset">
<description summary="surface was unfocused">
The focused_unset event is sent when this surface has been
deactivated, because another surface has been activated. Window
decorations should be updated accordingly.
</description>
</event>
</interface>
@@ -454,6 +409,22 @@
</description>
</request>
<request name="pong">
<description summary="respond to a ping event">
A client must respond to a ping event with a pong request or
the client may be deemed unresponsive.
</description>
<arg name="serial" type="uint" summary="serial of the ping event"/>
</request>
<event name="ping">
<description summary="ping client">
Ping a client to check if it is receiving events and sending
requests. A client is expected to reply with a pong request.
</description>
<arg name="serial" type="uint"/>
</event>
<event name="popup_done">
<description summary="popup interaction is done">
The popup_done event is sent out when a popup grab is broken,

View File

@@ -29,18 +29,6 @@
<KeyListEntry name="move-to-workspace-down"
_description="Move window one workspace down" />
<KeyListEntry name="move-to-monitor-left"
_description="Move window one monitor to the left" />
<KeyListEntry name="move-to-monitor-right"
_description="Move window one monitor to the right" />
<KeyListEntry name="move-to-monitor-up"
_description="Move window one monitor up" />
<KeyListEntry name="move-to-monitor-down"
_description="Move window one monitor down" />
<KeyListEntry name="switch-applications"
_description="Switch applications"/>

View File

@@ -6,7 +6,6 @@ lib_LTLIBRARIES = libmutter-wayland.la
SUBDIRS=compositor/plugins
INCLUDES= \
-DCLUTTER_ENABLE_COMPOSITOR_API \
-DCLUTTER_ENABLE_EXPERIMENTAL_API \
-DCOGL_ENABLE_EXPERIMENTAL_API \
-DCOGL_ENABLE_EXPERIMENTAL_2_0_API \
@@ -43,10 +42,13 @@ mutter_built_sources = \
mutter-enum-types.c \
wayland/gtk-shell-protocol.c \
wayland/gtk-shell-server-protocol.h \
wayland/gtk-shell-client-protocol.h \
wayland/xdg-shell-protocol.c \
wayland/xdg-shell-server-protocol.h \
wayland/xdg-shell-client-protocol.h \
wayland/xserver-protocol.c \
wayland/xserver-server-protocol.h
wayland/xserver-server-protocol.h \
wayland/xserver-client-protocol.h
libmutter_wayland_la_SOURCES = \
core/async-getprop.c \
@@ -81,10 +83,6 @@ libmutter_wayland_la_SOURCES = \
compositor/meta-shaped-texture-private.h \
compositor/meta-surface-actor.c \
compositor/meta-surface-actor.h \
compositor/meta-surface-actor-x11.c \
compositor/meta-surface-actor-x11.h \
compositor/meta-surface-actor-wayland.c \
compositor/meta-surface-actor-wayland.h \
compositor/meta-texture-rectangle.c \
compositor/meta-texture-rectangle.h \
compositor/meta-texture-tower.c \
@@ -113,6 +111,8 @@ libmutter_wayland_la_SOURCES = \
core/display.c \
core/display-private.h \
meta/display.h \
ui/draw-workspace.c \
ui/draw-workspace.h \
core/edge-resistance.c \
core/edge-resistance.h \
core/edid-parse.c \
@@ -163,8 +163,6 @@ libmutter_wayland_la_SOURCES = \
core/util-private.h \
core/window-props.c \
core/window-props.h \
core/window-x11.c \
core/window-x11.h \
core/window.c \
core/window-private.h \
meta/window.h \
@@ -183,13 +181,21 @@ libmutter_wayland_la_SOURCES = \
ui/metaaccellabel.h \
ui/resizepopup.c \
ui/resizepopup.h \
ui/tabpopup.c \
ui/tabpopup.h \
ui/tile-preview.c \
ui/tile-preview.h \
ui/theme-parser.c \
ui/theme.c \
meta/theme.h \
ui/theme-private.h \
ui/ui.c \
ui/ui.c
nodist_libmutter_wayland_la_SOURCES = \
$(mutter_built_sources)
libmutter_wayland_la_SOURCES += \
wayland/meta-wayland.c \
wayland/meta-wayland.h \
wayland/meta-wayland-private.h \
wayland/meta-xwayland-private.h \
wayland/meta-xwayland.c \
@@ -210,9 +216,6 @@ libmutter_wayland_la_SOURCES = \
wayland/meta-weston-launch.c \
wayland/meta-weston-launch.h
nodist_libmutter_wayland_la_SOURCES = \
$(mutter_built_sources)
libmutter_wayland_la_LDFLAGS = -no-undefined
libmutter_wayland_la_LIBADD = $(MUTTER_LIBS)
@@ -415,3 +418,6 @@ wayland/%-protocol.c : $(top_builddir)/protocol/%.xml
wayland/%-server-protocol.h : $(top_builddir)/protocol/%.xml
mkdir -p wayland
$(AM_V_GEN)$(WAYLAND_SCANNER) server-header < $< > $@
wayland/%-client-protocol.h : $(top_builddir)/protocol/%.xml
mkdir -p wayland
$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@

View File

@@ -46,8 +46,11 @@ struct _MetaCompScreen
CoglFrameClosure *frame_closure;
/* Used for unredirecting fullscreen windows */
guint disable_unredirect_count;
MetaWindow *unredirected_window;
guint disable_unredirect_count;
MetaWindowActor *unredirected_window;
/* Before we create the output window */
XserverRegion pending_input_region;
gint switch_workspace_in_progress;

View File

@@ -42,6 +42,15 @@
* the call, so it may be necessary to readjust the display based on the
* old_rect to start the animation.
*
* meta_compositor_window_mapped() and meta_compositor_window_unmapped() are
* notifications when the toplevel window (frame or client window) is mapped or
* unmapped. That is, when the result of meta_window_toplevel_is_mapped()
* changes. The main use of this is to drop resources when a window is unmapped.
* A window will always be mapped before meta_compositor_show_window()
* is called and will not be unmapped until after meta_compositor_hide_window()
* is called. If the live_hidden_windows preference is set, windows will never
* be unmapped.
*
* # Containers #
*
* There's two containers in the stage that are used to place window actors, here
@@ -76,7 +85,6 @@
#include "window-private.h" /* to check window->hidden */
#include "display-private.h" /* for meta_display_lookup_x_window() */
#include "util-private.h"
#include "frame.h"
#include "meta-wayland-private.h"
#include "meta-wayland-pointer.h"
#include "meta-wayland-keyboard.h"
@@ -275,6 +283,25 @@ meta_get_window_actors (MetaScreen *screen)
return info->windows;
}
static void
do_set_stage_input_region (MetaScreen *screen,
XserverRegion region)
{
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdpy = meta_display_get_xdisplay (display);
Window xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region);
/* It's generally a good heuristic that when a crossing event is generated because
* we reshape the overlay, we don't want it to affect focus-follows-mouse focus -
* it's not the user doing something, it's the environment changing under the user.
*/
meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy));
XFixesSetWindowShapeRegion (xdpy, info->output, ShapeInput, 0, 0, region);
}
void
meta_set_stage_input_region (MetaScreen *screen,
XserverRegion region)
@@ -286,19 +313,29 @@ meta_set_stage_input_region (MetaScreen *screen,
*/
if (!meta_is_wayland_compositor ())
{
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdpy = meta_display_get_xdisplay (display);
Window xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdpy = meta_display_get_xdisplay (display);
XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region);
/* It's generally a good heuristic that when a crossing event is generated because
* we reshape the overlay, we don't want it to affect focus-follows-mouse focus -
* it's not the user doing something, it's the environment changing under the user.
*/
meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy));
XFixesSetWindowShapeRegion (xdpy, info->output, ShapeInput, 0, 0, region);
if (info->stage && info->output)
{
do_set_stage_input_region (screen, region);
}
else
{
/* Reset info->pending_input_region if one existed before and set the new
* one to use it later. */
if (info->pending_input_region)
{
XFixesDestroyRegion (xdpy, info->pending_input_region);
info->pending_input_region = None;
}
if (region != None)
{
info->pending_input_region = XFixesCreateRegion (xdpy, NULL, 0);
XFixesCopyRegion (xdpy, info->pending_input_region, region);
}
}
}
}
@@ -330,36 +367,39 @@ meta_focus_stage_window (MetaScreen *screen,
if (!stage)
return;
window = clutter_x11_get_stage_window (stage);
if (!meta_is_wayland_compositor ())
{
window = clutter_x11_get_stage_window (stage);
if (window == None)
return;
if (window == None)
return;
meta_display_set_input_focus_xwindow (screen->display,
screen,
window,
timestamp);
meta_display_set_input_focus_xwindow (screen->display,
screen,
META_FOCUS_STAGE,
window,
timestamp);
}
else
{
meta_display_set_input_focus_xwindow (screen->display,
screen,
META_FOCUS_STAGE,
None,
timestamp);
}
}
gboolean
meta_stage_is_focused (MetaScreen *screen)
{
ClutterStage *stage;
Window window;
if (meta_is_wayland_compositor ())
return TRUE;
stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen));
if (!stage)
return FALSE;
window = clutter_x11_get_stage_window (stage);
if (window == None)
return FALSE;
return (screen->display->focus_xwindow == window);
return (screen->display->focus_type == META_FOCUS_STAGE);
}
static gboolean
@@ -637,6 +677,21 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
return;
info = g_new0 (MetaCompScreen, 1);
/*
* We use an empty input region for Clutter as a default because that allows
* the user to interact with all the windows displayed on the screen.
* We have to initialize info->pending_input_region to an empty region explicitly,
* because None value is used to mean that the whole screen is an input region.
*/
if (!meta_is_wayland_compositor ())
info->pending_input_region = XFixesCreateRegion (xdisplay, NULL, 0);
else
{
/* Stage input region trickery isn't needed when we're running as a
* wayland compositor. */
info->pending_input_region = None;
}
info->screen = screen;
meta_screen_set_compositor_data (screen, info);
@@ -722,8 +777,6 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
info->output = get_output_window (screen);
XReparentWindow (xdisplay, xwin, info->output, 0, 0);
meta_empty_stage_input_region (screen);
/* Make sure there isn't any left-over output shape on the
* overlay window by setting the whole screen to be an
* output region.
@@ -734,6 +787,13 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
*/
XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None);
do_set_stage_input_region (screen, info->pending_input_region);
if (info->pending_input_region != None)
{
XFixesDestroyRegion (xdisplay, info->pending_input_region);
info->pending_input_region = None;
}
/* Map overlay window before redirecting windows offscreen so we catch their
* contents until we show the stage.
*/
@@ -803,30 +863,6 @@ meta_shape_cow_for_window (MetaScreen *screen,
}
}
static void
set_unredirected_window (MetaCompScreen *info,
MetaWindow *window)
{
if (info->unredirected_window == window)
return;
if (info->unredirected_window != NULL)
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (info->unredirected_window));
meta_window_actor_set_unredirected (window_actor, FALSE);
}
info->unredirected_window = window;
if (info->unredirected_window != NULL)
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (info->unredirected_window));
meta_window_actor_set_unredirected (window_actor, TRUE);
}
meta_shape_cow_for_window (info->screen, info->unredirected_window);
}
void
meta_compositor_add_window (MetaCompositor *compositor,
MetaWindow *window)
@@ -855,11 +891,19 @@ meta_compositor_remove_window (MetaCompositor *compositor,
if (!window_actor)
return;
screen = meta_window_get_screen (window);
info = meta_screen_get_compositor_data (screen);
if (!meta_is_wayland_compositor ())
{
screen = meta_window_get_screen (window);
info = meta_screen_get_compositor_data (screen);
if (info->unredirected_window == window)
set_unredirected_window (info, NULL);
if (window_actor == info->unredirected_window)
{
meta_window_actor_set_redirected (window_actor, TRUE);
meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (info->unredirected_window)),
NULL);
info->unredirected_window = NULL;
}
}
meta_window_actor_destroy (window_actor);
}
@@ -941,66 +985,6 @@ meta_compositor_window_opacity_changed (MetaCompositor *compositor,
meta_window_actor_update_opacity (window_actor);
}
void
meta_compositor_window_surface_changed (MetaCompositor *compositor,
MetaWindow *window)
{
MetaWindowActor *window_actor;
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
if (!window_actor)
return;
meta_window_actor_update_surface (window_actor);
}
static gboolean
grab_op_is_clicking (MetaGrabOp grab_op)
{
switch (grab_op)
{
case META_GRAB_OP_CLICKING_MINIMIZE:
case META_GRAB_OP_CLICKING_MAXIMIZE:
case META_GRAB_OP_CLICKING_UNMAXIMIZE:
case META_GRAB_OP_CLICKING_DELETE:
case META_GRAB_OP_CLICKING_MENU:
case META_GRAB_OP_CLICKING_SHADE:
case META_GRAB_OP_CLICKING_UNSHADE:
case META_GRAB_OP_CLICKING_ABOVE:
case META_GRAB_OP_CLICKING_UNABOVE:
case META_GRAB_OP_CLICKING_STICK:
case META_GRAB_OP_CLICKING_UNSTICK:
return TRUE;
default:
return FALSE;
}
}
static gboolean
event_is_passive_button_grab (MetaDisplay *display,
XIDeviceEvent *device_event)
{
/* see display.c for which events are passive button
grabs (meta_display_grab_window_buttons() and
meta_display_handle_events())
we need to filter them here because normally they
would be sent to gtk+ (they are on gtk+ frame xwindow),
but we want to redirect them to clutter
*/
if (device_event->evtype != XI_ButtonPress)
return FALSE;
if (display->window_grab_modifiers == 0)
return FALSE;
if ((device_event->mods.effective & display->window_grab_modifiers) !=
display->window_grab_modifiers)
return FALSE;
return device_event->detail < 4;
}
/* Clutter makes the assumption that there is only one X window
* per stage, which is a valid assumption to make for a generic
* application toolkit. As such, it will ignore any events sent
@@ -1012,7 +996,6 @@ event_is_passive_button_grab (MetaDisplay *display,
*/
static void
maybe_spoof_event_as_stage_event (MetaCompScreen *info,
MetaWindow *window,
XEvent *event)
{
MetaDisplay *display = meta_screen_get_display (info->screen);
@@ -1021,30 +1004,24 @@ maybe_spoof_event_as_stage_event (MetaCompScreen *info,
event->xcookie.extension == display->xinput_opcode)
{
XIEvent *input_event = (XIEvent *) event->xcookie.data;
XIDeviceEvent *device_event = ((XIDeviceEvent *) input_event);
switch (input_event->evtype)
{
case XI_Motion:
case XI_ButtonPress:
case XI_ButtonRelease:
/* If this is a window frame, and we think GTK+ needs to handle the event,
let GTK+ handle it without mangling */
if (window && window->frame && device_event->event == window->frame->xwindow &&
(grab_op_is_clicking (display->grab_op) ||
(display->grab_op == META_GRAB_OP_NONE && !event_is_passive_button_grab (display, device_event))))
break;
case XI_KeyPress:
case XI_KeyRelease:
{
XIDeviceEvent *device_event = ((XIDeviceEvent *) input_event);
/* If this is a GTK+ widget, like a window menu, let GTK+ handle
* it as-is without mangling. */
if (meta_ui_window_is_widget (info->screen->ui, device_event->event))
break;
device_event->event = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
device_event->event_x = device_event->root_x;
device_event->event_y = device_event->root_y;
}
break;
default:
break;
@@ -1064,12 +1041,6 @@ meta_compositor_process_event (MetaCompositor *compositor,
XEvent *event,
MetaWindow *window)
{
MetaDisplay *display = compositor->display;
MetaScreen *screen = display->screens->data;
MetaCompScreen *info;
info = meta_screen_get_compositor_data (screen);
if (compositor->modal_plugin && is_grabbed_event (compositor->display, event))
{
_meta_plugin_xevent_filter (compositor->modal_plugin, event);
@@ -1079,13 +1050,43 @@ meta_compositor_process_event (MetaCompositor *compositor,
return TRUE;
}
if (!meta_is_wayland_compositor ())
maybe_spoof_event_as_stage_event (info, window, event);
if (meta_plugin_manager_xevent_filter (info->plugin_mgr, event))
if (window)
{
DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n");
return TRUE;
MetaCompScreen *info;
MetaScreen *screen;
screen = meta_window_get_screen (window);
info = meta_screen_get_compositor_data (screen);
if (meta_plugin_manager_xevent_filter (info->plugin_mgr, event))
{
DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n");
return TRUE;
}
}
else
{
GSList *l;
l = meta_display_get_screens (compositor->display);
while (l)
{
MetaScreen *screen = l->data;
MetaCompScreen *info;
info = meta_screen_get_compositor_data (screen);
maybe_spoof_event_as_stage_event (info, event);
if (meta_plugin_manager_xevent_filter (info->plugin_mgr, event))
{
DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n");
return TRUE;
}
l = l->next;
}
}
if (!meta_is_wayland_compositor () &&
@@ -1401,6 +1402,30 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
sync_actor_stacking (info);
}
void
meta_compositor_window_mapped (MetaCompositor *compositor,
MetaWindow *window)
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
DEBUG_TRACE ("meta_compositor_window_mapped\n");
if (!window_actor)
return;
meta_window_actor_mapped (window_actor);
}
void
meta_compositor_window_unmapped (MetaCompositor *compositor,
MetaWindow *window)
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
DEBUG_TRACE ("meta_compositor_window_unmapped\n");
if (!window_actor)
return;
meta_window_actor_unmapped (window_actor);
}
void
meta_compositor_sync_window_geometry (MetaCompositor *compositor,
MetaWindow *window,
@@ -1508,6 +1533,7 @@ pre_paint_windows (MetaCompScreen *info)
{
GList *l;
MetaWindowActor *top_window;
MetaWindowActor *expected_unredirected_window = NULL;
if (info->onscreen == NULL)
{
@@ -1521,13 +1547,33 @@ pre_paint_windows (MetaCompScreen *info)
if (info->windows == NULL)
return;
top_window = g_list_last (info->windows)->data;
if (!meta_is_wayland_compositor ())
{
top_window = g_list_last (info->windows)->data;
if (meta_window_actor_should_unredirect (top_window) &&
info->disable_unredirect_count == 0)
set_unredirected_window (info, meta_window_actor_get_meta_window (top_window));
else
set_unredirected_window (info, NULL);
if (meta_window_actor_should_unredirect (top_window) &&
info->disable_unredirect_count == 0)
expected_unredirected_window = top_window;
if (info->unredirected_window != expected_unredirected_window)
{
if (info->unredirected_window != NULL)
{
meta_window_actor_set_redirected (info->unredirected_window, TRUE);
meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (info->unredirected_window)),
NULL);
}
if (expected_unredirected_window != NULL)
{
meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (top_window)),
meta_window_actor_get_meta_window (top_window));
meta_window_actor_set_redirected (top_window, FALSE);
}
info->unredirected_window = expected_unredirected_window;
}
}
for (l = info->windows; l; l = l->next)
meta_window_actor_pre_paint (l->data);
@@ -1742,31 +1788,3 @@ meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
else
return monotonic_time + compositor->server_time_offset;
}
void
meta_compositor_show_tile_preview (MetaCompositor *compositor,
MetaScreen *screen,
MetaWindow *window,
MetaRectangle *tile_rect,
int tile_monitor_number)
{
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
if (!info->plugin_mgr)
return;
meta_plugin_manager_show_tile_preview (info->plugin_mgr,
window, tile_rect, tile_monitor_number);
}
void
meta_compositor_hide_tile_preview (MetaCompositor *compositor,
MetaScreen *screen)
{
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
if (!info->plugin_mgr)
return;
meta_plugin_manager_hide_tile_preview (info->plugin_mgr);
}

View File

@@ -70,16 +70,10 @@ meta_cullable_cull_out_children (MetaCullable *cullable,
while (clutter_actor_iter_prev (&iter, &child))
{
float x, y;
gboolean needs_culling;
if (!META_IS_CULLABLE (child))
if (!CLUTTER_ACTOR_IS_VISIBLE (child))
continue;
needs_culling = (unobscured_region != NULL && clip_region != NULL);
if (needs_culling && !CLUTTER_ACTOR_IS_VISIBLE (child))
needs_culling = FALSE;
/* If an actor has effects applied, then that can change the area
* it paints and the opacity, so we no longer can figure out what
* portion of the actor is obscured and what portion of the screen
@@ -96,29 +90,25 @@ meta_cullable_cull_out_children (MetaCullable *cullable,
* as well for the same reason, but omitted for simplicity in the
* hopes that no-one will do that.
*/
if (needs_culling && clutter_actor_has_effects (child))
needs_culling = FALSE;
if (clutter_actor_has_effects (child))
continue;
if (needs_culling && !meta_actor_is_untransformed (child, NULL, NULL))
needs_culling = FALSE;
if (!META_IS_CULLABLE (child))
continue;
if (needs_culling)
{
clutter_actor_get_position (child, &x, &y);
if (!meta_actor_is_untransformed (child, NULL, NULL))
continue;
/* Temporarily move to the coordinate system of the actor */
cairo_region_translate (unobscured_region, - x, - y);
cairo_region_translate (clip_region, - x, - y);
clutter_actor_get_position (child, &x, &y);
meta_cullable_cull_out (META_CULLABLE (child), unobscured_region, clip_region);
/* Temporarily move to the coordinate system of the actor */
cairo_region_translate (unobscured_region, - x, - y);
cairo_region_translate (clip_region, - x, - y);
cairo_region_translate (unobscured_region, x, y);
cairo_region_translate (clip_region, x, y);
}
else
{
meta_cullable_cull_out (META_CULLABLE (child), NULL, NULL);
}
meta_cullable_cull_out (META_CULLABLE (child), unobscured_region, clip_region);
cairo_region_translate (unobscured_region, x, y);
cairo_region_translate (clip_region, x, y);
}
}

View File

@@ -324,44 +324,3 @@ meta_plugin_manager_confirm_display_change (MetaPluginManager *plugin_mgr)
else
return meta_plugin_complete_display_change (plugin, TRUE);
}
gboolean
meta_plugin_manager_show_tile_preview (MetaPluginManager *plugin_mgr,
MetaWindow *window,
MetaRectangle *tile_rect,
int tile_monitor_number)
{
MetaPlugin *plugin = plugin_mgr->plugin;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
if (display->display_opening)
return FALSE;
if (klass->show_tile_preview)
{
klass->show_tile_preview (plugin, window, tile_rect, tile_monitor_number);
return TRUE;
}
return FALSE;
}
gboolean
meta_plugin_manager_hide_tile_preview (MetaPluginManager *plugin_mgr)
{
MetaPlugin *plugin = plugin_mgr->plugin;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
if (display->display_opening)
return FALSE;
if (klass->hide_tile_preview)
{
klass->hide_tile_preview (plugin);
return TRUE;
}
return FALSE;
}

View File

@@ -75,9 +75,4 @@ gboolean _meta_plugin_xevent_filter (MetaPlugin *plugin,
void meta_plugin_manager_confirm_display_change (MetaPluginManager *mgr);
gboolean meta_plugin_manager_show_tile_preview (MetaPluginManager *mgr,
MetaWindow *window,
MetaRectangle *tile_rect,
int tile_monitor_number);
gboolean meta_plugin_manager_hide_tile_preview (MetaPluginManager *mgr);
#endif

View File

@@ -30,7 +30,6 @@
#include "meta-plugin-manager.h"
#include <meta/screen.h>
#include <meta/display.h>
#include <meta/util.h>
#include <string.h>
#include <X11/Xlib.h>

View File

@@ -32,8 +32,5 @@
ClutterActor *meta_shaped_texture_new (void);
void meta_shaped_texture_set_texture (MetaShapedTexture *stex,
CoglTexture *texture);
gboolean meta_shaped_texture_get_unobscured_bounds (MetaShapedTexture *stex,
cairo_rectangle_int_t *unobscured_bounds);
gboolean meta_shaped_texture_is_obscured (MetaShapedTexture *self);
#endif

View File

@@ -33,7 +33,6 @@
#include "meta-texture-tower.h"
#include "meta-shaped-texture-private.h"
#include "meta-window-actor-private.h"
#include <clutter/clutter.h>
#include <cogl/cogl.h>
@@ -43,6 +42,8 @@
static void meta_shaped_texture_dispose (GObject *object);
static void meta_shaped_texture_paint (ClutterActor *actor);
static void meta_shaped_texture_pick (ClutterActor *actor,
const ClutterColor *color);
static void meta_shaped_texture_get_preferred_width (ClutterActor *self,
gfloat for_height,
@@ -72,12 +73,9 @@ struct _MetaShapedTexturePrivate
CoglTexture *texture;
CoglTexture *mask_texture;
/* The region containing only fully opaque pixels */
cairo_region_t *opaque_region;
/* MetaCullable regions, see that documentation for more details */
cairo_region_t *clip_region;
cairo_region_t *unobscured_region;
cairo_region_t *input_shape_region;
cairo_region_t *opaque_region;
guint tex_width, tex_height;
@@ -95,6 +93,7 @@ meta_shaped_texture_class_init (MetaShapedTextureClass *klass)
actor_class->get_preferred_width = meta_shaped_texture_get_preferred_width;
actor_class->get_preferred_height = meta_shaped_texture_get_preferred_height;
actor_class->paint = meta_shaped_texture_paint;
actor_class->pick = meta_shaped_texture_pick;
actor_class->get_paint_volume = meta_shaped_texture_get_paint_volume;
g_type_class_add_private (klass, sizeof (MetaShapedTexturePrivate));
@@ -114,21 +113,6 @@ meta_shaped_texture_init (MetaShapedTexture *self)
priv->create_mipmaps = TRUE;
}
static void
set_unobscured_region (MetaShapedTexture *self,
cairo_region_t *unobscured_region)
{
MetaShapedTexturePrivate *priv = self->priv;
g_clear_pointer (&priv->unobscured_region, (GDestroyNotify) cairo_region_destroy);
if (unobscured_region)
{
cairo_rectangle_int_t bounds = { 0, 0, priv->tex_width, priv->tex_height };
priv->unobscured_region = cairo_region_copy (unobscured_region);
cairo_region_intersect_rectangle (priv->unobscured_region, &bounds);
}
}
static void
set_clip_region (MetaShapedTexture *self,
cairo_region_t *clip_region)
@@ -154,7 +138,6 @@ meta_shaped_texture_dispose (GObject *object)
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
meta_shaped_texture_set_mask_texture (self, NULL);
set_unobscured_region (self, NULL);
set_clip_region (self, NULL);
G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object);
@@ -459,6 +442,71 @@ meta_shaped_texture_paint (ClutterActor *actor)
cairo_region_destroy (blended_region);
}
static void
meta_shaped_texture_pick (ClutterActor *actor,
const ClutterColor *color)
{
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
MetaShapedTexturePrivate *priv = stex->priv;
if (!clutter_actor_should_pick_paint (actor) ||
(priv->clip_region && cairo_region_is_empty (priv->clip_region)))
return;
/* If there is no region then use the regular pick */
if (priv->input_shape_region == NULL)
CLUTTER_ACTOR_CLASS (meta_shaped_texture_parent_class)->pick (actor, color);
else
{
int n_rects;
float *rectangles;
int i;
CoglPipeline *pipeline;
CoglContext *ctx;
CoglFramebuffer *fb;
CoglColor cogl_color;
/* Note: We don't bother trying to intersect the pick and clip regions
* since needing to copy the region, do the intersection, and probably
* increase the number of rectangles seems more likely to have a negative
* effect.
*
* NB: Most of the time when just using rectangles for picking then
* picking shouldn't involve any rendering, and minimizing the number of
* rectangles has more benefit than reducing the area of the pick
* region.
*/
n_rects = cairo_region_num_rectangles (priv->input_shape_region);
rectangles = g_alloca (sizeof (float) * 4 * n_rects);
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
int pos = i * 4;
cairo_region_get_rectangle (priv->input_shape_region, i, &rect);
rectangles[pos] = rect.x;
rectangles[pos + 1] = rect.y;
rectangles[pos + 2] = rect.x + rect.width;
rectangles[pos + 3] = rect.y + rect.height;
}
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
fb = cogl_get_draw_framebuffer ();
cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha);
pipeline = cogl_pipeline_new (ctx);
cogl_pipeline_set_color (pipeline, &cogl_color);
cogl_framebuffer_draw_rectangles (fb, pipeline,
rectangles, n_rects);
cogl_object_unref (pipeline);
}
}
static void
meta_shaped_texture_get_preferred_width (ClutterActor *self,
gfloat for_height,
@@ -498,37 +546,10 @@ meta_shaped_texture_get_preferred_height (ClutterActor *self,
}
static gboolean
meta_shaped_texture_get_paint_volume (ClutterActor *actor,
meta_shaped_texture_get_paint_volume (ClutterActor *self,
ClutterPaintVolume *volume)
{
MetaShapedTexture *self = META_SHAPED_TEXTURE (actor);
cairo_rectangle_int_t unobscured_bounds;
if (!clutter_paint_volume_set_from_allocation (volume, actor))
return FALSE;
if (meta_shaped_texture_get_unobscured_bounds (self, &unobscured_bounds))
{
ClutterVertex origin;
cairo_rectangle_int_t bounds;
/* I hate ClutterPaintVolume so much... */
clutter_paint_volume_get_origin (volume, &origin);
bounds.x = origin.x;
bounds.y = origin.y;
bounds.width = clutter_paint_volume_get_width (volume);
bounds.height = clutter_paint_volume_get_height (volume);
gdk_rectangle_intersect (&bounds, &unobscured_bounds, &bounds);
origin.x = bounds.x;
origin.y = bounds.y;
clutter_paint_volume_set_origin (volume, &origin);
clutter_paint_volume_set_width (volume, bounds.width);
clutter_paint_volume_set_height (volume, bounds.height);
}
return TRUE;
return clutter_paint_volume_set_from_allocation (volume, self);
}
void
@@ -573,48 +594,50 @@ meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
}
static cairo_region_t *
effective_unobscured_region (MetaShapedTexture *self)
static gboolean
get_clip (MetaShapedTexture *stex,
int x,
int y,
int width,
int height,
cairo_rectangle_int_t *clip)
{
MetaShapedTexturePrivate *priv = self->priv;
ClutterActor *parent = clutter_actor_get_parent (CLUTTER_ACTOR (self));
ClutterActor *self = CLUTTER_ACTOR (stex);
MetaShapedTexturePrivate *priv;
ClutterActorBox allocation;
float scale_x;
float scale_y;
if (clutter_actor_has_mapped_clones (CLUTTER_ACTOR (self)))
return NULL;
/* NB: clutter_actor_queue_redraw_with_clip expects a box in the actor's
* coordinate space so we need to convert from surface coordinates to
* actor coordinates...
*/
while (parent && !META_IS_WINDOW_ACTOR (parent))
parent = clutter_actor_get_parent (parent);
if (parent && clutter_actor_has_mapped_clones (parent))
return NULL;
return priv->unobscured_region;
}
gboolean
meta_shaped_texture_get_unobscured_bounds (MetaShapedTexture *self,
cairo_rectangle_int_t *unobscured_bounds)
{
cairo_region_t *unobscured_region = effective_unobscured_region (self);
if (unobscured_region)
{
cairo_region_get_extents (unobscured_region, unobscured_bounds);
return TRUE;
}
else
/* Calling clutter_actor_get_allocation_box() is enormously expensive
* if the actor has an out-of-date allocation, since it triggers
* a full redraw. clutter_actor_queue_redraw_with_clip() would redraw
* the whole stage anyways in that case, so just go ahead and do
* it here.
*/
if (!clutter_actor_has_allocation (self))
return FALSE;
}
gboolean
meta_shaped_texture_is_obscured (MetaShapedTexture *self)
{
cairo_region_t *unobscured_region = effective_unobscured_region (self);
priv = stex->priv;
if (unobscured_region)
return cairo_region_is_empty (unobscured_region);
else
if (priv->tex_width == 0 || priv->tex_height == 0)
return FALSE;
clutter_actor_get_allocation_box (self, &allocation);
scale_x = (allocation.x2 - allocation.x1) / priv->tex_width;
scale_y = (allocation.y2 - allocation.y1) / priv->tex_height;
clip->x = x * scale_x;
clip->y = y * scale_y;
clip->width = width * scale_x;
clip->height = height * scale_y;
return TRUE;
}
/**
@@ -624,9 +647,14 @@ meta_shaped_texture_is_obscured (MetaShapedTexture *self)
* @y: the y coordinate of the damaged area
* @width: the width of the damaged area
* @height: the height of the damaged area
* @unobscured_region: The unobscured region of the window or %NULL if
* there is no valid one (like when the actor is transformed or
* has a mapped clone)
*
* Repairs the damaged area indicated by @x, @y, @width and @height
* and potentially queues a redraw.
* and queues a redraw for the intersection @unobscured_region and
* the damage area. If @unobscured_region is %NULL a redraw will always
* get queued.
*
* Return value: Whether a redraw have been queued or not
*/
@@ -635,11 +663,12 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
int x,
int y,
int width,
int height)
int height,
cairo_region_t *unobscured_region)
{
MetaShapedTexturePrivate *priv;
cairo_region_t *unobscured_region;
const cairo_rectangle_int_t clip = { x, y, width, height };
cairo_rectangle_int_t clip;
gboolean has_clip;
priv = stex->priv;
@@ -648,7 +677,8 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
unobscured_region = effective_unobscured_region (stex);
has_clip = get_clip (stex, x, y, width, height, &clip);
if (unobscured_region)
{
cairo_region_t *intersection;
@@ -657,7 +687,8 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
return FALSE;
intersection = cairo_region_copy (unobscured_region);
cairo_region_intersect_rectangle (intersection, &clip);
if (has_clip)
cairo_region_intersect_rectangle (intersection, &clip);
if (!cairo_region_is_empty (intersection))
{
@@ -665,17 +696,21 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
cairo_region_get_extents (intersection, &damage_rect);
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &damage_rect);
cairo_region_destroy (intersection);
return TRUE;
}
cairo_region_destroy (intersection);
return FALSE;
}
if (has_clip)
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip);
else
{
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip);
return TRUE;
}
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
return TRUE;
}
/**
@@ -705,6 +740,41 @@ meta_shaped_texture_get_texture (MetaShapedTexture *stex)
return COGL_TEXTURE (stex->priv->texture);
}
/**
* meta_shaped_texture_set_input_shape_region:
* @stex: a #MetaShapedTexture
* @shape_region: the region of the texture that should respond to
* input.
*
* Determines what region of the texture should accept input. For
* X based windows this is defined by the ShapeInput region of the
* window.
*/
void
meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex,
cairo_region_t *shape_region)
{
MetaShapedTexturePrivate *priv;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
if (priv->input_shape_region != NULL)
{
cairo_region_destroy (priv->input_shape_region);
priv->input_shape_region = NULL;
}
if (shape_region != NULL)
{
cairo_region_reference (shape_region);
priv->input_shape_region = shape_region;
}
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
}
/**
* meta_shaped_texture_set_opaque_region:
* @stex: a #MetaShapedTexture
@@ -841,17 +911,14 @@ meta_shaped_texture_cull_out (MetaCullable *cullable,
MetaShapedTexture *self = META_SHAPED_TEXTURE (cullable);
MetaShapedTexturePrivate *priv = self->priv;
set_unobscured_region (self, unobscured_region);
set_clip_region (self, clip_region);
if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (self)) == 0xff)
{
if (priv->opaque_region)
{
if (unobscured_region)
cairo_region_subtract (unobscured_region, priv->opaque_region);
if (clip_region)
cairo_region_subtract (clip_region, priv->opaque_region);
cairo_region_subtract (unobscured_region, priv->opaque_region);
cairo_region_subtract (clip_region, priv->opaque_region);
}
}
}

View File

@@ -1,164 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2013 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#include "config.h"
#include "meta-surface-actor-wayland.h"
#include <cogl/cogl-wayland-server.h>
#include "meta-shaped-texture-private.h"
#include "meta-wayland-private.h"
struct _MetaSurfaceActorWaylandPrivate
{
MetaWaylandSurface *surface;
MetaWaylandBuffer *buffer;
};
typedef struct _MetaSurfaceActorWaylandPrivate MetaSurfaceActorWaylandPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MetaSurfaceActorWayland, meta_surface_actor_wayland, META_TYPE_SURFACE_ACTOR)
static void
meta_surface_actor_wayland_process_damage (MetaSurfaceActor *actor,
int x, int y, int width, int height)
{
MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (actor);
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self);
struct wl_resource *resource = priv->buffer->resource;
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (resource);
if (shm_buffer)
{
CoglTexture2D *texture = COGL_TEXTURE_2D (priv->buffer->texture);
cogl_wayland_texture_set_region_from_shm_buffer (texture, x, y, width, height, shm_buffer, x, y, 0, NULL);
}
meta_surface_actor_update_area (META_SURFACE_ACTOR (self), x, y, width, height);
}
static void
meta_surface_actor_wayland_pre_paint (MetaSurfaceActor *actor)
{
}
static gboolean
meta_surface_actor_wayland_is_argb32 (MetaSurfaceActor *actor)
{
/* XXX -- look at the SHM buffer format. */
return TRUE;
}
static gboolean
meta_surface_actor_wayland_is_visible (MetaSurfaceActor *actor)
{
/* TODO: ensure that the buffer isn't NULL, implement
* wayland mapping semantics */
return TRUE;
}
static gboolean
meta_surface_actor_wayland_should_unredirect (MetaSurfaceActor *actor)
{
return FALSE;
}
static void
meta_surface_actor_wayland_set_unredirected (MetaSurfaceActor *actor,
gboolean unredirected)
{
/* Do nothing. In the future, we'll use KMS to set this
* up as a hardware overlay or something. */
}
static gboolean
meta_surface_actor_wayland_is_unredirected (MetaSurfaceActor *actor)
{
return FALSE;
}
static MetaWindow *
meta_surface_actor_wayland_get_window (MetaSurfaceActor *actor)
{
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (META_SURFACE_ACTOR_WAYLAND (actor));
return priv->surface->window;
}
static void
meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass)
{
MetaSurfaceActorClass *surface_actor_class = META_SURFACE_ACTOR_CLASS (klass);
surface_actor_class->process_damage = meta_surface_actor_wayland_process_damage;
surface_actor_class->pre_paint = meta_surface_actor_wayland_pre_paint;
surface_actor_class->is_argb32 = meta_surface_actor_wayland_is_argb32;
surface_actor_class->is_visible = meta_surface_actor_wayland_is_visible;
surface_actor_class->should_unredirect = meta_surface_actor_wayland_should_unredirect;
surface_actor_class->set_unredirected = meta_surface_actor_wayland_set_unredirected;
surface_actor_class->is_unredirected = meta_surface_actor_wayland_is_unredirected;
surface_actor_class->get_window = meta_surface_actor_wayland_get_window;
}
static void
meta_surface_actor_wayland_init (MetaSurfaceActorWayland *self)
{
}
MetaSurfaceActor *
meta_surface_actor_wayland_new (MetaWaylandSurface *surface)
{
MetaSurfaceActorWayland *self = g_object_new (META_TYPE_SURFACE_ACTOR_WAYLAND, NULL);
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self);
g_assert (meta_is_wayland_compositor ());
priv->surface = surface;
return META_SURFACE_ACTOR (self);
}
void
meta_surface_actor_wayland_set_buffer (MetaSurfaceActorWayland *self,
MetaWaylandBuffer *buffer)
{
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self);
MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
priv->buffer = buffer;
if (buffer)
meta_shaped_texture_set_texture (stex, buffer->texture);
else
meta_shaped_texture_set_texture (stex, NULL);
}
MetaWaylandSurface *
meta_surface_actor_wayland_get_surface (MetaSurfaceActorWayland *self)
{
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self);
return priv->surface;
}

View File

@@ -1,66 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2013 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#ifndef __META_SURFACE_ACTOR_WAYLAND_H__
#define __META_SURFACE_ACTOR_WAYLAND_H__
#include <glib-object.h>
#include "meta-surface-actor.h"
#include "meta-wayland.h"
G_BEGIN_DECLS
#define META_TYPE_SURFACE_ACTOR_WAYLAND (meta_surface_actor_wayland_get_type ())
#define META_SURFACE_ACTOR_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SURFACE_ACTOR_WAYLAND, MetaSurfaceActorWayland))
#define META_SURFACE_ACTOR_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SURFACE_ACTOR_WAYLAND, MetaSurfaceActorWaylandClass))
#define META_IS_SURFACE_ACTOR_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SURFACE_ACTOR_WAYLAND))
#define META_IS_SURFACE_ACTOR_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SURFACE_ACTOR_WAYLAND))
#define META_SURFACE_ACTOR_WAYLAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SURFACE_ACTOR_WAYLAND, MetaSurfaceActorWaylandClass))
typedef struct _MetaSurfaceActorWayland MetaSurfaceActorWayland;
typedef struct _MetaSurfaceActorWaylandClass MetaSurfaceActorWaylandClass;
struct _MetaSurfaceActorWayland
{
MetaSurfaceActor parent;
};
struct _MetaSurfaceActorWaylandClass
{
MetaSurfaceActorClass parent_class;
};
GType meta_surface_actor_wayland_get_type (void);
MetaSurfaceActor * meta_surface_actor_wayland_new (MetaWaylandSurface *surface);
MetaWaylandSurface * meta_surface_actor_wayland_get_surface (MetaSurfaceActorWayland *self);
void meta_surface_actor_wayland_set_buffer (MetaSurfaceActorWayland *self,
MetaWaylandBuffer *buffer);
G_END_DECLS
#endif /* __META_SURFACE_ACTOR_WAYLAND_H__ */

View File

@@ -1,486 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2013 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Owen Taylor <otaylor@redhat.com>
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#include "config.h"
#include "meta-surface-actor-x11.h"
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xrender.h>
#include <cogl/cogl-texture-pixmap-x11.h>
#include <meta/errors.h>
#include "window-private.h"
#include "meta-shaped-texture-private.h"
#include "meta-cullable.h"
struct _MetaSurfaceActorX11Private
{
MetaWindow *window;
MetaDisplay *display;
CoglTexture *texture;
Pixmap pixmap;
Damage damage;
int last_width;
int last_height;
/* This is used to detect fullscreen windows that need to be unredirected */
guint full_damage_frames_count;
guint does_full_damage : 1;
/* Other state... */
guint argb32 : 1;
guint received_damage : 1;
guint size_changed : 1;
guint unredirected : 1;
};
typedef struct _MetaSurfaceActorX11Private MetaSurfaceActorX11Private;
G_DEFINE_TYPE_WITH_PRIVATE (MetaSurfaceActorX11, meta_surface_actor_x11, META_TYPE_SURFACE_ACTOR)
static void
free_damage (MetaSurfaceActorX11 *self)
{
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
MetaDisplay *display = priv->display;
Display *xdisplay = meta_display_get_xdisplay (display);
if (priv->damage == None)
return;
meta_error_trap_push (display);
XDamageDestroy (xdisplay, priv->damage);
priv->damage = None;
meta_error_trap_pop (display);
}
static void
detach_pixmap (MetaSurfaceActorX11 *self)
{
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
MetaDisplay *display = priv->display;
Display *xdisplay = meta_display_get_xdisplay (display);
MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
if (priv->pixmap == None)
return;
/* Get rid of all references to the pixmap before freeing it; it's unclear whether
* you are supposed to be able to free a GLXPixmap after freeing the underlying
* pixmap, but it certainly doesn't work with current DRI/Mesa
*/
meta_shaped_texture_set_texture (stex, NULL);
cogl_flush ();
meta_error_trap_push (display);
XFreePixmap (xdisplay, priv->pixmap);
priv->pixmap = None;
meta_error_trap_pop (display);
cogl_object_unref (priv->texture);
priv->texture = NULL;
}
static void
set_pixmap (MetaSurfaceActorX11 *self,
Pixmap pixmap)
{
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
CoglTexture *texture;
g_assert (priv->pixmap == None);
priv->pixmap = pixmap;
texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->pixmap, FALSE, NULL));
if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture))))
g_warning ("NOTE: Not using GLX TFP!\n");
priv->texture = texture;
meta_shaped_texture_set_texture (stex, texture);
}
static void
update_pixmap (MetaSurfaceActorX11 *self)
{
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
MetaDisplay *display = priv->display;
Display *xdisplay = meta_display_get_xdisplay (display);
if (priv->size_changed)
{
detach_pixmap (self);
priv->size_changed = FALSE;
}
if (priv->pixmap == None)
{
Pixmap new_pixmap;
Window xwindow = meta_window_get_toplevel_xwindow (priv->window);
meta_error_trap_push (display);
new_pixmap = XCompositeNameWindowPixmap (xdisplay, xwindow);
if (meta_error_trap_pop_with_return (display) != Success)
{
/* Probably a BadMatch if the window isn't viewable; we could
* GrabServer/GetWindowAttributes/NameWindowPixmap/UngrabServer/Sync
* to avoid this, but there's no reason to take two round trips
* when one will do. (We need that Sync if we want to handle failures
* for any reason other than !viewable. That's unlikely, but maybe
* we'll BadAlloc or something.)
*/
new_pixmap = None;
}
if (new_pixmap == None)
{
meta_verbose ("Unable to get named pixmap for %s\n",
meta_window_get_description (priv->window));
return;
}
set_pixmap (self, new_pixmap);
}
}
static gboolean
is_visible (MetaSurfaceActorX11 *self)
{
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
return (priv->pixmap != None) && !priv->unredirected;
}
static void
damage_area (MetaSurfaceActorX11 *self,
int x, int y, int width, int height)
{
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
if (!is_visible (self))
return;
cogl_texture_pixmap_x11_update_area (priv->texture, x, y, width, height);
meta_surface_actor_update_area (META_SURFACE_ACTOR (self), x, y, width, height);
}
static void
meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor,
int x, int y, int width, int height)
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
priv->received_damage = TRUE;
if (meta_window_is_fullscreen (priv->window) && !priv->unredirected && !priv->does_full_damage)
{
MetaRectangle window_rect;
meta_window_get_frame_rect (priv->window, &window_rect);
if (window_rect.x == x &&
window_rect.y == y &&
window_rect.width == width &&
window_rect.height == height)
priv->full_damage_frames_count++;
else
priv->full_damage_frames_count = 0;
if (priv->full_damage_frames_count >= 100)
priv->does_full_damage = TRUE;
}
/* Drop damage event for unredirected windows */
if (priv->unredirected)
return;
damage_area (self, x, y, width, height);
}
static void
meta_surface_actor_x11_pre_paint (MetaSurfaceActor *actor)
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
MetaDisplay *display = priv->display;
Display *xdisplay = meta_display_get_xdisplay (display);
if (priv->received_damage)
{
meta_error_trap_push (display);
XDamageSubtract (xdisplay, priv->damage, None, None);
meta_error_trap_pop (display);
/* We need to make sure that any X drawing that happens before the
* XDamageSubtract() above is visible to subsequent GL rendering;
* the only standardized way to do this is EXT_x11_sync_object,
* which isn't yet widely available. For now, we count on details
* of Xorg and the open source drivers, and hope for the best
* otherwise.
*
* Xorg and open source driver specifics:
*
* The X server makes sure to flush drawing to the kernel before
* sending out damage events, but since we use DamageReportBoundingBox
* there may be drawing between the last damage event and the
* XDamageSubtract() that needs to be flushed as well.
*
* Xorg always makes sure that drawing is flushed to the kernel
* before writing events or responses to the client, so any round trip
* request at this point is sufficient to flush the GLX buffers.
*/
XSync (xdisplay, False);
priv->received_damage = FALSE;
}
update_pixmap (self);
}
static void
update_is_argb32 (MetaSurfaceActorX11 *self)
{
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
MetaDisplay *display = priv->display;
Display *xdisplay = meta_display_get_xdisplay (display);
XRenderPictFormat *format;
format = XRenderFindVisualFormat (xdisplay, priv->window->xvisual);
priv->argb32 = (format && format->type == PictTypeDirect && format->direct.alphaMask);
}
static gboolean
meta_surface_actor_x11_is_argb32 (MetaSurfaceActor *actor)
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
return priv->argb32;
}
static gboolean
meta_surface_actor_x11_is_visible (MetaSurfaceActor *actor)
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
return is_visible (self);
}
static gboolean
meta_surface_actor_x11_should_unredirect (MetaSurfaceActor *actor)
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
MetaWindow *window = priv->window;
if (meta_window_requested_dont_bypass_compositor (window))
return FALSE;
if (window->opacity != 0xFF)
return FALSE;
if (window->shape_region != NULL)
return FALSE;
if (priv->argb32 && !meta_window_requested_bypass_compositor (window))
return FALSE;
if (!meta_window_is_monitor_sized (window))
return FALSE;
if (meta_window_requested_bypass_compositor (window))
return TRUE;
if (meta_window_is_override_redirect (window))
return TRUE;
if (priv->does_full_damage)
return TRUE;
return FALSE;
}
static void
sync_unredirected (MetaSurfaceActorX11 *self)
{
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
MetaDisplay *display = priv->display;
Display *xdisplay = meta_display_get_xdisplay (display);
Window xwindow = meta_window_get_toplevel_xwindow (priv->window);
meta_error_trap_push (display);
if (priv->unredirected)
{
detach_pixmap (self);
XCompositeUnredirectWindow (xdisplay, xwindow, CompositeRedirectManual);
}
else
{
XCompositeRedirectWindow (xdisplay, xwindow, CompositeRedirectManual);
}
meta_error_trap_pop (display);
}
static void
meta_surface_actor_x11_set_unredirected (MetaSurfaceActor *actor,
gboolean unredirected)
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
if (priv->unredirected == unredirected)
return;
priv->unredirected = unredirected;
sync_unredirected (self);
}
static gboolean
meta_surface_actor_x11_is_unredirected (MetaSurfaceActor *actor)
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
return priv->unredirected;
}
static void
meta_surface_actor_x11_dispose (GObject *object)
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (object);
detach_pixmap (self);
free_damage (self);
G_OBJECT_CLASS (meta_surface_actor_x11_parent_class)->dispose (object);
}
static MetaWindow *
meta_surface_actor_x11_get_window (MetaSurfaceActor *actor)
{
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (META_SURFACE_ACTOR_X11 (actor));
return priv->window;
}
static void
meta_surface_actor_x11_class_init (MetaSurfaceActorX11Class *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
MetaSurfaceActorClass *surface_actor_class = META_SURFACE_ACTOR_CLASS (klass);
object_class->dispose = meta_surface_actor_x11_dispose;
surface_actor_class->process_damage = meta_surface_actor_x11_process_damage;
surface_actor_class->pre_paint = meta_surface_actor_x11_pre_paint;
surface_actor_class->is_argb32 = meta_surface_actor_x11_is_argb32;
surface_actor_class->is_visible = meta_surface_actor_x11_is_visible;
surface_actor_class->should_unredirect = meta_surface_actor_x11_should_unredirect;
surface_actor_class->set_unredirected = meta_surface_actor_x11_set_unredirected;
surface_actor_class->is_unredirected = meta_surface_actor_x11_is_unredirected;
surface_actor_class->get_window = meta_surface_actor_x11_get_window;
}
static void
meta_surface_actor_x11_init (MetaSurfaceActorX11 *self)
{
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
priv->last_width = -1;
priv->last_height = -1;
}
static void
create_damage (MetaSurfaceActorX11 *self)
{
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
Display *xdisplay = meta_display_get_xdisplay (priv->display);
Window xwindow = meta_window_get_toplevel_xwindow (priv->window);
priv->damage = XDamageCreate (xdisplay, xwindow, XDamageReportBoundingBox);
}
static void
window_decorated_notify (MetaWindow *window,
GParamSpec *pspec,
gpointer user_data)
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (user_data);
free_damage (self);
create_damage (self);
}
MetaSurfaceActor *
meta_surface_actor_x11_new (MetaWindow *window)
{
MetaSurfaceActorX11 *self = g_object_new (META_TYPE_SURFACE_ACTOR_X11, NULL);
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
MetaDisplay *display = meta_window_get_display (window);
g_assert (!meta_is_wayland_compositor ());
priv->window = window;
priv->display = display;
create_damage (self);
g_signal_connect_object (priv->window, "notify::decorated",
G_CALLBACK (window_decorated_notify), self, 0);
update_is_argb32 (self);
priv->unredirected = FALSE;
sync_unredirected (self);
clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE);
return META_SURFACE_ACTOR (self);
}
void
meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self,
int width, int height)
{
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
if (priv->last_width == width &&
priv->last_height == height)
return;
priv->size_changed = TRUE;
priv->last_width = width;
priv->last_height = height;
}

View File

@@ -1,69 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2013 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Owen Taylor <otaylor@redhat.com>
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#ifndef __META_SURFACE_ACTOR_X11_H__
#define __META_SURFACE_ACTOR_X11_H__
#include <glib-object.h>
#include "meta-surface-actor.h"
#include <X11/extensions/Xdamage.h>
#include <meta/display.h>
#include <meta/window.h>
G_BEGIN_DECLS
#define META_TYPE_SURFACE_ACTOR_X11 (meta_surface_actor_x11_get_type ())
#define META_SURFACE_ACTOR_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SURFACE_ACTOR_X11, MetaSurfaceActorX11))
#define META_SURFACE_ACTOR_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SURFACE_ACTOR_X11, MetaSurfaceActorX11Class))
#define META_IS_SURFACE_ACTOR_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SURFACE_ACTOR_X11))
#define META_IS_SURFACE_ACTOR_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SURFACE_ACTOR_X11))
#define META_SURFACE_ACTOR_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SURFACE_ACTOR_X11, MetaSurfaceActorX11Class))
typedef struct _MetaSurfaceActorX11 MetaSurfaceActorX11;
typedef struct _MetaSurfaceActorX11Class MetaSurfaceActorX11Class;
struct _MetaSurfaceActorX11
{
MetaSurfaceActor parent;
};
struct _MetaSurfaceActorX11Class
{
MetaSurfaceActorClass parent_class;
};
GType meta_surface_actor_x11_get_type (void);
MetaSurfaceActor * meta_surface_actor_x11_new (MetaWindow *window);
void meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self,
int width, int height);
G_END_DECLS
#endif /* __META_SURFACE_ACTOR_X11_H__ */

View File

@@ -10,123 +10,45 @@
*/
#include <config.h>
#include "meta-surface-actor.h"
#include <clutter/clutter.h>
#include <cogl/cogl-wayland-server.h>
#include <cogl/cogl-texture-pixmap-x11.h>
#include <meta/meta-shaped-texture.h>
#include "meta-surface-actor.h"
#include "meta-wayland-private.h"
#include "meta-cullable.h"
#include "meta-shaped-texture-private.h"
struct _MetaSurfaceActorPrivate
{
MetaShapedTexture *texture;
MetaWaylandBuffer *buffer;
cairo_region_t *input_region;
/* Freeze/thaw accounting */
guint needs_damage_all : 1;
guint frozen : 1;
GSList *ops;
};
static void cullable_iface_init (MetaCullableInterface *iface);
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaSurfaceActor, meta_surface_actor, CLUTTER_TYPE_ACTOR,
G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init));
G_DEFINE_TYPE_WITH_CODE (MetaSurfaceActor, meta_surface_actor, CLUTTER_TYPE_ACTOR,
G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init));
enum {
REPAINT_SCHEDULED,
LAST_SIGNAL,
};
static guint signals[LAST_SIGNAL];
gboolean
meta_surface_actor_get_unobscured_bounds (MetaSurfaceActor *self,
cairo_rectangle_int_t *unobscured_bounds)
{
MetaSurfaceActorPrivate *priv = self->priv;
return meta_shaped_texture_get_unobscured_bounds (priv->texture, unobscured_bounds);
}
static void
meta_surface_actor_pick (ClutterActor *actor,
const ClutterColor *color)
{
MetaSurfaceActor *self = META_SURFACE_ACTOR (actor);
MetaSurfaceActorPrivate *priv = self->priv;
if (!clutter_actor_should_pick_paint (actor))
return;
/* If there is no region then use the regular pick */
if (priv->input_region == NULL)
CLUTTER_ACTOR_CLASS (meta_surface_actor_parent_class)->pick (actor, color);
else
{
int n_rects;
float *rectangles;
int i;
CoglPipeline *pipeline;
CoglContext *ctx;
CoglFramebuffer *fb;
CoglColor cogl_color;
n_rects = cairo_region_num_rectangles (priv->input_region);
rectangles = g_alloca (sizeof (float) * 4 * n_rects);
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
int pos = i * 4;
cairo_region_get_rectangle (priv->input_region, i, &rect);
rectangles[pos + 0] = rect.x;
rectangles[pos + 1] = rect.y;
rectangles[pos + 2] = rect.x + rect.width;
rectangles[pos + 3] = rect.y + rect.height;
}
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
fb = cogl_get_draw_framebuffer ();
cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha);
pipeline = cogl_pipeline_new (ctx);
cogl_pipeline_set_color (pipeline, &cogl_color);
cogl_framebuffer_draw_rectangles (fb, pipeline, rectangles, n_rects);
cogl_object_unref (pipeline);
}
}
static void meta_surface_actor_free_ops (MetaSurfaceActor *self);
static void
meta_surface_actor_dispose (GObject *object)
{
MetaSurfaceActor *self = META_SURFACE_ACTOR (object);
MetaSurfaceActorPrivate *priv = self->priv;
g_clear_pointer (&priv->input_region, cairo_region_destroy);
G_OBJECT_CLASS (meta_surface_actor_parent_class)->dispose (object);
meta_surface_actor_free_ops (self);
}
static void
meta_surface_actor_class_init (MetaSurfaceActorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
object_class->dispose = meta_surface_actor_dispose;
actor_class->pick = meta_surface_actor_pick;
signals[REPAINT_SCHEDULED] = g_signal_new ("repaint-scheduled",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
g_type_class_add_private (klass, sizeof (MetaSurfaceActorPrivate));
}
@@ -178,21 +100,80 @@ meta_surface_actor_get_texture (MetaSurfaceActor *self)
return self->priv->texture;
}
void
meta_surface_actor_update_area (MetaSurfaceActor *self,
int x, int y, int width, int height)
static void
update_area (MetaSurfaceActor *self,
int x, int y, int width, int height)
{
MetaSurfaceActorPrivate *priv = self->priv;
if (meta_shaped_texture_update_area (priv->texture, x, y, width, height))
g_signal_emit (self, signals[REPAINT_SCHEDULED], 0);
if (meta_is_wayland_compositor ())
{
struct wl_resource *resource = priv->buffer->resource;
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (resource);
if (shm_buffer)
{
CoglTexture2D *texture = COGL_TEXTURE_2D (priv->buffer->texture);
cogl_wayland_texture_set_region_from_shm_buffer (texture, x, y, width, height, shm_buffer, x, y, 0, NULL);
}
}
else
{
CoglTexturePixmapX11 *texture = COGL_TEXTURE_PIXMAP_X11 (meta_shaped_texture_get_texture (priv->texture));
cogl_texture_pixmap_x11_update_area (texture, x, y, width, height);
}
}
gboolean
meta_surface_actor_is_obscured (MetaSurfaceActor *self)
meta_surface_actor_damage_all (MetaSurfaceActor *self,
cairo_region_t *unobscured_region)
{
MetaSurfaceActorPrivate *priv = self->priv;
return meta_shaped_texture_is_obscured (priv->texture);
CoglTexture *texture = meta_shaped_texture_get_texture (priv->texture);
update_area (self, 0, 0, cogl_texture_get_width (texture), cogl_texture_get_height (texture));
return meta_shaped_texture_update_area (priv->texture,
0, 0,
cogl_texture_get_width (texture),
cogl_texture_get_height (texture),
unobscured_region);
}
gboolean
meta_surface_actor_damage_area (MetaSurfaceActor *self,
int x,
int y,
int width,
int height,
cairo_region_t *unobscured_region)
{
MetaSurfaceActorPrivate *priv = self->priv;
update_area (self, x, y, width, height);
return meta_shaped_texture_update_area (priv->texture,
x, y, width, height,
unobscured_region);
}
void
meta_surface_actor_attach_wayland_buffer (MetaSurfaceActor *self,
MetaWaylandBuffer *buffer)
{
MetaSurfaceActorPrivate *priv = self->priv;
priv->buffer = buffer;
if (buffer)
meta_shaped_texture_set_texture (priv->texture, buffer->texture);
else
meta_shaped_texture_set_texture (priv->texture, NULL);
}
void
meta_surface_actor_set_texture (MetaSurfaceActor *self,
CoglTexture *texture)
{
MetaSurfaceActorPrivate *priv = self->priv;
meta_shaped_texture_set_texture (priv->texture, texture);
}
void
@@ -200,14 +181,7 @@ meta_surface_actor_set_input_region (MetaSurfaceActor *self,
cairo_region_t *region)
{
MetaSurfaceActorPrivate *priv = self->priv;
if (priv->input_region)
cairo_region_destroy (priv->input_region);
if (region)
priv->input_region = cairo_region_reference (region);
else
priv->input_region = NULL;
meta_shaped_texture_set_input_shape_region (priv->texture, region);
}
void
@@ -218,102 +192,132 @@ meta_surface_actor_set_opaque_region (MetaSurfaceActor *self,
meta_shaped_texture_set_opaque_region (priv->texture, region);
}
static gboolean
is_frozen (MetaSurfaceActor *self)
MetaSurfaceActor *
meta_surface_actor_new (void)
{
return g_object_new (META_TYPE_SURFACE_ACTOR, NULL);
}
typedef enum {
OP_SET_POSITION,
OP_PLACE_ABOVE,
OP_PLACE_BELOW,
} MetaSurfaceActorOpType;
typedef struct {
MetaSurfaceActorOpType type;
} MetaSurfaceActorOp;
typedef struct {
MetaSurfaceActorOpType type;
ClutterActor *subsurface;
int32_t x;
int32_t y;
} MetaSurfaceActorOp_SetPosition;
typedef struct {
MetaSurfaceActorOpType type;
ClutterActor *subsurface;
ClutterActor *sibling;
} MetaSurfaceActorOp_Stack;
void
meta_surface_actor_subsurface_set_position (MetaSurfaceActor *self,
MetaSurfaceActor *subsurface,
int32_t x,
int32_t y)
{
MetaSurfaceActorPrivate *priv = self->priv;
return priv->frozen;
MetaSurfaceActorOp_SetPosition *op = g_slice_new0 (MetaSurfaceActorOp_SetPosition);
op->type = OP_SET_POSITION;
op->subsurface = CLUTTER_ACTOR (subsurface);
op->x = x;
op->y = y;
priv->ops = g_slist_append (priv->ops, op);
}
static void
meta_surface_actor_stack_op (MetaSurfaceActor *self,
MetaSurfaceActorOpType type,
MetaSurfaceActor *subsurface,
MetaSurfaceActor *sibling)
{
MetaSurfaceActorPrivate *priv = self->priv;
MetaSurfaceActorOp_Stack *op = g_slice_new0 (MetaSurfaceActorOp_Stack);
op->type = type;
op->subsurface = CLUTTER_ACTOR (subsurface);
op->sibling = CLUTTER_ACTOR (sibling);
priv->ops = g_slist_append (priv->ops, op);
}
void
meta_surface_actor_process_damage (MetaSurfaceActor *self,
int x, int y, int width, int height)
meta_surface_actor_subsurface_place_above (MetaSurfaceActor *self,
MetaSurfaceActor *subsurface,
MetaSurfaceActor *sibling)
{
MetaSurfaceActorPrivate *priv = self->priv;
meta_surface_actor_stack_op (self, OP_PLACE_ABOVE, subsurface, sibling);
}
if (is_frozen (self))
void
meta_surface_actor_subsurface_place_below (MetaSurfaceActor *self,
MetaSurfaceActor *subsurface,
MetaSurfaceActor *sibling)
{
meta_surface_actor_stack_op (self, OP_PLACE_BELOW, subsurface, sibling);
}
static void
meta_surface_actor_do_op (MetaSurfaceActor *self,
MetaSurfaceActorOp *op)
{
MetaSurfaceActorOp_SetPosition *op_pos = (MetaSurfaceActorOp_SetPosition *) op;
MetaSurfaceActorOp_Stack *op_stack = (MetaSurfaceActorOp_Stack *) op;
switch (op->type)
{
/* The window is frozen due to an effect in progress: we ignore damage
* here on the off chance that this will stop the corresponding
* texture_from_pixmap from being update.
*
* needs_damage_all tracks that some unknown damage happened while the
* window was frozen so that when the window becomes unfrozen we can
* issue a full window update to cover any lost damage.
*
* It should be noted that this is an unreliable mechanism since it's
* quite likely that drivers will aim to provide a zero-copy
* implementation of the texture_from_pixmap extension and in those cases
* any drawing done to the window is always immediately reflected in the
* texture regardless of damage event handling.
*/
priv->needs_damage_all = TRUE;
return;
}
META_SURFACE_ACTOR_GET_CLASS (self)->process_damage (self, x, y, width, height);
}
void
meta_surface_actor_pre_paint (MetaSurfaceActor *self)
{
META_SURFACE_ACTOR_GET_CLASS (self)->pre_paint (self);
}
gboolean
meta_surface_actor_is_argb32 (MetaSurfaceActor *self)
{
return META_SURFACE_ACTOR_GET_CLASS (self)->is_argb32 (self);
}
gboolean
meta_surface_actor_is_visible (MetaSurfaceActor *self)
{
return META_SURFACE_ACTOR_GET_CLASS (self)->is_visible (self);
}
void
meta_surface_actor_set_frozen (MetaSurfaceActor *self,
gboolean frozen)
{
MetaSurfaceActorPrivate *priv = self->priv;
priv->frozen = frozen;
if (!frozen && priv->needs_damage_all)
{
/* Since we ignore damage events while a window is frozen for certain effects
* we may need to issue an update_area() covering the whole pixmap if we
* don't know what real damage has happened. */
meta_surface_actor_process_damage (self, 0, 0,
clutter_actor_get_width (CLUTTER_ACTOR (priv->texture)),
clutter_actor_get_height (CLUTTER_ACTOR (priv->texture)));
priv->needs_damage_all = FALSE;
case OP_SET_POSITION:
clutter_actor_set_position (op_pos->subsurface, op_pos->x, op_pos->y);
break;
case OP_PLACE_ABOVE:
clutter_actor_set_child_above_sibling (CLUTTER_ACTOR (self), op_stack->subsurface, op_stack->sibling);
break;
case OP_PLACE_BELOW:
clutter_actor_set_child_below_sibling (CLUTTER_ACTOR (self), op_stack->subsurface, op_stack->sibling);
break;
}
}
gboolean
meta_surface_actor_should_unredirect (MetaSurfaceActor *self)
static void
meta_surface_actor_op_free (MetaSurfaceActorOp *op)
{
return META_SURFACE_ACTOR_GET_CLASS (self)->should_unredirect (self);
g_slice_free (MetaSurfaceActorOp, op);
}
static void
meta_surface_actor_free_ops (MetaSurfaceActor *self)
{
MetaSurfaceActorPrivate *priv = self->priv;
g_slist_free_full (priv->ops, (GDestroyNotify) meta_surface_actor_op_free);
priv->ops = NULL;
}
static void
meta_surface_actor_do_ops (MetaSurfaceActor *self)
{
MetaSurfaceActorPrivate *priv = self->priv;
GSList *l;
for (l = priv->ops; l; l = l->next)
meta_surface_actor_do_op (self, ((MetaSurfaceActorOp *) l->data));
}
void
meta_surface_actor_set_unredirected (MetaSurfaceActor *self,
gboolean unredirected)
meta_surface_actor_commit (MetaSurfaceActor *self)
{
META_SURFACE_ACTOR_GET_CLASS (self)->set_unredirected (self, unredirected);
}
gboolean
meta_surface_actor_is_unredirected (MetaSurfaceActor *self)
{
return META_SURFACE_ACTOR_GET_CLASS (self)->is_unredirected (self);
}
MetaWindow *
meta_surface_actor_get_window (MetaSurfaceActor *self)
{
return META_SURFACE_ACTOR_GET_CLASS (self)->get_window (self);
meta_surface_actor_do_ops (self);
}

View File

@@ -6,7 +6,7 @@
#include <config.h>
#include <meta/meta-shaped-texture.h>
#include <meta/window.h>
#include "meta-wayland-types.h"
G_BEGIN_DECLS
@@ -25,19 +25,6 @@ struct _MetaSurfaceActorClass
{
/*< private >*/
ClutterActorClass parent_class;
void (* process_damage) (MetaSurfaceActor *actor,
int x, int y, int width, int height);
void (* pre_paint) (MetaSurfaceActor *actor);
gboolean (* is_argb32) (MetaSurfaceActor *actor);
gboolean (* is_visible) (MetaSurfaceActor *actor);
gboolean (* should_unredirect) (MetaSurfaceActor *actor);
void (* set_unredirected) (MetaSurfaceActor *actor,
gboolean unredirected);
gboolean (* is_unredirected) (MetaSurfaceActor *actor);
MetaWindow *(* get_window) (MetaSurfaceActor *actor);
};
struct _MetaSurfaceActor
@@ -49,37 +36,43 @@ struct _MetaSurfaceActor
GType meta_surface_actor_get_type (void);
MetaSurfaceActor *meta_surface_actor_new (void);
cairo_surface_t *meta_surface_actor_get_image (MetaSurfaceActor *self,
cairo_rectangle_int_t *clip);
MetaShapedTexture *meta_surface_actor_get_texture (MetaSurfaceActor *self);
MetaWindow *meta_surface_actor_get_window (MetaSurfaceActor *self);
gboolean meta_surface_actor_is_obscured (MetaSurfaceActor *self);
gboolean meta_surface_actor_get_unobscured_bounds (MetaSurfaceActor *self,
cairo_rectangle_int_t *unobscured_bounds);
gboolean meta_surface_actor_damage_all (MetaSurfaceActor *self,
cairo_region_t *unobscured_region);
gboolean meta_surface_actor_damage_area (MetaSurfaceActor *self,
int x,
int y,
int width,
int height,
cairo_region_t *unobscured_region);
void meta_surface_actor_set_texture (MetaSurfaceActor *self,
CoglTexture *texture);
void meta_surface_actor_attach_wayland_buffer (MetaSurfaceActor *self,
MetaWaylandBuffer *buffer);
void meta_surface_actor_set_input_region (MetaSurfaceActor *self,
cairo_region_t *region);
void meta_surface_actor_set_opaque_region (MetaSurfaceActor *self,
cairo_region_t *region);
void meta_surface_actor_update_area (MetaSurfaceActor *actor,
int x, int y, int width, int height);
void meta_surface_actor_process_damage (MetaSurfaceActor *actor,
int x, int y, int width, int height);
void meta_surface_actor_pre_paint (MetaSurfaceActor *actor);
gboolean meta_surface_actor_is_argb32 (MetaSurfaceActor *actor);
gboolean meta_surface_actor_is_visible (MetaSurfaceActor *actor);
void meta_surface_actor_set_frozen (MetaSurfaceActor *actor,
gboolean frozen);
gboolean meta_surface_actor_should_unredirect (MetaSurfaceActor *actor);
void meta_surface_actor_set_unredirected (MetaSurfaceActor *actor,
gboolean unredirected);
gboolean meta_surface_actor_is_unredirected (MetaSurfaceActor *actor);
void meta_surface_actor_subsurface_set_position (MetaSurfaceActor *self,
MetaSurfaceActor *subsurface,
int32_t x,
int32_t y);
void meta_surface_actor_subsurface_place_above (MetaSurfaceActor *self,
MetaSurfaceActor *subsurface,
MetaSurfaceActor *sibling);
void meta_surface_actor_subsurface_place_below (MetaSurfaceActor *self,
MetaSurfaceActor *subsurface,
MetaSurfaceActor *sibling);
void meta_surface_actor_commit (MetaSurfaceActor *self);
G_END_DECLS

View File

@@ -5,6 +5,9 @@
#include <config.h>
#include <wayland-server.h>
#include <meta-wayland-private.h>
#include <X11/extensions/Xdamage.h>
#include <meta/compositor-mutter.h>
#include "meta-surface-actor.h"
@@ -36,13 +39,13 @@ void meta_window_actor_frame_complete (MetaWindowActor *self,
void meta_window_actor_invalidate_shadow (MetaWindowActor *self);
void meta_window_actor_set_redirected (MetaWindowActor *self, gboolean state);
gboolean meta_window_actor_should_unredirect (MetaWindowActor *self);
void meta_window_actor_get_shape_bounds (MetaWindowActor *self,
cairo_rectangle_int_t *bounds);
gboolean meta_window_actor_should_unredirect (MetaWindowActor *self);
void meta_window_actor_set_unredirected (MetaWindowActor *self,
gboolean unredirected);
gboolean meta_window_actor_effect_in_progress (MetaWindowActor *self);
void meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
gboolean did_placement);
@@ -56,10 +59,12 @@ void meta_window_actor_set_updates_frozen (MetaWindowActor *self,
void meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
gboolean no_delay_frame);
void meta_window_actor_set_unobscured_region (MetaWindowActor *self,
cairo_region_t *unobscured_region);
void meta_window_actor_effect_completed (MetaWindowActor *actor,
gulong event);
MetaSurfaceActor *meta_window_actor_get_surface (MetaWindowActor *self);
void meta_window_actor_update_surface (MetaWindowActor *self);
#endif /* META_WINDOW_ACTOR_PRIVATE_H */

File diff suppressed because it is too large Load Diff

View File

@@ -115,6 +115,8 @@ meta_window_group_paint (ClutterActor *actor)
{
cairo_region_t *clip_region;
cairo_region_t *unobscured_region;
ClutterActorIter iter;
ClutterActor *child;
cairo_rectangle_int_t visible_rect, clip_rect;
int paint_x_offset, paint_y_offset;
int paint_x_origin, paint_y_origin;
@@ -123,6 +125,18 @@ meta_window_group_paint (ClutterActor *actor)
MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
ClutterActor *stage = clutter_actor_get_stage (actor);
/* Start off by treating all windows as completely unobscured, so damage anywhere
* in a window queues redraws, but confine it more below. */
clutter_actor_iter_init (&iter, actor);
while (clutter_actor_iter_next (&iter, &child))
{
if (META_IS_WINDOW_ACTOR (child))
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
meta_window_actor_set_unobscured_region (window_actor, NULL);
}
}
/* Normally we expect an actor to be drawn at it's position on the screen.
* However, if we're inside the paint of a ClutterClone, that won't be the
* case and we need to compensate. We look at the position of the window
@@ -164,6 +178,20 @@ meta_window_group_paint (ClutterActor *actor)
paint_y_offset = paint_y_origin - actor_y_origin;
cairo_region_translate (clip_region, -paint_x_offset, -paint_y_offset);
if (!meta_is_wayland_compositor ())
{
MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen);
if (info->unredirected_window != NULL)
{
cairo_rectangle_int_t unredirected_rect;
MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window);
meta_window_get_frame_rect (window, (MetaRectangle *)&unredirected_rect);
cairo_region_subtract_rectangle (unobscured_region, &unredirected_rect);
cairo_region_subtract_rectangle (clip_region, &unredirected_rect);
}
}
meta_cullable_cull_out (META_CULLABLE (window_group), unobscured_region, clip_region);
cairo_region_destroy (unobscured_region);

View File

@@ -32,14 +32,13 @@
#include <gmodule.h>
#include <string.h>
#define DESTROY_TIMEOUT 100
#define DESTROY_TIMEOUT 250
#define MINIMIZE_TIMEOUT 250
#define MAXIMIZE_TIMEOUT 250
#define MAP_TIMEOUT 250
#define SWITCH_TIMEOUT 500
#define ACTOR_DATA_KEY "MCCP-Default-actor-data"
#define SCREEN_TILE_PREVIEW_DATA_KEY "MCCP-Default-screen-tile-preview-data"
#define META_TYPE_DEFAULT_PLUGIN (meta_default_plugin_get_type ())
#define META_DEFAULT_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_DEFAULT_PLUGIN, MetaDefaultPlugin))
@@ -68,7 +67,6 @@ struct _MetaDefaultPluginClass
};
static GQuark actor_data_quark = 0;
static GQuark screen_tile_preview_data_quark = 0;
static void start (MetaPlugin *plugin);
static void minimize (MetaPlugin *plugin,
@@ -99,12 +97,6 @@ static void kill_window_effects (MetaPlugin *plugin,
MetaWindowActor *actor);
static void kill_switch_workspace (MetaPlugin *plugin);
static void show_tile_preview (MetaPlugin *plugin,
MetaWindow *window,
MetaRectangle *tile_rect,
int tile_monitor_number);
static void hide_tile_preview (MetaPlugin *plugin);
static void confirm_display_change (MetaPlugin *plugin);
static const MetaPluginInfo * plugin_info (MetaPlugin *plugin);
@@ -151,15 +143,6 @@ typedef struct
} EffectCompleteData;
typedef struct _ScreenTilePreview
{
ClutterActor *actor;
GdkRGBA *preview_color;
MetaRectangle tile_rect;
} ScreenTilePreview;
static void
meta_default_plugin_dispose (GObject *object)
{
@@ -220,8 +203,6 @@ meta_default_plugin_class_init (MetaDefaultPluginClass *klass)
plugin_class->unmaximize = unmaximize;
plugin_class->destroy = destroy;
plugin_class->switch_workspace = switch_workspace;
plugin_class->show_tile_preview = show_tile_preview;
plugin_class->hide_tile_preview = hide_tile_preview;
plugin_class->plugin_info = plugin_info;
plugin_class->kill_window_effects = kill_window_effects;
plugin_class->kill_switch_workspace = kill_switch_workspace;
@@ -308,13 +289,26 @@ on_switch_workspace_effect_complete (ClutterTimeline *timeline, gpointer data)
meta_plugin_switch_workspace_completed (plugin);
}
static gboolean
show_stage (MetaPlugin *plugin)
{
MetaScreen *screen;
ClutterActor *stage;
screen = meta_plugin_get_screen (plugin);
stage = meta_get_stage_for_screen (screen);
clutter_actor_show (stage);
return FALSE;
}
static void
on_monitors_changed (MetaScreen *screen,
MetaPlugin *plugin)
{
MetaDefaultPlugin *self = META_DEFAULT_PLUGIN (plugin);
int i, n;
GRand *rand = g_rand_new_with_seed (12345);
clutter_actor_destroy_all_children (self->priv->background_group);
@@ -337,16 +331,14 @@ on_monitors_changed (MetaScreen *screen,
reproducible.
*/
clutter_color_init (&color,
g_rand_int_range (rand, 0, 255),
g_rand_int_range (rand, 0, 255),
g_rand_int_range (rand, 0, 255),
g_random_int () % 255,
g_random_int () % 255,
g_random_int () % 255,
255);
clutter_actor_set_background_color (background, &color);
clutter_actor_add_child (self->priv->background_group, background);
}
g_rand_free (rand);
}
static void
@@ -363,7 +355,10 @@ start (MetaPlugin *plugin)
G_CALLBACK (on_monitors_changed), plugin);
on_monitors_changed (screen, plugin);
clutter_actor_show (meta_get_stage_for_screen (screen));
meta_later_add (META_LATER_BEFORE_REDRAW,
(GSourceFunc) show_stage,
plugin,
NULL);
}
static void
@@ -412,11 +407,9 @@ switch_workspace (MetaPlugin *plugin,
MetaWindowActor *window_actor = l->data;
ActorPrivate *apriv = get_actor_private (window_actor);
ClutterActor *actor = CLUTTER_ACTOR (window_actor);
MetaWorkspace *workspace;
gint win_workspace;
workspace = meta_window_get_workspace (meta_window_actor_get_meta_window (window_actor));
win_workspace = meta_workspace_index (workspace);
win_workspace = meta_window_actor_get_workspace (window_actor);
if (win_workspace == to || win_workspace == from)
{
@@ -488,6 +481,8 @@ on_minimize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
/* FIXME - we shouldn't assume the original scale, it should be saved
* at the start of the effect */
clutter_actor_set_scale (data->actor, 1.0, 1.0);
clutter_actor_move_anchor_point_from_gravity (data->actor,
CLUTTER_GRAVITY_NORTH_WEST);
/* Now notify the manager that we are done with this effect */
meta_plugin_minimize_completed (plugin, window_actor);
@@ -524,6 +519,9 @@ minimize (MetaPlugin *plugin, MetaWindowActor *window_actor)
apriv->is_minimized = TRUE;
clutter_actor_move_anchor_point_from_gravity (actor,
CLUTTER_GRAVITY_CENTER);
animation = clutter_actor_animate (actor,
CLUTTER_EASE_IN_SINE,
MINIMIZE_TIMEOUT,
@@ -562,6 +560,8 @@ on_maximize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
/* FIXME - don't assume the original scale was 1.0 */
clutter_actor_set_scale (data->actor, 1.0, 1.0);
clutter_actor_move_anchor_point_from_gravity (data->actor,
CLUTTER_GRAVITY_NORTH_WEST);
/* Now notify the manager that we are done with this effect */
meta_plugin_maximize_completed (plugin, window_actor);
@@ -586,8 +586,10 @@ maximize (MetaPlugin *plugin,
ClutterActor *actor = CLUTTER_ACTOR (window_actor);
MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor);
gdouble scale_x = 1.0;
gdouble scale_y = 1.0;
gdouble scale_x = 1.0;
gdouble scale_y = 1.0;
gfloat anchor_x = 0;
gfloat anchor_y = 0;
type = meta_window_get_window_type (meta_window);
@@ -611,6 +613,13 @@ maximize (MetaPlugin *plugin,
scale_x = (gdouble)end_width / (gdouble) width;
scale_y = (gdouble)end_height / (gdouble) height;
anchor_x = (gdouble)(x - end_x)*(gdouble)width /
((gdouble)(end_width - width));
anchor_y = (gdouble)(y - end_y)*(gdouble)height /
((gdouble)(end_height - height));
clutter_actor_move_anchor_point (actor, anchor_x, anchor_y);
animation = clutter_actor_animate (actor,
CLUTTER_EASE_IN_SINE,
MAXIMIZE_TIMEOUT,
@@ -665,6 +674,9 @@ on_map_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data)
apriv->tml_map = NULL;
clutter_actor_move_anchor_point_from_gravity (data->actor,
CLUTTER_GRAVITY_NORTH_WEST);
/* Now notify the manager that we are done with this effect */
meta_plugin_map_completed (plugin, window_actor);
@@ -690,15 +702,15 @@ map (MetaPlugin *plugin, MetaWindowActor *window_actor)
EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
ActorPrivate *apriv = get_actor_private (window_actor);
clutter_actor_set_pivot_point (actor, 0.5, 0.5);
clutter_actor_set_opacity (actor, 0);
clutter_actor_set_scale (actor, 0.5, 0.5);
clutter_actor_move_anchor_point_from_gravity (actor,
CLUTTER_GRAVITY_CENTER);
clutter_actor_set_scale (actor, 0.0, 0.0);
clutter_actor_show (actor);
animation = clutter_actor_animate (actor,
CLUTTER_EASE_OUT_QUAD,
CLUTTER_EASE_IN_SINE,
MAP_TIMEOUT,
"opacity", 255,
"scale-x", 1.0,
"scale-y", 1.0,
NULL);
@@ -750,12 +762,14 @@ destroy (MetaPlugin *plugin, MetaWindowActor *window_actor)
EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
ActorPrivate *apriv = get_actor_private (window_actor);
clutter_actor_move_anchor_point_from_gravity (actor,
CLUTTER_GRAVITY_CENTER);
animation = clutter_actor_animate (actor,
CLUTTER_EASE_OUT_QUAD,
CLUTTER_EASE_IN_SINE,
DESTROY_TIMEOUT,
"opacity", 0,
"scale-x", 0.8,
"scale-y", 0.8,
"scale-x", 0.0,
"scale-y", 1.0,
NULL);
apriv->tml_destroy = clutter_animation_get_timeline (animation);
data->plugin = plugin;
@@ -768,82 +782,6 @@ destroy (MetaPlugin *plugin, MetaWindowActor *window_actor)
meta_plugin_destroy_completed (plugin, window_actor);
}
/*
* Tile preview private data accessor
*/
static void
free_screen_tile_preview (gpointer data)
{
ScreenTilePreview *preview = data;
if (G_LIKELY (preview != NULL)) {
clutter_actor_destroy (preview->actor);
g_slice_free (ScreenTilePreview, preview);
}
}
static ScreenTilePreview *
get_screen_tile_preview (MetaScreen *screen)
{
ScreenTilePreview *preview = g_object_get_qdata (G_OBJECT (screen), screen_tile_preview_data_quark);
if (G_UNLIKELY (screen_tile_preview_data_quark == 0))
screen_tile_preview_data_quark = g_quark_from_static_string (SCREEN_TILE_PREVIEW_DATA_KEY);
if (G_UNLIKELY (!preview))
{
preview = g_slice_new0 (ScreenTilePreview);
preview->actor = clutter_actor_new ();
clutter_actor_set_background_color (preview->actor, CLUTTER_COLOR_Blue);
clutter_actor_set_opacity (preview->actor, 100);
clutter_actor_add_child (meta_get_window_group_for_screen (screen), preview->actor);
g_object_set_qdata_full (G_OBJECT (screen),
screen_tile_preview_data_quark, preview,
free_screen_tile_preview);
}
return preview;
}
static void
show_tile_preview (MetaPlugin *plugin,
MetaWindow *window,
MetaRectangle *tile_rect,
int tile_monitor_number)
{
MetaScreen *screen = meta_plugin_get_screen (plugin);
ScreenTilePreview *preview = get_screen_tile_preview (screen);
ClutterActor *window_actor;
if (CLUTTER_ACTOR_IS_VISIBLE (preview->actor)
&& preview->tile_rect.x == tile_rect->x
&& preview->tile_rect.y == tile_rect->y
&& preview->tile_rect.width == tile_rect->width
&& preview->tile_rect.height == tile_rect->height)
return; /* nothing to do */
clutter_actor_set_position (preview->actor, tile_rect->x, tile_rect->y);
clutter_actor_set_size (preview->actor, tile_rect->width, tile_rect->height);
clutter_actor_show (preview->actor);
window_actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window));
clutter_actor_lower (preview->actor, window_actor);
preview->tile_rect = *tile_rect;
}
static void
hide_tile_preview (MetaPlugin *plugin)
{
MetaScreen *screen = meta_plugin_get_screen (plugin);
ScreenTilePreview *preview = get_screen_tile_preview (screen);
clutter_actor_hide (preview->actor);
}
static void
kill_switch_workspace (MetaPlugin *plugin)
{

View File

@@ -1353,6 +1353,7 @@ constrain_titlebar_visible (MetaWindow *window,
window->type == META_WINDOW_DOCK ||
window->fullscreen ||
!window->require_titlebar_visible ||
!window->decorated ||
unconstrained_user_action)
return TRUE;

View File

@@ -37,8 +37,6 @@
#include <stdlib.h>
#include <stdio.h>
#include "meta-wayland-surface.h"
static void meta_window_present_delete_dialog (MetaWindow *window,
guint32 timestamp);
@@ -132,42 +130,35 @@ void
meta_window_check_alive (MetaWindow *window,
guint32 timestamp)
{
meta_display_ping_window (window,
timestamp,
delete_ping_reply_func,
delete_ping_timeout_func,
NULL);
meta_window_ping (window,
timestamp,
delete_ping_reply_func,
delete_ping_timeout_func,
NULL);
}
void
meta_window_delete (MetaWindow *window,
guint32 timestamp)
{
if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
meta_error_trap_push (window->display);
if (window->delete_window)
{
meta_error_trap_push (window->display);
if (window->delete_window)
{
meta_topic (META_DEBUG_WINDOW_OPS,
"Deleting %s with delete_window request\n",
window->desc);
meta_window_send_icccm_message (window,
window->display->atom_WM_DELETE_WINDOW,
timestamp);
}
else
{
meta_topic (META_DEBUG_WINDOW_OPS,
"Deleting %s with explicit kill\n",
window->desc);
XKillClient (window->display->xdisplay, window->xwindow);
}
meta_error_trap_pop (window->display);
meta_topic (META_DEBUG_WINDOW_OPS,
"Deleting %s with delete_window request\n",
window->desc);
meta_window_send_icccm_message (window,
window->display->atom_WM_DELETE_WINDOW,
timestamp);
}
else
{
meta_wayland_surface_delete (window->surface);
meta_topic (META_DEBUG_WINDOW_OPS,
"Deleting %s with explicit kill\n",
window->desc);
XKillClient (window->display->xdisplay, window->xwindow);
}
meta_error_trap_pop (window->display);
meta_window_check_alive (window, timestamp);

View File

@@ -55,10 +55,6 @@ typedef struct _MetaWindowPropHooks MetaWindowPropHooks;
typedef struct MetaEdgeResistanceData MetaEdgeResistanceData;
typedef void (* MetaWindowPingFunc) (MetaWindow *window,
guint32 timestamp,
gpointer user_data);
typedef enum {
META_LIST_DEFAULT = 0, /* normal windows */
META_LIST_INCLUDE_OVERRIDE_REDIRECT = 1 << 0, /* normal and O-R */
@@ -84,6 +80,14 @@ typedef enum {
META_TILE_MAXIMIZED
} MetaTileMode;
typedef enum {
META_FOCUS_NONE = 0,
META_FOCUS_X_CLIENT = 1,
META_FOCUS_WAYLAND_CLIENT = 2,
META_FOCUS_NO_FOCUS_WINDOW = 3,
META_FOCUS_STAGE = 4
} MetaFocusType;
struct _MetaDisplay
{
GObject parent_instance;
@@ -117,6 +121,7 @@ struct _MetaDisplay
* like the no_focus_window or the stage X window. */
Window focus_xwindow;
gulong focus_serial;
MetaFocusType focus_type;
/* last timestamp passed to XSetInputFocus */
guint32 last_focus_time;
@@ -178,7 +183,7 @@ struct _MetaDisplay
guint32 window_sequence_counter;
/* Pings which we're waiting for a reply from */
GSList *pending_pings;
GHashTable *pending_pings;
/* Pending focus change */
guint focus_timeout_id;
@@ -215,6 +220,7 @@ struct _MetaDisplay
gboolean grab_threshold_movement_reached; /* raise_on_click == FALSE. */
MetaResizePopup *grab_resize_popup;
GTimeVal grab_last_moveresize_time;
guint32 grab_motion_notify_time;
GList* grab_old_window_stacking;
MetaEdgeResistanceData *grab_edge_resistance_data;
unsigned int grab_last_user_action_was_snap;
@@ -232,8 +238,8 @@ struct _MetaDisplay
int grab_resize_timeout_id;
/* Keybindings stuff */
GHashTable *key_bindings;
GHashTable *key_bindings_index;
MetaKeyBinding *key_bindings;
int n_key_bindings;
int min_keycode;
int max_keycode;
KeySym *keymap;
@@ -443,14 +449,6 @@ void meta_display_retheme_all (void);
void meta_display_set_cursor_theme (const char *theme,
int size);
void meta_display_ping_window (MetaWindow *window,
guint32 timestamp,
MetaWindowPingFunc ping_reply_func,
MetaWindowPingFunc ping_timeout_func,
void *user_data);
void meta_display_pong_for_serial (MetaDisplay *display,
guint32 serial);
int meta_resize_gravity_from_grab_op (MetaGrabOp op);
gboolean meta_grab_op_is_moving (MetaGrabOp op);
@@ -483,9 +481,10 @@ gboolean meta_display_process_barrier_event (MetaDisplay *display,
XIEvent *event);
#endif /* HAVE_XI23 */
void meta_display_set_input_focus_xwindow (MetaDisplay *display,
MetaScreen *screen,
Window window,
guint32 timestamp);
void meta_display_set_input_focus_xwindow (MetaDisplay *display,
MetaScreen *screen,
MetaFocusType type,
Window window,
guint32 timestamp);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -62,6 +62,7 @@ meta_window_ensure_frame (MetaWindow *window)
frame->right_width = 0;
frame->current_cursor = 0;
frame->mapped = FALSE;
frame->is_flashing = FALSE;
frame->borders_cached = FALSE;
@@ -156,8 +157,6 @@ meta_window_ensure_frame (MetaWindow *window)
/* Move keybindings to frame instead of window */
meta_window_grab_keys (window);
meta_ui_map_frame (frame->window->screen->ui, frame->xwindow);
}
void

View File

@@ -47,6 +47,7 @@ struct _MetaFrame
int right_width;
int bottom_height;
guint mapped : 1;
guint need_reapply_frame_shape : 1;
guint is_flashing : 1; /* used by the visual bell flash */
guint borders_cached : 1;

View File

@@ -30,7 +30,6 @@
#include <gio/gio.h>
#include <meta/keybindings.h>
typedef struct _MetaKeyHandler MetaKeyHandler;
struct _MetaKeyHandler
{
char *name;
@@ -48,48 +47,9 @@ struct _MetaKeyBinding
KeyCode keycode;
unsigned int mask;
MetaVirtualModifier modifiers;
gint flags;
MetaKeyHandler *handler;
};
/**
* MetaKeyCombo:
* @keysym: keysym
* @keycode: keycode
* @modifiers: modifiers
*/
typedef struct _MetaKeyCombo MetaKeyCombo;
struct _MetaKeyCombo
{
unsigned int keysym;
unsigned int keycode;
MetaVirtualModifier modifiers;
};
typedef struct
{
char *name;
GSettings *settings;
MetaKeyBindingAction action;
/*
* A list of MetaKeyCombos. Each of them is bound to
* this keypref. If one has keysym==modifiers==0, it is
* ignored.
*/
GSList *combos;
/* for keybindings that can have shift or not like Alt+Tab */
gboolean add_shift:1;
/* for keybindings that apply only to a window */
gboolean per_window:1;
/* for keybindings not added with meta_display_add_keybinding() */
gboolean builtin:1;
} MetaKeyPref;
void meta_display_init_keys (MetaDisplay *display);
void meta_display_shutdown_keys (MetaDisplay *display);
void meta_screen_grab_keys (MetaScreen *screen);
@@ -117,8 +77,5 @@ gboolean meta_prefs_add_keybinding (const char *name,
gboolean meta_prefs_remove_keybinding (const char *name);
GList *meta_prefs_get_keybindings (void);
void meta_prefs_get_overlay_binding (MetaKeyCombo *combo);
const char *meta_prefs_get_iso_next_group_option (void);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -53,7 +53,7 @@
#include "session.h"
#include <meta/prefs.h>
#include <meta/compositor.h>
#include "meta-wayland.h"
#include "meta-wayland-private.h"
#include <glib-object.h>
#include <glib-unix.h>
@@ -254,8 +254,19 @@ meta_get_option_context (void)
bindtextdomain (GETTEXT_PACKAGE, MUTTER_LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
/* We must set the windowing backend here, because Clutter creates the backend
object when the first call is made.
We consider running from mutter-launch equivalent to running from bare metal.
*/
if (getenv ("WESTON_LAUNCHER_SOCK"))
clutter_set_windowing_backend (CLUTTER_WINDOWING_EGL);
ctx = g_option_context_new (NULL);
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, cogl_get_option_group ());
return ctx;
}
@@ -291,12 +302,8 @@ event_dispatch (GSource *source,
gpointer user_data)
{
ClutterEvent *event = clutter_event_get ();
if (event)
{
clutter_do_event (event);
clutter_event_free (event);
}
clutter_do_event (event);
return TRUE;
}
@@ -334,17 +341,16 @@ meta_clutter_init (void)
* also is %NULL, use the default - :0.0
*/
static void
meta_select_display (char *display_arg)
meta_select_display (gchar *display_name)
{
const char *display_name;
if (display_arg)
display_name = (const char *) display_arg;
else
display_name = g_getenv ("MUTTER_DISPLAY");
gchar *envVar = "";
if (display_name)
g_setenv ("DISPLAY", display_name, TRUE);
envVar = g_strconcat ("DISPLAY=", display_name, NULL);
else if (g_getenv ("MUTTER_DISPLAY"))
envVar = g_strconcat ("DISPLAY=",
g_getenv ("MUTTER_DISPLAY"), NULL);
/* DO NOT FREE envVar, putenv() sucks */
putenv (envVar);
}
static void
@@ -379,8 +385,7 @@ meta_init (void)
{
struct sigaction act;
sigset_t empty_mask;
ClutterSettings *clutter_settings;
sigemptyset (&empty_mask);
act.sa_handler = SIG_IGN;
act.sa_mask = empty_mask;
@@ -401,10 +406,6 @@ meta_init (void)
if (g_getenv ("MUTTER_DEBUG"))
meta_set_debugging (TRUE);
/* We consider running from mutter-launch equivalent to running from bare metal. */
if (getenv ("WESTON_LAUNCHER_SOCK"))
clutter_set_windowing_backend (CLUTTER_WINDOWING_EGL);
meta_set_is_wayland_compositor (opt_wayland);
if (g_get_home_dir ())
@@ -436,7 +437,7 @@ meta_init (void)
meta_fatal ("Can't specify both SM save file and SM client id\n");
meta_main_loop = g_main_loop_new (NULL, FALSE);
meta_ui_init ();
/* If we are running with wayland then we don't wait until we have
@@ -450,13 +451,6 @@ meta_init (void)
*/
meta_clutter_init ();
}
/*
* XXX: We cannot handle high dpi scaling yet, so fix the scale to 1
* for now.
*/
clutter_settings = clutter_settings_get_default ();
g_object_set (clutter_settings, "window-scaling-factor", 1, NULL);
}
/**

View File

@@ -468,10 +468,47 @@ meta_cursor_reference_from_buffer (MetaCursorTracker *tracker,
if (tracker->gbm)
{
self->bo = gbm_bo_import (tracker->gbm, GBM_BO_IMPORT_WL_BUFFER,
buffer, GBM_BO_USE_CURSOR_64X64);
if (!self->bo)
meta_warning ("Importing HW cursor from wl_buffer failed\n");
cogl_format = cogl_texture_get_format (COGL_TEXTURE (self->texture));
switch (cogl_format)
{
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
case COGL_PIXEL_FORMAT_ARGB_8888_PRE:
case COGL_PIXEL_FORMAT_ARGB_8888:
gbm_format = GBM_FORMAT_BGRA8888;
break;
case COGL_PIXEL_FORMAT_BGRA_8888_PRE:
case COGL_PIXEL_FORMAT_BGRA_8888:
break;
case COGL_PIXEL_FORMAT_RGB_888:
break;
#else
case COGL_PIXEL_FORMAT_ARGB_8888_PRE:
case COGL_PIXEL_FORMAT_ARGB_8888:
gbm_format = GBM_FORMAT_ARGB8888;
break;
case COGL_PIXEL_FORMAT_BGRA_8888_PRE:
case COGL_PIXEL_FORMAT_BGRA_8888:
gbm_format = GBM_FORMAT_BGRA8888;
break;
case COGL_PIXEL_FORMAT_RGB_888:
gbm_format = GBM_FORMAT_RGB888;
break;
#endif
default:
meta_warning ("Unknown cogl format %d\n", cogl_format);
return self;
}
if (gbm_device_is_format_supported (tracker->gbm, gbm_format,
GBM_BO_USE_CURSOR_64X64))
{
self->bo = gbm_bo_import (tracker->gbm, GBM_BO_IMPORT_WL_BUFFER,
buffer, GBM_BO_USE_CURSOR_64X64);
if (!self->bo)
meta_warning ("Importing HW cursor from wl_buffer failed\n");
}
else
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
}
}
@@ -570,14 +607,12 @@ make_wayland_cursor_tracker (MetaScreen *screen)
compositor = meta_wayland_compositor_get_default ();
compositor->seat->cursor_tracker = self;
#if defined(CLUTTER_WINDOWING_EGL)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
if (meta_wayland_compositor_is_native (compositor))
{
CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (ctx));
self->drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
self->gbm = gbm_create_device (self->drm_fd);
}
#endif
monitors = meta_monitor_manager_get ();
g_signal_connect_object (monitors, "monitors-changed",
@@ -615,9 +650,11 @@ meta_cursor_tracker_get_for_screen (MetaScreen *screen)
if (screen->cursor_tracker)
return screen->cursor_tracker;
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor ())
self = make_wayland_cursor_tracker (screen);
else
#endif
self = make_x11_cursor_tracker (screen);
screen->cursor_tracker = self;

View File

@@ -535,7 +535,7 @@ make_watch (MetaIdleMonitor *monitor,
watch->timeout_source = source;
}
}
else if (monitor->user_active_alarm != None)
else
{
if (timeout_msec != 0)
{
@@ -653,10 +653,8 @@ meta_idle_monitor_remove_watch (MetaIdleMonitor *monitor,
{
g_return_if_fail (META_IS_IDLE_MONITOR (monitor));
g_object_ref (monitor);
g_hash_table_remove (monitor->watches,
GUINT_TO_POINTER (id));
g_object_unref (monitor);
}
/**

View File

@@ -111,7 +111,8 @@ make_output_name (drmModeConnector *connector)
};
const char *connector_type_name;
if (connector->connector_type < G_N_ELEMENTS (connector_type_names))
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";
@@ -650,7 +651,7 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
state = DRM_MODE_DPMS_SUSPEND;
break;
case META_POWER_SAVE_OFF:
state = DRM_MODE_DPMS_OFF;
state = DRM_MODE_DPMS_SUSPEND;
break;
default:
return;

View File

@@ -42,7 +42,9 @@
#include <meta/screen.h>
#include "stack-tracker.h"
#include "ui.h"
#ifdef HAVE_WAYLAND
#include <wayland-server.h>
#endif
#include "meta-xrandr-shared.h"
#include "meta-dbus-xrandr.h"
@@ -52,6 +54,19 @@ typedef struct _MetaMonitorManager MetaMonitorManager;
typedef struct _MetaMonitorConfigClass MetaMonitorConfigClass;
typedef struct _MetaMonitorConfig MetaMonitorConfig;
#ifndef HAVE_WAYLAND
enum wl_output_transform {
WL_OUTPUT_TRANSFORM_NORMAL,
WL_OUTPUT_TRANSFORM_90,
WL_OUTPUT_TRANSFORM_180,
WL_OUTPUT_TRANSFORM_270,
WL_OUTPUT_TRANSFORM_FLIPPED,
WL_OUTPUT_TRANSFORM_FLIPPED_90,
WL_OUTPUT_TRANSFORM_FLIPPED_180,
WL_OUTPUT_TRANSFORM_FLIPPED_270
};
#endif
typedef struct _MetaOutput MetaOutput;
typedef struct _MetaCRTC MetaCRTC;
typedef struct _MetaMonitorMode MetaMonitorMode;

View File

@@ -34,6 +34,7 @@
#include "util-private.h"
#include <meta/errors.h>
#include "monitor-private.h"
#include "meta-wayland-private.h"
#include "meta-dbus-xrandr.h"
@@ -287,7 +288,7 @@ make_logical_config (MetaMonitorManager *manager)
for (j = 0; j < monitor_infos->len; j++)
{
MetaMonitorInfo *info = &g_array_index (monitor_infos, MetaMonitorInfo, j);
MetaMonitorInfo *info = &g_array_index (monitor_infos, MetaMonitorInfo, i);
if (meta_rectangle_equal (&crtc->rect,
&info->rect))
{
@@ -355,35 +356,19 @@ make_logical_config (MetaMonitorManager *manager)
static GType
get_default_backend (void)
{
#if defined(CLUTTER_WINDOWING_EGL)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
return META_TYPE_MONITOR_MANAGER_KMS;
#endif
#if defined(CLUTTER_WINDOWING_X11)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
if (meta_is_wayland_compositor ())
{
/* If we're a Wayland compositor using the X11 backend,
* we're a nested configuration, so return the dummy
* monitor setup. */
if (meta_is_wayland_compositor ())
return META_TYPE_MONITOR_MANAGER;
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_XRANDR;
return META_TYPE_MONITOR_MANAGER;
}
#endif
#if defined(CLUTTER_WINDOWING_WAYLAND)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WAYLAND))
{
/* Use the dummy implementation on Wayland for now.
* In the future, we should support wl_fullscreen_output
* which will have CRTC management in the protocol. */
return META_TYPE_MONITOR_MANAGER;
}
#endif
g_assert_not_reached ();
else
return META_TYPE_MONITOR_MANAGER_XRANDR;
}
static MetaMonitorManager *

View File

@@ -57,6 +57,7 @@
#define KEY_OVERLAY_KEY "overlay-key"
#define KEY_WORKSPACES_ONLY_ON_PRIMARY "workspaces-only-on-primary"
#define KEY_NO_TAB_POPUP "no-tab-popup"
/* These are the different schemas we are keeping
* a GSettings instance for */
@@ -111,6 +112,8 @@ static char **workspace_names = NULL;
static gboolean workspaces_only_on_primary = FALSE;
static gboolean no_tab_popup = FALSE;
static char *iso_next_group_option = NULL;
static void handle_preference_update_enum (GSettings *settings,
@@ -362,6 +365,13 @@ static MetaBoolPreference preferences_bool[] =
},
&workspaces_only_on_primary,
},
{
{ KEY_NO_TAB_POPUP,
SCHEMA_MUTTER,
META_PREF_NO_TAB_POPUP,
},
&no_tab_popup,
},
{
{ "auto-maximize",
SCHEMA_MUTTER,
@@ -1803,6 +1813,9 @@ meta_preference_to_string (MetaPreference pref)
case META_PREF_WORKSPACES_ONLY_ON_PRIMARY:
return "WORKSPACES_ONLY_ON_PRIMARY";
case META_PREF_NO_TAB_POPUP:
return "NO_TAB_POPUP";
case META_PREF_DRAGGABLE_BORDER_WIDTH:
return "DRAGGABLE_BORDER_WIDTH";
@@ -1856,7 +1869,7 @@ init_bindings (void)
pref = g_new0 (MetaKeyPref, 1);
pref->name = g_strdup ("overlay-key");
pref->action = META_KEYBINDING_ACTION_OVERLAY_KEY;
pref->combos = g_slist_prepend (pref->combos, &overlay_key_combo);
pref->bindings = g_slist_prepend (pref->bindings, &overlay_key_combo);
pref->builtin = 1;
g_hash_table_insert (key_bindings, g_strdup ("overlay-key"), pref);
@@ -1866,7 +1879,7 @@ static gboolean
update_binding (MetaKeyPref *binding,
gchar **strokes)
{
GSList *old_combos, *a, *b;
GSList *old_bindings, *a, *b;
gboolean changed;
unsigned int keysym;
unsigned int keycode;
@@ -1878,8 +1891,8 @@ update_binding (MetaKeyPref *binding,
"Binding \"%s\" has new GSettings value\n",
binding->name);
old_combos = binding->combos;
binding->combos = NULL;
old_bindings = binding->bindings;
binding->bindings = NULL;
for (i = 0; strokes && strokes[i]; i++)
{
@@ -1920,17 +1933,17 @@ update_binding (MetaKeyPref *binding,
combo->keysym = keysym;
combo->keycode = keycode;
combo->modifiers = mods;
binding->combos = g_slist_prepend (binding->combos, combo);
binding->bindings = g_slist_prepend (binding->bindings, combo);
meta_topic (META_DEBUG_KEYBINDINGS,
"New keybinding for \"%s\" is keysym = 0x%x keycode = 0x%x mods = 0x%x\n",
binding->name, keysym, keycode, mods);
}
binding->combos = g_slist_reverse (binding->combos);
binding->bindings = g_slist_reverse (binding->bindings);
a = old_combos;
b = binding->combos;
a = old_bindings;
b = binding->bindings;
while (TRUE)
{
if ((!a && b) || (a && !b))
@@ -1955,7 +1968,7 @@ update_binding (MetaKeyPref *binding,
}
}
g_slist_free_full (old_combos, g_free);
g_slist_free_full (old_bindings, g_free);
return changed;
}
@@ -2090,7 +2103,7 @@ meta_prefs_add_keybinding (const char *name,
pref->name = g_strdup (name);
pref->settings = g_object_ref (settings);
pref->action = action;
pref->combos = NULL;
pref->bindings = NULL;
pref->add_shift = (flags & META_KEY_BINDING_REVERSES) != 0;
pref->per_window = (flags & META_KEY_BINDING_PER_WINDOW) != 0;
pref->builtin = (flags & META_KEY_BINDING_BUILTIN) != 0;
@@ -2154,6 +2167,11 @@ meta_prefs_remove_keybinding (const char *name)
return TRUE;
}
/**
* meta_prefs_get_keybindings:
*
* Returns: (element-type MetaKeyPref) (transfer container):
*/
GList *
meta_prefs_get_keybindings ()
{
@@ -2254,7 +2272,7 @@ meta_prefs_get_window_binding (const char *name,
if (pref->per_window)
{
GSList *s = pref->combos;
GSList *s = pref->bindings;
while (s)
{
@@ -2302,6 +2320,25 @@ meta_prefs_get_workspaces_only_on_primary (void)
return workspaces_only_on_primary;
}
gboolean
meta_prefs_get_no_tab_popup (void)
{
return no_tab_popup;
}
void
meta_prefs_set_no_tab_popup (gboolean whether)
{
MetaBasePreference *pref;
if (find_pref (preferences_bool, sizeof(MetaBoolPreference),
KEY_NO_TAB_POPUP, &pref))
{
g_settings_set_boolean (SETTINGS (pref->schema), KEY_NO_TAB_POPUP, whether);
}
}
int
meta_prefs_get_draggable_border_width (void)
{

View File

@@ -64,6 +64,8 @@ struct _MetaScreen
Visual *default_xvisual;
MetaRectangle rect; /* Size of screen; rect.x & rect.y are always 0 */
MetaUI *ui;
MetaTabPopup *tab_popup, *ws_popup;
MetaTilePreview *tile_preview;
guint tile_preview_timeout_id;
@@ -149,9 +151,25 @@ void meta_screen_foreach_window (MetaScreen *scree
void meta_screen_update_cursor (MetaScreen *screen);
void meta_screen_update_tile_preview (MetaScreen *screen,
void meta_screen_tab_popup_create (MetaScreen *screen,
MetaTabList list_type,
MetaTabShowType show_type,
MetaWindow *initial_window);
void meta_screen_tab_popup_forward (MetaScreen *screen);
void meta_screen_tab_popup_backward (MetaScreen *screen);
MetaWindow* meta_screen_tab_popup_get_selected (MetaScreen *screen);
void meta_screen_tab_popup_destroy (MetaScreen *screen);
void meta_screen_workspace_popup_create (MetaScreen *screen,
MetaWorkspace *initial_selection);
void meta_screen_workspace_popup_select (MetaScreen *screen,
MetaWorkspace *workspace);
MetaWorkspace*meta_screen_workspace_popup_get_selected (MetaScreen *screen);
void meta_screen_workspace_popup_destroy (MetaScreen *screen);
void meta_screen_tile_preview_update (MetaScreen *screen,
gboolean delay);
void meta_screen_hide_tile_preview (MetaScreen *screen);
void meta_screen_tile_preview_hide (MetaScreen *screen);
MetaWindow* meta_screen_get_mouse_window (MetaScreen *screen,
MetaWindow *not_this_one);
@@ -223,7 +241,7 @@ void meta_screen_workspace_switched (MetaScreen *screen,
void meta_screen_set_active_workspace_hint (MetaScreen *screen);
void meta_screen_create_guard_window (MetaScreen *screen);
Window meta_screen_create_guard_window (Display *xdisplay, MetaScreen *screen);
gboolean meta_screen_handle_xevent (MetaScreen *screen,
XEvent *xevent);

View File

@@ -43,7 +43,7 @@
#include <meta/compositor.h>
#include "mutter-enum-types.h"
#include "core.h"
#include "meta-wayland.h"
#include "meta-wayland-private.h"
#include "meta-cursor-tracker-private.h"
#include <X11/extensions/Xinerama.h>
@@ -308,8 +308,6 @@ set_supported_hint (MetaScreen *screen)
#include <meta/atomnames.h>
#undef item
#undef EWMH_ATOMS_ONLY
screen->display->atom__GTK_FRAME_EXTENTS,
};
XChangeProperty (screen->display->xdisplay, screen->xroot,
@@ -391,8 +389,6 @@ int
meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen,
int index)
{
g_return_val_if_fail (index >= 0 && index < screen->n_monitor_infos, -1);
meta_screen_ensure_xinerama_indices (screen);
return screen->monitor_infos[index].xinerama_index;
@@ -449,16 +445,17 @@ reload_monitor_infos (MetaScreen *screen)
* should effectively be forwarded to events on the background actor,
* providing that the scene graph is set up correctly.
*/
static Window
create_guard_window (Display *xdisplay, MetaScreen *screen)
Window
meta_screen_create_guard_window (Display *xdisplay, MetaScreen *screen)
{
XSetWindowAttributes attributes;
Window guard_window;
gulong create_serial;
MetaStackWindow stack_window;
attributes.event_mask = NoEventMask;
attributes.override_redirect = True;
attributes.background_pixel = BlackPixel (xdisplay, screen->number);
/* We have to call record_add() after we have the new window ID,
* so save the serial for the CreateWindow request until then */
@@ -471,10 +468,10 @@ create_guard_window (Display *xdisplay, MetaScreen *screen)
screen->rect.width,
screen->rect.height,
0, /* border width */
0, /* depth */
InputOnly, /* class */
CopyFromParent, /* depth */
CopyFromParent, /* class */
CopyFromParent, /* visual */
CWEventMask|CWOverrideRedirect,
CWEventMask|CWOverrideRedirect|CWBackPixel,
&attributes);
{
@@ -762,6 +759,10 @@ meta_screen_new (MetaDisplay *display,
screen->ui = meta_ui_new (screen->display->xdisplay,
screen->xscreen);
screen->tab_popup = NULL;
screen->ws_popup = NULL;
screen->tile_preview = NULL;
screen->tile_preview_timeout_id = 0;
screen->stack = meta_stack_new (screen);
@@ -866,6 +867,9 @@ meta_screen_free (MetaScreen *screen,
if (screen->tile_preview_timeout_id)
g_source_remove (screen->tile_preview_timeout_id);
if (screen->tile_preview)
meta_tile_preview_free (screen->tile_preview);
g_free (screen->screen_name);
g_object_unref (screen);
@@ -874,13 +878,6 @@ meta_screen_free (MetaScreen *screen,
meta_display_ungrab (display);
}
void
meta_screen_create_guard_window (MetaScreen *screen)
{
if (screen->guard_window == None)
screen->guard_window = create_guard_window (screen->display->xdisplay, screen);
}
void
meta_screen_manage_all_windows (MetaScreen *screen)
{
@@ -888,6 +885,10 @@ meta_screen_manage_all_windows (MetaScreen *screen)
MetaStackWindow *children;
int n_children, i;
if (screen->guard_window == None)
screen->guard_window =
meta_screen_create_guard_window (screen->display->xdisplay, screen);
meta_stack_freeze (screen->stack);
meta_stack_tracker_get_stack (screen->stack_tracker, &_children, &n_children);
@@ -896,8 +897,8 @@ meta_screen_manage_all_windows (MetaScreen *screen)
for (i = 0; i < n_children; ++i)
{
meta_window_x11_new (screen->display, children[i].x11.xwindow, TRUE,
META_COMP_EFFECT_NONE);
meta_window_new (screen->display, children[i].x11.xwindow, TRUE,
META_COMP_EFFECT_NONE);
}
g_free (children);
@@ -1427,8 +1428,255 @@ meta_screen_update_cursor (MetaScreen *screen)
screen->current_cursor);
}
void
meta_screen_tab_popup_create (MetaScreen *screen,
MetaTabList list_type,
MetaTabShowType show_type,
MetaWindow *initial_selection)
{
MetaTabEntry *entries;
GList *tab_list;
GList *tmp;
int len;
int i;
if (screen->tab_popup)
return;
tab_list = meta_display_get_tab_list (screen->display,
list_type,
screen,
screen->active_workspace);
len = g_list_length (tab_list);
entries = g_new (MetaTabEntry, len + 1);
entries[len].key = NULL;
entries[len].title = NULL;
entries[len].icon = NULL;
i = 0;
tmp = tab_list;
while (i < len)
{
MetaWindow *window;
MetaRectangle r;
window = tmp->data;
entries[i].key = (MetaTabEntryKey) window;
entries[i].title = window->title;
entries[i].icon = g_object_ref (window->icon);
entries[i].blank = FALSE;
entries[i].hidden = !meta_window_showing_on_its_workspace (window);
entries[i].demands_attention = window->wm_state_demands_attention;
if (show_type == META_TAB_SHOW_INSTANTLY ||
!entries[i].hidden ||
!meta_window_get_icon_geometry (window, &r))
meta_window_get_frame_rect (window, &r);
entries[i].rect = r;
/* Find inside of highlight rectangle to be used when window is
* outlined for tabbing. This should be the size of the
* east/west frame, and the size of the south frame, on those
* sides. On the top it should be the size of the south frame
* edge.
*/
#define OUTLINE_WIDTH 5
/* Top side */
if (!entries[i].hidden &&
window->frame && window->frame->bottom_height > 0 &&
window->frame->child_y >= window->frame->bottom_height)
entries[i].inner_rect.y = window->frame->bottom_height;
else
entries[i].inner_rect.y = OUTLINE_WIDTH;
/* Bottom side */
if (!entries[i].hidden &&
window->frame && window->frame->bottom_height != 0)
entries[i].inner_rect.height = r.height
- entries[i].inner_rect.y - window->frame->bottom_height;
else
entries[i].inner_rect.height = r.height
- entries[i].inner_rect.y - OUTLINE_WIDTH;
/* Left side */
if (!entries[i].hidden && window->frame && window->frame->child_x != 0)
entries[i].inner_rect.x = window->frame->child_x;
else
entries[i].inner_rect.x = OUTLINE_WIDTH;
/* Right side */
if (!entries[i].hidden &&
window->frame && window->frame->right_width != 0)
entries[i].inner_rect.width = r.width
- entries[i].inner_rect.x - window->frame->right_width;
else
entries[i].inner_rect.width = r.width
- entries[i].inner_rect.x - OUTLINE_WIDTH;
++i;
tmp = tmp->next;
}
if (!meta_prefs_get_no_tab_popup ())
screen->tab_popup = meta_ui_tab_popup_new (entries,
screen->number,
len,
5, /* FIXME */
TRUE);
for (i = 0; i < len; i++)
g_object_unref (entries[i].icon);
g_free (entries);
g_list_free (tab_list);
meta_ui_tab_popup_select (screen->tab_popup,
(MetaTabEntryKey) initial_selection);
if (show_type != META_TAB_SHOW_INSTANTLY)
meta_ui_tab_popup_set_showing (screen->tab_popup, TRUE);
}
void
meta_screen_tab_popup_forward (MetaScreen *screen)
{
g_return_if_fail (screen->tab_popup != NULL);
meta_ui_tab_popup_forward (screen->tab_popup);
}
void
meta_screen_tab_popup_backward (MetaScreen *screen)
{
g_return_if_fail (screen->tab_popup != NULL);
meta_ui_tab_popup_backward (screen->tab_popup);
}
MetaWindow *
meta_screen_tab_popup_get_selected (MetaScreen *screen)
{
g_return_val_if_fail (screen->tab_popup != NULL, NULL);
return (MetaWindow *) meta_ui_tab_popup_get_selected (screen->tab_popup);
}
void
meta_screen_tab_popup_destroy (MetaScreen *screen)
{
if (screen->tab_popup)
{
meta_ui_tab_popup_free (screen->tab_popup);
screen->tab_popup = NULL;
}
}
void
meta_screen_workspace_popup_create (MetaScreen *screen,
MetaWorkspace *initial_selection)
{
MetaTabEntry *entries;
int len;
int i;
MetaWorkspaceLayout layout;
int n_workspaces;
int current_workspace;
if (screen->ws_popup || meta_prefs_get_no_tab_popup ())
return;
current_workspace = meta_workspace_index (screen->active_workspace);
n_workspaces = meta_screen_get_n_workspaces (screen);
meta_screen_calc_workspace_layout (screen, n_workspaces,
current_workspace, &layout);
len = layout.grid_area;
entries = g_new (MetaTabEntry, len + 1);
entries[len].key = NULL;
entries[len].title = NULL;
entries[len].icon = NULL;
i = 0;
while (i < len)
{
if (layout.grid[i] >= 0)
{
MetaWorkspace *workspace;
workspace = meta_screen_get_workspace_by_index (screen,
layout.grid[i]);
entries[i].key = (MetaTabEntryKey) workspace;
entries[i].title = meta_workspace_get_name (workspace);
entries[i].icon = NULL;
entries[i].blank = FALSE;
g_assert (entries[i].title != NULL);
}
else
{
entries[i].key = NULL;
entries[i].title = NULL;
entries[i].icon = NULL;
entries[i].blank = TRUE;
}
entries[i].hidden = FALSE;
entries[i].demands_attention = FALSE;
++i;
}
screen->ws_popup = meta_ui_tab_popup_new (entries,
screen->number,
len,
layout.cols,
FALSE);
g_free (entries);
meta_screen_free_workspace_layout (&layout);
meta_ui_tab_popup_select (screen->ws_popup,
(MetaTabEntryKey) initial_selection);
meta_ui_tab_popup_set_showing (screen->ws_popup, TRUE);
}
void
meta_screen_workspace_popup_select (MetaScreen *screen,
MetaWorkspace *workspace)
{
g_return_if_fail (screen->ws_popup != NULL);
meta_ui_tab_popup_select (screen->ws_popup,
(MetaTabEntryKey) workspace);
}
MetaWorkspace *
meta_screen_workspace_popup_get_selected (MetaScreen *screen)
{
g_return_val_if_fail (screen->ws_popup != NULL, NULL);
return (MetaWorkspace *) meta_ui_tab_popup_get_selected (screen->ws_popup);
}
void
meta_screen_workspace_popup_destroy (MetaScreen *screen)
{
if (screen->ws_popup)
{
meta_ui_tab_popup_free (screen->ws_popup);
screen->ws_popup = NULL;
}
}
static gboolean
meta_screen_update_tile_preview_timeout (gpointer data)
meta_screen_tile_preview_update_timeout (gpointer data)
{
MetaScreen *screen = data;
MetaWindow *window = screen->display->grab_window;
@@ -1436,6 +1684,22 @@ meta_screen_update_tile_preview_timeout (gpointer data)
screen->tile_preview_timeout_id = 0;
if (!screen->tile_preview)
{
Window xwindow;
gulong create_serial;
MetaStackWindow stack_window;
screen->tile_preview = meta_tile_preview_new (screen->number);
xwindow = meta_tile_preview_get_xwindow (screen->tile_preview,
&create_serial);
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
stack_window.x11.xwindow = xwindow;
meta_stack_tracker_record_add (screen->stack_tracker,
&stack_window,
create_serial);
}
if (window)
{
switch (window->tile_mode)
@@ -1460,16 +1724,12 @@ meta_screen_update_tile_preview_timeout (gpointer data)
if (needs_preview)
{
MetaRectangle tile_rect;
int monitor;
monitor = meta_window_get_current_tile_monitor_number (window);
meta_window_get_current_tile_area (window, &tile_rect);
meta_compositor_show_tile_preview (screen->display->compositor,
screen, window, &tile_rect, monitor);
meta_tile_preview_show (screen->tile_preview, &tile_rect);
}
else
meta_compositor_hide_tile_preview (screen->display->compositor,
screen);
meta_tile_preview_hide (screen->tile_preview);
return FALSE;
}
@@ -1477,7 +1737,7 @@ meta_screen_update_tile_preview_timeout (gpointer data)
#define TILE_PREVIEW_TIMEOUT_MS 200
void
meta_screen_update_tile_preview (MetaScreen *screen,
meta_screen_tile_preview_update (MetaScreen *screen,
gboolean delay)
{
if (delay)
@@ -1487,7 +1747,7 @@ meta_screen_update_tile_preview (MetaScreen *screen,
screen->tile_preview_timeout_id =
g_timeout_add (TILE_PREVIEW_TIMEOUT_MS,
meta_screen_update_tile_preview_timeout,
meta_screen_tile_preview_update_timeout,
screen);
}
else
@@ -1495,18 +1755,18 @@ meta_screen_update_tile_preview (MetaScreen *screen,
if (screen->tile_preview_timeout_id > 0)
g_source_remove (screen->tile_preview_timeout_id);
meta_screen_update_tile_preview_timeout ((gpointer)screen);
meta_screen_tile_preview_update_timeout ((gpointer)screen);
}
}
void
meta_screen_hide_tile_preview (MetaScreen *screen)
meta_screen_tile_preview_hide (MetaScreen *screen)
{
if (screen->tile_preview_timeout_id > 0)
g_source_remove (screen->tile_preview_timeout_id);
meta_compositor_hide_tile_preview (screen->display->compositor,
screen);
if (screen->tile_preview)
meta_tile_preview_hide (screen->tile_preview);
}
MetaWindow*

View File

@@ -1041,7 +1041,7 @@ stack_tracker_event_received (MetaStackTracker *tracker,
if (op->any.serial < tracker->xserver_serial)
{
/* g_warning ("Spurious X event received affecting stack; doing full re-query"); */
g_warning ("Spurious X event received affecting stack; doing full re-query");
resync_verified_stack_with_xserver_stack (tracker);
meta_stack_tracker_dump (tracker);
return;

View File

@@ -79,7 +79,9 @@ struct _MetaWindow
const MetaMonitorInfo *monitor;
MetaWorkspace *workspace;
MetaWindowClientType client_type;
#ifdef HAVE_WAYLAND
MetaWaylandSurface *surface;
#endif
Window xwindow;
/* may be NULL! not all windows get decorated */
MetaFrame *frame;
@@ -238,7 +240,7 @@ struct _MetaWindow
/* These are the flags from WM_PROTOCOLS */
guint take_focus : 1;
guint delete_window : 1;
guint can_ping : 1;
guint net_wm_ping : 1;
/* Globally active / No input */
guint input : 1;
@@ -408,6 +410,12 @@ struct _MetaWindow
*/
MetaRectangle rect;
/* The size and position 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;
GtkBorder custom_frame_extents;
@@ -459,6 +467,8 @@ struct _MetaWindow
/* Bypass compositor hints */
guint bypass_compositor;
GSList *pending_pings;
};
struct _MetaWindowClass
@@ -496,22 +506,12 @@ struct _MetaWindowClass
#define META_WINDOW_ALLOWS_HORIZONTAL_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && (w)->size_hints.min_width < (w)->size_hints.max_width)
#define META_WINDOW_ALLOWS_VERTICAL_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && (w)->size_hints.min_height < (w)->size_hints.max_height)
MetaWindow * _meta_window_shared_new (MetaDisplay *display,
MetaScreen *screen,
MetaWindowClientType client_type,
MetaWaylandSurface *surface,
Window xwindow,
gulong existing_wm_state,
MetaCompEffect effect,
XWindowAttributes *attrs);
MetaWindow * meta_window_x11_new (MetaDisplay *display,
Window xwindow,
gboolean must_be_viewable,
MetaCompEffect effect);
MetaWindow * meta_window_wayland_new (MetaDisplay *display,
MetaWindow* meta_window_new (MetaDisplay *display,
Window xwindow,
gboolean must_be_viewable,
MetaCompEffect effect);
MetaWindow *meta_window_new_for_wayland (MetaDisplay *display,
MetaWaylandSurface *surface);
void meta_window_unmanage (MetaWindow *window,
guint32 timestamp);
void meta_window_calc_showing (MetaWindow *window);
@@ -615,6 +615,12 @@ void meta_window_move_resize_wayland (MetaWindow *window,
int height,
int dx,
int dy);
gboolean meta_window_configure_request (MetaWindow *window,
XEvent *event);
gboolean meta_window_property_notify (MetaWindow *window,
XEvent *event);
gboolean meta_window_client_message (MetaWindow *window,
XEvent *event);
void meta_window_set_focused_internal (MetaWindow *window,
gboolean focused);
@@ -646,7 +652,6 @@ void meta_window_handle_mouse_grab_op_xevent (MetaWindow *window,
GList* meta_window_get_workspaces (MetaWindow *window);
int meta_window_get_current_tile_monitor_number (MetaWindow *window);
void meta_window_get_current_tile_area (MetaWindow *window,
MetaRectangle *tile_area);
@@ -692,6 +697,8 @@ void meta_window_set_user_time (MetaWindow *window,
void meta_window_update_icon_now (MetaWindow *window);
void meta_window_update_role (MetaWindow *window);
void meta_window_update_net_wm_type (MetaWindow *window);
void meta_window_update_for_monitors_changed (MetaWindow *window);
void meta_window_update_on_all_workspaces (MetaWindow *window);
@@ -705,6 +712,10 @@ void meta_window_compute_tile_match (MetaWindow *window);
gboolean meta_window_updates_are_frozen (MetaWindow *window);
void meta_window_update_opaque_region_x11 (MetaWindow *window);
void meta_window_update_input_region_x11 (MetaWindow *window);
void meta_window_update_shape_region_x11 (MetaWindow *window);
void meta_window_set_title (MetaWindow *window,
const char *title);
void meta_window_set_wm_class (MetaWindow *window,
@@ -724,9 +735,6 @@ void meta_window_set_transient_for (MetaWindow *window,
void meta_window_set_opacity (MetaWindow *window,
guint opacity);
void meta_window_set_custom_frame_extents (MetaWindow *window,
GtkBorder *extents);
void meta_window_handle_enter (MetaWindow *window,
guint32 timestamp,
guint root_x,
@@ -735,14 +743,17 @@ void meta_window_handle_enter (MetaWindow *window,
void meta_window_set_surface_mapped (MetaWindow *window,
gboolean surface_mapped);
typedef void (* MetaWindowPingFunc) (MetaWindow *window,
guint32 timestamp,
gpointer user_data);
void meta_window_ping (MetaWindow *window,
guint32 timestamp,
MetaWindowPingFunc ping_reply_func,
MetaWindowPingFunc ping_timeout_func,
void *user_data);
void meta_window_pong (MetaWindow *window,
guint32 timestamp);
Window meta_window_get_toplevel_xwindow (MetaWindow *window);
void meta_window_get_client_area_rect (const MetaWindow *window,
cairo_rectangle_int_t *rect);
void meta_window_activate_full (MetaWindow *window,
guint32 timestamp,
MetaClientType source_indication,
MetaWorkspace *workspace);
#endif

View File

@@ -39,7 +39,6 @@
#include <config.h>
#include "window-props.h"
#include "window-x11.h"
#include <meta/errors.h>
#include "xprops.h"
#include "frame.h"
@@ -230,7 +229,7 @@ reload_net_wm_window_type (MetaWindow *window,
MetaPropValue *value,
gboolean initial)
{
meta_window_x11_update_net_wm_type (window);
meta_window_update_net_wm_type (window);
}
static void
@@ -303,18 +302,22 @@ reload_gtk_frame_extents (MetaWindow *window,
}
else
{
GtkBorder extents;
extents.left = (int)value->v.cardinal_list.cardinals[0];
extents.right = (int)value->v.cardinal_list.cardinals[1];
extents.top = (int)value->v.cardinal_list.cardinals[2];
extents.bottom = (int)value->v.cardinal_list.cardinals[3];
meta_window_set_custom_frame_extents (window, &extents);
GtkBorder *extents = &window->custom_frame_extents;
window->has_custom_frame_extents = TRUE;
extents->left = (int)value->v.cardinal_list.cardinals[0];
extents->right = (int)value->v.cardinal_list.cardinals[1];
extents->top = (int)value->v.cardinal_list.cardinals[2];
extents->bottom = (int)value->v.cardinal_list.cardinals[3];
}
}
else
{
meta_window_set_custom_frame_extents (window, NULL);
window->has_custom_frame_extents = FALSE;
}
if (!initial)
meta_window_queue(window, META_QUEUE_MOVE_RESIZE);
}
static void
@@ -330,7 +333,7 @@ reload_wm_window_role (MetaWindow *window,
MetaPropValue *value,
gboolean initial)
{
meta_window_x11_update_role (window);
meta_window_update_role (window);
}
static void
@@ -555,7 +558,7 @@ reload_opaque_region (MetaWindow *window,
MetaPropValue *value,
gboolean initial)
{
meta_window_x11_update_opaque_region (window);
meta_window_update_opaque_region_x11 (window);
}
static void
@@ -842,7 +845,7 @@ reload_mwm_hints (MetaWindow *window,
meta_window_recalc_features (window);
/* We do all this anyhow at the end of meta_window_x11_new() */
/* We do all this anyhow at the end of meta_window_new() */
if (!window->constructing)
{
if (window->decorated)
@@ -1407,7 +1410,7 @@ reload_wm_protocols (MetaWindow *window,
window->take_focus = FALSE;
window->delete_window = FALSE;
window->can_ping = FALSE;
window->net_wm_ping = FALSE;
if (value->type == META_PROP_VALUE_INVALID)
return;
@@ -1423,7 +1426,7 @@ reload_wm_protocols (MetaWindow *window,
window->delete_window = TRUE;
else if (value->v.atom_list.atoms[i] ==
window->display->atom__NET_WM_PING)
window->can_ping = TRUE;
window->net_wm_ping = TRUE;
++i;
}
@@ -1761,8 +1764,8 @@ meta_display_init_window_prop_hooks (MetaDisplay *display)
{ display->atom__NET_WM_ICON_GEOMETRY, META_PROP_VALUE_CARDINAL_LIST, reload_icon_geometry, FALSE, FALSE },
{ display->atom_WM_CLIENT_LEADER, META_PROP_VALUE_INVALID, complain_about_broken_client, FALSE, FALSE },
{ display->atom_SM_CLIENT_ID, META_PROP_VALUE_INVALID, complain_about_broken_client, FALSE, FALSE },
{ display->atom_WM_WINDOW_ROLE, META_PROP_VALUE_INVALID, reload_wm_window_role, TRUE, FALSE },
{ display->atom__NET_WM_WINDOW_TYPE, META_PROP_VALUE_INVALID, reload_net_wm_window_type, TRUE, TRUE },
{ display->atom_WM_WINDOW_ROLE, META_PROP_VALUE_INVALID, reload_wm_window_role, FALSE, FALSE },
{ display->atom__NET_WM_WINDOW_TYPE, META_PROP_VALUE_INVALID, reload_net_wm_window_type, FALSE, TRUE },
{ display->atom__NET_WM_STRUT, META_PROP_VALUE_INVALID, reload_struts, FALSE, FALSE },
{ display->atom__NET_WM_STRUT_PARTIAL, META_PROP_VALUE_INVALID, reload_struts, FALSE, FALSE },
{ display->atom__NET_WM_BYPASS_COMPOSITOR, META_PROP_VALUE_CARDINAL, reload_bypass_compositor, FALSE, FALSE },

File diff suppressed because it is too large Load Diff

View File

@@ -1,45 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2002 Red Hat, Inc.
* Copyright (C) 2003, 2004 Rob Adams
* Copyright (C) 2004-2006 Elijah Newren
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef META_WINDOW_X11_H
#define META_WINDOW_X11_H
#include <meta/window.h>
#include <X11/Xlib.h>
void meta_window_x11_set_net_wm_state (MetaWindow *window);
void meta_window_x11_set_wm_state (MetaWindow *window);
void meta_window_x11_update_role (MetaWindow *window);
void meta_window_x11_update_net_wm_type (MetaWindow *window);
void meta_window_x11_update_opaque_region (MetaWindow *window);
void meta_window_x11_update_input_region (MetaWindow *window);
void meta_window_x11_update_shape_region (MetaWindow *window);
gboolean meta_window_x11_configure_request (MetaWindow *window,
XEvent *event);
gboolean meta_window_x11_property_notify (MetaWindow *window,
XEvent *event);
gboolean meta_window_x11_client_message (MetaWindow *window,
XEvent *event);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -214,6 +214,21 @@ typedef enum
META_GRAB_OP_KEYBOARD_RESIZING_SW,
META_GRAB_OP_KEYBOARD_RESIZING_NW,
/* Alt+Tab */
META_GRAB_OP_KEYBOARD_TABBING_NORMAL,
META_GRAB_OP_KEYBOARD_TABBING_DOCK,
/* Alt+Esc */
META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL,
META_GRAB_OP_KEYBOARD_ESCAPING_DOCK,
META_GRAB_OP_KEYBOARD_ESCAPING_GROUP,
/* Alt+F6 */
META_GRAB_OP_KEYBOARD_TABBING_GROUP,
META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING,
/* Frame button ops */
META_GRAB_OP_CLICKING_MINIMIZE,
META_GRAB_OP_CLICKING_MAXIMIZE,

View File

@@ -66,8 +66,6 @@ void meta_compositor_window_shape_changed (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_window_opacity_changed (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_window_surface_changed (MetaCompositor *compositor,
MetaWindow *window);
gboolean meta_compositor_process_event (MetaCompositor *compositor,
XEvent *event,
@@ -77,10 +75,11 @@ gboolean meta_compositor_filter_keybinding (MetaCompositor *compositor,
MetaScreen *screen,
MetaKeyBinding *binding);
void meta_compositor_add_window (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_remove_window (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_add_window (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_remove_window (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_show_window (MetaCompositor *compositor,
MetaWindow *window,
MetaCompEffect effect);
@@ -102,6 +101,10 @@ void meta_compositor_unmaximize_window (MetaCompositor *compositor,
MetaRectangle *old_rect,
MetaRectangle *new_rect);
void meta_compositor_window_mapped (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_window_unmapped (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_sync_window_geometry (MetaCompositor *compositor,
MetaWindow *window,
gboolean did_placement);
@@ -123,12 +126,4 @@ void meta_compositor_sync_screen_size (MetaCompositor *compositor,
void meta_compositor_flash_screen (MetaCompositor *compositor,
MetaScreen *screen);
void meta_compositor_show_tile_preview (MetaCompositor *compositor,
MetaScreen *screen,
MetaWindow *window,
MetaRectangle *tile_rect,
int tile_monitor_number);
void meta_compositor_hide_tile_preview (MetaCompositor *compositor,
MetaScreen *screen);
#endif /* META_COMPOSITOR_H */

View File

@@ -158,11 +158,6 @@ struct _MetaPluginClass
gint to,
MetaMotionDirection direction);
void (*show_tile_preview) (MetaPlugin *plugin,
MetaWindow *window,
MetaRectangle *tile_rect,
int tile_monitor_number);
void (*hide_tile_preview) (MetaPlugin *plugin);
/**
* MetaPluginClass::kill_window_effects:

View File

@@ -69,12 +69,16 @@ gboolean meta_shaped_texture_update_area (MetaShapedTexture *stex,
int x,
int y,
int width,
int height);
int height,
cairo_region_t *unobscured_region);
CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex);
void meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
CoglTexture *mask_texture);
void meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex,
cairo_region_t *shape_region);
void meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex,
cairo_region_t *opaque_region);

View File

@@ -58,8 +58,11 @@ struct _MetaWindowActor
GType meta_window_actor_get_type (void);
Window meta_window_actor_get_x_window (MetaWindowActor *self);
gint meta_window_actor_get_workspace (MetaWindowActor *self);
MetaWindow * meta_window_actor_get_meta_window (MetaWindowActor *self);
ClutterActor * meta_window_actor_get_texture (MetaWindowActor *self);
gboolean meta_window_actor_is_override_redirect (MetaWindowActor *self);
gboolean meta_window_actor_showing_on_its_workspace (MetaWindowActor *self);
gboolean meta_window_actor_is_destroyed (MetaWindowActor *self);
#endif /* META_WINDOW_ACTOR_H */

View File

@@ -62,6 +62,7 @@
* @META_PREF_EDGE_TILING: edge tiling
* @META_PREF_FORCE_FULLSCREEN: force fullscreen
* @META_PREF_WORKSPACES_ONLY_ON_PRIMARY: workspaces only on primary
* @META_PREF_NO_TAB_POPUP: no tab popup
* @META_PREF_DRAGGABLE_BORDER_WIDTH: draggable border width
* @META_PREF_AUTO_MAXIMIZE: auto-maximize
*/
@@ -99,6 +100,7 @@ typedef enum
META_PREF_EDGE_TILING,
META_PREF_FORCE_FULLSCREEN,
META_PREF_WORKSPACES_ONLY_ON_PRIMARY,
META_PREF_NO_TAB_POPUP,
META_PREF_DRAGGABLE_BORDER_WIDTH,
META_PREF_AUTO_MAXIMIZE
} MetaPreference;
@@ -161,6 +163,9 @@ void meta_prefs_set_force_fullscreen (gboolean whether);
gboolean meta_prefs_get_workspaces_only_on_primary (void);
gboolean meta_prefs_get_no_tab_popup (void);
void meta_prefs_set_no_tab_popup (gboolean whether);
int meta_prefs_get_draggable_border_width (void);
gboolean meta_prefs_get_ignore_request_hide_titlebar (void);
@@ -199,6 +204,8 @@ void meta_prefs_set_ignore_request_hide_titlebar (gboolean whether);
* @META_KEYBINDING_ACTION_CYCLE_WINDOWS_BACKWARD: FILLME
* @META_KEYBINDING_ACTION_CYCLE_PANELS: FILLME
* @META_KEYBINDING_ACTION_CYCLE_PANELS_BACKWARD: FILLME
* @META_KEYBINDING_ACTION_TAB_POPUP_SELECT: FILLME
* @META_KEYBINDING_ACTION_TAB_POPUP_CANCEL: FILLME
* @META_KEYBINDING_ACTION_SHOW_DESKTOP: FILLME
* @META_KEYBINDING_ACTION_PANEL_MAIN_MENU: FILLME
* @META_KEYBINDING_ACTION_PANEL_RUN_DIALOG: FILLME
@@ -294,6 +301,8 @@ typedef enum _MetaKeyBindingAction
META_KEYBINDING_ACTION_CYCLE_WINDOWS_BACKWARD,
META_KEYBINDING_ACTION_CYCLE_PANELS,
META_KEYBINDING_ACTION_CYCLE_PANELS_BACKWARD,
META_KEYBINDING_ACTION_TAB_POPUP_SELECT,
META_KEYBINDING_ACTION_TAB_POPUP_CANCEL,
META_KEYBINDING_ACTION_SHOW_DESKTOP,
META_KEYBINDING_ACTION_PANEL_MAIN_MENU,
META_KEYBINDING_ACTION_PANEL_RUN_DIALOG,
@@ -371,6 +380,20 @@ typedef enum
META_KEY_BINDING_IS_REVERSED = 1 << 3
} MetaKeyBindingFlags;
/**
* MetaKeyCombo:
* @keysym: keysym
* @keycode: keycode
* @modifiers: modifiers
*/
typedef struct _MetaKeyCombo MetaKeyCombo;
struct _MetaKeyCombo
{
unsigned int keysym;
unsigned int keycode;
MetaVirtualModifier modifiers;
};
/**
* MetaKeyHandlerFunc:
* @display: a #MetaDisplay
@@ -388,14 +411,45 @@ typedef void (* MetaKeyHandlerFunc) (MetaDisplay *display,
MetaKeyBinding *binding,
gpointer user_data);
typedef struct _MetaKeyHandler MetaKeyHandler;
typedef struct
{
char *name;
GSettings *settings;
MetaKeyBindingAction action;
/*
* A list of MetaKeyCombos. Each of them is bound to
* this keypref. If one has keysym==modifiers==0, it is
* ignored.
*/
GSList *bindings;
/* for keybindings that can have shift or not like Alt+Tab */
gboolean add_shift:1;
/* for keybindings that apply only to a window */
gboolean per_window:1;
/* for keybindings not added with meta_display_add_keybinding() */
gboolean builtin:1;
} MetaKeyPref;
GType meta_key_binding_get_type (void);
GList *meta_prefs_get_keybindings (void);
MetaKeyBindingAction meta_prefs_get_keybinding_action (const char *name);
void meta_prefs_get_window_binding (const char *name,
unsigned int *keysym,
MetaVirtualModifier *modifiers);
void meta_prefs_get_overlay_binding (MetaKeyCombo *combo);
const char *meta_prefs_get_iso_next_group_option (void);
gboolean meta_prefs_get_visual_bell (void);
gboolean meta_prefs_bell_is_audible (void);
GDesktopVisualBellType meta_prefs_get_visual_bell_type (void);

View File

@@ -189,6 +189,8 @@ gboolean meta_window_requested_bypass_compositor (MetaWindow *window);
gboolean meta_window_requested_dont_bypass_compositor (MetaWindow *window);
gint *meta_window_get_all_monitors (MetaWindow *window, gsize *length);
gboolean meta_window_is_mapped (MetaWindow *window);
gboolean meta_window_toplevel_is_mapped (MetaWindow *window);
gboolean meta_window_get_icon_geometry (MetaWindow *window,
MetaRectangle *rect);
void meta_window_set_icon_geometry (MetaWindow *window,

224
src/ui/draw-workspace.c Normal file
View File

@@ -0,0 +1,224 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Draw a workspace */
/* This file should not be modified to depend on other files in
* libwnck or mutter, since it's used in both of them
*/
/*
* Copyright (C) 2002 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "draw-workspace.h"
#include "theme-private.h"
static void
get_window_rect (const WnckWindowDisplayInfo *win,
int screen_width,
int screen_height,
const GdkRectangle *workspace_rect,
GdkRectangle *rect)
{
double width_ratio, height_ratio;
int x, y, width, height;
width_ratio = (double) workspace_rect->width / (double) screen_width;
height_ratio = (double) workspace_rect->height / (double) screen_height;
x = win->x;
y = win->y;
width = win->width;
height = win->height;
x *= width_ratio;
y *= height_ratio;
width *= width_ratio;
height *= height_ratio;
x += workspace_rect->x;
y += workspace_rect->y;
if (width < 3)
width = 3;
if (height < 3)
height = 3;
rect->x = x;
rect->y = y;
rect->width = width;
rect->height = height;
}
static void
draw_window (GtkWidget *widget,
cairo_t *cr,
const WnckWindowDisplayInfo *win,
const GdkRectangle *winrect,
GtkStateFlags state)
{
GdkPixbuf *icon;
int icon_x, icon_y, icon_w, icon_h;
gboolean is_active;
GdkRGBA color;
GtkStyleContext *style;
is_active = win->is_active;
cairo_save (cr);
cairo_rectangle (cr, winrect->x, winrect->y, winrect->width, winrect->height);
cairo_clip (cr);
style = gtk_widget_get_style_context (widget);
if (is_active)
meta_gtk_style_get_light_color (style, state, &color);
else
gtk_style_context_get_background_color (style, state, &color);
gdk_cairo_set_source_rgba (cr, &color);
cairo_rectangle (cr,
winrect->x + 1, winrect->y + 1,
MAX (0, winrect->width - 2), MAX (0, winrect->height - 2));
cairo_fill (cr);
icon = win->icon;
icon_w = icon_h = 0;
if (icon)
{
icon_w = gdk_pixbuf_get_width (icon);
icon_h = gdk_pixbuf_get_height (icon);
/* If the icon is too big, fall back to mini icon.
* We don't arbitrarily scale the icon, because it's
* just too slow on my Athlon 850.
*/
if (icon_w > (winrect->width - 2) ||
icon_h > (winrect->height - 2))
{
icon = win->mini_icon;
if (icon)
{
icon_w = gdk_pixbuf_get_width (icon);
icon_h = gdk_pixbuf_get_height (icon);
/* Give up. */
if (icon_w > (winrect->width - 2) ||
icon_h > (winrect->height - 2))
icon = NULL;
}
}
}
if (icon)
{
icon_x = winrect->x + (winrect->width - icon_w) / 2;
icon_y = winrect->y + (winrect->height - icon_h) / 2;
cairo_save (cr);
gdk_cairo_set_source_pixbuf (cr, icon, icon_x, icon_y);
cairo_rectangle (cr, icon_x, icon_y, icon_w, icon_h);
cairo_clip (cr);
cairo_paint (cr);
cairo_restore (cr);
}
gtk_style_context_get_color (style, state, &color);
gdk_cairo_set_source_rgba (cr, &color);
cairo_set_line_width (cr, 1.0);
cairo_rectangle (cr,
winrect->x + 0.5, winrect->y + 0.5,
MAX (0, winrect->width - 1), MAX (0, winrect->height - 1));
cairo_stroke (cr);
cairo_restore (cr);
}
void
wnck_draw_workspace (GtkWidget *widget,
cairo_t *cr,
int x,
int y,
int width,
int height,
int screen_width,
int screen_height,
GdkPixbuf *workspace_background,
gboolean is_active,
const WnckWindowDisplayInfo *windows,
int n_windows)
{
int i;
GdkRectangle workspace_rect;
GtkStateFlags state;
GtkStyleContext *style;
workspace_rect.x = x;
workspace_rect.y = y;
workspace_rect.width = width;
workspace_rect.height = height;
if (is_active)
state = GTK_STATE_FLAG_SELECTED;
else if (workspace_background)
state = GTK_STATE_FLAG_PRELIGHT;
else
state = GTK_STATE_FLAG_NORMAL;
style = gtk_widget_get_style_context (widget);
cairo_save (cr);
if (workspace_background)
{
gdk_cairo_set_source_pixbuf (cr, workspace_background, x, y);
cairo_paint (cr);
}
else
{
GdkRGBA color;
meta_gtk_style_get_dark_color (style,state, &color);
gdk_cairo_set_source_rgba (cr, &color);
cairo_rectangle (cr, x, y, width, height);
cairo_fill (cr);
}
i = 0;
while (i < n_windows)
{
const WnckWindowDisplayInfo *win = &windows[i];
GdkRectangle winrect;
get_window_rect (win, screen_width,
screen_height, &workspace_rect, &winrect);
draw_window (widget,
cr,
win,
&winrect,
state);
++i;
}
cairo_restore (cr);
}

59
src/ui/draw-workspace.h Normal file
View File

@@ -0,0 +1,59 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Draw a workspace */
/* This file should not be modified to depend on other files in
* libwnck or metacity, since it's used in both of them
*/
/*
* Copyright (C) 2002 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WNCK_DRAW_WORKSPACE_H
#define WNCK_DRAW_WORKSPACE_H
#include <gdk/gdk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gtk/gtk.h>
typedef struct
{
GdkPixbuf *icon;
GdkPixbuf *mini_icon;
int x;
int y;
int width;
int height;
guint is_active : 1;
} WnckWindowDisplayInfo;
void wnck_draw_workspace (GtkWidget *widget,
cairo_t *cr,
int x,
int y,
int width,
int height,
int screen_width,
int screen_height,
GdkPixbuf *workspace_background,
gboolean is_active,
const WnckWindowDisplayInfo *windows,
int n_windows);
#endif

963
src/ui/tabpopup.c Normal file
View File

@@ -0,0 +1,963 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter popup window thing showing windows you can tab to */
/*
* Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2002 Red Hat, Inc.
* Copyright (C) 2005 Elijah Newren
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <meta/util.h>
#include "core.h"
#include "tabpopup.h"
/* FIXME these two includes are 100% broken ...
*/
#include "workspace-private.h"
#include "frame.h"
#include "draw-workspace.h"
#include <gtk/gtk.h>
#include <math.h>
#define OUTSIDE_SELECT_RECT 2
#define INSIDE_SELECT_RECT 2
typedef struct _TabEntry TabEntry;
struct _TabEntry
{
MetaTabEntryKey key;
char *title;
GdkPixbuf *icon, *dimmed_icon;
GtkWidget *widget;
GdkRectangle rect;
GdkRectangle inner_rect;
guint blank : 1;
};
struct _MetaTabPopup
{
GtkWidget *window;
GtkWidget *label;
GList *current;
GList *entries;
TabEntry *current_selected_entry;
GtkWidget *outline_window;
gboolean outline;
};
static GtkWidget* selectable_image_new (GdkPixbuf *pixbuf);
static void select_image (GtkWidget *widget);
static void unselect_image (GtkWidget *widget);
static GtkWidget* selectable_workspace_new (MetaWorkspace *workspace);
static void select_workspace (GtkWidget *widget);
static void unselect_workspace (GtkWidget *widget);
static gboolean
outline_window_draw (GtkWidget *widget,
cairo_t *cr,
gpointer data)
{
MetaTabPopup *popup;
TabEntry *te;
popup = data;
if (!popup->outline || popup->current_selected_entry == NULL)
return FALSE;
te = popup->current_selected_entry;
cairo_set_line_width (cr, 1.0);
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
cairo_rectangle (cr,
0.5, 0.5,
te->rect.width - 1,
te->rect.height - 1);
cairo_stroke (cr);
cairo_rectangle (cr,
te->inner_rect.x - 0.5, te->inner_rect.y - 0.5,
te->inner_rect.width + 1,
te->inner_rect.height + 1);
cairo_stroke (cr);
return FALSE;
}
static GdkPixbuf*
dimm_icon (GdkPixbuf *pixbuf)
{
int x, y, pixel_stride, row_stride;
guchar *row, *pixels;
int w, h;
GdkPixbuf *dimmed_pixbuf;
if (gdk_pixbuf_get_has_alpha (pixbuf))
{
dimmed_pixbuf = gdk_pixbuf_copy (pixbuf);
}
else
{
dimmed_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
}
w = gdk_pixbuf_get_width (dimmed_pixbuf);
h = gdk_pixbuf_get_height (dimmed_pixbuf);
pixel_stride = 4;
row = gdk_pixbuf_get_pixels (dimmed_pixbuf);
row_stride = gdk_pixbuf_get_rowstride (dimmed_pixbuf);
for (y = 0; y < h; y++)
{
pixels = row;
for (x = 0; x < w; x++)
{
pixels[3] /= 2;
pixels += pixel_stride;
}
row += row_stride;
}
return dimmed_pixbuf;
}
static TabEntry*
tab_entry_new (const MetaTabEntry *entry,
gint screen_width,
gboolean outline)
{
TabEntry *te;
te = g_new (TabEntry, 1);
te->key = entry->key;
te->title = NULL;
if (entry->title)
{
gchar *str;
gchar *tmp;
gchar *formatter = "%s";
str = meta_g_utf8_strndup (entry->title, 4096);
if (entry->hidden)
{
formatter = "[%s]";
}
tmp = g_markup_printf_escaped (formatter, str);
g_free (str);
str = tmp;
if (entry->demands_attention)
{
/* Escape the whole line of text then markup the text and
* copy it back into the original buffer.
*/
tmp = g_strdup_printf ("<b>%s</b>", str);
g_free (str);
str = tmp;
}
te->title=g_strdup(str);
g_free (str);
}
te->widget = NULL;
te->icon = entry->icon;
te->blank = entry->blank;
te->dimmed_icon = NULL;
if (te->icon)
{
g_object_ref (G_OBJECT (te->icon));
if (entry->hidden)
te->dimmed_icon = dimm_icon (entry->icon);
}
if (outline)
{
te->rect.x = entry->rect.x;
te->rect.y = entry->rect.y;
te->rect.width = entry->rect.width;
te->rect.height = entry->rect.height;
te->inner_rect.x = entry->inner_rect.x;
te->inner_rect.y = entry->inner_rect.y;
te->inner_rect.width = entry->inner_rect.width;
te->inner_rect.height = entry->inner_rect.height;
}
return te;
}
MetaTabPopup*
meta_ui_tab_popup_new (const MetaTabEntry *entries,
int screen_number,
int entry_count,
int width,
gboolean outline)
{
MetaTabPopup *popup;
int i, left, top;
int height;
GtkWidget *grid;
GtkWidget *vbox;
GtkWidget *align;
GList *tmp;
GtkWidget *frame;
int max_label_width; /* the actual max width of the labels we create */
AtkObject *obj;
GdkScreen *screen;
int screen_width;
popup = g_new (MetaTabPopup, 1);
popup->outline_window = gtk_window_new (GTK_WINDOW_POPUP);
screen = gdk_display_get_screen (gdk_display_get_default (),
screen_number);
gtk_window_set_screen (GTK_WINDOW (popup->outline_window),
screen);
gtk_widget_set_app_paintable (popup->outline_window, TRUE);
gtk_widget_realize (popup->outline_window);
g_signal_connect (G_OBJECT (popup->outline_window), "draw",
G_CALLBACK (outline_window_draw), popup);
popup->window = gtk_window_new (GTK_WINDOW_POPUP);
gtk_window_set_screen (GTK_WINDOW (popup->window),
screen);
gtk_window_set_position (GTK_WINDOW (popup->window),
GTK_WIN_POS_CENTER_ALWAYS);
/* enable resizing, to get never-shrink behavior */
gtk_window_set_resizable (GTK_WINDOW (popup->window),
TRUE);
popup->current = NULL;
popup->entries = NULL;
popup->current_selected_entry = NULL;
popup->outline = outline;
screen_width = gdk_screen_get_width (screen);
for (i = 0; i < entry_count; ++i)
{
TabEntry* new_entry = tab_entry_new (&entries[i], screen_width, outline);
popup->entries = g_list_prepend (popup->entries, new_entry);
}
popup->entries = g_list_reverse (popup->entries);
g_assert (width > 0);
height = i / width;
if (i % width)
height += 1;
grid = gtk_grid_new ();
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
gtk_container_set_border_width (GTK_CONTAINER (grid), 1);
gtk_container_add (GTK_CONTAINER (popup->window),
frame);
gtk_container_add (GTK_CONTAINER (frame),
vbox);
align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
gtk_box_pack_start (GTK_BOX (vbox), align, TRUE, TRUE, 0);
gtk_container_add (GTK_CONTAINER (align),
grid);
popup->label = gtk_label_new ("");
/* Set the accessible role of the label to a status bar so it
* will emit name changed events that can be used by screen
* readers.
*/
obj = gtk_widget_get_accessible (popup->label);
atk_object_set_role (obj, ATK_ROLE_STATUSBAR);
gtk_misc_set_padding (GTK_MISC (popup->label), 3, 3);
gtk_box_pack_end (GTK_BOX (vbox), popup->label, FALSE, FALSE, 0);
max_label_width = 0;
top = 0;
tmp = popup->entries;
while (tmp && top < height)
{
left = 0;
while (tmp && left < width)
{
GtkWidget *image;
GtkRequisition req;
TabEntry *te;
te = tmp->data;
if (te->blank)
{
/* just stick a widget here to avoid special cases */
image = gtk_alignment_new (0.0, 0.0, 0.0, 0.0);
}
else if (outline)
{
if (te->dimmed_icon)
{
image = selectable_image_new (te->dimmed_icon);
}
else
{
image = selectable_image_new (te->icon);
}
gtk_misc_set_padding (GTK_MISC (image),
INSIDE_SELECT_RECT + OUTSIDE_SELECT_RECT + 1,
INSIDE_SELECT_RECT + OUTSIDE_SELECT_RECT + 1);
gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.5);
}
else
{
image = selectable_workspace_new ((MetaWorkspace *) te->key);
}
te->widget = image;
gtk_grid_attach (GTK_GRID (grid),
te->widget,
left, top, 1, 1);
/* Efficiency rules! */
gtk_label_set_markup (GTK_LABEL (popup->label),
te->title);
gtk_widget_get_preferred_size (popup->label, &req, NULL);
max_label_width = MAX (max_label_width, req.width);
tmp = tmp->next;
++left;
}
++top;
}
/* remove all the temporary text */
gtk_label_set_text (GTK_LABEL (popup->label), "");
/* Make it so that we ellipsize if the text is too long */
gtk_label_set_ellipsize (GTK_LABEL (popup->label), PANGO_ELLIPSIZE_END);
/* Limit the window size to no bigger than screen_width/4 */
if (max_label_width>(screen_width/4))
{
max_label_width = screen_width/4;
}
max_label_width += 20; /* add random padding */
gtk_window_set_default_size (GTK_WINDOW (popup->window),
max_label_width,
-1);
return popup;
}
static void
free_tab_entry (gpointer data, gpointer user_data)
{
TabEntry *te;
te = data;
g_free (te->title);
if (te->icon)
g_object_unref (G_OBJECT (te->icon));
if (te->dimmed_icon)
g_object_unref (G_OBJECT (te->dimmed_icon));
g_free (te);
}
void
meta_ui_tab_popup_free (MetaTabPopup *popup)
{
meta_verbose ("Destroying tab popup window\n");
if (!popup)
{
meta_warning ("NULL passed to meta_ui_tab_popup_free\n");
return;
}
gtk_widget_destroy (popup->outline_window);
gtk_widget_destroy (popup->window);
g_list_foreach (popup->entries, free_tab_entry, NULL);
g_list_free (popup->entries);
g_free (popup);
}
void
meta_ui_tab_popup_set_showing (MetaTabPopup *popup,
gboolean showing)
{
if (showing)
{
gtk_widget_show_all (popup->window);
}
else
{
if (gtk_widget_get_visible (popup->window))
{
meta_verbose ("Hiding tab popup window\n");
gtk_widget_hide (popup->window);
meta_core_increment_event_serial (
GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
}
}
}
static void
display_entry (MetaTabPopup *popup,
TabEntry *te)
{
GdkRectangle rect;
GdkWindow *window;
if (popup->current_selected_entry)
{
if (popup->outline)
unselect_image (popup->current_selected_entry->widget);
else
unselect_workspace (popup->current_selected_entry->widget);
}
gtk_label_set_markup (GTK_LABEL (popup->label), te->title);
if (popup->outline)
select_image (te->widget);
else
select_workspace (te->widget);
if (popup->outline)
{
cairo_region_t *region;
cairo_region_t *inner_region;
GdkRGBA black = { 0.0, 0.0, 0.0, 1.0 };
window = gtk_widget_get_window (popup->outline_window);
/* Do stuff behind gtk's back */
gdk_window_hide (window);
meta_core_increment_event_serial (
GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
rect = te->rect;
rect.x = 0;
rect.y = 0;
gdk_window_move_resize (window,
te->rect.x, te->rect.y,
te->rect.width, te->rect.height);
gdk_window_set_background_rgba (window, &black);
region = cairo_region_create_rectangle (&rect);
inner_region = cairo_region_create_rectangle (&te->inner_rect);
cairo_region_subtract (region, inner_region);
cairo_region_destroy (inner_region);
gdk_window_shape_combine_region (window,
region,
0, 0);
cairo_region_destroy (region);
/* This should piss off gtk a bit, but we don't want to raise
* above the tab popup. So, instead of calling gtk_widget_show,
* we manually set the window as mapped and then manually map it
* with gdk functions.
*/
gtk_widget_set_mapped (popup->outline_window, TRUE);
gdk_window_show_unraised (window);
}
/* Must be before we handle an expose for the outline window */
popup->current_selected_entry = te;
}
void
meta_ui_tab_popup_forward (MetaTabPopup *popup)
{
if (popup->current != NULL)
popup->current = popup->current->next;
if (popup->current == NULL)
popup->current = popup->entries;
if (popup->current != NULL)
{
TabEntry *te;
te = popup->current->data;
display_entry (popup, te);
}
}
void
meta_ui_tab_popup_backward (MetaTabPopup *popup)
{
if (popup->current != NULL)
popup->current = popup->current->prev;
if (popup->current == NULL)
popup->current = g_list_last (popup->entries);
if (popup->current != NULL)
{
TabEntry *te;
te = popup->current->data;
display_entry (popup, te);
}
}
MetaTabEntryKey
meta_ui_tab_popup_get_selected (MetaTabPopup *popup)
{
if (popup->current)
{
TabEntry *te;
te = popup->current->data;
return te->key;
}
else
return (MetaTabEntryKey)None;
}
void
meta_ui_tab_popup_select (MetaTabPopup *popup,
MetaTabEntryKey key)
{
GList *tmp;
/* Note, "key" may not be in the list of entries; other code assumes
* it's OK to pass in a key that isn't.
*/
tmp = popup->entries;
while (tmp != NULL)
{
TabEntry *te;
te = tmp->data;
if (te->key == key)
{
popup->current = tmp;
display_entry (popup, te);
return;
}
tmp = tmp->next;
}
}
#define META_TYPE_SELECT_IMAGE (meta_select_image_get_type ())
#define META_SELECT_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SELECT_IMAGE, MetaSelectImage))
typedef struct _MetaSelectImage MetaSelectImage;
typedef struct _MetaSelectImageClass MetaSelectImageClass;
struct _MetaSelectImage
{
GtkImage parent_instance;
guint selected : 1;
};
struct _MetaSelectImageClass
{
GtkImageClass parent_class;
};
static GType meta_select_image_get_type (void) G_GNUC_CONST;
static GtkWidget*
selectable_image_new (GdkPixbuf *pixbuf)
{
GtkWidget *w;
w = g_object_new (meta_select_image_get_type (), NULL);
gtk_image_set_from_pixbuf (GTK_IMAGE (w), pixbuf);
return w;
}
static void
select_image (GtkWidget *widget)
{
META_SELECT_IMAGE (widget)->selected = TRUE;
gtk_widget_queue_draw (widget);
}
static void
unselect_image (GtkWidget *widget)
{
META_SELECT_IMAGE (widget)->selected = FALSE;
gtk_widget_queue_draw (widget);
}
static void meta_select_image_class_init (MetaSelectImageClass *klass);
static gboolean meta_select_image_draw (GtkWidget *widget,
cairo_t *cr);
static GtkImageClass *parent_class;
GType
meta_select_image_get_type (void)
{
static GType image_type = 0;
if (!image_type)
{
static const GTypeInfo image_info =
{
sizeof (MetaSelectImageClass),
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) meta_select_image_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (MetaSelectImage),
16, /* n_preallocs */
(GInstanceInitFunc) NULL,
};
image_type = g_type_register_static (GTK_TYPE_IMAGE, "MetaSelectImage", &image_info, 0);
}
return image_type;
}
static void
meta_select_image_class_init (MetaSelectImageClass *klass)
{
GtkWidgetClass *widget_class;
parent_class = g_type_class_peek (gtk_image_get_type ());
widget_class = GTK_WIDGET_CLASS (klass);
widget_class->draw = meta_select_image_draw;
}
static gboolean
meta_select_image_draw (GtkWidget *widget,
cairo_t *cr)
{
GtkAllocation allocation;
gtk_widget_get_allocation (widget, &allocation);
if (META_SELECT_IMAGE (widget)->selected)
{
GtkMisc *misc;
GtkRequisition requisition;
GtkStyleContext *context;
GdkRGBA color;
int x, y, w, h;
gint xpad, ypad;
gfloat xalign, yalign;
misc = GTK_MISC (widget);
gtk_widget_get_requisition (widget, &requisition);
gtk_misc_get_alignment (misc, &xalign, &yalign);
gtk_misc_get_padding (misc, &xpad, &ypad);
x = (allocation.width - (requisition.width - xpad * 2)) * xalign + 0.5;
y = (allocation.height - (requisition.height - ypad * 2)) * yalign + 0.5;
x -= INSIDE_SELECT_RECT + 1;
y -= INSIDE_SELECT_RECT + 1;
w = requisition.width - OUTSIDE_SELECT_RECT * 2 - 1;
h = requisition.height - OUTSIDE_SELECT_RECT * 2 - 1;
context = gtk_widget_get_style_context (widget);
gtk_style_context_set_state (context,
gtk_widget_get_state_flags (widget));
gtk_style_context_lookup_color (context, "color", &color);
cairo_set_line_width (cr, 2.0);
cairo_set_source_rgb (cr, color.red, color.green, color.blue);
cairo_rectangle (cr, x, y, w + 1, h + 1);
cairo_stroke (cr);
cairo_set_line_width (cr, 1.0);
}
return GTK_WIDGET_CLASS (parent_class)->draw (widget, cr);
}
#define META_TYPE_SELECT_WORKSPACE (meta_select_workspace_get_type ())
#define META_SELECT_WORKSPACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SELECT_WORKSPACE, MetaSelectWorkspace))
typedef struct _MetaSelectWorkspace MetaSelectWorkspace;
typedef struct _MetaSelectWorkspaceClass MetaSelectWorkspaceClass;
struct _MetaSelectWorkspace
{
GtkDrawingArea parent_instance;
MetaWorkspace *workspace;
guint selected : 1;
};
struct _MetaSelectWorkspaceClass
{
GtkDrawingAreaClass parent_class;
};
static GType meta_select_workspace_get_type (void) G_GNUC_CONST;
#define SELECT_OUTLINE_WIDTH 2
#define MINI_WORKSPACE_WIDTH 48
static GtkWidget*
selectable_workspace_new (MetaWorkspace *workspace)
{
GtkWidget *widget;
double screen_aspect;
widget = g_object_new (meta_select_workspace_get_type (), NULL);
screen_aspect = (double) workspace->screen->rect.height /
(double) workspace->screen->rect.width;
/* account for select rect */
gtk_widget_set_size_request (widget,
MINI_WORKSPACE_WIDTH + SELECT_OUTLINE_WIDTH * 2,
MINI_WORKSPACE_WIDTH * screen_aspect + SELECT_OUTLINE_WIDTH * 2);
META_SELECT_WORKSPACE (widget)->workspace = workspace;
return widget;
}
static void
select_workspace (GtkWidget *widget)
{
META_SELECT_WORKSPACE(widget)->selected = TRUE;
gtk_widget_queue_draw (widget);
}
static void
unselect_workspace (GtkWidget *widget)
{
META_SELECT_WORKSPACE (widget)->selected = FALSE;
gtk_widget_queue_draw (widget);
}
static void meta_select_workspace_class_init (MetaSelectWorkspaceClass *klass);
static gboolean meta_select_workspace_draw (GtkWidget *widget,
cairo_t *cr);
GType
meta_select_workspace_get_type (void)
{
static GType workspace_type = 0;
if (!workspace_type)
{
static const GTypeInfo workspace_info =
{
sizeof (MetaSelectWorkspaceClass),
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) meta_select_workspace_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (MetaSelectWorkspace),
16, /* n_preallocs */
(GInstanceInitFunc) NULL,
};
workspace_type = g_type_register_static (GTK_TYPE_DRAWING_AREA,
"MetaSelectWorkspace",
&workspace_info,
0);
}
return workspace_type;
}
static void
meta_select_workspace_class_init (MetaSelectWorkspaceClass *klass)
{
GtkWidgetClass *widget_class;
widget_class = GTK_WIDGET_CLASS (klass);
widget_class->draw = meta_select_workspace_draw;
}
/**
* meta_convert_meta_to_wnck:
* @window: the #MetaWindow
* @screen: the #MetaScreen the window is on
*
* Converts a #MetaWindow to a #WnckWindowDisplayInfo window
* that is used to build a thumbnail of a workspace.
**/
static WnckWindowDisplayInfo
meta_convert_meta_to_wnck (MetaWindow *window, MetaScreen *screen)
{
WnckWindowDisplayInfo wnck_window;
wnck_window.icon = window->icon;
wnck_window.mini_icon = window->mini_icon;
wnck_window.is_active = window->has_focus;
if (window->frame)
{
wnck_window.x = window->frame->rect.x;
wnck_window.y = window->frame->rect.y;
wnck_window.width = window->frame->rect.width;
wnck_window.height = window->frame->rect.height;
}
else
{
wnck_window.x = window->rect.x;
wnck_window.y = window->rect.y;
wnck_window.width = window->rect.width;
wnck_window.height = window->rect.height;
}
return wnck_window;
}
static gboolean
meta_select_workspace_draw (GtkWidget *widget,
cairo_t *cr)
{
MetaWorkspace *workspace;
WnckWindowDisplayInfo *windows;
GtkAllocation allocation;
int i, n_windows;
GList *tmp, *list;
workspace = META_SELECT_WORKSPACE (widget)->workspace;
list = meta_stack_list_windows (workspace->screen->stack, workspace);
n_windows = g_list_length (list);
windows = g_new (WnckWindowDisplayInfo, n_windows);
tmp = list;
i = 0;
while (tmp != NULL)
{
MetaWindow *window;
gboolean ignoreable_sticky;
window = tmp->data;
ignoreable_sticky = window->on_all_workspaces &&
workspace != workspace->screen->active_workspace;
if (window->skip_pager ||
!meta_window_showing_on_its_workspace (window) ||
window->unmaps_pending ||
ignoreable_sticky)
{
--n_windows;
}
else
{
windows[i] = meta_convert_meta_to_wnck (window, workspace->screen);
i++;
}
tmp = tmp->next;
}
g_list_free (list);
gtk_widget_get_allocation (widget, &allocation);
wnck_draw_workspace (widget,
cr,
SELECT_OUTLINE_WIDTH,
SELECT_OUTLINE_WIDTH,
allocation.width - SELECT_OUTLINE_WIDTH * 2,
allocation.height - SELECT_OUTLINE_WIDTH * 2,
workspace->screen->rect.width,
workspace->screen->rect.height,
NULL,
(workspace->screen->active_workspace == workspace),
windows,
n_windows);
g_free (windows);
if (META_SELECT_WORKSPACE (widget)->selected)
{
GtkStyleContext *context;
GdkRGBA color;
context = gtk_widget_get_style_context (widget);
gtk_style_context_set_state (context,
gtk_widget_get_state_flags (widget));
gtk_style_context_lookup_color (context, "color", &color);
cairo_set_line_width (cr, SELECT_OUTLINE_WIDTH);
cairo_set_source_rgb (cr, color.red, color.green, color.blue);
cairo_rectangle (cr,
SELECT_OUTLINE_WIDTH / 2.0, SELECT_OUTLINE_WIDTH / 2.0,
allocation.width - SELECT_OUTLINE_WIDTH,
allocation.height - SELECT_OUTLINE_WIDTH);
cairo_stroke (cr);
}
return TRUE;
}

65
src/ui/tabpopup.h Normal file
View File

@@ -0,0 +1,65 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter tab popup window */
/*
* Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2005 Elijah Newren
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef META_TABPOPUP_H
#define META_TABPOPUP_H
/* Don't include gtk.h or gdk.h here */
#include <meta/common.h>
#include <meta/boxes.h>
#include <X11/Xlib.h>
#include <glib.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
typedef struct _MetaTabEntry MetaTabEntry;
typedef struct _MetaTabPopup MetaTabPopup;
typedef void *MetaTabEntryKey;
struct _MetaTabEntry
{
MetaTabEntryKey key;
const char *title;
GdkPixbuf *icon;
MetaRectangle rect;
MetaRectangle inner_rect;
guint blank : 1;
guint hidden : 1;
guint demands_attention : 1;
};
MetaTabPopup* meta_ui_tab_popup_new (const MetaTabEntry *entries,
int screen_number,
int entry_count,
int width,
gboolean outline);
void meta_ui_tab_popup_free (MetaTabPopup *popup);
void meta_ui_tab_popup_set_showing (MetaTabPopup *popup,
gboolean showing);
void meta_ui_tab_popup_forward (MetaTabPopup *popup);
void meta_ui_tab_popup_backward (MetaTabPopup *popup);
MetaTabEntryKey meta_ui_tab_popup_get_selected (MetaTabPopup *popup);
void meta_ui_tab_popup_select (MetaTabPopup *popup,
MetaTabEntryKey key);
#endif

196
src/ui/tile-preview.c Normal file
View File

@@ -0,0 +1,196 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter tile-preview marks the area a window will *ehm* snap to */
/*
* Copyright (C) 2010 Florian Müllner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <gtk/gtk.h>
#include <cairo.h>
#include "tile-preview.h"
#include "core.h"
#define OUTLINE_WIDTH 5 /* frame width in non-composite case */
struct _MetaTilePreview {
GtkWidget *preview_window;
gulong create_serial;
GdkRGBA *preview_color;
MetaRectangle tile_rect;
};
static gboolean
meta_tile_preview_draw (GtkWidget *widget,
cairo_t *cr,
gpointer user_data)
{
MetaTilePreview *preview = user_data;
cairo_set_line_width (cr, 1.0);
/* Fill the preview area with a transparent color */
gdk_cairo_set_source_rgba (cr, preview->preview_color);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
/* Use the opaque color for the border */
cairo_set_source_rgb (cr,
preview->preview_color->red,
preview->preview_color->green,
preview->preview_color->blue);
cairo_rectangle (cr,
0.5, 0.5,
preview->tile_rect.width - 1,
preview->tile_rect.height - 1);
cairo_stroke (cr);
return FALSE;
}
MetaTilePreview *
meta_tile_preview_new (int screen_number)
{
MetaTilePreview *preview;
GdkScreen *screen;
GtkStyleContext *context;
GtkWidgetPath *path;
guchar selection_alpha = 0xFF;
screen = gdk_display_get_screen (gdk_display_get_default (), screen_number);
preview = g_new (MetaTilePreview, 1);
preview->preview_window = gtk_window_new (GTK_WINDOW_POPUP);
gtk_window_set_screen (GTK_WINDOW (preview->preview_window), screen);
gtk_widget_set_app_paintable (preview->preview_window, TRUE);
preview->preview_color = NULL;
preview->tile_rect.x = preview->tile_rect.y = 0;
preview->tile_rect.width = preview->tile_rect.height = 0;
gtk_widget_set_visual (preview->preview_window,
gdk_screen_get_rgba_visual (screen));
path = gtk_widget_path_new ();
gtk_widget_path_append_type (path, GTK_TYPE_ICON_VIEW);
context = gtk_style_context_new ();
gtk_style_context_set_path (context, path);
gtk_style_context_add_class (context,
GTK_STYLE_CLASS_RUBBERBAND);
gtk_widget_path_free (path);
gtk_style_context_get (context, GTK_STATE_FLAG_SELECTED,
"background-color", &preview->preview_color,
NULL);
/* The background-color for the .rubberband class should probably
* contain the correct alpha value - unfortunately, at least for now
* it doesn't. Hopefully the following workaround can be removed
* when GtkIconView gets ported to GtkStyleContext.
*/
gtk_style_context_get_style (context,
"selection-box-alpha", &selection_alpha,
NULL);
preview->preview_color->alpha = (double)selection_alpha / 0xFF;
g_object_unref (context);
/* We make an assumption that XCreateWindow will be the first operation
* when calling gtk_widget_realize() (via gdk_window_new()), or that it
* is at least "close enough".
*/
preview->create_serial = XNextRequest (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
gtk_widget_realize (preview->preview_window);
g_signal_connect (preview->preview_window, "draw",
G_CALLBACK (meta_tile_preview_draw), preview);
return preview;
}
void
meta_tile_preview_free (MetaTilePreview *preview)
{
gtk_widget_destroy (preview->preview_window);
if (preview->preview_color)
gdk_rgba_free (preview->preview_color);
g_free (preview);
}
void
meta_tile_preview_show (MetaTilePreview *preview,
MetaRectangle *tile_rect)
{
GdkWindow *window;
GdkRectangle old_rect;
if (gtk_widget_get_visible (preview->preview_window)
&& preview->tile_rect.x == tile_rect->x
&& preview->tile_rect.y == tile_rect->y
&& preview->tile_rect.width == tile_rect->width
&& preview->tile_rect.height == tile_rect->height)
return; /* nothing to do */
gtk_widget_show (preview->preview_window);
window = gtk_widget_get_window (preview->preview_window);
meta_core_lower_beneath_grab_window (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
GDK_WINDOW_XID (window),
gtk_get_current_event_time ());
old_rect.x = old_rect.y = 0;
old_rect.width = preview->tile_rect.width;
old_rect.height = preview->tile_rect.height;
gdk_window_invalidate_rect (window, &old_rect, FALSE);
preview->tile_rect = *tile_rect;
gdk_window_move_resize (window,
preview->tile_rect.x, preview->tile_rect.y,
preview->tile_rect.width, preview->tile_rect.height);
}
void
meta_tile_preview_hide (MetaTilePreview *preview)
{
gtk_widget_hide (preview->preview_window);
}
Window
meta_tile_preview_get_xwindow (MetaTilePreview *preview,
gulong *create_serial)
{
GdkWindow *window = gtk_widget_get_window (preview->preview_window);
if (create_serial)
*create_serial = preview->create_serial;
return GDK_WINDOW_XID (window);
}

36
src/ui/tile-preview.h Normal file
View File

@@ -0,0 +1,36 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Meta tile preview */
/*
* Copyright (C) 2010 Florian Müllner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef META_TILE_PREVIEW_H
#define META_TILE_PREVIEW_H
#include <meta/boxes.h>
typedef struct _MetaTilePreview MetaTilePreview;
MetaTilePreview *meta_tile_preview_new (int screen_number);
void meta_tile_preview_free (MetaTilePreview *preview);
void meta_tile_preview_show (MetaTilePreview *preview,
MetaRectangle *rect);
void meta_tile_preview_hide (MetaTilePreview *preview);
Window meta_tile_preview_get_xwindow (MetaTilePreview *preview,
gulong *create_serial);
#endif /* META_TILE_PREVIEW_H */

View File

@@ -178,4 +178,7 @@ int meta_ui_get_drag_threshold (MetaUI *ui);
MetaUIDirection meta_ui_get_direction (void);
#include "tabpopup.h"
#include "tile-preview.h"
#endif

View File

@@ -60,6 +60,14 @@
#include "meta-wayland-private.h"
static MetaWaylandSeat *
meta_wayland_keyboard_get_seat (MetaWaylandKeyboard *keyboard)
{
MetaWaylandSeat *seat = wl_container_of (keyboard, seat, keyboard);
return seat;
}
static int
create_anonymous_file (off_t size,
GError **error)
@@ -107,7 +115,7 @@ inform_clients_of_new_keymap (MetaWaylandKeyboard *keyboard,
struct wl_resource *keyboard_resource;
compositor = meta_wayland_compositor_get_default ();
xclient = compositor->xwayland_manager.client;
xclient = compositor->xwayland_client;
wl_resource_for_each (keyboard_resource, &keyboard->resource_list)
{
@@ -193,17 +201,13 @@ meta_wayland_keyboard_take_keymap (MetaWaylandKeyboard *keyboard,
strcpy (xkb_info->keymap_area, keymap_str);
free (keymap_str);
#if defined(CLUTTER_WINDOWING_EGL)
/* XXX -- the evdev backend can be used regardless of the
* windowing backend. To do this properly we need a Clutter
* API to check the input backend. */
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
if (keyboard->is_evdev)
{
ClutterDeviceManager *manager;
manager = clutter_device_manager_get_default ();
clutter_evdev_set_keyboard_map (manager, xkb_info->keymap);
}
#endif
inform_clients_of_new_keymap (keyboard, flags);
@@ -218,25 +222,13 @@ err_keymap_str:
}
static void
keyboard_handle_focus_surface_destroy (struct wl_listener *listener, void *data)
lose_keyboard_focus (struct wl_listener *listener, void *data)
{
MetaWaylandKeyboard *keyboard = wl_container_of (listener, keyboard, focus_surface_listener);
keyboard->focus_surface = NULL;
if (keyboard->focus_resource)
{
wl_list_remove (&keyboard->focus_resource_listener.link);
keyboard->focus_resource = NULL;
}
}
static void
keyboard_handle_focus_resource_destroy (struct wl_listener *listener, void *data)
{
MetaWaylandKeyboard *keyboard = wl_container_of (listener, keyboard, focus_resource_listener);
MetaWaylandKeyboard *keyboard =
wl_container_of (listener, keyboard, focus_listener);
keyboard->focus_resource = NULL;
keyboard->focus = NULL;
}
static gboolean
@@ -281,11 +273,29 @@ default_grab_modifiers (MetaWaylandKeyboardGrab *grab, uint32_t serial,
uint32_t mods_locked, uint32_t group)
{
MetaWaylandKeyboard *keyboard = grab->keyboard;
MetaWaylandSeat *seat = meta_wayland_keyboard_get_seat (keyboard);
MetaWaylandPointer *pointer = &seat->pointer;
struct wl_resource *resource, *pr;
if (keyboard->focus_resource)
resource = keyboard->focus_resource;
if (!resource)
return;
wl_keyboard_send_modifiers (resource, serial, mods_depressed,
mods_latched, mods_locked, group);
if (pointer && pointer->focus && pointer->focus != keyboard->focus)
{
wl_keyboard_send_modifiers (keyboard->focus_resource, serial, mods_depressed,
mods_latched, mods_locked, group);
pr = find_resource_for_surface (&keyboard->resource_list,
pointer->focus);
if (pr)
{
wl_keyboard_send_modifiers (pr, serial,
mods_depressed,
mods_latched,
mods_locked,
group);
}
}
}
@@ -322,17 +332,15 @@ static MetaWaylandKeyboardGrabInterface modal_grab = {
gboolean
meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
struct wl_display *display)
struct wl_display *display,
gboolean is_evdev)
{
memset (keyboard, 0, sizeof *keyboard);
keyboard->xkb_info.keymap_fd = -1;
wl_list_init (&keyboard->resource_list);
wl_array_init (&keyboard->keys);
keyboard->focus_surface_listener.notify = keyboard_handle_focus_surface_destroy;
keyboard->focus_resource_listener.notify = keyboard_handle_focus_resource_destroy;
keyboard->focus_listener.notify = lose_keyboard_focus;
keyboard->default_grab.interface = &default_keyboard_grab_interface;
keyboard->default_grab.keyboard = keyboard;
keyboard->grab = &keyboard->default_grab;
@@ -340,6 +348,7 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
keyboard->display = display;
keyboard->xkb_context = xkb_context_new (0 /* flags */);
keyboard->is_evdev = is_evdev;
/* Compute a default until gnome-settings-daemon starts and sets
the appropriate values
@@ -500,66 +509,62 @@ void
meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
MetaWaylandSurface *surface)
{
if (keyboard->focus_surface == surface && keyboard->focus_resource != NULL)
struct wl_resource *resource;
uint32_t serial;
if (keyboard->focus == surface && keyboard->focus_resource != NULL)
return;
if (keyboard->focus_surface != NULL)
resource = keyboard->focus_resource;
if (keyboard->focus_resource && keyboard->focus->resource)
{
if (keyboard->focus_resource)
{
if (keyboard->focus_surface->resource)
{
struct wl_client *client = wl_resource_get_client (keyboard->focus_resource);
struct wl_display *display = wl_client_get_display (client);
uint32_t serial = wl_display_next_serial (display);
wl_keyboard_send_leave (keyboard->focus_resource, serial, keyboard->focus_surface->resource);
}
struct wl_client *client = wl_resource_get_client (resource);
struct wl_display *display = wl_client_get_display (client);
serial = wl_display_next_serial (display);
wl_keyboard_send_leave (resource, serial, keyboard->focus->resource);
wl_list_remove (&keyboard->focus_listener.link);
wl_list_remove (&keyboard->focus_resource_listener.link);
keyboard->focus_resource = NULL;
}
wl_list_remove (&keyboard->focus_surface_listener.link);
keyboard->focus_surface = NULL;
meta_wayland_surface_focused_unset (keyboard->focus);
}
if (surface != NULL)
resource = find_resource_for_surface (&keyboard->resource_list, surface);
if (resource)
{
keyboard->focus_surface = surface;
wl_resource_add_destroy_listener (keyboard->focus_surface->resource, &keyboard->focus_surface_listener);
struct wl_client *client = wl_resource_get_client (resource);
struct wl_display *display = wl_client_get_display (client);
keyboard->focus_resource = find_resource_for_surface (&keyboard->resource_list, surface);
if (keyboard->focus_resource)
{
struct wl_client *client = wl_resource_get_client (keyboard->focus_resource);
struct wl_display *display = wl_client_get_display (client);
uint32_t serial = wl_display_next_serial (display);
serial = wl_display_next_serial (display);
/* If we're in a modal grab, the client is focused but doesn't see
modifiers or pressed keys (and fix that up when we exit the modal) */
if (keyboard->grab->interface == &modal_grab)
{
struct wl_array empty;
wl_array_init (&empty);
/* If we're in a modal grab, the client is focused but doesn't see
modifiers or pressed keys (and fix that up when we exit the modal) */
if (keyboard->grab->interface == &modal_grab)
{
struct wl_array empty;
wl_array_init (&empty);
wl_keyboard_send_modifiers (keyboard->focus_resource, serial, 0, 0, 0, 0);
wl_keyboard_send_enter (keyboard->focus_resource, serial, keyboard->focus_surface->resource, &empty);
}
else
{
wl_keyboard_send_modifiers (keyboard->focus_resource, serial,
keyboard->modifier_state.mods_depressed,
keyboard->modifier_state.mods_latched,
keyboard->modifier_state.mods_locked,
keyboard->modifier_state.group);
wl_keyboard_send_enter (keyboard->focus_resource, serial, keyboard->focus_surface->resource,
&keyboard->keys);
}
wl_keyboard_send_modifiers (resource, serial,
0, 0, 0, 0);
wl_keyboard_send_enter (resource, serial, surface->resource,
&empty);
}
else
{
wl_keyboard_send_modifiers (resource, serial,
keyboard->modifier_state.mods_depressed,
keyboard->modifier_state.mods_latched,
keyboard->modifier_state.mods_locked,
keyboard->modifier_state.group);
wl_keyboard_send_enter (resource, serial, surface->resource,
&keyboard->keys);
}
wl_resource_add_destroy_listener (resource, &keyboard->focus_listener);
keyboard->focus_serial = serial;
wl_resource_add_destroy_listener (keyboard->focus_resource, &keyboard->focus_resource_listener);
keyboard->focus_serial = serial;
}
meta_wayland_surface_focused_set (surface);
}
keyboard->focus_resource = resource;
keyboard->focus = surface;
}
void
@@ -585,6 +590,8 @@ meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard)
xkb_context_unref (keyboard->xkb_context);
/* XXX: What about keyboard->resource_list? */
if (keyboard->focus_resource)
wl_list_remove (&keyboard->focus_listener.link);
wl_array_release (&keyboard->keys);
}
@@ -603,7 +610,7 @@ meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard,
if (keyboard->grab != &keyboard->default_grab)
return FALSE;
if (keyboard->focus_surface)
if (keyboard->focus)
{
/* Fake key release events for the focused app */
serial = wl_display_next_serial (keyboard->display);
@@ -645,7 +652,7 @@ meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard,
meta_wayland_keyboard_end_grab (keyboard);
g_slice_free (MetaWaylandKeyboardGrab, grab);
if (keyboard->focus_surface)
if (keyboard->focus)
{
/* Fake key press events for the focused app */
serial = wl_display_next_serial (keyboard->display);

View File

@@ -47,7 +47,6 @@
#include <clutter/clutter.h>
#include <wayland-server.h>
#include <xkbcommon/xkbcommon.h>
struct _MetaWaylandKeyboardGrabInterface
{
@@ -93,11 +92,9 @@ typedef struct
struct _MetaWaylandKeyboard
{
struct wl_list resource_list;
MetaWaylandSurface *focus_surface;
struct wl_listener focus_surface_listener;
MetaWaylandSurface *focus;
struct wl_resource *focus_resource;
struct wl_listener focus_resource_listener;
struct wl_listener focus_listener;
uint32_t focus_serial;
MetaWaylandKeyboardGrab *grab;
@@ -113,6 +110,7 @@ struct _MetaWaylandKeyboard
struct wl_display *display;
struct xkb_context *xkb_context;
gboolean is_evdev;
MetaWaylandXkbInfo xkb_info;
MetaWaylandKeyboardGrab input_method_grab;
@@ -121,7 +119,8 @@ struct _MetaWaylandKeyboard
gboolean
meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
struct wl_display *display);
struct wl_display *display,
gboolean is_evdev);
typedef enum {
META_WAYLAND_KEYBOARD_SKIP_XCLIENTS = 1,

View File

@@ -49,31 +49,28 @@
#include "meta-wayland-pointer.h"
#include "meta-wayland-private.h"
#include "xdg-shell-server-protocol.h"
#include <string.h>
static void meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer);
static void
pointer_handle_focus_surface_destroy (struct wl_listener *listener, void *data)
static MetaWaylandSeat *
meta_wayland_pointer_get_seat (MetaWaylandPointer *pointer)
{
MetaWaylandPointer *pointer = wl_container_of (listener, pointer, focus_surface_listener);
MetaWaylandSeat *seat = wl_container_of (pointer, seat, pointer);
pointer->focus_surface = NULL;
if (pointer->focus_resource)
{
wl_list_remove (&pointer->focus_resource_listener.link);
pointer->focus_resource = NULL;
}
return seat;
}
static void
pointer_handle_focus_resource_destroy (struct wl_listener *listener, void *data)
lose_pointer_focus (struct wl_listener *listener, void *data)
{
MetaWaylandPointer *pointer = wl_container_of (listener, pointer, focus_resource_listener);
MetaWaylandPointer *pointer =
wl_container_of (listener, pointer, focus_listener);
pointer->focus_resource = NULL;
pointer->focus = NULL;
}
static void
@@ -101,7 +98,7 @@ default_grab_motion (MetaWaylandPointerGrab *grab,
wl_fixed_t sx, sy;
meta_wayland_pointer_get_relative_coordinates (grab->pointer,
grab->pointer->focus_surface,
grab->pointer->focus,
&sx, &sy);
wl_pointer_send_motion (resource, clutter_event_get_time (event), sx, sy);
}
@@ -261,7 +258,8 @@ pointer_constrain_callback (ClutterInputDevice *device,
}
void
meta_wayland_pointer_init (MetaWaylandPointer *pointer)
meta_wayland_pointer_init (MetaWaylandPointer *pointer,
gboolean is_native)
{
ClutterDeviceManager *manager;
ClutterInputDevice *device;
@@ -269,10 +267,7 @@ meta_wayland_pointer_init (MetaWaylandPointer *pointer)
memset (pointer, 0, sizeof *pointer);
wl_list_init (&pointer->resource_list);
pointer->focus_surface_listener.notify = pointer_handle_focus_surface_destroy;
pointer->focus_resource_listener.notify = pointer_handle_focus_resource_destroy;
pointer->focus_listener.notify = lose_pointer_focus;
pointer->default_grab.interface = &default_pointer_grab_interface;
pointer->default_grab.pointer = pointer;
pointer->grab = &pointer->default_grab;
@@ -280,16 +275,9 @@ meta_wayland_pointer_init (MetaWaylandPointer *pointer)
manager = clutter_device_manager_get_default ();
device = clutter_device_manager_get_core_device (manager, CLUTTER_POINTER_DEVICE);
#if defined(CLUTTER_WINDOWING_EGL)
/* XXX -- the evdev backend can be used regardless of the
* windowing backend. To do this properly we need a Clutter
* API to check the input backend. */
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
{
clutter_evdev_set_pointer_constrain_callback (manager, pointer_constrain_callback,
pointer, NULL);
}
#endif
if (is_native)
clutter_evdev_set_pointer_constrain_callback (manager, pointer_constrain_callback,
pointer, NULL);
clutter_input_device_get_coords (device, NULL, &current);
pointer->x = wl_fixed_from_double (current.x);
@@ -299,7 +287,12 @@ meta_wayland_pointer_init (MetaWaylandPointer *pointer)
void
meta_wayland_pointer_release (MetaWaylandPointer *pointer)
{
/* Do nothing. */
/* XXX: What about pointer->resource_list? */
if (pointer->focus_resource)
wl_list_remove (&pointer->focus_listener.link);
pointer->focus = NULL;
pointer->focus_resource = NULL;
}
static struct wl_resource *
@@ -320,58 +313,60 @@ void
meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface)
{
if (pointer->focus_surface == surface && pointer->focus_resource != NULL)
MetaWaylandSeat *seat = meta_wayland_pointer_get_seat (pointer);
MetaWaylandKeyboard *kbd = &seat->keyboard;
struct wl_resource *resource, *kr;
uint32_t serial;
if (pointer->focus == surface && pointer->focus_resource != NULL)
return;
if (pointer->focus_surface)
resource = pointer->focus_resource;
if (resource && pointer->focus->resource)
{
if (pointer->focus_resource)
struct wl_client *client = wl_resource_get_client (resource);
struct wl_display *display = wl_client_get_display (client);
serial = wl_display_next_serial (display);
wl_pointer_send_leave (resource, serial, pointer->focus->resource);
wl_list_remove (&pointer->focus_listener.link);
}
resource = find_resource_for_surface (&pointer->resource_list, surface);
if (resource)
{
struct wl_client *client = wl_resource_get_client (resource);
struct wl_display *display = wl_client_get_display (client);
wl_fixed_t sx, sy;
serial = wl_display_next_serial (display);
if (kbd)
{
if (pointer->focus_surface->resource)
kr = find_resource_for_surface (&kbd->resource_list, surface);
if (kr)
{
struct wl_client *client = wl_resource_get_client (pointer->focus_resource);
struct wl_display *display = wl_client_get_display (client);
uint32_t serial = wl_display_next_serial (display);
wl_pointer_send_leave (pointer->focus_resource, serial, pointer->focus_surface->resource);
wl_keyboard_send_modifiers (kr,
serial,
kbd->modifier_state.mods_depressed,
kbd->modifier_state.mods_latched,
kbd->modifier_state.mods_locked,
kbd->modifier_state.group);
}
wl_list_remove (&pointer->focus_resource_listener.link);
pointer->focus_resource = NULL;
}
wl_list_remove (&pointer->focus_surface_listener.link);
pointer->focus_surface = NULL;
meta_wayland_pointer_get_relative_coordinates (pointer, surface, &sx, &sy);
meta_window_handle_enter (surface->window,
/* XXX -- can we reliably get a timestamp for setting focus? */
clutter_get_current_event_time (),
wl_fixed_to_int (pointer->x),
wl_fixed_to_int (pointer->y));
wl_pointer_send_enter (resource, serial, surface->resource, sx, sy);
wl_resource_add_destroy_listener (resource, &pointer->focus_listener);
pointer->focus_serial = serial;
}
if (surface != NULL)
{
pointer->focus_surface = surface;
wl_resource_add_destroy_listener (pointer->focus_surface->resource, &pointer->focus_surface_listener);
pointer->focus_resource = find_resource_for_surface (&pointer->resource_list, surface);
if (pointer->focus_resource)
{
struct wl_client *client = wl_resource_get_client (pointer->focus_resource);
struct wl_display *display = wl_client_get_display (client);
uint32_t serial = wl_display_next_serial (display);
meta_window_handle_enter (pointer->focus_surface->window,
/* XXX -- can we reliably get a timestamp for setting focus? */
clutter_get_current_event_time (),
wl_fixed_to_int (pointer->x),
wl_fixed_to_int (pointer->y));
{
wl_fixed_t sx, sy;
meta_wayland_pointer_get_relative_coordinates (pointer, pointer->focus_surface, &sx, &sy);
wl_pointer_send_enter (pointer->focus_resource, serial, pointer->focus_surface->resource, sx, sy);
}
wl_resource_add_destroy_listener (pointer->focus_resource, &pointer->focus_resource_listener);
pointer->focus_serial = serial;
}
}
pointer->focus_resource = resource;
pointer->focus = surface;
}
void
@@ -527,7 +522,14 @@ meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer)
wl_list_for_each_safe (popup, tmp, &popup_grab->all_popups, link)
{
meta_wayland_surface_popup_done (popup->surface);
MetaWaylandSurfaceExtension *xdg_popup = &popup->surface->xdg_popup;
struct wl_client *client = wl_resource_get_client (xdg_popup->resource);
struct wl_display *display = wl_client_get_display (client);
uint32_t serial;
serial = wl_display_next_serial (display);
xdg_popup_send_popup_done (xdg_popup->resource, serial);
wl_list_remove (&popup->surface_destroy_listener.link);
wl_list_remove (&popup->link);
g_slice_free (MetaWaylandPopup, popup);
@@ -561,13 +563,15 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
if (pointer->grab != &pointer->default_grab)
{
if (pointer->grab->interface != &popup_grab_interface)
return FALSE;
if (pointer->grab->interface == &popup_grab_interface)
{
grab = (MetaWaylandPopupGrab*)pointer->grab;
grab = (MetaWaylandPopupGrab*)pointer->grab;
if (wl_resource_get_client (surface->resource) != grab->grab_client)
return FALSE;
}
if (wl_resource_get_client (surface->resource) != grab->grab_client)
return FALSE;
return FALSE;
}
if (pointer->grab == &pointer->default_grab)
@@ -587,10 +591,7 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
popup->grab = grab;
popup->surface = surface;
popup->surface_destroy_listener.notify = on_popup_surface_destroy;
if (surface->xdg_popup.resource)
wl_resource_add_destroy_listener (surface->xdg_popup.resource, &popup->surface_destroy_listener);
else if (surface->wl_shell_surface.resource)
wl_resource_add_destroy_listener (surface->wl_shell_surface.resource, &popup->surface_destroy_listener);
wl_resource_add_destroy_listener (surface->xdg_popup.resource, &popup->surface_destroy_listener);
wl_list_insert (&grab->all_popups, &popup->link);

View File

@@ -46,11 +46,9 @@ struct _MetaWaylandPointerGrab
struct _MetaWaylandPointer
{
struct wl_list resource_list;
MetaWaylandSurface *focus_surface;
struct wl_listener focus_surface_listener;
MetaWaylandSurface *focus;
struct wl_resource *focus_resource;
struct wl_listener focus_resource_listener;
struct wl_listener focus_listener;
guint32 focus_serial;
guint32 click_serial;
@@ -69,7 +67,8 @@ struct _MetaWaylandPointer
};
void
meta_wayland_pointer_init (MetaWaylandPointer *pointer);
meta_wayland_pointer_init (MetaWaylandPointer *pointer,
gboolean is_native);
void
meta_wayland_pointer_release (MetaWaylandPointer *pointer);

View File

@@ -21,6 +21,7 @@
#define META_WAYLAND_PRIVATE_H
#include <wayland-server.h>
#include <xkbcommon/xkbcommon.h>
#include <clutter/clutter.h>
#include <glib.h>
@@ -30,7 +31,7 @@
#include "meta-weston-launch.h"
#include <meta/meta-cursor-tracker.h>
#include "meta-wayland.h"
#include "meta-wayland-types.h"
#include "meta-wayland-versions.h"
#include "meta-wayland-surface.h"
#include "meta-wayland-seat.h"
@@ -58,40 +59,55 @@ typedef struct
struct wl_resource *resource;
} MetaWaylandFrameCallback;
typedef struct
{
int display_index;
char *lockfile;
int abstract_fd;
int unix_fd;
pid_t pid;
struct wl_client *client;
struct wl_resource *xserver_resource;
char *display_name;
GMainLoop *init_loop;
} MetaXWaylandManager;
struct _MetaWaylandCompositor
{
struct wl_display *wayland_display;
char *display_name;
struct wl_event_loop *wayland_loop;
GMainLoop *init_loop;
ClutterActor *stage;
GHashTable *outputs;
GSource *wayland_event_source;
GList *surfaces;
struct wl_list frame_callbacks;
MetaXWaylandManager xwayland_manager;
int xwayland_display_index;
char *xwayland_lockfile;
int xwayland_abstract_fd;
int xwayland_unix_fd;
pid_t xwayland_pid;
struct wl_client *xwayland_client;
struct wl_resource *xserver_resource;
MetaLauncher *launcher;
gboolean native;
MetaWaylandSeat *seat;
};
MetaWaylandBuffer * meta_wayland_buffer_from_resource (struct wl_resource *resource);
void meta_wayland_buffer_ref (MetaWaylandBuffer *buffer);
void meta_wayland_buffer_unref (MetaWaylandBuffer *buffer);
void meta_wayland_init (void);
void meta_wayland_finalize (void);
/* We maintain a singleton MetaWaylandCompositor which can be got at via this
* API after meta_wayland_init() has been called. */
MetaWaylandCompositor *meta_wayland_compositor_get_default (void);
void meta_wayland_compositor_repick (MetaWaylandCompositor *compositor);
void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
MetaWindow *window);
gboolean meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor,
const ClutterEvent *event);
gboolean meta_wayland_compositor_is_native (MetaWaylandCompositor *compositor);
MetaWaylandBuffer * meta_wayland_buffer_from_resource (struct wl_resource *resource);
void meta_wayland_buffer_reference (MetaWaylandBufferReference *ref,
MetaWaylandBuffer *buffer);
void meta_wayland_compositor_update (MetaWaylandCompositor *compositor,
const ClutterEvent *event);
void meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor);
#endif /* META_WAYLAND_PRIVATE_H */

View File

@@ -38,7 +38,6 @@
#include "meta-shaped-texture-private.h"
#include "meta-wayland-stage.h"
#include "meta-cursor-tracker-private.h"
#include "meta-surface-actor-wayland.h"
#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int (10)
@@ -49,32 +48,28 @@ unbind_resource (struct wl_resource *resource)
}
static void
set_cursor_surface (MetaWaylandSeat *seat,
MetaWaylandSurface *surface)
pointer_unmap_sprite (MetaWaylandSeat *seat)
{
if (seat->cursor_surface == surface)
return;
if (seat->cursor_tracker)
meta_cursor_tracker_set_window_cursor (seat->cursor_tracker, NULL, 0, 0);
if (seat->cursor_surface)
wl_list_remove (&seat->cursor_surface_destroy_listener.link);
seat->cursor_surface = surface;
if (seat->cursor_surface)
wl_resource_add_destroy_listener (seat->cursor_surface->resource,
&seat->cursor_surface_destroy_listener);
if (seat->sprite)
{
wl_list_remove (&seat->sprite_destroy_listener.link);
seat->sprite = NULL;
}
}
void
meta_wayland_seat_update_cursor_surface (MetaWaylandSeat *seat)
meta_wayland_seat_update_sprite (MetaWaylandSeat *seat)
{
struct wl_resource *buffer;
if (seat->cursor_tracker == NULL)
return;
if (seat->cursor_surface && seat->cursor_surface->buffer)
buffer = seat->cursor_surface->buffer->resource;
if (seat->sprite->buffer_ref.buffer)
buffer = seat->sprite->buffer_ref.buffer->resource;
else
buffer = NULL;
@@ -94,24 +89,42 @@ pointer_set_cursor (struct wl_client *client,
MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface;
surface = (surface_resource ? wl_resource_get_user_data (surface_resource) : NULL);
surface = (surface_resource ?
wl_resource_get_user_data (surface_resource) :
NULL);
if (seat->pointer.focus_surface == NULL)
if (seat->pointer.focus == NULL)
return;
if (wl_resource_get_client (seat->pointer.focus_surface->resource) != client)
if (wl_resource_get_client (seat->pointer.focus->resource) != client)
return;
if (seat->pointer.focus_serial - serial > G_MAXUINT32 / 2)
return;
seat->hotspot_x = x;
seat->hotspot_y = y;
set_cursor_surface (seat, surface);
meta_wayland_seat_update_cursor_surface (seat);
if (seat->sprite != surface)
{
pointer_unmap_sprite (seat);
if (!surface)
return;
wl_resource_add_destroy_listener (surface->resource,
&seat->sprite_destroy_listener);
seat->sprite = surface;
if (seat->sprite->buffer_ref.buffer)
meta_wayland_seat_update_sprite (seat);
}
}
static const struct wl_pointer_interface pointer_interface = {
pointer_set_cursor
};
static const struct wl_pointer_interface
pointer_interface =
{
pointer_set_cursor
};
static void
seat_get_pointer (struct wl_client *client,
@@ -126,9 +139,9 @@ seat_get_pointer (struct wl_client *client,
wl_resource_set_implementation (cr, &pointer_interface, seat, unbind_resource);
wl_list_insert (&seat->pointer.resource_list, wl_resource_get_link (cr));
if (seat->pointer.focus_surface &&
wl_resource_get_client (seat->pointer.focus_surface->resource) == client)
meta_wayland_pointer_set_focus (&seat->pointer, seat->pointer.focus_surface);
if (seat->pointer.focus &&
wl_resource_get_client (seat->pointer.focus->resource) == client)
meta_wayland_pointer_set_focus (&seat->pointer, seat->pointer.focus);
}
static void
@@ -149,10 +162,10 @@ seat_get_keyboard (struct wl_client *client,
seat->keyboard.xkb_info.keymap_fd,
seat->keyboard.xkb_info.keymap_size);
if (seat->keyboard.focus_surface &&
wl_resource_get_client (seat->keyboard.focus_surface->resource) == client)
if (seat->keyboard.focus &&
wl_resource_get_client (seat->keyboard.focus->resource) == client)
{
meta_wayland_keyboard_set_focus (&seat->keyboard, seat->keyboard.focus_surface);
meta_wayland_keyboard_set_focus (&seat->keyboard, seat->keyboard.focus);
meta_wayland_data_device_set_keyboard_focus (seat);
}
}
@@ -196,16 +209,17 @@ bind_seat (struct wl_client *client,
}
static void
pointer_handle_cursor_surface_destroy (struct wl_listener *listener, void *data)
pointer_handle_sprite_destroy (struct wl_listener *listener, void *data)
{
MetaWaylandSeat *seat = wl_container_of (listener, seat, cursor_surface_destroy_listener);
MetaWaylandSeat *seat =
wl_container_of (listener, seat, sprite_destroy_listener);
set_cursor_surface (seat, NULL);
meta_wayland_seat_update_cursor_surface (seat);
pointer_unmap_sprite (seat);
}
MetaWaylandSeat *
meta_wayland_seat_new (struct wl_display *display)
meta_wayland_seat_new (struct wl_display *display,
gboolean is_native)
{
MetaWaylandSeat *seat = g_new0 (MetaWaylandSeat, 1);
@@ -213,15 +227,16 @@ meta_wayland_seat_new (struct wl_display *display)
wl_list_init (&seat->base_resource_list);
wl_list_init (&seat->data_device_resource_list);
meta_wayland_pointer_init (&seat->pointer);
meta_wayland_keyboard_init (&seat->keyboard, display);
meta_wayland_pointer_init (&seat->pointer, is_native);
meta_wayland_keyboard_init (&seat->keyboard, display, is_native);
seat->display = display;
seat->current_stage = 0;
seat->cursor_surface = NULL;
seat->cursor_surface_destroy_listener.notify = pointer_handle_cursor_surface_destroy;
seat->sprite = NULL;
seat->sprite_destroy_listener.notify = pointer_handle_sprite_destroy;
seat->hotspot_x = 16;
seat->hotspot_y = 16;
@@ -421,11 +436,16 @@ meta_wayland_seat_repick (MetaWaylandSeat *seat,
else
seat->current_stage = NULL;
if (META_IS_SURFACE_ACTOR_WAYLAND (actor))
surface = meta_surface_actor_wayland_get_surface (META_SURFACE_ACTOR_WAYLAND (actor));
if (META_IS_WINDOW_ACTOR (actor))
{
MetaWindow *window =
meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor));
surface = window->surface;
}
pointer->current = surface;
if (surface != pointer->focus_surface)
if (surface != pointer->focus)
{
const MetaWaylandPointerGrabInterface *interface =
pointer->grab->interface;
@@ -437,7 +457,7 @@ meta_wayland_seat_repick (MetaWaylandSeat *seat,
void
meta_wayland_seat_free (MetaWaylandSeat *seat)
{
set_cursor_surface (seat, NULL);
pointer_unmap_sprite (seat);
meta_wayland_pointer_release (&seat->pointer);
meta_wayland_keyboard_release (&seat->keyboard);

View File

@@ -66,15 +66,16 @@ struct _MetaWaylandSeat
struct wl_display *display;
MetaCursorTracker *cursor_tracker;
MetaWaylandSurface *cursor_surface;
MetaWaylandSurface *sprite;
int hotspot_x, hotspot_y;
struct wl_listener cursor_surface_destroy_listener;
struct wl_listener sprite_destroy_listener;
ClutterActor *current_stage;
};
MetaWaylandSeat *
meta_wayland_seat_new (struct wl_display *display);
meta_wayland_seat_new (struct wl_display *display,
gboolean is_native);
void
meta_wayland_seat_update_pointer (MetaWaylandSeat *seat,
@@ -89,7 +90,7 @@ meta_wayland_seat_repick (MetaWaylandSeat *seat,
const ClutterEvent *for_event);
void
meta_wayland_seat_update_cursor_surface (MetaWaylandSeat *seat);
meta_wayland_seat_update_sprite (MetaWaylandSeat *seat);
void
meta_wayland_seat_free (MetaWaylandSeat *seat);

File diff suppressed because it is too large Load Diff

View File

@@ -38,14 +38,15 @@ struct _MetaWaylandBuffer
struct wl_listener destroy_listener;
CoglTexture *texture;
uint32_t ref_count;
int32_t width, height;
uint32_t busy_count;
};
typedef struct
struct _MetaWaylandBufferReference
{
guint changed : 1;
guint value : 1;
} MetaWaylandStateFlag;
MetaWaylandBuffer *buffer;
struct wl_listener destroy_listener;
};
typedef struct
{
@@ -64,49 +65,26 @@ typedef struct
/* wl_surface.frame */
struct wl_list frame_callback_list;
gboolean frame_extents_changed;
GtkBorder frame_extents;
MetaWaylandStateFlag fullscreen;
MetaWaylandStateFlag maximized;
} MetaWaylandDoubleBufferedState;
typedef struct
{
struct wl_resource *resource;
struct wl_listener surface_destroy_listener;
} MetaWaylandSurfaceExtension;
struct _MetaWaylandSurface
{
struct wl_resource *resource;
MetaWaylandCompositor *compositor;
MetaWaylandBufferReference buffer_ref;
MetaSurfaceActor *surface_actor;
MetaWindow *window;
MetaWaylandSurfaceExtension xdg_surface;
MetaWaylandSurfaceExtension xdg_popup;
MetaWaylandSurfaceExtension wl_shell_surface;
MetaWaylandSurfaceExtension gtk_surface;
MetaWaylandSurfaceExtension subsurface;
MetaWaylandBuffer *buffer;
struct wl_listener buffer_destroy_listener;
GList *subsurfaces;
struct {
MetaWaylandSurface *parent;
struct wl_listener parent_destroy_listener;
gboolean synchronous;
MetaWaylandDoubleBufferedState pending_surface_state;
int32_t pending_x;
int32_t pending_y;
gboolean pending_pos;
GSList *pending_placement_ops;
} sub;
/* All the pending state, that wl_surface.commit will apply. */
MetaWaylandDoubleBufferedState pending;
};
@@ -117,22 +95,15 @@ MetaWaylandSurface *meta_wayland_surface_create (MetaWaylandCompositor *composit
struct wl_client *client,
guint32 id,
guint32 version);
void meta_wayland_surface_make_toplevel (MetaWaylandSurface *surface);
void meta_wayland_surface_window_unmanaged (MetaWaylandSurface *surface);
void meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
int width,
int height);
int height,
int edges);
void meta_wayland_surface_activated (MetaWaylandSurface *surface);
void meta_wayland_surface_deactivated (MetaWaylandSurface *surface);
void meta_wayland_surface_focused_set (MetaWaylandSurface *surface);
void meta_wayland_surface_focused_unset (MetaWaylandSurface *surface);
void meta_wayland_surface_ping (MetaWaylandSurface *surface,
guint32 serial);
void meta_wayland_surface_delete (MetaWaylandSurface *surface);
void meta_wayland_surface_popup_done (MetaWaylandSurface *surface);
#endif

View File

@@ -37,11 +37,11 @@
/* Global/master objects (version exported by wl_registry and negotiated through bind) */
#define META_WL_COMPOSITOR_VERSION 3
#define META_WL_DATA_DEVICE_MANAGER_VERSION 1
#define META_WL_SHELL_VERSION 1
#define META_WL_SEAT_VERSION 2 /* 3 not implemented yet */
#define META_WL_OUTPUT_VERSION 2
#define META_XSERVER_VERSION 1
#define META_GTK_SHELL_VERSION 1
#define META_XDG_SHELL_VERSION 1
#define META_WL_SUBCOMPOSITOR_VERSION 1
/* Slave objects (version inherited from a master object) */
@@ -53,10 +53,9 @@
#define META_WL_KEYBOARD_VERSION 2 /* from wl_seat; 3 not implemented yet */
#define META_WL_TOUCH_VERSION 0 /* from wl_seat; wl_touch not supported */
#define META_WL_REGION_VERSION 1 /* from wl_compositor */
#define META_GTK_SURFACE_VERSION 1 /* from gtk_shell */
#define META_XDG_SURFACE_VERSION 1 /* from xdg_shell */
#define META_XDG_POPUP_VERSION 1 /* from xdg_shell */
#define META_WL_SHELL_SURFACE_VERSION 1 /* from wl_shell */
#define META_GTK_SURFACE_VERSION 1 /* from gtk_shell */
#define META_WL_SUBSURFACE_VERSION 1 /* from wl_subcompositor */
/* The first version to implement a specific event */

View File

@@ -138,24 +138,6 @@ meta_wayland_buffer_destroy_handler (struct wl_listener *listener,
g_slice_free (MetaWaylandBuffer, buffer);
}
void
meta_wayland_buffer_ref (MetaWaylandBuffer *buffer)
{
buffer->ref_count++;
}
void
meta_wayland_buffer_unref (MetaWaylandBuffer *buffer)
{
buffer->ref_count--;
if (buffer->ref_count == 0)
{
g_clear_pointer (&buffer->texture, cogl_object_unref);
g_assert (wl_resource_get_client (buffer->resource));
wl_resource_queue_event (buffer->resource, WL_BUFFER_RELEASE);
}
}
MetaWaylandBuffer *
meta_wayland_buffer_from_resource (struct wl_resource *resource)
{
@@ -183,6 +165,46 @@ meta_wayland_buffer_from_resource (struct wl_resource *resource)
return buffer;
}
static void
meta_wayland_buffer_reference_handle_destroy (struct wl_listener *listener,
void *data)
{
MetaWaylandBufferReference *ref =
wl_container_of (listener, ref, destroy_listener);
g_assert (data == ref->buffer);
ref->buffer = NULL;
}
void
meta_wayland_buffer_reference (MetaWaylandBufferReference *ref,
MetaWaylandBuffer *buffer)
{
if (ref->buffer && buffer != ref->buffer)
{
ref->buffer->busy_count--;
if (ref->buffer->busy_count == 0)
{
g_clear_pointer (&ref->buffer->texture, cogl_object_unref);
g_assert (wl_resource_get_client (ref->buffer->resource));
wl_resource_queue_event (ref->buffer->resource, WL_BUFFER_RELEASE);
}
wl_list_remove (&ref->destroy_listener.link);
}
if (buffer && buffer != ref->buffer)
{
buffer->busy_count++;
wl_signal_add (&buffer->destroy_signal, &ref->destroy_listener);
}
ref->buffer = buffer;
ref->destroy_listener.notify = meta_wayland_buffer_reference_handle_destroy;
}
void
meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
MetaWindow *window)
@@ -483,7 +505,8 @@ meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor)
MetaWaylandFrameCallback *callback =
wl_container_of (compositor->frame_callbacks.next, callback, link);
wl_callback_send_done (callback->resource, get_time ());
wl_resource_post_event (callback->resource,
WL_CALLBACK_DONE, get_time ());
wl_resource_destroy (callback->resource);
}
}
@@ -600,11 +623,31 @@ meta_wayland_log_func (const char *fmt,
g_free (str);
}
static gboolean
are_we_native (int *out_drm_fd)
{
ClutterBackend *backend = clutter_get_default_backend ();
CoglContext *cogl_context = clutter_backend_get_cogl_context (backend);
CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (cogl_context));
if (cogl_renderer_get_winsys_id (cogl_renderer) == COGL_WINSYS_ID_EGL_KMS)
{
*out_drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
return TRUE;
}
else
{
return FALSE;
}
}
void
meta_wayland_init (void)
{
MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
MetaMonitorManager *monitors;
char *display_name;
int drm_fd;
memset (compositor, 0, sizeof (MetaWaylandCompositor));
@@ -643,24 +686,27 @@ meta_wayland_init (void)
clutter_wayland_set_compositor_display (compositor->wayland_display);
#if defined(CLUTTER_WINDOWING_EGL)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
compositor->launcher = meta_launcher_new ();
#endif
if (getenv ("WESTON_LAUNCHER_SOCK"))
compositor->launcher = meta_launcher_new ();
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
g_error ("Failed to initialize Clutter");
#if defined(CLUTTER_WINDOWING_EGL)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
if (are_we_native (&drm_fd))
{
ClutterBackend *backend = clutter_get_default_backend ();
CoglContext *cogl_context = clutter_backend_get_cogl_context (backend);
CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (cogl_context));
int drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
meta_launcher_set_drm_fd (compositor->launcher, drm_fd, NULL);
GError *error = NULL;
if (!meta_launcher_set_drm_fd (compositor->launcher, drm_fd, &error))
{
g_error ("Failed to set DRM fd to weston-launch and become DRM master: %s", error->message);
g_error_free (error);
}
compositor->native = TRUE;
}
else
{
compositor->native = FALSE;
}
#endif
meta_monitor_manager_initialize ();
monitors = meta_monitor_manager_get ();
@@ -676,7 +722,7 @@ meta_wayland_init (void)
meta_wayland_data_device_manager_init (compositor->wayland_display);
compositor->seat = meta_wayland_seat_new (compositor->wayland_display);
compositor->seat = meta_wayland_seat_new (compositor->wayland_display, compositor->native);
meta_wayland_init_shell (compositor);
@@ -697,10 +743,13 @@ meta_wayland_init (void)
* and so EGL must be initialized by this point.
*/
if (!meta_xwayland_start (&compositor->xwayland_manager, compositor->wayland_display))
if (!meta_xwayland_start (compositor))
g_error ("Failed to start X Wayland");
set_gnome_env ("DISPLAY", compositor->xwayland_manager.display_name);
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", compositor->display_name);
}
@@ -711,24 +760,12 @@ meta_wayland_finalize (void)
compositor = meta_wayland_compositor_get_default ();
meta_xwayland_stop (&compositor->xwayland_manager);
if (compositor->launcher)
meta_launcher_free (compositor->launcher);
meta_xwayland_stop (compositor);
meta_launcher_free (compositor->launcher);
}
gboolean
meta_wayland_compositor_activate_vt (MetaWaylandCompositor *compositor,
int vt,
GError **error)
meta_wayland_compositor_is_native (MetaWaylandCompositor *compositor)
{
if (compositor->launcher)
{
return meta_launcher_activate_vt (compositor->launcher, vt, error);
}
else
{
g_debug ("Ignoring VT switch keybinding, not running as VT manager");
return TRUE;
}
return compositor->native;
}

View File

@@ -1,51 +0,0 @@
/*
* Copyright (C) 2014 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#ifndef META_WAYLAND_H
#define META_WAYLAND_H
#include "meta-wayland-types.h"
void meta_wayland_init (void);
void meta_wayland_finalize (void);
/* We maintain a singleton MetaWaylandCompositor which can be got at via this
* API after meta_wayland_init() has been called. */
MetaWaylandCompositor *meta_wayland_compositor_get_default (void);
void meta_wayland_compositor_repick (MetaWaylandCompositor *compositor);
void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
MetaWindow *window);
gboolean meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor,
const ClutterEvent *event);
void meta_wayland_compositor_update (MetaWaylandCompositor *compositor,
const ClutterEvent *event);
void meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor);
gboolean meta_wayland_compositor_activate_vt (MetaWaylandCompositor *compositor,
int vt,
GError **error);
#endif

View File

@@ -385,17 +385,3 @@ meta_launcher_free (MetaLauncher *launcher)
g_slice_free (MetaLauncher, launcher);
}
gboolean
meta_launcher_activate_vt (MetaLauncher *launcher,
int vt,
GError **error)
{
struct weston_launcher_activate_vt message;
message.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT;
message.vt = vt;
return send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, error);
}

View File

@@ -28,10 +28,6 @@ typedef struct _MetaLauncher MetaLauncher;
MetaLauncher *meta_launcher_new (void);
void meta_launcher_free (MetaLauncher *self);
gboolean meta_launcher_activate_vt (MetaLauncher *self,
int number,
GError **error);
gboolean meta_launcher_set_drm_fd (MetaLauncher *self,
int drm_fd,
GError **error);

View File

@@ -25,13 +25,12 @@
#include <glib.h>
gboolean
meta_xwayland_start (MetaXWaylandManager *manager,
struct wl_display *display);
meta_xwayland_start (MetaWaylandCompositor *compositor);
void
meta_xwayland_complete_init (void);
void
meta_xwayland_stop (MetaXWaylandManager *manager);
meta_xwayland_stop (MetaWaylandCompositor *compositor);
#endif /* META_XWAYLAND_PRIVATE_H */

View File

@@ -44,19 +44,15 @@ xserver_set_window_id (struct wl_client *client,
MetaWindow *window;
window = meta_display_lookup_x_window (display, xid);
if (!window)
return;
meta_wayland_surface_make_toplevel (surface);
surface->window = window;
window->surface = surface;
meta_compositor_window_surface_changed (display->compositor, window);
if (window)
{
surface->window = window;
window->surface = surface;
}
}
static const struct xserver_interface xserver_implementation = {
xserver_set_window_id
xserver_set_window_id
};
static void
@@ -65,20 +61,25 @@ bind_xserver (struct wl_client *client,
guint32 version,
guint32 id)
{
MetaXWaylandManager *manager = data;
MetaWaylandCompositor *compositor = data;
/* If it's a different client than the xserver we launched,
* just freeze up... */
if (client != manager->client)
* don't start the wm. */
if (client != compositor->xwayland_client)
return;
manager->xserver_resource = wl_resource_create (client, &xserver_interface,
MIN (META_XSERVER_VERSION, version), id);
wl_resource_set_implementation (manager->xserver_resource,
&xserver_implementation, manager, NULL);
compositor->xserver_resource = wl_resource_create (client, &xserver_interface,
MIN (META_XSERVER_VERSION, version), id);
wl_resource_set_implementation (compositor->xserver_resource,
&xserver_implementation, compositor, NULL);
xserver_send_listen_socket (manager->xserver_resource, manager->abstract_fd);
xserver_send_listen_socket (manager->xserver_resource, manager->unix_fd);
wl_resource_post_event (compositor->xserver_resource,
XSERVER_LISTEN_SOCKET,
compositor->xwayland_abstract_fd);
wl_resource_post_event (compositor->xserver_resource,
XSERVER_LISTEN_SOCKET,
compositor->xwayland_unix_fd);
/* Make sure xwayland will recieve the above sockets in a finite
* time before unblocking the initialization mainloop since we are
@@ -90,8 +91,8 @@ bind_xserver (struct wl_client *client,
* connections so we can quit the transient initialization mainloop
* and unblock meta_wayland_init() to continue initializing mutter.
* */
g_main_loop_quit (manager->init_loop);
g_clear_pointer (&manager->init_loop, g_main_loop_unref);
g_main_loop_quit (compositor->init_loop);
g_clear_pointer (&compositor->init_loop, g_main_loop_unref);
}
static char *
@@ -122,7 +123,7 @@ create_lockfile (int display, int *display_out)
/* ignore error and try the next display number */
display++;
continue;
}
}
close (fd);
other = strtol (pid, &end, 0);
@@ -134,7 +135,7 @@ create_lockfile (int display, int *display_out)
/* ignore error and try the next display number */
display++;
continue;
}
}
if (kill (other, 0) < 0 && errno == ESRCH)
{
@@ -147,7 +148,7 @@ create_lockfile (int display, int *display_out)
}
g_free (filename);
continue;
}
}
g_free (filename);
display++;
@@ -239,12 +240,11 @@ bind_to_unix_socket (int display)
return -1;
}
if (listen (fd, 1) < 0)
{
if (listen (fd, 1) < 0) {
unlink (addr.sun_path);
close (fd);
return -1;
}
}
return fd;
}
@@ -287,8 +287,7 @@ x_io_error (Display *display)
}
gboolean
meta_xwayland_start (MetaXWaylandManager *manager,
struct wl_display *wl_display)
meta_xwayland_start (MetaWaylandCompositor *compositor)
{
int display = 0;
char *lockfile = NULL;
@@ -296,25 +295,27 @@ meta_xwayland_start (MetaXWaylandManager *manager,
pid_t pid;
char **env;
char *fd_string;
char *display_name;
char *log_path;
char *args[10];
char *args[11];
GError *error;
wl_global_create (wl_display, &xserver_interface,
wl_global_create (compositor->wayland_display,
&xserver_interface,
META_XSERVER_VERSION,
manager, bind_xserver);
compositor, bind_xserver);
do
{
lockfile = create_lockfile (display, &display);
if (!lockfile)
{
g_warning ("Failed to create an X lock file");
return FALSE;
g_warning ("Failed to create an X lock file");
return FALSE;
}
manager->abstract_fd = bind_to_abstract_socket (display);
if (manager->abstract_fd < 0)
compositor->xwayland_abstract_fd = bind_to_abstract_socket (display);
if (compositor->xwayland_abstract_fd < 0)
{
unlink (lockfile);
@@ -327,11 +328,11 @@ meta_xwayland_start (MetaXWaylandManager *manager,
return FALSE;
}
manager->unix_fd = bind_to_unix_socket (display);
if (manager->abstract_fd < 0)
compositor->xwayland_unix_fd = bind_to_unix_socket (display);
if (compositor->xwayland_abstract_fd < 0)
{
unlink (lockfile);
close (manager->abstract_fd);
close (compositor->xwayland_abstract_fd);
return FALSE;
}
@@ -339,8 +340,8 @@ meta_xwayland_start (MetaXWaylandManager *manager,
}
while (1);
manager->display_index = display;
manager->lockfile = lockfile;
compositor->xwayland_display_index = display;
compositor->xwayland_lockfile = lockfile;
/* We want xwayland to be a wayland client so we make a socketpair to setup a
* wayland protocol connection. */
@@ -356,19 +357,21 @@ meta_xwayland_start (MetaXWaylandManager *manager,
env = g_environ_setenv (env, "WAYLAND_SOCKET", fd_string, TRUE);
g_free (fd_string);
manager->display_name = g_strdup_printf (":%d", manager->display_index);
display_name = g_strdup_printf (":%d",
compositor->xwayland_display_index);
log_path = g_build_filename (g_get_user_cache_dir (), "xwayland.log", NULL);
args[0] = XWAYLAND_PATH;
args[1] = manager->display_name;
args[1] = display_name;
args[2] = "-wayland";
args[3] = "-rootless";
args[4] = "-noreset";
args[5] = "-logfile";
args[6] = log_path;
args[7] = "-nolisten";
args[8] = "all";
args[9] = NULL;
args[4] = "-retro";
args[5] = "-noreset";
args[6] = "-logfile";
args[7] = log_path;
args[8] = "-nolisten";
args[9] = "all";
args[10] = NULL;
error = NULL;
if (g_spawn_async (NULL, /* cwd */
@@ -386,9 +389,10 @@ meta_xwayland_start (MetaXWaylandManager *manager,
g_message ("forked X server, pid %d\n", pid);
close (sp[1]);
manager->client = wl_client_create (wl_display, sp[0]);
compositor->xwayland_client =
wl_client_create (compositor->wayland_display, sp[0]);
manager->pid = pid;
compositor->xwayland_pid = pid;
g_child_watch_add (pid, xserver_died, NULL);
}
else
@@ -397,13 +401,15 @@ meta_xwayland_start (MetaXWaylandManager *manager,
}
g_strfreev (env);
g_free (display_name);
g_free (log_path);
/* We need to run a mainloop until we know xwayland has a binding
* for our xserver interface at which point we can assume it's
* ready to start accepting connections. */
manager->init_loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (manager->init_loop);
compositor->init_loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (compositor->init_loop);
return TRUE;
}
@@ -421,14 +427,16 @@ meta_xwayland_complete_init (void)
}
void
meta_xwayland_stop (MetaXWaylandManager *manager)
meta_xwayland_stop (MetaWaylandCompositor *compositor)
{
char path[256];
snprintf (path, sizeof path, "/tmp/.X%d-lock", manager->display_index);
snprintf (path, sizeof path, "/tmp/.X%d-lock",
compositor->xwayland_display_index);
unlink (path);
snprintf (path, sizeof path, "/tmp/.X11-unix/X%d", manager->display_index);
snprintf (path, sizeof path, "/tmp/.X11-unix/X%d",
compositor->xwayland_display_index);
unlink (path);
unlink (manager->lockfile);
unlink (compositor->xwayland_lockfile);
}

View File

@@ -269,40 +269,6 @@ out:
return 0;
}
static int
handle_activate_vt(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
{
struct weston_launcher_reply reply;
struct weston_launcher_activate_vt *message;
reply.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT;
reply.ret = -1;
if (len != sizeof(*message)) {
error(0, 0, "missing value in activate_vt request");
goto out;
}
message = msg->msg_iov->iov_base;
reply.ret = ioctl(wl->tty, VT_ACTIVATE, message->vt);
if (reply.ret < 0)
reply.ret = -errno;
if (wl->verbose)
fprintf(stderr, "mutter-launch: activate VT, ret: %d\n", reply.ret);
out:
do {
len = send(wl->sock[0], &reply, sizeof reply, 0);
} while (len < 0 && errno == EINTR);
if (len < 0)
return -1;
return 0;
}
static int
handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
{
@@ -419,9 +385,6 @@ handle_socket_msg(struct weston_launch *wl)
case WESTON_LAUNCHER_CONFIRM_VT_SWITCH:
ret = handle_confirm_vt_switch(wl, &msg, len);
break;
case WESTON_LAUNCHER_ACTIVATE_VT:
ret = handle_activate_vt(wl, &msg, len);
break;
}
return ret;

View File

@@ -32,8 +32,7 @@ enum weston_launcher_message_type {
enum weston_launcher_opcode {
WESTON_LAUNCHER_OPEN = (1 << 1 | WESTON_LAUNCHER_REQUEST),
WESTON_LAUNCHER_DRM_SET_FD = (2 << 1 | WESTON_LAUNCHER_REQUEST),
WESTON_LAUNCHER_ACTIVATE_VT = (3 << 1 | WESTON_LAUNCHER_REQUEST),
WESTON_LAUNCHER_CONFIRM_VT_SWITCH = (4 << 1 | WESTON_LAUNCHER_REQUEST),
WESTON_LAUNCHER_CONFIRM_VT_SWITCH = (3 << 1 | WESTON_LAUNCHER_REQUEST),
};
enum weston_launcher_server_opcode {