Compare commits

..

19 Commits

Author SHA1 Message Date
Owen W. Taylor
8a0de6dfd3 Avoid restacking animating hidden actors
Since the stack passed to the compositor now accurately reflects
the X stacking order, we need to treat hidden windows (which are
at the bottom of the X stacking order) specially - when the
compositor stacking order is synced, try to keep animating hidden
actors in their old positions in the stack.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-27 09:58:45 -04:00
Owen W. Taylor
2bf0b2b6de Merge branch 'master' into override-redirect-exclusion 2009-06-19 11:42:03 -04:00
Owen W. Taylor
eed2a2d324 Fix shadowing problem breaking MetaStackTracker
A variable shadowing problem introduced in cleanup was causing
queued elements to be removed too early.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-17 14:23:57 -04:00
Owen W. Taylor
9828007a02 Merge branch 'master' into override-redirect-exclusion
Conflicts:
	src/core/bell.c
2009-06-17 13:40:42 -04:00
Owen W. Taylor
1f890672bb Use MetaStackTracker to avoid a round-trip XQueryTree()
With MetaStackTracker, it's no longer necessary to XQueryTree to
get a reasonably-up-to-date view of the server stacking order.

Add some comments explaining unclear aspects of
raise_window_relative_to_managed_windows() and with future possible
improvements.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-16 09:56:43 -04:00
Owen W. Taylor
ef966854d5 Don't do stacking for override-redirect windows
Don't add override-redirect windows to MetaStack; we shouldn't
be restacking them.

Since we *aren't* stacking the override-redirect windows, we need to
be careful that to ignore them when looking for the top managed
window.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-16 09:56:42 -04:00
Owen W. Taylor
7309b6cfe3 Move compositor-stack handling to MetaStackTracker
In order to properly track the stacking order for override-redirect
windows, move meta_compositor_sync_stack() call into MetaStackTracker.
In the new location, we sync the stack as a before-redraw idle function,
rather then using the freeze-thaw facilities of MetaStack. This is
simpler, and also properly compresses multiple stack changes on
notifications received from the X server.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-16 09:56:42 -04:00
Owen W. Taylor
3705a224f0 Add better tracking of real stacking order
Wedging override-redirect windows into the constraint code in stack.c
results in Mutter getting confused about the stacking order of
these windows with respect to other windows, and may also in some
cases cause Mutter to restack override-redirect windows.

core/stack-tracker.c core/stack-tracker.h: MetaStackTracker - combine
  events received from the X server with local changes we have made
  to come up with the best possible idea of what the stacking order
  is at any one point in time.

core/screen.c core/screen-private.h: Create a MetaStackTracker for
  the screen.

core/display.c: Feed relevant events to MetaStackTracker

core/frame.c core/screen.c core/stack.c: When we make changes to the
  stacking order or add windows, record those changes immediatley
  in MetaStackTracker so we have the information without waiting
  for a round-trip.

include/ui.h ui/ui.c: meta_ui_create_frame_window add a return value
  for the X request serial used to create the window.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-16 09:56:42 -04:00
Owen W. Taylor
2ebedb822d Avoid moving and resizing override-redirect windows
Override-redirect windows should not be moved or resized by the
window manager.

- Mark override-redirect windows as already placed to avoid
  placing them when first shown.
- Don't move-resize newly created override-redirect MetaWindow
- Don't queue a resize on override-redirect windows when reading
  their WM_TRANSIENT_FOR hint.
- Add g_return_if_fail (!window->override_redirect) to catch
  unexpected code paths that might result in override-redirect
  windows being moved or resized.
http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
d6576d9b70 Don't add override-redirect windows to workspaces
Normally a window that is "on all workspaces", is also on a particular
workspace (to deal with being unstuck.) This is pointless for
override-redirect windows.

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
6516c19ec5 Ignore client messages sent to override-redirect windows
If someone asks us to close, maximize, etc, an override-redirect
window, just ignore the request.

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
5518fee61c meta_screen_foreach_window(): Skip override-redirect windows
Don't include override-redirect windows when iterating the windows
in the screen. We don't need them for any of the current uses:

 - Queueing redraws and resizes on managed windows
 - Checking which windows should be added to a new workspace

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
ace0521cba meta_display_list_windows: Exclude override-redirect
Don't include override-redirect windows in the list return by
meta_display_list_windows(), since we almost never want to handle
them when considering "all window" for the display. Add a separate
meta_display_list_all_windows() that includes override-redirect
windows.

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
0091a3aab5 Don't read most properties for override-redirect windows
Skipping handling of properties for override redirect windows has
two advantages: first it reduces the amount of work needed to get
an override-redirect window (menu, tooltip, drag icon) onto the
screen. But more importantly, it reduces the number of code-paths
for an override-redirect to get into some code portion where it
isn't expected.

* Integrate the list of properties we load initially with the
  list of property hooks; this avoids having two separate lists
  that we have to keep in sync.

* Add a flag to MetaWindowPropHooks to indicate whether the
  property should be handled for override-redirect windows;
  currently we load a) properties that identify the window -
  useful for debugging purposes b) WM_TRANSIENT_FOR (could be
  used to associate menus with toplevels.)

* For properties that aren't always loaded through window-props.c,
  add !window->override checks to places that trigger loading,
  and add g_return_if_fail(!window->override) to the load
  functions as a double-check.

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
268b92a4ec Add checks against inappropriate changes to override-redirect window
Add g_return_if_fail() to check that window-management functions like
meta_window_maximize() aren't called on override-redirect windows.

This reveals that were were "unminimizing" override-redirect windows
when adding them; avoid doing that.

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:41 -04:00
Owen W. Taylor
29bb4c27e3 Fix property notifications for certain properties
If a property has a reload function, but the standard property-fetching
mechanism isn't used (hooks->type == META_PROP_VALUE_INVALID), then the
a logic error (introduced in January) caused the hook to never be run.

This meant that changes to struts and icons weren't noticed.

Same as: http://bugzilla.gnome.org/show_bug.cgi?id=572573
The fix here is different in detail from that applied to Metacity, but
similar in spirit.

http://bugzilla.gnome.org/show_bug.cgi?id=585980
2009-06-16 09:56:41 -04:00
Owen W. Taylor
bd3bdc51b9 Load NET_WM_USER_TIME from the right window
On subsequent changes, if there is a NET_WM_USER_TIME_WINDOW, then
read the property from that rather than from the main window.
(Fix an accidental regression: the right Window was being computed
but no longer passed in.)

http://bugzilla.gnome.org/show_bug.cgi?id=585979
2009-06-16 09:56:41 -04:00
Owen W. Taylor
0123dab87a Fix missing static for meta_window_show()
Definition of meta_window_show() was missing static although it
was forward-declared with static.

http://bugzilla.gnome.org/show_bug.cgi?id=585978
2009-06-16 09:56:41 -04:00
Owen W. Taylor
413acc9574 Regularize main loop priorities
If there is a client that is continually redrawing, then
sources that are less-prioritized than CLUTTER_PRIORITY_REDRAW
will never get run. This patch sorts out how all the different
main loop sources fit in CLUTTER_PRIORITY_REDRAW.

common.h: Document all the relevant priorities and how they
  fit in with each other.
ui.h common.h: Move META_PRIORITY_RESIZE to to common.h with
  other priorities.
src/core/window.c src/core/screen.c: Change calc-showing,
  update-icon, and update-work-area idles to be prioritized above
  redraws so they don't get starved.
bell.c: Make the visual bell priority the same as the clutter
  redraw priority.
delete.c: Use a G_PRIORITY_DEFAULT idle when responding to the
  dialog response; we want to handle it as soon as practical.

http://bugzilla.gnome.org/show_bug.cgi?id=568874
2009-06-16 09:56:41 -04:00
165 changed files with 53275 additions and 45422 deletions

31
.gitignore vendored
View File

@@ -13,22 +13,17 @@ config.sub
configure
depcomp
install-sh
intltool-extract.in
intltool-merge.in
libtool
ltmain.sh
missing
.deps
src/mutter-wm.desktop
src/mutter.desktop
src/metacity-wm.desktop
*.o
*.a
*.lo
*.la
.libs
*.swp
*.gir
*.typelib
tidy-enum-types.[ch]
tidy-marshal.[ch]
stamp-tidy-enum-types.h
@@ -43,18 +38,19 @@ POTFILES
50-metacity-desktop-key.xml
50-metacity-key.xml
inlinepixbufs.h
libmutter-private.pc
mutter
mutter-theme-viewer
mutter.desktop
mutter.schemas
libmetacity-private.pc
metacity
metacity-dialog
metacity-theme-viewer
metacity.desktop
metacity.schemas
testasyncgetprop
testboxes
testgradient
mutter-grayscale
mutter-mag
mutter-message
mutter-window-demo
metacity-grayscale
metacity-mag
metacity-message
metacity-window-demo
focus-window
test-gravity
test-resizing
@@ -62,8 +58,3 @@ test-size-hints
wm-tester
INSTALL
mkinstalldirs
src/mutter-enum-types.[ch]
src/stamp-mutter-enum-types.h
src/mutter-marshal.[ch]
src/stamp-mutter-marshal.h
src/mutter-plugins.pc

2
README
View File

@@ -20,7 +20,7 @@ libstartup-notification at
http://www.freedesktop.org/software/startup-notification/ or on the
GNOME ftp site. You also need GConf 1.2 (unless building a funky
extra-small embedded metacity with --disable-gconf, see below).
You need Clutter 1.0. You need gobject-introspection 0.6.3.
You need Clutter 0.9.3. You need gobject-introspection 0.6.3.
REPORTING BUGS AND SUBMITTING PATCHES
===

View File

@@ -1,13 +1,15 @@
AC_PREREQ(2.50)
m4_define([mutter_major_version], [2])
m4_define([mutter_minor_version], [91])
m4_define([mutter_micro_version], [2])
m4_define([mutter_minor_version], [27])
# Fibonacci sequence for micro version numbering:
# 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987
m4_define([mutter_micro_version], [0])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
m4_define([mutter_plugin_api_version], [3])
m4_define([mutter_plugin_api_version], [2])
AC_INIT([mutter], [mutter_version],
[http://bugzilla.gnome.org/enter_bug.cgi?product=mutter])
@@ -15,8 +17,7 @@ AC_INIT([mutter], [mutter_version],
AC_CONFIG_SRCDIR(src/core/display.c)
AC_CONFIG_HEADERS(config.h)
AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip])
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],)
AM_INIT_AUTOMAKE
AM_MAINTAINER_MODE
MUTTER_MAJOR_VERSION=mutter_major_version
@@ -45,9 +46,6 @@ AC_HEADER_STDC
AC_LIBTOOL_WIN32_DLL
AM_PROG_LIBTOOL
# Sets GLIB_GENMARSHAL and GLIB_MKENUMS
AM_PATH_GLIB_2_0()
#### Integer sizes
AC_CHECK_SIZEOF(char)
@@ -63,75 +61,68 @@ AC_C_BIGENDIAN
#### Warnings
# Stay command-line compatible with the gnome-common configure option. Here
# minimum/yes/maximum are the same, however.
AC_ARG_ENABLE(compile_warnings,
AS_HELP_STRING([--enable-compile-warnings=@<:@no/minimum/yes/maximum/error@:>@],[Turn on compiler warnings]),,
enable_compile_warnings=error)
changequote(,)dnl
if test "$enable_compile_warnings" != no ; then
if test "x$GCC" = "xyes"; then
case " $CFLAGS " in
*[\ \ ]-Wall[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wall" ;;
esac
if test "x$GCC" = "xyes"; then
case " $CFLAGS " in
*[\ \ ]-Wall[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wall" ;;
esac
# case " $CFLAGS " in
# *[\ \ ]-Wshadow[\ \ ]*) ;;
# *) CFLAGS="$CFLAGS -Wshadow" ;;
# esac
# case " $CFLAGS " in
# *[\ \ ]-Wshadow[\ \ ]*) ;;
# *) CFLAGS="$CFLAGS -Wshadow" ;;
# esac
case " $CFLAGS " in
*[\ \ ]-Wchar-subscripts[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wchar-subscripts" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wmissing-declarations[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wmissing-declarations" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wmissing-prototypes[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wmissing-prototypes" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wnested-externs[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wnested-externs" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wpointer-arith[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wpointer-arith" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wcast-align[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wcast-align" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wsign-compare[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wsign-compare" ;;
esac
if test "x$enable_ansi" = "xyes"; then
case " $CFLAGS " in
*[\ \ ]-Wchar-subscripts[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wchar-subscripts" ;;
*[\ \ ]-ansi[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -ansi" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wmissing-declarations[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wmissing-declarations" ;;
*[\ \ ]-pedantic[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -pedantic" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wmissing-prototypes[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wmissing-prototypes" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wnested-externs[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wnested-externs" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wpointer-arith[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wpointer-arith" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wcast-align[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wcast-align" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wsign-compare[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wsign-compare" ;;
esac
if test "$enable_compile_warnings" = error; then
case " $CFLAGS " in
*[\ \ ]-Werror[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Werror" ;;
esac
fi
fi
fi
changequote([,])dnl
GTK_MIN_VERSION=2.90.7
CANBERRA_GTK=libcanberra-gtk3
CANBERRA_GTK_VERSION=0.26
MUTTER_PC_MODULES="gtk+-3.0 >= $GTK_MIN_VERSION pango >= 1.2.0 cairo >= 1.10.0"
MUTTER_PC_MODULES='gtk+-2.0 >= 2.10.0 pango >= 1.2.0'
AC_ARG_ENABLE(gconf,
AC_HELP_STRING([--disable-gconf],
@@ -162,21 +153,31 @@ AC_ARG_ENABLE(startup-notification,
[disable mutter's startup notification support, for embedded/size-sensitive custom non-GNOME builds]),,
enable_startup_notification=auto)
AC_ARG_WITH(introspection,
AC_ARG_ENABLE(compositor,
AC_HELP_STRING([--disable-compositor],
[disable mutter's compositing manager]),,
enable_compositor=auto)
AC_ARG_ENABLE(clutter,
AC_HELP_STRING([--without-clutter],
[disable the use of clutter for compositing]),,
with_clutter=auto)
AC_ARG_ENABLE(introspection,
AC_HELP_STRING([--without-introspection],
[disable the use of GObject introspection]),,
with_introspection=auto)
AC_ARG_WITH(libcanberra,
AC_HELP_STRING([--without-libcanberra],
[disable the use of libcanberra for playing sounds]),,
with_libcanberra=auto)
AC_ARG_ENABLE(xsync,
AC_HELP_STRING([--disable-xsync],
[disable mutter's use of the XSync extension]),,
enable_xsync=auto)
AC_ARG_ENABLE(render,
AC_HELP_STRING([--disable-render],
[disable mutter's use of the RENDER extension]),,
enable_render=auto)
AC_ARG_ENABLE(shape,
AC_HELP_STRING([--disable-shape],
[disable mutter's use of the shaped window extension]),,
@@ -188,11 +189,17 @@ AC_CHECK_HEADERS(execinfo.h, [AC_CHECK_FUNCS(backtrace)])
AM_GLIB_GNU_GETTEXT
## here we get the flags we'll actually use
# GRegex requires Glib-2.14.0
PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.14.0)
# gtk_window_set_icon_name requires gtk2+-2.6.0
PKG_CHECK_MODULES(MUTTER_MESSAGE, gtk+-3.0 >= $GTK_MIN_VERSION)
PKG_CHECK_MODULES(MUTTER_WINDOW_DEMO, gtk+-3.0 >= $GTK_MIN_VERSION)
# GOptionEntry requires glib-2.6.0
PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.6.0)
# gtk_window_set_icon_name requires gtk2+-2.60
PKG_CHECK_MODULES(MUTTER_MESSAGE, gtk+-2.0 >= 2.6.0)
PKG_CHECK_MODULES(MUTTER_WINDOW_DEMO, gtk+-2.0 >= 2.6.0)
if $PKG_CONFIG --atleast-version 1.2.0 pangoxft; then
echo "pangoxft found"
else
AC_MSG_ERROR("Pango 1.2.0 or greater based on Xft2 is required")
fi
# Unconditionally use this dir to avoid a circular dep with gnomecc
GNOME_KEYBINDINGS_KEYSDIR="${datadir}/gnome-control-center/keybindings"
@@ -224,28 +231,43 @@ else
echo "Building without libstartup-notification"
fi
have_libcanberra=no
AC_MSG_CHECKING([libcanberra-gtk])
if test x$with_libcanberra = xno ; then
AC_MSG_RESULT([disabled])
else
if $PKG_CONFIG --exists $CANBERRA_GTK '>=' $CANBERRA_GTK_VERSION; then
have_libcanberra=yes
AC_MSG_RESULT(yes)
MUTTER_PC_MODULES="$MUTTER_PC_MODULES $CANBERRA_GTK"
AC_DEFINE([HAVE_LIBCANBERRA], 1, [Building with libcanberra for playing sounds])
else
AC_MSG_RESULT(no)
if test x$with_libcanberra = xyes ; then
AC_MSG_ERROR([libcanberra forced and libcanberra-gtk was not found])
fi
fi
fi
## init this, it gets set either in the compositor check below
## or the render-specific check later
have_xrender=no
XCOMPOSITE_VERSION=0.2
if test x$enable_compositor = xyes; then
have_xcomposite=yes
elif test x$enable_compositor = xauto; then
echo "Building compositing manager by default now."
have_xcomposite=yes
else
have_xcomposite=no
fi
AC_MSG_CHECKING([Xcomposite >= $XCOMPOSITE_VERSION])
if $PKG_CONFIG --atleast-version $XCOMPOSITE_VERSION xcomposite; then
if test x$with_clutter = xyes; then
have_xcomposite=yes
have_clutter=yes
elif test x$with_clutter = xauto; then
echo "Building clutter compositing manager by default now."
have_xcomposite=yes
have_clutter=yes
else
have_clutter=no
fi
AM_CONDITIONAL(WITH_CLUTTER, test "$have_clutter" = "yes")
if test x$have_xcomposite = xyes; then
AC_MSG_CHECKING([Xcomposite >= $XCOMPOSITE_VERSION])
if $PKG_CONFIG --atleast-version $XCOMPOSITE_VERSION xcomposite; then
AC_MSG_RESULT([yes])
else
AC_MSG_ERROR([no. Use --disable-compositor to disable.])
fi
fi
if test x$have_xcomposite = xyes; then
MUTTER_PC_MODULES="$MUTTER_PC_MODULES xcomposite >= $XCOMPOSITE_VERSION xfixes xrender xdamage"
AC_DEFINE(HAVE_COMPOSITE_EXTENSIONS, 1, [Building with compositing manager support])
echo "Building with compositing manager"
@@ -253,13 +275,42 @@ if $PKG_CONFIG --atleast-version $XCOMPOSITE_VERSION xcomposite; then
## force on render also
have_xrender=yes
else
AC_MSG_ERROR([no. Mutter requires the Xcomposite extension to build.])
echo "Building without compositing manager"
fi
CLUTTER_VERSION=1.2.0
CLUTTER_PACKAGE=clutter-1.0
## if no compositor, still possibly enable render
if test x$have_xcomposite = xno; then
XRENDER_VERSION=0.0
AC_MSG_CHECKING([xrender >= $XRENDER_VERSION])
if $PKG_CONFIG --atleast-version $XRENDER_VERSION xrender; then
have_xrender=yes
else
have_xrender=no
fi
AC_MSG_RESULT($have_xrender)
if test x$enable_render = xyes; then
have_xrender=yes
echo "Render support forced on"
elif test x$enable_render = xauto; then
true
else
have_xrender=no
fi
if test x$have_xrender = xyes; then
echo "Building with Render"
MUTTER_PC_MODULES="$MUTTER_PC_MODULES xrender >= $XRENDER_VERSION"
fi
fi ## have_composite
if test x$have_xrender = xyes; then
AC_DEFINE(HAVE_RENDER, , [Building with Render extension support])
fi
CLUTTER_PACKAGE=clutter-0.9
AC_SUBST(CLUTTER_PACKAGE)
if $PKG_CONFIG --atleast-version $CLUTTER_VERSION $CLUTTER_PACKAGE ; then
if test x$have_clutter = xyes; then
MUTTER_PC_MODULES="$MUTTER_PC_MODULES $CLUTTER_PACKAGE "
PKG_CHECK_MODULES(CLUTTER, $CLUTTER_PACKAGE)
AC_DEFINE(WITH_CLUTTER, , [Building with Clutter compositor])
@@ -276,12 +327,10 @@ if $PKG_CONFIG --atleast-version $CLUTTER_VERSION $CLUTTER_PACKAGE ; then
AC_DEFINE(HAVE_GLX_TEXTURE_PIXMAP, ,
[Is ClutterGLXTexturePixmap available?])
fi
else
AC_MSG_ERROR([no. Mutter requires Clutter version $CLUTTER_VERSION.])
fi
if test x$with_introspection != xno; then
PKG_CHECK_MODULES(INTROSPECTION, gobject-introspection-1.0 >= 0.9.5, have_introspection=yes, have_introspection=no)
PKG_CHECK_MODULES(INTROSPECTION, gobject-introspection-1.0, have_introspection=yes, have_introspection=no)
if test x$have_introspection=xyes; then
MUTTER_PC_MODULES="$MUTTER_PC_MODULES gobject-introspection-1.0"
AC_DEFINE(HAVE_INTROSPECTION, 1, [Define if GObject introspection is available])
@@ -444,7 +493,7 @@ fi
MUTTER_LIBS="$MUTTER_LIBS $XSYNC_LIBS $RANDR_LIBS $SHAPE_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS -lm"
MUTTER_MESSAGE_LIBS="$MUTTER_MESSAGE_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS"
MUTTER_WINDOW_DEMO_LIBS="$MUTTER_WINDOW_DEMO_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS -lm"
MUTTER_WINDOW_DEMO_LIBS="$MUTTER_WINDOW_DEMO_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS"
MUTTER_PROPS_LIBS="$MUTTER_PROPS_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS"
found_sm=no
@@ -512,8 +561,10 @@ if test "x$enable_debug" = "xyes"; then
CFLAGS="$CFLAGS -g -O"
fi
# For fix-meta-rectangle.py
AM_PATH_PYTHON([2.5])
# Warnings are there for a reason
if test "x$GCC" = "xyes"; then
CFLAGS="$CFLAGS -Wall -Werror -ansi"
fi
# Use gnome-doc-utils:
GNOME_DOC_INIT([0.8.0])
@@ -527,7 +578,7 @@ src/wm-tester/Makefile
src/libmutter-private.pc
src/mutter-plugins.pc
src/tools/Makefile
src/compositor/plugins/Makefile
src/compositor/mutter/plugins/Makefile
po/Makefile.in
])
@@ -550,7 +601,7 @@ fi
dnl ==========================================================================
echo "
mutter-$VERSION
mutter-$VERSION:
prefix: ${prefix}
source code location: ${srcdir}
@@ -560,18 +611,20 @@ mutter-$VERSION
XFree86 Xinerama: ${use_xfree_xinerama}
Solaris Xinerama: ${use_solaris_xinerama}
Startup notification: ${have_startup_notification}
libcanberra: ${have_libcanberra}
Compositing manager: ${have_xcomposite}
Introspection: ${have_introspection}
Session management: ${found_sm}
Shape extension: ${found_shape}
Resize-and-rotate: ${found_randr}
Xsync: ${found_xsync}
Render: ${have_xrender}
Xcursor: ${have_xcursor}
Clutter: ${have_clutter}
"
MUTTER_MINOR_VERSION=mutter_minor_version
if expr $MUTTER_MINOR_VERSION % 2 > /dev/null ; then
stable_version=`expr $MUTTER_MINOR_VERSION - 1`
if test $(( $(echo $MUTTER_MINOR_VERSION) %2)) == "1"; then
stable_version=$(( ($MUTTER_MINOR_VERSION / 2) * 2))
echo "This is the UNSTABLE branch of mutter"
echo -n "Use 2.$stable_version.x for stable "
echo "(gnome-2-$stable_version branch in Subversion)"

View File

@@ -4,7 +4,6 @@ of the theme format, and a given theme can support more than one format.
Version 1: THEMEDIR/metacity-1/metacity-theme-1.xml
(original metacity format)
Version 2: THEMEDIR/metacity-1/metacity-theme-2.xml
Version 3: THEMEDIR/metacity-1/metacity-theme-3.xml
The subdirectory name is "metacity-1" in all versions.
@@ -22,41 +21,6 @@ This document has separate sections for each format version. You may
want to read the document in reverse order, since the base features
are discussed under version 1.
New Features in Theme Format Version 3.1
========================================
Additional predefined variables are added for positioning expressions:
frame_x_center: the X center of the entire frame, with respect to the
piece currently being drawn.
frame_y_center: the Y center of the entire frame, with respect to the
piece currently being drawn.
The <title/> element now supports an "ellipsize_width" attribute. When
specified, this gives a width at which to ellipsize the title. If not
specified, the title will simply be clipped to the title area.
New Features in Theme Format Version 3
======================================
Format version 3 has exactly one new feature; any element in the file
can now have a version attribute:
version="[<|<=|=>|>] MAJOR.MINOR"
(< and > should be to be entity escaped as &lt; and &gt;). If this
version check is not met, then the element and its children will be
ignored. This allows having alternate sections of the theme file for
older and newer version of the Metacity theme format.
When placed on the toplevel <metacity_theme> element, an unsatisfied
version check will not just cause the contents of the file to be
ignored, it will also cause the lookup of a theme file to proceed on
and look for an older format 2 or format 1 file. This allows making a
metacity-theme-3.xml file that is only used the format version 3.2 or
newer is supported, and using metacity-theme-1.xml for older window
managers.
New Features in Theme Format Version 2
======================================

View File

@@ -10,7 +10,6 @@ be@latin
bg
bn
bn_IN
br
bs
ca
ca@valencia
@@ -57,7 +56,6 @@ mn
mr
ms
nb
nds
ne
nl
nn

View File

@@ -1,6 +1,5 @@
# List of source files containing translatable strings.
# Please keep this file sorted alphabetically.
src/core/bell.c
src/core/core.c
src/core/delete.c
src/core/display.c

5069
po/ar.po

File diff suppressed because it is too large Load Diff

1825
po/ast.po

File diff suppressed because it is too large Load Diff

1483
po/bg.po

File diff suppressed because it is too large Load Diff

1835
po/br.po

File diff suppressed because it is too large Load Diff

1521
po/cs.po

File diff suppressed because it is too large Load Diff

1855
po/da.po

File diff suppressed because it is too large Load Diff

3290
po/de.po

File diff suppressed because it is too large Load Diff

1485
po/el.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2008
po/es.po

File diff suppressed because it is too large Load Diff

1162
po/eu.po

File diff suppressed because it is too large Load Diff

3013
po/fr.po

File diff suppressed because it is too large Load Diff

3199
po/gl.po

File diff suppressed because it is too large Load Diff

2803
po/he.po

File diff suppressed because it is too large Load Diff

1529
po/hu.po

File diff suppressed because it is too large Load Diff

2191
po/it.po

File diff suppressed because it is too large Load Diff

1677
po/lt.po

File diff suppressed because it is too large Load Diff

1482
po/nb.po

File diff suppressed because it is too large Load Diff

1814
po/nds.po

File diff suppressed because it is too large Load Diff

2014
po/pa.po

File diff suppressed because it is too large Load Diff

2988
po/pl.po

File diff suppressed because it is too large Load Diff

2009
po/pt.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2118
po/sk.po

File diff suppressed because it is too large Load Diff

2589
po/sl.po

File diff suppressed because it is too large Load Diff

1984
po/sr.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

783
po/sv.po

File diff suppressed because it is too large Load Diff

2076
po/ta.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,49 +1,29 @@
# Flag build for parallelism; see https://savannah.gnu.org/patch/?6905
.AUTOPARALLEL:
lib_LTLIBRARIES = libmutter-private.la
SUBDIRS=wm-tester tools compositor/plugins
SUBDIRS=wm-tester tools
if WITH_CLUTTER
SUBDIRS += compositor/mutter/plugins
endif
INCLUDES=@MUTTER_CFLAGS@ -I $(srcdir)/include -I$(srcdir)/compositor -DMUTTER_LIBEXECDIR=\"$(libexecdir)\" -DHOST_ALIAS=\"@HOST_ALIAS@\" -DMUTTER_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" -DMUTTER_PKGDATADIR=\"$(pkgdatadir)\" -DMUTTER_DATADIR=\"$(datadir)\" -DG_LOG_DOMAIN=\"mutter\" -DSN_API_NOT_YET_FROZEN=1 -DMUTTER_MAJOR_VERSION=$(MUTTER_MAJOR_VERSION) -DMUTTER_MINOR_VERSION=$(MUTTER_MINOR_VERSION) -DMUTTER_MICRO_VERSION=$(MUTTER_MICRO_VERSION) -DMUTTER_PLUGIN_API_VERSION=$(MUTTER_PLUGIN_API_VERSION) -DMUTTER_PKGLIBDIR=\"$(pkglibdir)\" -DMUTTER_PLUGIN_DIR=\"@MUTTER_PLUGIN_DIR@\"
mutter_built_sources = \
mutter-marshal.h \
mutter-marshal.c \
mutter-enum-types.h \
mutter-enum-types.c
mutter_SOURCES= \
core/async-getprop.c \
core/async-getprop.h \
core/alttabhandler.c \
include/alttabhandler.h \
core/alttabhandlerdefault.c \
include/alttabhandlerdefault.h \
core/bell.c \
core/bell.h \
core/boxes.c \
core/boxes-private.h \
include/boxes.h \
compositor/compositor.c \
compositor/compositor-private.h \
compositor/meta-module.c \
compositor/meta-module.h \
compositor/meta-plugin.c \
compositor/meta-plugin-manager.c \
compositor/meta-plugin-manager.h \
compositor/meta-shaped-texture.c \
compositor/meta-shaped-texture.h \
compositor/meta-texture-tower.c \
compositor/meta-texture-tower.h \
compositor/meta-window-actor.c \
compositor/meta-window-actor-private.h \
compositor/meta-window-group.c \
compositor/meta-window-group.h \
compositor/shadow.c \
compositor/shadow.h \
compositor/tidy/tidy-texture-frame.c \
compositor/tidy/tidy-texture-frame.h \
compositor/compositor-xrender.c \
compositor/compositor-xrender.h \
include/compositor.h \
include/meta-plugin.h \
include/meta-window-actor.h \
include/compositor-mutter.h \
core/constraints.c \
core/constraints.h \
core/core.c \
@@ -55,6 +35,8 @@ mutter_SOURCES= \
ui/draw-workspace.h \
core/edge-resistance.c \
core/edge-resistance.h \
core/effects.c \
core/effects.h \
core/errors.c \
include/errors.h \
core/eventqueue.c \
@@ -74,7 +56,8 @@ mutter_SOURCES= \
core/keybindings.c \
core/keybindings-private.h \
core/main.c \
core/mutter-Xatomtype.h \
include/main.h \
core/mutter-Xatomtype.h \
core/place.c \
core/place.h \
core/prefs.c \
@@ -116,15 +99,30 @@ mutter_SOURCES= \
include/resizepopup.h \
ui/tabpopup.c \
include/tabpopup.h \
ui/tile-preview.c \
include/tile-preview.h \
ui/theme-parser.c \
ui/theme-parser.h \
ui/theme.c \
ui/theme.h \
ui/theme-private.h \
ui/themewidget.c \
ui/themewidget.h \
ui/ui.c \
include/all-keybindings.h \
$(mutter_built_sources)
include/all-keybindings.h
if WITH_CLUTTER
mutter_SOURCES += \
compositor/mutter/compositor-mutter.c \
compositor/mutter/mutter-shaped-texture.c \
compositor/mutter/mutter-shaped-texture.h \
compositor/mutter/mutter-plugin-manager.c \
compositor/mutter/mutter-plugin-manager.h \
compositor/mutter/tidy/tidy-texture-frame.c \
compositor/mutter/tidy/tidy-texture-frame.h \
compositor/mutter/mutter-module.c \
compositor/mutter/mutter-module.h \
compositor/mutter/mutter-plugin.c \
include/mutter-plugin.h \
include/compositor-mutter.h
endif
# by setting libmutter_private_la_CFLAGS, the files shared with
# mutter proper will be compiled with different names.
@@ -140,20 +138,23 @@ libmutter_private_la_SOURCES= \
ui/preview-widget.c \
ui/preview-widget.h \
ui/theme-parser.c \
ui/theme-parser.h \
ui/theme.c \
ui/theme.h
libmutter_private_la_LDFLAGS = -no-undefined
libmutter_private_la_LIBADD = @MUTTER_LIBS@
# Headers installed for plugins; introspected information will
# be extracted into Mutter-<version>.gir
libmutterincludedir = $(includedir)/mutter/mutter-private
libmutterinclude_base_headers = \
include/alttabhandler.h \
include/boxes.h \
ui/gradient.h \
include/main.h \
include/util.h \
include/common.h \
ui/preview-widget.h \
ui/theme-parser.h \
ui/theme.h \
include/prefs.h \
include/window.h \
@@ -161,23 +162,16 @@ libmutterinclude_base_headers = \
include/compositor.h \
include/compositor-mutter.h \
include/types.h \
include/errors.h \
include/screen.h \
include/display.h \
include/group.h \
include/keybindings.h \
include/meta-plugin.h \
include/meta-window-actor.h
include/mutter-plugin.h
# Excluded from scanning for introspection but installed
# preview-widget.h: only part of libmutter-private
# atomnames.h: macros cause problems for scanning process
libmutterinclude_extra_headers = \
ui/preview-widget.h \
include/atomnames.h
libmutterincludedir = $(includedir)/mutter/mutter-private
libmutterinclude_HEADERS = \
$(libmutterinclude_base_headers) \
$(libmutterinclude_extra_headers)
@@ -201,35 +195,29 @@ typelib_DATA = Meta-$(api_version).typelib
# We need to strip out the attribute that would point back to libmutter-introspect
# so that libgirepository looks for symbols in the executable instead
Meta-$(api_version).gir: $(G_IR_SCANNER) mutter $(libmutterinclude_HEADERS) $(mutter_SOURCES) Makefile
$(AM_V_GEN) pwd=`pwd` ; \
cd $(srcdir) && \
Meta-$(api_version).gir: $(G_IR_SCANNER) mutter $(libmutterinclude_HEADERS) $(mutter_SOURCES)
$(G_IR_SCANNER) \
--namespace=Meta \
--nsversion=$(api_version) \
--warn-all \
--warn-error \
--include=GObject-2.0 \
--include=Gdk-3.0 \
--include=Gtk-3.0 \
--include=Clutter-1.0 \
--pkg=clutter-1.0 \
--pkg=gtk+-3.0 \
--include=xlib-2.0 \
--include=Gdk-2.0 \
--include=Gtk-2.0 \
--include=Clutter-0.9 \
--pkg=clutter-0.9 \
--pkg=gtk+-2.0 \
--include=xfixes-4.0 \
--program=$$pwd/mutter \
mutter-enum-types.h \
$(filter %.c,$(mutter_SOURCES)) \
--program=./mutter \
$(filter %.c,$(mutter_SOURCES)) \
$(libmutterinclude_base_headers) \
$(INCLUDES) \
-o $$pwd/$@
-o $@
Meta-$(api_version).typelib: $(G_IR_COMPILER) Meta-$(api_version).gir
$(AM_V_GEN) LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. $(G_IR_COMPILER) Meta-$(api_version).gir -o $@
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. $(G_IR_COMPILER) Meta-$(api_version).gir -o $@
endif
EFENCE=
mutter_LDADD=@MUTTER_LIBS@ $(EFENCE)
mutter_LDADD=@MUTTER_LIBS@ libmutter-private.la $(EFENCE)
mutter_LDFLAGS=-export-dynamic
mutter_theme_viewer_LDADD= @MUTTER_LIBS@ libmutter-private.la
@@ -240,9 +228,9 @@ testasyncgetprop_SOURCES=core/async-getprop.h core/async-getprop.c core/testasyn
noinst_PROGRAMS=testboxes testgradient testasyncgetprop
testboxes_LDADD= @MUTTER_LIBS@
testgradient_LDADD= @MUTTER_LIBS@
testasyncgetprop_LDADD= @MUTTER_LIBS@
testboxes_LDADD= @MUTTER_LIBS@ libmutter-private.la
testgradient_LDADD= @MUTTER_LIBS@ libmutter-private.la
testasyncgetprop_LDADD= @MUTTER_LIBS@ libmutter-private.la
@INTLTOOL_DESKTOP_RULE@
@@ -277,14 +265,7 @@ VARIABLES=stock_maximize_data $(srcdir)/stock_maximize.png \
stock_delete_data $(srcdir)/stock_delete.png
BUILT_SOURCES = inlinepixbufs.h
CLEANFILES = \
inlinepixbufs.h \
mutter.desktop \
mutter-wm.desktop \
mutter.schemas \
$(mutter_built_sources) \
$(typelib_DATA) \
$(gir_DATA)
CLEANFILES = inlinepixbufs.h mutter.desktop mutter-wm.desktop mutter.schemas
inlinepixbufs.h: $(IMAGES)
$(GDK_PIXBUF_CSOURCE) --raw --build-list $(VARIABLES) >$(srcdir)/inlinepixbufs.h
@@ -295,55 +276,10 @@ pkgconfig_DATA = libmutter-private.pc mutter-plugins.pc
EXTRA_DIST=$(desktopfiles_files) \
$(wmproperties_files) \
$(IMAGES) \
$(IMAGES) $(schema_DATA) \
$(desktopfiles_in_files) \
$(wmproperties_in_files) \
$(schema_in_files) \
libmutter-private.pc.in \
mutter-plugins.pc.in \
mutter-enum-types.h.in \
mutter-enum-types.c.in \
mutter-marshal.list
mutter-plugins.pc.in
BUILT_SOURCES += $(mutter_built_sources)
MUTTER_STAMP_FILES = stamp-mutter-marshal.h stamp-mutter-enum-types.h
CLEANFILES += $(MUTTER_STAMP_FILES)
mutter-marshal.h: stamp-mutter-marshal.h
@true
stamp-mutter-marshal.h: Makefile mutter-marshal.list
$(AM_V_GEN) $(GLIB_GENMARSHAL) \
--prefix=_mutter_marshal \
--header \
$(srcdir)/mutter-marshal.list > xgen-tmh && \
(cmp -s xgen-tmh mutter-marshal.h || cp -f xgen-tmh mutter-marshal.h) && \
rm -f xgen-tmh && \
echo timestamp > $(@F)
mutter-marshal.c: Makefile mutter-marshal.list
$(AM_V_GEN) (echo "#include \"mutter-marshal.h\"" ; \
$(GLIB_GENMARSHAL) \
--prefix=_mutter_marshal \
--body \
$(srcdir)/mutter-marshal.list ) > xgen-tmc && \
cp -f xgen-tmc mutter-marshal.c && \
rm -f xgen-tmc
mutter-enum-types.h: stamp-mutter-enum-types.h Makefile
@true
stamp-mutter-enum-types.h: $(libmutterinclude_base_headers) mutter-enum-types.h.in
$(AM_V_GEN) ( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template $(srcdir)/mutter-enum-types.h.in \
$(libmutterinclude_base_headers) ) >> xgen-teth && \
(cmp -s xgen-teth mutter-enum-types.h || cp xgen-teth mutter-enum-types.h) && \
rm -f xgen-teth && \
echo timestamp > $(@F)
mutter-enum-types.c: stamp-mutter-enum-types.h mutter-enum-types.c.in
$(AM_V_GEN) ( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template $(srcdir)/mutter-enum-types.c.in \
$(libmutterinclude_base_headers) ) >> xgen-tetc && \
cp xgen-tetc mutter-enum-types.c && \
rm -f xgen-tetc

View File

@@ -1,68 +1,90 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2008 Iain Holmes
*
* 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.
*/
#ifndef META_COMPOSITOR_PRIVATE_H
#define META_COMPOSITOR_PRIVATE_H
#include <X11/extensions/Xfixes.h>
#include "compositor.h"
#include "display.h"
#include "meta-plugin-manager.h"
#include <clutter/clutter.h>
typedef struct _MetaCompScreen MetaCompScreen;
struct _MetaCompositor
{
MetaDisplay *display;
void (* destroy) (MetaCompositor *compositor);
Atom atom_x_root_pixmap;
Atom atom_x_set_root;
Atom atom_net_wm_window_opacity;
guint repaint_func_id;
ClutterActor *shadow_src;
MetaPlugin *modal_plugin;
gboolean show_redraw : 1;
gboolean debug : 1;
gboolean no_mipmaps : 1;
void (*manage_screen) (MetaCompositor *compositor,
MetaScreen *screen);
void (*unmanage_screen) (MetaCompositor *compositor,
MetaScreen *screen);
void (*add_window) (MetaCompositor *compositor,
MetaWindow *window);
void (*remove_window) (MetaCompositor *compositor,
MetaWindow *window);
void (*set_updates) (MetaCompositor *compositor,
MetaWindow *window,
gboolean update);
gboolean (*process_event) (MetaCompositor *compositor,
XEvent *event,
MetaWindow *window);
Pixmap (*get_window_pixmap) (MetaCompositor *compositor,
MetaWindow *window);
void (*set_active_window) (MetaCompositor *compositor,
MetaScreen *screen,
MetaWindow *window);
void (*map_window) (MetaCompositor *compositor,
MetaWindow *window);
void (*unmap_window) (MetaCompositor *compositor,
MetaWindow *window);
void (*minimize_window) (MetaCompositor *compositor,
MetaWindow *window,
MetaRectangle *window_rect,
MetaRectangle *icon_rect);
void (*unminimize_window) (MetaCompositor *compositor,
MetaWindow *window,
MetaRectangle *window_rect,
MetaRectangle *icon_rect);
void (*maximize_window) (MetaCompositor *compositor,
MetaWindow *window,
MetaRectangle *window_rect);
void (*unmaximize_window) (MetaCompositor *compositor,
MetaWindow *window,
MetaRectangle *window_rect);
void (*update_workspace_geometry) (MetaCompositor *compositor,
MetaWorkspace *workspace);
void (*switch_workspace) (MetaCompositor *compositor,
MetaScreen *screen,
MetaWorkspace *from,
MetaWorkspace *to,
MetaMotionDirection direction);
void (*sync_stack) (MetaCompositor *compositor,
MetaScreen *screen,
GList *stack);
void (*set_window_hidden) (MetaCompositor *compositor,
MetaScreen *screen,
MetaWindow *window,
gboolean hidden);
void (*sync_window_geometry) (MetaCompositor *compositor,
MetaWindow *window);
void (*sync_screen_size) (MetaCompositor *compositor,
MetaScreen *screen,
guint width,
guint height);
};
struct _MetaCompScreen
{
MetaScreen *screen;
ClutterActor *stage, *window_group, *overlay_group;
ClutterActor *hidden_group;
GList *windows;
GHashTable *windows_by_xid;
Window output;
/* Before we create the output window */
XserverRegion pending_input_region;
gint switch_workspace_in_progress;
MetaPluginManager *plugin_mgr;
};
void meta_switch_workspace_completed (MetaScreen *screen);
void meta_set_stage_input_region (MetaScreen *screen,
XserverRegion region);
void meta_empty_stage_input_region (MetaScreen *screen);
gboolean meta_begin_modal_for_plugin (MetaScreen *screen,
MetaPlugin *plugin,
Window grab_window,
Cursor cursor,
MetaModalOptions options,
guint32 timestamp);
void meta_end_modal_for_plugin (MetaScreen *screen,
MetaPlugin *plugin,
guint32 timestamp);
void meta_check_end_modal (MetaScreen *screen);
#endif /* META_COMPOSITOR_PRIVATE_H */
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,31 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2007 Iain Holmes
* Based on xcompmgr - (c) 2003 Keith Packard
* xfwm4 - (c) 2005-2007 Olivier Fourdan
*
* 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.
*/
#ifndef META_COMPOSITOR_XRENDER_H_
#define META_COMPOSITOR_XRENDER_H_
#include "types.h"
MetaCompositor *meta_compositor_xrender_new (MetaDisplay *display);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,78 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (c) 2008 Intel Corp.
*
* Author: Tomas Frydrych <tf@linux.intel.com>
*
* 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.
*/
#ifndef META_PLUGIN_MANAGER_H_
#define META_PLUGIN_MANAGER_H_
#include "types.h"
#include "screen.h"
#define META_PLUGIN_FROM_MANAGER_
#include "meta-plugin.h"
#undef META_PLUGIN_FROM_MANAGER_
#define META_PLUGIN_MINIMIZE (1<<0)
#define META_PLUGIN_MAXIMIZE (1<<1)
#define META_PLUGIN_UNMAXIMIZE (1<<2)
#define META_PLUGIN_MAP (1<<3)
#define META_PLUGIN_DESTROY (1<<4)
#define META_PLUGIN_SWITCH_WORKSPACE (1<<5)
#define META_PLUGIN_ALL_EFFECTS (~0)
/**
* MetaPluginManager: (skip)
*
*/
typedef struct MetaPluginManager MetaPluginManager;
MetaPluginManager * meta_plugin_manager_get (MetaScreen *screen);
MetaPluginManager * meta_plugin_manager_get_default (void);
gboolean meta_plugin_manager_load (MetaPluginManager *mgr);
gboolean meta_plugin_manager_initialize (MetaPluginManager *plugin_mgr);
gboolean meta_plugin_manager_event_simple (MetaPluginManager *mgr,
MetaWindowActor *actor,
unsigned long event);
gboolean meta_plugin_manager_event_maximize (MetaPluginManager *mgr,
MetaWindowActor *actor,
unsigned long event,
gint target_x,
gint target_y,
gint target_width,
gint target_height);
void meta_plugin_manager_update_workspaces (MetaPluginManager *mgr);
void meta_plugin_manager_update_workspace (MetaPluginManager *mgr,
MetaWorkspace *w);
gboolean meta_plugin_manager_switch_workspace (MetaPluginManager *mgr,
gint from,
gint to,
MetaMotionDirection direction);
gboolean meta_plugin_manager_xevent_filter (MetaPluginManager *mgr,
XEvent *xev);
#endif

View File

@@ -1,607 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (c) 2008 Intel Corp.
*
* Author: Tomas Frydrych <tf@linux.intel.com>
*
* 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.
*/
#include "meta-plugin.h"
#include "screen.h"
#include "display.h"
#include <string.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/shape.h>
#include <clutter/x11/clutter-x11.h>
#include "compositor-private.h"
#include "meta-window-actor-private.h"
G_DEFINE_ABSTRACT_TYPE (MetaPlugin, meta_plugin, G_TYPE_OBJECT);
#define META_PLUGIN_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_PLUGIN, MetaPluginPrivate))
enum
{
PROP_0,
PROP_SCREEN,
PROP_PARAMS,
PROP_FEATURES,
PROP_DISABLED,
PROP_DEBUG_MODE,
};
struct _MetaPluginPrivate
{
MetaScreen *screen;
gchar *params;
gulong features;
gint running;
gboolean disabled : 1;
gboolean debug : 1;
};
static void
meta_plugin_dispose (GObject *object)
{
G_OBJECT_CLASS (meta_plugin_parent_class)->dispose (object);
}
static void
meta_plugin_finalize (GObject *object)
{
MetaPluginPrivate *priv = META_PLUGIN (object)->priv;
g_free (priv->params);
priv->params = NULL;
G_OBJECT_CLASS (meta_plugin_parent_class)->finalize (object);
}
static void
meta_plugin_parse_params (MetaPlugin *plugin)
{
char *p;
gulong features = 0;
MetaPluginPrivate *priv = plugin->priv;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
/*
* Feature flags: identify events that the plugin can handle; a plugin can
* handle one or more events.
*/
if (klass->minimize)
features |= META_PLUGIN_MINIMIZE;
if (klass->maximize)
features |= META_PLUGIN_MAXIMIZE;
if (klass->unmaximize)
features |= META_PLUGIN_UNMAXIMIZE;
if (klass->map)
features |= META_PLUGIN_MAP;
if (klass->destroy)
features |= META_PLUGIN_DESTROY;
if (klass->switch_workspace)
features |= META_PLUGIN_SWITCH_WORKSPACE;
if (priv->params)
{
gboolean debug = FALSE;
if ((p = strstr (priv->params, "disable:")))
{
gchar *d = g_strdup (p+8);
p = strchr (d, ';');
if (p)
*p = 0;
if (strstr (d, "minimize"))
features &= ~ META_PLUGIN_MINIMIZE;
if (strstr (d, "maximize"))
features &= ~ META_PLUGIN_MAXIMIZE;
if (strstr (d, "unmaximize"))
features &= ~ META_PLUGIN_UNMAXIMIZE;
if (strstr (d, "map"))
features &= ~ META_PLUGIN_MAP;
if (strstr (d, "destroy"))
features &= ~ META_PLUGIN_DESTROY;
if (strstr (d, "switch-workspace"))
features &= ~META_PLUGIN_SWITCH_WORKSPACE;
g_free (d);
}
if (strstr (priv->params, "debug"))
debug = TRUE;
if (debug != priv->debug)
{
priv->debug = debug;
g_object_notify (G_OBJECT (plugin), "debug-mode");
}
}
if (features != priv->features)
{
priv->features = features;
g_object_notify (G_OBJECT (plugin), "features");
}
}
static void
meta_plugin_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaPluginPrivate *priv = META_PLUGIN (object)->priv;
switch (prop_id)
{
case PROP_SCREEN:
priv->screen = g_value_get_object (value);
break;
case PROP_PARAMS:
priv->params = g_value_dup_string (value);
meta_plugin_parse_params (META_PLUGIN (object));
break;
case PROP_DISABLED:
priv->disabled = g_value_get_boolean (value);
break;
case PROP_DEBUG_MODE:
priv->debug = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_plugin_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaPluginPrivate *priv = META_PLUGIN (object)->priv;
switch (prop_id)
{
case PROP_SCREEN:
g_value_set_object (value, priv->screen);
break;
case PROP_PARAMS:
g_value_set_string (value, priv->params);
break;
case PROP_DISABLED:
g_value_set_boolean (value, priv->disabled);
break;
case PROP_DEBUG_MODE:
g_value_set_boolean (value, priv->debug);
break;
case PROP_FEATURES:
g_value_set_ulong (value, priv->features);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_plugin_class_init (MetaPluginClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = meta_plugin_finalize;
gobject_class->dispose = meta_plugin_dispose;
gobject_class->set_property = meta_plugin_set_property;
gobject_class->get_property = meta_plugin_get_property;
g_object_class_install_property (gobject_class,
PROP_SCREEN,
g_param_spec_object ("screen",
"MetaScreen",
"MetaScreen",
META_TYPE_SCREEN,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_PARAMS,
g_param_spec_string ("params",
"Parameters",
"Plugin Parameters",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_FEATURES,
g_param_spec_ulong ("features",
"Features",
"Plugin Features",
0 , G_MAXULONG, 0,
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_DISABLED,
g_param_spec_boolean ("disabled",
"Plugin disabled",
"Plugin disabled",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_DEBUG_MODE,
g_param_spec_boolean ("debug-mode",
"Debug Mode",
"Debug Mode",
FALSE,
G_PARAM_READABLE));
g_type_class_add_private (gobject_class, sizeof (MetaPluginPrivate));
}
static void
meta_plugin_init (MetaPlugin *self)
{
MetaPluginPrivate *priv;
self->priv = priv = META_PLUGIN_GET_PRIVATE (self);
}
gulong
meta_plugin_features (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return priv->features;
}
gboolean
meta_plugin_disabled (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return priv->disabled;
}
gboolean
meta_plugin_running (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return (priv->running > 0);
}
gboolean
meta_plugin_debug_mode (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return priv->debug;
}
const MetaPluginInfo *
meta_plugin_get_info (MetaPlugin *plugin)
{
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
if (klass && klass->plugin_info)
return klass->plugin_info (plugin);
return NULL;
}
ClutterActor *
meta_plugin_get_overlay_group (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return meta_get_overlay_group_for_screen (priv->screen);
}
ClutterActor *
meta_plugin_get_stage (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return meta_get_stage_for_screen (priv->screen);
}
ClutterActor *
meta_plugin_get_window_group (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return meta_get_window_group_for_screen (priv->screen);
}
/**
* _meta_plugin_effect_started:
* @plugin: the plugin
*
* Mark that an effect has started for the plugin. This is called
* internally by MetaPluginManager.
*/
void
_meta_plugin_effect_started (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
priv->running++;
}
void
meta_plugin_switch_workspace_completed (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
MetaScreen *screen = meta_plugin_get_screen (plugin);
if (priv->running-- < 0)
{
g_warning ("Error in running effect accounting, adjusting.");
priv->running = 0;
}
meta_switch_workspace_completed (screen);
}
static void
meta_plugin_window_effect_completed (MetaPlugin *plugin,
MetaWindowActor *actor,
unsigned long event)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
if (priv->running-- < 0)
{
g_warning ("Error in running effect accounting, adjusting.");
priv->running = 0;
}
if (!actor)
{
const MetaPluginInfo *info;
const gchar *name = NULL;
if (plugin && (info = meta_plugin_get_info (plugin)))
name = info->name;
g_warning ("Plugin [%s] passed NULL for actor!",
name ? name : "unknown");
}
meta_window_actor_effect_completed (actor, event);
}
void
meta_plugin_minimize_completed (MetaPlugin *plugin,
MetaWindowActor *actor)
{
meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_MINIMIZE);
}
void
meta_plugin_maximize_completed (MetaPlugin *plugin,
MetaWindowActor *actor)
{
meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_MAXIMIZE);
}
void
meta_plugin_unmaximize_completed (MetaPlugin *plugin,
MetaWindowActor *actor)
{
meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_UNMAXIMIZE);
}
void
meta_plugin_map_completed (MetaPlugin *plugin,
MetaWindowActor *actor)
{
meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_MAP);
}
void
meta_plugin_destroy_completed (MetaPlugin *plugin,
MetaWindowActor *actor)
{
meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_DESTROY);
}
void
meta_plugin_query_screen_size (MetaPlugin *plugin,
int *width,
int *height)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
meta_screen_get_size (priv->screen, width, height);
}
void
meta_plugin_set_stage_reactive (MetaPlugin *plugin,
gboolean reactive)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
MetaScreen *screen = priv->screen;
if (reactive)
meta_set_stage_input_region (screen, None);
else
meta_empty_stage_input_region (screen);
}
void
meta_plugin_set_stage_input_area (MetaPlugin *plugin,
gint x, gint y, gint width, gint height)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
MetaScreen *screen = priv->screen;
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdpy = meta_display_get_xdisplay (display);
XRectangle rect;
XserverRegion region;
rect.x = x;
rect.y = y;
rect.width = width;
rect.height = height;
region = XFixesCreateRegion (xdpy, &rect, 1);
meta_set_stage_input_region (screen, region);
XFixesDestroyRegion (xdpy, region);
}
void
meta_plugin_set_stage_input_region (MetaPlugin *plugin,
XserverRegion region)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
MetaScreen *screen = priv->screen;
meta_set_stage_input_region (screen, region);
}
/**
* meta_plugin_get_window_actors:
* @plugin: A #MetaPlugin
*
* This function returns all of the #MetaWindowActor objects referenced by Mutter, including
* override-redirect windows. The returned list is a snapshot of Mutter's current
* stacking order, with the topmost window last.
*
* The 'restacked' signal of #MetaScreen signals when this value has changed.
*
* Returns: (transfer none) (element-type MetaWindowActor): Windows in stacking order, topmost last
*/
GList *
meta_plugin_get_window_actors (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return meta_get_window_actors (priv->screen);
}
/**
* meta_plugin_begin_modal:
* @plugin: a #MetaPlugin
* @grab_window: the X window to grab the keyboard and mouse on
* @cursor: the cursor to use for the pointer grab, or None,
* to use the normal cursor for the grab window and
* its descendants.
* @options: flags that modify the behavior of the modal grab
* @timestamp: the timestamp used for establishing grabs
*
* This function is used to grab the keyboard and mouse for the exclusive
* use of the plugin. Correct operation requires that both the keyboard
* and mouse are grabbed, or thing will break. (In particular, other
* passive X grabs in Meta can trigger but not be handled by the normal
* keybinding handling code.) However, the plugin can establish the keyboard
* and/or mouse grabs ahead of time and pass in the
* %META_MODAL_POINTER_ALREADY_GRABBED and/or %META_MODAL_KEYBOARD_ALREADY_GRABBED
* options. This facility is provided for two reasons: first to allow using
* this function to establish modality after a passive grab, and second to
* allow using obscure features of XGrabPointer() and XGrabKeyboard() without
* having to add them to this API.
*
* Return value: whether we successfully grabbed the keyboard and
* mouse and made the plugin modal.
*/
gboolean
meta_plugin_begin_modal (MetaPlugin *plugin,
Window grab_window,
Cursor cursor,
MetaModalOptions options,
guint32 timestamp)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return meta_begin_modal_for_plugin (priv->screen, plugin,
grab_window, cursor, options, timestamp);
}
/**
* meta_plugin_end_modal
* @plugin: a #MetaPlugin
* @timestamp: the time used for releasing grabs
*
* Ends the modal operation begun with meta_plugin_begin_modal(). This
* ungrabs both the mouse and keyboard even when
* %META_MODAL_POINTER_ALREADY_GRABBED or
* %META_MODAL_KEYBOARD_ALREADY_GRABBED were provided as options
* when beginnning the modal operation.
*/
void
meta_plugin_end_modal (MetaPlugin *plugin,
guint32 timestamp)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
meta_end_modal_for_plugin (priv->screen, plugin, timestamp);
}
Display *
meta_plugin_get_xdisplay (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
MetaDisplay *display = meta_screen_get_display (priv->screen);
Display *xdpy = meta_display_get_xdisplay (display);
return xdpy;
}
/**
* meta_plugin_get_screen:
* @plugin: a #MetaPlugin
*
* Gets the #MetaScreen corresponding to a plugin. Each plugin instance
* is associated with exactly one screen; if Metacity is managing
* multiple screens, multiple plugin instances will be created.
*
* Return value: (transfer none): the #MetaScreen for the plugin
*/
MetaScreen *
meta_plugin_get_screen (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return priv->screen;
}

View File

@@ -1,635 +0,0 @@
/*
* shaped texture
*
* An actor to draw a texture clipped to a list of rectangles
*
* Authored By Neil Roberts <neil@linux.intel.com>
*
* Copyright (C) 2008 Intel Corporation
*
* 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.
*/
#include <config.h>
#include "meta-shaped-texture.h"
#include "meta-texture-tower.h"
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <string.h>
static void meta_shaped_texture_dispose (GObject *object);
static void meta_shaped_texture_finalize (GObject *object);
static void meta_shaped_texture_notify (GObject *object,
GParamSpec *pspec);
static void meta_shaped_texture_paint (ClutterActor *actor);
static void meta_shaped_texture_pick (ClutterActor *actor,
const ClutterColor *color);
static void meta_shaped_texture_update_area (ClutterX11TexturePixmap *texture,
int x,
int y,
int width,
int height);
static void meta_shaped_texture_dirty_mask (MetaShapedTexture *stex);
#ifdef HAVE_GLX_TEXTURE_PIXMAP
G_DEFINE_TYPE (MetaShapedTexture, meta_shaped_texture,
CLUTTER_GLX_TYPE_TEXTURE_PIXMAP);
#else /* HAVE_GLX_TEXTURE_PIXMAP */
G_DEFINE_TYPE (MetaShapedTexture, meta_shaped_texture,
CLUTTER_X11_TYPE_TEXTURE_PIXMAP);
#endif /* HAVE_GLX_TEXTURE_PIXMAP */
#define META_SHAPED_TEXTURE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_SHAPED_TEXTURE, \
MetaShapedTexturePrivate))
struct _MetaShapedTexturePrivate
{
MetaTextureTower *paint_tower;
CoglHandle mask_texture;
CoglHandle material;
CoglHandle material_unshaped;
cairo_region_t *clip_region;
guint mask_width, mask_height;
GArray *rectangles;
guint create_mipmaps : 1;
};
static void
meta_shaped_texture_class_init (MetaShapedTextureClass *klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
ClutterActorClass *actor_class = (ClutterActorClass *) klass;
ClutterX11TexturePixmapClass *x11_texture_class = (ClutterX11TexturePixmapClass *) klass;
gobject_class->dispose = meta_shaped_texture_dispose;
gobject_class->finalize = meta_shaped_texture_finalize;
gobject_class->notify = meta_shaped_texture_notify;
actor_class->paint = meta_shaped_texture_paint;
actor_class->pick = meta_shaped_texture_pick;
x11_texture_class->update_area = meta_shaped_texture_update_area;
g_type_class_add_private (klass, sizeof (MetaShapedTexturePrivate));
}
static void
meta_shaped_texture_init (MetaShapedTexture *self)
{
MetaShapedTexturePrivate *priv;
priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self);
priv->rectangles = g_array_new (FALSE, FALSE, sizeof (XRectangle));
priv->paint_tower = meta_texture_tower_new ();
priv->mask_texture = COGL_INVALID_HANDLE;
priv->create_mipmaps = TRUE;
}
static void
meta_shaped_texture_dispose (GObject *object)
{
MetaShapedTexture *self = (MetaShapedTexture *) object;
MetaShapedTexturePrivate *priv = self->priv;
if (priv->paint_tower)
meta_texture_tower_free (priv->paint_tower);
priv->paint_tower = NULL;
meta_shaped_texture_dirty_mask (self);
if (priv->material != COGL_INVALID_HANDLE)
{
cogl_handle_unref (priv->material);
priv->material = COGL_INVALID_HANDLE;
}
if (priv->material_unshaped != COGL_INVALID_HANDLE)
{
cogl_handle_unref (priv->material_unshaped);
priv->material_unshaped = COGL_INVALID_HANDLE;
}
meta_shaped_texture_set_clip_region (self, NULL);
G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object);
}
static void
meta_shaped_texture_finalize (GObject *object)
{
MetaShapedTexture *self = (MetaShapedTexture *) object;
MetaShapedTexturePrivate *priv = self->priv;
g_array_free (priv->rectangles, TRUE);
G_OBJECT_CLASS (meta_shaped_texture_parent_class)->finalize (object);
}
static void
meta_shaped_texture_notify (GObject *object,
GParamSpec *pspec)
{
if (G_OBJECT_CLASS (meta_shaped_texture_parent_class)->notify)
G_OBJECT_CLASS (meta_shaped_texture_parent_class)->notify (object, pspec);
/* It seems like we could just do this out of update_area(), but unfortunately,
* clutter_glx_texture_pixmap() doesn't call through the vtable on the
* initial update_area, so we need to look for changes to the texture
* explicitly.
*/
if (strcmp (pspec->name, "cogl-texture") == 0)
{
MetaShapedTexture *stex = (MetaShapedTexture *) object;
MetaShapedTexturePrivate *priv = stex->priv;
meta_shaped_texture_clear (stex);
if (priv->create_mipmaps)
meta_texture_tower_set_base_texture (priv->paint_tower,
clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex)));
}
}
static void
meta_shaped_texture_dirty_mask (MetaShapedTexture *stex)
{
MetaShapedTexturePrivate *priv = stex->priv;
if (priv->mask_texture != COGL_INVALID_HANDLE)
{
GLuint mask_gl_tex;
GLenum mask_gl_target;
cogl_texture_get_gl_texture (priv->mask_texture,
&mask_gl_tex, &mask_gl_target);
if (mask_gl_target == GL_TEXTURE_RECTANGLE_ARB)
glDeleteTextures (1, &mask_gl_tex);
cogl_handle_unref (priv->mask_texture);
priv->mask_texture = COGL_INVALID_HANDLE;
if (priv->material != COGL_INVALID_HANDLE)
cogl_material_set_layer (priv->material, 1, COGL_INVALID_HANDLE);
}
}
static void
meta_shaped_texture_ensure_mask (MetaShapedTexture *stex)
{
MetaShapedTexturePrivate *priv = stex->priv;
CoglHandle paint_tex;
guint tex_width, tex_height;
paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex));
if (paint_tex == COGL_INVALID_HANDLE)
return;
tex_width = cogl_texture_get_width (paint_tex);
tex_height = cogl_texture_get_height (paint_tex);
/* If the mask texture we have was created for a different size then
recreate it */
if (priv->mask_texture != COGL_INVALID_HANDLE
&& (priv->mask_width != tex_width || priv->mask_height != tex_height))
meta_shaped_texture_dirty_mask (stex);
/* If we don't have a mask texture yet then create one */
if (priv->mask_texture == COGL_INVALID_HANDLE)
{
guchar *mask_data;
const XRectangle *rect;
GLenum paint_gl_target;
/* Create data for an empty image */
mask_data = g_malloc0 (tex_width * tex_height);
/* Cut out a hole for each rectangle */
for (rect = (XRectangle *) priv->rectangles->data
+ priv->rectangles->len;
rect-- > (XRectangle *) priv->rectangles->data;)
{
gint x1 = rect->x, x2 = x1 + rect->width;
gint y1 = rect->y, y2 = y1 + rect->height;
guchar *p;
/* Clip the rectangle to the size of the texture */
x1 = CLAMP (x1, 0, (gint) tex_width - 1);
x2 = CLAMP (x2, x1, (gint) tex_width);
y1 = CLAMP (y1, 0, (gint) tex_height - 1);
y2 = CLAMP (y2, y1, (gint) tex_height);
/* Fill the rectangle */
for (p = mask_data + y1 * tex_width + x1;
y1 < y2;
y1++, p += tex_width)
memset (p, 255, x2 - x1);
}
cogl_texture_get_gl_texture (paint_tex, NULL, &paint_gl_target);
if (paint_gl_target == GL_TEXTURE_RECTANGLE_ARB)
{
GLuint tex;
glGenTextures (1, &tex);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, tex);
glPixelStorei (GL_UNPACK_ROW_LENGTH, tex_width);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0,
GL_ALPHA, tex_width, tex_height,
0, GL_ALPHA, GL_UNSIGNED_BYTE, mask_data);
priv->mask_texture
= cogl_texture_new_from_foreign (tex,
GL_TEXTURE_RECTANGLE_ARB,
tex_width, tex_height,
0, 0,
COGL_PIXEL_FORMAT_A_8);
}
else
priv->mask_texture = cogl_texture_new_from_data (tex_width, tex_height,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_A_8,
COGL_PIXEL_FORMAT_ANY,
tex_width,
mask_data);
g_free (mask_data);
priv->mask_width = tex_width;
priv->mask_height = tex_height;
}
}
static void
meta_shaped_texture_paint (ClutterActor *actor)
{
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
MetaShapedTexturePrivate *priv = stex->priv;
CoglHandle paint_tex;
guint tex_width, tex_height;
ClutterActorBox alloc;
static CoglHandle material_template = COGL_INVALID_HANDLE;
static CoglHandle material_unshaped_template = COGL_INVALID_HANDLE;
CoglHandle material;
if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
return;
if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
clutter_actor_realize (CLUTTER_ACTOR (stex));
/* The GL EXT_texture_from_pixmap extension does allow for it to be
* used together with SGIS_generate_mipmap, however this is very
* rarely supported. Also, even when it is supported there
* are distinct performance implications from:
*
* - Updating mipmaps that we don't need
* - Having to reallocate pixmaps on the server into larger buffers
*
* So, we just unconditionally use our mipmap emulation code. If we
* wanted to use SGIS_generate_mipmap, we'd have to query COGL to
* see if it was supported (no API currently), and then if and only
* if that was the case, set the clutter texture quality to HIGH.
* Setting the texture quality to high without SGIS_generate_mipmap
* support for TFP textures will result in fallbacks to XGetImage.
*/
if (priv->create_mipmaps)
paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower);
else
paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex));
if (paint_tex == COGL_INVALID_HANDLE)
return;
tex_width = cogl_texture_get_width (paint_tex);
tex_height = cogl_texture_get_height (paint_tex);
if (tex_width == 0 || tex_height == 0) /* no contents yet */
return;
if (priv->rectangles->len < 1)
{
/* If there are no rectangles use a single-layer texture */
if (priv->material_unshaped == COGL_INVALID_HANDLE)
{
if (G_UNLIKELY (material_unshaped_template == COGL_INVALID_HANDLE))
material_unshaped_template = cogl_material_new ();
priv->material_unshaped = cogl_material_copy (material_unshaped_template);
}
material = priv->material_unshaped;
}
else
{
meta_shaped_texture_ensure_mask (stex);
if (priv->material == COGL_INVALID_HANDLE)
{
if (G_UNLIKELY (material_template == COGL_INVALID_HANDLE))
{
material_template = cogl_material_new ();
cogl_material_set_layer_combine (material_template, 1,
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
NULL);
}
priv->material = cogl_material_copy (material_template);
}
material = priv->material;
cogl_material_set_layer (material, 1, priv->mask_texture);
}
cogl_material_set_layer (material, 0, paint_tex);
{
CoglColor color;
guchar opacity = clutter_actor_get_paint_opacity (actor);
cogl_color_set_from_4ub (&color, opacity, opacity, opacity, opacity);
cogl_material_set_color (material, &color);
}
cogl_set_source (material);
clutter_actor_get_allocation_box (actor, &alloc);
if (priv->clip_region)
{
int n_rects;
int i;
/* Limit to how many separate rectangles we'll draw; beyond this just
* fall back and draw the whole thing */
# define MAX_RECTS 16
n_rects = cairo_region_num_rectangles (priv->clip_region);
if (n_rects <= MAX_RECTS)
{
float coords[8];
float x1, y1, x2, y2;
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (priv->clip_region, i, &rect);
x1 = rect.x;
y1 = rect.y;
x2 = rect.x + rect.width;
y2 = rect.y + rect.height;
coords[0] = rect.x / (alloc.x2 - alloc.x1);
coords[1] = rect.y / (alloc.y2 - alloc.y1);
coords[2] = (rect.x + rect.width) / (alloc.x2 - alloc.x1);
coords[3] = (rect.y + rect.height) / (alloc.y2 - alloc.y1);
coords[4] = coords[0];
coords[5] = coords[1];
coords[6] = coords[2];
coords[7] = coords[3];
cogl_rectangle_with_multitexture_coords (x1, y1, x2, y2,
&coords[0], 8);
}
return;
}
}
cogl_rectangle (0, 0,
alloc.x2 - alloc.x1,
alloc.y2 - alloc.y1);
}
static void
meta_shaped_texture_pick (ClutterActor *actor,
const ClutterColor *color)
{
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
MetaShapedTexturePrivate *priv = stex->priv;
/* If there are no rectangles then use the regular pick */
if (priv->rectangles->len < 1)
CLUTTER_ACTOR_CLASS (meta_shaped_texture_parent_class)
->pick (actor, color);
else if (clutter_actor_should_pick_paint (actor))
{
CoglHandle paint_tex;
ClutterActorBox alloc;
guint tex_width, tex_height;
paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex));
if (paint_tex == COGL_INVALID_HANDLE)
return;
tex_width = cogl_texture_get_width (paint_tex);
tex_height = cogl_texture_get_height (paint_tex);
if (tex_width == 0 || tex_height == 0) /* no contents yet */
return;
meta_shaped_texture_ensure_mask (stex);
cogl_set_source_color4ub (color->red, color->green, color->blue,
color->alpha);
clutter_actor_get_allocation_box (actor, &alloc);
/* Paint the mask rectangle in the given color */
cogl_set_source_texture (priv->mask_texture);
cogl_rectangle_with_texture_coords (0, 0,
alloc.x2 - alloc.x1,
alloc.y2 - alloc.y1,
0, 0, 1, 1);
}
}
static void
meta_shaped_texture_update_area (ClutterX11TexturePixmap *texture,
int x,
int y,
int width,
int height)
{
MetaShapedTexture *stex = (MetaShapedTexture *) texture;
MetaShapedTexturePrivate *priv = stex->priv;
CLUTTER_X11_TEXTURE_PIXMAP_CLASS (meta_shaped_texture_parent_class)->update_area (texture,
x, y, width, height);
meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
}
ClutterActor *
meta_shaped_texture_new (void)
{
ClutterActor *self = g_object_new (META_TYPE_SHAPED_TEXTURE, NULL);
return self;
}
void
meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
gboolean create_mipmaps)
{
MetaShapedTexturePrivate *priv;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
create_mipmaps = create_mipmaps != FALSE;
if (create_mipmaps != priv->create_mipmaps)
{
CoglHandle base_texture;
priv->create_mipmaps = create_mipmaps;
base_texture = create_mipmaps ?
clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex)) : COGL_INVALID_HANDLE;
meta_texture_tower_set_base_texture (priv->paint_tower, base_texture);
}
}
/* This is a workaround for deficiencies in the hack tower:
*
* When we call clutter_x11_texture_pixmap_set_pixmap(tp, None),
* ClutterX11TexturePixmap knows that it has to get rid of the old texture, but
* clutter_texture_set_cogl_texture(texture, COGL_INVALID_HANDLE) isn't allowed, so
* it grabs the material for the texture and manually sets the texture in it. This means
* that the "cogl-texture" property isn't notified, so we don't find out about it.
*
* And if we keep the CoglX11TexturePixmap around after the X pixmap is freed, then
* we'll trigger X errors when we actually try to free it.
*
* The only correct thing to do here is to change our code to derive
* from ClutterActor and get rid of the inheritance hack tower. Once
* we want to depend on Clutter-1.4 (which has CoglTexturePixmapX11),
* that will be very easy to do.
*/
void
meta_shaped_texture_clear (MetaShapedTexture *stex)
{
MetaShapedTexturePrivate *priv;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
meta_texture_tower_set_base_texture (priv->paint_tower, COGL_INVALID_HANDLE);
if (priv->material != COGL_INVALID_HANDLE)
cogl_material_set_layer (priv->material, 0, COGL_INVALID_HANDLE);
if (priv->material_unshaped != COGL_INVALID_HANDLE)
cogl_material_set_layer (priv->material_unshaped, 0, COGL_INVALID_HANDLE);
}
void
meta_shaped_texture_clear_rectangles (MetaShapedTexture *stex)
{
MetaShapedTexturePrivate *priv;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
g_array_set_size (priv->rectangles, 0);
meta_shaped_texture_dirty_mask (stex);
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
}
void
meta_shaped_texture_add_rectangle (MetaShapedTexture *stex,
const XRectangle *rect)
{
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
meta_shaped_texture_add_rectangles (stex, 1, rect);
}
void
meta_shaped_texture_add_rectangles (MetaShapedTexture *stex,
size_t num_rects,
const XRectangle *rects)
{
MetaShapedTexturePrivate *priv;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
g_array_append_vals (priv->rectangles, rects, num_rects);
meta_shaped_texture_dirty_mask (stex);
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
}
/**
* meta_shaped_texture_set_clip_region:
* @frame: a #TidyTextureframe
* @clip_region: (transfer full): the region of the texture that
* is visible and should be painted. OWNERSHIP IS ASSUMED BY
* THE FUNCTION (for efficiency to avoid a copy.)
*
* Provides a hint to the texture about what areas of the texture
* are not completely obscured and thus need to be painted. This
* is an optimization and is not supposed to have any effect on
* the output.
*
* Typically a parent container will set the clip region before
* painting its children, and then unset it afterwards.
*/
void
meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
cairo_region_t *clip_region)
{
MetaShapedTexturePrivate *priv;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
if (priv->clip_region)
{
cairo_region_destroy (priv->clip_region);
priv->clip_region = NULL;
}
priv->clip_region = clip_region;
}

View File

@@ -1,92 +0,0 @@
/*
* shaped texture
*
* An actor to draw a texture clipped to a list of rectangles
*
* Authored By Neil Roberts <neil@linux.intel.com>
*
* Copyright (C) 2008 Intel Corporation
*
* 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.
*/
#ifndef __META_SHAPED_TEXTURE_H__
#define __META_SHAPED_TEXTURE_H__
#include <config.h>
#include <clutter/clutter.h>
#ifdef HAVE_GLX_TEXTURE_PIXMAP
#include <clutter/glx/clutter-glx.h>
#endif /* HAVE_GLX_TEXTURE_PIXMAP */
G_BEGIN_DECLS
#define META_TYPE_SHAPED_TEXTURE (meta_shaped_texture_get_type())
#define META_SHAPED_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),META_TYPE_SHAPED_TEXTURE, MetaShapedTexture))
#define META_SHAPED_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SHAPED_TEXTURE, MetaShapedTextureClass))
#define META_IS_SHAPED_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SHAPED_TEXTURE))
#define META_IS_SHAPED_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SHAPED_TEXTURE))
#define META_SHAPED_TEXTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SHAPED_TEXTURE, MetaShapedTextureClass))
typedef struct _MetaShapedTexture MetaShapedTexture;
typedef struct _MetaShapedTextureClass MetaShapedTextureClass;
typedef struct _MetaShapedTexturePrivate MetaShapedTexturePrivate;
struct _MetaShapedTextureClass
{
#ifdef HAVE_GLX_TEXTURE_PIXMAP
ClutterGLXTexturePixmapClass parent_class;
#else
ClutterX11TexturePixmapClass parent_class;
#endif
};
struct _MetaShapedTexture
{
#ifdef HAVE_GLX_TEXTURE_PIXMAP
ClutterGLXTexturePixmap parent;
#else
ClutterX11TexturePixmap parent;
#endif
MetaShapedTexturePrivate *priv;
};
GType meta_shaped_texture_get_type (void) G_GNUC_CONST;
ClutterActor *meta_shaped_texture_new (void);
void meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
gboolean create_mipmaps);
void meta_shaped_texture_clear (MetaShapedTexture *stex);
void meta_shaped_texture_clear_rectangles (MetaShapedTexture *stex);
void meta_shaped_texture_add_rectangle (MetaShapedTexture *stex,
const XRectangle *rect);
void meta_shaped_texture_add_rectangles (MetaShapedTexture *stex,
size_t num_rects,
const XRectangle *rects);
/* Assumes ownership of clip_region */
void meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
cairo_region_t *clip_region);
G_END_DECLS
#endif /* __META_SHAPED_TEXTURE_H__ */

View File

@@ -1,654 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* MetaTextureTower
*
* Mipmap emulation by creation of scaled down images
*
* Copyright (C) 2009 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <math.h>
#include <string.h>
#include "meta-texture-tower.h"
#ifndef M_LOG2E
#define M_LOG2E 1.4426950408889634074
#endif
#define MAX_TEXTURE_LEVELS 12
/* If the texture format in memory doesn't match this, then Mesa
* will do the conversion, so things will still work, but it might
* be slow depending on how efficient Mesa is. These should be the
* native formats unless the display is 16bpp. If conversions
* here are a bottleneck, investigate whether we are converting when
* storing window data *into* the texture before adding extra code
* to handle multiple texture formats.
*/
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define TEXTURE_FORMAT COGL_PIXEL_FORMAT_BGRA_8888_PRE
#else
#define TEXTURE_FORMAT COGL_PIXEL_FORMAT_ARGB_8888_PRE
#endif
typedef struct
{
guint16 x1;
guint16 y1;
guint16 x2;
guint16 y2;
} Box;
struct _MetaTextureTower
{
int n_levels;
CoglHandle textures[MAX_TEXTURE_LEVELS];
CoglHandle fbos[MAX_TEXTURE_LEVELS];
Box invalid[MAX_TEXTURE_LEVELS];
};
/**
* meta_texture_tower_new:
*
* Creates a new texture tower. The base texture has to be set with
* meta_texture_tower_set_base_texture() before use.
*
* Return value: the new texture tower. Free with meta_texture_tower_free()
*/
MetaTextureTower *
meta_texture_tower_new (void)
{
MetaTextureTower *tower;
tower = g_slice_new0 (MetaTextureTower);
return tower;
}
/**
* meta_texture_tower_free:
* @tower: a #MetaTextureTower
*
* Frees a texture tower created with meta_texture_tower_new().
*/
void
meta_texture_tower_free (MetaTextureTower *tower)
{
g_return_if_fail (tower != NULL);
meta_texture_tower_set_base_texture (tower, COGL_INVALID_HANDLE);
g_slice_free (MetaTextureTower, tower);
}
static gboolean
texture_is_rectangle (CoglHandle texture)
{
GLuint gl_tex;
GLenum gl_target;
cogl_texture_get_gl_texture (texture, &gl_tex, &gl_target);
return gl_target == GL_TEXTURE_RECTANGLE_ARB;
}
static void
free_texture (CoglHandle texture)
{
GLuint gl_tex;
GLenum gl_target;
cogl_texture_get_gl_texture (texture, &gl_tex, &gl_target);
if (gl_target == GL_TEXTURE_RECTANGLE_ARB)
glDeleteTextures (1, &gl_tex);
cogl_handle_unref (texture);
}
/**
* meta_texture_tower_update_area:
* @tower: a MetaTextureTower
* @texture: the new texture used as a base for scaled down versions
*
* Sets the base texture that is the scaled texture that the
* scaled textures of the tower are derived from. The texture itself
* will be used as level 0 of the tower and will be referenced until
* unset or until the tower is freed.
*/
void
meta_texture_tower_set_base_texture (MetaTextureTower *tower,
CoglHandle texture)
{
int i;
g_return_if_fail (tower != NULL);
if (texture == tower->textures[0])
return;
if (tower->textures[0] != COGL_INVALID_HANDLE)
{
for (i = 1; i < tower->n_levels; i++)
{
if (tower->textures[i] != COGL_INVALID_HANDLE)
{
free_texture (tower->textures[i]);
tower->textures[i] = COGL_INVALID_HANDLE;
}
if (tower->fbos[i] != COGL_INVALID_HANDLE)
{
cogl_handle_unref (tower->fbos[i]);
tower->fbos[i] = COGL_INVALID_HANDLE;
}
}
cogl_handle_unref (tower->textures[0]);
}
tower->textures[0] = texture;
if (tower->textures[0] != COGL_INVALID_HANDLE)
{
int width, height;
cogl_handle_ref (tower->textures[0]);
width = cogl_texture_get_width (tower->textures[0]);
height = cogl_texture_get_height (tower->textures[0]);
tower->n_levels = 1 + MAX ((int)(M_LOG2E * log (width)), (int)(M_LOG2E * log (height)));
tower->n_levels = MIN(tower->n_levels, MAX_TEXTURE_LEVELS);
meta_texture_tower_update_area (tower, 0, 0, width, height);
}
else
{
tower->n_levels = 0;
}
}
/**
* meta_texture_tower_update_area:
* @tower: a MetaTextureTower
* @x: X coordinate of upper left of rectangle that changed
* @y: Y coordinate of upper left of rectangle that changed
* @width: width of rectangle that changed
* @height: height rectangle that changed
*
* Mark a region of the base texture as having changed; the next
* time a scaled down version of the base texture is retrieved,
* the appropriate area of the scaled down texture will be updated.
*/
void
meta_texture_tower_update_area (MetaTextureTower *tower,
int x,
int y,
int width,
int height)
{
int texture_width, texture_height;
Box invalid;
int i;
g_return_if_fail (tower != NULL);
texture_width = cogl_texture_get_width (tower->textures[0]);
texture_height = cogl_texture_get_height (tower->textures[0]);
invalid.x1 = x;
invalid.y1 = y;
invalid.x2 = x + width;
invalid.y2 = y + height;
for (i = 1; i < tower->n_levels; i++)
{
texture_width = MAX (1, texture_width / 2);
texture_height = MAX (1, texture_height / 2);
invalid.x1 = invalid.x1 / 2;
invalid.y1 = invalid.y1 / 2;
invalid.x2 = MIN (texture_width, (invalid.x2 + 1) / 2);
invalid.y2 = MIN (texture_height, (invalid.y2 + 1) / 2);
if (tower->invalid[i].x1 == tower->invalid[i].x2 ||
tower->invalid[i].y1 == tower->invalid[i].y2)
{
tower->invalid[i] = invalid;
}
else
{
tower->invalid[i].x1 = MIN (tower->invalid[i].x1, invalid.x1);
tower->invalid[i].y1 = MIN (tower->invalid[i].y1, invalid.y1);
tower->invalid[i].x2 = MAX (tower->invalid[i].x2, invalid.x2);
tower->invalid[i].y2 = MAX (tower->invalid[i].y2, invalid.y2);
}
}
}
/* It generally looks worse if we scale up a window texture by even a
* small amount than if we scale it down using bilinear filtering, so
* we always pick the *larger* adjacent level. */
#define LOD_BIAS (-0.49)
/* This determines the appropriate level of detail to use when drawing the
* texture, in a way that corresponds to what the GL specification does
* when mip-mapping. This is probably fancier and slower than what we need,
* but we do the computation only once each time we paint a window, and
* its easier to just use the equations from the specification than to
* come up with something simpler.
*
* If window is being painted at an angle from the viewer, then we have to
* pick a point in the texture; we use the middle of the texture (which is
* why the width/height are passed in.) This is not the normal case for
* Meta.
*/
static int
get_paint_level (int width, int height)
{
CoglMatrix projection, modelview, pm;
float v[4];
double viewport_width, viewport_height;
double u0, v0;
double xc, yc, wc;
double dxdu_, dxdv_, dydu_, dydv_;
double det_, det_sq;
double rho_sq;
double lambda;
/* See
* http://www.opengl.org/registry/doc/glspec32.core.20090803.pdf
* Section 3.8.9, p. 1.6.2. Here we have
*
* u(x,y) = x_o;
* v(x,y) = y_o;
*
* Since we are mapping 1:1 from object coordinates into pixel
* texture coordinates, the clip coordinates are:
*
* (x_c) (x_o) (u)
* (y_c) = (M_projection)(M_modelview) (y_o) = (PM) (v)
* (z_c) (z_o) (0)
* (w_c) (w_o) (1)
*/
cogl_get_projection_matrix (&projection);
cogl_get_modelview_matrix (&modelview);
cogl_matrix_multiply (&pm, &projection, &modelview);
cogl_get_viewport (v);
viewport_width = v[2];
viewport_height = v[3];
u0 = width / 2.;
v0 = height / 2.;
xc = pm.xx * u0 + pm.xy * v0 + pm.xw;
yc = pm.yx * u0 + pm.yy * v0 + pm.yw;
wc = pm.wx * u0 + pm.wy * v0 + pm.ww;
/* We'll simplify the equations below for a bit of micro-optimization.
* The commented out code is the unsimplified version.
// Partial derivates of window coordinates:
//
// x_w = 0.5 * viewport_width * x_c / w_c + viewport_center_x
// y_w = 0.5 * viewport_height * y_c / w_c + viewport_center_y
//
// with respect to u, v, using
// d(a/b)/dx = da/dx * (1/b) - a * db/dx / (b^2)
dxdu = 0.5 * viewport_width * (pm.xx - pm.wx * (xc/wc)) / wc;
dxdv = 0.5 * viewport_width * (pm.xy - pm.wy * (xc/wc)) / wc;
dydu = 0.5 * viewport_height * (pm.yx - pm.wx * (yc/wc)) / wc;
dydv = 0.5 * viewport_height * (pm.yy - pm.wy * (yc/wc)) / wc;
// Compute the inverse partials as the matrix inverse
det = dxdu * dydv - dxdv * dydu;
dudx = dydv / det;
dudy = - dxdv / det;
dvdx = - dydu / det;
dvdy = dvdu / det;
// Scale factor; maximum of the distance in texels for a change of 1 pixel
// in the X direction or 1 pixel in the Y direction
rho = MAX (sqrt (dudx * dudx + dvdx * dvdx), sqrt(dudy * dudy + dvdy * dvdy));
// Level of detail
lambda = log2 (rho) + LOD_BIAS;
*/
/* dxdu * wc, etc */
dxdu_ = 0.5 * viewport_width * (pm.xx - pm.wx * (xc/wc));
dxdv_ = 0.5 * viewport_width * (pm.xy - pm.wy * (xc/wc));
dydu_ = 0.5 * viewport_height * (pm.yx - pm.wx * (yc/wc));
dydv_ = 0.5 * viewport_height * (pm.yy - pm.wy * (yc/wc));
/* det * wc^2 */
det_ = dxdu_ * dydv_ - dxdv_ * dydu_;
det_sq = det_ * det_;
if (det_sq == 0.0)
return -1;
/* (rho * det * wc)^2 */
rho_sq = MAX (dydv_ * dydv_ + dydu_ * dydu_, dxdv_ * dxdv_ + dxdu_ * dxdu_);
lambda = 0.5 * M_LOG2E * log (rho_sq * wc * wc / det_sq) + LOD_BIAS;
#if 0
g_print ("%g %g %g\n", 0.5 * viewport_width * pm.xx / pm.ww, 0.5 * viewport_height * pm.yy / pm.ww, lambda);
#endif
if (lambda <= 0.)
return 0;
else
return (int)(0.5 + lambda);
}
static gboolean
is_power_of_two (int x)
{
return (x & (x - 1)) == 0;
}
static void
texture_tower_create_texture (MetaTextureTower *tower,
int level,
int width,
int height)
{
if ((!is_power_of_two (width) || !is_power_of_two (height)) &&
texture_is_rectangle (tower->textures[level - 1]))
{
GLuint tex = 0;
glGenTextures (1, &tex);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, tex);
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0,
GL_RGBA, width,height,
#if TEXTURE_FORMAT == COGL_PIXEL_FORMAT_BGRA_8888_PRE
0, GL_BGRA, GL_UNSIGNED_BYTE,
#else /* assume big endian */
0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
#endif
NULL);
tower->textures[level] = cogl_texture_new_from_foreign (tex, GL_TEXTURE_RECTANGLE_ARB,
width, height,
0, 0,
TEXTURE_FORMAT);
}
else
{
tower->textures[level] = cogl_texture_new_with_size (width, height,
COGL_TEXTURE_NO_AUTO_MIPMAP,
TEXTURE_FORMAT);
}
tower->invalid[level].x1 = 0;
tower->invalid[level].y1 = 0;
tower->invalid[level].x2 = width;
tower->invalid[level].y2 = height;
}
static gboolean
texture_tower_revalidate_fbo (MetaTextureTower *tower,
int level)
{
CoglHandle source_texture = tower->textures[level - 1];
int source_texture_width = cogl_texture_get_width (source_texture);
int source_texture_height = cogl_texture_get_height (source_texture);
CoglHandle dest_texture = tower->textures[level];
int dest_texture_width = cogl_texture_get_width (dest_texture);
int dest_texture_height = cogl_texture_get_height (dest_texture);
Box *invalid = &tower->invalid[level];
CoglMatrix modelview;
if (tower->fbos[level] == COGL_INVALID_HANDLE)
{
/* Work around http://bugzilla.openedhand.com/show_bug.cgi?id=2110 */
cogl_flush();
tower->fbos[level] = cogl_offscreen_new_to_texture (dest_texture);
}
if (tower->fbos[level] == COGL_INVALID_HANDLE)
return FALSE;
cogl_push_framebuffer (tower->fbos[level]);
cogl_ortho (0, dest_texture_width, dest_texture_height, 0, -1., 1.);
cogl_matrix_init_identity (&modelview);
cogl_set_modelview_matrix (&modelview);
cogl_set_source_texture (tower->textures[level - 1]);
cogl_rectangle_with_texture_coords (invalid->x1, invalid->y1,
invalid->x2, invalid->y2,
(2. * invalid->x1) / source_texture_width,
(2. * invalid->y1) / source_texture_height,
(2. * invalid->x2) / source_texture_width,
(2. * invalid->y2) / source_texture_height);
cogl_pop_framebuffer ();
return TRUE;
}
static void
fill_copy (guchar *buf,
const guchar *source,
int width)
{
memcpy (buf, source, width * 4);
}
static void
fill_scale_down (guchar *buf,
const guchar *source,
int width)
{
while (width > 1)
{
buf[0] = (source[0] + source[4]) / 2;
buf[1] = (source[1] + source[5]) / 2;
buf[2] = (source[2] + source[6]) / 2;
buf[3] = (source[3] + source[7]) / 2;
buf += 4;
source += 8;
width -= 2;
}
if (width > 0)
{
buf[0] = source[0] / 2;
buf[1] = source[1] / 2;
buf[2] = source[2] / 2;
buf[3] = source[3] / 2;
}
}
static void
texture_tower_revalidate_client (MetaTextureTower *tower,
int level)
{
CoglHandle source_texture = tower->textures[level - 1];
int source_texture_width = cogl_texture_get_width (source_texture);
int source_texture_height = cogl_texture_get_height (source_texture);
guint source_rowstride;
guchar *source_data;
CoglHandle dest_texture = tower->textures[level];
int dest_texture_width = cogl_texture_get_width (dest_texture);
int dest_texture_height = cogl_texture_get_height (dest_texture);
int dest_x = tower->invalid[level].x1;
int dest_y = tower->invalid[level].y1;
int dest_width = tower->invalid[level].x2 - tower->invalid[level].x1;
int dest_height = tower->invalid[level].y2 - tower->invalid[level].y1;
guchar *dest_data;
guchar *source_tmp1 = NULL, *source_tmp2 = NULL;
int i, j;
source_rowstride = source_texture_width * 4;
source_data = g_malloc (source_texture_height * source_rowstride);
cogl_texture_get_data (source_texture, TEXTURE_FORMAT, source_rowstride,
source_data);
dest_data = g_malloc (dest_height * dest_width * 4);
if (dest_texture_height < source_texture_height)
{
source_tmp1 = g_malloc (dest_width * 4);
source_tmp2 = g_malloc (dest_width * 4);
}
for (i = 0; i < dest_height; i++)
{
guchar *dest_row = dest_data + i * dest_width * 4;
if (dest_texture_height < source_texture_height)
{
guchar *source1, *source2;
guchar *dest;
if (dest_texture_width < source_texture_width)
{
fill_scale_down (source_tmp1,
source_data + ((i + dest_y) * 2) * source_rowstride + dest_x * 2 * 4,
dest_width * 2);
fill_scale_down (source_tmp2,
source_data + ((i + dest_y) * 2 + 1) * source_rowstride + dest_x * 2 * 4,
dest_width * 2);
}
else
{
fill_copy (source_tmp1,
source_data + ((i + dest_y) * 2) * source_rowstride + dest_x * 4,
dest_width);
fill_copy (source_tmp2,
source_data + ((i + dest_y) * 2 + 1) * source_rowstride + dest_x * 4,
dest_width);
}
source1 = source_tmp1;
source2 = source_tmp2;
dest = dest_row;
for (j = 0; j < dest_width * 4; j++)
*(dest++) = (*(source1++) + *(source2++)) / 2;
}
else
{
if (dest_texture_width < source_texture_width)
fill_scale_down (dest_row,
source_data + (i + dest_y) * source_rowstride + dest_x * 2 * 4,
dest_width * 2);
else
fill_copy (dest_row,
source_data + (i + dest_y) * source_rowstride,
dest_width);
}
}
cogl_texture_set_region (dest_texture,
0, 0,
dest_x, dest_y,
dest_width, dest_height,
dest_width, dest_height,
TEXTURE_FORMAT,
4 * dest_width,
dest_data);
if (dest_height < source_texture_height)
{
g_free (source_tmp1);
g_free (source_tmp2);
}
g_free (source_data);
g_free (dest_data);
}
static void
texture_tower_revalidate (MetaTextureTower *tower,
int level)
{
if (!texture_tower_revalidate_fbo (tower, level))
texture_tower_revalidate_client (tower, level);
}
/**
* meta_texture_tower_get_paint_texture:
* @tower: a MetaTextureTower
*
* Gets the texture from the tower that best matches the current
* rendering scale. (On the assumption here the texture is going to
* be rendered with vertex coordinates that correspond to its
* size in pixels, so a 200x200 texture will be rendered on the
* rectangle (0, 0, 200, 200).
*
* Return value: the COGL texture handle to use for painting, or
* %COGL_INVALID_HANDLE if no base texture has yet been set.
*/
CoglHandle
meta_texture_tower_get_paint_texture (MetaTextureTower *tower)
{
int texture_width, texture_height;
int level;
g_return_val_if_fail (tower != NULL, COGL_INVALID_HANDLE);
if (tower->textures[0] == COGL_INVALID_HANDLE)
return COGL_INVALID_HANDLE;
texture_width = cogl_texture_get_width (tower->textures[0]);
texture_height = cogl_texture_get_height (tower->textures[0]);
level = get_paint_level(texture_width, texture_height);
if (level < 0) /* singular paint matrix, scaled to nothing */
return COGL_INVALID_HANDLE;
level = MIN (level, tower->n_levels - 1);
if (tower->textures[level] == COGL_INVALID_HANDLE ||
(tower->invalid[level].x2 != tower->invalid[level].x1 &&
tower->invalid[level].y2 != tower->invalid[level].y1))
{
int i;
for (i = 1; i <= level; i++)
{
/* Use "floor" convention here to be consistent with the NPOT texture extension */
texture_width = MAX (1, texture_width / 2);
texture_height = MAX (1, texture_height / 2);
if (tower->textures[i] == COGL_INVALID_HANDLE)
texture_tower_create_texture (tower, i, texture_width, texture_height);
}
for (i = 1; i <= level; i++)
{
if (tower->invalid[level].x2 != tower->invalid[level].x1 &&
tower->invalid[level].y2 != tower->invalid[level].y1)
texture_tower_revalidate (tower, i);
}
}
return tower->textures[level];
}

View File

@@ -1,69 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* MetaTextureTower
*
* Mipmap emulation by creation of scaled down images
*
* Copyright (C) 2009 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef __META_TEXTURE_TOWER_H__
#define __META_TEXTURE_TOWER_H__
#include <clutter/clutter.h>
G_BEGIN_DECLS
/**
* SECTION:MetaTextureTower
* @short_description: mipmap emulation by creation of scaled down images
*
* A #MetaTextureTower is used to get good looking scaled down images when
* we can't use the GL drivers mipmap support. There are two separate reasons
*
* - Some cards (including radeon cards <= r5xx) only support
* TEXTURE_RECTANGLE_ARB and not NPOT textures. Rectangular textures
* are defined not to support mipmapping.
* - Even when NPOT textures are available, the combination of NPOT
* textures, texture_from_pixmap, and mipmapping doesn't typically
* work, since the X server doesn't allocate pixmaps in the right
* layout for mipmapping.
*
* So, what we do is create the "mipmap" levels ourselves by successive
* power-of-two scaledowns, and when rendering pick the single texture
* that best matches the scale we are rendering at. (Since we aren't
* typically using perspective transforms, we'll frequently have a single
* scale for the entire texture.)
*/
typedef struct _MetaTextureTower MetaTextureTower;
MetaTextureTower *meta_texture_tower_new (void);
void meta_texture_tower_free (MetaTextureTower *tower);
void meta_texture_tower_set_base_texture (MetaTextureTower *tower,
CoglHandle texture);
void meta_texture_tower_update_area (MetaTextureTower *tower,
int x,
int y,
int width,
int height);
CoglHandle meta_texture_tower_get_paint_texture (MetaTextureTower *tower);
G_BEGIN_DECLS
#endif /* __META_TEXTURE_TOWER_H__ */

View File

@@ -1,51 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#ifndef META_WINDOW_ACTOR_PRIVATE_H
#define META_WINDOW_ACTOR_PRIVATE_H
#include <config.h>
#include <X11/extensions/Xdamage.h>
#include "compositor-mutter.h"
MetaWindowActor *meta_window_actor_new (MetaWindow *window);
void meta_window_actor_destroy (MetaWindowActor *self);
void meta_window_actor_show (MetaWindowActor *self,
MetaCompEffect effect);
void meta_window_actor_hide (MetaWindowActor *self,
MetaCompEffect effect);
void meta_window_actor_maximize (MetaWindowActor *self,
MetaRectangle *old_rect,
MetaRectangle *new_rect);
void meta_window_actor_unmaximize (MetaWindowActor *self,
MetaRectangle *old_rect,
MetaRectangle *new_rect);
void meta_window_actor_process_damage (MetaWindowActor *self,
XDamageNotifyEvent *event);
void meta_window_actor_pre_paint (MetaWindowActor *self);
gboolean meta_window_actor_effect_in_progress (MetaWindowActor *self);
void meta_window_actor_sync_actor_position (MetaWindowActor *self);
void meta_window_actor_sync_visibility (MetaWindowActor *self);
void meta_window_actor_update_shape (MetaWindowActor *self,
gboolean shaped);
void meta_window_actor_update_opacity (MetaWindowActor *self);
void meta_window_actor_mapped (MetaWindowActor *self);
void meta_window_actor_unmapped (MetaWindowActor *self);
cairo_region_t *meta_window_actor_get_obscured_region (MetaWindowActor *self);
void meta_window_actor_set_visible_region (MetaWindowActor *self,
cairo_region_t *visible_region);
void meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
cairo_region_t *beneath_region);
void meta_window_actor_reset_visible_regions (MetaWindowActor *self);
void meta_window_actor_effect_completed (MetaWindowActor *actor,
gulong event);
#endif /* META_WINDOW_ACTOR_PRIVATE_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,196 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#include <config.h>
#define _ISOC99_SOURCE /* for roundf */
#include <math.h>
#include "meta-window-actor-private.h"
#include "meta-window-group.h"
struct _MetaWindowGroupClass
{
ClutterGroupClass parent_class;
};
struct _MetaWindowGroup
{
ClutterGroup parent;
MetaScreen *screen;
};
G_DEFINE_TYPE (MetaWindowGroup, meta_window_group, CLUTTER_TYPE_GROUP);
/* We want to find out if the window is "close enough" to
* 1:1 transform. We do that by converting the transformed coordinates
* to 24.8 fixed-point before checking if they look right.
*/
static inline int
round_to_fixed (float x)
{
return roundf (x * 256);
}
/* We can only (easily) apply our logic for figuring out what a window
* obscures if is not transformed. This function does that check and
* as a side effect gets the position of the upper-left corner of the
* actors.
*
* (We actually could handle scaled and non-integrally positioned actors
* too as long as they weren't shaped - no filtering is done at the
* edges so a rectangle stays a rectangle. But the gain from that is
* small, especally since most of our windows are shaped. The simple
* case we handle here is the case that matters when the user is just
* using the desktop normally.)
*
* If we assume that the window group is untransformed (it better not
* be!) then we could also make this determination by checking directly
* if the actor itself is rotated, scaled, or at a non-integral position.
* However, the criterion for "close enough" in that case get trickier,
* since, for example, the allowed rotation depends on the size of
* actor. The approach we take here is to just require everything
* to be within 1/256th of a pixel.
*/
static gboolean
actor_is_untransformed (ClutterActor *actor,
int *x_origin,
int *y_origin)
{
gfloat widthf, heightf;
int width, height;
ClutterVertex verts[4];
int v0x, v0y, v1x, v1y, v2x, v2y, v3x, v3y;
int x, y;
clutter_actor_get_size (actor, &widthf, &heightf);
width = round_to_fixed (widthf); height = round_to_fixed (heightf);
clutter_actor_get_abs_allocation_vertices (actor, verts);
v0x = round_to_fixed (verts[0].x); v0y = round_to_fixed (verts[0].y);
v1x = round_to_fixed (verts[1].x); v1y = round_to_fixed (verts[1].y);
v2x = round_to_fixed (verts[2].x); v2y = round_to_fixed (verts[2].y);
v3x = round_to_fixed (verts[3].x); v3y = round_to_fixed (verts[3].y);
/* Using shifting for converting fixed => int, gets things right for
* negative values. / 256. wouldn't do the same
*/
x = v0x >> 8;
y = v0y >> 8;
/* At integral coordinates? */
if (x * 256 != v0x || y * 256 != v0y)
return FALSE;
/* Not scaled? */
if (v1x - v0x != width || v2y - v0y != height)
return FALSE;
/* Not rotated/skewed? */
if (v0x != v2x || v0y != v1y ||
v3x != v1x || v3y != v2y)
return FALSE;
*x_origin = x;
*y_origin = y;
return TRUE;
}
static void
meta_window_group_paint (ClutterActor *actor)
{
MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
cairo_region_t *visible_region;
cairo_rectangle_int_t screen_rect = { 0 };
GList *children, *l;
/* We walk the list from top to bottom (opposite of painting order),
* and subtract the opaque area of each window out of the visible
* region that we pass to the windows below.
*/
children = clutter_container_get_children (CLUTTER_CONTAINER (actor));
children = g_list_reverse (children);
/* Start off with the full screen area (for a multihead setup, we
* might want to use a more accurate union of the monitors to avoid
* painting in holes from mismatched monitor sizes. That's just an
* optimization, however.)
*/
meta_screen_get_size (window_group->screen, &screen_rect.width, &screen_rect.height);
visible_region = cairo_region_create_rectangle (&screen_rect);
for (l = children; l; l = l->next)
{
MetaWindowActor *window_actor;
gboolean x, y;
if (!META_IS_WINDOW_ACTOR (l->data) || !CLUTTER_ACTOR_IS_VISIBLE (l->data))
continue;
window_actor = l->data;
if (!actor_is_untransformed (CLUTTER_ACTOR (window_actor), &x, &y))
continue;
/* Temporarily move to the coordinate system of the actor */
cairo_region_translate (visible_region, - x, - y);
meta_window_actor_set_visible_region (window_actor, visible_region);
if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
{
cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
if (obscured_region)
cairo_region_subtract (visible_region, obscured_region);
}
meta_window_actor_set_visible_region_beneath (window_actor, visible_region);
cairo_region_translate (visible_region, x, y);
}
cairo_region_destroy (visible_region);
CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);
/* Now that we are done painting, unset the visible regions (they will
* mess up painting clones of our actors)
*/
for (l = children; l; l = l->next)
{
MetaWindowActor *window_actor;
if (!META_IS_WINDOW_ACTOR (l->data))
continue;
window_actor = l->data;
meta_window_actor_reset_visible_regions (window_actor);
}
g_list_free (children);
}
static void
meta_window_group_class_init (MetaWindowGroupClass *klass)
{
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
actor_class->paint = meta_window_group_paint;
}
static void
meta_window_group_init (MetaWindowGroup *window_group)
{
}
ClutterActor *
meta_window_group_new (MetaScreen *screen)
{
MetaWindowGroup *window_group;
window_group = g_object_new (META_TYPE_WINDOW_GROUP, NULL);
window_group->screen = screen;
return CLUTTER_ACTOR (window_group);
}

View File

@@ -1,52 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#ifndef META_WINDOW_GROUP_H
#define META_WINDOW_GROUP_H
#include <clutter/clutter.h>
#include "screen.h"
/**
* MetaWindowGroup:
*
* This class is a subclass of ClutterGroup with special handling for
* MetaWindowActor when painting the group. When we are painting a stack
* of 5-10 maximized windows, the standard bottom-to-top method of
* drawing every actor results in a tremendous amount of overdraw
* and can easily max out the available memory bandwidth on a low-end
* graphics chipset. It's even worse if window textures are being accessed
* over the AGP bus.
*
* The basic technique applied here is to do a pre-pass before painting
* where we walk window from top to bottom and compute the visible area
* at each step by subtracting out the windows above it. The visible
* area is passed to MetaWindowActor which uses it to clip the portion of
* the window which drawn and avoid redrawing the shadow if it is completely
* obscured.
*
* A caveat is that this is ineffective if applications are using ARGB
* visuals, since we have no way of knowing whether a window obscures
* the windows behind it or not. Alternate approaches using the depth
* or stencil buffer rather than client side regions might be able to
* handle alpha windows, but the combination of glAlphaFunc and stenciling
* tends not to be efficient except on newer cards. (And on newer cards
* we have lots of memory and bandwidth.)
*/
#define META_TYPE_WINDOW_GROUP (meta_window_group_get_type ())
#define META_WINDOW_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WINDOW_GROUP, MetaWindowGroup))
#define META_WINDOW_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WINDOW_GROUP, MetaWindowGroupClass))
#define META_IS_WINDOW_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_WINDOW_GROUP))
#define META_IS_WINDOW_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_WINDOW_GROUP))
#define META_WINDOW_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_WINDOW_GROUP, MetaWindowGroupClass))
typedef struct _MetaWindowGroup MetaWindowGroup;
typedef struct _MetaWindowGroupClass MetaWindowGroupClass;
typedef struct _MetaWindowGroupPrivate MetaWindowGroupPrivate;
GType meta_window_group_get_type (void);
ClutterActor *meta_window_group_new (MetaScreen *screen);
#endif /* META_WINDOW_GROUP_H */

File diff suppressed because it is too large Load Diff

View File

@@ -21,8 +21,8 @@
* 02111-1307, USA.
*/
#include "meta-plugin.h"
#include "meta-module.h"
#include "mutter-plugin.h"
#include "mutter-module.h"
#include <gmodule.h>
@@ -32,23 +32,23 @@ enum
PROP_PATH,
};
struct _MetaModulePrivate
struct _MutterModulePrivate
{
GModule *lib;
gchar *path;
GType plugin_type;
};
#define META_MODULE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_MODULE, MetaModulePrivate))
#define MUTTER_MODULE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUTTER_TYPE_MODULE, MutterModulePrivate))
G_DEFINE_TYPE (MetaModule, meta_module, G_TYPE_TYPE_MODULE);
G_DEFINE_TYPE (MutterModule, mutter_module, G_TYPE_TYPE_MODULE);
static gboolean
meta_module_load (GTypeModule *gmodule)
mutter_module_load (GTypeModule *gmodule)
{
MetaModulePrivate *priv = META_MODULE (gmodule)->priv;
MetaPluginVersion *info = NULL;
MutterModulePrivate *priv = MUTTER_MODULE (gmodule)->priv;
MutterPluginVersion *info = NULL;
GType (*register_type) (GTypeModule *) = NULL;
if (priv->lib && priv->plugin_type)
@@ -64,9 +64,9 @@ meta_module_load (GTypeModule *gmodule)
return FALSE;
}
if (g_module_symbol (priv->lib, "meta_plugin_version",
if (g_module_symbol (priv->lib, "mutter_plugin_version",
(gpointer *)(void *)&info) &&
g_module_symbol (priv->lib, "meta_plugin_register_type",
g_module_symbol (priv->lib, "mutter_plugin_register_type",
(gpointer *)(void *)&register_type) &&
info && register_type)
{
@@ -97,9 +97,9 @@ meta_module_load (GTypeModule *gmodule)
}
static void
meta_module_unload (GTypeModule *gmodule)
mutter_module_unload (GTypeModule *gmodule)
{
MetaModulePrivate *priv = META_MODULE (gmodule)->priv;
MutterModulePrivate *priv = MUTTER_MODULE (gmodule)->priv;
g_module_close (priv->lib);
@@ -108,29 +108,29 @@ meta_module_unload (GTypeModule *gmodule)
}
static void
meta_module_dispose (GObject *object)
mutter_module_dispose (GObject *object)
{
G_OBJECT_CLASS (meta_module_parent_class)->dispose (object);
G_OBJECT_CLASS (mutter_module_parent_class)->dispose (object);
}
static void
meta_module_finalize (GObject *object)
mutter_module_finalize (GObject *object)
{
MetaModulePrivate *priv = META_MODULE (object)->priv;
MutterModulePrivate *priv = MUTTER_MODULE (object)->priv;
g_free (priv->path);
priv->path = NULL;
G_OBJECT_CLASS (meta_module_parent_class)->finalize (object);
G_OBJECT_CLASS (mutter_module_parent_class)->finalize (object);
}
static void
meta_module_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
mutter_module_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaModulePrivate *priv = META_MODULE (object)->priv;
MutterModulePrivate *priv = MUTTER_MODULE (object)->priv;
switch (prop_id)
{
@@ -145,12 +145,12 @@ meta_module_set_property (GObject *object,
}
static void
meta_module_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
mutter_module_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaModulePrivate *priv = META_MODULE (object)->priv;
MutterModulePrivate *priv = MUTTER_MODULE (object)->priv;
switch (prop_id)
{
@@ -164,18 +164,18 @@ meta_module_get_property (GObject *object,
}
static void
meta_module_class_init (MetaModuleClass *klass)
mutter_module_class_init (MutterModuleClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GTypeModuleClass *gmodule_class = G_TYPE_MODULE_CLASS (klass);
gobject_class->finalize = meta_module_finalize;
gobject_class->dispose = meta_module_dispose;
gobject_class->set_property = meta_module_set_property;
gobject_class->get_property = meta_module_get_property;
gobject_class->finalize = mutter_module_finalize;
gobject_class->dispose = mutter_module_dispose;
gobject_class->set_property = mutter_module_set_property;
gobject_class->get_property = mutter_module_get_property;
gmodule_class->load = meta_module_load;
gmodule_class->unload = meta_module_unload;
gmodule_class->load = mutter_module_load;
gmodule_class->unload = mutter_module_unload;
g_object_class_install_property (gobject_class,
PROP_PATH,
@@ -186,22 +186,22 @@ meta_module_class_init (MetaModuleClass *klass)
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_type_class_add_private (gobject_class, sizeof (MetaModulePrivate));
g_type_class_add_private (gobject_class, sizeof (MutterModulePrivate));
}
static void
meta_module_init (MetaModule *self)
mutter_module_init (MutterModule *self)
{
MetaModulePrivate *priv;
MutterModulePrivate *priv;
self->priv = priv = META_MODULE_GET_PRIVATE (self);
self->priv = priv = MUTTER_MODULE_GET_PRIVATE (self);
}
GType
meta_module_get_plugin_type (MetaModule *module)
mutter_module_get_plugin_type (MutterModule *module)
{
MetaModulePrivate *priv = META_MODULE (module)->priv;
MutterModulePrivate *priv = MUTTER_MODULE (module)->priv;
return priv->plugin_type;
}

View File

@@ -21,37 +21,37 @@
* 02111-1307, USA.
*/
#ifndef META_MODULE_H_
#define META_MODULE_H_
#ifndef MUTTER_MODULE_H_
#define MUTTER_MODULE_H_
#include <glib-object.h>
#define META_TYPE_MODULE (meta_module_get_type ())
#define META_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MODULE, MetaModule))
#define META_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MODULE, MetaModuleClass))
#define META_IS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_MODULE_TYPE))
#define META_IS_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MODULE))
#define META_MODULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MODULE, MetaModuleClass))
#define MUTTER_TYPE_MODULE (mutter_module_get_type ())
#define MUTTER_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MUTTER_TYPE_MODULE, MutterModule))
#define MUTTER_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MUTTER_TYPE_MODULE, MutterModuleClass))
#define MUTTER_IS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MUTTER_MODULE_TYPE))
#define MUTTER_IS_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MUTTER_TYPE_MODULE))
#define MUTTER_MODULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MUTTER_TYPE_MODULE, MutterModuleClass))
typedef struct _MetaModule MetaModule;
typedef struct _MetaModuleClass MetaModuleClass;
typedef struct _MetaModulePrivate MetaModulePrivate;
typedef struct _MutterModule MutterModule;
typedef struct _MutterModuleClass MutterModuleClass;
typedef struct _MutterModulePrivate MutterModulePrivate;
struct _MetaModule
struct _MutterModule
{
GTypeModule parent;
MetaModulePrivate *priv;
MutterModulePrivate *priv;
};
struct _MetaModuleClass
struct _MutterModuleClass
{
GTypeModuleClass parent_class;
};
GType meta_module_get_type (void);
GType mutter_module_get_type (void);
GType meta_module_get_plugin_type (MetaModule *module);
GType mutter_module_get_plugin_type (MutterModule *module);
#endif

View File

@@ -22,55 +22,50 @@
*/
#include "config.h"
#include "compositor-private.h"
#include "meta-plugin-manager.h"
#include "mutter-plugin-manager.h"
#include "prefs.h"
#include "errors.h"
#include "workspace.h"
#include "meta-module.h"
#include "../core/window-private.h"
#include "mutter-module.h"
#include <string.h>
#include <clutter/x11/clutter-x11.h>
/*
* There is only one instace of each module per the process.
*/
static GHashTable *plugin_modules = NULL;
/*
* We have one "default plugin manager" that acts for the first screen,
* but also can be used before we open any screens, and additional
* plugin managers for each screen. (This is ugly. Probably we should
* have one plugin manager and only make the plugins per-screen.)
*/
static gboolean mutter_plugin_manager_reload (MutterPluginManager *plugin_mgr);
static MetaPluginManager *default_plugin_manager;
static gboolean meta_plugin_manager_reload (MetaPluginManager *plugin_mgr);
struct MetaPluginManager
struct MutterPluginManager
{
MetaScreen *screen;
GList /* MetaPlugin */ *plugins; /* TODO -- maybe use hash table */
GList *unload; /* Plugins that are disabled and pending unload */
GList /* MutterPluginPending */ *pending_plugin_modules; /* Plugins not yet fully loaded */
GList /* MutterPlugin */ *plugins; /* TODO -- maybe use hash table */
GList *unload; /* Plugins that are disabled and pending unload */
guint idle_unload_id;
};
typedef struct MutterPluginPending
{
MutterModule *module;
char *path;
char *params;
} MutterPluginPending;
/*
* Checks that the plugin is compatible with the WM and sets up the plugin
* struct.
*/
static MetaPlugin *
meta_plugin_load (MetaPluginManager *mgr,
MetaModule *module,
const gchar *params)
static MutterPlugin *
mutter_plugin_load (MutterPluginManager *mgr,
MutterModule *module,
const gchar *params)
{
MetaPlugin *plugin = NULL;
GType plugin_type = meta_module_get_plugin_type (module);
MutterPlugin *plugin = NULL;
GType plugin_type = mutter_module_get_plugin_type (module);
if (!plugin_type)
{
@@ -79,6 +74,7 @@ meta_plugin_load (MetaPluginManager *mgr,
}
plugin = g_object_new (plugin_type,
"screen", mgr->screen,
"params", params,
NULL);
@@ -91,9 +87,9 @@ meta_plugin_load (MetaPluginManager *mgr,
* removal later.
*/
static gboolean
meta_plugin_unload (MetaPlugin *plugin)
mutter_plugin_unload (MutterPlugin *plugin)
{
if (meta_plugin_running (plugin))
if (mutter_plugin_running (plugin))
{
g_object_set (plugin, "disabled", TRUE, NULL);
return FALSE;
@@ -109,16 +105,16 @@ meta_plugin_unload (MetaPlugin *plugin)
* pending for removal.
*/
static gboolean
meta_plugin_manager_idle_unload (MetaPluginManager *plugin_mgr)
mutter_plugin_manager_idle_unload (MutterPluginManager *plugin_mgr)
{
GList *l = plugin_mgr->unload;
gboolean dont_remove = TRUE;
while (l)
{
MetaPlugin *plugin = l->data;
MutterPlugin *plugin = l->data;
if (meta_plugin_unload (plugin))
if (mutter_plugin_unload (plugin))
{
/* Remove from list */
GList *p = l->prev;
@@ -154,23 +150,23 @@ meta_plugin_manager_idle_unload (MetaPluginManager *plugin_mgr)
* Unloads all plugins
*/
static void
meta_plugin_manager_unload (MetaPluginManager *plugin_mgr)
mutter_plugin_manager_unload (MutterPluginManager *plugin_mgr)
{
GList *plugins = plugin_mgr->plugins;
while (plugins)
{
MetaPlugin *plugin = plugins->data;
MutterPlugin *plugin = plugins->data;
/* If the plugin could not be removed, move it to the unload list */
if (!meta_plugin_unload (plugin))
if (!mutter_plugin_unload (plugin))
{
plugin_mgr->unload = g_list_prepend (plugin_mgr->unload, plugin);
if (!plugin_mgr->idle_unload_id)
{
plugin_mgr->idle_unload_id = g_idle_add ((GSourceFunc)
meta_plugin_manager_idle_unload,
mutter_plugin_manager_idle_unload,
plugin_mgr);
}
}
@@ -186,21 +182,21 @@ static void
prefs_changed_callback (MetaPreference pref,
void *data)
{
MetaPluginManager *plugin_mgr = data;
MutterPluginManager *plugin_mgr = data;
if (pref == META_PREF_CLUTTER_PLUGINS)
{
meta_plugin_manager_reload (plugin_mgr);
mutter_plugin_manager_reload (plugin_mgr);
}
}
static MetaModule *
meta_plugin_manager_get_module (const gchar *path)
static MutterModule *
mutter_plugin_manager_get_module (const gchar *path)
{
MetaModule *module = g_hash_table_lookup (plugin_modules, path);
MutterModule *module = g_hash_table_lookup (plugin_modules, path);
if (!module &&
(module = g_object_new (META_TYPE_MODULE, "path", path, NULL)))
(module = g_object_new (MUTTER_TYPE_MODULE, "path", path, NULL)))
{
g_hash_table_insert (plugin_modules, g_strdup (path), module);
}
@@ -212,7 +208,7 @@ meta_plugin_manager_get_module (const gchar *path)
* Loads all plugins listed in gconf registry.
*/
gboolean
meta_plugin_manager_load (MetaPluginManager *plugin_mgr)
mutter_plugin_manager_load (MutterPluginManager *plugin_mgr)
{
const gchar *dpath = MUTTER_PLUGIN_DIR "/";
GSList *plugins, *fallback = NULL;
@@ -237,7 +233,7 @@ meta_plugin_manager_load (MetaPluginManager *plugin_mgr)
if (plugin_string)
{
MetaModule *module;
MutterModule *module;
gchar *path;
params = strchr (plugin_string, ':');
@@ -253,7 +249,7 @@ meta_plugin_manager_load (MetaPluginManager *plugin_mgr)
else
path = g_strconcat (dpath, plugin_string, ".so", NULL);
module = meta_plugin_manager_get_module (path);
module = mutter_plugin_manager_get_module (path);
if (module)
{
@@ -270,14 +266,12 @@ meta_plugin_manager_load (MetaPluginManager *plugin_mgr)
if (use_succeeded)
{
MetaPlugin *plugin = meta_plugin_load (plugin_mgr, module, params);
if (plugin)
plugin_mgr->plugins = g_list_prepend (plugin_mgr->plugins, plugin);
else
g_warning ("Plugin load for [%s] failed", path);
g_type_module_unuse (G_TYPE_MODULE (module));
MutterPluginPending *pending = g_new0 (MutterPluginPending, 1);
pending->module = module;
pending->path = g_strdup (path);
pending->params = g_strdup (params);
plugin_mgr->pending_plugin_modules =
g_list_prepend (plugin_mgr->pending_plugin_modules, pending);
}
}
else
@@ -295,7 +289,7 @@ meta_plugin_manager_load (MetaPluginManager *plugin_mgr)
if (fallback)
g_slist_free (fallback);
if (plugin_mgr->plugins != NULL)
if (plugin_mgr->pending_plugin_modules != NULL)
{
meta_prefs_add_listener (prefs_changed_callback, plugin_mgr);
return TRUE;
@@ -305,23 +299,31 @@ meta_plugin_manager_load (MetaPluginManager *plugin_mgr)
}
gboolean
meta_plugin_manager_initialize (MetaPluginManager *plugin_mgr)
mutter_plugin_manager_initialize (MutterPluginManager *plugin_mgr)
{
GList *iter;
for (iter = plugin_mgr->plugins; iter; iter = iter->next)
for (iter = plugin_mgr->pending_plugin_modules; iter; iter = iter->next)
{
MetaPlugin *plugin = (MetaPlugin*) iter->data;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
MutterPluginPending *pending = (MutterPluginPending*) iter->data;
MutterPlugin *p;
g_object_set (plugin,
"screen", plugin_mgr->screen,
NULL);
if ((p = mutter_plugin_load (plugin_mgr, pending->module, pending->params)))
{
plugin_mgr->plugins = g_list_prepend (plugin_mgr->plugins, p);
}
else
{
g_warning ("Plugin load for [%s] failed", pending->path);
}
if (klass->start)
klass->start (plugin);
g_type_module_unuse (G_TYPE_MODULE (pending->module));
g_free (pending->path);
g_free (pending->params);
g_free (pending);
}
g_list_free (plugin_mgr->pending_plugin_modules);
plugin_mgr->pending_plugin_modules = NULL;
return TRUE;
}
@@ -329,24 +331,20 @@ meta_plugin_manager_initialize (MetaPluginManager *plugin_mgr)
* Reloads all plugins
*/
static gboolean
meta_plugin_manager_reload (MetaPluginManager *plugin_mgr)
mutter_plugin_manager_reload (MutterPluginManager *plugin_mgr)
{
/* TODO -- brute force; should we build a list of plugins to load and list of
* plugins to unload? We are probably not going to have large numbers of
* plugins loaded at the same time, so it might not be worth it.
*/
/* Prevent stale grabs on unloaded plugins */
meta_check_end_modal (plugin_mgr->screen);
meta_plugin_manager_unload (plugin_mgr);
return meta_plugin_manager_load (plugin_mgr);
mutter_plugin_manager_unload (plugin_mgr);
return mutter_plugin_manager_load (plugin_mgr);
}
static MetaPluginManager *
meta_plugin_manager_new (MetaScreen *screen)
MutterPluginManager *
mutter_plugin_manager_new (MetaScreen *screen)
{
MetaPluginManager *plugin_mgr;
MutterPluginManager *plugin_mgr;
if (!plugin_modules)
{
@@ -354,91 +352,37 @@ meta_plugin_manager_new (MetaScreen *screen)
NULL);
}
plugin_mgr = g_new0 (MetaPluginManager, 1);
plugin_mgr = g_new0 (MutterPluginManager, 1);
plugin_mgr->screen = screen;
if (screen)
g_object_set_data (G_OBJECT (screen), "meta-plugin-manager", plugin_mgr);
return plugin_mgr;
}
MetaPluginManager *
meta_plugin_manager_get_default (void)
{
if (!default_plugin_manager)
{
default_plugin_manager = meta_plugin_manager_new (NULL);
}
return default_plugin_manager;
}
MetaPluginManager *
meta_plugin_manager_get (MetaScreen *screen)
{
MetaPluginManager *plugin_mgr;
plugin_mgr = g_object_get_data (G_OBJECT (screen), "meta-plugin-manager");
if (plugin_mgr)
return plugin_mgr;
if (!default_plugin_manager)
meta_plugin_manager_get_default ();
if (!default_plugin_manager->screen)
{
/* The default plugin manager is so far unused, we can recycle it */
default_plugin_manager->screen = screen;
g_object_set_data (G_OBJECT (screen), "meta-plugin-manager", default_plugin_manager);
return default_plugin_manager;
}
else
{
return meta_plugin_manager_new (screen);
}
}
static void
meta_plugin_manager_kill_window_effects (MetaPluginManager *plugin_mgr,
MetaWindowActor *actor)
mutter_plugin_manager_kill_effect (MutterPluginManager *plugin_mgr,
MutterWindow *actor,
unsigned long events)
{
GList *l = plugin_mgr->plugins;
while (l)
{
MetaPlugin *plugin = l->data;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
MutterPlugin *plugin = l->data;
MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin);
if (!meta_plugin_disabled (plugin)
&& klass->kill_window_effects)
klass->kill_window_effects (plugin, actor);
l = l->next;
}
}
static void
meta_plugin_manager_kill_switch_workspace (MetaPluginManager *plugin_mgr)
{
GList *l = plugin_mgr->plugins;
while (l)
{
MetaPlugin *plugin = l->data;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
if (!meta_plugin_disabled (plugin)
&& (meta_plugin_features (plugin) & META_PLUGIN_SWITCH_WORKSPACE)
&& klass->kill_switch_workspace)
klass->kill_switch_workspace (plugin);
if (!mutter_plugin_disabled (plugin)
&& (mutter_plugin_features (plugin) & events)
&& klass->kill_effect)
klass->kill_effect (plugin, actor, events);
l = l->next;
}
}
#define ALL_BUT_SWITCH \
MUTTER_PLUGIN_ALL_EFFECTS & \
~MUTTER_PLUGIN_SWITCH_WORKSPACE
/*
* Public method that the compositor hooks into for events that require
* no additional parameters.
@@ -449,55 +393,53 @@ meta_plugin_manager_kill_switch_workspace (MetaPluginManager *plugin_mgr)
* appropriate post-effect cleanup is carried out.
*/
gboolean
meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr,
MetaWindowActor *actor,
unsigned long event)
mutter_plugin_manager_event_simple (MutterPluginManager *plugin_mgr,
MutterWindow *actor,
unsigned long event)
{
GList *l = plugin_mgr->plugins;
gboolean retval = FALSE;
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
if (display->display_opening)
return FALSE;
while (l)
{
MetaPlugin *plugin = l->data;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
MutterPlugin *plugin = l->data;
MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin);
if (!meta_plugin_disabled (plugin) &&
(meta_plugin_features (plugin) & event))
if (!mutter_plugin_disabled (plugin) &&
(mutter_plugin_features (plugin) & event))
{
retval = TRUE;
switch (event)
{
case META_PLUGIN_MINIMIZE:
case MUTTER_PLUGIN_MINIMIZE:
if (klass->minimize)
{
meta_plugin_manager_kill_window_effects (
mutter_plugin_manager_kill_effect (
plugin_mgr,
actor);
actor,
ALL_BUT_SWITCH);
_meta_plugin_effect_started (plugin);
_mutter_plugin_effect_started (plugin);
klass->minimize (plugin, actor);
}
break;
case META_PLUGIN_MAP:
case MUTTER_PLUGIN_MAP:
if (klass->map)
{
meta_plugin_manager_kill_window_effects (
mutter_plugin_manager_kill_effect (
plugin_mgr,
actor);
actor,
ALL_BUT_SWITCH);
_meta_plugin_effect_started (plugin);
_mutter_plugin_effect_started (plugin);
klass->map (plugin, actor);
}
break;
case META_PLUGIN_DESTROY:
case MUTTER_PLUGIN_DESTROY:
if (klass->destroy)
{
_meta_plugin_effect_started (plugin);
_mutter_plugin_effect_started (plugin);
klass->destroy (plugin, actor);
}
break;
@@ -522,54 +464,52 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr,
* appropriate post-effect cleanup is carried out.
*/
gboolean
meta_plugin_manager_event_maximize (MetaPluginManager *plugin_mgr,
MetaWindowActor *actor,
unsigned long event,
gint target_x,
gint target_y,
gint target_width,
gint target_height)
mutter_plugin_manager_event_maximize (MutterPluginManager *plugin_mgr,
MutterWindow *actor,
unsigned long event,
gint target_x,
gint target_y,
gint target_width,
gint target_height)
{
GList *l = plugin_mgr->plugins;
gboolean retval = FALSE;
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
if (display->display_opening)
return FALSE;
while (l)
{
MetaPlugin *plugin = l->data;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
MutterPlugin *plugin = l->data;
MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin);
if (!meta_plugin_disabled (plugin) &&
(meta_plugin_features (plugin) & event))
if (!mutter_plugin_disabled (plugin) &&
(mutter_plugin_features (plugin) & event))
{
retval = TRUE;
switch (event)
{
case META_PLUGIN_MAXIMIZE:
case MUTTER_PLUGIN_MAXIMIZE:
if (klass->maximize)
{
meta_plugin_manager_kill_window_effects (
mutter_plugin_manager_kill_effect (
plugin_mgr,
actor);
actor,
ALL_BUT_SWITCH);
_meta_plugin_effect_started (plugin);
_mutter_plugin_effect_started (plugin);
klass->maximize (plugin, actor,
target_x, target_y,
target_width, target_height);
}
break;
case META_PLUGIN_UNMAXIMIZE:
case MUTTER_PLUGIN_UNMAXIMIZE:
if (klass->unmaximize)
{
meta_plugin_manager_kill_window_effects (
mutter_plugin_manager_kill_effect (
plugin_mgr,
actor);
actor,
ALL_BUT_SWITCH);
_meta_plugin_effect_started (plugin);
_mutter_plugin_effect_started (plugin);
klass->unmaximize (plugin, actor,
target_x, target_y,
target_width, target_height);
@@ -595,33 +535,34 @@ meta_plugin_manager_event_maximize (MetaPluginManager *plugin_mgr,
* appropriate post-effect cleanup is carried out.
*/
gboolean
meta_plugin_manager_switch_workspace (MetaPluginManager *plugin_mgr,
gint from,
gint to,
MetaMotionDirection direction)
mutter_plugin_manager_switch_workspace (MutterPluginManager *plugin_mgr,
const GList **actors,
gint from,
gint to,
MetaMotionDirection direction)
{
GList *l = plugin_mgr->plugins;
gboolean retval = FALSE;
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
if (display->display_opening)
return FALSE;
while (l)
{
MetaPlugin *plugin = l->data;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
MutterPlugin *plugin = l->data;
MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin);
if (!meta_plugin_disabled (plugin) &&
(meta_plugin_features (plugin) & META_PLUGIN_SWITCH_WORKSPACE))
if (!mutter_plugin_disabled (plugin) &&
(mutter_plugin_features (plugin) & MUTTER_PLUGIN_SWITCH_WORKSPACE) &&
(actors && *actors))
{
if (klass->switch_workspace)
{
retval = TRUE;
meta_plugin_manager_kill_switch_workspace (plugin_mgr);
mutter_plugin_manager_kill_effect (
plugin_mgr,
MUTTER_WINDOW ((*actors)->data),
MUTTER_PLUGIN_SWITCH_WORKSPACE);
_meta_plugin_effect_started (plugin);
klass->switch_workspace (plugin, from, to, direction);
_mutter_plugin_effect_started (plugin);
klass->switch_workspace (plugin, actors, from, to, direction);
}
}
@@ -640,43 +581,23 @@ meta_plugin_manager_switch_workspace (MetaPluginManager *plugin_mgr,
* appropriate post-effect cleanup is carried out.
*/
gboolean
meta_plugin_manager_xevent_filter (MetaPluginManager *plugin_mgr,
XEvent *xev)
mutter_plugin_manager_xevent_filter (MutterPluginManager *plugin_mgr,
XEvent *xev)
{
GList *l;
gboolean have_plugin_xevent_func;
if (!plugin_mgr)
return FALSE;
l = plugin_mgr->plugins;
/* We need to make sure that clutter gets certain events, like
* ConfigureNotify on the stage window. If there is a plugin that
* provides an xevent_filter function, then it's the responsibility
* of that plugin to pass events to Clutter. Otherwise, we send the
* event directly to Clutter ourselves.
*
* What happens if there are two plugins with xevent_filter functions
* is undefined; in general, multiple competing plugins are something
* we don't support well or care much about.
*
* FIXME: Really, we should just always handle sending the event to
* clutter if a plugin doesn't report the event as handled by
* returning TRUE, but it doesn't seem worth breaking compatibility
* of the plugin interface right now to achieve this; the way it is
* now works fine in practice.
*/
have_plugin_xevent_func = FALSE;
while (l)
{
MetaPlugin *plugin = l->data;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
MutterPlugin *plugin = l->data;
MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin);
if (klass->xevent_filter)
{
have_plugin_xevent_func = TRUE;
if (klass->xevent_filter (plugin, xev) == TRUE)
return TRUE;
}
@@ -684,8 +605,5 @@ meta_plugin_manager_xevent_filter (MetaPluginManager *plugin_mgr,
l = l->next;
}
if (!have_plugin_xevent_func)
return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE;
return FALSE;
}

View File

@@ -0,0 +1,63 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (c) 2008 Intel Corp.
*
* Author: Tomas Frydrych <tf@linux.intel.com>
*
* 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.
*/
#ifndef MUTTER_PLUGIN_MANAGER_H_
#define MUTTER_PLUGIN_MANAGER_H_
#include "types.h"
#include "screen.h"
#define MUTTER_PLUGIN_FROM_MANAGER_
#include "mutter-plugin.h"
#undef MUTTER_PLUGIN_FROM_MANAGER_
typedef struct MutterPluginManager MutterPluginManager;
MutterPluginManager * mutter_plugin_manager_new (MetaScreen *screen);
gboolean mutter_plugin_manager_load (MutterPluginManager *mgr);
gboolean mutter_plugin_manager_initialize (MutterPluginManager *plugin_mgr);
gboolean mutter_plugin_manager_event_simple (MutterPluginManager *mgr,
MutterWindow *actor,
unsigned long event);
gboolean mutter_plugin_manager_event_maximize (MutterPluginManager *mgr,
MutterWindow *actor,
unsigned long event,
gint target_x,
gint target_y,
gint target_width,
gint target_height);
void mutter_plugin_manager_update_workspaces (MutterPluginManager *mgr);
void mutter_plugin_manager_update_workspace (MutterPluginManager *mgr, MetaWorkspace *w);
gboolean mutter_plugin_manager_switch_workspace (MutterPluginManager *mgr,
const GList **actors,
gint from,
gint to,
MetaMotionDirection direction);
gboolean mutter_plugin_manager_xevent_filter (MutterPluginManager *mgr,
XEvent *xev);
#endif

View File

@@ -0,0 +1,484 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (c) 2008 Intel Corp.
*
* Author: Tomas Frydrych <tf@linux.intel.com>
*
* 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.
*/
#include "mutter-plugin.h"
#include "screen.h"
#include "display.h"
#include <string.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/shape.h>
#include <clutter/x11/clutter-x11.h>
G_DEFINE_ABSTRACT_TYPE (MutterPlugin, mutter_plugin, G_TYPE_OBJECT);
#define MUTTER_PLUGIN_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUTTER_TYPE_PLUGIN, MutterPluginPrivate))
enum
{
PROP_0,
PROP_SCREEN,
PROP_PARAMS,
PROP_FEATURES,
PROP_DISABLED,
PROP_DEBUG_MODE,
};
struct _MutterPluginPrivate
{
MetaScreen *screen;
gchar *params;
gulong features;
gint running;
gboolean disabled : 1;
gboolean debug : 1;
};
static void
mutter_plugin_dispose (GObject *object)
{
G_OBJECT_CLASS (mutter_plugin_parent_class)->dispose (object);
}
static void
mutter_plugin_finalize (GObject *object)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (object)->priv;
g_free (priv->params);
priv->params = NULL;
G_OBJECT_CLASS (mutter_plugin_parent_class)->finalize (object);
}
static void
mutter_plugin_parse_params (MutterPlugin *plugin)
{
char *p;
gulong features = 0;
MutterPluginPrivate *priv = plugin->priv;
MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin);
/*
* Feature flags: identify events that the plugin can handle; a plugin can
* handle one or more events.
*/
if (klass->minimize)
features |= MUTTER_PLUGIN_MINIMIZE;
if (klass->maximize)
features |= MUTTER_PLUGIN_MAXIMIZE;
if (klass->unmaximize)
features |= MUTTER_PLUGIN_UNMAXIMIZE;
if (klass->map)
features |= MUTTER_PLUGIN_MAP;
if (klass->destroy)
features |= MUTTER_PLUGIN_DESTROY;
if (klass->switch_workspace)
features |= MUTTER_PLUGIN_SWITCH_WORKSPACE;
if (priv->params)
{
gboolean debug = FALSE;
if ((p = strstr (priv->params, "disable:")))
{
gchar *d = g_strdup (p+8);
p = strchr (d, ';');
if (p)
*p = 0;
if (strstr (d, "minimize"))
features &= ~ MUTTER_PLUGIN_MINIMIZE;
if (strstr (d, "maximize"))
features &= ~ MUTTER_PLUGIN_MAXIMIZE;
if (strstr (d, "unmaximize"))
features &= ~ MUTTER_PLUGIN_UNMAXIMIZE;
if (strstr (d, "map"))
features &= ~ MUTTER_PLUGIN_MAP;
if (strstr (d, "destroy"))
features &= ~ MUTTER_PLUGIN_DESTROY;
if (strstr (d, "switch-workspace"))
features &= ~MUTTER_PLUGIN_SWITCH_WORKSPACE;
g_free (d);
}
if (strstr (priv->params, "debug"))
debug = TRUE;
if (debug != priv->debug)
{
priv->debug = debug;
g_object_notify (G_OBJECT (plugin), "debug-mode");
}
}
if (features != priv->features)
{
priv->features = features;
g_object_notify (G_OBJECT (plugin), "features");
}
}
static void
mutter_plugin_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (object)->priv;
switch (prop_id)
{
case PROP_SCREEN:
priv->screen = g_value_get_object (value);
break;
case PROP_PARAMS:
priv->params = g_value_dup_string (value);
mutter_plugin_parse_params (MUTTER_PLUGIN (object));
break;
case PROP_DISABLED:
priv->disabled = g_value_get_boolean (value);
break;
case PROP_DEBUG_MODE:
priv->debug = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
mutter_plugin_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (object)->priv;
switch (prop_id)
{
case PROP_SCREEN:
g_value_set_object (value, priv->screen);
break;
case PROP_PARAMS:
g_value_set_string (value, priv->params);
break;
case PROP_DISABLED:
g_value_set_boolean (value, priv->disabled);
break;
case PROP_DEBUG_MODE:
g_value_set_boolean (value, priv->debug);
break;
case PROP_FEATURES:
g_value_set_ulong (value, priv->features);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
mutter_plugin_class_init (MutterPluginClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = mutter_plugin_finalize;
gobject_class->dispose = mutter_plugin_dispose;
gobject_class->set_property = mutter_plugin_set_property;
gobject_class->get_property = mutter_plugin_get_property;
g_object_class_install_property (gobject_class,
PROP_SCREEN,
g_param_spec_object ("screen",
"MetaScreen",
"MetaScreen",
META_TYPE_SCREEN,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (gobject_class,
PROP_PARAMS,
g_param_spec_string ("params",
"Parameters",
"Plugin Parameters",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_FEATURES,
g_param_spec_ulong ("features",
"Features",
"Plugin Features",
0 , G_MAXULONG, 0,
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_DISABLED,
g_param_spec_boolean ("disabled",
"Plugin disabled",
"Plugin disabled",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_DEBUG_MODE,
g_param_spec_boolean ("debug-mode",
"Debug Mode",
"Debug Mode",
FALSE,
G_PARAM_READABLE));
g_type_class_add_private (gobject_class, sizeof (MutterPluginPrivate));
}
static void
mutter_plugin_init (MutterPlugin *self)
{
MutterPluginPrivate *priv;
self->priv = priv = MUTTER_PLUGIN_GET_PRIVATE (self);
}
gulong
mutter_plugin_features (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return priv->features;
}
gboolean
mutter_plugin_disabled (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return priv->disabled;
}
gboolean
mutter_plugin_running (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return (priv->running > 0);
}
gboolean
mutter_plugin_debug_mode (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return priv->debug;
}
const MutterPluginInfo *
mutter_plugin_get_info (MutterPlugin *plugin)
{
MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin);
if (klass && klass->plugin_info)
return klass->plugin_info (plugin);
return NULL;
}
ClutterActor *
mutter_plugin_get_overlay_group (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return mutter_get_overlay_group_for_screen (priv->screen);
}
ClutterActor *
mutter_plugin_get_stage (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return mutter_get_stage_for_screen (priv->screen);
}
ClutterActor *
mutter_plugin_get_window_group (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return mutter_get_window_group_for_screen (priv->screen);
}
/**
* _mutter_plugin_effect_started:
* @plugin: the plugin
*
* Mark that an effect has started for the plugin. This is called
* internally by MutterPluginManager.
*/
void
_mutter_plugin_effect_started (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
priv->running++;
}
void
mutter_plugin_effect_completed (MutterPlugin *plugin,
MutterWindow *actor,
unsigned long event)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
if (priv->running-- < 0)
{
g_warning ("Error in running effect accounting, adjusting.");
priv->running = 0;
}
if (!actor)
{
const MutterPluginInfo *info;
const gchar *name = NULL;
if (plugin && (info = mutter_plugin_get_info (plugin)))
name = info->name;
g_warning ("Plugin [%s] passed NULL for actor!",
name ? name : "unknown");
}
mutter_window_effect_completed (actor, event);
}
void
mutter_plugin_query_screen_size (MutterPlugin *plugin,
int *width,
int *height)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
meta_screen_get_size (priv->screen, width, height);
}
void
mutter_plugin_set_stage_reactive (MutterPlugin *plugin,
gboolean reactive)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
MetaScreen *screen = priv->screen;
if (reactive)
mutter_set_stage_input_region (screen, None);
else
mutter_empty_stage_input_region (screen);
}
void
mutter_plugin_set_stage_input_area (MutterPlugin *plugin,
gint x, gint y, gint width, gint height)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
MetaScreen *screen = priv->screen;
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdpy = meta_display_get_xdisplay (display);
XRectangle rect;
XserverRegion region;
rect.x = x;
rect.y = y;
rect.width = width;
rect.height = height;
region = XFixesCreateRegion (xdpy, &rect, 1);
mutter_set_stage_input_region (screen, region);
XFixesDestroyRegion (xdpy, region);
}
void
mutter_plugin_set_stage_input_region (MutterPlugin *plugin,
XserverRegion region)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
MetaScreen *screen = priv->screen;
mutter_set_stage_input_region (screen, region);
}
GList *
mutter_plugin_get_windows (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return mutter_get_windows (priv->screen);
}
Display *
mutter_plugin_get_xdisplay (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
MetaDisplay *display = meta_screen_get_display (priv->screen);
Display *xdpy = meta_display_get_xdisplay (display);
return xdpy;
}
/**
* mutter_plugin_get_screen:
* @plugin: a #MutterPlugin
*
* Gets the #MetaScreen corresponding to a plugin. Each plugin instance
* is associated with exactly one screen; if Metacity is managing
* multiple screens, multiple plugin instances will be created.
*
* Return value: (transfer none): the #MetaScreen for the plugin
*/
MetaScreen *
mutter_plugin_get_screen (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return priv->screen;
}

View File

@@ -0,0 +1,428 @@
/*
* shaped texture
*
* An actor to draw a texture clipped to a list of rectangles
*
* Authored By Neil Roberts <neil@linux.intel.com>
*
* Copyright (C) 2008 Intel Corporation
*
* 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.
*/
#include <config.h>
#include "mutter-shaped-texture.h"
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <string.h>
static void mutter_shaped_texture_dispose (GObject *object);
static void mutter_shaped_texture_finalize (GObject *object);
static void mutter_shaped_texture_paint (ClutterActor *actor);
static void mutter_shaped_texture_pick (ClutterActor *actor,
const ClutterColor *color);
static void mutter_shaped_texture_dirty_mask (MutterShapedTexture *stex);
#ifdef HAVE_GLX_TEXTURE_PIXMAP
G_DEFINE_TYPE (MutterShapedTexture, mutter_shaped_texture,
CLUTTER_GLX_TYPE_TEXTURE_PIXMAP);
#else /* HAVE_GLX_TEXTURE_PIXMAP */
G_DEFINE_TYPE (MutterShapedTexture, mutter_shaped_texture,
CLUTTER_X11_TYPE_TEXTURE_PIXMAP);
#endif /* HAVE_GLX_TEXTURE_PIXMAP */
#define MUTTER_SHAPED_TEXTURE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUTTER_TYPE_SHAPED_TEXTURE, \
MutterShapedTexturePrivate))
struct _MutterShapedTexturePrivate
{
CoglHandle mask_texture;
CoglHandle material;
#if 1 /* see workaround comment in mutter_shaped_texture_paint */
CoglHandle material_workaround;
#endif
guint mask_width, mask_height;
GArray *rectangles;
};
static void
mutter_shaped_texture_class_init (MutterShapedTextureClass *klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
ClutterActorClass *actor_class = (ClutterActorClass *) klass;
gobject_class->dispose = mutter_shaped_texture_dispose;
gobject_class->finalize = mutter_shaped_texture_finalize;
actor_class->paint = mutter_shaped_texture_paint;
actor_class->pick = mutter_shaped_texture_pick;
g_type_class_add_private (klass, sizeof (MutterShapedTexturePrivate));
}
static void
mutter_shaped_texture_init (MutterShapedTexture *self)
{
MutterShapedTexturePrivate *priv;
priv = self->priv = MUTTER_SHAPED_TEXTURE_GET_PRIVATE (self);
priv->rectangles = g_array_new (FALSE, FALSE, sizeof (XRectangle));
priv->mask_texture = COGL_INVALID_HANDLE;
}
static void
mutter_shaped_texture_dispose (GObject *object)
{
MutterShapedTexture *self = (MutterShapedTexture *) object;
MutterShapedTexturePrivate *priv = self->priv;
mutter_shaped_texture_dirty_mask (self);
if (priv->material != COGL_INVALID_HANDLE)
{
cogl_material_unref (priv->material);
priv->material = COGL_INVALID_HANDLE;
}
#if 1 /* see comment in mutter_shaped_texture_paint */
if (priv->material_workaround != COGL_INVALID_HANDLE)
{
cogl_material_unref (priv->material_workaround);
priv->material_workaround = COGL_INVALID_HANDLE;
}
#endif
G_OBJECT_CLASS (mutter_shaped_texture_parent_class)->dispose (object);
}
static void
mutter_shaped_texture_finalize (GObject *object)
{
MutterShapedTexture *self = (MutterShapedTexture *) object;
MutterShapedTexturePrivate *priv = self->priv;
g_array_free (priv->rectangles, TRUE);
G_OBJECT_CLASS (mutter_shaped_texture_parent_class)->finalize (object);
}
static void
mutter_shaped_texture_dirty_mask (MutterShapedTexture *stex)
{
MutterShapedTexturePrivate *priv = stex->priv;
if (priv->mask_texture != COGL_INVALID_HANDLE)
{
GLuint mask_gl_tex;
GLenum mask_gl_target;
cogl_texture_get_gl_texture (priv->mask_texture,
&mask_gl_tex, &mask_gl_target);
if (mask_gl_target == CGL_TEXTURE_RECTANGLE_ARB)
glDeleteTextures (1, &mask_gl_tex);
cogl_texture_unref (priv->mask_texture);
priv->mask_texture = COGL_INVALID_HANDLE;
}
}
static void
mutter_shaped_texture_ensure_mask (MutterShapedTexture *stex)
{
MutterShapedTexturePrivate *priv = stex->priv;
CoglHandle paint_tex;
guint tex_width, tex_height;
paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex));
if (paint_tex == COGL_INVALID_HANDLE)
return;
tex_width = cogl_texture_get_width (paint_tex);
tex_height = cogl_texture_get_height (paint_tex);
/* If the mask texture we have was created for a different size then
recreate it */
if (priv->mask_texture != COGL_INVALID_HANDLE
&& (priv->mask_width != tex_width || priv->mask_height != tex_height))
mutter_shaped_texture_dirty_mask (stex);
/* If we don't have a mask texture yet then create one */
if (priv->mask_texture == COGL_INVALID_HANDLE)
{
guchar *mask_data;
const XRectangle *rect;
GLenum paint_gl_target;
/* Create data for an empty image */
mask_data = g_malloc0 (tex_width * tex_height);
/* Cut out a hole for each rectangle */
for (rect = (XRectangle *) priv->rectangles->data
+ priv->rectangles->len;
rect-- > (XRectangle *) priv->rectangles->data;)
{
gint x1 = rect->x, x2 = x1 + rect->width;
gint y1 = rect->y, y2 = y1 + rect->height;
guchar *p;
/* Clip the rectangle to the size of the texture */
x1 = CLAMP (x1, 0, (gint) tex_width - 1);
x2 = CLAMP (x2, x1, (gint) tex_width);
y1 = CLAMP (y1, 0, (gint) tex_height - 1);
y2 = CLAMP (y2, y1, (gint) tex_height);
/* Fill the rectangle */
for (p = mask_data + y1 * tex_width + x1;
y1 < y2;
y1++, p += tex_width)
memset (p, 255, x2 - x1);
}
cogl_texture_get_gl_texture (paint_tex, NULL, &paint_gl_target);
if (paint_gl_target == CGL_TEXTURE_RECTANGLE_ARB)
{
GLuint tex;
glGenTextures (1, &tex);
glBindTexture (CGL_TEXTURE_RECTANGLE_ARB, tex);
glPixelStorei (GL_UNPACK_ROW_LENGTH, tex_width);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
glTexImage2D (CGL_TEXTURE_RECTANGLE_ARB, 0,
GL_ALPHA, tex_width, tex_height,
0, GL_ALPHA, GL_UNSIGNED_BYTE, mask_data);
priv->mask_texture
= cogl_texture_new_from_foreign (tex,
CGL_TEXTURE_RECTANGLE_ARB,
tex_width, tex_height,
0, 0,
COGL_PIXEL_FORMAT_A_8);
}
else
priv->mask_texture = cogl_texture_new_from_data (tex_width, tex_height,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_A_8,
COGL_PIXEL_FORMAT_ANY,
tex_width,
mask_data);
g_free (mask_data);
priv->mask_width = tex_width;
priv->mask_height = tex_height;
}
}
static void
mutter_shaped_texture_paint (ClutterActor *actor)
{
MutterShapedTexture *stex = (MutterShapedTexture *) actor;
MutterShapedTexturePrivate *priv = stex->priv;
CoglHandle paint_tex;
guint tex_width, tex_height;
ClutterActorBox alloc;
CoglHandle material;
#if 1 /* please see comment below about workaround */
guint depth;
#endif
if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
clutter_actor_realize (CLUTTER_ACTOR (stex));
paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex));
tex_width = cogl_texture_get_width (paint_tex);
tex_height = cogl_texture_get_height (paint_tex);
if (tex_width == 0 || tex_width == 0) /* no contents yet */
return;
/* If there are no rectangles fallback to the regular paint
method */
if (priv->rectangles->len < 1)
{
CLUTTER_ACTOR_CLASS (mutter_shaped_texture_parent_class)
->paint (actor);
return;
}
if (paint_tex == COGL_INVALID_HANDLE)
return;
mutter_shaped_texture_ensure_mask (stex);
if (priv->material == COGL_INVALID_HANDLE)
{
priv->material = cogl_material_new ();
cogl_material_set_layer_combine (priv->material, 1,
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
NULL);
}
material = priv->material;
#if 1
/* This was added as a workaround. It seems that with the intel
* drivers when multi-texturing using an RGB TFP texture, the
* texture is actually setup internally as an RGBA texture, where
* the alpha channel is mostly 0.0 so you only see a shimmer of the
* window. This workaround forcibly defines the alpha channel as
* 1.0. Maybe there is some clutter/cogl state that is interacting
* with this that is being overlooked, but for now this seems to
* work. */
g_object_get (stex, "pixmap-depth", &depth, NULL);
if (depth == 24)
{
if (priv->material_workaround == COGL_INVALID_HANDLE)
{
material = priv->material_workaround = cogl_material_new ();
cogl_material_set_layer_combine (material, 0,
"RGB = MODULATE (TEXTURE, PREVIOUS)"
"A = REPLACE (PREVIOUS)",
NULL);
cogl_material_set_layer_combine (material, 1,
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
NULL);
}
material = priv->material_workaround;
}
#endif
cogl_material_set_layer (material, 0, paint_tex);
cogl_material_set_layer (material, 1, priv->mask_texture);
{
CoglColor color;
guchar opacity = clutter_actor_get_paint_opacity (actor);
cogl_color_set_from_4ub (&color, opacity, opacity, opacity, opacity);
cogl_material_set_color (material, &color);
}
cogl_set_source (material);
clutter_actor_get_allocation_box (actor, &alloc);
cogl_rectangle (0, 0,
alloc.x2 - alloc.x1,
alloc.y2 - alloc.y1);
}
static void
mutter_shaped_texture_pick (ClutterActor *actor,
const ClutterColor *color)
{
MutterShapedTexture *stex = (MutterShapedTexture *) actor;
MutterShapedTexturePrivate *priv = stex->priv;
/* If there are no rectangles then use the regular pick */
if (priv->rectangles->len < 1)
CLUTTER_ACTOR_CLASS (mutter_shaped_texture_parent_class)
->pick (actor, color);
else if (clutter_actor_should_pick_paint (actor))
{
CoglHandle paint_tex;
ClutterActorBox alloc;
guint tex_width, tex_height;
paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex));
if (paint_tex == COGL_INVALID_HANDLE)
return;
tex_width = cogl_texture_get_width (paint_tex);
tex_height = cogl_texture_get_height (paint_tex);
if (tex_width == 0 || tex_width == 0) /* no contents yet */
return;
mutter_shaped_texture_ensure_mask (stex);
cogl_set_source_color4ub (color->red, color->green, color->blue,
color->alpha);
clutter_actor_get_allocation_box (actor, &alloc);
/* Paint the mask rectangle in the given color */
cogl_set_source_texture (priv->mask_texture);
cogl_rectangle_with_texture_coords (0, 0,
alloc.x2 - alloc.x1,
alloc.y2 - alloc.y1,
0, 0, 1, 1);
}
}
ClutterActor *
mutter_shaped_texture_new (void)
{
ClutterActor *self = g_object_new (MUTTER_TYPE_SHAPED_TEXTURE, NULL);
return self;
}
void
mutter_shaped_texture_clear_rectangles (MutterShapedTexture *stex)
{
MutterShapedTexturePrivate *priv;
g_return_if_fail (MUTTER_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
g_array_set_size (priv->rectangles, 0);
mutter_shaped_texture_dirty_mask (stex);
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
}
void
mutter_shaped_texture_add_rectangle (MutterShapedTexture *stex,
const XRectangle *rect)
{
g_return_if_fail (MUTTER_IS_SHAPED_TEXTURE (stex));
mutter_shaped_texture_add_rectangles (stex, 1, rect);
}
void
mutter_shaped_texture_add_rectangles (MutterShapedTexture *stex,
size_t num_rects,
const XRectangle *rects)
{
MutterShapedTexturePrivate *priv;
g_return_if_fail (MUTTER_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
g_array_append_vals (priv->rectangles, rects, num_rects);
mutter_shaped_texture_dirty_mask (stex);
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
}

View File

@@ -0,0 +1,95 @@
/*
* shaped texture
*
* An actor to draw a texture clipped to a list of rectangles
*
* Authored By Neil Roberts <neil@linux.intel.com>
*
* Copyright (C) 2008 Intel Corporation
*
* 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.
*/
#ifndef __MUTTER_SHAPED_TEXTURE_H__
#define __MUTTER_SHAPED_TEXTURE_H__
#include <clutter/clutter.h>
#ifdef HAVE_GLX_TEXTURE_PIXMAP
#include <clutter/glx/clutter-glx.h>
#endif /* HAVE_GLX_TEXTURE_PIXMAP */
G_BEGIN_DECLS
#define MUTTER_TYPE_SHAPED_TEXTURE \
(mutter_shaped_texture_get_type())
#define MUTTER_SHAPED_TEXTURE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
MUTTER_TYPE_SHAPED_TEXTURE, \
MutterShapedTexture))
#define MUTTER_SHAPED_TEXTURE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), \
MUTTER_TYPE_SHAPED_TEXTURE, \
MutterShapedTextureClass))
#define MUTTER_IS_SHAPED_TEXTURE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
MUTTER_TYPE_SHAPED_TEXTURE))
#define MUTTER_IS_SHAPED_TEXTURE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
MUTTER_TYPE_SHAPED_TEXTURE))
#define MUTTER_SHAPED_TEXTURE_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
MUTTER_TYPE_SHAPED_TEXTURE, \
MutterShapedTextureClass))
typedef struct _MutterShapedTexture MutterShapedTexture;
typedef struct _MutterShapedTextureClass MutterShapedTextureClass;
typedef struct _MutterShapedTexturePrivate MutterShapedTexturePrivate;
struct _MutterShapedTextureClass
{
#ifdef HAVE_GLX_TEXTURE_PIXMAP
ClutterGLXTexturePixmapClass parent_class;
#else
ClutterX11TexturePixmapClass parent_class;
#endif
};
struct _MutterShapedTexture
{
#ifdef HAVE_GLX_TEXTURE_PIXMAP
ClutterGLXTexturePixmap parent;
#else
ClutterX11TexturePixmap parent;
#endif
MutterShapedTexturePrivate *priv;
};
GType mutter_shaped_texture_get_type (void) G_GNUC_CONST;
ClutterActor *mutter_shaped_texture_new (void);
void mutter_shaped_texture_clear_rectangles (MutterShapedTexture *stex);
void mutter_shaped_texture_add_rectangle (MutterShapedTexture *stex,
const XRectangle *rect);
void mutter_shaped_texture_add_rectangles (MutterShapedTexture *stex,
size_t num_rects,
const XRectangle *rects);
G_END_DECLS
#endif /* __MUTTER_SHAPED_TEXTURE_H__ */

View File

@@ -1,6 +1,8 @@
pkglibdir=@MUTTER_PLUGIN_DIR@
if WITH_CLUTTER
INCLUDES=@MUTTER_CFLAGS@ -I $(top_srcdir)/src/include -DMUTTER_LIBEXECDIR=\"$(libexecdir)\" -DHOST_ALIAS=\"@HOST_ALIAS@\" -DMUTTER_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" -DMUTTER_PKGDATADIR=\"$(pkgdatadir)\" -DMUTTER_DATADIR=\"$(datadir)\" -DG_LOG_DOMAIN=\"mutter\" -DSN_API_NOT_YET_FROZEN=1 -DMUTTER_MAJOR_VERSION=$(MUTTER_MAJOR_VERSION) -DMUTTER_MINOR_VERSION=$(MUTTER_MINOR_VERSION) -DMUTTER_MICRO_VERSION=$(MUTTER_MICRO_VERSION) -DMUTTER_PLUGIN_API_VERSION=$(MUTTER_PLUGIN_API_VERSION) -DMUTTER_PLUGIN_DIR=\"@MUTTER_PLUGIN_DIR@\"
default_la_CFLAGS = -fPIC
@@ -16,3 +18,5 @@ pkglib_LTLIBRARIES = default.la
install-exec-hook:
-rm $(DESTDIR)$(pkglibdir)/*.a
-rm $(DESTDIR)$(pkglibdir)/*.la
endif

View File

@@ -21,8 +21,7 @@
* 02111-1307, USA.
*/
#include "meta-plugin.h"
#include "window.h"
#include "mutter-plugin.h"
#include <libintl.h>
#define _(x) dgettext (GETTEXT_PACKAGE, x)
@@ -40,78 +39,71 @@
#define ACTOR_DATA_KEY "MCCP-Default-actor-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))
#define META_DEFAULT_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_DEFAULT_PLUGIN, MetaDefaultPluginClass))
#define META_IS_DEFAULT_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_DEFAULT_PLUGIN_TYPE))
#define META_IS_DEFAULT_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_DEFAULT_PLUGIN))
#define META_DEFAULT_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_DEFAULT_PLUGIN, MetaDefaultPluginClass))
#define MUTTER_TYPE_DEFAULT_PLUGIN (mutter_default_plugin_get_type ())
#define MUTTER_DEFAULT_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MUTTER_TYPE_DEFAULT_PLUGIN, MutterDefaultPlugin))
#define MUTTER_DEFAULT_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MUTTER_TYPE_DEFAULT_PLUGIN, MutterDefaultPluginClass))
#define MUTTER_IS_DEFAULT_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MUTTER_DEFAULT_PLUGIN_TYPE))
#define MUTTER_IS_DEFAULT_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MUTTER_TYPE_DEFAULT_PLUGIN))
#define MUTTER_DEFAULT_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MUTTER_TYPE_DEFAULT_PLUGIN, MutterDefaultPluginClass))
#define META_DEFAULT_PLUGIN_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_DEFAULT_PLUGIN, MetaDefaultPluginPrivate))
#define MUTTER_DEFAULT_PLUGIN_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUTTER_TYPE_DEFAULT_PLUGIN, MutterDefaultPluginPrivate))
typedef struct _MetaDefaultPlugin MetaDefaultPlugin;
typedef struct _MetaDefaultPluginClass MetaDefaultPluginClass;
typedef struct _MetaDefaultPluginPrivate MetaDefaultPluginPrivate;
typedef struct _MutterDefaultPlugin MutterDefaultPlugin;
typedef struct _MutterDefaultPluginClass MutterDefaultPluginClass;
typedef struct _MutterDefaultPluginPrivate MutterDefaultPluginPrivate;
struct _MetaDefaultPlugin
struct _MutterDefaultPlugin
{
MetaPlugin parent;
MutterPlugin parent;
MetaDefaultPluginPrivate *priv;
MutterDefaultPluginPrivate *priv;
};
struct _MetaDefaultPluginClass
struct _MutterDefaultPluginClass
{
MetaPluginClass parent_class;
MutterPluginClass parent_class;
};
static GQuark actor_data_quark = 0;
static void minimize (MetaPlugin *plugin,
MetaWindowActor *actor);
static void map (MetaPlugin *plugin,
MetaWindowActor *actor);
static void destroy (MetaPlugin *plugin,
MetaWindowActor *actor);
static void maximize (MetaPlugin *plugin,
MetaWindowActor *actor,
gint x,
gint y,
gint width,
gint height);
static void unmaximize (MetaPlugin *plugin,
MetaWindowActor *actor,
gint x,
gint y,
gint width,
gint height);
static void minimize (MutterPlugin *plugin,
MutterWindow *actor);
static void map (MutterPlugin *plugin,
MutterWindow *actor);
static void destroy (MutterPlugin *plugin,
MutterWindow *actor);
static void maximize (MutterPlugin *plugin,
MutterWindow *actor,
gint x, gint y, gint width, gint height);
static void unmaximize (MutterPlugin *plugin,
MutterWindow *actor,
gint x, gint y, gint width, gint height);
static void switch_workspace (MetaPlugin *plugin,
gint from,
gint to,
MetaMotionDirection direction);
static void switch_workspace (MutterPlugin *plugin,
const GList **actors, gint from, gint to,
MetaMotionDirection direction);
static void kill_window_effects (MetaPlugin *plugin,
MetaWindowActor *actor);
static void kill_switch_workspace (MetaPlugin *plugin);
static void kill_effect (MutterPlugin *plugin,
MutterWindow *actor, gulong event);
static const MetaPluginInfo * plugin_info (MetaPlugin *plugin);
static const MutterPluginInfo * plugin_info (MutterPlugin *plugin);
META_PLUGIN_DECLARE(MetaDefaultPlugin, meta_default_plugin);
MUTTER_PLUGIN_DECLARE(MutterDefaultPlugin, mutter_default_plugin);
/*
* Plugin private data that we store in the .plugin_private member.
*/
struct _MetaDefaultPluginPrivate
struct _MutterDefaultPluginPrivate
{
/* Valid only when switch_workspace effect is in progress */
ClutterTimeline *tml_switch_workspace1;
ClutterTimeline *tml_switch_workspace2;
GList **actors;
ClutterActor *desktop1;
ClutterActor *desktop2;
MetaPluginInfo info;
MutterPluginInfo info;
gboolean debug_mode : 1;
};
@@ -136,26 +128,26 @@ typedef struct _ActorPrivate
typedef struct
{
ClutterActor *actor;
MetaPlugin *plugin;
MutterPlugin *plugin;
} EffectCompleteData;
static void
meta_default_plugin_dispose (GObject *object)
mutter_default_plugin_dispose (GObject *object)
{
/* MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (object)->priv;
/* MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (object)->priv;
*/
G_OBJECT_CLASS (meta_default_plugin_parent_class)->dispose (object);
G_OBJECT_CLASS (mutter_default_plugin_parent_class)->dispose (object);
}
static void
meta_default_plugin_finalize (GObject *object)
mutter_default_plugin_finalize (GObject *object)
{
G_OBJECT_CLASS (meta_default_plugin_parent_class)->finalize (object);
G_OBJECT_CLASS (mutter_default_plugin_parent_class)->finalize (object);
}
static void
meta_default_plugin_set_property (GObject *object,
mutter_default_plugin_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
@@ -169,7 +161,7 @@ meta_default_plugin_set_property (GObject *object,
}
static void
meta_default_plugin_get_property (GObject *object,
mutter_default_plugin_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
@@ -183,9 +175,10 @@ meta_default_plugin_get_property (GObject *object,
}
static void
start (MetaPlugin *plugin)
mutter_default_plugin_constructed (GObject *object)
{
MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv;
MutterPlugin *plugin = MUTTER_PLUGIN (object);
MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (object)->priv;
guint destroy_timeout = DESTROY_TIMEOUT;
guint minimize_timeout = MINIMIZE_TIMEOUT;
@@ -193,7 +186,7 @@ start (MetaPlugin *plugin)
guint map_timeout = MAP_TIMEOUT;
guint switch_timeout = SWITCH_TIMEOUT;
if (meta_plugin_debug_mode (plugin))
if (mutter_plugin_debug_mode (plugin))
{
g_debug ("Plugin %s: Entering debug mode.", priv->info.name);
@@ -208,39 +201,39 @@ start (MetaPlugin *plugin)
map_timeout *= 2;
switch_timeout *= 2;
}
}
static void
meta_default_plugin_class_init (MetaDefaultPluginClass *klass)
mutter_default_plugin_class_init (MutterDefaultPluginClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
MetaPluginClass *plugin_class = META_PLUGIN_CLASS (klass);
MutterPluginClass *plugin_class = MUTTER_PLUGIN_CLASS (klass);
gobject_class->finalize = meta_default_plugin_finalize;
gobject_class->dispose = meta_default_plugin_dispose;
gobject_class->set_property = meta_default_plugin_set_property;
gobject_class->get_property = meta_default_plugin_get_property;
gobject_class->finalize = mutter_default_plugin_finalize;
gobject_class->dispose = mutter_default_plugin_dispose;
gobject_class->constructed = mutter_default_plugin_constructed;
gobject_class->set_property = mutter_default_plugin_set_property;
gobject_class->get_property = mutter_default_plugin_get_property;
plugin_class->start = start;
plugin_class->map = map;
plugin_class->minimize = minimize;
plugin_class->maximize = maximize;
plugin_class->unmaximize = unmaximize;
plugin_class->destroy = destroy;
plugin_class->switch_workspace = switch_workspace;
plugin_class->kill_effect = kill_effect;
plugin_class->plugin_info = plugin_info;
plugin_class->kill_window_effects = kill_window_effects;
plugin_class->kill_switch_workspace = kill_switch_workspace;
g_type_class_add_private (gobject_class, sizeof (MetaDefaultPluginPrivate));
g_type_class_add_private (gobject_class, sizeof (MutterDefaultPluginPrivate));
}
static void
meta_default_plugin_init (MetaDefaultPlugin *self)
mutter_default_plugin_init (MutterDefaultPlugin *self)
{
MetaDefaultPluginPrivate *priv;
MutterDefaultPluginPrivate *priv;
self->priv = priv = META_DEFAULT_PLUGIN_GET_PRIVATE (self);
self->priv = priv = MUTTER_DEFAULT_PLUGIN_GET_PRIVATE (self);
priv->info.name = "Default Effects";
priv->info.version = "0.1";
@@ -260,7 +253,7 @@ free_actor_private (gpointer data)
}
static ActorPrivate *
get_actor_private (MetaWindowActor *actor)
get_actor_private (MutterWindow *actor)
{
ActorPrivate *priv = g_object_get_qdata (G_OBJECT (actor), actor_data_quark);
@@ -279,18 +272,26 @@ get_actor_private (MetaWindowActor *actor)
return priv;
}
typedef struct SwitchWorkspaceData
{
MutterPlugin *plugin;
const GList **actors;
} SwitchWorkspaceData;
static void
on_switch_workspace_effect_complete (ClutterTimeline *timeline, gpointer data)
{
MetaPlugin *plugin = META_PLUGIN (data);
MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv;
GList *l = meta_plugin_get_window_actors (plugin);
SwitchWorkspaceData *sw_data = data;
MutterPlugin *plugin = sw_data->plugin;
MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv;
GList *l = *((GList**)sw_data->actors);
MutterWindow *actor_for_cb = l->data;
while (l)
{
ClutterActor *a = l->data;
MetaWindowActor *window_actor = META_WINDOW_ACTOR (a);
ActorPrivate *apriv = get_actor_private (window_actor);
MutterWindow *mc_window = MUTTER_WINDOW (a);
ActorPrivate *apriv = get_actor_private (mc_window);
if (apriv->orig_parent)
{
@@ -304,32 +305,40 @@ on_switch_workspace_effect_complete (ClutterTimeline *timeline, gpointer data)
clutter_actor_destroy (priv->desktop1);
clutter_actor_destroy (priv->desktop2);
priv->actors = NULL;
priv->tml_switch_workspace1 = NULL;
priv->tml_switch_workspace2 = NULL;
priv->desktop1 = NULL;
priv->desktop2 = NULL;
meta_plugin_switch_workspace_completed (plugin);
g_free (data);
mutter_plugin_effect_completed (plugin, actor_for_cb,
MUTTER_PLUGIN_SWITCH_WORKSPACE);
}
static void
switch_workspace (MetaPlugin *plugin,
gint from, gint to,
switch_workspace (MutterPlugin *plugin,
const GList **actors, gint from, gint to,
MetaMotionDirection direction)
{
MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv;
MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv;
GList *l;
gint n_workspaces;
ClutterActor *workspace0 = clutter_group_new ();
ClutterActor *workspace1 = clutter_group_new ();
ClutterActor *stage;
int screen_width, screen_height;
MetaScreen *screen = meta_plugin_get_screen (plugin);
MetaScreen *screen = mutter_plugin_get_screen (plugin);
SwitchWorkspaceData *sw_data = g_new (SwitchWorkspaceData, 1);
ClutterAnimation *animation;
stage = meta_plugin_get_stage (plugin);
sw_data->plugin = plugin;
sw_data->actors = actors;
meta_plugin_query_screen_size (plugin,
stage = mutter_plugin_get_stage (plugin);
mutter_plugin_query_screen_size (plugin,
&screen_width,
&screen_height);
clutter_actor_set_anchor_point (workspace1,
@@ -346,31 +355,32 @@ switch_workspace (MetaPlugin *plugin,
if (from == to)
{
meta_plugin_switch_workspace_completed (plugin);
mutter_plugin_effect_completed (plugin, NULL,
MUTTER_PLUGIN_SWITCH_WORKSPACE);
return;
}
n_workspaces = meta_screen_get_n_workspaces (screen);
l = g_list_last (meta_plugin_get_window_actors (plugin));
l = g_list_last (*((GList**) actors));
while (l)
{
MetaWindowActor *window_actor = l->data;
ActorPrivate *apriv = get_actor_private (window_actor);
ClutterActor *actor = CLUTTER_ACTOR (window_actor);
gint win_workspace;
MutterWindow *mc_window = l->data;
ActorPrivate *apriv = get_actor_private (mc_window);
ClutterActor *window = CLUTTER_ACTOR (mc_window);
gint win_workspace;
win_workspace = meta_window_actor_get_workspace (window_actor);
win_workspace = mutter_window_get_workspace (mc_window);
if (win_workspace == to || win_workspace == from)
{
apriv->orig_parent = clutter_actor_get_parent (actor);
apriv->orig_parent = clutter_actor_get_parent (window);
clutter_actor_reparent (actor,
clutter_actor_reparent (window,
win_workspace == to ? workspace1 : workspace0);
clutter_actor_show_all (actor);
clutter_actor_raise_top (actor);
clutter_actor_show_all (window);
clutter_actor_raise_top (window);
}
else if (win_workspace < 0)
{
@@ -380,13 +390,14 @@ switch_workspace (MetaPlugin *plugin,
else
{
/* Window on some other desktop */
clutter_actor_hide (actor);
clutter_actor_hide (window);
apriv->orig_parent = NULL;
}
l = l->prev;
}
priv->actors = (GList **)actors;
priv->desktop1 = workspace0;
priv->desktop2 = workspace1;
@@ -399,7 +410,7 @@ switch_workspace (MetaPlugin *plugin,
g_signal_connect (priv->tml_switch_workspace1,
"completed",
G_CALLBACK (on_switch_workspace_effect_complete),
plugin);
sw_data);
animation = clutter_actor_animate (workspace1, CLUTTER_EASE_IN_SINE,
SWITCH_TIMEOUT,
@@ -421,11 +432,11 @@ on_minimize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
* Must reverse the effect of the effect; must hide it first to ensure
* that the restoration will not be visible.
*/
MetaPlugin *plugin = data->plugin;
MutterPlugin *plugin = data->plugin;
ActorPrivate *apriv;
MetaWindowActor *window_actor = META_WINDOW_ACTOR (data->actor);
MutterWindow *mc_window = MUTTER_WINDOW (data->actor);
apriv = get_actor_private (META_WINDOW_ACTOR (data->actor));
apriv = get_actor_private (MUTTER_WINDOW (data->actor));
apriv->tml_minimize = NULL;
clutter_actor_hide (data->actor);
@@ -437,7 +448,8 @@ on_minimize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
CLUTTER_GRAVITY_NORTH_WEST);
/* Now notify the manager that we are done with this effect */
meta_plugin_minimize_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window,
MUTTER_PLUGIN_MINIMIZE);
g_free (data);
}
@@ -447,20 +459,18 @@ on_minimize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
* completion).
*/
static void
minimize (MetaPlugin *plugin, MetaWindowActor *window_actor)
minimize (MutterPlugin *plugin, MutterWindow *mc_window)
{
MetaWindowType type;
MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor);
ClutterActor *actor = CLUTTER_ACTOR (window_actor);
MetaCompWindowType type;
ClutterActor *actor = CLUTTER_ACTOR (mc_window);
type = mutter_window_get_window_type (mc_window);
type = meta_window_get_window_type (meta_window);
if (type == META_WINDOW_NORMAL)
if (type == META_COMP_WINDOW_NORMAL)
{
ClutterAnimation *animation;
EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
ActorPrivate *apriv = get_actor_private (window_actor);
ActorPrivate *apriv = get_actor_private (mc_window);
apriv->is_minimized = TRUE;
@@ -482,7 +492,8 @@ minimize (MetaPlugin *plugin, MetaWindowActor *window_actor)
}
else
meta_plugin_minimize_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window,
MUTTER_PLUGIN_MINIMIZE);
}
/*
@@ -495,9 +506,9 @@ on_maximize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
/*
* Must reverse the effect of the effect.
*/
MetaPlugin *plugin = data->plugin;
MetaWindowActor *window_actor = META_WINDOW_ACTOR (data->actor);
ActorPrivate *apriv = get_actor_private (window_actor);
MutterPlugin * plugin = data->plugin;
MutterWindow *mc_window = MUTTER_WINDOW (data->actor);
ActorPrivate *apriv = get_actor_private (mc_window);
apriv->tml_maximize = NULL;
@@ -507,7 +518,8 @@ on_maximize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
CLUTTER_GRAVITY_NORTH_WEST);
/* Now notify the manager that we are done with this effect */
meta_plugin_maximize_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window,
MUTTER_PLUGIN_MAXIMIZE);
g_free (data);
}
@@ -521,26 +533,25 @@ on_maximize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
* (Something like a sound would be more appropriate.)
*/
static void
maximize (MetaPlugin *plugin,
MetaWindowActor *window_actor,
maximize (MutterPlugin *plugin,
MutterWindow *mc_window,
gint end_x, gint end_y, gint end_width, gint end_height)
{
MetaWindowType type;
ClutterActor *actor = CLUTTER_ACTOR (window_actor);
MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor);
MetaCompWindowType type;
ClutterActor *actor = CLUTTER_ACTOR (mc_window);
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);
type = mutter_window_get_window_type (mc_window);
if (type == META_WINDOW_NORMAL)
if (type == META_COMP_WINDOW_NORMAL)
{
ClutterAnimation *animation;
EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
ActorPrivate *apriv = get_actor_private (window_actor);
ActorPrivate *apriv = get_actor_private (mc_window);
gfloat width, height;
gfloat x, y;
@@ -578,7 +589,8 @@ maximize (MetaPlugin *plugin,
return;
}
meta_plugin_maximize_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window,
MUTTER_PLUGIN_MAXIMIZE);
}
/*
@@ -587,22 +599,22 @@ maximize (MetaPlugin *plugin,
* (Just a skeleton code.)
*/
static void
unmaximize (MetaPlugin *plugin,
MetaWindowActor *window_actor,
unmaximize (MutterPlugin *plugin,
MutterWindow *mc_window,
gint end_x, gint end_y, gint end_width, gint end_height)
{
MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor);
MetaWindowType type = meta_window_get_window_type (meta_window);
MetaCompWindowType type = mutter_window_get_window_type (mc_window);
if (type == META_WINDOW_NORMAL)
if (type == META_COMP_WINDOW_NORMAL)
{
ActorPrivate *apriv = get_actor_private (window_actor);
ActorPrivate *apriv = get_actor_private (mc_window);
apriv->is_maximized = FALSE;
}
/* Do this conditionally, if the effect requires completion callback. */
meta_plugin_unmaximize_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window,
MUTTER_PLUGIN_UNMAXIMIZE);
}
static void
@@ -611,9 +623,9 @@ on_map_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data)
/*
* Must reverse the effect of the effect.
*/
MetaPlugin *plugin = data->plugin;
MetaWindowActor *window_actor = META_WINDOW_ACTOR (data->actor);
ActorPrivate *apriv = get_actor_private (window_actor);
MutterPlugin *plugin = data->plugin;
MutterWindow *mc_window = MUTTER_WINDOW (data->actor);
ActorPrivate *apriv = get_actor_private (mc_window);
apriv->tml_map = NULL;
@@ -621,7 +633,7 @@ on_map_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data)
CLUTTER_GRAVITY_NORTH_WEST);
/* Now notify the manager that we are done with this effect */
meta_plugin_map_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window, MUTTER_PLUGIN_MAP);
g_free (data);
}
@@ -631,19 +643,18 @@ on_map_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data)
* completion).
*/
static void
map (MetaPlugin *plugin, MetaWindowActor *window_actor)
map (MutterPlugin *plugin, MutterWindow *mc_window)
{
MetaWindowType type;
ClutterActor *actor = CLUTTER_ACTOR (window_actor);
MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor);
MetaCompWindowType type;
ClutterActor *actor = CLUTTER_ACTOR (mc_window);
type = meta_window_get_window_type (meta_window);
type = mutter_window_get_window_type (mc_window);
if (type == META_WINDOW_NORMAL)
if (type == META_COMP_WINDOW_NORMAL)
{
ClutterAnimation *animation;
EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
ActorPrivate *apriv = get_actor_private (window_actor);
ActorPrivate *apriv = get_actor_private (mc_window);
clutter_actor_move_anchor_point_from_gravity (actor,
CLUTTER_GRAVITY_CENTER);
@@ -668,7 +679,8 @@ map (MetaPlugin *plugin, MetaWindowActor *window_actor)
}
else
meta_plugin_map_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window,
MUTTER_PLUGIN_MAP);
}
/*
@@ -678,32 +690,32 @@ map (MetaPlugin *plugin, MetaWindowActor *window_actor)
static void
on_destroy_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data)
{
MetaPlugin *plugin = data->plugin;
MetaWindowActor *window_actor = META_WINDOW_ACTOR (data->actor);
ActorPrivate *apriv = get_actor_private (window_actor);
MutterPlugin *plugin = data->plugin;
MutterWindow *mc_window = MUTTER_WINDOW (data->actor);
ActorPrivate *apriv = get_actor_private (mc_window);
apriv->tml_destroy = NULL;
meta_plugin_destroy_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window,
MUTTER_PLUGIN_DESTROY);
}
/*
* Simple TV-out like effect.
*/
static void
destroy (MetaPlugin *plugin, MetaWindowActor *window_actor)
destroy (MutterPlugin *plugin, MutterWindow *mc_window)
{
MetaWindowType type;
ClutterActor *actor = CLUTTER_ACTOR (window_actor);
MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor);
MetaCompWindowType type;
ClutterActor *actor = CLUTTER_ACTOR (mc_window);
type = meta_window_get_window_type (meta_window);
type = mutter_window_get_window_type (mc_window);
if (type == META_WINDOW_NORMAL)
if (type == META_COMP_WINDOW_NORMAL)
{
ClutterAnimation *animation;
EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
ActorPrivate *apriv = get_actor_private (window_actor);
ActorPrivate *apriv = get_actor_private (mc_window);
clutter_actor_move_anchor_point_from_gravity (actor,
CLUTTER_GRAVITY_CENTER);
@@ -722,59 +734,64 @@ destroy (MetaPlugin *plugin, MetaWindowActor *window_actor)
data);
}
else
meta_plugin_destroy_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window,
MUTTER_PLUGIN_DESTROY);
}
static void
kill_switch_workspace (MetaPlugin *plugin)
{
MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv;
if (priv->tml_switch_workspace1)
{
clutter_timeline_stop (priv->tml_switch_workspace1);
clutter_timeline_stop (priv->tml_switch_workspace2);
g_signal_emit_by_name (priv->tml_switch_workspace1, "completed", NULL);
}
}
static void
kill_window_effects (MetaPlugin *plugin,
MetaWindowActor *window_actor)
kill_effect (MutterPlugin *plugin, MutterWindow *mc_window, gulong event)
{
ActorPrivate *apriv;
apriv = get_actor_private (window_actor);
if (event & MUTTER_PLUGIN_SWITCH_WORKSPACE)
{
MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv;
if (apriv->tml_minimize)
if (priv->tml_switch_workspace1)
{
clutter_timeline_stop (priv->tml_switch_workspace1);
clutter_timeline_stop (priv->tml_switch_workspace2);
g_signal_emit_by_name (priv->tml_switch_workspace1, "completed", NULL);
}
if (!(event & ~MUTTER_PLUGIN_SWITCH_WORKSPACE))
{
/* Workspace switch only, nothing more to do */
return;
}
}
apriv = get_actor_private (mc_window);
if ((event & MUTTER_PLUGIN_MINIMIZE) && apriv->tml_minimize)
{
clutter_timeline_stop (apriv->tml_minimize);
g_signal_emit_by_name (apriv->tml_minimize, "completed", NULL);
}
if (apriv->tml_maximize)
if ((event & MUTTER_PLUGIN_MAXIMIZE) && apriv->tml_maximize)
{
clutter_timeline_stop (apriv->tml_maximize);
g_signal_emit_by_name (apriv->tml_maximize, "completed", NULL);
}
if (apriv->tml_map)
if ((event & MUTTER_PLUGIN_MAP) && apriv->tml_map)
{
clutter_timeline_stop (apriv->tml_map);
g_signal_emit_by_name (apriv->tml_map, "completed", NULL);
}
if (apriv->tml_destroy)
if ((event & MUTTER_PLUGIN_DESTROY) && apriv->tml_destroy)
{
clutter_timeline_stop (apriv->tml_destroy);
g_signal_emit_by_name (apriv->tml_destroy, "completed", NULL);
}
}
static const MetaPluginInfo *
plugin_info (MetaPlugin *plugin)
static const MutterPluginInfo *
plugin_info (MutterPlugin *plugin)
{
MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv;
MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv;
return &priv->info;
}

View File

@@ -64,8 +64,6 @@ struct _TidyTextureFramePrivate
gfloat bottom;
CoglHandle material;
guint needs_paint : 1;
};
static void
@@ -155,7 +153,7 @@ tidy_texture_frame_unrealize (ClutterActor *self)
if (priv->material == COGL_INVALID_HANDLE)
return;
cogl_handle_unref (priv->material);
cogl_material_unref (priv->material);
priv->material = COGL_INVALID_HANDLE;
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
@@ -177,9 +175,6 @@ tidy_texture_frame_paint (ClutterActor *self)
if (G_UNLIKELY (priv->parent_texture == NULL))
return;
if (!priv->needs_paint)
return;
/* parent texture may have been hidden, so need to make sure it gets
* realized
*/
@@ -415,7 +410,7 @@ tidy_texture_frame_dispose (GObject *gobject)
if (priv->material)
{
cogl_handle_unref (priv->material);
cogl_material_unref (priv->material);
priv->material = COGL_INVALID_HANDLE;
}
@@ -613,29 +608,3 @@ tidy_texture_frame_get_frame (TidyTextureFrame *frame,
if (left)
*left = priv->left;
}
/**
* tidy_texture_frame_set_needs_paint:
* @frame: a #TidyTextureframe
* @needs_paint: if %FALSE, the paint will be skipped
*
* Provides a hint to the texture frame that it is totally obscured
* and doesn't need to be painted. This would typically be called
* by a parent container if it detects the condition prior to
* painting its children and then unset afterwards.
*
* Since it is not supposed to have any effect on display, it does
* not queue a repaint.
*/
void
tidy_texture_frame_set_needs_paint (TidyTextureFrame *frame,
gboolean needs_paint)
{
TidyTextureFramePrivate *priv;
g_return_if_fail (TIDY_IS_TEXTURE_FRAME (frame));
priv = frame->priv;
priv->needs_paint = needs_paint;
}

View File

@@ -76,9 +76,6 @@ void tidy_texture_frame_get_frame (TidyTextureFrame *frame,
gfloat *bottom,
gfloat *left);
void tidy_texture_frame_set_needs_paint (TidyTextureFrame *frame,
gboolean needs_paint);
G_END_DECLS
#endif /* _HAVE_TIDY_TEXTURE_FRAME_H */

View File

@@ -1,350 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#define _GNU_SOURCE /* For M_PI */
#include <math.h>
#include "compositor-private.h"
#include "shadow.h"
#include "tidy/tidy-texture-frame.h"
#define SHADOW_RADIUS 8
#define SHADOW_OPACITY 0.9
#define SHADOW_OFFSET_X (SHADOW_RADIUS)
#define SHADOW_OFFSET_Y (SHADOW_RADIUS)
#define MAX_TILE_SZ 8 /* Must be <= shaddow radius */
#define TILE_WIDTH (3*MAX_TILE_SZ)
#define TILE_HEIGHT (3*MAX_TILE_SZ)
static unsigned char* shadow_gaussian_make_tile (void);
ClutterActor *
meta_create_shadow_frame (MetaCompositor *compositor)
{
ClutterActor *frame;
if (!compositor->shadow_src)
{
guchar *data;
data = shadow_gaussian_make_tile ();
compositor->shadow_src = clutter_texture_new ();
clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (compositor->shadow_src),
data,
TRUE,
TILE_WIDTH,
TILE_HEIGHT,
TILE_WIDTH*4,
4,
0,
NULL);
g_free (data);
}
frame = tidy_texture_frame_new (CLUTTER_TEXTURE (compositor->shadow_src),
MAX_TILE_SZ,
MAX_TILE_SZ,
MAX_TILE_SZ,
MAX_TILE_SZ);
clutter_actor_set_position (frame,
SHADOW_OFFSET_X , SHADOW_OFFSET_Y);
return frame;
}
typedef struct GaussianMap
{
int size;
double * data;
} GaussianMap;
static double
gaussian (double r, double x, double y)
{
return ((1 / (sqrt (2 * M_PI * r))) *
exp ((- (x * x + y * y)) / (2 * r * r)));
}
static GaussianMap *
make_gaussian_map (double r)
{
GaussianMap *c;
int size = ((int) ceil ((r * 3)) + 1) & ~1;
int center = size / 2;
int x, y;
double t = 0.0;
double g;
c = g_malloc (sizeof (GaussianMap) + size * size * sizeof (double));
c->size = size;
c->data = (double *) (c + 1);
for (y = 0; y < size; y++)
for (x = 0; x < size; x++)
{
g = gaussian (r, (double) (x - center), (double) (y - center));
t += g;
c->data[y * size + x] = g;
}
for (y = 0; y < size; y++)
for (x = 0; x < size; x++)
c->data[y*size + x] /= t;
return c;
}
static unsigned char
sum_gaussian (GaussianMap * map, double opacity,
int x, int y, int width, int height)
{
int fx, fy;
double * g_data;
double * g_line = map->data;
int g_size = map->size;
int center = g_size / 2;
int fx_start, fx_end;
int fy_start, fy_end;
double v;
unsigned int r;
/*
* Compute set of filter values which are "in range",
* that's the set with:
* 0 <= x + (fx-center) && x + (fx-center) < width &&
* 0 <= y + (fy-center) && y + (fy-center) < height
*
* 0 <= x + (fx - center) x + fx - center < width
* center - x <= fx fx < width + center - x
*/
fx_start = center - x;
if (fx_start < 0)
fx_start = 0;
fx_end = width + center - x;
if (fx_end > g_size)
fx_end = g_size;
fy_start = center - y;
if (fy_start < 0)
fy_start = 0;
fy_end = height + center - y;
if (fy_end > g_size)
fy_end = g_size;
g_line = g_line + fy_start * g_size + fx_start;
v = 0;
for (fy = fy_start; fy < fy_end; fy++)
{
g_data = g_line;
g_line += g_size;
for (fx = fx_start; fx < fx_end; fx++)
v += *g_data++;
}
if (v > 1)
v = 1;
v *= (opacity * 255.0);
r = (unsigned int) v;
return (unsigned char) r;
}
static unsigned char *
shadow_gaussian_make_tile ()
{
unsigned char * data;
int size;
int center;
int x, y;
unsigned char d;
int pwidth, pheight;
double opacity = SHADOW_OPACITY;
static GaussianMap * gaussian_map = NULL;
struct _mypixel
{
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
} * _d;
if (!gaussian_map)
gaussian_map =
make_gaussian_map (SHADOW_RADIUS);
size = gaussian_map->size;
center = size / 2;
/* Top & bottom */
pwidth = MAX_TILE_SZ;
pheight = MAX_TILE_SZ;
data = g_malloc0 (4 * TILE_WIDTH * TILE_HEIGHT);
_d = (struct _mypixel*) data;
/* N */
for (y = 0; y < pheight; y++)
{
d = sum_gaussian (gaussian_map, opacity,
center, y - center,
TILE_WIDTH, TILE_HEIGHT);
for (x = 0; x < pwidth; x++)
{
_d[y*3*pwidth + x + pwidth].r = 0;
_d[y*3*pwidth + x + pwidth].g = 0;
_d[y*3*pwidth + x + pwidth].b = 0;
_d[y*3*pwidth + x + pwidth].a = d;
}
}
/* S */
pwidth = MAX_TILE_SZ;
pheight = MAX_TILE_SZ;
for (y = 0; y < pheight; y++)
{
d = sum_gaussian (gaussian_map, opacity,
center, y - center,
TILE_WIDTH, TILE_HEIGHT);
for (x = 0; x < pwidth; x++)
{
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].r = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].g = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].b = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].a = d;
}
}
/* w */
pwidth = MAX_TILE_SZ;
pheight = MAX_TILE_SZ;
for (x = 0; x < pwidth; x++)
{
d = sum_gaussian (gaussian_map, opacity,
x - center, center,
TILE_WIDTH, TILE_HEIGHT);
for (y = 0; y < pheight; y++)
{
_d[y*3*pwidth + 3*pwidth*pheight + x].r = 0;
_d[y*3*pwidth + 3*pwidth*pheight + x].g = 0;
_d[y*3*pwidth + 3*pwidth*pheight + x].b = 0;
_d[y*3*pwidth + 3*pwidth*pheight + x].a = d;
}
}
/* E */
for (x = 0; x < pwidth; x++)
{
d = sum_gaussian (gaussian_map, opacity,
x - center, center,
TILE_WIDTH, TILE_HEIGHT);
for (y = 0; y < pheight; y++)
{
_d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].r = 0;
_d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].g = 0;
_d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].b = 0;
_d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].a = d;
}
}
/* NW */
pwidth = MAX_TILE_SZ;
pheight = MAX_TILE_SZ;
for (x = 0; x < pwidth; x++)
for (y = 0; y < pheight; y++)
{
d = sum_gaussian (gaussian_map, opacity,
x-center, y-center,
TILE_WIDTH, TILE_HEIGHT);
_d[y*3*pwidth + x].r = 0;
_d[y*3*pwidth + x].g = 0;
_d[y*3*pwidth + x].b = 0;
_d[y*3*pwidth + x].a = d;
}
/* SW */
for (x = 0; x < pwidth; x++)
for (y = 0; y < pheight; y++)
{
d = sum_gaussian (gaussian_map, opacity,
x-center, y-center,
TILE_WIDTH, TILE_HEIGHT);
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].r = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].g = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].b = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].a = d;
}
/* SE */
for (x = 0; x < pwidth; x++)
for (y = 0; y < pheight; y++)
{
d = sum_gaussian (gaussian_map, opacity,
x-center, y-center,
TILE_WIDTH, TILE_HEIGHT);
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) +
2*pwidth].r = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) +
2*pwidth].g = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) +
2*pwidth].b = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) +
2*pwidth].a = d;
}
/* NE */
for (x = 0; x < pwidth; x++)
for (y = 0; y < pheight; y++)
{
d = sum_gaussian (gaussian_map, opacity,
x-center, y-center,
TILE_WIDTH, TILE_HEIGHT);
_d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].r = 0;
_d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].g = 0;
_d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].b = 0;
_d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].a = d;
}
/* center */
pwidth = MAX_TILE_SZ;
pheight = MAX_TILE_SZ;
d = sum_gaussian (gaussian_map, opacity,
center, center, TILE_WIDTH, TILE_HEIGHT);
for (x = 0; x < pwidth; x++)
for (y = 0; y < pheight; y++)
{
_d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].r = 0;
_d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].g = 0;
_d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].b = 0;
_d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].a = 0;
}
return data;
}

View File

@@ -1,9 +0,0 @@
#ifndef SHADOW_H
#define SHADOW_H
#include <clutter/clutter.h>
#include "compositor.h"
ClutterActor *meta_create_shadow_frame (MetaCompositor *compositor);
#endif /* SHADOW_H */

138
src/core/alttabhandler.c Normal file
View File

@@ -0,0 +1,138 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Metacity Alt-Tab abstraction */
/*
* Copyright (C) 2009 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <config.h>
#include "alttabhandlerdefault.h"
#include "screen-private.h"
static GType handler_type = G_TYPE_INVALID;
GType meta_alt_tab_handler_default_get_type (void);
void
meta_alt_tab_handler_register (GType type)
{
handler_type = type;
}
MetaAltTabHandler *
meta_alt_tab_handler_new (MetaScreen *screen,
gboolean immediate)
{
if (handler_type == G_TYPE_INVALID)
handler_type = meta_alt_tab_handler_default_get_type ();
return g_object_new (handler_type,
"screen", screen,
"immediate", immediate,
NULL);
}
static void meta_alt_tab_handler_class_init (GObjectClass *object_class);
GType
meta_alt_tab_handler_get_type (void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
const GTypeInfo type_info =
{
sizeof (MetaAltTabHandlerInterface), /* class_size */
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc)meta_alt_tab_handler_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
0,
0, /* n_preallocs */
NULL
};
GType g_define_type_id =
g_type_register_static (G_TYPE_INTERFACE, "MetaAltTabHandler",
&type_info, 0);
g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}
static void
meta_alt_tab_handler_class_init (GObjectClass *object_class)
{
g_object_interface_install_property (object_class,
g_param_spec_object ("screen",
"Screen",
"MetaScreen this is the switcher for",
META_TYPE_SCREEN,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
g_object_interface_install_property (object_class,
g_param_spec_boolean ("immediate",
"Immediate mode",
"Whether or not to select windows immediately",
FALSE,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
}
void
meta_alt_tab_handler_add_window (MetaAltTabHandler *handler,
MetaWindow *window)
{
META_ALT_TAB_HANDLER_GET_INTERFACE (handler)->add_window (handler, window);
}
void
meta_alt_tab_handler_show (MetaAltTabHandler *handler,
MetaWindow *initial_selection)
{
META_ALT_TAB_HANDLER_GET_INTERFACE (handler)->show (handler,
initial_selection);
}
void
meta_alt_tab_handler_destroy (MetaAltTabHandler *handler)
{
META_ALT_TAB_HANDLER_GET_INTERFACE (handler)->destroy (handler);
}
void
meta_alt_tab_handler_forward (MetaAltTabHandler *handler)
{
META_ALT_TAB_HANDLER_GET_INTERFACE (handler)->forward (handler);
}
void
meta_alt_tab_handler_backward (MetaAltTabHandler *handler)
{
META_ALT_TAB_HANDLER_GET_INTERFACE (handler)->backward (handler);
}
MetaWindow *
meta_alt_tab_handler_get_selected (MetaAltTabHandler *handler)
{
return META_ALT_TAB_HANDLER_GET_INTERFACE (handler)->get_selected (handler);
}

View File

@@ -0,0 +1,223 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Metacity Alt-Tab abstraction: default implementation */
/*
* Copyright (C) 2009 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <config.h>
#include "alttabhandlerdefault.h"
#include "frame-private.h"
#include "window-private.h"
static void meta_alt_tab_handler_default_interface_init (MetaAltTabHandlerInterface *handler_iface);
G_DEFINE_TYPE_WITH_CODE (MetaAltTabHandlerDefault, meta_alt_tab_handler_default, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (META_TYPE_ALT_TAB_HANDLER,
meta_alt_tab_handler_default_interface_init))
enum {
PROP_SCREEN = 1,
PROP_IMMEDIATE
};
static void
meta_alt_tab_handler_default_init (MetaAltTabHandlerDefault *hd)
{
hd->entries = g_array_new (FALSE, FALSE, sizeof (MetaTabEntry));
}
static void
meta_alt_tab_handler_default_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaAltTabHandlerDefault *hd = META_ALT_TAB_HANDLER_DEFAULT (object);
switch (prop_id)
{
case PROP_SCREEN:
hd->screen = g_value_get_object (value);
break;
case PROP_IMMEDIATE:
hd->immediate_mode = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_alt_tab_handler_default_finalize (GObject *object)
{
MetaAltTabHandlerDefault *hd = META_ALT_TAB_HANDLER_DEFAULT (object);
g_array_free (hd->entries, TRUE);
if (hd->tab_popup)
meta_ui_tab_popup_free (hd->tab_popup);
G_OBJECT_CLASS (meta_alt_tab_handler_default_parent_class)->finalize (object);
}
static void
meta_alt_tab_handler_default_add_window (MetaAltTabHandler *handler,
MetaWindow *window)
{
MetaAltTabHandlerDefault *hd = META_ALT_TAB_HANDLER_DEFAULT (handler);
MetaTabEntry entry;
MetaRectangle r;
entry.key = (MetaTabEntryKey) window;
entry.title = window->title;
entry.icon = window->icon;
entry.blank = FALSE;
entry.hidden = !meta_window_showing_on_its_workspace (window);
entry.demands_attention = window->wm_state_demands_attention;
if (hd->immediate_mode || !entry.hidden ||
!meta_window_get_icon_geometry (window, &r))
meta_window_get_outer_rect (window, &r);
entry.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 (!entry.hidden &&
window->frame && window->frame->bottom_height > 0 &&
window->frame->child_y >= window->frame->bottom_height)
entry.inner_rect.y = window->frame->bottom_height;
else
entry.inner_rect.y = OUTLINE_WIDTH;
/* Bottom side */
if (!entry.hidden &&
window->frame && window->frame->bottom_height != 0)
entry.inner_rect.height = r.height
- entry.inner_rect.y - window->frame->bottom_height;
else
entry.inner_rect.height = r.height
- entry.inner_rect.y - OUTLINE_WIDTH;
/* Left side */
if (!entry.hidden && window->frame && window->frame->child_x != 0)
entry.inner_rect.x = window->frame->child_x;
else
entry.inner_rect.x = OUTLINE_WIDTH;
/* Right side */
if (!entry.hidden &&
window->frame && window->frame->right_width != 0)
entry.inner_rect.width = r.width
- entry.inner_rect.x - window->frame->right_width;
else
entry.inner_rect.width = r.width
- entry.inner_rect.x - OUTLINE_WIDTH;
g_array_append_val (hd->entries, entry);
}
static void
meta_alt_tab_handler_default_show (MetaAltTabHandler *handler,
MetaWindow *initial_selection)
{
MetaAltTabHandlerDefault *hd = META_ALT_TAB_HANDLER_DEFAULT (handler);
if (hd->tab_popup)
return;
hd->tab_popup = meta_ui_tab_popup_new ((MetaTabEntry *)hd->entries->data,
hd->screen->number,
hd->entries->len,
5, /* FIXME */
TRUE);
meta_ui_tab_popup_select (hd->tab_popup, (MetaTabEntryKey) initial_selection);
meta_ui_tab_popup_set_showing (hd->tab_popup, !hd->immediate_mode);
}
static void
meta_alt_tab_handler_default_destroy (MetaAltTabHandler *handler)
{
MetaAltTabHandlerDefault *hd = META_ALT_TAB_HANDLER_DEFAULT (handler);
if (hd->tab_popup)
{
meta_ui_tab_popup_free (hd->tab_popup);
hd->tab_popup = NULL;
}
}
static void
meta_alt_tab_handler_default_forward (MetaAltTabHandler *handler)
{
MetaAltTabHandlerDefault *hd = META_ALT_TAB_HANDLER_DEFAULT (handler);
if (hd->tab_popup)
meta_ui_tab_popup_forward (hd->tab_popup);
}
static void
meta_alt_tab_handler_default_backward (MetaAltTabHandler *handler)
{
MetaAltTabHandlerDefault *hd = META_ALT_TAB_HANDLER_DEFAULT (handler);
if (hd->tab_popup)
meta_ui_tab_popup_backward (hd->tab_popup);
}
static MetaWindow *
meta_alt_tab_handler_default_get_selected (MetaAltTabHandler *handler)
{
MetaAltTabHandlerDefault *hd = META_ALT_TAB_HANDLER_DEFAULT (handler);
if (hd->tab_popup)
return (MetaWindow *)meta_ui_tab_popup_get_selected (hd->tab_popup);
else
return NULL;
}
static void
meta_alt_tab_handler_default_class_init (MetaAltTabHandlerDefaultClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = meta_alt_tab_handler_default_set_property;
object_class->finalize = meta_alt_tab_handler_default_finalize;
g_object_class_override_property (object_class, PROP_SCREEN, "screen");
g_object_class_override_property (object_class, PROP_IMMEDIATE, "immediate");
}
static void
meta_alt_tab_handler_default_interface_init (MetaAltTabHandlerInterface *handler_iface)
{
handler_iface->add_window = meta_alt_tab_handler_default_add_window;
handler_iface->show = meta_alt_tab_handler_default_show;
handler_iface->destroy = meta_alt_tab_handler_default_destroy;
handler_iface->forward = meta_alt_tab_handler_default_forward;
handler_iface->backward = meta_alt_tab_handler_default_backward;
handler_iface->get_selected = meta_alt_tab_handler_default_get_selected;
}

View File

@@ -52,9 +52,6 @@
#include "bell.h"
#include "screen-private.h"
#include "prefs.h"
#ifdef HAVE_LIBCANBERRA
#include <canberra-gtk.h>
#endif
/**
* Flashes one entire screen. This is done by making a window the size of the
@@ -231,18 +228,18 @@ bell_flash_window_frame (MetaWindow *window)
*/
static void
bell_flash_frame (MetaDisplay *display,
XkbAnyEvent *xkb_ev)
XkbAnyEvent *xkb_ev)
{
XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent *) xkb_ev;
MetaWindow *window;
g_assert (xkb_ev->xkb_type == XkbBellNotify);
window = meta_display_lookup_x_window (display, xkb_bell_event->window);
if (!window && (display->focus_window))
if (!window && (display->focus_window) && (display->focus_window->frame))
{
window = display->focus_window;
}
if (window && window->frame)
if (window)
{
bell_flash_window_frame (window);
}
@@ -288,48 +285,6 @@ meta_bell_notify (MetaDisplay *display,
/* flash something */
if (meta_prefs_get_visual_bell ())
bell_visual_notify (display, xkb_ev);
#ifdef HAVE_LIBCANBERRA
if (meta_prefs_bell_is_audible ())
{
ca_proplist *p;
XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent*) xkb_ev;
MetaWindow *window;
int res;
ca_proplist_create (&p);
ca_proplist_sets (p, CA_PROP_EVENT_ID, "bell-window-system");
ca_proplist_sets (p, CA_PROP_EVENT_DESCRIPTION, _("Bell event"));
ca_proplist_sets (p, CA_PROP_CANBERRA_CACHE_CONTROL, "permanent");
window = meta_display_lookup_x_window (display, xkb_bell_event->window);
if (!window && (display->focus_window) && (display->focus_window->frame))
window = display->focus_window;
if (window)
{
ca_proplist_sets (p, CA_PROP_WINDOW_NAME, window->title);
ca_proplist_setf (p, CA_PROP_WINDOW_X11_XID, "%lu", (unsigned long)window->xwindow);
ca_proplist_sets (p, CA_PROP_APPLICATION_NAME, window->res_name);
ca_proplist_setf (p, CA_PROP_APPLICATION_PROCESS_ID, "%d", window->net_wm_pid);
}
/* First, we try to play a real sound ... */
res = ca_context_play_full (ca_gtk_context_get (), 1, p, NULL, NULL);
ca_proplist_destroy (p);
if (res != CA_SUCCESS && res != CA_ERROR_DISABLED)
{
/* ...and in case that failed we use the classic X11 bell. */
XkbForceDeviceBell (display->xdisplay,
xkb_bell_event->device,
xkb_bell_event->bell_class,
xkb_bell_event->bell_id,
xkb_bell_event->percent);
}
}
#endif /* HAVE_LIBCANBERRA */
}
#endif /* HAVE_XKB */
@@ -337,19 +292,11 @@ void
meta_bell_set_audible (MetaDisplay *display, gboolean audible)
{
#ifdef HAVE_XKB
#ifdef HAVE_LIBCANBERRA
/* When we are playing sounds using libcanberra support, we handle the
* bell whether its an audible bell or a visible bell */
gboolean enable_system_bell = FALSE;
#else
gboolean enable_system_bell = audible;
#endif /* HAVE_LIBCANBERRA */
XkbChangeEnabledControls (display->xdisplay,
XkbUseCoreKbd,
XkbAudibleBellMask,
enable_system_bell ? XkbAudibleBellMask : 0);
#endif /* HAVE_XKB */
XkbUseCoreKbd,
XkbAudibleBellMask,
audible ? XkbAudibleBellMask : 0);
#endif
}
gboolean
@@ -376,7 +323,11 @@ meta_bell_init (MetaDisplay *display)
XkbUseCoreKbd,
XkbBellNotifyMask,
XkbBellNotifyMask);
meta_bell_set_audible (display, meta_prefs_bell_is_audible ());
XkbChangeEnabledControls (display->xdisplay,
XkbUseCoreKbd,
XkbAudibleBellMask,
meta_prefs_bell_is_audible ()
? XkbAudibleBellMask : 0);
if (visual_bell_auto_reset) {
XkbSetAutoResetControls (display->xdisplay,
XkbAudibleBellMask,

View File

@@ -1,220 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Simple box operations */
/*
* Copyright (C) 2005, 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef META_BOXES_PRIVATE_H
#define META_BOXES_PRIVATE_H
#include <glib-object.h>
#include "common.h"
#include "boxes.h"
#define BOX_LEFT(box) ((box).x) /* Leftmost pixel of rect */
#define BOX_RIGHT(box) ((box).x + (box).width) /* One pixel past right */
#define BOX_TOP(box) ((box).y) /* Topmost pixel of rect */
#define BOX_BOTTOM(box) ((box).y + (box).height) /* One pixel past bottom */
typedef enum
{
FIXED_DIRECTION_NONE = 0,
FIXED_DIRECTION_X = 1 << 0,
FIXED_DIRECTION_Y = 1 << 1,
} FixedDirections;
/* Output functions -- note that the output buffer had better be big enough:
* rect_to_string: RECT_LENGTH
* region_to_string: (RECT_LENGTH+strlen(separator_string)) *
* g_list_length (region)
* edge_to_string: EDGE_LENGTH
* edge_list_to_...: (EDGE_LENGTH+strlen(separator_string)) *
* g_list_length (edge_list)
*/
#define RECT_LENGTH 27
#define EDGE_LENGTH 37
char* meta_rectangle_to_string (const MetaRectangle *rect,
char *output);
char* meta_rectangle_region_to_string (GList *region,
const char *separator_string,
char *output);
char* meta_rectangle_edge_to_string (const MetaEdge *edge,
char *output);
char* meta_rectangle_edge_list_to_string (
GList *edge_list,
const char *separator_string,
char *output);
/* Resize old_rect to the given new_width and new_height, but store the
* result in rect. NOTE THAT THIS IS RESIZE ONLY SO IT CANNOT BE USED FOR
* A MOVERESIZE OPERATION (that simplies the routine a little bit as it
* means there's no difference between NorthWestGravity and StaticGravity.
* Also, I lied a little bit--technically, you could use it in a MoveResize
* operation if you muck with old_rect just right).
*/
void meta_rectangle_resize_with_gravity (const MetaRectangle *old_rect,
MetaRectangle *rect,
int gravity,
int new_width,
int new_height);
/* find a list of rectangles with the property that a window is contained
* in the given region if and only if it is contained in one of the
* rectangles in the list.
*
* In this case, the region is given by taking basic_rect, removing from
* it the intersections with all the rectangles in the all_struts list,
* then expanding all the rectangles in the resulting list by the given
* amounts on each side.
*
* See boxes.c for more details.
*/
GList* meta_rectangle_get_minimal_spanning_set_for_region (
const MetaRectangle *basic_rect,
const GSList *all_struts);
/* Expand all rectangles in region by the given amount on each side */
GList* meta_rectangle_expand_region (GList *region,
const int left_expand,
const int right_expand,
const int top_expand,
const int bottom_expand);
/* Same as for meta_rectangle_expand_region except that rectangles not at
* least min_x or min_y in size are not expanded in that direction
*/
GList* meta_rectangle_expand_region_conditionally (
GList *region,
const int left_expand,
const int right_expand,
const int top_expand,
const int bottom_expand,
const int min_x,
const int min_y);
/* Expand rect in direction to the size of expand_to, and then clip out any
* overlapping struts oriented orthognal to the expansion direction. (Think
* horizontal or vertical maximization)
*/
void meta_rectangle_expand_to_avoiding_struts (
MetaRectangle *rect,
const MetaRectangle *expand_to,
const MetaDirection direction,
const GSList *all_struts);
/* Free the list created by
* meta_rectangle_get_minimal_spanning_set_for_region()
* or
* meta_rectangle_find_onscreen_edges ()
* or
* meta_rectangle_find_nonintersected_monitor_edges()
*/
void meta_rectangle_free_list_and_elements (GList *filled_list);
/* could_fit_in_region determines whether one of the spanning_rects is
* big enough to contain rect. contained_in_region checks whether one
* actually contains it.
*/
gboolean meta_rectangle_could_fit_in_region (
const GList *spanning_rects,
const MetaRectangle *rect);
gboolean meta_rectangle_contained_in_region (
const GList *spanning_rects,
const MetaRectangle *rect);
gboolean meta_rectangle_overlaps_with_region (
const GList *spanning_rects,
const MetaRectangle *rect);
/* Make the rectangle small enough to fit into one of the spanning_rects,
* but make it no smaller than min_size.
*/
void meta_rectangle_clamp_to_fit_into_region (
const GList *spanning_rects,
FixedDirections fixed_directions,
MetaRectangle *rect,
const MetaRectangle *min_size);
/* Clip the rectangle so that it fits into one of the spanning_rects, assuming
* it overlaps with at least one of them
*/
void meta_rectangle_clip_to_region (const GList *spanning_rects,
FixedDirections fixed_directions,
MetaRectangle *rect);
/* Shove the rectangle into one of the spanning_rects, assuming it fits in
* one of them.
*/
void meta_rectangle_shove_into_region(
const GList *spanning_rects,
FixedDirections fixed_directions,
MetaRectangle *rect);
/* Finds the point on the line connecting (x1,y1) to (x2,y2) which is closest
* to (px, py). Useful for finding an optimal rectangle size when given a
* range between two sizes that are all candidates.
*/
void meta_rectangle_find_linepoint_closest_to_point (double x1, double y1,
double x2, double y2,
double px, double py,
double *valx, double *valy);
/***************************************************************************/
/* */
/* Switching gears to code for edges instead of just rectangles */
/* */
/***************************************************************************/
/* Return whether an edge overlaps or is adjacent to the rectangle in the
* nonzero-width dimension of the edge.
*/
gboolean meta_rectangle_edge_aligns (const MetaRectangle *rect,
const MetaEdge *edge);
/* Compare two edges, so that sorting functions can put a list of edges in
* canonical order.
*/
gint meta_rectangle_edge_cmp (gconstpointer a, gconstpointer b);
/* Compare two edges, so that sorting functions can put a list of edges in
* order. This function doesn't separate left edges first, then right edges,
* etc., but rather compares only upon location.
*/
gint meta_rectangle_edge_cmp_ignore_type (gconstpointer a, gconstpointer b);
/* Removes an parts of edges in the given list that intersect any box in the
* given rectangle list. Returns the result.
*/
GList* meta_rectangle_remove_intersections_with_boxes_from_edges (
GList *edges,
const GSList *rectangles);
/* Finds all the edges of an onscreen region, returning a GList* of
* MetaEdgeRect's.
*/
GList* meta_rectangle_find_onscreen_edges (const MetaRectangle *basic_rect,
const GSList *all_struts);
/* Finds edges between adjacent monitors which are not covered by the given
* struts.
*/
GList* meta_rectangle_find_nonintersected_monitor_edges (
const GList *monitor_rects,
const GSList *all_struts);
#endif /* META_BOXES_PRIVATE_H */

View File

@@ -26,39 +26,10 @@
* 02111-1307, USA.
*/
#include "boxes-private.h"
#include "boxes.h"
#include "util.h"
#include <X11/Xutil.h> /* Just for the definition of the various gravities */
/* It would make sense to use GSlice here, but until we clean up the
* rest of this file and the internal API to use these functions, we
* leave it using g_malloc()/g_free() for consistency.
*/
MetaRectangle *
meta_rectangle_copy (const MetaRectangle *rect)
{
return g_memdup (rect, sizeof (MetaRectangle));
}
void
meta_rectangle_free (MetaRectangle *rect)
{
g_free (rect);
}
GType
meta_rectangle_get_type (void)
{
static GType type_id = 0;
if (!type_id)
type_id = g_boxed_type_register_static (g_intern_static_string ("MetaRectangle"),
(GBoxedCopyFunc) meta_rectangle_copy,
(GBoxedFreeFunc) meta_rectangle_free);
return type_id;
}
char*
meta_rectangle_to_string (const MetaRectangle *rect,
char *output)
@@ -529,12 +500,7 @@ compare_rect_areas (gconstpointer a, gconstpointer b)
return b_area - a_area; /* positive ret value denotes b > a, ... */
}
/**
* meta_rectangle_get_minimal_spanning_set_for_region:
* @basic_rect: Input rectangle
* @all_struts: (element-type Meta.Rectangle): List of struts
*
* This function is trying to find a "minimal spanning set (of rectangles)"
/* This function is trying to find a "minimal spanning set (of rectangles)"
* for a given region.
*
* The region is given by taking basic_rect, then removing the areas
@@ -547,7 +513,10 @@ compare_rect_areas (gconstpointer a, gconstpointer b)
* the region if and only if it is contained within at least one of the
* rectangles.
*
* Returns: (transfer full) (element-type Meta.Rectangle): Minimal spanning set
* The GList* returned will be a list of (allocated) MetaRectangles.
* The list will need to be freed by calling
* meta_rectangle_free_spanning_set() on it (or by manually
* implementing that function...)
*/
GList*
meta_rectangle_get_minimal_spanning_set_for_region (
@@ -566,7 +535,7 @@ meta_rectangle_get_minimal_spanning_set_for_region (
* enough to make this worth bothering. Further, it is only called from
* workspace.c:ensure_work_areas_validated (at least as of the time of
* writing this comment), which in turn should only be called if the
* strut list changes or the screen or monitor size changes. If it ever
* strut list changes or the screen or xinerama size changes. If it ever
* does show up on profiles (most likely because people start using
* ridiculously huge numbers of partial struts), possible optimizations
* include:
@@ -680,10 +649,6 @@ meta_rectangle_get_minimal_spanning_set_for_region (
return ret;
}
/**
* meta_rectangle_expand_region: (skip)
*
*/
GList*
meta_rectangle_expand_region (GList *region,
const int left_expand,
@@ -700,10 +665,6 @@ meta_rectangle_expand_region (GList *region,
0);
}
/**
* meta_rectangle_expand_region_conditionally: (skip)
*
*/
GList*
meta_rectangle_expand_region_conditionally (GList *region,
const int left_expand,
@@ -1681,10 +1642,7 @@ fix_up_edges (MetaRectangle *rect, MetaEdge *edge,
}
}
/**
* meta_rectangle_remove_intersections_with_boxes_from_edges: (skip)
*
* This function removes intersections of edges with the rectangles from the
/* This function removes intersections of edges with the rectangles from the
* list of edges.
*/
GList*
@@ -1750,11 +1708,7 @@ meta_rectangle_remove_intersections_with_boxes_from_edges (
return edges;
}
/**
* meta_rectangle_find_onscreen_edges: (skip)
*
* This function is trying to find all the edges of an onscreen region.
*/
/* This function is trying to find all the edges of an onscreen region. */
GList*
meta_rectangle_find_onscreen_edges (const MetaRectangle *basic_rect,
const GSList *all_struts)
@@ -1837,19 +1791,15 @@ meta_rectangle_find_onscreen_edges (const MetaRectangle *basic_rect,
return ret;
}
/**
* meta_rectangle_find_nonintersected_monitor_edges: (skip)
*
*/
GList*
meta_rectangle_find_nonintersected_monitor_edges (
const GList *monitor_rects,
meta_rectangle_find_nonintersected_xinerama_edges (
const GList *xinerama_rects,
const GSList *all_struts)
{
/* This function cannot easily be merged with
* meta_rectangle_find_onscreen_edges() because real screen edges
* and strut edges both are of the type "there ain't anything
* immediately on the other side"; monitor edges are different.
* immediately on the other side"; xinerama edges are different.
*/
GList *ret;
const GList *cur;
@@ -1858,14 +1808,14 @@ meta_rectangle_find_nonintersected_monitor_edges (
/* Initialize the return list to be empty */
ret = NULL;
/* start of ret with all the edges of monitors that are adjacent to
* another monitor.
/* start of ret with all the edges of xineramas that are adjacent to
* another xinerama.
*/
cur = monitor_rects;
cur = xinerama_rects;
while (cur)
{
MetaRectangle *cur_rect = cur->data;
const GList *compare = monitor_rects;
const GList *compare = xinerama_rects;
while (compare)
{
MetaRectangle *compare_rect = compare->data;
@@ -1899,15 +1849,15 @@ meta_rectangle_find_nonintersected_monitor_edges (
/* If the rectangles really are adjacent */
if (x != INT_MIN)
{
/* We need a left edge for the monitor on the right, and
* a right edge for the monitor on the left. Just fill
/* We need a left edge for the xinerama on the right, and
* a right edge for the xinerama on the left. Just fill
* up the edges and stick 'em on the list.
*/
MetaEdge *new_edge = g_new (MetaEdge, 1);
new_edge->rect = meta_rect (x, y, width, height);
new_edge->side_type = side_type;
new_edge->edge_type = META_EDGE_MONITOR;
new_edge->edge_type = META_EDGE_XINERAMA;
ret = g_list_prepend (ret, new_edge);
}
@@ -1942,15 +1892,15 @@ meta_rectangle_find_nonintersected_monitor_edges (
/* If the rectangles really are adjacent */
if (y != INT_MIN)
{
/* We need a top edge for the monitor on the bottom, and
* a bottom edge for the monitor on the top. Just fill
/* We need a top edge for the xinerama on the bottom, and
* a bottom edge for the xinerama on the top. Just fill
* up the edges and stick 'em on the list.
*/
MetaEdge *new_edge = g_new (MetaEdge, 1);
new_edge->rect = meta_rect (x, y, width, height);
new_edge->side_type = side_type;
new_edge->edge_type = META_EDGE_MONITOR;
new_edge->edge_type = META_EDGE_XINERAMA;
ret = g_list_prepend (ret, new_edge);
}

View File

@@ -24,11 +24,9 @@
*/
#include <config.h>
#include "boxes-private.h"
#include "constraints.h"
#include "workspace-private.h"
#include "place.h"
#include "prefs.h"
#include <stdlib.h>
#include <math.h>
@@ -95,11 +93,10 @@ typedef enum
{
PRIORITY_MINIMUM = 0, /* Dummy value used for loop start = min(all priorities) */
PRIORITY_ASPECT_RATIO = 0,
PRIORITY_ENTIRELY_VISIBLE_ON_SINGLE_MONITOR = 0,
PRIORITY_ENTIRELY_VISIBLE_ON_SINGLE_XINERAMA = 0,
PRIORITY_ENTIRELY_VISIBLE_ON_WORKAREA = 1,
PRIORITY_SIZE_HINTS_INCREMENTS = 1,
PRIORITY_MAXIMIZATION = 2,
PRIORITY_TILING = 2,
PRIORITY_FULLSCREEN = 2,
PRIORITY_SIZE_HINTS_LIMITS = 3,
PRIORITY_TITLEBAR_VISIBLE = 4,
@@ -130,30 +127,23 @@ typedef struct
int resize_gravity;
FixedDirections fixed_directions;
/* work_area_monitor - current monitor region minus struts
* entire_monitor - current monitor, including strut regions
/* work_area_xinerama - current xinerama region minus struts
* entire_xinerama - current xienrama, including strut regions
*/
MetaRectangle work_area_monitor;
MetaRectangle entire_monitor;
MetaRectangle work_area_xinerama;
MetaRectangle entire_xinerama;
/* Spanning rectangles for the non-covered (by struts) region of the
* screen and also for just the current monitor
* screen and also for just the current xinerama
*/
GList *usable_screen_region;
GList *usable_monitor_region;
GList *usable_xinerama_region;
} ConstraintInfo;
static gboolean constrain_modal_dialog (MetaWindow *window,
ConstraintInfo *info,
ConstraintPriority priority,
gboolean check_only);
static gboolean constrain_maximization (MetaWindow *window,
ConstraintInfo *info,
ConstraintPriority priority,
gboolean check_only);
static gboolean constrain_tiling (MetaWindow *window,
ConstraintInfo *info,
ConstraintPriority priority,
gboolean check_only);
static gboolean constrain_fullscreen (MetaWindow *window,
ConstraintInfo *info,
ConstraintPriority priority,
@@ -170,7 +160,7 @@ static gboolean constrain_aspect_ratio (MetaWindow *window,
ConstraintInfo *info,
ConstraintPriority priority,
gboolean check_only);
static gboolean constrain_to_single_monitor (MetaWindow *window,
static gboolean constrain_to_single_xinerama (MetaWindow *window,
ConstraintInfo *info,
ConstraintPriority priority,
gboolean check_only);
@@ -219,14 +209,12 @@ typedef struct {
} Constraint;
static const Constraint all_constraints[] = {
{constrain_modal_dialog, "constrain_modal_dialog"},
{constrain_maximization, "constrain_maximization"},
{constrain_tiling, "constrain_tiling"},
{constrain_fullscreen, "constrain_fullscreen"},
{constrain_size_increments, "constrain_size_increments"},
{constrain_size_limits, "constrain_size_limits"},
{constrain_aspect_ratio, "constrain_aspect_ratio"},
{constrain_to_single_monitor, "constrain_to_single_monitor"},
{constrain_to_single_xinerama, "constrain_to_single_xinerama"},
{constrain_fully_onscreen, "constrain_fully_onscreen"},
{constrain_titlebar_visible, "constrain_titlebar_visible"},
{constrain_partially_onscreen, "constrain_partially_onscreen"},
@@ -323,7 +311,7 @@ meta_window_constrain (MetaWindow *window,
*new = info.current;
/* We may need to update window->require_fully_onscreen,
* window->require_on_single_monitor, and perhaps other quantities
* window->require_on_single_xinerama, and perhaps other quantities
* if this was a user move or user move-and-resize operation.
*/
update_onscreen_requirements (window, &info);
@@ -345,7 +333,7 @@ setup_constraint_info (ConstraintInfo *info,
const MetaRectangle *orig,
MetaRectangle *new)
{
const MetaMonitorInfo *monitor_info;
const MetaXineramaScreenInfo *xinerama_info;
MetaWorkspace *cur_workspace;
info->orig = *orig;
@@ -399,15 +387,15 @@ setup_constraint_info (ConstraintInfo *info,
if (!info->is_user_action)
info->fixed_directions = FIXED_DIRECTION_NONE;
monitor_info =
meta_screen_get_monitor_for_rect (window->screen, &info->current);
meta_window_get_work_area_for_monitor (window,
monitor_info->number,
&info->work_area_monitor);
xinerama_info =
meta_screen_get_xinerama_for_rect (window->screen, &info->current);
meta_window_get_work_area_for_xinerama (window,
xinerama_info->number,
&info->work_area_xinerama);
if (!window->fullscreen || window->fullscreen_monitors[0] == -1)
{
info->entire_monitor = monitor_info->rect;
info->entire_xinerama = xinerama_info->rect;
}
else
{
@@ -415,29 +403,28 @@ setup_constraint_info (ConstraintInfo *info,
long monitor;
monitor = window->fullscreen_monitors[i];
info->entire_monitor =
window->screen->monitor_infos[monitor].rect;
info->entire_xinerama =
window->screen->xinerama_infos[monitor].rect;
for (i = 1; i <= 3; i++)
{
monitor = window->fullscreen_monitors[i];
meta_rectangle_union (&info->entire_monitor,
&window->screen->monitor_infos[monitor].rect,
&info->entire_monitor);
meta_rectangle_union (&info->entire_xinerama,
&window->screen->xinerama_infos[monitor].rect,
&info->entire_xinerama);
}
}
cur_workspace = window->screen->active_workspace;
info->usable_screen_region =
meta_workspace_get_onscreen_region (cur_workspace);
info->usable_monitor_region =
meta_workspace_get_onmonitor_region (cur_workspace,
monitor_info->number);
info->usable_xinerama_region =
meta_workspace_get_onxinerama_region (cur_workspace,
xinerama_info->number);
/* Workaround braindead legacy apps that don't know how to
* fullscreen themselves properly.
*/
if (meta_prefs_get_force_fullscreen() &&
meta_rectangle_equal (new, &monitor_info->rect) &&
if (meta_rectangle_equal (new, &xinerama_info->rect) &&
window->has_fullscreen_func &&
!window->fullscreen)
{
@@ -461,8 +448,8 @@ setup_constraint_info (ConstraintInfo *info,
" is_user_action : %s\n"
" resize_gravity : %s\n"
" fixed_directions: %s\n"
" work_area_monitor: %d,%d +%d,%d\n"
" entire_monitor : %d,%d +%d,%d\n",
" work_area_xinerama: %d,%d +%d,%d\n"
" entire_xinerama : %d,%d +%d,%d\n",
info->orig.x, info->orig.y, info->orig.width, info->orig.height,
info->current.x, info->current.y,
info->current.width, info->current.height,
@@ -478,11 +465,11 @@ setup_constraint_info (ConstraintInfo *info,
(info->fixed_directions == FIXED_DIRECTION_X) ? "X fixed" :
(info->fixed_directions == FIXED_DIRECTION_Y) ? "Y fixed" :
"Freakin' Invalid Stupid",
info->work_area_monitor.x, info->work_area_monitor.y,
info->work_area_monitor.width,
info->work_area_monitor.height,
info->entire_monitor.x, info->entire_monitor.y,
info->entire_monitor.width, info->entire_monitor.height);
info->work_area_xinerama.x, info->work_area_xinerama.y,
info->work_area_xinerama.width,
info->work_area_xinerama.height,
info->entire_xinerama.x, info->entire_xinerama.y,
info->entire_xinerama.width, info->entire_xinerama.height);
}
static void
@@ -506,25 +493,25 @@ place_window_if_needed(MetaWindow *window,
{
MetaRectangle placed_rect = info->orig;
MetaWorkspace *cur_workspace;
const MetaMonitorInfo *monitor_info;
const MetaXineramaScreenInfo *xinerama_info;
meta_window_place (window, info->fgeom, info->orig.x, info->orig.y,
&placed_rect.x, &placed_rect.y);
did_placement = TRUE;
/* placing the window may have changed the monitor. Find the
* new monitor and update the ConstraintInfo
/* placing the window may have changed the xinerama. Find the
* new xinerama and update the ConstraintInfo
*/
monitor_info =
meta_screen_get_monitor_for_rect (window->screen, &placed_rect);
info->entire_monitor = monitor_info->rect;
meta_window_get_work_area_for_monitor (window,
monitor_info->number,
&info->work_area_monitor);
xinerama_info =
meta_screen_get_xinerama_for_rect (window->screen, &placed_rect);
info->entire_xinerama = xinerama_info->rect;
meta_window_get_work_area_for_xinerama (window,
xinerama_info->number,
&info->work_area_xinerama);
cur_workspace = window->screen->active_workspace;
info->usable_monitor_region =
meta_workspace_get_onmonitor_region (cur_workspace,
monitor_info->number);
info->usable_xinerama_region =
meta_workspace_get_onxinerama_region (cur_workspace,
xinerama_info->number);
info->current.x = placed_rect.x;
@@ -539,23 +526,22 @@ place_window_if_needed(MetaWindow *window,
if (window->placed || did_placement)
{
if (window->maximize_horizontally_after_placement ||
window->maximize_vertically_after_placement ||
window->fullscreen_after_placement)
window->maximize_vertically_after_placement)
{
/* define a sane saved_rect so that the user can unmaximize or
* make unfullscreen to something reasonable.
/* define a sane saved_rect so that the user can unmaximize to
* something reasonable.
*/
if (info->current.width >= info->work_area_monitor.width)
if (info->current.width >= info->work_area_xinerama.width)
{
info->current.width = .75 * info->work_area_monitor.width;
info->current.x = info->work_area_monitor.x +
.125 * info->work_area_monitor.width;
info->current.width = .75 * info->work_area_xinerama.width;
info->current.x = info->work_area_xinerama.x +
.125 * info->work_area_xinerama.width;
}
if (info->current.height >= info->work_area_monitor.height)
if (info->current.height >= info->work_area_xinerama.height)
{
info->current.height = .75 * info->work_area_monitor.height;
info->current.y = info->work_area_monitor.y +
.083 * info->work_area_monitor.height;
info->current.height = .75 * info->work_area_xinerama.height;
info->current.y = info->work_area_xinerama.y +
.083 * info->work_area_xinerama.height;
}
if (window->maximize_horizontally_after_placement ||
@@ -570,15 +556,6 @@ place_window_if_needed(MetaWindow *window,
if (window->frame && !window->fullscreen)
meta_frame_calc_geometry (window->frame, info->fgeom);
if (window->fullscreen_after_placement)
{
window->saved_rect = info->current;
window->fullscreen = TRUE;
window->fullscreen_after_placement = FALSE;
g_object_notify (G_OBJECT (window), "fullscreen");
}
window->maximize_horizontally_after_placement = FALSE;
window->maximize_vertically_after_placement = FALSE;
}
@@ -612,7 +589,7 @@ update_onscreen_requirements (MetaWindow *window,
return;
/* USABILITY NOTE: Naturally, I only want the require_fully_onscreen,
* require_on_single_monitor, and require_titlebar_visible flags to
* require_on_single_xinerama, and require_titlebar_visible flags to
* *become false* due to user interactions (which is allowed since
* certain constraints are ignored for user interactions regardless of
* the setting of these flags). However, whether to make these flags
@@ -626,7 +603,7 @@ update_onscreen_requirements (MetaWindow *window,
* problematic case but this may need to be revisited.
*/
/* The require onscreen/on-single-monitor and titlebar_visible
/* The require onscreen/on-single-xinerama and titlebar_visible
* stuff is relative to the outer window, not the inner
*/
extend_by_frame (&info->current, info->fgeom);
@@ -645,17 +622,17 @@ update_onscreen_requirements (MetaWindow *window,
window->require_fully_onscreen ? "TRUE" : "FALSE");
/* Update whether we want future constraint runs to require the
* window to be on a single monitor.
* window to be on a single xinerama.
*/
old = window->require_on_single_monitor;
window->require_on_single_monitor =
meta_rectangle_contained_in_region (info->usable_monitor_region,
old = window->require_on_single_xinerama;
window->require_on_single_xinerama =
meta_rectangle_contained_in_region (info->usable_xinerama_region,
&info->current);
if (old ^ window->require_on_single_monitor)
if (old ^ window->require_on_single_xinerama)
meta_topic (META_DEBUG_GEOMETRY,
"require_on_single_monitor for %s toggled to %s\n",
"require_on_single_xinerama for %s toggled to %s\n",
window->desc,
window->require_on_single_monitor ? "TRUE" : "FALSE");
window->require_on_single_xinerama ? "TRUE" : "FALSE");
/* Update whether we want future constraint runs to require the
* titlebar to be visible.
@@ -723,62 +700,11 @@ get_size_limits (const MetaWindow *window,
min_size->width += fw;
min_size->height += fh;
/* Do check to avoid overflow (e.g. max_size->width & max_size->height
* may be set to G_MAXINT by meta_set_normal_hints()).
*/
if (max_size->width < (G_MAXINT - fw))
max_size->width += fw;
else
max_size->width = G_MAXINT;
if (max_size->height < (G_MAXINT - fh))
max_size->height += fh;
else
max_size->height = G_MAXINT;
max_size->width += fw;
max_size->height += fh;
}
}
static gboolean
constrain_modal_dialog (MetaWindow *window,
ConstraintInfo *info,
ConstraintPriority priority,
gboolean check_only)
{
int x, y;
MetaWindow *parent = meta_window_get_transient_for (window);
gboolean constraint_already_satisfied;
if (!meta_prefs_get_attach_modal_dialogs ())
return TRUE;
if (window->type != META_WINDOW_MODAL_DIALOG || !parent || parent == window)
return TRUE;
x = parent->rect.x + (parent->rect.width / 2 - info->current.width / 2);
y = 0;
if (parent->frame)
{
MetaFrameGeometry fgeom;
x += parent->frame->rect.x;
y += parent->frame->rect.y;
meta_frame_calc_geometry (parent->frame, &fgeom);
y += fgeom.top_height;
y += info->fgeom->top_height;
}
else
y = parent->rect.y + info->fgeom->top_height;
constraint_already_satisfied = (x == info->current.x) && (y == info->current.y);
if (check_only || constraint_already_satisfied)
return constraint_already_satisfied;
info->current.y = y;
info->current.x = x;
return TRUE;
}
static gboolean
constrain_maximization (MetaWindow *window,
ConstraintInfo *info,
@@ -795,13 +721,12 @@ constrain_maximization (MetaWindow *window,
return TRUE;
/* Determine whether constraint applies; exit if it doesn't */
if ((!window->maximized_horizontally && !window->maximized_vertically) ||
META_WINDOW_TILED (window))
if (!window->maximized_horizontally && !window->maximized_vertically)
return TRUE;
/* Calculate target_size = maximized size of (window + frame) */
if (window->maximized_horizontally && window->maximized_vertically)
target_size = info->work_area_monitor;
target_size = info->work_area_xinerama;
else
{
/* Amount of maximization possible in a single direction depends
@@ -823,7 +748,7 @@ constrain_maximization (MetaWindow *window,
target_size = info->current;
extend_by_frame (&target_size, info->fgeom);
meta_rectangle_expand_to_avoiding_struts (&target_size,
&info->entire_monitor,
&info->entire_xinerama,
direction,
active_workspace_struts);
}
@@ -864,66 +789,13 @@ constrain_maximization (MetaWindow *window,
return TRUE;
}
static gboolean
constrain_tiling (MetaWindow *window,
ConstraintInfo *info,
ConstraintPriority priority,
gboolean check_only)
{
MetaRectangle target_size;
MetaRectangle min_size, max_size;
gboolean hminbad, vminbad;
gboolean horiz_equal, vert_equal;
gboolean constraint_already_satisfied;
if (priority > PRIORITY_TILING)
return TRUE;
/* Determine whether constraint applies; exit if it doesn't */
if (!META_WINDOW_TILED (window))
return TRUE;
/* Calculate target_size - as the tile previews need this as well, we
* use an external function for the actual calculation
*/
meta_window_get_current_tile_area (window, &target_size);
unextend_by_frame (&target_size, info->fgeom);
/* Check min size constraints; max size constraints are ignored as for
* maximized windows.
*/
get_size_limits (window, info->fgeom, FALSE, &min_size, &max_size);
hminbad = target_size.width < min_size.width;
vminbad = target_size.height < min_size.height;
if (hminbad || vminbad)
return TRUE;
/* Determine whether constraint is already satisfied; exit if it is */
horiz_equal = target_size.x == info->current.x &&
target_size.width == info->current.width;
vert_equal = target_size.y == info->current.y &&
target_size.height == info->current.height;
constraint_already_satisfied = horiz_equal && vert_equal;
if (check_only || constraint_already_satisfied)
return constraint_already_satisfied;
/*** Enforce constraint ***/
info->current.x = target_size.x;
info->current.width = target_size.width;
info->current.y = target_size.y;
info->current.height = target_size.height;
return TRUE;
}
static gboolean
constrain_fullscreen (MetaWindow *window,
ConstraintInfo *info,
ConstraintPriority priority,
gboolean check_only)
{
MetaRectangle min_size, max_size, monitor;
MetaRectangle min_size, max_size, xinerama;
gboolean too_big, too_small, constraint_already_satisfied;
if (priority > PRIORITY_FULLSCREEN)
@@ -933,22 +805,22 @@ constrain_fullscreen (MetaWindow *window,
if (!window->fullscreen)
return TRUE;
monitor = info->entire_monitor;
xinerama = info->entire_xinerama;
get_size_limits (window, info->fgeom, FALSE, &min_size, &max_size);
too_big = !meta_rectangle_could_fit_rect (&monitor, &min_size);
too_small = !meta_rectangle_could_fit_rect (&max_size, &monitor);
too_big = !meta_rectangle_could_fit_rect (&xinerama, &min_size);
too_small = !meta_rectangle_could_fit_rect (&max_size, &xinerama);
if (too_big || too_small)
return TRUE;
/* Determine whether constraint is already satisfied; exit if it is */
constraint_already_satisfied =
meta_rectangle_equal (&info->current, &monitor);
meta_rectangle_equal (&info->current, &xinerama);
if (check_only || constraint_already_satisfied)
return constraint_already_satisfied;
/*** Enforce constraint ***/
info->current = monitor;
info->current = xinerama;
return TRUE;
}
@@ -968,7 +840,7 @@ constrain_size_increments (MetaWindow *window,
/* Determine whether constraint applies; exit if it doesn't */
if (META_WINDOW_MAXIMIZED (window) || window->fullscreen ||
META_WINDOW_TILED (window) || info->action_type == ACTION_MOVE)
info->action_type == ACTION_MOVE)
return TRUE;
/* Determine whether constraint is already satisfied; exit if it is */
@@ -1099,7 +971,7 @@ constrain_aspect_ratio (MetaWindow *window,
constraints_are_inconsistent = minr > maxr;
if (constraints_are_inconsistent ||
META_WINDOW_MAXIMIZED (window) || window->fullscreen ||
META_WINDOW_TILED (window) || info->action_type == ACTION_MOVE)
info->action_type == ACTION_MOVE)
return TRUE;
/* Determine whether constraint is already satisfied; exit if it is. We
@@ -1210,7 +1082,7 @@ constrain_aspect_ratio (MetaWindow *window,
}
static gboolean
do_screen_and_monitor_relative_constraints (
do_screen_and_xinerama_relative_constraints (
MetaWindow *window,
GList *region_spanning_rectangles,
ConstraintInfo *info,
@@ -1226,7 +1098,7 @@ do_screen_and_monitor_relative_constraints (
char spanning_region[1 + 28 * g_list_length (region_spanning_rectangles)];
meta_topic (META_DEBUG_GEOMETRY,
"screen/monitor constraint; region_spanning_rectangles: %s\n",
"screen/xinerama constraint; region_spanning_rectangles: %s\n",
meta_rectangle_region_to_string (region_spanning_rectangles, ", ",
spanning_region));
}
@@ -1284,32 +1156,32 @@ do_screen_and_monitor_relative_constraints (
}
static gboolean
constrain_to_single_monitor (MetaWindow *window,
ConstraintInfo *info,
ConstraintPriority priority,
gboolean check_only)
constrain_to_single_xinerama (MetaWindow *window,
ConstraintInfo *info,
ConstraintPriority priority,
gboolean check_only)
{
if (priority > PRIORITY_ENTIRELY_VISIBLE_ON_SINGLE_MONITOR)
if (priority > PRIORITY_ENTIRELY_VISIBLE_ON_SINGLE_XINERAMA)
return TRUE;
/* Exit early if we know the constraint won't apply--note that this constraint
* is only meant for normal windows (e.g. we don't want docks to be shoved
* "onscreen" by their own strut) and we can't apply it to frameless windows
* or else users will be unable to move windows such as XMMS across monitors.
* or else users will be unable to move windows such as XMMS across xineramas.
*/
if (window->type == META_WINDOW_DESKTOP ||
window->type == META_WINDOW_DOCK ||
window->screen->n_monitor_infos == 1 ||
!window->require_on_single_monitor ||
window->screen->n_xinerama_infos == 1 ||
!window->require_on_single_xinerama ||
!window->frame ||
info->is_user_action)
return TRUE;
/* Have a helper function handle the constraint for us */
return do_screen_and_monitor_relative_constraints (window,
info->usable_monitor_region,
info,
check_only);
return do_screen_and_xinerama_relative_constraints (window,
info->usable_xinerama_region,
info,
check_only);
}
static gboolean
@@ -1333,10 +1205,10 @@ constrain_fully_onscreen (MetaWindow *window,
return TRUE;
/* Have a helper function handle the constraint for us */
return do_screen_and_monitor_relative_constraints (window,
info->usable_screen_region,
info,
check_only);
return do_screen_and_xinerama_relative_constraints (window,
info->usable_screen_region,
info,
check_only);
}
static gboolean
@@ -1409,10 +1281,10 @@ constrain_titlebar_visible (MetaWindow *window,
horiz_amount_onscreen,
vert_amount_onscreen);
retval =
do_screen_and_monitor_relative_constraints (window,
info->usable_screen_region,
info,
check_only);
do_screen_and_xinerama_relative_constraints (window,
info->usable_screen_region,
info,
check_only);
meta_rectangle_expand_region_conditionally (info->usable_screen_region,
-horiz_amount_offscreen,
-horiz_amount_offscreen,
@@ -1484,10 +1356,10 @@ constrain_partially_onscreen (MetaWindow *window,
horiz_amount_onscreen,
vert_amount_onscreen);
retval =
do_screen_and_monitor_relative_constraints (window,
info->usable_screen_region,
info,
check_only);
do_screen_and_xinerama_relative_constraints (window,
info->usable_screen_region,
info,
check_only);
meta_rectangle_expand_region_conditionally (info->usable_screen_region,
-horiz_amount_offscreen,
-horiz_amount_offscreen,

View File

@@ -28,7 +28,6 @@
#include "frame-private.h"
#include "workspace-private.h"
#include "prefs.h"
#include "errors.h"
/* Looks up the MetaWindow representing the frame of the given X window.
* Used as a helper function by a bunch of the functions below.
@@ -261,14 +260,15 @@ meta_core_user_raise (Display *xdisplay,
meta_window_raise (window);
}
static gboolean
lower_window_and_transients (MetaWindow *window,
gpointer data)
void
meta_core_user_lower_and_unfocus (Display *xdisplay,
Window frame_xwindow,
guint32 timestamp)
{
MetaWindow *window = get_window (xdisplay, frame_xwindow);
meta_window_lower (window);
meta_window_foreach_transient (window, lower_window_and_transients, NULL);
if (meta_prefs_get_focus_mode () == META_FOCUS_MODE_CLICK &&
meta_prefs_get_raise_on_click ())
{
@@ -296,59 +296,11 @@ lower_window_and_transients (MetaWindow *window,
}
}
return FALSE;
}
void
meta_core_user_lower_and_unfocus (Display *xdisplay,
Window frame_xwindow,
guint32 timestamp)
{
MetaWindow *window = get_window (xdisplay, frame_xwindow);
lower_window_and_transients (window, NULL);
/* Rather than try to figure that out whether we just lowered
* the focus window, assume that's always the case. (Typically,
* this will be invoked via keyboard action or by a mouse action;
* in either case the window or a modal child will have been focused.) */
meta_workspace_focus_default_window (window->screen->active_workspace,
NULL,
timestamp);
}
void
meta_core_lower_beneath_focus_window (Display *xdisplay,
Window xwindow,
guint32 timestamp)
{
XWindowChanges changes;
MetaDisplay *display;
MetaScreen *screen;
MetaWindow *focus_window;
display = meta_display_for_x_display (xdisplay);
screen = meta_display_screen_for_xwindow (display, xwindow);
focus_window = meta_stack_get_top (screen->stack);
if (focus_window == NULL)
return;
changes.stack_mode = Below;
changes.sibling = focus_window->frame ? focus_window->frame->xwindow
: focus_window->xwindow;
meta_stack_tracker_record_lower_below (screen->stack_tracker,
xwindow,
changes.sibling,
XNextRequest (screen->display->xdisplay));
meta_error_trap_push (display);
XConfigureWindow (xdisplay,
xwindow,
CWSibling | CWStackMode,
&changes);
meta_error_trap_pop (display);
/* focus the default window, if needed */
if (window->has_focus)
meta_workspace_focus_default_window (window->screen->active_workspace,
NULL,
timestamp);
}
void
@@ -574,9 +526,6 @@ meta_core_get_menu_accelerator (MetaMenuOp menu_op,
switch (menu_op)
{
case META_MENU_OP_NONE:
/* No keybinding for this one */
break;
case META_MENU_OP_DELETE:
name = "close";
break;
@@ -817,7 +766,7 @@ meta_invalidate_default_icons (void)
if (display == NULL)
return; /* We can validly be called before the display is opened. */
windows = meta_display_list_windows (display, META_LIST_DEFAULT);
windows = meta_display_list_windows (display);
for (l = windows; l != NULL; l = l->next)
{
MetaWindow *window = (MetaWindow*)l->data;

View File

@@ -22,7 +22,8 @@
* 02111-1307, USA.
*/
#define _XOPEN_SOURCE /* for kill() */
#define _GNU_SOURCE
#define _SVID_SOURCE /* for gethostname() */
#include <config.h>
#include "util.h"
@@ -31,7 +32,6 @@
#include "workspace.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
@@ -55,16 +55,27 @@ delete_ping_reply_func (MetaDisplay *display,
/* we do nothing */
}
static gboolean
delete_window_callback (gpointer w_p)
{
meta_window_kill ((MetaWindow*) w_p);
return FALSE; /* don't do it again */
}
static void
dialog_exited (GPid pid, int status, gpointer user_data)
sigchld_handler (MetaNexus *nexus, guint arg1, gpointer arg2, gpointer user_data)
{
MetaWindow *ours = (MetaWindow*) user_data;
ours->dialog_pid = -1;
if (GPOINTER_TO_INT (arg2) == ours->dialog_pid)
{
if (arg1 == 1 /* pressed "force quit" */)
g_idle_add_full (G_PRIORITY_DEFAULT,
delete_window_callback, user_data, NULL);
/* exit status of 1 means the user pressed "Force Quit" */
if (WIFEXITED (status) && WEXITSTATUS (status) == 1)
meta_window_kill (ours);
ours->dialog_pid = -1; /* forget it anyway */
}
}
static void
@@ -75,7 +86,7 @@ delete_ping_timeout_func (MetaDisplay *display,
{
MetaWindow *window = user_data;
char *window_title;
gchar *window_content, *tmp;
gchar *window_content;
GPid dialog_pid;
meta_topic (META_DEBUG_PING,
@@ -90,14 +101,11 @@ delete_ping_timeout_func (MetaDisplay *display,
window_title = g_locale_from_utf8 (window->title, -1, NULL, NULL, NULL);
/* Translators: %s is a window title */
tmp = g_strdup_printf (_("<tt>%s</tt> is not responding."),
window_title);
window_content = g_strdup_printf (
"<big><b>%s</b></big>\n\n<i>%s</i>",
tmp,
_("You may choose to wait a short while for it to "
"continue or force the application to quit entirely."));
window_content = g_strdup_printf(
_("<big><b><tt>%s</tt> is not responding.</b></big>\n\n"
"<i>You may choose to wait a short while for it to "
"continue or force the application to quit entirely.</i>"),
window_title);
g_free (window_title);
@@ -109,10 +117,13 @@ delete_ping_timeout_func (MetaDisplay *display,
NULL, NULL);
g_free (window_content);
g_free (tmp);
window->dialog_pid = dialog_pid;
g_child_watch_add (dialog_pid, dialog_exited, window);
g_signal_connect (sigchld_nexus, "sigchld",
G_CALLBACK (sigchld_handler),
window);
}
void
@@ -136,7 +147,7 @@ meta_window_delete (MetaWindow *window,
window->desc);
XKillClient (window->display->xdisplay, window->xwindow);
}
meta_error_trap_pop (window->display);
meta_error_trap_pop (window->display, FALSE);
meta_display_ping_window (window->display,
window,
@@ -178,29 +189,42 @@ meta_window_delete (MetaWindow *window,
void
meta_window_kill (MetaWindow *window)
{
char buf[257];
meta_topic (META_DEBUG_WINDOW_OPS,
"Killing %s brutally\n",
window->desc);
if (!meta_window_is_remote (window) &&
if (window->wm_client_machine != NULL &&
window->net_wm_pid > 0)
{
meta_topic (META_DEBUG_WINDOW_OPS,
"Killing %s with kill()\n",
window->desc);
if (gethostname (buf, sizeof(buf)-1) == 0)
{
if (strcmp (buf, window->wm_client_machine) == 0)
{
meta_topic (META_DEBUG_WINDOW_OPS,
"Killing %s with kill()\n",
window->desc);
if (kill (window->net_wm_pid, 9) < 0)
meta_topic (META_DEBUG_WINDOW_OPS,
"Failed to signal %s: %s\n",
window->desc, strerror (errno));
if (kill (window->net_wm_pid, 9) < 0)
meta_topic (META_DEBUG_WINDOW_OPS,
"Failed to signal %s: %s\n",
window->desc, strerror (errno));
}
}
else
{
meta_warning (_("Failed to get hostname: %s\n"),
strerror (errno));
}
}
meta_topic (META_DEBUG_WINDOW_OPS,
"Disconnecting %s with XKillClient()\n",
window->desc);
meta_error_trap_push (window->display);
XKillClient (window->display->xdisplay, window->xwindow);
meta_error_trap_pop (window->display);
meta_error_trap_pop (window->display, FALSE);
}
void
@@ -229,7 +253,7 @@ meta_window_present_delete_dialog (MetaWindow *window, guint32 timestamp)
* mutter-dialog
*/
windows = meta_display_list_windows (window->display, META_LIST_DEFAULT);
windows = meta_display_list_windows (window->display);
tmp = windows;
while (tmp != NULL)
{

View File

@@ -61,10 +61,6 @@ typedef void (* MetaWindowPingFunc) (MetaDisplay *display,
guint32 timestamp,
gpointer user_data);
typedef enum {
META_LIST_DEFAULT = 0, /* normal windows */
META_LIST_INCLUDE_OVERRIDE_REDIRECT = 1 << 0, /* normal and O-R */
} MetaListWindowsFlags;
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
#define _NET_WM_STATE_ADD 1 /* add/set property */
@@ -83,11 +79,10 @@ struct _MetaDisplay
char *name;
Display *xdisplay;
char *hostname;
Window leader_window;
Window timestamp_pinging_window;
/* Pull in all the names of atoms as fields; we will intern them when the
* class is constructed.
*/
@@ -151,15 +146,6 @@ struct _MetaDisplay
guint32 current_time;
/* We maintain a sequence counter, incremented for each #MetaWindow
* created. This is exposed by meta_window_get_stable_sequence()
* but is otherwise not used inside mutter.
*
* It can be useful to plugins which want to sort windows in a
* stable fashion.
*/
guint32 window_sequence_counter;
/* Pings which we're waiting for a reply from */
GSList *pending_pings;
@@ -184,16 +170,19 @@ struct _MetaDisplay
gulong grab_mask;
guint grab_have_pointer : 1;
guint grab_have_keyboard : 1;
guint grab_wireframe_active : 1;
guint grab_was_cancelled : 1; /* Only used in wireframe mode */
guint grab_frame_action : 1;
/* During a resize operation, the directions in which we've broken
* out of the initial maximization state */
guint grab_resize_unmaximize : 2; /* MetaMaximizeFlags */
MetaRectangle grab_wireframe_rect;
MetaRectangle grab_wireframe_last_xor_rect;
MetaRectangle grab_initial_window_pos;
int grab_initial_x, grab_initial_y; /* These are only relevant for */
gboolean grab_threshold_movement_reached; /* raise_on_click == FALSE. */
MetaResizePopup *grab_resize_popup;
GTimeVal grab_last_moveresize_time;
guint32 grab_motion_notify_time;
int grab_wireframe_last_display_width;
int grab_wireframe_last_display_height;
GList* grab_old_window_stacking;
MetaEdgeResistanceData *grab_edge_resistance_data;
unsigned int grab_last_user_action_was_snap;
@@ -230,8 +219,8 @@ struct _MetaDisplay
MetaKeyCombo overlay_key_combo;
gboolean overlay_key_only_pressed;
/* Monitor cache */
unsigned int monitor_cache_invalidated : 1;
/* Xinerama cache */
unsigned int xinerama_cache_invalidated : 1;
/* Opening the display */
unsigned int display_opening : 1;
@@ -256,18 +245,6 @@ struct _MetaDisplay
/* Managed by compositor.c */
MetaCompositor *compositor;
int render_event_base;
int render_error_base;
int composite_event_base;
int composite_error_base;
int composite_major_version;
int composite_minor_version;
int damage_event_base;
int damage_error_base;
int xfixes_event_base;
int xfixes_error_base;
#ifdef HAVE_STARTUP_NOTIFICATION
SnDisplay *sn_display;
@@ -280,6 +257,20 @@ struct _MetaDisplay
int shape_event_base;
int shape_error_base;
#endif
#ifdef HAVE_RENDER
int render_event_base;
int render_error_base;
#endif
#ifdef HAVE_COMPOSITE_EXTENSIONS
int composite_event_base;
int composite_error_base;
int composite_major_version;
int composite_minor_version;
int damage_event_base;
int damage_error_base;
int xfixes_event_base;
int xfixes_error_base;
#endif
#ifdef HAVE_XSYNC
unsigned int have_xsync : 1;
#define META_DISPLAY_HAS_XSYNC(display) ((display)->have_xsync)
@@ -292,14 +283,24 @@ struct _MetaDisplay
#else
#define META_DISPLAY_HAS_SHAPE(display) FALSE
#endif
#ifdef HAVE_RENDER
unsigned int have_render : 1;
#define META_DISPLAY_HAS_RENDER(display) ((display)->have_render)
#else
#define META_DISPLAY_HAS_RENDER(display) FALSE
#endif
#ifdef HAVE_COMPOSITE_EXTENSIONS
unsigned int have_composite : 1;
unsigned int have_damage : 1;
unsigned int have_xfixes : 1;
#define META_DISPLAY_HAS_COMPOSITE(display) ((display)->have_composite)
#define META_DISPLAY_HAS_DAMAGE(display) ((display)->have_damage)
#define META_DISPLAY_HAS_XFIXES(display) ((display)->have_xfixes)
#else
#define META_DISPLAY_HAS_COMPOSITE(display) FALSE
#define META_DISPLAY_HAS_DAMAGE(display) FALSE
#define META_DISPLAY_HAS_XFIXES(display) FALSE
#endif
};
struct _MetaDisplayClass
@@ -307,15 +308,22 @@ struct _MetaDisplayClass
GObjectClass parent_class;
};
/* Xserver time can wraparound, thus comparing two timestamps needs to take
* this into account. Here's a little macro to help out. If no wraparound
* has occurred, this is equivalent to
* time1 < time2
* Of course, the rest of the ugliness of this macro comes from accounting
* for the fact that wraparound can occur and the fact that a timestamp of
* 0 must be special-cased since it means older than anything else.
*
* Note that this is NOT an equivalent for time1 <= time2; if that's what
* you need then you'll need to swap the order of the arguments and negate
* the result.
*/
#define XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS(time1, time2) \
( (( (time1) < (time2) ) && ( (time2) - (time1) < ((guint32)-1)/2 )) || \
(( (time1) > (time2) ) && ( (time1) - (time2) > ((guint32)-1)/2 )) \
)
/**
* XSERVER_TIME_IS_BEFORE:
*
* See the docs for meta_display_xserver_time_is_before().
*/
#define XSERVER_TIME_IS_BEFORE(time1, time2) \
( (time1) == 0 || \
(XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS(time1, time2) && \
@@ -354,12 +362,12 @@ void meta_display_register_x_window (MetaDisplay *display,
MetaWindow *window);
void meta_display_unregister_x_window (MetaDisplay *display,
Window xwindow);
/* Return whether the xwindow is a no focus window for any of the screens */
gboolean meta_display_xwindow_is_a_no_focus_window (MetaDisplay *display,
Window xwindow);
void meta_display_notify_window_created (MetaDisplay *display,
MetaWindow *window);
GSList* meta_display_list_windows (MetaDisplay *display,
MetaListWindowsFlags flags);
GSList* meta_display_list_windows (MetaDisplay *display);
GSList* meta_display_list_all_windows (MetaDisplay *display);
MetaDisplay* meta_display_for_x_display (Display *xdisplay);
MetaDisplay* meta_get_display (void);
@@ -387,8 +395,9 @@ void meta_display_grab_focus_window_button (MetaDisplay *display,
void meta_display_ungrab_focus_window_button (MetaDisplay *display,
MetaWindow *window);
/* Next function is defined in edge-resistance.c */
void meta_display_cleanup_edges (MetaDisplay *display);
/* Next two functions are defined in edge-resistance.c */
void meta_display_compute_resistance_and_snapping_edges (MetaDisplay *display);
void meta_display_cleanup_edges (MetaDisplay *display);
/* make a request to ensure the event serial has changed */
void meta_display_increment_event_serial (MetaDisplay *display);

File diff suppressed because it is too large Load Diff

View File

@@ -23,7 +23,7 @@
#include <config.h>
#include "edge-resistance.h"
#include "boxes-private.h"
#include "boxes.h"
#include "display-private.h"
#include "workspace-private.h"
@@ -63,8 +63,6 @@ struct MetaEdgeResistanceData
ResistanceDataForAnEdge bottom_data;
};
static void compute_resistance_and_snapping_edges (MetaDisplay *display);
/* !WARNING!: this function can return invalid indices (namely, either -1 or
* edges->len); this is by design, but you need to remember this.
*/
@@ -342,12 +340,12 @@ apply_edge_resistance (MetaWindow *window,
const int PIXEL_DISTANCE_THRESHOLD_TOWARDS_WINDOW = 16;
const int PIXEL_DISTANCE_THRESHOLD_AWAYFROM_WINDOW = 0;
const int PIXEL_DISTANCE_THRESHOLD_TOWARDS_MONITOR = 32;
const int PIXEL_DISTANCE_THRESHOLD_AWAYFROM_MONITOR = 0;
const int PIXEL_DISTANCE_THRESHOLD_TOWARDS_XINERAMA = 32;
const int PIXEL_DISTANCE_THRESHOLD_AWAYFROM_XINERAMA = 0;
const int PIXEL_DISTANCE_THRESHOLD_TOWARDS_SCREEN = 32;
const int PIXEL_DISTANCE_THRESHOLD_AWAYFROM_SCREEN = 0;
const int TIMEOUT_RESISTANCE_LENGTH_MS_WINDOW = 0;
const int TIMEOUT_RESISTANCE_LENGTH_MS_MONITOR = 0;
const int TIMEOUT_RESISTANCE_LENGTH_MS_XINERAMA = 0;
const int TIMEOUT_RESISTANCE_LENGTH_MS_SCREEN = 0;
/* Quit if no movement was specified */
@@ -425,8 +423,8 @@ apply_edge_resistance (MetaWindow *window,
case META_EDGE_WINDOW:
timeout_length_ms = TIMEOUT_RESISTANCE_LENGTH_MS_WINDOW;
break;
case META_EDGE_MONITOR:
timeout_length_ms = TIMEOUT_RESISTANCE_LENGTH_MS_MONITOR;
case META_EDGE_XINERAMA:
timeout_length_ms = TIMEOUT_RESISTANCE_LENGTH_MS_XINERAMA;
break;
case META_EDGE_SCREEN:
timeout_length_ms = TIMEOUT_RESISTANCE_LENGTH_MS_SCREEN;
@@ -470,11 +468,11 @@ apply_edge_resistance (MetaWindow *window,
else
threshold = PIXEL_DISTANCE_THRESHOLD_AWAYFROM_WINDOW;
break;
case META_EDGE_MONITOR:
case META_EDGE_XINERAMA:
if (movement_towards_edge (edge->side_type, increment))
threshold = PIXEL_DISTANCE_THRESHOLD_TOWARDS_MONITOR;
threshold = PIXEL_DISTANCE_THRESHOLD_TOWARDS_XINERAMA;
else
threshold = PIXEL_DISTANCE_THRESHOLD_AWAYFROM_MONITOR;
threshold = PIXEL_DISTANCE_THRESHOLD_AWAYFROM_XINERAMA;
break;
case META_EDGE_SCREEN:
if (movement_towards_edge (edge->side_type, increment))
@@ -552,9 +550,7 @@ apply_edge_resistance_to_each_side (MetaDisplay *display,
gboolean modified;
int new_left, new_right, new_top, new_bottom;
if (display->grab_edge_resistance_data == NULL)
compute_resistance_and_snapping_edges (display);
g_assert (display->grab_edge_resistance_data != NULL);
edge_data = display->grab_edge_resistance_data;
if (auto_snap)
@@ -675,8 +671,7 @@ meta_display_cleanup_edges (MetaDisplay *display)
MetaEdgeResistanceData *edge_data = display->grab_edge_resistance_data;
GHashTable *edges_to_be_freed;
if (edge_data == NULL) /* Not currently cached */
return;
g_assert (edge_data != NULL);
/* We first need to clean out any window edges */
edges_to_be_freed = g_hash_table_new_full (g_direct_hash, g_direct_equal,
@@ -766,7 +761,7 @@ stupid_sort_requiring_extra_pointer_dereference (gconstpointer a,
static void
cache_edges (MetaDisplay *display,
GList *window_edges,
GList *monitor_edges,
GList *xinerama_edges,
GList *screen_edges)
{
MetaEdgeResistanceData *edge_data;
@@ -781,7 +776,7 @@ cache_edges (MetaDisplay *display,
if (meta_is_verbose())
{
int max_edges = MAX (MAX( g_list_length (window_edges),
g_list_length (monitor_edges)),
g_list_length (xinerama_edges)),
g_list_length (screen_edges));
char big_buffer[(EDGE_LENGTH+2)*max_edges];
@@ -789,9 +784,9 @@ cache_edges (MetaDisplay *display,
meta_topic (META_DEBUG_EDGE_RESISTANCE,
"Window edges for resistance : %s\n", big_buffer);
meta_rectangle_edge_list_to_string (monitor_edges, ", ", big_buffer);
meta_rectangle_edge_list_to_string (xinerama_edges, ", ", big_buffer);
meta_topic (META_DEBUG_EDGE_RESISTANCE,
"Monitor edges for resistance: %s\n", big_buffer);
"Xinerama edges for resistance: %s\n", big_buffer);
meta_rectangle_edge_list_to_string (screen_edges, ", ", big_buffer);
meta_topic (META_DEBUG_EDGE_RESISTANCE,
@@ -812,7 +807,7 @@ cache_edges (MetaDisplay *display,
tmp = window_edges;
break;
case 1:
tmp = monitor_edges;
tmp = xinerama_edges;
break;
case 2:
tmp = screen_edges;
@@ -849,7 +844,7 @@ cache_edges (MetaDisplay *display,
* 2nd: Allocate the edges
*/
g_assert (display->grab_edge_resistance_data == NULL);
display->grab_edge_resistance_data = g_new0 (MetaEdgeResistanceData, 1);
display->grab_edge_resistance_data = g_new (MetaEdgeResistanceData, 1);
edge_data = display->grab_edge_resistance_data;
edge_data->left_edges = g_array_sized_new (FALSE,
FALSE,
@@ -880,7 +875,7 @@ cache_edges (MetaDisplay *display,
tmp = window_edges;
break;
case 1:
tmp = monitor_edges;
tmp = xinerama_edges;
break;
case 2:
tmp = screen_edges;
@@ -943,8 +938,8 @@ initialize_grab_edge_resistance_data (MetaDisplay *display)
edge_data->bottom_data.keyboard_buildup = 0;
}
static void
compute_resistance_and_snapping_edges (MetaDisplay *display)
void
meta_display_compute_resistance_and_snapping_edges (MetaDisplay *display)
{
GList *stacked_windows;
GList *cur_window_iter;
@@ -957,11 +952,6 @@ compute_resistance_and_snapping_edges (MetaDisplay *display)
*/
GSList *rem_windows, *rem_win_stacking;
g_assert (display->grab_window != NULL);
meta_topic (META_DEBUG_WINDOW_OPS,
"Computing edges to resist-movement or snap-to for %s.\n",
display->grab_window->desc);
/*
* 1st: Get the list of relevant windows, from bottom to top
*/
@@ -1120,12 +1110,12 @@ compute_resistance_and_snapping_edges (MetaDisplay *display)
/*
* 5th: Cache the combination of these edges with the onscreen and
* monitor edges in an array for quick access. Free the edges since
* xinerama edges in an array for quick access. Free the edges since
* they've been cached elsewhere.
*/
cache_edges (display,
edges,
display->grab_screen->active_workspace->monitor_edges,
display->grab_screen->active_workspace->xinerama_edges,
display->grab_screen->active_workspace->screen_edges);
g_list_free (edges);
@@ -1151,8 +1141,17 @@ meta_window_edge_resistance_for_move (MetaWindow *window,
MetaRectangle old_outer, proposed_outer, new_outer;
gboolean is_resize;
meta_window_get_outer_rect (window, &old_outer);
if (window == window->display->grab_window &&
window->display->grab_wireframe_active)
{
meta_window_get_xor_rect (window,
&window->display->grab_wireframe_rect,
&old_outer);
}
else
{
meta_window_get_outer_rect (window, &old_outer);
}
proposed_outer = old_outer;
proposed_outer.x += (*new_x - old_x);
proposed_outer.y += (*new_y - old_y);
@@ -1237,7 +1236,17 @@ meta_window_edge_resistance_for_resize (MetaWindow *window,
int proposed_outer_width, proposed_outer_height;
gboolean is_resize;
meta_window_get_outer_rect (window, &old_outer);
if (window == window->display->grab_window &&
window->display->grab_wireframe_active)
{
meta_window_get_xor_rect (window,
&window->display->grab_wireframe_rect,
&old_outer);
}
else
{
meta_window_get_outer_rect (window, &old_outer);
}
proposed_outer_width = old_outer.width + (*new_width - old_width);
proposed_outer_height = old_outer.height + (*new_height - old_height);
meta_rectangle_resize_with_gravity (&old_outer,

735
src/core/effects.c Normal file
View File

@@ -0,0 +1,735 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/**
* \file effects.c "Special effects" other than compositor effects.
*
* Before we had a serious compositor, we supported swooping
* rectangles for minimising and so on. These are still supported
* today, even when the compositor is enabled. The file contains two
* parts:
*
* 1) A set of functions, each of which implements a special effect.
* (Only the minimize function does anything interesting; we should
* probably get rid of the rest.)
*
* 2) A set of functions for moving a highlighted wireframe box around
* the screen, optionally with height and width shown in the middle.
* This is used for moving and resizing when reduced_resources is set.
*
* There was formerly a system which allowed callers to drop in their
* own handlers for various things; it was never used (people who want
* their own handlers can just modify this file, after all) and it added
* a good deal of extra complexity, so it has been removed. If you want it,
* it can be found in svn r3769.
*
* Once upon a time there were three different ways of drawing the box
* animation: window wireframe, window opaque, and root. People who had
* the shape extension theoretically had the choice of all three, and
* people who didn't weren't given the choice of the wireframe option.
* In practice, though, the opaque animation was never perfect, so it came
* down to the wireframe option for those who had the extension and
* the root option for those who didn't; there was actually no way of choosing
* any other option anyway. Work on the opaque animation stopped in 2002;
* anyone who wants something like that these days will be using the
* compositor anyway.
*
* In svn r3769 this was made explicit.
*/
/*
* Copyright (C) 2001 Anders Carlsson, Havoc Pennington
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <config.h>
#include "effects.h"
#include "display-private.h"
#include "ui.h"
#include "window-private.h"
#include "prefs.h"
#ifdef HAVE_SHAPE
#include <X11/extensions/shape.h>
#endif
#define META_MINIMIZE_ANIMATION_LENGTH 0.25
#define META_SHADE_ANIMATION_LENGTH 0.2
#include <string.h>
typedef struct MetaEffect MetaEffect;
typedef struct MetaEffectPriv MetaEffectPriv;
typedef struct
{
MetaScreen *screen;
double millisecs_duration;
GTimeVal start_time;
#ifdef HAVE_SHAPE
/** For wireframe window */
Window wireframe_xwindow;
#else
/** Rectangle to erase */
MetaRectangle last_rect;
/** First time we've plotted anything in this animation? */
gboolean first_time;
/** For wireframe drawn on root window */
GC gc;
#endif
MetaRectangle start_rect;
MetaRectangle end_rect;
} BoxAnimationContext;
/**
* Information we need to know during a maximise or minimise effect.
*/
typedef struct
{
/** This is the normal-size window. */
MetaRectangle window_rect;
/** This is the size of the window when it's an icon. */
MetaRectangle icon_rect;
} MetaMinimizeEffect, MetaUnminimizeEffect;
struct MetaEffectPriv
{
MetaEffectFinished finished;
gpointer finished_data;
};
struct MetaEffect
{
/** The window the effect is applied to. */
MetaWindow *window;
/** Which effect is happening here. */
MetaEffectType type;
/** The effect handler can hang data here. */
gpointer info;
union
{
MetaMinimizeEffect minimize;
/* ... and theoretically anything else */
} u;
MetaEffectPriv *priv;
};
static void run_default_effect_handler (MetaEffect *effect);
static void run_handler (MetaEffect *effect);
static void effect_free (MetaEffect *effect);
static MetaEffect *
create_effect (MetaEffectType type,
MetaWindow *window,
MetaEffectFinished finished,
gpointer finished_data);
static void
draw_box_animation (MetaScreen *screen,
MetaRectangle *initial_rect,
MetaRectangle *destination_rect,
double seconds_duration);
/**
* Creates an effect.
*
*/
static MetaEffect*
create_effect (MetaEffectType type,
MetaWindow *window,
MetaEffectFinished finished,
gpointer finished_data)
{
MetaEffect *effect = g_new (MetaEffect, 1);
effect->type = type;
effect->window = window;
effect->priv = g_new (MetaEffectPriv, 1);
effect->priv->finished = finished;
effect->priv->finished_data = finished_data;
return effect;
}
/**
* Destroys an effect. If the effect has a "finished" hook, it will be
* called before cleanup.
*
* \param effect The effect.
*/
static void
effect_free (MetaEffect *effect)
{
if (effect->priv->finished)
effect->priv->finished (effect->priv->finished_data);
g_free (effect->priv);
g_free (effect);
}
void
meta_effect_run_focus (MetaWindow *window,
MetaEffectFinished finished,
gpointer data)
{
MetaEffect *effect;
g_return_if_fail (window != NULL);
effect = create_effect (META_EFFECT_FOCUS, window, finished, data);
run_handler (effect);
}
void
meta_effect_run_minimize (MetaWindow *window,
MetaRectangle *window_rect,
MetaRectangle *icon_rect,
MetaEffectFinished finished,
gpointer data)
{
MetaEffect *effect;
g_return_if_fail (window != NULL);
g_return_if_fail (icon_rect != NULL);
effect = create_effect (META_EFFECT_MINIMIZE, window, finished, data);
effect->u.minimize.window_rect = *window_rect;
effect->u.minimize.icon_rect = *icon_rect;
run_handler (effect);
}
void
meta_effect_run_unminimize (MetaWindow *window,
MetaRectangle *window_rect,
MetaRectangle *icon_rect,
MetaEffectFinished finished,
gpointer data)
{
MetaEffect *effect;
g_return_if_fail (window != NULL);
g_return_if_fail (icon_rect != NULL);
effect = create_effect (META_EFFECT_UNMINIMIZE, window, finished, data);
effect->u.minimize.window_rect = *window_rect;
effect->u.minimize.icon_rect = *icon_rect;
run_handler (effect);
}
void
meta_effect_run_close (MetaWindow *window,
MetaEffectFinished finished,
gpointer data)
{
MetaEffect *effect;
g_return_if_fail (window != NULL);
effect = create_effect (META_EFFECT_CLOSE, window,
finished, data);
run_handler (effect);
}
/* old ugly minimization effect */
#ifdef HAVE_SHAPE
static void
update_wireframe_window (MetaDisplay *display,
Window xwindow,
const MetaRectangle *rect)
{
XMoveResizeWindow (display->xdisplay,
xwindow,
rect->x, rect->y,
rect->width, rect->height);
#define OUTLINE_WIDTH 3
if (rect->width > OUTLINE_WIDTH * 2 &&
rect->height > OUTLINE_WIDTH * 2)
{
XRectangle xrect;
Region inner_xregion;
Region outer_xregion;
inner_xregion = XCreateRegion ();
outer_xregion = XCreateRegion ();
xrect.x = 0;
xrect.y = 0;
xrect.width = rect->width;
xrect.height = rect->height;
XUnionRectWithRegion (&xrect, outer_xregion, outer_xregion);
xrect.x += OUTLINE_WIDTH;
xrect.y += OUTLINE_WIDTH;
xrect.width -= OUTLINE_WIDTH * 2;
xrect.height -= OUTLINE_WIDTH * 2;
XUnionRectWithRegion (&xrect, inner_xregion, inner_xregion);
XSubtractRegion (outer_xregion, inner_xregion, outer_xregion);
XShapeCombineRegion (display->xdisplay, xwindow,
ShapeBounding, 0, 0, outer_xregion, ShapeSet);
XDestroyRegion (outer_xregion);
XDestroyRegion (inner_xregion);
}
else
{
/* Unset the shape */
XShapeCombineMask (display->xdisplay, xwindow,
ShapeBounding, 0, 0, None, ShapeSet);
}
}
#endif
/**
* A hack to force the X server to synchronize with the
* graphics hardware.
*/
static void
graphics_sync (BoxAnimationContext *context)
{
XImage *image;
image = XGetImage (context->screen->display->xdisplay,
context->screen->xroot,
0, 0, 1, 1,
AllPlanes, ZPixmap);
XDestroyImage (image);
}
static gboolean
effects_draw_box_animation_timeout (BoxAnimationContext *context)
{
double elapsed;
GTimeVal current_time;
MetaRectangle draw_rect;
double fraction;
#ifndef HAVE_SHAPE
if (!context->first_time)
{
/* Restore the previously drawn background */
XDrawRectangle (context->screen->display->xdisplay,
context->screen->xroot,
context->gc,
context->last_rect.x, context->last_rect.y,
context->last_rect.width, context->last_rect.height);
}
else
context->first_time = FALSE;
#endif /* !HAVE_SHAPE */
g_get_current_time (&current_time);
/* We use milliseconds for all times */
elapsed =
((((double)current_time.tv_sec - context->start_time.tv_sec) * G_USEC_PER_SEC +
(current_time.tv_usec - context->start_time.tv_usec))) / 1000.0;
if (elapsed < 0)
{
/* Probably the system clock was set backwards? */
meta_warning ("System clock seemed to go backwards?\n");
elapsed = G_MAXDOUBLE; /* definitely done. */
}
if (elapsed > context->millisecs_duration)
{
/* All done */
#ifdef HAVE_SHAPE
XDestroyWindow (context->screen->display->xdisplay,
context->wireframe_xwindow);
#else
meta_display_ungrab (context->screen->display);
meta_ui_pop_delay_exposes (context->screen->ui);
XFreeGC (context->screen->display->xdisplay,
context->gc);
#endif /* !HAVE_SHAPE */
graphics_sync (context);
g_free (context);
return FALSE;
}
g_assert (context->millisecs_duration > 0.0);
fraction = elapsed / context->millisecs_duration;
draw_rect = context->start_rect;
/* Now add a delta proportional to elapsed time. */
draw_rect.x += (context->end_rect.x - context->start_rect.x) * fraction;
draw_rect.y += (context->end_rect.y - context->start_rect.y) * fraction;
draw_rect.width += (context->end_rect.width - context->start_rect.width) * fraction;
draw_rect.height += (context->end_rect.height - context->start_rect.height) * fraction;
/* don't confuse X or gdk-pixbuf with bogus rectangles */
if (draw_rect.width < 1)
draw_rect.width = 1;
if (draw_rect.height < 1)
draw_rect.height = 1;
#ifdef HAVE_SHAPE
update_wireframe_window (context->screen->display,
context->wireframe_xwindow,
&draw_rect);
#else
context->last_rect = draw_rect;
/* Draw the rectangle */
XDrawRectangle (context->screen->display->xdisplay,
context->screen->xroot,
context->gc,
draw_rect.x, draw_rect.y,
draw_rect.width, draw_rect.height);
#endif /* !HAVE_SHAPE */
/* kick changes onto the server */
graphics_sync (context);
return TRUE;
}
void
draw_box_animation (MetaScreen *screen,
MetaRectangle *initial_rect,
MetaRectangle *destination_rect,
double seconds_duration)
{
BoxAnimationContext *context;
#ifdef HAVE_SHAPE
XSetWindowAttributes attrs;
#else
XGCValues gc_values;
#endif
g_return_if_fail (seconds_duration > 0.0);
if (g_getenv ("MUTTER_DEBUG_EFFECTS"))
seconds_duration *= 10; /* slow things down */
/* Create the animation context */
context = g_new0 (BoxAnimationContext, 1);
context->screen = screen;
context->millisecs_duration = seconds_duration * 1000.0;
context->start_rect = *initial_rect;
context->end_rect = *destination_rect;
#ifdef HAVE_SHAPE
attrs.override_redirect = True;
attrs.background_pixel = BlackPixel (screen->display->xdisplay,
screen->number);
context->wireframe_xwindow = XCreateWindow (screen->display->xdisplay,
screen->xroot,
initial_rect->x,
initial_rect->y,
initial_rect->width,
initial_rect->height,
0,
CopyFromParent,
CopyFromParent,
(Visual *)CopyFromParent,
CWOverrideRedirect | CWBackPixel,
&attrs);
update_wireframe_window (screen->display,
context->wireframe_xwindow,
initial_rect);
XMapWindow (screen->display->xdisplay,
context->wireframe_xwindow);
#else /* !HAVE_SHAPE */
context->first_time = TRUE;
gc_values.subwindow_mode = IncludeInferiors;
gc_values.function = GXinvert;
context->gc = XCreateGC (screen->display->xdisplay,
screen->xroot,
GCSubwindowMode | GCFunction,
&gc_values);
/* Grab the X server to avoid screen dirt */
meta_display_grab (context->screen->display);
meta_ui_push_delay_exposes (context->screen->ui);
#endif
/* Do this only after we get the pixbuf from the server,
* so that the animation doesn't get truncated.
*/
g_get_current_time (&context->start_time);
/* Add the timeout - a short one, could even use an idle,
* but this is maybe more CPU-friendly.
*/
g_timeout_add (15,
(GSourceFunc)effects_draw_box_animation_timeout,
context);
/* kick changes onto the server */
XFlush (context->screen->display->xdisplay);
}
void
meta_effects_begin_wireframe (MetaScreen *screen,
const MetaRectangle *rect,
int width,
int height)
{
/* Grab the X server to avoid screen dirt */
meta_display_grab (screen->display);
meta_ui_push_delay_exposes (screen->ui);
meta_effects_update_wireframe (screen,
NULL, -1, -1,
rect, width, height);
}
static void
draw_xor_rect (MetaScreen *screen,
const MetaRectangle *rect,
int width,
int height)
{
/* The lines in the center can't overlap the rectangle or each
* other, or the XOR gets reversed. So we have to draw things
* a bit oddly.
*/
XSegment segments[8];
MetaRectangle shrunk_rect;
int i;
#define LINE_WIDTH META_WIREFRAME_XOR_LINE_WIDTH
/* We don't want the wireframe going outside the window area.
* It makes it harder for the user to position windows and it exposes other
* annoying bugs.
*/
shrunk_rect = *rect;
shrunk_rect.x += LINE_WIDTH / 2 + LINE_WIDTH % 2;
shrunk_rect.y += LINE_WIDTH / 2 + LINE_WIDTH % 2;
shrunk_rect.width -= LINE_WIDTH + 2 * (LINE_WIDTH % 2);
shrunk_rect.height -= LINE_WIDTH + 2 * (LINE_WIDTH % 2);
XDrawRectangle (screen->display->xdisplay,
screen->xroot,
screen->root_xor_gc,
shrunk_rect.x, shrunk_rect.y,
shrunk_rect.width, shrunk_rect.height);
/* Don't put lines inside small rectangles where they won't fit */
if (shrunk_rect.width < (LINE_WIDTH * 4) ||
shrunk_rect.height < (LINE_WIDTH * 4))
return;
if ((width >= 0) && (height >= 0))
{
XGCValues gc_values = { 0 };
if (XGetGCValues (screen->display->xdisplay,
screen->root_xor_gc,
GCFont, &gc_values))
{
char *text;
int text_length;
XFontStruct *font_struct;
int text_width, text_height;
int box_x, box_y;
int box_width, box_height;
font_struct = XQueryFont (screen->display->xdisplay,
gc_values.font);
if (font_struct != NULL)
{
text = g_strdup_printf ("%d x %d", width, height);
text_length = strlen (text);
text_width = text_length * font_struct->max_bounds.width;
text_height = font_struct->max_bounds.descent +
font_struct->max_bounds.ascent;
box_width = text_width + 2 * LINE_WIDTH;
box_height = text_height + 2 * LINE_WIDTH;
box_x = shrunk_rect.x + (shrunk_rect.width - box_width) / 2;
box_y = shrunk_rect.y + (shrunk_rect.height - box_height) / 2;
if ((box_width < shrunk_rect.width) &&
(box_height < shrunk_rect.height))
{
XFillRectangle (screen->display->xdisplay,
screen->xroot,
screen->root_xor_gc,
box_x, box_y,
box_width, box_height);
XDrawString (screen->display->xdisplay,
screen->xroot,
screen->root_xor_gc,
box_x + LINE_WIDTH,
box_y + LINE_WIDTH + font_struct->max_bounds.ascent,
text, text_length);
}
g_free (text);
XFreeFontInfo (NULL, font_struct, 1);
if ((box_width + LINE_WIDTH) >= (shrunk_rect.width / 3))
return;
if ((box_height + LINE_WIDTH) >= (shrunk_rect.height / 3))
return;
}
}
}
/* Two vertical lines at 1/3 and 2/3 */
segments[0].x1 = shrunk_rect.x + shrunk_rect.width / 3;
segments[0].y1 = shrunk_rect.y + LINE_WIDTH / 2 + LINE_WIDTH % 2;
segments[0].x2 = segments[0].x1;
segments[0].y2 = shrunk_rect.y + shrunk_rect.height - LINE_WIDTH / 2;
segments[1] = segments[0];
segments[1].x1 = shrunk_rect.x + (shrunk_rect.width / 3) * 2;
segments[1].x2 = segments[1].x1;
/* Now make two horizontal lines at 1/3 and 2/3, but not
* overlapping the verticals
*/
segments[2].x1 = shrunk_rect.x + LINE_WIDTH / 2 + LINE_WIDTH % 2;
segments[2].x2 = segments[0].x1 - LINE_WIDTH / 2;
segments[2].y1 = shrunk_rect.y + shrunk_rect.height / 3;
segments[2].y2 = segments[2].y1;
segments[3] = segments[2];
segments[3].x1 = segments[2].x2 + LINE_WIDTH;
segments[3].x2 = segments[1].x1 - LINE_WIDTH / 2;
segments[4] = segments[3];
segments[4].x1 = segments[3].x2 + LINE_WIDTH;
segments[4].x2 = shrunk_rect.x + shrunk_rect.width - LINE_WIDTH / 2;
/* Second horizontal line is just like the first, but
* shifted down
*/
i = 5;
while (i < 8)
{
segments[i] = segments[i - 3];
segments[i].y1 = shrunk_rect.y + (shrunk_rect.height / 3) * 2;
segments[i].y2 = segments[i].y1;
++i;
}
XDrawSegments (screen->display->xdisplay,
screen->xroot,
screen->root_xor_gc,
segments,
G_N_ELEMENTS (segments));
}
void
meta_effects_update_wireframe (MetaScreen *screen,
const MetaRectangle *old_rect,
int old_width,
int old_height,
const MetaRectangle *new_rect,
int new_width,
int new_height)
{
if (old_rect)
draw_xor_rect (screen, old_rect, old_width, old_height);
if (new_rect)
draw_xor_rect (screen, new_rect, new_width, new_height);
XFlush (screen->display->xdisplay);
}
void
meta_effects_end_wireframe (MetaScreen *screen,
const MetaRectangle *old_rect,
int old_width,
int old_height)
{
meta_effects_update_wireframe (screen,
old_rect, old_width, old_height,
NULL, -1, -1);
meta_display_ungrab (screen->display);
meta_ui_pop_delay_exposes (screen->ui);
}
static void
run_default_effect_handler (MetaEffect *effect)
{
switch (effect->type)
{
case META_EFFECT_MINIMIZE:
draw_box_animation (effect->window->screen,
&(effect->u.minimize.window_rect),
&(effect->u.minimize.icon_rect),
META_MINIMIZE_ANIMATION_LENGTH);
break;
default:
break;
}
}
static void
run_handler (MetaEffect *effect)
{
if (meta_prefs_get_gnome_animations ())
run_default_effect_handler (effect);
effect_free (effect);
}

170
src/core/effects.h Normal file
View File

@@ -0,0 +1,170 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/**
* \file effects.h "Special effects" other than compositor effects.
*
* Before we had a serious compositor, we supported swooping
* rectangles for minimising and so on. These are still supported
* today, even when the compositor is enabled. The file contains two
* parts:
*
* 1) A set of functions, each of which implements a special effect.
* (Only the minimize function does anything interesting; we should
* probably get rid of the rest.)
*
* 2) A set of functions for moving a highlighted wireframe box around
* the screen, optionally with height and width shown in the middle.
* This is used for moving and resizing when reduced_resources is set.
*
* There was formerly a system which allowed callers to drop in their
* own handlers for various things; it was never used (people who want
* their own handlers can just modify this file, after all) and it added
* a good deal of extra complexity, so it has been removed. If you want it,
* it can be found in svn r3769.
*/
/*
* Copyright (C) 2001 Anders Carlsson, Havoc Pennington
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef META_EFFECTS_H
#define META_EFFECTS_H
#include "util.h"
#include "screen-private.h"
typedef enum
{
META_EFFECT_MINIMIZE,
META_EFFECT_UNMINIMIZE,
META_EFFECT_FOCUS,
META_EFFECT_CLOSE,
META_NUM_EFFECTS
} MetaEffectType;
/**
* A callback which will be called when the effect has finished.
*/
typedef void (* MetaEffectFinished) (gpointer data);
/**
* Performs the minimize effect.
*
* \param window The window we're moving
* \param window_rect Its current state
* \param target Where it should end up
* \param finished Callback for when it's finished
* \param data Data for callback
*/
void meta_effect_run_minimize (MetaWindow *window,
MetaRectangle *window_rect,
MetaRectangle *target,
MetaEffectFinished finished,
gpointer data);
/**
* Performs the unminimize effect. There is no such effect.
* FIXME: delete this.
*
* \param window The window we're moving
* \param icon_rect Its current state
* \param window_rect Where it should end up
* \param finished Callback for when it's finished
* \param data Data for callback
*/
void meta_effect_run_unminimize (MetaWindow *window,
MetaRectangle *window_rect,
MetaRectangle *icon_rect,
MetaEffectFinished finished,
gpointer data);
/**
* Performs the close effect. There is no such effect.
* FIXME: delete this.
*
* \param window The window we're moving
* \param finished Callback for when it's finished
* \param data Data for callback
*/
void meta_effect_run_close (MetaWindow *window,
MetaEffectFinished finished,
gpointer data);
/**
* Performs the focus effect. There is no such effect.
* FIXME: delete this.
*
* \param window The window we're moving
* \param finished Callback for when it's finished
* \param data Data for callback
*/
void meta_effect_run_focus (MetaWindow *window,
MetaEffectFinished finished,
gpointer data);
/**
* Grabs the server and paints a wireframe rectangle on the screen.
* Since this involves starting a grab, please be considerate of other
* users and don't keep the grab for long. You may move the wireframe
* around using meta_effects_update_wireframe() and remove it, and undo
* the grab, using meta_effects_end_wireframe().
*
* \param screen The screen to draw the rectangle on.
* \param rect The size of the rectangle to draw.
* \param width The width to display in the middle (or 0 not to)
* \param height The width to display in the middle (or 0 not to)
*/
void meta_effects_begin_wireframe (MetaScreen *screen,
const MetaRectangle *rect,
int width,
int height);
/**
* Moves a wireframe rectangle around after its creation by
* meta_effects_begin_wireframe(). (Perhaps we ought to remember the old
* positions and not require people to pass them in?)
*
* \param old_rect Where the rectangle is now
* \param old_width The width that was displayed on it (or 0 if there wasn't)
* \param old_height The height that was displayed on it (or 0 if there wasn't)
* \param new_rect Where the rectangle is going
* \param new_width The width that will be displayed on it (or 0 not to)
* \param new_height The height that will be displayed on it (or 0 not to)
*/
void meta_effects_update_wireframe (MetaScreen *screen,
const MetaRectangle *old_rect,
int old_width,
int old_height,
const MetaRectangle *new_rect,
int new_width,
int new_height);
/**
* Removes a wireframe rectangle from the screen and ends the grab started by
* meta_effects_begin_wireframe().
*
* \param old_rect Where the rectangle is now
* \param old_width The width that was displayed on it (or 0 if there wasn't)
* \param old_height The height that was displayed on it (or 0 if there wasn't)
*/
void meta_effects_end_wireframe (MetaScreen *screen,
const MetaRectangle *old_rect,
int width,
int height);
#endif /* META_EFFECTS_H */

View File

@@ -29,38 +29,260 @@
#include <stdlib.h>
#include <gdk/gdk.h>
/* In GTK+-3.0, the error trapping code was significantly rewritten. The new code
* has some neat features (like knowing automatically if a sync is needed or not
* and handling errors asynchronously when the error code isn't needed immediately),
* but it's basically incompatible with the hacks we played with GTK+-2.0 to
* use a custom error handler along with gdk_error_trap_push().
*
* Since the main point of our custom error trap was to get the error logged
* to the right place, with GTK+-3.0 we simply omit our own error handler and
* use the GTK+ handling straight-up.
* (See https://bugzilla.gnome.org/show_bug.cgi?id=630216 for restoring logging.)
*/
static int x_error_handler (Display *display,
XErrorEvent *error);
static int x_io_error_handler (Display *display);
void
meta_errors_init (void)
{
XSetErrorHandler (x_error_handler);
XSetIOErrorHandler (x_io_error_handler);
}
typedef struct ForeignDisplay ForeignDisplay;
struct ForeignDisplay
{
Display *dpy;
ErrorHandler handler;
gpointer data;
ForeignDisplay *next;
};
static ForeignDisplay *foreign_displays;
void
meta_errors_register_foreign_display (Display *foreign_dpy,
ErrorHandler handler,
gpointer data)
{
ForeignDisplay *info = g_new0 (ForeignDisplay, 1);
info->dpy = foreign_dpy;
info->handler = handler;
info->data = data;
info->next = foreign_displays;
foreign_displays = info;
}
static void
meta_error_trap_push_internal (MetaDisplay *display,
gboolean need_sync)
{
/* GDK resets the error handler on each push */
int (* old_error_handler) (Display *,
XErrorEvent *);
if (need_sync)
{
XSync (display->xdisplay, False);
}
gdk_error_trap_push ();
/* old_error_handler will just be equal to x_error_handler
* for nested traps
*/
old_error_handler = XSetErrorHandler (x_error_handler);
/* Replace GDK handler, but save it so we can chain up */
if (display->error_trap_handler == NULL)
{
g_assert (display->error_traps == 0);
display->error_trap_handler = old_error_handler;
g_assert (display->error_trap_handler != x_error_handler);
}
display->error_traps += 1;
meta_topic (META_DEBUG_ERRORS, "%d traps remain\n", display->error_traps);
}
static int
meta_error_trap_pop_internal (MetaDisplay *display,
gboolean need_sync)
{
int result;
g_assert (display->error_traps > 0);
if (need_sync)
{
XSync (display->xdisplay, False);
}
result = gdk_error_trap_pop ();
display->error_traps -= 1;
if (display->error_traps == 0)
{
/* check that GDK put our handler back; this
* assumes that there are no pending GDK traps from GDK itself
*/
int (* restored_error_handler) (Display *,
XErrorEvent *);
restored_error_handler = XSetErrorHandler (x_error_handler);
/* remove this */
display->error_trap_handler = NULL;
}
meta_topic (META_DEBUG_ERRORS, "%d traps\n", display->error_traps);
return result;
}
void
meta_error_trap_push (MetaDisplay *display)
{
gdk_error_trap_push ();
meta_error_trap_push_internal (display, FALSE);
}
void
meta_error_trap_pop (MetaDisplay *display)
meta_error_trap_pop (MetaDisplay *display,
gboolean last_request_was_roundtrip)
{
gdk_error_trap_pop_ignored ();
gboolean need_sync;
/* we only have to sync when popping the outermost trap */
need_sync = (display->error_traps == 1 && !last_request_was_roundtrip);
if (need_sync)
meta_topic (META_DEBUG_SYNC, "Syncing on error_trap_pop, traps = %d, roundtrip = %d\n",
display->error_traps, last_request_was_roundtrip);
display->error_trap_synced_at_last_pop = need_sync || last_request_was_roundtrip;
meta_error_trap_pop_internal (display, need_sync);
}
void
meta_error_trap_push_with_return (MetaDisplay *display)
{
gdk_error_trap_push ();
gboolean need_sync;
/* We don't sync on push_with_return if there are no traps
* currently, because we assume that any errors were either covered
* by a previous pop, or were fatal.
*
* More generally, we don't sync if we were synchronized last time
* we popped. This is known to be the case if there are no traps,
* but we also keep a flag so we know whether it's the case otherwise.
*/
if (!display->error_trap_synced_at_last_pop)
need_sync = TRUE;
else
need_sync = FALSE;
if (need_sync)
meta_topic (META_DEBUG_SYNC, "Syncing on error_trap_push_with_return, traps = %d\n",
display->error_traps);
meta_error_trap_push_internal (display, FALSE);
}
int
meta_error_trap_pop_with_return (MetaDisplay *display)
meta_error_trap_pop_with_return (MetaDisplay *display,
gboolean last_request_was_roundtrip)
{
return gdk_error_trap_pop ();
if (!last_request_was_roundtrip)
meta_topic (META_DEBUG_SYNC, "Syncing on error_trap_pop_with_return, traps = %d, roundtrip = %d\n",
display->error_traps, last_request_was_roundtrip);
display->error_trap_synced_at_last_pop = TRUE;
return meta_error_trap_pop_internal (display,
!last_request_was_roundtrip);
}
static int
x_error_handler (Display *xdisplay,
XErrorEvent *error)
{
int retval;
gchar buf[64];
MetaDisplay *display;
ForeignDisplay *foreign;
for (foreign = foreign_displays; foreign != NULL; foreign = foreign->next)
{
if (foreign->dpy == xdisplay)
{
foreign->handler (xdisplay, error, foreign->data);
return 0;
}
}
XGetErrorText (xdisplay, error->error_code, buf, 63);
display = meta_display_for_x_display (xdisplay);
/* Display can be NULL here because the compositing manager
* has its own Display, but Xlib only has one global error handler
*/
if (display->error_traps > 0)
{
/* we're in an error trap, chain to the trap handler
* saved from GDK
*/
meta_verbose ("X error: %s serial %ld error_code %d request_code %d minor_code %d)\n",
buf,
error->serial,
error->error_code,
error->request_code,
error->minor_code);
g_assert (display->error_trap_handler != NULL);
g_assert (display->error_trap_handler != x_error_handler);
retval = (* display->error_trap_handler) (xdisplay, error);
}
else
{
meta_bug ("Unexpected X error: %s serial %ld error_code %d request_code %d minor_code %d)\n",
buf,
error->serial,
error->error_code,
error->request_code,
error->minor_code);
retval = 1; /* compiler warning */
}
return retval;
}
static int
x_io_error_handler (Display *xdisplay)
{
MetaDisplay *display;
display = meta_display_for_x_display (xdisplay);
if (display == NULL)
meta_bug ("IO error received for unknown display?\n");
if (errno == EPIPE)
{
meta_warning (_("Lost connection to the display '%s';\n"
"most likely the X server was shut down or you killed/destroyed\n"
"the window manager.\n"),
display->name);
}
else
{
meta_warning (_("Fatal IO error %d (%s) on display '%s'.\n"),
errno, g_strerror (errno),
display->name);
}
/* Xlib would force an exit anyhow */
exit (1);
return 0;
}

View File

@@ -29,7 +29,9 @@
#include "errors.h"
#include "keybindings-private.h"
#ifdef HAVE_RENDER
#include <X11/extensions/Xrender.h>
#endif
#define EVENT_MASK (SubstructureRedirectMask | \
StructureNotifyMask | SubstructureNotifyMask | \
@@ -153,7 +155,7 @@ meta_window_ensure_frame (MetaWindow *window)
window->rect.x,
window->rect.y);
/* FIXME handle this error */
meta_error_trap_pop (window->display);
meta_error_trap_pop (window->display, FALSE);
/* stick frame to the window */
window->frame = frame;
@@ -217,7 +219,7 @@ meta_window_destroy_frame (MetaWindow *window)
*/
window->frame->rect.x,
window->frame->rect.y);
meta_error_trap_pop (window->display);
meta_error_trap_pop (window->display, FALSE);
meta_ui_destroy_frame_window (window->screen->ui, frame->xwindow);
@@ -276,7 +278,7 @@ meta_frame_get_flags (MetaFrame *frame)
if (META_WINDOW_ALLOWS_VERTICAL_RESIZE (frame->window))
flags |= META_FRAME_ALLOWS_VERTICAL_RESIZE;
if (meta_window_appears_focused (frame->window))
if (frame->window->has_focus)
flags |= META_FRAME_HAS_FOCUS;
if (frame->window->shaded)

View File

@@ -104,10 +104,6 @@ meta_group_unref (MetaGroup *group)
}
}
/**
* meta_window_get_group: (skip)
*
*/
MetaGroup*
meta_window_get_group (MetaWindow *window)
{
@@ -202,10 +198,6 @@ meta_window_shutdown_group (MetaWindow *window)
remove_window_from_group (window);
}
/**
* meta_display_lookup_group: (skip)
*
*/
MetaGroup*
meta_display_lookup_group (MetaDisplay *display,
Window group_leader)
@@ -221,12 +213,6 @@ meta_display_lookup_group (MetaDisplay *display,
return group;
}
/**
* meta_group_list_windows:
* @group: A #MetaGroup
*
* Returns: (transfer container) (element-type Meta.Window): List of windows
*/
GSList*
meta_group_list_windows (MetaGroup *group)
{
@@ -277,10 +263,6 @@ meta_group_get_startup_id (MetaGroup *group)
return group->startup_id;
}
/**
* meta_group_property_notify: (skip)
*
*/
gboolean
meta_group_property_notify (MetaGroup *group,
XEvent *event)

View File

@@ -241,7 +241,7 @@ read_rgb_icon (MetaDisplay *display,
0, G_MAXLONG,
False, XA_CARDINAL, &type, &format, &nitems,
&bytes_after, &data);
err = meta_error_trap_pop_with_return (display);
err = meta_error_trap_pop_with_return (display, TRUE);
if (err != Success ||
result != Success)
@@ -394,19 +394,21 @@ try_pixmap_and_mask (MetaDisplay *display,
get_pixmap_geometry (display, src_pixmap, &w, &h, NULL);
unscaled = meta_gdk_pixbuf_get_from_pixmap (src_pixmap,
0, 0,
unscaled = meta_gdk_pixbuf_get_from_pixmap (NULL,
src_pixmap,
0, 0, 0, 0,
w, h);
if (unscaled && src_mask != None)
{
get_pixmap_geometry (display, src_mask, &w, &h, NULL);
mask = meta_gdk_pixbuf_get_from_pixmap (src_mask,
0, 0,
mask = meta_gdk_pixbuf_get_from_pixmap (NULL,
src_mask,
0, 0, 0, 0,
w, h);
}
meta_error_trap_pop (display);
meta_error_trap_pop (display, FALSE);
if (mask)
{
@@ -482,7 +484,7 @@ get_kwm_win_icon (MetaDisplay *display,
&bytes_after, &data);
icons = (Pixmap *)data;
err = meta_error_trap_pop_with_return (display);
err = meta_error_trap_pop_with_return (display, TRUE);
if (err != Success ||
result != Success)
return;

View File

@@ -45,7 +45,7 @@ gboolean meta_window_grab_all_keys (MetaWindow *window,
guint32 timestamp);
void meta_window_ungrab_all_keys (MetaWindow *window,
guint32 timestamp);
gboolean meta_display_process_key_event (MetaDisplay *display,
void meta_display_process_key_event (MetaDisplay *display,
MetaWindow *window,
XEvent *event);
void meta_set_keybindings_disabled (gboolean setting);

View File

@@ -35,6 +35,7 @@
#include "frame-private.h"
#include "place.h"
#include "prefs.h"
#include "effects.h"
#include "util.h"
#include <X11/keysym.h>
@@ -459,7 +460,7 @@ regrab_key_bindings (MetaDisplay *display)
tmp = tmp->next;
}
windows = meta_display_list_windows (display, META_LIST_DEFAULT);
windows = meta_display_list_windows (display);
tmp = windows;
while (tmp != NULL)
{
@@ -470,16 +471,16 @@ regrab_key_bindings (MetaDisplay *display)
tmp = tmp->next;
}
meta_error_trap_pop (display);
meta_error_trap_pop (display, FALSE);
g_slist_free (windows);
}
static MetaKeyBinding *
display_get_keybinding (MetaDisplay *display,
unsigned int keysym,
unsigned int keycode,
unsigned long mask)
static MetaKeyBindingAction
display_get_keybinding_action (MetaDisplay *display,
unsigned int keysym,
unsigned int keycode,
unsigned long mask)
{
int i;
@@ -490,40 +491,13 @@ display_get_keybinding (MetaDisplay *display,
display->key_bindings[i].keycode == keycode &&
display->key_bindings[i].mask == mask)
{
return &display->key_bindings[i];
return meta_prefs_get_keybinding_action (display->key_bindings[i].name);
}
--i;
}
return NULL;
}
/**
* meta_display_get_keybinding_action:
* @display: A #MetaDisplay
* @keycode: Raw keycode
* @mask: Event mask
*
* Returns: The action that should be taken for the given key, or
* %META_KEYBINDING_ACTION_NONE.
*/
MetaKeyBindingAction
meta_display_get_keybinding_action (MetaDisplay *display,
unsigned int keycode,
unsigned long mask)
{
MetaKeyBinding *binding;
KeySym keysym;
keysym = XKeycodeToKeysym (display->xdisplay, keycode, 0);
mask = mask & 0xff & ~display->ignored_modifier_mask;
binding = display_get_keybinding (display, keysym, keycode, mask);
if (binding)
return meta_prefs_get_keybinding_action (binding->name);
else
return META_KEYBINDING_ACTION_NONE;
return META_KEYBINDING_ACTION_NONE;
}
void
@@ -700,7 +674,7 @@ meta_change_keygrab (MetaDisplay *display,
{
int result;
result = meta_error_trap_pop_with_return (display);
result = meta_error_trap_pop_with_return (display, FALSE);
if (grab && result != Success)
{
@@ -716,7 +690,7 @@ meta_change_keygrab (MetaDisplay *display,
++ignored_mask;
}
meta_error_trap_pop (display);
meta_error_trap_pop (display, FALSE);
}
static void
@@ -758,7 +732,7 @@ grab_keys (MetaKeyBinding *bindings,
++i;
}
meta_error_trap_pop (display);
meta_error_trap_pop (display, FALSE);
}
static void
@@ -777,14 +751,14 @@ ungrab_all_keys (MetaDisplay *display,
{
int result;
result = meta_error_trap_pop_with_return (display);
result = meta_error_trap_pop_with_return (display, FALSE);
if (result != Success)
meta_topic (META_DEBUG_KEYBINDINGS,
"Ungrabbing all keys on 0x%lx failed\n", xwindow);
}
else
meta_error_trap_pop (display);
meta_error_trap_pop (display, FALSE);
}
void
@@ -916,7 +890,7 @@ grab_keyboard (MetaDisplay *display,
if (grab_status != GrabSuccess)
{
meta_error_trap_pop_with_return (display);
meta_error_trap_pop_with_return (display, TRUE);
meta_topic (META_DEBUG_KEYBINDINGS,
"XGrabKeyboard() returned failure status %s time %u\n",
grab_status_to_string (grab_status),
@@ -925,7 +899,7 @@ grab_keyboard (MetaDisplay *display,
}
else
{
result = meta_error_trap_pop_with_return (display);
result = meta_error_trap_pop_with_return (display, TRUE);
if (result != Success)
{
meta_topic (META_DEBUG_KEYBINDINGS,
@@ -948,7 +922,7 @@ ungrab_keyboard (MetaDisplay *display, guint32 timestamp)
"Ungrabbing keyboard with timestamp %u\n",
timestamp);
XUngrabKeyboard (display->xdisplay, timestamp);
meta_error_trap_pop (display);
meta_error_trap_pop (display, FALSE);
}
gboolean
@@ -1224,45 +1198,6 @@ process_overlay_key (MetaDisplay *display,
return TRUE;
}
static void
invoke_handler (MetaDisplay *display,
MetaScreen *screen,
MetaKeyHandler *handler,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding)
{
if (handler->func)
(* handler->func) (display, screen,
handler->flags & BINDING_PER_WINDOW ?
window : NULL,
event,
binding,
handler->user_data);
else
(* handler->default_func) (display, screen,
handler->flags & BINDING_PER_WINDOW ?
window: NULL,
event,
binding,
NULL);
}
static void
invoke_handler_by_name (MetaDisplay *display,
MetaScreen *screen,
const char *handler_name,
MetaWindow *window,
XEvent *event)
{
MetaKeyHandler *handler;
handler = find_handler (key_handlers, handler_name);
if (handler)
invoke_handler (display, screen, handler, window, event, NULL);
}
/* now called from only one place, may be worth merging */
static gboolean
process_event (MetaKeyBinding *bindings,
@@ -1319,7 +1254,20 @@ process_event (MetaKeyBinding *bindings,
*/
display->allow_terminal_deactivation = TRUE;
invoke_handler (display, screen, handler, window, event, &bindings[i]);
if (handler->func)
(* handler->func) (display, screen,
bindings[i].handler->flags & BINDING_PER_WINDOW ?
window: NULL,
event,
&bindings[i],
handler->user_data);
else
(* handler->default_func) (display, screen,
bindings[i].handler->flags & BINDING_PER_WINDOW ?
window: NULL,
event,
&bindings[i],
NULL);
return TRUE;
}
@@ -1334,16 +1282,13 @@ process_event (MetaKeyBinding *bindings,
* right. This cannot cause infinite recursion because we never call
* ourselves when there wasn't a grab, and we always clear the grab
* first; the invariant is enforced using an assertion. See #112560.
*
* The return value is whether we handled the key event.
*
* FIXME: We need to prove there are no race conditions here.
* FIXME: Does it correctly handle alt-Tab being followed by another
* grabbing keypress without letting go of alt?
* FIXME: An iterative solution would probably be simpler to understand
* (and help us solve the other fixmes).
*/
gboolean
void
meta_display_process_key_event (MetaDisplay *display,
MetaWindow *window,
XEvent *event)
@@ -1359,7 +1304,7 @@ meta_display_process_key_event (MetaDisplay *display,
all_bindings_disabled ? ReplayKeyboard : AsyncKeyboard,
event->xkey.time);
if (all_bindings_disabled)
return FALSE;
return;
/* if key event was on root window, we have a shortcut */
screen = meta_display_screen_for_root (display, event->xkey.window);
@@ -1370,11 +1315,12 @@ meta_display_process_key_event (MetaDisplay *display,
event->xany.window);
if (screen == NULL)
return FALSE; /* event window is destroyed */
return; /* event window is destroyed */
/* ignore key events on popup menus and such. */
if (meta_ui_window_is_widget (screen->ui, event->xany.window))
return FALSE;
if (window == NULL &&
meta_ui_window_is_widget (screen->ui, event->xany.window))
return;
/* window may be NULL */
@@ -1394,7 +1340,7 @@ meta_display_process_key_event (MetaDisplay *display,
if (all_keys_grabbed)
{
if (display->grab_op == META_GRAB_OP_NONE)
return TRUE;
return;
/* If we get here we have a global grab, because
* we're in some special keyboard mode such as window move
* mode.
@@ -1471,20 +1417,18 @@ meta_display_process_key_event (MetaDisplay *display,
"Ending grab op %u on key event sym %s\n",
display->grab_op, XKeysymToString (keysym));
meta_display_end_grab_op (display, event->xkey.time);
return;
}
return TRUE;
}
}
handled = process_overlay_key (display, screen, event, keysym);
if (handled)
return TRUE;
/* Do the normal keybindings */
return process_event (display->key_bindings,
display->n_key_bindings,
display, screen, window, event, keysym,
!all_keys_grabbed && window);
if (!handled)
process_event (display->key_bindings,
display->n_key_bindings,
display, screen, window, event, keysym,
!all_keys_grabbed && window);
}
static gboolean
@@ -1503,19 +1447,23 @@ process_mouse_move_resize_grab (MetaDisplay *display,
/* End move or resize and restore to original state. If the
* window was a maximized window that had been "shaken loose" we
* need to remaximize it. In normal cases, we need to do a
* moveresize now to get the position back to the original.
* moveresize now to get the position back to the original. In
* wireframe mode, we just need to set grab_was_cancelled to tru
* to avoid avoid moveresizing to the position of the wireframe.
*/
if (window->shaken_loose)
meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
else
else if (!display->grab_wireframe_active)
meta_window_move_resize (display->grab_window,
TRUE,
display->grab_initial_window_pos.x,
display->grab_initial_window_pos.y,
display->grab_initial_window_pos.width,
display->grab_initial_window_pos.height);
else
display->grab_was_cancelled = TRUE;
/* End grab */
return FALSE;
@@ -1546,7 +1494,15 @@ process_keyboard_move_grab (MetaDisplay *display,
if (is_modifier (display, event->xkey.keycode))
return TRUE;
meta_window_get_position (window, &x, &y);
if (display->grab_wireframe_active)
{
x = display->grab_wireframe_rect.x;
y = display->grab_wireframe_rect.y;
}
else
{
meta_window_get_position (window, &x, &y);
}
smart_snap = (event->xkey.state & ShiftMask) != 0;
@@ -1565,19 +1521,23 @@ process_keyboard_move_grab (MetaDisplay *display,
/* End move and restore to original state. If the window was a
* maximized window that had been "shaken loose" we need to
* remaximize it. In normal cases, we need to do a moveresize
* now to get the position back to the original.
* now to get the position back to the original. In wireframe
* mode, we just need to set grab_was_cancelled to tru to avoid
* avoid moveresizing to the position of the wireframe.
*/
if (window->shaken_loose)
meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
else
else if (!display->grab_wireframe_active)
meta_window_move_resize (display->grab_window,
TRUE,
display->grab_initial_window_pos.x,
display->grab_initial_window_pos.y,
display->grab_initial_window_pos.width,
display->grab_initial_window_pos.height);
else
display->grab_was_cancelled = TRUE;
}
/* When moving by increments, we still snap to edges if the move
@@ -1628,7 +1588,10 @@ process_keyboard_move_grab (MetaDisplay *display,
"Computed new window location %d,%d due to keypress\n",
x, y);
meta_window_get_client_root_coords (window, &old_rect);
if (display->grab_wireframe_active)
old_rect = display->grab_wireframe_rect;
else
meta_window_get_client_root_coords (window, &old_rect);
meta_window_edge_resistance_for_move (window,
old_rect.x,
@@ -1639,7 +1602,17 @@ process_keyboard_move_grab (MetaDisplay *display,
smart_snap,
TRUE);
meta_window_move (window, TRUE, x, y);
if (display->grab_wireframe_active)
{
meta_window_update_wireframe (window, x, y,
display->grab_wireframe_rect.width,
display->grab_wireframe_rect.height);
}
else
{
meta_window_move (window, TRUE, x, y);
}
meta_window_update_keyboard_move (window);
}
@@ -1794,13 +1767,21 @@ process_keyboard_resize_grab (MetaDisplay *display,
if (keysym == XK_Escape)
{
/* End resize and restore to original state. */
meta_window_move_resize (display->grab_window,
TRUE,
display->grab_initial_window_pos.x,
display->grab_initial_window_pos.y,
display->grab_initial_window_pos.width,
display->grab_initial_window_pos.height);
/* End resize and restore to original state. If not in
* wireframe mode, we need to do a moveresize now to get the
* position back to the original. If we are in wireframe mode,
* we need to avoid moveresizing to the position of the
* wireframe.
*/
if (!display->grab_wireframe_active)
meta_window_move_resize (display->grab_window,
TRUE,
display->grab_initial_window_pos.x,
display->grab_initial_window_pos.y,
display->grab_initial_window_pos.width,
display->grab_initial_window_pos.height);
else
display->grab_was_cancelled = TRUE;
return FALSE;
}
@@ -1809,8 +1790,16 @@ process_keyboard_resize_grab (MetaDisplay *display,
event, keysym))
return TRUE;
width = window->rect.width;
height = window->rect.height;
if (display->grab_wireframe_active)
{
width = display->grab_wireframe_rect.width;
height = display->grab_wireframe_rect.height;
}
else
{
width = window->rect.width;
height = window->rect.height;
}
gravity = meta_resize_gravity_from_grab_op (display->grab_op);
@@ -1975,7 +1964,10 @@ process_keyboard_resize_grab (MetaDisplay *display,
"%dx%d, gravity %s\n",
width, height, meta_gravity_to_string (gravity));
old_rect = window->rect; /* Don't actually care about x,y */
if (display->grab_wireframe_active)
old_rect = display->grab_wireframe_rect;
else
old_rect = window->rect; /* Don't actually care about x,y */
/* Do any edge resistance/snapping */
meta_window_edge_resistance_for_resize (window,
@@ -1988,16 +1980,32 @@ process_keyboard_resize_grab (MetaDisplay *display,
smart_snap,
TRUE);
/* We don't need to update unless the specified width and height
* are actually different from what we had before.
*/
if (window->rect.width != width || window->rect.height != height)
meta_window_resize_with_gravity (window,
TRUE,
width,
height,
gravity);
if (display->grab_wireframe_active)
{
MetaRectangle new_position;
meta_rectangle_resize_with_gravity (&display->grab_wireframe_rect,
&new_position,
gravity,
width,
height);
meta_window_update_wireframe (window,
new_position.x,
new_position.y,
new_position.width,
new_position.height);
}
else
{
/* We don't need to update unless the specified width and height
* are actually different from what we had before.
*/
if (window->rect.width != width || window->rect.height != height)
meta_window_resize_with_gravity (window,
TRUE,
width,
height,
gravity);
}
meta_window_update_keyboard_resize (window, FALSE);
}
@@ -2037,7 +2045,6 @@ process_tab_grab (MetaDisplay *display,
XEvent *event,
KeySym keysym)
{
MetaKeyBinding *binding;
MetaKeyBindingAction action;
gboolean popup_not_showing;
gboolean backward;
@@ -2047,84 +2054,79 @@ process_tab_grab (MetaDisplay *display,
if (screen != display->grab_screen)
return FALSE;
binding = display_get_keybinding (display,
keysym,
event->xkey.keycode,
display->grab_mask);
if (binding)
action = meta_prefs_get_keybinding_action (binding->name);
else
action = META_KEYBINDING_ACTION_NONE;
action = display_get_keybinding_action (display,
keysym,
event->xkey.keycode,
display->grab_mask);
/*
* If there is no tab_pop up object, i.e., there is some custom handler
* implementing Alt+Tab & Co., we call this custom handler; we do not
* mess about with the grab, as that is up to the handler to deal with.
*/
if (!screen->tab_popup)
if (!screen->tab_handler)
{
if (event->type == KeyRelease)
{
if (end_keyboard_grab (display, event->xkey.keycode))
{
invoke_handler_by_name (display, screen, "tab_popup_select", NULL, event);
/* We return FALSE to end the grab; if the handler ended the grab itself
* that will be a noop. If the handler didn't end the grab, then it's a
* safety measure to prevent a stuck grab.
*/
return FALSE;
}
return TRUE;
}
MetaKeyHandler *handler = NULL;
const gchar *handler_name = NULL;
switch (action)
{
case META_KEYBINDING_ACTION_CYCLE_PANELS:
handler_name = "cycle_group";
break;
case META_KEYBINDING_ACTION_CYCLE_WINDOWS:
handler_name = "cycle_windows";
break;
case META_KEYBINDING_ACTION_CYCLE_PANELS_BACKWARD:
handler_name = "cycle_panels_backward";
break;
case META_KEYBINDING_ACTION_CYCLE_WINDOWS_BACKWARD:
handler_name = "cycle_windows_backward";
break;
case META_KEYBINDING_ACTION_SWITCH_PANELS:
handler_name = "switch_panels";
break;
case META_KEYBINDING_ACTION_SWITCH_WINDOWS:
handler_name = "switch_windows";
break;
case META_KEYBINDING_ACTION_SWITCH_PANELS_BACKWARD:
handler_name = "switch_panels_backward";
break;
case META_KEYBINDING_ACTION_SWITCH_WINDOWS_BACKWARD:
handler_name = "switch_windows_backward";
break;
case META_KEYBINDING_ACTION_CYCLE_GROUP:
handler_name = "cycle_group";
break;
case META_KEYBINDING_ACTION_CYCLE_GROUP_BACKWARD:
handler_name = "cycle_group_backward";
break;
case META_KEYBINDING_ACTION_SWITCH_GROUP:
handler_name = "switch_group";
break;
case META_KEYBINDING_ACTION_SWITCH_GROUP_BACKWARD:
/* These are the tab-popup bindings. If a custom Alt-Tab implementation
* is in effect, we expect it to want to handle all of these as a group
*
* If there are some of them that the custom implementation didn't
* handle, we treat them as "unbound" for the duration - running the
* normal handlers could get us into trouble.
*/
if (binding->handler &&
binding->handler->func &&
binding->handler->func != binding->handler->default_func)
{
invoke_handler (display, screen, binding->handler, NULL, event, binding);
return TRUE;
}
handler_name = "switch_group_backward";
break;
case META_KEYBINDING_ACTION_NONE:
{
/*
* If this is simply user pressing the Shift key, we do not want
* to cancel the grab.
*/
if (is_modifier (display, event->xkey.keycode))
return TRUE;
}
default:
break;
/*
* This is the case when the Alt key is released; we preserve
* the grab, as it is up to the custom implementaiton to free it
* (a plugin can catch this in their xevent_filter function).
*/
return TRUE;
}
/* Some unhandled key press */
invoke_handler_by_name (display, screen, "tab_popup_cancel", NULL, event);
return FALSE;
/*
* We do not want to actually call the handler, we just want to ensure
* that if a custom handler is installed, we do not release the grab here.
* The handler will get called as normal in the process_event() function.
*/
handler = find_handler (key_handlers, handler_name);
if (!handler || !handler->func || handler->func == handler->default_func)
return FALSE;
return TRUE;
}
if (event->type == KeyRelease &&
@@ -2569,7 +2571,7 @@ handle_move_to_corner_backend (MetaDisplay *display,
int new_x, new_y;
int frame_width, frame_height;
meta_window_get_work_area_all_monitors (window, &work_area);
meta_window_get_work_area_all_xineramas (window, &work_area);
meta_window_get_outer_rect (window, &outer);
meta_window_get_position (window, &orig_x, &orig_y);
@@ -2701,7 +2703,7 @@ handle_move_to_center (MetaDisplay *display,
int orig_x, orig_y;
int frame_width, frame_height;
meta_window_get_work_area_all_monitors (window, &work_area);
meta_window_get_work_area_all_xineramas (window, &work_area);
meta_window_get_outer_rect (window, &outer);
meta_window_get_position (window, &orig_x, &orig_y);
@@ -2776,9 +2778,10 @@ process_workspace_switch_grab (MetaDisplay *display,
MetaWorkspace *target_workspace;
MetaKeyBindingAction action;
action = meta_display_get_keybinding_action (display,
event->xkey.keycode,
display->grab_mask);
action = display_get_keybinding_action (display,
keysym,
event->xkey.keycode,
display->grab_mask);
switch (action)
{
@@ -2898,7 +2901,7 @@ handle_panel (MetaDisplay *display,
StructureNotifyMask,
(XEvent*) &ev);
meta_error_trap_pop (display);
meta_error_trap_pop (display, FALSE);
}
static void
@@ -3105,27 +3108,6 @@ handle_cycle (MetaDisplay *display,
backwards, FALSE);
}
static void
handle_tab_popup_select (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
gpointer dummy)
{
/* Stub for custom handlers; no default implementation */
}
static void
handle_tab_popup_cancel (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
gpointer dummy)
{
/* Stub for custom handlers; no default implementation */
}
static void
handle_toggle_fullscreen (MetaDisplay *display,
@@ -3545,10 +3527,6 @@ meta_keybindings_set_custom_handler (const gchar *name,
return TRUE;
}
/**
* meta_keybindings_switch_window: (skip)
*
*/
void
meta_keybindings_switch_window (MetaDisplay *display,
MetaScreen *screen,

View File

@@ -68,14 +68,15 @@
#include <fcntl.h>
#include <locale.h>
#include <time.h>
#include <unistd.h>
#ifdef WITH_CLUTTER
#include <clutter/clutter.h>
#include <clutter/x11/clutter-x11.h>
#endif
#ifdef HAVE_INTROSPECTION
#include <girepository.h>
#include "compositor/meta-plugin-manager.h"
#include "compositor/mutter/mutter-plugin-manager.h"
#endif
/**
@@ -125,13 +126,11 @@ log_handler (const gchar *log_domain,
static void
version (void)
{
const int latest_year = 2010;
g_print (_("mutter %s\n"
"Copyright (C) 2001-%d Havoc Pennington, Red Hat, Inc., and others\n"
"Copyright (C) 2001-2008 Havoc Pennington, Red Hat, Inc., and others\n"
"This is free software; see the source for copying conditions.\n"
"There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"),
VERSION, latest_year);
VERSION);
exit (0);
}
@@ -179,6 +178,11 @@ meta_print_compilation_info (void)
#else
meta_verbose ("Compiled without startup notification\n");
#endif
#ifdef HAVE_COMPOSITE_EXTENSIONS
meta_verbose ("Compiled with composite extensions\n");
#else
meta_verbose ("Compiled without composite extensions\n");
#endif
}
/**
@@ -229,12 +233,16 @@ typedef struct
gboolean sync;
gboolean composite;
gboolean no_composite;
gboolean no_force_fullscreen;
gboolean no_tab_popup;
gchar *introspect;
} MetaArguments;
#ifdef HAVE_COMPOSITE_EXTENSIONS
#define COMPOSITE_OPTS_FLAGS 0
#else /* HAVE_COMPOSITE_EXTENSIONS */
/* No compositor, so don't show the arguments in --help */
#define COMPOSITE_OPTS_FLAGS G_OPTION_FLAG_HIDDEN
#endif /* HAVE_COMPOSITE_EXTENSIONS */
/**
* Parses argc and argv and returns the
@@ -308,18 +316,14 @@ meta_parse_options (int *argc, char ***argv,
N_("Turn compositing off"),
NULL
},
{
"no-force-fullscreen", 0, COMPOSITE_OPTS_FLAGS, G_OPTION_ARG_NONE,
&my_args.no_force_fullscreen,
N_("Don't make fullscreen windows that are maximized and have no decorations"),
NULL
},
#ifdef WITH_CLUTTER
{
"mutter-plugins", 0, 0, G_OPTION_ARG_STRING,
&my_args.mutter_plugins,
N_("Comma-separated list of compositor plugins"),
"PLUGINS"
},
#endif
{
"no-tab-popup", 0, 0, G_OPTION_ARG_NONE,
&my_args.no_tab_popup,
@@ -340,8 +344,15 @@ meta_parse_options (int *argc, char ***argv,
ctx = g_option_context_new (NULL);
g_option_context_add_main_entries (ctx, options, "mutter");
#ifdef WITH_CLUTTER
/*
* This function is only available in clutter >= 0.8.2
*/
#if CLUTTER_CHECK_VERSION(0,8,2)
g_option_context_add_group (ctx, clutter_get_option_group_without_init ());
g_option_context_add_group (ctx, cogl_get_option_group ());
#endif
#endif
if (!g_option_context_parse (ctx, argc, argv, &error))
{
@@ -354,6 +365,8 @@ meta_parse_options (int *argc, char ***argv,
return ctx;
}
#ifdef WITH_CLUTTER
/* Mutter is responsible for pulling events off the X queue, so Clutter
* doesn't need (and shouldn't) run its normal event source which polls
* the X fd, but we do have to deal with dispatching events that accumulate
@@ -401,20 +414,24 @@ static GSourceFuncs event_funcs = {
static void
meta_clutter_init (GOptionContext *ctx, int *argc, char ***argv)
{
clutter_x11_set_display (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
clutter_x11_set_display (gdk_display);
clutter_x11_disable_event_retrieval ();
if (CLUTTER_INIT_SUCCESS == clutter_init (argc, argv))
{
meta_compositor_can_use_clutter__ = 1;
GSource *source = g_source_new (&event_funcs, sizeof (GSource));
g_source_attach (source, NULL);
g_source_unref (source);
}
else
{
meta_fatal ("Unable to initialize Clutter.\n");
g_message ("Unable to initialize Clutter.\n");
meta_compositor_can_use_clutter__ = 0;
}
}
#endif
/**
* Selects which display Mutter should use. It first tries to use
@@ -438,37 +455,43 @@ meta_select_display (gchar *display_name)
static void
meta_finalize (void)
{
MetaDisplay *display = meta_get_display ();
if (display)
meta_display_close (display,
CurrentTime); /* I doubt correct timestamps matter here */
meta_display_close (meta_get_display (),
CurrentTime); /* I doubt correct timestamps matter here */
meta_session_shutdown ();
}
static int sigterm_pipe_fds[2] = { -1, -1 };
static void
sigterm_handler (int signum)
{
if (sigterm_pipe_fds[1] >= 0)
{
int dummy;
meta_finalize ();
dummy = write (sigterm_pipe_fds[1], "", 1);
close (sigterm_pipe_fds[1]);
sigterm_pipe_fds[1] = -1;
}
exit (meta_exit_code);
}
static gboolean
on_sigterm (void)
static guint sigchld_signal_id = 0;
static void
sigchld_handler (int signum, siginfo_t *info, void *context)
{
meta_quit (META_EXIT_SUCCESS);
return FALSE;
}
int stat;
if (info->si_code == CLD_EXITED)
{
g_signal_emit (sigchld_nexus, sigchld_signal_id, 0,
info->si_status,
GINT_TO_POINTER (info->si_pid));
}
g_signal_handlers_disconnect_matched (sigchld_nexus,
G_SIGNAL_MATCH_DATA,
sigchld_signal_id,
0, NULL, NULL,
GINT_TO_POINTER (info->si_pid));
waitpid (info->si_pid, &stat, WNOHANG);
}
/**
* This is where the story begins. It parses commandline options and
* environment variables, sets up the screen, hands control off to
@@ -491,9 +514,8 @@ main (int argc, char **argv)
"Pango", "GLib-GObject", "GThread"
};
guint i;
GIOChannel *channel;
GOptionContext *ctx;
if (!g_thread_supported ())
g_thread_init (NULL);
@@ -515,21 +537,29 @@ main (int argc, char **argv)
g_strerror (errno));
#endif
if (pipe (sigterm_pipe_fds) != 0)
g_printerr ("Failed to create SIGTERM pipe: %s\n",
g_strerror (errno));
channel = g_io_channel_unix_new (sigterm_pipe_fds[0]);
g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL);
g_io_add_watch (channel, G_IO_IN, (GIOFunc) on_sigterm, NULL);
g_io_channel_set_close_on_unref (channel, TRUE);
g_io_channel_unref (channel);
act.sa_handler = &sigterm_handler;
if (sigaction (SIGTERM, &act, NULL) < 0)
g_printerr ("Failed to register SIGTERM handler: %s\n",
g_strerror (errno));
sigchld_nexus = g_object_new (META_TYPE_NEXUS, NULL);
sigchld_signal_id =
g_signal_new ("sigchld", META_TYPE_NEXUS,
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__UINT_POINTER,
G_TYPE_NONE,
2,
G_TYPE_UINT, G_TYPE_POINTER);
act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
act.sa_handler = SIG_DFL;
act.sa_sigaction = &sigchld_handler;
if (sigaction (SIGCHLD, &act, NULL) < 0)
g_printerr ("Failed to register SIGCHLD handler: %s\n",
g_strerror (errno));
if (g_getenv ("MUTTER_VERBOSE"))
meta_set_verbose (TRUE);
if (g_getenv ("MUTTER_DEBUG"))
@@ -551,6 +581,7 @@ main (int argc, char **argv)
/* Parse command line arguments.*/
ctx = meta_parse_options (&argc, &argv, &meta_args);
#ifdef WITH_CLUTTER
/* This must come before the introspect below, so we load all the plugins
* in order to get their get_type functions.
*/
@@ -572,6 +603,7 @@ main (int argc, char **argv)
g_slist_free(plugins_list);
g_strfreev (plugins);
}
#endif /* WITH_CLUTTER */
#ifdef HAVE_INTROSPECTION
g_irepository_prepend_search_path (MUTTER_PKGLIBDIR);
@@ -586,8 +618,8 @@ main (int argc, char **argv)
* is initialized at this point, and we don't plan to run any real
* plugin code.
*/
MetaPluginManager *mgr = meta_plugin_manager_get_default ();
if (!meta_plugin_manager_load (mgr))
MutterPluginManager *mgr = mutter_plugin_manager_new (NULL);
if (!mutter_plugin_manager_load (mgr))
g_critical ("failed to load plugins");
}
if (!g_irepository_dump (meta_args.introspect, &error))
@@ -616,13 +648,18 @@ main (int argc, char **argv)
meta_ui_init (&argc, &argv);
#ifdef WITH_CLUTTER
/*
* Clutter can only be initialized after the UI.
*/
meta_clutter_init (ctx, &argc, &argv);
#endif
g_option_context_free (ctx);
/* must be after UI init so we can override GDK handlers */
meta_errors_init ();
/* Load prefs */
meta_prefs_init ();
meta_prefs_add_listener (prefs_changed_callback, NULL);
@@ -708,9 +745,6 @@ main (int argc, char **argv)
if (meta_args.composite || meta_args.no_composite)
meta_prefs_set_compositing_manager (meta_args.composite);
if (meta_args.no_force_fullscreen)
meta_prefs_set_force_fullscreen (FALSE);
if (meta_args.no_tab_popup)
{
meta_prefs_override_no_tab_popup (TRUE);

View File

@@ -26,7 +26,6 @@
#include <config.h>
#include "boxes-private.h"
#include "place.h"
#include "workspace.h"
#include "prefs.h"
@@ -105,7 +104,7 @@ find_next_cascade (MetaWindow *window,
int window_width, window_height;
int cascade_stage;
MetaRectangle work_area;
const MetaMonitorInfo* current;
const MetaXineramaScreenInfo* current;
sorted = g_list_copy (windows);
sorted = g_list_sort (sorted, northwestcmp);
@@ -136,8 +135,8 @@ find_next_cascade (MetaWindow *window,
* of NW corner of window frame.
*/
current = meta_screen_get_current_monitor (window->screen);
meta_window_get_work_area_for_monitor (window, current->number, &work_area);
current = meta_screen_get_current_xinerama (window->screen);
meta_window_get_work_area_for_xinerama (window, current->number, &work_area);
cascade_x = MAX (0, work_area.x);
cascade_y = MAX (0, work_area.y);
@@ -258,7 +257,7 @@ find_most_freespace (MetaWindow *window,
frame_size_left = fgeom ? fgeom->left_width : 0;
frame_size_top = fgeom ? fgeom->top_height : 0;
meta_window_get_work_area_current_monitor (focus_window, &work_area);
meta_window_get_work_area_current_xinerama (focus_window, &work_area);
meta_window_get_outer_rect (focus_window, &avoid);
meta_window_get_outer_rect (window, &outer);
@@ -509,7 +508,7 @@ find_first_fit (MetaWindow *window,
MetaFrameGeometry *fgeom,
/* visible windows on relevant workspaces */
GList *windows,
int monitor,
int xinerama,
int x,
int y,
int *new_x,
@@ -552,16 +551,16 @@ find_first_fit (MetaWindow *window,
#ifdef WITH_VERBOSE_MODE
{
char monitor_location_string[RECT_LENGTH];
meta_rectangle_to_string (&window->screen->monitor_infos[monitor].rect,
monitor_location_string);
char xinerama_location_string[RECT_LENGTH];
meta_rectangle_to_string (&window->screen->xinerama_infos[xinerama].rect,
xinerama_location_string);
meta_topic (META_DEBUG_XINERAMA,
"Natural monitor is %s\n",
monitor_location_string);
"Natural xinerama is %s\n",
xinerama_location_string);
}
#endif
meta_window_get_work_area_for_monitor (window, monitor, &work_area);
meta_window_get_work_area_for_xinerama (window, xinerama, &work_area);
center_tile_rect_in_area (&rect, &work_area);
@@ -659,7 +658,7 @@ meta_window_place (MetaWindow *window,
int *new_y)
{
GList *windows;
const MetaMonitorInfo *xi;
const MetaXineramaScreenInfo *xi;
/* frame member variables should NEVER be used in here, only
* MetaFrameGeometry. But remember fgeom == NULL
@@ -811,11 +810,11 @@ meta_window_place (MetaWindow *window,
window->type == META_WINDOW_MODAL_DIALOG ||
window->type == META_WINDOW_SPLASHSCREEN)
{
/* Center on current monitor */
/* Center on current xinerama (i.e. on current monitor) */
int w, h;
/* Warning, this function is a round trip! */
xi = meta_screen_get_current_monitor (window->screen);
xi = meta_screen_get_current_xinerama (window->screen);
w = xi->rect.width;
h = xi->rect.height;
@@ -826,7 +825,7 @@ meta_window_place (MetaWindow *window,
x += xi->rect.x;
y += xi->rect.y;
meta_topic (META_DEBUG_PLACEMENT, "Centered window %s on screen %d monitor %d\n",
meta_topic (META_DEBUG_PLACEMENT, "Centered window %s on screen %d xinerama %d\n",
window->desc, window->screen->number, xi->number);
goto done_check_denied_focus;
@@ -840,7 +839,7 @@ meta_window_place (MetaWindow *window,
GSList *all_windows;
GSList *tmp;
all_windows = meta_display_list_windows (window->display, META_LIST_DEFAULT);
all_windows = meta_display_list_windows (window->display);
tmp = all_windows;
while (tmp != NULL)
@@ -860,7 +859,7 @@ meta_window_place (MetaWindow *window,
}
/* Warning, this is a round trip! */
xi = meta_screen_get_current_monitor (window->screen);
xi = meta_screen_get_current_xinerama (window->screen);
/* "Origin" placement algorithm */
x = xi->rect.x;
@@ -881,9 +880,9 @@ meta_window_place (MetaWindow *window,
MetaRectangle workarea;
MetaRectangle outer;
meta_window_get_work_area_for_monitor (window,
xi->number,
&workarea);
meta_window_get_work_area_for_xinerama (window,
xi->number,
&workarea);
meta_window_get_outer_rect (window, &outer);
/* If the window is bigger than the screen, then automaximize. Do NOT

View File

@@ -27,7 +27,6 @@
#include "prefs.h"
#include "ui.h"
#include "util.h"
#include "compositor/meta-plugin-manager.h"
#ifdef HAVE_GCONF
#include <gconf/gconf-client.h>
#endif
@@ -53,7 +52,6 @@
#define KEY_COMPOSITOR "/apps/metacity/general/compositing_manager"
#define KEY_GNOME_ACCESSIBILITY "/desktop/gnome/interface/accessibility"
#define KEY_COMMAND_DIRECTORY "/apps/metacity/keybinding_commands"
#define KEY_COMMAND_PREFIX "/apps/metacity/keybinding_commands/command_"
#define KEY_TERMINAL_DIR "/desktop/gnome/applications/terminal"
@@ -64,10 +62,12 @@
#define KEY_WINDOW_BINDINGS_PREFIX "/apps/metacity/window_keybindings"
#define KEY_LIST_BINDINGS_SUFFIX "_list"
#define KEY_WORKSPACE_NAME_DIRECTORY "/apps/metacity/workspace_names"
#define KEY_WORKSPACE_NAME_PREFIX "/apps/metacity/workspace_names/name_"
#ifdef WITH_CLUTTER
#define KEY_CLUTTER_DISABLED "/apps/mutter/general/clutter_disabled"
#define KEY_CLUTTER_PLUGINS "/apps/mutter/general/clutter_plugins"
#endif
#define KEY_LIVE_HIDDEN_WINDOWS "/apps/mutter/general/live_hidden_windows"
@@ -86,7 +86,6 @@ static MetaVirtualModifier mouse_button_mods = Mod1Mask;
static MetaFocusMode focus_mode = META_FOCUS_MODE_CLICK;
static MetaFocusNewWindows focus_new_windows = META_FOCUS_NEW_WINDOWS_SMART;
static gboolean raise_on_click = TRUE;
static gboolean attach_modal_dialogs = FALSE;
static char* current_theme = NULL;
static int num_workspaces = 4;
static MetaActionTitlebar action_double_click_titlebar = META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE;
@@ -98,14 +97,13 @@ static gboolean auto_raise = FALSE;
static gboolean auto_raise_delay = 500;
static gboolean provide_visual_bell = FALSE;
static gboolean bell_is_audible = TRUE;
static gboolean reduced_resources = FALSE;
static gboolean gnome_accessibility = FALSE;
static gboolean gnome_animations = TRUE;
static char *cursor_theme = NULL;
static int cursor_size = 24;
static gboolean compositing_manager = FALSE;
static gboolean resize_with_right_button = FALSE;
static gboolean side_by_side_tiling = FALSE;
static gboolean force_fullscreen = TRUE;
static MetaVisualBellType visual_bell_type = META_VISUAL_BELL_FULLSCREEN_FLASH;
static MetaButtonLayout button_layout;
@@ -117,8 +115,11 @@ static char *terminal_command = NULL;
static char *workspace_names[MAX_REASONABLE_WORKSPACES] = { NULL, };
#ifdef WITH_CLUTTER
static gboolean clutter_disabled = FALSE;
static gboolean clutter_plugins_overridden = FALSE;
static GSList *clutter_plugins = NULL;
#endif
static gboolean live_hidden_windows = FALSE;
@@ -127,30 +128,18 @@ static gboolean no_tab_popup = FALSE;
#ifdef HAVE_GCONF
static gboolean handle_preference_update_enum (const gchar *key, GConfValue *value);
static char *binding_name (const char *gconf_key);
static gboolean update_key_binding (const char *key,
static gboolean update_key_binding (const char *name,
const char *value);
typedef enum
{
META_LIST_OF_STRINGS,
META_LIST_OF_GCONFVALUE_STRINGS
} MetaStringListType;
static gboolean find_and_update_list_binding (MetaKeyPref *bindings,
const char *key,
GSList *value,
MetaStringListType type_of_value);
static gboolean update_key_list_binding (const char *key,
GSList *value,
MetaStringListType type_of_value);
static gboolean find_and_update_list_binding (MetaKeyPref *bindings,
const char *name,
GSList *value);
static gboolean update_key_list_binding (const char *name,
GSList *value);
static gboolean update_command (const char *name,
const char *value);
static gboolean update_workspace_name (const char *name,
const char *value);
static void notify_new_value (const char *key,
GConfValue *value);
static void change_notify (GConfClient *client,
guint cnxn_id,
GConfEntry *entry,
@@ -160,8 +149,14 @@ static char* gconf_key_for_workspace_name (int i);
static void queue_changed (MetaPreference pref);
static gboolean update_list_binding (MetaKeyPref *binding,
GSList *value,
typedef enum
{
META_LIST_OF_STRINGS,
META_LIST_OF_GCONFVALUE_STRINGS
} MetaStringListType;
static gboolean update_list_binding (MetaKeyPref *binding,
GSList *value,
MetaStringListType type_of_value);
static void cleanup_error (GError **error);
@@ -233,12 +228,7 @@ static GConfEnumStringPair symtab_titlebar_action[] =
{ 0, NULL },
};
/*
* Note that 'gchar *key' is the first element of all these structures;
* we count on that below in key_is_used and do_override.
*/
/*
/**
* The details of one preference which is constrained to be
* one of a small number of string values-- in other words,
* an enumeration.
@@ -251,6 +241,21 @@ static GConfEnumStringPair symtab_titlebar_action[] =
* been outweighed by the bugs caused when the ordering of the enum
* strings got out of sync with the actual enum statement. Also,
* there is existing library code to use this kind of symbol tables.
*
* Other things we might consider doing to clean this up in the
* future include:
*
* - most of the keys begin with the same prefix, and perhaps we
* could assume it if they don't start with a slash
*
* - there are several cases where a single identifier could be used
* to generate an entire entry, and perhaps this could be done
* with a macro. (This would reduce clarity, however, and is
* probably a bad thing.)
*
* - these types all begin with a gchar* (and contain a MetaPreference)
* and we can factor out the repeated code in the handlers by taking
* advantage of this using some kind of union arrangement.
*/
typedef struct
{
@@ -363,11 +368,6 @@ static MetaEnumPreference preferences_enum[] =
static MetaBoolPreference preferences_bool[] =
{
{ "/apps/mutter/general/attach_modal_dialogs",
META_PREF_ATTACH_MODAL_DIALOGS,
&attach_modal_dialogs,
TRUE,
},
{ "/apps/metacity/general/raise_on_click",
META_PREF_RAISE_ON_CLICK,
&raise_on_click,
@@ -403,6 +403,11 @@ static MetaBoolPreference preferences_bool[] =
&bell_is_audible, /* FIXME: change the name: it's confusing */
FALSE,
},
{ "/apps/metacity/general/reduced_resources",
META_PREF_REDUCED_RESOURCES,
&reduced_resources,
FALSE,
},
{ "/desktop/gnome/interface/accessibility",
META_PREF_GNOME_ACCESSIBILITY,
&gnome_accessibility,
@@ -423,11 +428,13 @@ static MetaBoolPreference preferences_bool[] =
&resize_with_right_button,
FALSE,
},
{ "/apps/metacity/general/side_by_side_tiling",
META_PREF_SIDE_BY_SIDE_TILING,
&side_by_side_tiling,
#ifdef WITH_CLUTTER
{ "/apps/mutter/general/clutter_disabled",
META_PREF_CLUTTER_DISABLED,
&clutter_disabled,
FALSE,
},
#endif
{ "/apps/mutter/general/live_hidden_windows",
META_PREF_LIVE_HIDDEN_WINDOWS,
&live_hidden_windows,
@@ -501,20 +508,6 @@ static MetaIntPreference preferences_int[] =
{ NULL, 0, NULL, 0, 0, 0, },
};
/*
* This is used to keep track of preferences that have been
* repointed to a different GConf key location; we modify the
* preferences arrays directly, but we also need to remember
* what we have done to handle subsequent overrides correctly.
*/
typedef struct
{
gchar *original_key;
gchar *new_key;
} MetaPrefsOverriddenKey;
static GSList *overridden_keys;
static void
handle_preference_init_enum (void)
{
@@ -898,10 +891,6 @@ handle_preference_update_int (const gchar *key, GConfValue *value)
/* Listeners. */
/****************************************************************************/
/**
* meta_prefs_add_listener: (skip)
*
*/
void
meta_prefs_add_listener (MetaPrefsChangedFunc func,
gpointer data)
@@ -915,10 +904,6 @@ meta_prefs_add_listener (MetaPrefsChangedFunc func,
listeners = g_list_prepend (listeners, l);
}
/**
* meta_prefs_remove_listener: (skip)
*
*/
void
meta_prefs_remove_listener (MetaPrefsChangedFunc func,
gpointer data)
@@ -1058,7 +1043,6 @@ meta_prefs_init (void)
#ifdef HAVE_GCONF
GError *err = NULL;
gchar **gconf_dir_cursor;
MetaPluginManager *plugin_manager;
if (default_client != NULL)
return;
@@ -1077,19 +1061,6 @@ meta_prefs_init (void)
cleanup_error (&err);
}
/* The plugin list is special and needs to be handled first */
if (!clutter_plugins_overridden)
clutter_plugins = gconf_client_get_list (default_client, KEY_CLUTTER_PLUGINS,
GCONF_VALUE_STRING, &err);
cleanup_error (&err);
/* We now initialize plugins so that they can override any preference locations */
plugin_manager = meta_plugin_manager_get_default ();
meta_plugin_manager_load (plugin_manager);
/* Pick up initial values. */
handle_preference_init_enum ();
@@ -1097,6 +1068,14 @@ meta_prefs_init (void)
handle_preference_init_string ();
handle_preference_init_int ();
#ifdef WITH_CLUTTER
if (!clutter_plugins_overridden)
clutter_plugins = gconf_client_get_list (default_client, KEY_CLUTTER_PLUGINS,
GCONF_VALUE_STRING, &err);
cleanup_error (&err);
#endif
/* @@@ Is there any reason we don't do the add_dir here? */
for (gconf_dir_cursor=gconf_dirs_we_are_interested_in;
*gconf_dir_cursor!=NULL;
@@ -1129,160 +1108,6 @@ meta_prefs_init (void)
init_workspace_names ();
}
/* This count on the key being the first element of the
* preference structure */
static gboolean
key_is_used (void *prefs,
size_t pref_size,
const char *new_key)
{
void *p = prefs;
while (TRUE)
{
char **key = p;
if (*key == NULL)
break;
if (strcmp (*key, new_key) == 0)
return TRUE;
p = (guchar *)p + pref_size;
}
return FALSE;
}
static gboolean
do_override (void *prefs,
size_t pref_size,
const char *search_key,
char *new_key)
{
void *p = prefs;
while (TRUE)
{
char **key = p;
if (*key == NULL)
break;
if (strcmp (*key, search_key) == 0)
{
*key = new_key;
return TRUE;
}
p = (guchar *)p + pref_size;
}
return FALSE;
}
/**
* meta_prefs_override_preference_location
* @original_key: the normal Metacity preference location
* @new_key: the Metacity preference location to use instead.
*
* Substitute a different location to use instead of a standard Metacity
* GConf key location. This might be used if a plugin expected a different
* value for some preference than the Metacity default. While this function
* can be called at any point, this function should generally be called
* in a plugin's constructor, rather than in its start() method so the
* preference isn't first loaded with one value then changed to another
* value.
*/
void
meta_prefs_override_preference_location (const char *original_key,
const char *new_key)
{
const char *search_key;
char *new_key_copy;
gboolean found;
MetaPrefsOverriddenKey *overridden;
GSList *tmp;
/* Merge identical overrides, this isn't an error */
for (tmp = overridden_keys; tmp; tmp = tmp->next)
{
MetaPrefsOverriddenKey *tmp_overridden = tmp->data;
if (strcmp (tmp_overridden->original_key, original_key) == 0 &&
strcmp (tmp_overridden->new_key, new_key) == 0)
return;
}
/* We depend on a unique mapping from GConf key to preference, so
* enforce this */
if (key_is_used (preferences_enum, sizeof(MetaEnumPreference), new_key) ||
key_is_used (preferences_bool, sizeof(MetaBoolPreference), new_key) ||
key_is_used (preferences_string, sizeof(MetaStringPreference), new_key) ||
key_is_used (preferences_int, sizeof(MetaIntPreference), new_key))
{
meta_warning (_("GConf key %s is already in use and can't be used to override %s\n"),
new_key, original_key);
}
new_key_copy = g_strdup (new_key);
search_key = original_key;
overridden = NULL;
for (tmp = overridden_keys; tmp; tmp = tmp->next)
{
MetaPrefsOverriddenKey *tmp_overridden = tmp->data;
if (strcmp (overridden->original_key, original_key) == 0)
{
overridden = tmp_overridden;
search_key = tmp_overridden->new_key;
}
}
found =
do_override (preferences_enum, sizeof(MetaEnumPreference), search_key, new_key_copy) ||
do_override (preferences_bool, sizeof(MetaBoolPreference), search_key, new_key_copy) ||
do_override (preferences_string, sizeof(MetaStringPreference), search_key, new_key_copy) ||
do_override (preferences_int, sizeof(MetaIntPreference), search_key, new_key_copy);
if (found)
{
if (overridden)
{
g_free (overridden->new_key);
overridden->new_key = new_key_copy;
}
else
{
overridden = g_slice_new (MetaPrefsOverriddenKey);
overridden->original_key = g_strdup (original_key);
overridden->new_key = new_key_copy;
}
#ifdef HAVE_GCONF
if (default_client != NULL)
{
/* We're already initialized, so notify of a change */
GConfValue *value;
GError *err = NULL;
value = gconf_client_get (default_client, new_key, &err);
cleanup_error (&err);
notify_new_value (new_key, value);
if (value)
gconf_value_free (value);
}
#endif /* HAVE_GCONF */
}
else
{
meta_warning (_("Can't override GConf key, %s not found\n"), original_key);
g_free (new_key_copy);
}
}
/****************************************************************************/
/* Updates. */
@@ -1298,23 +1123,6 @@ gboolean (*preference_update_handler[]) (const gchar*, GConfValue*) = {
NULL
};
static void
notify_new_value (const char *key,
GConfValue *value)
{
int i = 0;
/* FIXME: Use MetaGenericPreference and save a bit of code duplication */
while (preference_update_handler[i] != NULL)
{
if (preference_update_handler[i] (key, value))
return;
i++;
}
}
static void
change_notify (GConfClient *client,
guint cnxn_id,
@@ -1323,13 +1131,25 @@ change_notify (GConfClient *client,
{
const char *key;
GConfValue *value;
gint i=0;
key = gconf_entry_get_key (entry);
value = gconf_entry_get_value (entry);
/* First, search for a handler that might know what to do. */
notify_new_value (key, value);
/* FIXME: When this is all working, since the first item in every
* array is the gchar* of the key, there's no reason we can't
* find the correct record for that key here and save code duplication.
*/
while (preference_update_handler[i]!=NULL)
{
if (preference_update_handler[i] (key, value))
goto out; /* Get rid of this eventually */
i++;
}
if (g_str_has_prefix (key, KEY_WINDOW_BINDINGS_PREFIX) ||
g_str_has_prefix (key, KEY_SCREEN_BINDINGS_PREFIX))
@@ -1347,7 +1167,7 @@ change_notify (GConfClient *client,
list = value ? gconf_value_get_list (value) : NULL;
if (update_key_list_binding (key, list, META_LIST_OF_GCONFVALUE_STRINGS))
if (update_key_list_binding (key, list))
queue_changed (META_PREF_KEYBINDINGS);
}
else
@@ -1403,6 +1223,7 @@ change_notify (GConfClient *client,
{
queue_changed (META_PREF_KEYBINDINGS);
}
#ifdef WITH_CLUTTER
else if (g_str_equal (key, KEY_CLUTTER_PLUGINS) && !clutter_plugins_overridden)
{
GError *err = NULL;
@@ -1420,6 +1241,7 @@ change_notify (GConfClient *client,
clutter_plugins = l;
queue_changed (META_PREF_CLUTTER_PLUGINS);
}
#endif
else
{
meta_topic (META_DEBUG_PREFS, "Key %s doesn't mean anything to Mutter\n",
@@ -1505,12 +1327,6 @@ meta_prefs_get_focus_new_windows (void)
return focus_new_windows;
}
gboolean
meta_prefs_get_attach_modal_dialogs (void)
{
return attach_modal_dialogs;
}
gboolean
meta_prefs_get_raise_on_click (void)
{
@@ -1932,9 +1748,6 @@ meta_preference_to_string (MetaPreference pref)
case META_PREF_FOCUS_NEW_WINDOWS:
return "FOCUS_NEW_WINDOWS";
case META_PREF_ATTACH_MODAL_DIALOGS:
return "ATTACH_MODAL_DIALOGS";
case META_PREF_RAISE_ON_CLICK:
return "RAISE_ON_CLICK";
@@ -1992,6 +1805,9 @@ meta_preference_to_string (MetaPreference pref)
case META_PREF_VISUAL_BELL_TYPE:
return "VISUAL_BELL_TYPE";
case META_PREF_REDUCED_RESOURCES:
return "REDUCED_RESOURCES";
case META_PREF_GNOME_ACCESSIBILITY:
return "GNOME_ACCESSIBILTY";
@@ -2009,19 +1825,14 @@ meta_preference_to_string (MetaPreference pref)
case META_PREF_RESIZE_WITH_RIGHT_BUTTON:
return "RESIZE_WITH_RIGHT_BUTTON";
case META_PREF_SIDE_BY_SIDE_TILING:
return "SIDE_BY_SIDE_TILING";
case META_PREF_FORCE_FULLSCREEN:
return "FORCE_FULLSCREEN";
#ifdef WITH_CLUTTER
case META_PREF_CLUTTER_DISABLED:
return "CLUTTER_DISABLED";
case META_PREF_CLUTTER_PLUGINS:
return "CLUTTER_PLUGINS";
#endif
case META_PREF_LIVE_HIDDEN_WINDOWS:
return "LIVE_HIDDEN_WINDOWS";
case META_PREF_NO_TAB_POPUP:
return "NO_TAB_POPUP";
}
@@ -2104,66 +1915,57 @@ init_special_bindings (void)
static void
init_bindings (void)
{
#ifdef HAVE_GCONF
const char *prefix[] = {
KEY_WINDOW_BINDINGS_PREFIX,
KEY_SCREEN_BINDINGS_PREFIX,
NULL
};
int i;
GSList *list, *l, *list_val;
const char *str_val;
const char *key;
GConfEntry *entry;
GConfValue *value;
GHashTable *to_update;
#ifdef HAVE_GCONF
int i = 0;
GError *err;
g_assert (G_N_ELEMENTS (key_bindings) == META_KEYBINDING_ACTION_LAST + 1);
to_update = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
for (i = 0; prefix[i]; i++)
{
list = gconf_client_all_entries (default_client, prefix[i], NULL);
for (l = list; l; l = l->next)
{
entry = l->data;
key = gconf_entry_get_key (entry);
value = gconf_entry_get_value (entry);
if (g_str_has_suffix (key, KEY_LIST_BINDINGS_SUFFIX))
{
/* List bindings are used in addition to the normal bindings and never
* have defaults, so we just go ahead and set them immediately; there
* will be only a few of them, so don't worry about the linear scan
* in find_and_update_list_binding.
*/
list_val = gconf_client_get_list (default_client, key, GCONF_VALUE_STRING, NULL);
update_key_list_binding (key, list_val, META_LIST_OF_STRINGS);
g_slist_foreach (list_val, (GFunc)g_free, NULL);
g_slist_free (list_val);
}
else
{
str_val = gconf_value_get_string (value);
g_hash_table_insert (to_update, binding_name (key), g_strdup (str_val));
}
gconf_entry_free (entry);
}
g_slist_free (list);
}
i = 0;
while (key_bindings[i].name)
{
update_binding (&key_bindings[i],
g_hash_table_lookup (to_update, key_bindings[i].name));
GSList *list_val, *tmp;
char *str_val;
char *key;
key = g_strconcat (key_bindings[i].per_window?
KEY_WINDOW_BINDINGS_PREFIX:
KEY_SCREEN_BINDINGS_PREFIX,
"/",
key_bindings[i].name, NULL);
err = NULL;
str_val = gconf_client_get_string (default_client, key, &err);
cleanup_error (&err);
update_binding (&key_bindings[i], str_val);
g_free (str_val);
g_free (key);
key = g_strconcat (key_bindings[i].per_window?
KEY_WINDOW_BINDINGS_PREFIX:
KEY_SCREEN_BINDINGS_PREFIX,
"/",
key_bindings[i].name,
KEY_LIST_BINDINGS_SUFFIX, NULL);
err = NULL;
list_val = gconf_client_get_list (default_client, key, GCONF_VALUE_STRING, &err);
cleanup_error (&err);
update_list_binding (&key_bindings[i], list_val, META_LIST_OF_STRINGS);
tmp = list_val;
while (tmp)
{
g_free (tmp->data);
tmp = tmp->next;
}
g_slist_free (list_val);
g_free (key);
++i;
}
g_hash_table_destroy (to_update);
#else /* HAVE_GCONF */
int i = 0;
while (key_bindings[i].name)
@@ -2185,23 +1987,28 @@ static void
init_commands (void)
{
#ifdef HAVE_GCONF
GSList *list, *l;
const char *str_val;
const char *key;
GConfEntry *entry;
GConfValue *value;
list = gconf_client_all_entries (default_client, KEY_COMMAND_DIRECTORY, NULL);
for (l = list; l; l = l->next)
int i;
GError *err;
i = 0;
while (i < MAX_COMMANDS)
{
entry = l->data;
key = gconf_entry_get_key (entry);
value = gconf_entry_get_value (entry);
str_val = gconf_value_get_string (value);
char *str_val;
char *key;
key = meta_prefs_get_gconf_key_for_command (i);
err = NULL;
str_val = gconf_client_get_string (default_client, key, &err);
cleanup_error (&err);
update_command (key, str_val);
gconf_entry_free (entry);
g_free (str_val);
g_free (key);
++i;
}
g_slist_free (list);
#else
int i;
for (i = 0; i < MAX_COMMANDS; i++)
@@ -2212,34 +2019,39 @@ init_commands (void)
static void
init_workspace_names (void)
{
int i;
#ifdef HAVE_GCONF
GSList *list, *l;
const char *str_val;
const char *key;
GConfEntry *entry;
GConfValue *value;
list = gconf_client_all_entries (default_client, KEY_WORKSPACE_NAME_DIRECTORY, NULL);
for (l = list; l; l = l->next)
int i;
GError *err;
i = 0;
while (i < MAX_REASONABLE_WORKSPACES)
{
entry = l->data;
key = gconf_entry_get_key (entry);
value = gconf_entry_get_value (entry);
str_val = gconf_value_get_string (value);
update_workspace_name (key, str_val);
gconf_entry_free (entry);
}
g_slist_free (list);
#endif /* HAVE_GCONF */
char *str_val;
char *key;
key = gconf_key_for_workspace_name (i);
err = NULL;
str_val = gconf_client_get_string (default_client, key, &err);
cleanup_error (&err);
update_workspace_name (key, str_val);
g_assert (workspace_names[i] != NULL);
g_free (str_val);
g_free (key);
++i;
}
#else
int i;
for (i = 0; i < MAX_REASONABLE_WORKSPACES; i++)
if (workspace_names[i] == NULL)
workspace_names[i] = g_strdup_printf (_("Workspace %d"), i + 1);
workspace_names[i] = g_strdup_printf (_("Workspace %d"), i + 1);
meta_topic (META_DEBUG_PREFS,
"Initialized workspace names\n");
#endif /* HAVE_GCONF */
}
static gboolean
@@ -2490,22 +2302,16 @@ update_list_binding (MetaKeyPref *binding,
return changed;
}
static char *
binding_name (const char *gconf_key)
static const gchar*
relative_key (const gchar* key)
{
const char *start, *end;
const gchar* end;
end = strrchr (key, '/');
if (*gconf_key == '/')
start = strrchr (gconf_key, '/') + 1;
else
start = gconf_key;
++end;
if (g_str_has_suffix (gconf_key, KEY_LIST_BINDINGS_SUFFIX))
end = gconf_key + strlen(gconf_key) - strlen (KEY_LIST_BINDINGS_SUFFIX);
else
end = gconf_key + strlen(gconf_key);
return g_strndup (start, end - start);
return end;
}
/* Return value is TRUE if a preference changed and we need to
@@ -2513,19 +2319,22 @@ binding_name (const char *gconf_key)
*/
static gboolean
find_and_update_binding (MetaKeyPref *bindings,
const char *key,
const char *name,
const char *value)
{
char *name = binding_name (key);
const char *key;
int i;
if (*name == '/')
key = relative_key (name);
else
key = name;
i = 0;
while (bindings[i].name &&
strcmp (name, bindings[i].name) != 0)
strcmp (key, bindings[i].name) != 0)
++i;
g_free (name);
if (bindings[i].name)
return update_binding (&bindings[i], value);
else
@@ -2533,40 +2342,46 @@ find_and_update_binding (MetaKeyPref *bindings,
}
static gboolean
update_key_binding (const char *key,
const char *value)
update_key_binding (const char *name,
const char *value)
{
return find_and_update_binding (key_bindings, key, value);
return find_and_update_binding (key_bindings, name, value);
}
static gboolean
find_and_update_list_binding (MetaKeyPref *bindings,
const char *key,
GSList *value,
MetaStringListType type_of_value)
find_and_update_list_binding (MetaKeyPref *bindings,
const char *name,
GSList *value)
{
char *name = binding_name (key);
const char *key;
int i;
gchar *name_without_suffix = g_strdup(name);
name_without_suffix[strlen(name_without_suffix) - strlen(KEY_LIST_BINDINGS_SUFFIX)] = 0;
if (*name_without_suffix == '/')
key = relative_key (name_without_suffix);
else
key = name_without_suffix;
i = 0;
while (bindings[i].name &&
strcmp (name, bindings[i].name) != 0)
strcmp (key, bindings[i].name) != 0)
++i;
g_free (name);
g_free (name_without_suffix);
if (bindings[i].name)
return update_list_binding (&bindings[i], value, type_of_value);
return update_list_binding (&bindings[i], value, META_LIST_OF_GCONFVALUE_STRINGS);
else
return FALSE;
}
static gboolean
update_key_list_binding (const char *key,
GSList *value,
MetaStringListType type_of_value)
update_key_list_binding (const char *name,
GSList *value)
{
return find_and_update_list_binding (key_bindings, key, value, type_of_value);
return find_and_update_list_binding (key_bindings, name, value);
}
static gboolean
@@ -2913,6 +2728,12 @@ meta_prefs_get_auto_raise_delay (void)
return auto_raise_delay;
}
gboolean
meta_prefs_get_reduced_resources (void)
{
return reduced_resources;
}
gboolean
meta_prefs_get_gnome_accessibility ()
{
@@ -2925,12 +2746,6 @@ meta_prefs_get_gnome_animations ()
return gnome_animations;
}
gboolean
meta_prefs_get_side_by_side_tiling ()
{
return side_by_side_tiling;
}
MetaKeyBindingAction
meta_prefs_get_keybinding_action (const char *name)
{
@@ -3010,12 +2825,6 @@ meta_prefs_get_mouse_button_menu (void)
return resize_with_right_button ? 2: 3;
}
gboolean
meta_prefs_get_force_fullscreen (void)
{
return force_fullscreen;
}
void
meta_prefs_set_compositing_manager (gboolean whether)
{
@@ -3038,11 +2847,35 @@ meta_prefs_set_compositing_manager (gboolean whether)
#endif
}
/**
* meta_prefs_get_clutter_plugins:
*
* Returns: (transfer none) (element-type utf8): Plugin names to load
*/
#ifdef WITH_CLUTTER
gboolean
meta_prefs_get_clutter_disabled (void)
{
return clutter_disabled;
}
void
meta_prefs_set_clutter_disabled (gboolean whether)
{
#ifdef HAVE_GCONF
GError *err = NULL;
gconf_client_set_bool (default_client,
KEY_CLUTTER_DISABLED,
whether,
&err);
if (err)
{
meta_warning (_("Error setting clutter status status: %s\n"),
err->message);
g_error_free (err);
}
#else
clutter_disabled = whether;
#endif
}
GSList *
meta_prefs_get_clutter_plugins (void)
{
@@ -3052,7 +2885,6 @@ meta_prefs_get_clutter_plugins (void)
void
meta_prefs_set_clutter_plugins (GSList *list)
{
#ifdef HAVE_GCONF
GError *err = NULL;
gconf_client_set_list (default_client,
@@ -3067,7 +2899,6 @@ meta_prefs_set_clutter_plugins (GSList *list)
err->message);
g_error_free (err);
}
#endif
}
void
@@ -3083,6 +2914,7 @@ meta_prefs_override_clutter_plugins (GSList *list)
clutter_plugins = g_slist_reverse (clutter_plugins);
}
#endif
gboolean
meta_prefs_get_live_hidden_windows (void)
@@ -3188,10 +3020,3 @@ init_button_layout(void)
};
#endif
void
meta_prefs_set_force_fullscreen (gboolean whether)
{
force_fullscreen = whether;
}

View File

@@ -37,11 +37,12 @@
#include "screen.h"
#include <X11/Xutil.h>
#include "stack-tracker.h"
#include "alttabhandler.h"
#include "ui.h"
typedef struct _MetaMonitorInfo MetaMonitorInfo;
typedef struct _MetaXineramaScreenInfo MetaXineramaScreenInfo;
struct _MetaMonitorInfo
struct _MetaXineramaScreenInfo
{
int number;
MetaRectangle rect;
@@ -81,11 +82,9 @@ 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;
MetaAltTabHandler *tab_handler;
MetaTabPopup *ws_popup;
MetaWorkspace *active_workspace;
/* This window holds the focus when we don't want to focus
@@ -106,11 +105,11 @@ struct _MetaScreen
Atom wm_sn_atom;
guint32 wm_sn_timestamp;
MetaMonitorInfo *monitor_infos;
int n_monitor_infos;
MetaXineramaScreenInfo *xinerama_infos;
int n_xinerama_infos;
/* Cache the current monitor */
int last_monitor_index;
/* Cache the current Xinerama */
int last_xinerama_index;
#ifdef HAVE_STARTUP_NOTIFICATION
SnMonitorContext *sn_context;
@@ -118,10 +117,11 @@ struct _MetaScreen
guint startup_sequence_timeout;
#endif
#ifdef HAVE_COMPOSITE_EXTENSIONS
Window wm_cm_selection_window;
guint32 wm_cm_timestamp;
#endif
guint work_area_later;
guint work_area_idle;
int rows_of_workspaces;
int columns_of_workspaces;
@@ -133,6 +133,9 @@ struct _MetaScreen
int closing;
/* gc for XOR on root window */
GC root_xor_gc;
/* Managed by compositor.c */
gpointer compositor_data;
@@ -146,8 +149,7 @@ struct _MetaScreenClass
{
GObjectClass parent_class;
void (*restacked) (MetaScreen *);
void (*workareas_changed) (MetaScreen *);
void (*restacked) (MetaScreen *);
};
MetaScreen* meta_screen_new (MetaDisplay *display,
@@ -182,25 +184,22 @@ void meta_screen_workspace_popup_select (MetaScreen *screen,
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);
MetaWindow* meta_screen_get_mouse_window (MetaScreen *screen,
MetaWindow *not_this_one);
const MetaMonitorInfo* meta_screen_get_current_monitor (MetaScreen *screen);
const MetaMonitorInfo* meta_screen_get_monitor_for_rect (MetaScreen *screen,
MetaRectangle *rect);
const MetaMonitorInfo* meta_screen_get_monitor_for_window (MetaScreen *screen,
MetaWindow *window);
const MetaXineramaScreenInfo* meta_screen_get_current_xinerama (MetaScreen *screen);
const MetaXineramaScreenInfo* meta_screen_get_xinerama_for_rect (MetaScreen *screen,
MetaRectangle *rect);
const MetaXineramaScreenInfo* meta_screen_get_xinerama_for_window (MetaScreen *screen,
MetaWindow *window);
const MetaMonitorInfo* meta_screen_get_monitor_neighbor (MetaScreen *screen,
int which_monitor,
MetaScreenDirection dir);
void meta_screen_get_natural_monitor_list (MetaScreen *screen,
int** monitors_list,
int* n_monitors);
const MetaXineramaScreenInfo* meta_screen_get_xinerama_neighbor (MetaScreen *screen,
int which_xinerama,
MetaScreenDirection dir);
void meta_screen_get_natural_xinerama_list (MetaScreen *screen,
int** xineramas_list,
int* n_xineramas);
void meta_screen_update_workspace_layout (MetaScreen *screen);
void meta_screen_update_workspace_names (MetaScreen *screen);
@@ -249,9 +248,4 @@ void meta_screen_composite_all_windows (MetaScreen *screen);
void meta_screen_restacked (MetaScreen *screen);
void meta_screen_workspace_switched (MetaScreen *screen,
int from,
int to,
MetaMotionDirection direction);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,6 @@
#include <X11/Xatom.h>
#include <time.h>
#include <sys/wait.h>
#ifndef HAVE_SM
void
@@ -84,7 +83,6 @@ static char* load_state (const char *previous_save_file);
static void regenerate_save_file (void);
static const char* full_save_file (void);
static void warn_about_lame_clients_and_finish_interact (gboolean shutdown);
static void disconnect (void);
/* This is called when data is available on an ICE connection. */
static gboolean
@@ -107,12 +105,9 @@ process_ice_messages (GIOChannel *channel,
IcePointer context = IceGetConnectionContext (connection);
#endif
/* We were disconnected; close our connection to the
* session manager, this will result in the ICE connection
* being cleaned up, since it is owned by libSM.
*/
disconnect ();
meta_quit (META_EXIT_SUCCESS);
/* We were disconnected */
IceSetShutdownNegotiation (connection, False);
IceCloseConnection (connection);
return FALSE;
}
@@ -894,7 +889,7 @@ save_state (void)
fprintf (outfile, "<mutter_session id=\"%s\">\n",
client_id);
windows = meta_display_list_windows (meta_get_display (), META_LIST_DEFAULT);
windows = meta_display_list_windows (meta_get_display ());
stack_position = 0;
windows = g_slist_sort (windows, meta_display_stack_cmp);
@@ -1109,6 +1104,8 @@ load_state (const char *previous_save_file)
{
/* oh, just give up */
meta_warning (_("Failed to read saved session file %s: %s\n"),
canonical_session_file, error->message);
g_error_free (error);
g_free (session_file);
g_free (canonical_session_file);
@@ -1752,11 +1749,11 @@ finish_interact (gboolean shutdown)
}
static void
dialog_closed (GPid pid, int status, gpointer user_data)
sigchld_handler (MetaNexus *nexus, guint arg1, gpointer arg2, gpointer user_data)
{
gboolean shutdown = GPOINTER_TO_INT (user_data);
if (WIFEXITED (status) && WEXITSTATUS (status) == 0) /* pressed "OK" */
if (arg1 == 0) /* pressed "OK" */
{
finish_interact (shutdown);
}
@@ -1770,9 +1767,8 @@ warn_about_lame_clients_and_finish_interact (gboolean shutdown)
GSList *lame_details = NULL;
GSList *tmp;
GSList *columns = NULL;
GPid pid;
windows = meta_display_list_windows (meta_get_display (), META_LIST_DEFAULT);
windows = meta_display_list_windows (meta_get_display ());
tmp = windows;
while (tmp != NULL)
{
@@ -1818,20 +1814,23 @@ warn_about_lame_clients_and_finish_interact (gboolean shutdown)
}
g_slist_free (lame);
pid = meta_show_dialog("--list",
_("These windows do not support &quot;save current setup&quot; "
"and will have to be restarted manually next time "
"you log in."),
"240",
meta_screen_get_screen_number (meta_get_display()->active_screen),
NULL, NULL,
None,
columns,
lame_details);
meta_show_dialog("--list",
_("These windows do not support &quot;save current setup&quot; "
"and will have to be restarted manually next time "
"you log in."),
"240",
meta_screen_get_screen_number (meta_get_display()->active_screen),
NULL, NULL,
None,
columns,
lame_details);
g_slist_free (lame_details);
g_child_watch_add (pid, dialog_closed, GINT_TO_POINTER (shutdown));
g_signal_connect (sigchld_nexus, "sigchld",
G_CALLBACK (sigchld_handler),
GINT_TO_POINTER (shutdown));
}
#endif /* HAVE_SM */

View File

@@ -23,7 +23,6 @@
#include <string.h>
#include "frame-private.h"
#include "screen-private.h"
#include "stack-tracker.h"
#include "util.h"
@@ -135,7 +134,7 @@ struct _MetaStackTracker
/* Idle function used to sync the compositor's view of the window
* stack up with our best guess before a frame is drawn.
*/
guint sync_stack_later;
guint sync_stack_idle;
};
static void
@@ -384,8 +383,8 @@ meta_stack_tracker_new (MetaScreen *screen)
void
meta_stack_tracker_free (MetaStackTracker *tracker)
{
if (tracker->sync_stack_later)
meta_later_remove (tracker->sync_stack_later);
if (tracker->sync_stack_idle)
g_source_remove (tracker->sync_stack_idle);
g_array_free (tracker->server_stack, TRUE);
if (tracker->predicted_stack)
@@ -668,10 +667,10 @@ meta_stack_tracker_sync_stack (MetaStackTracker *tracker)
int n_windows;
int i;
if (tracker->sync_stack_later)
if (tracker->sync_stack_idle)
{
meta_later_remove (tracker->sync_stack_later);
tracker->sync_stack_later = 0;
g_source_remove (tracker->sync_stack_idle);
tracker->sync_stack_idle = 0;
}
meta_stack_tracker_get_stack (tracker, &windows, &n_windows);
@@ -683,29 +682,20 @@ meta_stack_tracker_sync_stack (MetaStackTracker *tracker)
meta_window = meta_display_lookup_x_window (tracker->screen->display,
windows[i]);
/* When mapping back from xwindow to MetaWindow we have to be a bit careful;
* children of the root could include unmapped windows created by toolkits
* for internal purposes, including ones that we have registered in our
* XID => window table. (Wine uses a toplevel for _NET_WM_USER_TIME_WINDOW;
* see window-prop.c:reload_net_wm_user_time_window() for registration.)
*/
if (meta_window &&
(windows[i] == meta_window->xwindow ||
(meta_window->frame && windows[i] == meta_window->frame->xwindow)))
if (meta_window)
meta_windows = g_list_prepend (meta_windows, meta_window);
}
if (tracker->screen->display->compositor)
meta_compositor_sync_stack (tracker->screen->display->compositor,
tracker->screen,
meta_windows);
meta_compositor_sync_stack (tracker->screen->display->compositor,
tracker->screen,
meta_windows);
g_list_free (meta_windows);
meta_screen_restacked (tracker->screen);
}
static gboolean
stack_tracker_sync_stack_later (gpointer data)
stack_tracker_sync_stack_idle (gpointer data)
{
meta_stack_tracker_sync_stack (data);
@@ -728,10 +718,10 @@ stack_tracker_sync_stack_later (gpointer data)
void
meta_stack_tracker_queue_sync_stack (MetaStackTracker *tracker)
{
if (tracker->sync_stack_later == 0)
if (tracker->sync_stack_idle == 0)
{
tracker->sync_stack_later = meta_later_add (META_LATER_BEFORE_REDRAW,
stack_tracker_sync_stack_later,
tracker->sync_stack_idle = g_idle_add_full (META_PRIORITY_BEFORE_REDRAW,
stack_tracker_sync_stack_idle,
tracker, NULL);
}
}

View File

@@ -224,14 +224,14 @@ is_focused_foreach (MetaWindow *window,
}
static gboolean
windows_on_different_monitor (MetaWindow *a,
MetaWindow *b)
windows_on_different_xinerama (MetaWindow *a,
MetaWindow *b)
{
if (a->screen != b->screen)
return TRUE;
return meta_screen_get_monitor_for_window (a->screen, a) !=
meta_screen_get_monitor_for_window (b->screen, b);
return meta_screen_get_xinerama_for_window (a->screen, a) !=
meta_screen_get_xinerama_for_window (b->screen, b);
}
/* Get layer ignoring any transient or group relationships */
@@ -241,6 +241,12 @@ get_standalone_layer (MetaWindow *window)
MetaStackLayer layer;
gboolean focused_transient = FALSE;
if (window->hidden)
{
layer = META_LAYER_DESKTOP;
return layer;
}
switch (window->type)
{
case META_WINDOW_DESKTOP:
@@ -275,8 +281,8 @@ get_standalone_layer (MetaWindow *window)
window == window->display->expected_focus_window ||
window->display->expected_focus_window == NULL ||
(window->display->expected_focus_window != NULL &&
windows_on_different_monitor (window,
window->display->expected_focus_window))))
windows_on_different_xinerama (window,
window->display->expected_focus_window))))
layer = META_LAYER_FULLSCREEN;
else if (window->wm_state_above)
layer = META_LAYER_TOP;
@@ -1026,7 +1032,7 @@ raise_window_relative_to_managed_windows (MetaScreen *screen,
xwindow,
CWSibling | CWStackMode,
&changes);
meta_error_trap_pop (screen->display);
meta_error_trap_pop (screen->display, FALSE);
break;
}
@@ -1046,7 +1052,7 @@ raise_window_relative_to_managed_windows (MetaScreen *screen,
XNextRequest (screen->display->xdisplay));
XLowerWindow (screen->display->xdisplay,
xwindow);
meta_error_trap_pop (screen->display);
meta_error_trap_pop (screen->display, FALSE);
}
}
@@ -1267,7 +1273,7 @@ stack_sync_to_server (MetaStack *stack)
all_hidden->len);
g_array_free (all_hidden, TRUE);
meta_error_trap_pop (stack->screen->display);
meta_error_trap_pop (stack->screen->display, FALSE);
/* on error, a window was destroyed; it should eventually
* get removed from the stacking list when we unmanage it
* and we'll fix stacking at that time.

View File

@@ -21,7 +21,7 @@
* 02111-1307, USA.
*/
#include "boxes-private.h"
#include "boxes.h"
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
@@ -85,7 +85,7 @@ new_screen_edge (int x, int y, int width, int height, int side_type)
}
static MetaEdge*
new_monitor_edge (int x, int y, int width, int height, int side_type)
new_xinerama_edge (int x, int y, int width, int height, int side_type)
{
MetaEdge* temporary;
temporary = g_new (MetaEdge, 1);
@@ -94,7 +94,7 @@ new_monitor_edge (int x, int y, int width, int height, int side_type)
temporary->rect.width = width;
temporary->rect.height = height;
temporary->side_type = side_type;
temporary->edge_type = META_EDGE_MONITOR;
temporary->edge_type = META_EDGE_XINERAMA;
return temporary;
}
@@ -317,15 +317,15 @@ get_screen_edges (int which)
}
static GList*
get_monitor_edges (int which_monitor_set, int which_strut_set)
get_xinerama_edges (int which_xinerama_set, int which_strut_set)
{
GList *ret;
GSList *struts;
GList *xins;
xins = NULL;
g_assert (which_monitor_set >=0 && which_monitor_set <= 3);
switch (which_monitor_set)
g_assert (which_xinerama_set >=0 && which_xinerama_set <= 3);
switch (which_xinerama_set)
{
case 0:
xins = g_list_prepend (xins, new_meta_rect ( 0, 0, 1600, 1200));
@@ -348,7 +348,7 @@ get_monitor_edges (int which_monitor_set, int which_strut_set)
ret = NULL;
struts = get_strut_list (which_strut_set);
ret = meta_rectangle_find_nonintersected_monitor_edges (xins, struts);
ret = meta_rectangle_find_nonintersected_xinerama_edges (xins, struts);
free_strut_list (struts);
meta_rectangle_free_list_and_elements (xins);
@@ -1145,7 +1145,7 @@ test_find_onscreen_edges ()
}
static void
test_find_nonintersected_monitor_edges ()
test_find_nonintersected_xinerama_edges ()
{
GList* edges;
GList* tmp;
@@ -1156,32 +1156,32 @@ test_find_nonintersected_monitor_edges ()
int bottom = META_DIRECTION_BOTTOM;
/*************************************************************************/
/* Make sure test monitor set 0 for with region 0 has the correct edges */
/* Make sure test xinerama set 0 for with region 0 has the correct edges */
/*************************************************************************/
edges = get_monitor_edges (0, 0);
edges = get_xinerama_edges (0, 0);
tmp = NULL;
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (edges);
/*************************************************************************/
/* Make sure test monitor set 2 for with region 1 has the correct edges */
/* Make sure test xinerama set 2 for with region 1 has the correct edges */
/*************************************************************************/
edges = get_monitor_edges (2, 1);
edges = get_xinerama_edges (2, 1);
tmp = NULL;
tmp = g_list_prepend (tmp, new_monitor_edge ( 0, 600, 1600, 0, bottom));
tmp = g_list_prepend (tmp, new_monitor_edge ( 0, 600, 1600, 0, top));
tmp = g_list_prepend (tmp, new_xinerama_edge ( 0, 600, 1600, 0, bottom));
tmp = g_list_prepend (tmp, new_xinerama_edge ( 0, 600, 1600, 0, top));
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (edges);
/*************************************************************************/
/* Make sure test monitor set 1 for with region 2 has the correct edges */
/* Make sure test xinerama set 1 for with region 2 has the correct edges */
/*************************************************************************/
edges = get_monitor_edges (1, 2);
edges = get_xinerama_edges (1, 2);
tmp = NULL;
tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 20, 0, 1080, right));
tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 20, 0, 1180, left));
tmp = g_list_prepend (tmp, new_xinerama_edge ( 800, 20, 0, 1080, right));
tmp = g_list_prepend (tmp, new_xinerama_edge ( 800, 20, 0, 1180, left));
#if 0
#define FUDGE 50
char big_buffer1[(EDGE_LENGTH+2)*FUDGE], big_buffer2[(EDGE_LENGTH+2)*FUDGE];
@@ -1195,36 +1195,36 @@ test_find_nonintersected_monitor_edges ()
meta_rectangle_free_list_and_elements (edges);
/*************************************************************************/
/* Make sure test monitor set 3 for with region 3 has the correct edges */
/* Make sure test xinerama set 3 for with region 3 has the correct edges */
/*************************************************************************/
edges = get_monitor_edges (3, 3);
edges = get_xinerama_edges (3, 3);
tmp = NULL;
tmp = g_list_prepend (tmp, new_monitor_edge ( 900, 600, 700, 0, bottom));
tmp = g_list_prepend (tmp, new_monitor_edge ( 0, 600, 700, 0, bottom));
tmp = g_list_prepend (tmp, new_monitor_edge ( 900, 600, 700, 0, top));
tmp = g_list_prepend (tmp, new_monitor_edge ( 0, 600, 700, 0, top));
tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 675, 0, 425, right));
tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 675, 0, 525, left));
tmp = g_list_prepend (tmp, new_xinerama_edge ( 900, 600, 700, 0, bottom));
tmp = g_list_prepend (tmp, new_xinerama_edge ( 0, 600, 700, 0, bottom));
tmp = g_list_prepend (tmp, new_xinerama_edge ( 900, 600, 700, 0, top));
tmp = g_list_prepend (tmp, new_xinerama_edge ( 0, 600, 700, 0, top));
tmp = g_list_prepend (tmp, new_xinerama_edge ( 800, 675, 0, 425, right));
tmp = g_list_prepend (tmp, new_xinerama_edge ( 800, 675, 0, 525, left));
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (edges);
/*************************************************************************/
/* Make sure test monitor set 3 for with region 4 has the correct edges */
/* Make sure test xinerama set 3 for with region 4 has the correct edges */
/*************************************************************************/
edges = get_monitor_edges (3, 4);
edges = get_xinerama_edges (3, 4);
tmp = NULL;
tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 600, 800, 0, bottom));
tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 600, 800, 0, top));
tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 600, 0, 600, right));
tmp = g_list_prepend (tmp, new_xinerama_edge ( 800, 600, 800, 0, bottom));
tmp = g_list_prepend (tmp, new_xinerama_edge ( 800, 600, 800, 0, top));
tmp = g_list_prepend (tmp, new_xinerama_edge ( 800, 600, 0, 600, right));
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (edges);
/*************************************************************************/
/* Make sure test monitor set 3 for with region 5has the correct edges */
/* Make sure test xinerama set 3 for with region 5has the correct edges */
/*************************************************************************/
edges = get_monitor_edges (3, 5);
edges = get_xinerama_edges (3, 5);
tmp = NULL;
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
@@ -1405,7 +1405,7 @@ main()
/* And now the functions dealing with edges more than boxes */
test_find_onscreen_edges ();
test_find_nonintersected_monitor_edges ();
test_find_nonintersected_xinerama_edges ();
/* And now the misfit functions that don't quite fit in anywhere else... */
test_gravity_resize ();

View File

@@ -26,12 +26,9 @@
#define _POSIX_C_SOURCE 200112L /* for fdopen() */
#include <config.h>
#include "common.h"
#include "util.h"
#include "main.h"
#include <clutter/clutter.h> /* For clutter_threads_add_repaint_func() */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -40,12 +37,7 @@
#include <X11/Xlib.h> /* must explicitly be included for Solaris; #326746 */
#include <X11/Xutil.h> /* Just for the definition of the various gravities */
#ifdef WITH_VERBOSE_MODE
static void
meta_topic_real_valist (MetaDebugTopic topic,
const char *format,
va_list args);
#endif
MetaNexus *sigchld_nexus;
#ifdef HAVE_BACKTRACE
#include <execinfo.h>
@@ -78,7 +70,7 @@ meta_print_backtrace (void)
}
#endif
static gint verbose_topics = 0;
static gboolean is_verbose = FALSE;
static gboolean is_debugging = FALSE;
static gboolean replace_current = FALSE;
static int no_prefix = 0;
@@ -135,7 +127,7 @@ ensure_logfile (void)
gboolean
meta_is_verbose (void)
{
return verbose_topics != 0;
return is_verbose;
}
void
@@ -148,48 +140,8 @@ meta_set_verbose (gboolean setting)
if (setting)
ensure_logfile ();
#endif
if (setting)
meta_add_verbose_topic (META_DEBUG_VERBOSE);
else
meta_remove_verbose_topic (META_DEBUG_VERBOSE);
}
/**
* meta_add_verbose_topic:
* @topic: Topic for which logging will be started
*
* Ensure log messages for the given topic @topic
* will be printed.
*/
void
meta_add_verbose_topic (MetaDebugTopic topic)
{
if (verbose_topics == META_DEBUG_VERBOSE)
return;
if (topic == META_DEBUG_VERBOSE)
verbose_topics = META_DEBUG_VERBOSE;
else
verbose_topics |= topic;
}
/**
* meta_remove_verbose_topic:
* @topic: Topic for which logging will be stopped
*
* Stop printing log messages for the given topic @topic. Note
* that this method does not stack with meta_add_verbose_topic();
* i.e. if two calls to meta_add_verbose_topic() for the same
* topic are made, one call to meta_remove_verbose_topic() will
* remove it.
*/
void
meta_remove_verbose_topic (MetaDebugTopic topic)
{
if (topic == META_DEBUG_VERBOSE)
verbose_topics = 0;
else
verbose_topics &= ~topic;
is_verbose = setting;
}
gboolean
@@ -297,10 +249,27 @@ void
meta_verbose_real (const char *format, ...)
{
va_list args;
gchar *str;
FILE *out;
g_return_if_fail (format != NULL);
if (!is_verbose)
return;
va_start (args, format);
meta_topic_real_valist (META_DEBUG_VERBOSE, format, args);
str = g_strdup_vprintf (format, args);
va_end (args);
out = logfile ? logfile : stderr;
if (no_prefix == 0)
utf8_fputs ("Window manager: ", out);
utf8_fputs (str, out);
fflush (out);
g_free (str);
}
#endif /* WITH_VERBOSE_MODE */
@@ -354,8 +323,6 @@ topic_name (MetaDebugTopic topic)
return "COMPOSITOR";
case META_DEBUG_EDGE_RESISTANCE:
return "EDGE_RESISTANCE";
case META_DEBUG_VERBOSE:
return "VERBOSE";
}
return "WM";
@@ -363,22 +330,23 @@ topic_name (MetaDebugTopic topic)
static int sync_count = 0;
static void
meta_topic_real_valist (MetaDebugTopic topic,
const char *format,
va_list args)
void
meta_topic_real (MetaDebugTopic topic,
const char *format,
...)
{
va_list args;
gchar *str;
FILE *out;
g_return_if_fail (format != NULL);
if (verbose_topics == 0
|| (topic == META_DEBUG_VERBOSE && verbose_topics != META_DEBUG_VERBOSE)
|| (!(verbose_topics & topic)))
if (!is_verbose)
return;
va_start (args, format);
str = g_strdup_vprintf (format, args);
va_end (args);
out = logfile ? logfile : stderr;
@@ -397,18 +365,6 @@ meta_topic_real_valist (MetaDebugTopic topic,
g_free (str);
}
void
meta_topic_real (MetaDebugTopic topic,
const char *format,
...)
{
va_list args;
va_start (args, format);
meta_topic_real_valist (topic, format, args);
va_end (args);
}
#endif /* WITH_VERBOSE_MODE */
void
@@ -601,7 +557,7 @@ meta_show_dialog (const char *type,
int i=0;
GPid child_pid;
const char **argvl = g_malloc(sizeof (char*) *
(17 +
(15 +
g_slist_length (columns)*2 +
g_slist_length (entries)));
@@ -609,8 +565,6 @@ meta_show_dialog (const char *type,
argvl[i++] = type;
argvl[i++] = "--screen";
argvl[i++] = screen_number_text;
argvl[i++] = "--class";
argvl[i++] = "mutter-dialog";
argvl[i++] = "--title";
/* Translators: This is the title used on dialog boxes */
argvl[i++] = _("Mutter");
@@ -684,200 +638,29 @@ meta_show_dialog (const char *type,
return child_pid;
}
/***************************************************************************
* Later functions: like idles but integrated with the Clutter repaint loop
***************************************************************************/
static guint last_later_id = 0;
typedef struct
GType
meta_nexus_get_type (void)
{
guint id;
MetaLaterType when;
GSourceFunc func;
gpointer data;
GDestroyNotify notify;
int source;
gboolean run_once;
} MetaLater;
static GType nexus_type = 0;
static GSList *laters = NULL;
/* This is a dummy timeline used to get the Clutter master clock running */
static ClutterTimeline *later_timeline;
static guint later_repaint_func = 0;
static void ensure_later_repaint_func (void);
static void
destroy_later (MetaLater *later)
{
if (later->source)
g_source_remove (later->source);
if (later->notify)
later->notify (later->data);
g_slice_free (MetaLater, later);
}
/* Used to sort the list of laters with the highest priority
* functions first.
*/
static int
compare_laters (gconstpointer a,
gconstpointer b)
{
return ((const MetaLater *)a)->when - ((const MetaLater *)b)->when;
}
static gboolean
run_repaint_laters (gpointer data)
{
GSList *old_laters = laters;
GSList *l;
gboolean keep_timeline_running = FALSE;
laters = NULL;
for (l = old_laters; l; l = l->next)
if (!nexus_type)
{
MetaLater *later = l->data;
if (later->source == 0 ||
(later->when <= META_LATER_BEFORE_REDRAW && !later->run_once))
{
if (later->func (later->data))
{
if (later->source == 0)
keep_timeline_running = TRUE;
laters = g_slist_insert_sorted (laters, later, compare_laters);
}
else
destroy_later (later);
}
else
laters = g_slist_insert_sorted (laters, later, compare_laters);
static const GTypeInfo nexus_info =
{
sizeof (MetaNexusClass),
NULL, NULL, NULL, NULL, NULL,
sizeof (MetaNexus),
0,
NULL, NULL
};
nexus_type = g_type_register_static (G_TYPE_OBJECT,
"MetaNexus",
&nexus_info,
0);
}
if (!keep_timeline_running)
clutter_timeline_stop (later_timeline);
g_slist_free (old_laters);
/* Just keep the repaint func around - it's cheap if the list is empty */
return TRUE;
}
static void
ensure_later_repaint_func (void)
{
if (!later_timeline)
later_timeline = clutter_timeline_new (G_MAXUINT);
if (later_repaint_func == 0)
later_repaint_func = clutter_threads_add_repaint_func (run_repaint_laters,
NULL, NULL);
/* Make sure the repaint function gets run */
clutter_timeline_start (later_timeline);
}
static gboolean
call_idle_later (gpointer data)
{
MetaLater *later = data;
if (!later->func (later->data))
{
laters = g_slist_remove (laters, later);
later->source = 0;
destroy_later (later);
return FALSE;
}
else
{
later->run_once = TRUE;
return TRUE;
}
}
/**
* meta_later_add:
* @when: enumeration value determining the phase at which to run the callback
* @func: callback to run later
* @data: data to pass to the callback
* @notify: function to call to destroy @data when it is no longer in use, or %NULL
*
* Sets up a callback to be called at some later time. @when determines the
* particular later occasion at which it is called. This is much like g_idle_add(),
* except that the functions interact properly with clutter event handling.
* If a "later" function is added from a clutter event handler, and is supposed
* to be run before the stage is redrawn, it will be run before that redraw
* of the stage, not the next one.
*
* Return value: an integer ID (guaranteed to be non-zero) that can be used
* to cancel the callback and prevent it from being run.
*/
guint
meta_later_add (MetaLaterType when,
GSourceFunc func,
gpointer data,
GDestroyNotify notify)
{
MetaLater *later = g_slice_new0 (MetaLater);
later->id = ++last_later_id;
later->when = when;
later->func = func;
later->data = data;
later->notify = notify;
laters = g_slist_insert_sorted (laters, later, compare_laters);
switch (when)
{
case META_LATER_RESIZE:
/* We add this one two ways - as a high-priority idle and as a
* repaint func. If we are in a clutter event callback, the repaint
* handler will get hit first, and we'll take care of this function
* there so it gets called before the stage is redrawn, even if
* we haven't gotten back to the main loop. Otherwise, the idle
* handler will get hit first and we want to call this function
* there so it will happen before GTK+ repaints.
*/
later->source = g_idle_add_full (META_PRIORITY_RESIZE, call_idle_later, later, NULL);
ensure_later_repaint_func ();
break;
case META_LATER_BEFORE_REDRAW:
ensure_later_repaint_func ();
break;
case META_LATER_IDLE:
later->source = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, call_idle_later, later, NULL);
break;
}
return later->id;
}
/**
* meta_later_remove:
* @later_id: the integer ID returned from meta_later_add()
*
* Removes a callback added with meta_later_add()
*/
void
meta_later_remove (guint later_id)
{
GSList *l;
for (l = laters; l; l = l->next)
{
MetaLater *later = l->data;
if (later->id == later_id)
{
laters = g_slist_remove_link (laters, l);
/* If this was a "repaint func" later, we just let the
* repaint func run and get removed
*/
destroy_later (later);
}
}
return nexus_type;
}
/* eof util.c */

View File

@@ -35,7 +35,6 @@
#define META_WINDOW_PRIVATE_H
#include <config.h>
#include "compositor.h"
#include "window.h"
#include "screen-private.h"
#include "util.h"
@@ -46,6 +45,9 @@
typedef struct _MetaWindowQueue MetaWindowQueue;
typedef gboolean (*MetaWindowForeachFunc) (MetaWindow *window,
void *data);
typedef enum {
META_CLIENT_TYPE_UNKNOWN = 0,
META_CLIENT_TYPE_APPLICATION = 1,
@@ -61,12 +63,6 @@ typedef enum {
#define NUMBER_OF_QUEUES 3
typedef enum {
META_TILE_NONE,
META_TILE_LEFT,
META_TILE_RIGHT
} MetaTileMode;
struct _MetaWindow
{
GObject parent_instance;
@@ -102,7 +98,6 @@ struct _MetaWindow
char *sm_client_id;
char *wm_client_machine;
char *startup_id;
char *mutter_hints;
int net_wm_pid;
@@ -128,23 +123,12 @@ struct _MetaWindow
guint maximize_vertically_after_placement : 1;
guint minimize_after_placement : 1;
/* The current or requested tile mode. If maximized_vertically is true,
* this is the current mode. If not, it is the mode which will be
* requested after the window grab is released */
guint tile_mode : 2;
/* Whether we're shaded */
guint shaded : 1;
/* Whether we're fullscreen */
guint fullscreen : 1;
/* Whether the urgent flag of WM_HINTS is set */
guint wm_hints_urgent : 1;
/* Whether we have to fullscreen after placement */
guint fullscreen_after_placement : 1;
/* Area to cover when in fullscreen mode. If _NET_WM_FULLSCREEN_MONITORS has
* been overridden (via a client message), the window will cover the union of
* these monitors. If not, this is the single monitor which the window's
@@ -154,8 +138,8 @@ struct _MetaWindow
/* Whether we're trying to constrain the window to be fully onscreen */
guint require_fully_onscreen : 1;
/* Whether we're trying to constrain the window to be on a single monitor */
guint require_on_single_monitor : 1;
/* Whether we're trying to constrain the window to be on a single xinerama */
guint require_on_single_xinerama : 1;
/* Whether we're trying to constrain the window's titlebar to be onscreen */
guint require_titlebar_visible : 1;
@@ -168,6 +152,7 @@ struct _MetaWindow
/* Minimize is the state controlled by the minimize button */
guint minimized : 1;
guint was_minimized : 1;
guint tab_unminimized : 1;
/* Whether the window is mapped; actual server-side state
@@ -180,15 +165,6 @@ struct _MetaWindow
*/
guint hidden : 1;
/* Whether the compositor thinks the window is visible
*/
guint visible_to_compositor : 1;
/* When we next show or hide the window, what effect we should
* tell the compositor to perform.
*/
guint pending_compositor_effect : 4; /* MetaCompEffect */
/* Iconic is the state in WM_STATE; happens for workspaces/shading
* in addition to minimize
*/
@@ -261,9 +237,6 @@ struct _MetaWindow
/* Have we placed this window? */
guint placed : 1;
/* Must we force_save_user_window_placement? */
guint force_save_user_rect : 1;
/* Is this not a transient of the focus window which is being denied focus? */
guint denied_focus_and_not_transient : 1;
@@ -334,9 +307,6 @@ struct _MetaWindow
*/
int unmaps_pending;
/* See docs for meta_window_get_stable_sequence() */
guint32 stable_sequence;
/* set to the most recent user-interaction event timestamp that we
know about for this window */
guint32 net_wm_user_time;
@@ -388,7 +358,9 @@ struct _MetaWindow
/* maintained by group.c */
MetaGroup *group;
#ifdef HAVE_COMPOSITE_EXTENSIONS
GObject *compositor_private;
#endif
};
struct _MetaWindowClass
@@ -398,7 +370,6 @@ struct _MetaWindowClass
void (*workspace_changed) (MetaWindow *window, int old_workspace);
void (*focus) (MetaWindow *window);
void (*raised) (MetaWindow *window);
void (*unmanaged) (MetaWindow *window);
};
/* These differ from window->has_foo_func in that they consider
@@ -409,11 +380,8 @@ struct _MetaWindowClass
(w)->maximized_vertically)
#define META_WINDOW_MAXIMIZED_VERTICALLY(w) ((w)->maximized_vertically)
#define META_WINDOW_MAXIMIZED_HORIZONTALLY(w) ((w)->maximized_horizontally)
#define META_WINDOW_TILED(w) ((w)->maximized_vertically && \
!(w)->maximized_horizontally && \
(w)->tile_mode != META_TILE_NONE)
#define META_WINDOW_ALLOWS_MOVE(w) ((w)->has_move_func && !(w)->fullscreen)
#define META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS(w) ((w)->has_resize_func && !META_WINDOW_MAXIMIZED (w) && !META_WINDOW_TILED(w) && !(w)->fullscreen && !(w)->shaded)
#define META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS(w) ((w)->has_resize_func && !META_WINDOW_MAXIMIZED (w) && !(w)->fullscreen && !(w)->shaded)
#define META_WINDOW_ALLOWS_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && \
(((w)->size_hints.min_width < (w)->size_hints.max_width) || \
((w)->size_hints.min_height < (w)->size_hints.max_height)))
@@ -423,10 +391,9 @@ struct _MetaWindowClass
MetaWindow* meta_window_new (MetaDisplay *display,
Window xwindow,
gboolean must_be_viewable);
MetaWindow* meta_window_new_with_attrs (MetaDisplay *display,
Window xwindow,
gboolean must_be_viewable,
MetaCompEffect effect,
MetaWindow* meta_window_new_with_attrs (MetaDisplay *display,
Window xwindow,
gboolean must_be_viewable,
XWindowAttributes *attrs);
void meta_window_unmanage (MetaWindow *window,
guint32 timestamp);
@@ -436,11 +403,6 @@ void meta_window_queue (MetaWindow *window,
void meta_window_maximize_internal (MetaWindow *window,
MetaMaximizeFlags directions,
MetaRectangle *saved_rect);
void meta_window_unmaximize_with_gravity (MetaWindow *window,
MetaMaximizeFlags directions,
int new_width,
int new_height,
int gravity);
void meta_window_make_above (MetaWindow *window);
void meta_window_unmake_above (MetaWindow *window);
void meta_window_shade (MetaWindow *window,
@@ -461,8 +423,6 @@ void meta_window_update_fullscreen_monitors (MetaWindow *window,
unsigned long left,
unsigned long right);
gboolean meta_window_appears_focused (MetaWindow *window);
/* args to move are window pos, not frame pos */
void meta_window_move (MetaWindow *window,
gboolean user_op,
@@ -521,10 +481,22 @@ void meta_window_get_geometry (MetaWindow *window,
int *y,
int *width,
int *height);
void meta_window_get_xor_rect (MetaWindow *window,
const MetaRectangle *grab_wireframe_rect,
MetaRectangle *xor_rect);
void meta_window_begin_wireframe (MetaWindow *window);
void meta_window_update_wireframe (MetaWindow *window,
int x,
int y,
int width,
int height);
void meta_window_end_wireframe (MetaWindow *window);
void meta_window_kill (MetaWindow *window);
void meta_window_focus (MetaWindow *window,
guint32 timestamp);
void meta_window_raise (MetaWindow *window);
void meta_window_lower (MetaWindow *window);
void meta_window_update_unfocused_button_grabs (MetaWindow *window);
@@ -574,16 +546,13 @@ GList* meta_window_get_workspaces (MetaWindow *window);
gboolean meta_window_located_on_workspace (MetaWindow *window,
MetaWorkspace *workspace);
void meta_window_get_work_area_current_monitor (MetaWindow *window,
MetaRectangle *area);
void meta_window_get_work_area_for_monitor (MetaWindow *window,
int which_monitor,
MetaRectangle *area);
void meta_window_get_work_area_all_monitors (MetaWindow *window,
MetaRectangle *area);
void meta_window_get_current_tile_area (MetaWindow *window,
MetaRectangle *tile_area);
void meta_window_get_work_area_current_xinerama (MetaWindow *window,
MetaRectangle *area);
void meta_window_get_work_area_for_xinerama (MetaWindow *window,
int which_xinerama,
MetaRectangle *area);
void meta_window_get_work_area_all_xineramas (MetaWindow *window,
MetaRectangle *area);
gboolean meta_window_same_application (MetaWindow *window,
@@ -602,6 +571,14 @@ void meta_window_refresh_resize_popup (MetaWindow *window);
void meta_window_free_delete_dialog (MetaWindow *window);
void meta_window_foreach_transient (MetaWindow *window,
MetaWindowForeachFunc func,
void *data);
gboolean meta_window_is_ancestor_of_transient (MetaWindow *window,
MetaWindow *transient);
void meta_window_foreach_ancestor (MetaWindow *window,
MetaWindowForeachFunc func,
void *data);
void meta_window_begin_grab_op (MetaWindow *window,
MetaGrabOp op,
@@ -624,6 +601,10 @@ void meta_window_stack_just_below (MetaWindow *window,
void meta_window_set_user_time (MetaWindow *window,
guint32 timestamp);
void meta_window_set_demands_attention (MetaWindow *window);
void meta_window_unset_demands_attention (MetaWindow *window);
void meta_window_update_icon_now (MetaWindow *window);
void meta_window_update_role (MetaWindow *window);

View File

@@ -179,7 +179,7 @@ meta_window_load_initial_properties (MetaWindow *window)
{
/* If we didn't actually manage to load anything then we don't need
* to call the reload function; this is different from a notification
* where disappearance of a previously present value is significant.
* where disappearance of a previously value is significant.
*/
if (values[j].type != META_PROP_VALUE_INVALID)
reload_prop_value (window, hooks, &values[j], TRUE);
@@ -442,7 +442,7 @@ set_title_text (MetaWindow *window,
XDeleteProperty (window->display->xdisplay,
window->xwindow,
atom);
meta_error_trap_pop (window->display);
meta_error_trap_pop (window->display, FALSE);
}
return modified;
@@ -472,8 +472,8 @@ set_window_title (MetaWindow *window,
meta_ui_set_frame_title (window->screen->ui,
window->frame->xwindow,
window->title);
g_object_notify (G_OBJECT (window), "title");
if (modified)
g_object_notify (G_OBJECT (window), "title");
}
static void
@@ -523,49 +523,6 @@ reload_wm_name (MetaWindow *window,
}
}
static void
reload_mutter_hints (MetaWindow *window,
MetaPropValue *value,
gboolean initial)
{
if (value->type != META_PROP_VALUE_INVALID)
{
char *new_hints = value->v.str;
char *old_hints = window->mutter_hints;
gboolean changed = FALSE;
if (new_hints)
{
if (!old_hints || strcmp (new_hints, old_hints))
changed = TRUE;
}
else
{
if (old_hints)
changed = TRUE;
}
if (changed)
{
g_free (old_hints);
if (new_hints)
window->mutter_hints = g_strdup (new_hints);
else
window->mutter_hints = NULL;
g_object_notify (G_OBJECT (window), "mutter-hints");
}
}
else if (window->mutter_hints)
{
g_free (window->mutter_hints);
window->mutter_hints = NULL;
g_object_notify (G_OBJECT (window), "mutter-hints");
}
}
static void
set_icon_title (MetaWindow *window,
const char *title)
@@ -647,7 +604,6 @@ reload_net_wm_state (MetaWindow *window,
window->shaded = FALSE;
window->maximized_horizontally = FALSE;
window->maximized_vertically = FALSE;
window->fullscreen = FALSE;
window->wm_state_modal = FALSE;
window->wm_state_skip_taskbar = FALSE;
window->wm_state_skip_pager = FALSE;
@@ -676,7 +632,13 @@ reload_net_wm_state (MetaWindow *window,
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_SKIP_PAGER)
window->wm_state_skip_pager = TRUE;
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_FULLSCREEN)
window->fullscreen_after_placement = TRUE;
{
if (!window->fullscreen)
{
window->fullscreen = TRUE;
g_object_notify (G_OBJECT (window), "fullscreen");
}
}
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_ABOVE)
window->wm_state_above = TRUE;
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_BELOW)
@@ -1388,10 +1350,8 @@ reload_wm_hints (MetaWindow *window,
gboolean initial)
{
Window old_group_leader;
gboolean old_urgent;
old_group_leader = window->xgroup_leader;
old_urgent = window->wm_hints_urgent;
/* Fill in defaults */
window->input = TRUE;
@@ -1399,8 +1359,7 @@ reload_wm_hints (MetaWindow *window,
window->xgroup_leader = None;
window->wm_hints_pixmap = None;
window->wm_hints_mask = None;
window->wm_hints_urgent = FALSE;
if (value->type != META_PROP_VALUE_INVALID)
{
const XWMHints *hints = value->v.wm_hints;
@@ -1419,10 +1378,7 @@ reload_wm_hints (MetaWindow *window,
if (hints->flags & IconMaskHint)
window->wm_hints_mask = hints->icon_mask;
if (hints->flags & XUrgencyHint)
window->wm_hints_urgent = TRUE;
meta_verbose ("Read WM_HINTS input: %d iconic: %d group leader: 0x%lx pixmap: 0x%lx mask: 0x%lx\n",
window->input, window->initially_iconic,
window->xgroup_leader,
@@ -1438,21 +1394,6 @@ reload_wm_hints (MetaWindow *window,
meta_window_group_leader_changed (window);
}
/*
* Do not emit urgency notification on the inital property load
*/
if (!initial && (window->wm_hints_urgent != old_urgent))
g_object_notify (G_OBJECT (window), "urgent");
/*
* Do not emit signal for the initial property load, let the constructor to
* take care of it once the MetaWindow is fully constructed.
*
* Only emit if the property is both changed and set.
*/
if (!initial && window->wm_hints_urgent && !old_urgent)
g_signal_emit_by_name (window->display, "window-marked-urgent", window);
meta_icon_cache_property_changed (&window->icon_cache,
window->display,
XA_WM_HINTS);
@@ -1540,6 +1481,9 @@ meta_display_init_window_prop_hooks (MetaDisplay *display)
*
* - properties that identify the window: useful for debugging
* purposes.
* - WM_TRANSIENT_FOR: could be used to associate menus or other
* override-redirect transients with their parent windows if
* the app sets the property (GTK+ does set this for menus.)
* - NET_WM_WINDOW_TYPE: can be used to do appropriate handling
* for different types of override-redirect windows.
*/
@@ -1549,19 +1493,18 @@ meta_display_init_window_prop_hooks (MetaDisplay *display)
{ XA_WM_CLASS, META_PROP_VALUE_CLASS_HINT, reload_wm_class, TRUE, TRUE },
{ display->atom__NET_WM_PID, META_PROP_VALUE_CARDINAL, reload_net_wm_pid, TRUE, TRUE },
{ XA_WM_NAME, META_PROP_VALUE_TEXT_PROPERTY, reload_wm_name, TRUE, TRUE },
{ display->atom__MUTTER_HINTS, META_PROP_VALUE_TEXT_PROPERTY, reload_mutter_hints, TRUE, TRUE },
{ display->atom__NET_WM_ICON_NAME, META_PROP_VALUE_UTF8, reload_net_wm_icon_name, TRUE, FALSE },
{ XA_WM_ICON_NAME, META_PROP_VALUE_TEXT_PROPERTY, reload_wm_icon_name, TRUE, FALSE },
{ display->atom__NET_WM_DESKTOP, META_PROP_VALUE_CARDINAL, reload_net_wm_desktop, TRUE, FALSE },
{ display->atom__NET_STARTUP_ID, META_PROP_VALUE_UTF8, reload_net_startup_id, TRUE, FALSE },
{ display->atom__NET_WM_SYNC_REQUEST_COUNTER, META_PROP_VALUE_SYNC_COUNTER, reload_update_counter, TRUE, FALSE },
{ XA_WM_NORMAL_HINTS, META_PROP_VALUE_SIZE_HINTS, reload_normal_hints, TRUE, FALSE },
{ display->atom_WM_PROTOCOLS, META_PROP_VALUE_ATOM_LIST, reload_wm_protocols, TRUE, FALSE },
{ display->atom_WM_PROTOCOLS, META_PROP_VALUE_ATOM_LIST, reload_wm_protocols, TRUE, TRUE },
{ XA_WM_HINTS, META_PROP_VALUE_WM_HINTS, reload_wm_hints, TRUE, FALSE },
{ display->atom__NET_WM_USER_TIME, META_PROP_VALUE_CARDINAL, reload_net_wm_user_time, TRUE, FALSE },
{ display->atom__NET_WM_STATE, META_PROP_VALUE_ATOM_LIST, reload_net_wm_state, TRUE, FALSE },
{ display->atom__MOTIF_WM_HINTS, META_PROP_VALUE_MOTIF_HINTS, reload_mwm_hints, TRUE, FALSE },
{ XA_WM_TRANSIENT_FOR, META_PROP_VALUE_WINDOW, reload_transient_for, TRUE, FALSE },
{ XA_WM_TRANSIENT_FOR, META_PROP_VALUE_WINDOW, reload_transient_for, TRUE, TRUE },
{ display->atom__NET_WM_USER_TIME_WINDOW, META_PROP_VALUE_WINDOW, reload_net_wm_user_time_window, TRUE, FALSE },
{ display->atom_WM_STATE, META_PROP_VALUE_INVALID, NULL, FALSE, FALSE },
{ display->atom__NET_WM_ICON, META_PROP_VALUE_INVALID, reload_net_wm_icon, FALSE, FALSE },

Some files were not shown because too many files have changed in this diff Show More