Compare commits

..

31 Commits

Author SHA1 Message Date
8b80a70efc Bump version to 3.14.4
Update NEWS.
2015-03-23 18:41:32 +01:00
63ad42e1f6 window-x11: Fix height computation of shaded windows
Since commit 6e06648f7, we start out with the invisible frame parts
only, and then add the unconstrained rect's height (which consists of
the visible parts of both frame and client window) *unless* the window
is shaded. While we indeed don't want to add the client height in that
case, we need to explicitly include the visible frame parts now.

https://bugzilla.gnome.org/show_bug.cgi?id=746145
2015-03-23 18:40:19 +01:00
6b3be51ca8 meta-background: Add a function to refresh all background instances
We need to reload the FBOs under some circumstances, this adds a way
to easily do so.

https://bugzilla.gnome.org/show_bug.cgi?id=739178
2015-03-20 17:11:30 +01:00
46d57bf0ac Updated Bosnian translation 2015-03-14 23:06:25 +00:00
8dd7102909 MetaBackgroundActor: glsl: do not mix int and float.
Implicit conversion from int to float is not supported by
GLSL ES.

Fixes:
(gnome-shell:8954): Cogl-WARNING **: Shader compilation failed:
1:2: P0004: High precision not supported, instead compiling high precision as medium precision
4:17: S0001: Type mismatch in arithmetic operation between 'int' and 'float'
when one trigger the overview mode on Mali 400 r1p1 GPU.

https://bugzilla.gnome.org/show_bug.cgi?id=745442
2015-03-03 22:10:43 +01:00
7a57e59fcc compositor: Update composite overlay window before unredirecting
The current ordering updates the clip shape of the composite overlay
window after unredirecting the target window. This has the effect of
forcing X to clear the target window and sending an expose to the
application to repaint - causing an unsightly flash. If we update the
shape first, then unredirect, X restores the background of the root
window (sending no expose events as no one is interested) and the
background is typically NONE for the root window. Then the unredirect
paints the contents of the composite backing pixmap over top without
requiring a round trip and waiting for the client to repaint - thus no
flashing.

Fixes regression from

commit d6282716b2
Author: Jasper St. Pierre <jstpierre@mecheye.net>
Date:   Fri Dec 6 17:10:44 2013 -0500

    compositor: Simplify the unredirected window management code

Cc: Jasper St. Pierre <jstpierre@mecheye.net>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

https://bugzilla.gnome.org/show_bug.cgi?id=743858
2015-02-02 15:43:01 +01:00
6772758a64 display: Fix moving grab op check
We were regarding META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN as a move.

https://bugzilla.gnome.org/show_bug.cgi?id=743254
2015-01-20 17:52:54 +01:00
08ba9c689e place: Fix workspace check when collecting relevant windows
When looking for space to place a new window, other non-minimized
windows on the same workspace should be taken into account. However
the current check does not work correctly when the placed window is
located on all workspaces, so handle that case explicitly.

https://bugzilla.gnome.org/show_bug.cgi?id=743217
2015-01-20 00:43:05 +01:00
bdb2dac244 Updated Turkish translation 2015-01-03 08:30:58 +00:00
dd9b1ce440 Bump GLib requirement
We have depended on GTask for a while now, bump the GLib requirement
to a new enough version to include that.

https://bugzilla.gnome.org/show_bug.cgi?id=698995
2014-12-29 17:53:52 +01:00
878f0e6443 Updated Slovenian translation 2014-12-26 19:37:02 +01:00
fc1f78e8cc Bump version to 3.14.3
Update NEWS.
2014-12-19 12:04:48 +01:00
25aa942a0e monitor-manager-xrandr: Set CRTC config even if it might be redundant
This optimization breaks our use of XRRScreenResources' timestamps to
detect hotplugs in case one of the outputs is disconnected and the
remaining ones don't need any mode, position or transform adjustments.

In that scenario, when applying the new configuration, we resize the X
screen but never call XRRSetCrtcConfig() and since XRRSetScreenSize()
doesn't take a timestamp and the X server doesn't update its last set
timestamp, when we next get a RRScreenChangeNotify and update
ourselves, XRRScreenResources.timestamp will still be smaller than
XRRScreenResources.configTimestamp which makes us think we're seeing a
new hotplug. We just don't enter an endless loop because the screen
size that we keep applying is always the same and the X server
short-circuits and stops sending us RRScreenChangeNotifys.

Always calling XRRSetCrtcConfig() ensures that the last set timestamp
will be bigger than configTimestamp in the next event and thus making
us trigger the monitors-changed signal properly.

Note that the X server already does basically the same checks that
we're removing here, so doing this shouldn't be a significant
efficiency loss. See

http://cgit.freedesktop.org/xorg/xserver/tree/randr/rrcrtc.c?h=server-1.16-branch#n539

https://bugzilla.gnome.org/show_bug.cgi?id=740838
2014-12-10 19:14:58 +01:00
56e74b1ea8 MetaWindowActor: don't overwrite send_frame_messages_timer
If the app finished multiple frames before we sent _NET_WM_FRAME_DRAWN,
we could add the send_frame_messages_timer multiple times. In the rare
case that the app immediately closed the window, the older timeout
could potentially then run on the freed actor.

https://bugzilla.gnome.org/show_bug.cgi?id=738686
2014-12-02 11:49:06 -05:00
7d3204b196 Fix problems resulting in left-over queued frames
* Use -1 rather than 0 as a flag for pending queue entries; 0 is
  a valid frame_counter value from Cogl.
* Consistently handle the fact we can have more than one pending
  entry. It's app misbehavior to submit a new frame before
  _NET_WM_FRAME_DRAWN is received; but we accept such frame messages,
  so we can't just leak them.
* If we remove send_frame_message_timer, assign the current frame counter
  to pending entries.
* To try to avoid regressing on this, when sending _NET_WM_FRAME_TIMINGS
  messages, if we have stale messages, or messages with no frame drawn
  time, warn and remove them from the queue rather than just accumulating.
* Improve commenting.

https://bugzilla.gnome.org/show_bug.cgi?id=738686
2014-12-02 11:49:01 -05:00
d7ff632c67 window-x11: Fix windows that set empty input shapes
Windows that set empty input shapes get n_rects of 0 when querying them
later, which makes sense, but the code that interpreted the result
translated it into a NULL input shape, which meant it was the same as
the bounding region. As such, an empty input shape would actually get
interpreted as a full input shape!

We, ourselves, set an empty input shape on tray icon windows in
gnome-shell since we would handle the picking ourselves. This meant that
we'd actually get the MetaSurfaceActorX11 when hovering over the tray
icon, instead of the ShellGTKEmbed that we capture events on and react
to.

This fixes weird tray icon behavior in gnome-shell.
2014-11-26 22:46:59 +01:00
6d3e64226d Revert "screen: Set a black background for testing purposes"
This reverts commit ec8ed1dbb0.

1) It turns out to add a momentary flicker from the transition
between the login screen and user session
2) It actually isn't needed anymore since bug 733026

https://bugzilla.gnome.org/show_bug.cgi?id=740377
2014-11-20 16:22:55 -05:00
2e7b9e0dfe window-actor: Do not request unredirection when destroyed
WindowActors can outlive their corresponding window to animate unmap.
Unredirecting the actor does not make sense in that case, so make
sure to not request it.

https://bugzilla.gnome.org/show_bug.cgi?id=740133
2014-11-14 18:31:02 +01:00
08d81b6f7f Bump version to 3.14.2
Update NEWS.
2014-11-12 19:00:56 +01:00
e01077914d configure: Actually make gbm optional
Whoops, I made the code work without it, but forgot to strip it from the
actual list of requires packages.

Spotted-by: Rico Tzschichholz <ricotz@ubuntu.com>
2014-11-10 14:54:31 +01:00
d7cf6bed63 Make gbm optional
Now it's only required by the native backend. The cursor code is getting
quite messy, but it was already considerable messy to start with.
2014-11-10 14:54:11 +01:00
d071ba8446 cursor: Clean up code flow slightly
Reverse the set of expressions so testing for gbm is at the top.
2014-11-10 14:53:19 +01:00
4d08e89c16 xrandr: ignore hotplug_mode_update value
The important thing is whether this property exists or not, but the value
doesn't matter.
2014-11-05 16:36:24 -06:00
21d8c4b032 monitor-manager: Don't try to match the outputs on hotplug
meta_monitor_config_match_current() only matches the number of outputs
and if the output connector, vendor, product and serial match.

This means that we can't use it to bypass doing any
work because it won't detect cases where we actually want to update
ourselves like e.g. an output being turned off either by us or by
another X client (e.g. xrandr).

https://bugzilla.gnome.org/show_bug.cgi?id=738630
2014-11-05 15:51:26 +01:00
c98686da92 monitor-config: Prevent a crash applying config for a closed lid
When a laptop's lid is closed we try to build and apply a temporary
configuration that disables the laptop's display if we have other
outputs.

This isn't enough though, we must also check if at least one of these
other outputs is enabled otherwise we'll try to resize the screen to
0x0 which (rightfully) hits an assertion.

https://bugzilla.gnome.org/show_bug.cgi?id=739450
2014-10-31 17:38:29 +01:00
a19eda5ae7 Bump version to 3.14.1.5
Update NEWS.
2014-10-30 11:01:04 +00:00
0a9bbe0109 meta-wayland-surface: Correcly scale the input region
The input region currently only gets scaled by the surface
scale while ignoring the output scale, which causes input events to not get
delivered correctly for clients on hidpi screens. So take the output scale
into account when doing so.

https://bugzilla.gnome.org/show_bug.cgi?id=739161
2014-10-27 18:13:00 +01:00
a8eb42e43c Revert "wayland-surface: Apply the surface scale only if needed"
This commit is wrong, it assumes that the scale only applies to the one
set by the client but its not. meta_surface_actor_wayland_scale_texture
also handles the output scale. Revert the commit to fix hidpi for wayland
clients like weston-terminal.

This reverts commit 0364ea9140.

https://bugzilla.gnome.org/show_bug.cgi?id=739161
2014-10-27 18:12:52 +01:00
9d0c9f1f42 Updated Slovak translation 2014-10-19 17:43:23 +00:00
9fa0743394 Remove unused variable 2014-10-16 11:00:51 +02:00
bb79a20fac display: Fix accidental inversion from 2f9c601
Commit 2f9c601 accidentally changed the logic here, changing the grab
behavior when not using raise-on-click. Fix this.

Spotted-by: Adam Goode <adam@spicenitz.org>
2014-10-15 23:54:20 +02:00
45 changed files with 5586 additions and 6726 deletions

48
NEWS
View File

@ -1,28 +1,44 @@
3.15.2
3.14.4
======
* Don't enable hiDPI on monitors with broken EDID [Bastien; #734839]
* Prevent crash applying monitor config for a closed lid [Rui; #739450]
* Fix "flicker" during startup transition [Ray; #740377]
* Misc. bug fixes [Lan, Florian, Carlos; #731521, #740133, #738890]
* Fix flash on unredirection [Chris; #743858]
* Fix incompatibility with GLES2 GLSL [Alban; #745442]
* Add function to refresh all background instances [Rui; #739178]
* Fix geometry of shaded windows [Florian; #746145]
* Misc. bug fixes [Florian, Rui; #698995, #743217, #743254]
Contributors:
Emmanuele Bassi, Carlos Garnacho, Jonathon Jongsma, Ting-Wei Lan, Rui Matos,
Florian Müllner, Bastien Nocera, Jasper St. Pierre, Ray Strode
Alban Browaeys, Rui Matos, Florian Müllner, Chris Wilson
Translations:
Kjartan Maraas [nb]
Matej Urbančič [sl], Muhammet Kara [tr], Samir Ribic [bs]
3.15.1
3.14.3
======
* Use GResources for theme loading [Cosimo; #736936]
* Fix headerbar drag getting stuck on xwayland [Carlos; #738411]
* Fix wayland hiDPI regressions [Adel; #739161]
* Misc bug fixes and cleanups [Jasper, Rui, Carlos; #662962, #738630, #738888,
#738890]
* Fix crash when trying to unredirect a destroyed window [Florian; #740133]
* Fix "flicker" during startup transition [Ray; #740377]
* Don't leave left-over frames queued [Owen; #738686]
* Set CRTC configuration even if it might be redundant [Rui; #740838]
Contributors:
Cosimo Cecchi, Adel Gadllah, Carlos Garnacho, Rui Matos, Florian Müllner,
Jasper St. Pierre
Rui Matos, Florian Müllner, Jasper St. Pierre, Ray Strode, Owen W. Taylor
3.14.2
======
* Prevent crash applying monitor config for a closed lid [Rui; #739450]
* Misc. fixes [Rui, Jonathon, Jasper; #738630]
Contributors:
Jonathon Jongsma, Rui Matos, Jasper St. Pierre
3.14.1.5
========
* Fix wayland hiDPI regressions [Adel; #739161]
Contributors:
Adel Gadllah, Florian Müllner, Jasper St. Pierre
Translations:
Dušan Kazik [sk]
3.14.1
======

View File

@ -1,8 +1,8 @@
AC_PREREQ(2.62)
m4_define([mutter_major_version], [3])
m4_define([mutter_minor_version], [15])
m4_define([mutter_micro_version], [2])
m4_define([mutter_minor_version], [14])
m4_define([mutter_micro_version], [4])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
@ -72,7 +72,7 @@ CLUTTER_PACKAGE=clutter-1.0
MUTTER_PC_MODULES="
gtk+-3.0 >= 3.9.11
gio-unix-2.0 >= 2.25.10
gio-unix-2.0 >= 2.35.1
pango >= 1.2.0
cairo >= 1.10.0
gsettings-desktop-schemas >= 3.7.3
@ -200,7 +200,7 @@ AC_SUBST(XWAYLAND_PATH)
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
PKG_CHECK_MODULES(MUTTER_NATIVE_BACKEND, [clutter-egl-1.0 libdrm libsystemd libinput gudev-1.0 gbm >= 10.3], [have_native_backend=yes], [have_native_backend=no])
PKG_CHECK_MODULES(MUTTER_NATIVE_BACKEND, [clutter-egl-1.0 libdrm libsystemd libinput gbm >= 10.3], [have_native_backend=yes], [have_native_backend=no])
if test $have_native_backend = yes; then
AC_DEFINE([HAVE_NATIVE_BACKEND],[1],[Define if you want to enable the native (KMS) backend based on systemd])
fi

View File

@ -111,15 +111,6 @@ IGNORE_HFILES= \
xprops.h \
$(NULL)
if !HAVE_NATIVE_BACKEND
IGNORE_HFILES+= \
meta-backend-native.h \
meta-cursor-renderer-native.h \
meta-idle-monitor-native.h \
meta-monitor-manager-kms.h \
$(NULL)
endif
if !HAVE_WAYLAND
IGNORE_HFILES += \
meta-surface-actor-wayland.h \

View File

@ -259,6 +259,8 @@ Overview of Theme Format Version 1
<!-- color obtained by a 0.5 alpha composite of the second color onto the first -->
<color value="blend/gtk:bg[SELECTED]/gtk:fg[SELECTED]/0.5"/>
</gradient>
<!-- image has an optional colorize="#color" attribute to give the
image a certain color -->
<image filename="foo.png" alpha="0.7"
x="10" y="30" width="width / 3" height="height / 4"/>
<gtk_arrow state="normal" shadow="in" arrow="up"

4046
po/bs.po

File diff suppressed because it is too large Load Diff

273
po/nb.po
View File

@ -4,10 +4,10 @@
#
msgid ""
msgstr ""
"Project-Id-Version: mutter 3.15.x\n"
"Project-Id-Version: mutter 3.13.x\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-11-15 18:32+0100\n"
"PO-Revision-Date: 2014-11-15 18:34+0100\n"
"POT-Creation-Date: 2014-09-06 14:13+0200\n"
"PO-Revision-Date: 2014-08-23 13:37+0200\n"
"Last-Translator: Kjartan Maraas <kmaraas@gnome.org>\n"
"Language-Team: Norwegian bokmål <i18n-no@lister.ping.uio.no>\n"
"Language: \n"
@ -351,7 +351,7 @@ msgid ""
"If set to true, and the focus mode is either \"sloppy\" or \"mouse\" then "
"the focus will not be changed immediately when entering a window, but only "
"after the pointer stops moving."
msgstr "Hvis denne settes til «true» og fokusmodus er enten «sloppy» eller «mouse» så vil fokus ikke endres med en gang markøren kommer inn i et vindu, men i stedet når markørens bevegelse stopper."
msgstr ""
#: ../data/org.gnome.mutter.gschema.xml.in.h:15
msgid "Draggable border width"
@ -385,7 +385,7 @@ msgstr "Plasser nye vinduer i senter"
msgid ""
"When true, the new windows will always be put in the center of the active "
"screen of the monitor."
msgstr "Når denne er «true» vil mye vinduer alltid plasseres midt på aktivt område på skjermen."
msgstr ""
#: ../data/org.gnome.mutter.gschema.xml.in.h:21
msgid "Select window from tab popup"
@ -423,29 +423,29 @@ msgstr "Bytt til VT 6"
msgid "Switch to VT 7"
msgstr "Bytt til VT 7"
#: ../src/backends/meta-monitor-manager.c:350
#: ../src/backends/meta-monitor-manager.c:412
msgid "Built-in display"
msgstr "Innebygget skjerm"
#: ../src/backends/meta-monitor-manager.c:375
#: ../src/backends/meta-monitor-manager.c:437
msgid "Unknown"
msgstr "Ukjent"
#: ../src/backends/meta-monitor-manager.c:377
#: ../src/backends/meta-monitor-manager.c:439
msgid "Unknown Display"
msgstr "Ukjent skjerm"
#. TRANSLATORS: this is a monitor vendor name, followed by a
#. * size in inches, like 'Dell 15"'
#.
#: ../src/backends/meta-monitor-manager.c:385
#: ../src/backends/meta-monitor-manager.c:447
#, c-format
msgid "%s %s"
msgstr "%s %s"
#. This probably means that a non-WM compositor like xcompmgr is running;
#. * we have no way to get it to exit
#: ../src/compositor/compositor.c:456
#: ../src/compositor/compositor.c:443
#, c-format
msgid ""
"Another compositing manager is already running on screen %i on display \"%s"
@ -481,7 +481,7 @@ msgstr "_Vent"
msgid "_Force Quit"
msgstr "_Tvungen nedstenging"
#: ../src/core/display.c:550
#: ../src/core/display.c:547
#, c-format
msgid "Failed to open X Window System display '%s'\n"
msgstr "Feil under åpning av X Window System skjerm «%s»\n"
@ -518,12 +518,12 @@ msgstr "Kjør som en wayland-kompositør"
msgid "Run as a full display server, rather than nested"
msgstr "Kjør som en full skjermtjener, heller enn nøstet"
#: ../src/core/main.c:451
#: ../src/core/main.c:459
#, c-format
msgid "Failed to scan themes directory: %s\n"
msgstr "Feil under søk i temakatalog: %s\n"
#: ../src/core/main.c:467
#: ../src/core/main.c:475
#, c-format
msgid ""
"Could not find a theme! Be sure %s exists and contains the usual themes.\n"
@ -553,17 +553,17 @@ msgstr "Skriv versjonsnummer"
msgid "Mutter plugin to use"
msgstr "Mutter-tillegg som skal brukes"
#: ../src/core/prefs.c:2064
#: ../src/core/prefs.c:2101
#, c-format
msgid "Workspace %d"
msgstr "Arbeidsområde %d"
#: ../src/core/screen.c:543
#: ../src/core/screen.c:548
#, c-format
msgid "Screen %d on display '%s' is invalid\n"
msgstr "Skjerm %d på display «%s» er ugyldig\n"
#: ../src/core/screen.c:559
#: ../src/core/screen.c:564
#, c-format
msgid ""
"Screen %d on display \"%s\" already has a window manager; try using the --"
@ -572,7 +572,7 @@ msgstr ""
"Skjerm %d på display «%s» har allerede en vindushåndterer; prøv å bruke "
"flagget --replace for å erstatte aktiv vindushåndterer.\n"
#: ../src/core/screen.c:652
#: ../src/core/screen.c:657
#, c-format
msgid "Screen %d on display \"%s\" already has a window manager\n"
msgstr "Skjerm %d på display «%s» har allerede en vinduhåndterer\n"
@ -589,48 +589,48 @@ msgstr "Mutter er kompilert uten støtte for «verbose» modus\n"
msgid "%d x %d"
msgstr "%d x %d"
#: ../src/ui/theme.c:154
#: ../src/ui/theme.c:233
msgid "top"
msgstr "topp"
#: ../src/ui/theme.c:156
#: ../src/ui/theme.c:235
msgid "bottom"
msgstr "bunn"
#: ../src/ui/theme.c:158
#: ../src/ui/theme.c:237
msgid "left"
msgstr "venstre"
#: ../src/ui/theme.c:160
#: ../src/ui/theme.c:239
msgid "right"
msgstr "høyre"
#: ../src/ui/theme.c:188
#: ../src/ui/theme.c:267
#, c-format
msgid "frame geometry does not specify \"%s\" dimension"
msgstr "rammegeometrien spesifiserer ikke «%s»-dimensjon"
#: ../src/ui/theme.c:207
#: ../src/ui/theme.c:286
#, c-format
msgid "frame geometry does not specify dimension \"%s\" for border \"%s\""
msgstr "rammegeometri spesifiserer ikke dimensjon «%s» for kant «%s»"
#: ../src/ui/theme.c:244
#: ../src/ui/theme.c:323
#, c-format
msgid "Button aspect ratio %g is not reasonable"
msgstr "Aspektrate %g for knapp er ikke fornuftig"
#: ../src/ui/theme.c:256
#: ../src/ui/theme.c:335
#, c-format
msgid "Frame geometry does not specify size of buttons"
msgstr "Rammegeometrien spesifiserer ikke størrelse på knapper"
#: ../src/ui/theme.c:1024
#: ../src/ui/theme.c:1061
#, c-format
msgid "Gradients should have at least two colors"
msgstr "Gradienter må ha minst to farger"
#: ../src/ui/theme.c:1174
#: ../src/ui/theme.c:1211
#, c-format
msgid ""
"GTK custom color specification must have color name and fallback in "
@ -639,7 +639,7 @@ msgstr ""
"Egendefinert GTK-fargespesifikasjon må ha fargenavn og reserve i parantes, f."
"eks gtk:custom(foo,bar); kunne ikke lese «%s»"
#: ../src/ui/theme.c:1190
#: ../src/ui/theme.c:1227
#, c-format
msgid ""
"Invalid character '%c' in color_name parameter of gtk:custom, only A-Za-z0-9-"
@ -648,7 +648,7 @@ msgstr ""
"Ugyldig tegn «%c» i parameter color_name for gtk:custom, kun A-Za-z0-9-_ er "
"gyldig"
#: ../src/ui/theme.c:1204
#: ../src/ui/theme.c:1241
#, c-format
msgid ""
"Gtk:custom format is \"gtk:custom(color_name,fallback)\", \"%s\" does not "
@ -657,7 +657,7 @@ msgstr ""
"Gtk:custom-format er «gtk:custom(color_name,fallback)», «%s» passer ikke i "
"formatet"
#: ../src/ui/theme.c:1249
#: ../src/ui/theme.c:1286
#, c-format
msgid ""
"GTK color specification must have the state in brackets, e.g. gtk:fg[NORMAL] "
@ -666,7 +666,7 @@ msgstr ""
"GTK-fargespesifikasjon må ha tilstand i klammer, f.eks. gtk:fg[NORMAL], hvor "
"NORMAL er tilstanden; kunne ikke lese «%s»"
#: ../src/ui/theme.c:1263
#: ../src/ui/theme.c:1300
#, c-format
msgid ""
"GTK color specification must have a close bracket after the state, e.g. gtk:"
@ -675,17 +675,17 @@ msgstr ""
"GTK-fargespesifikasjon må ha en avsluttende klamme etter tilstanden, f.eks. "
"gtk:fg[NORMAL], hvor NORMAL er tilstanden; kunne ikke lese «%s»"
#: ../src/ui/theme.c:1274
#: ../src/ui/theme.c:1311
#, c-format
msgid "Did not understand state \"%s\" in color specification"
msgstr "Forsto ikke tilstand «%s» i fargespesifikasjonen"
#: ../src/ui/theme.c:1287
#: ../src/ui/theme.c:1324
#, c-format
msgid "Did not understand color component \"%s\" in color specification"
msgstr "Forsto ikke fargekomponent «%s» i fargespesifikasjonen"
#: ../src/ui/theme.c:1315
#: ../src/ui/theme.c:1352
#, c-format
msgid ""
"Blend format is \"blend/bg_color/fg_color/alpha\", \"%s\" does not fit the "
@ -694,56 +694,56 @@ msgstr ""
"Blandingsformat er «blend/bg_color/fg_color/alpha», «%s» passer ikke i "
"formatet"
#: ../src/ui/theme.c:1326
#: ../src/ui/theme.c:1363
#, c-format
msgid "Could not parse alpha value \"%s\" in blended color"
msgstr "Kunne ikke lese alpha-verdi «%s» i blandet farge"
#: ../src/ui/theme.c:1336
#: ../src/ui/theme.c:1373
#, c-format
msgid "Alpha value \"%s\" in blended color is not between 0.0 and 1.0"
msgstr "Alpha-verdi «%s» i blandet farge er ikke mellom 0.0 og 1.0"
#: ../src/ui/theme.c:1382
#: ../src/ui/theme.c:1419
#, c-format
msgid ""
"Shade format is \"shade/base_color/factor\", \"%s\" does not fit the format"
msgstr ""
"Skyggeformatet er «shade/base_color/factor», «%s» passer ikke i formatet"
#: ../src/ui/theme.c:1393
#: ../src/ui/theme.c:1430
#, c-format
msgid "Could not parse shade factor \"%s\" in shaded color"
msgstr "Kunne ikke lese skyggefaktor «%s» i skyggelagt farge"
#: ../src/ui/theme.c:1403
#: ../src/ui/theme.c:1440
#, c-format
msgid "Shade factor \"%s\" in shaded color is negative"
msgstr "Skyggefaktor «%s» i skyggelagt farge er negativ"
#: ../src/ui/theme.c:1432
#: ../src/ui/theme.c:1469
#, c-format
msgid "Could not parse color \"%s\""
msgstr "Kunne ikke lese farge «%s»"
#: ../src/ui/theme.c:1741
#: ../src/ui/theme.c:1778
#, c-format
msgid "Coordinate expression contains character '%s' which is not allowed"
msgstr "Koordinatuttrykk inneholder tegn «%s» som ikke er tillatt"
#: ../src/ui/theme.c:1768
#: ../src/ui/theme.c:1805
#, c-format
msgid ""
"Coordinate expression contains floating point number '%s' which could not be "
"parsed"
msgstr "Koordinatuttrykk inneholder flyttall «%s» som ikke kunne tolkes"
#: ../src/ui/theme.c:1782
#: ../src/ui/theme.c:1819
#, c-format
msgid "Coordinate expression contains integer '%s' which could not be parsed"
msgstr "Koordinatuttrykk inneholder heltall «%s» som ikke kunne tolkes"
#: ../src/ui/theme.c:1903
#: ../src/ui/theme.c:1940
#, c-format
msgid ""
"Coordinate expression contained unknown operator at the start of this text: "
@ -752,39 +752,39 @@ msgstr ""
"Koordinatuttrykket inneholdt en ukjent operator ved begynnelsen av denne "
"teksten: «%s»"
#: ../src/ui/theme.c:1960
#: ../src/ui/theme.c:1997
#, c-format
msgid "Coordinate expression was empty or not understood"
msgstr "Koordinatuttrykket var tomt eller ble ikke forstått"
#: ../src/ui/theme.c:2073 ../src/ui/theme.c:2083 ../src/ui/theme.c:2117
#: ../src/ui/theme.c:2110 ../src/ui/theme.c:2120 ../src/ui/theme.c:2154
#, c-format
msgid "Coordinate expression results in division by zero"
msgstr "Koordinatuttrykket resulterer i divisjon med null"
#: ../src/ui/theme.c:2125
#: ../src/ui/theme.c:2162
#, c-format
msgid ""
"Coordinate expression tries to use mod operator on a floating-point number"
msgstr "Koordinatuttrykket prøver å bruke mod-operator på et flyttall"
#: ../src/ui/theme.c:2181
#: ../src/ui/theme.c:2218
#, c-format
msgid ""
"Coordinate expression has an operator \"%s\" where an operand was expected"
msgstr "Koordinatuttrykket har en operator «%s» hvor en operand var ventet"
#: ../src/ui/theme.c:2190
#: ../src/ui/theme.c:2227
#, c-format
msgid "Coordinate expression had an operand where an operator was expected"
msgstr "Koordinatuttrykket hadde en operand hvor en operator var ventet"
#: ../src/ui/theme.c:2198
#: ../src/ui/theme.c:2235
#, c-format
msgid "Coordinate expression ended with an operator instead of an operand"
msgstr "Koordinatuttrykket sluttet med en operator i stedet for en operand"
#: ../src/ui/theme.c:2208
#: ../src/ui/theme.c:2245
#, c-format
msgid ""
"Coordinate expression has operator \"%c\" following operator \"%c\" with no "
@ -793,38 +793,38 @@ msgstr ""
"Koordinatuttrykket har en operator «%c» etter en operator «%c» og ingen "
"operand mellom dem."
#: ../src/ui/theme.c:2359 ../src/ui/theme.c:2404
#: ../src/ui/theme.c:2396 ../src/ui/theme.c:2441
#, c-format
msgid "Coordinate expression had unknown variable or constant \"%s\""
msgstr "Koordinatuttrykket haddeen ukjent variabel eller konstant «%s»"
#: ../src/ui/theme.c:2458
#: ../src/ui/theme.c:2495
#, c-format
msgid "Coordinate expression parser overflowed its buffer."
msgstr "Tolkeren for koordinatuttrykk oversteg buffergrensen."
#: ../src/ui/theme.c:2487
#: ../src/ui/theme.c:2524
#, c-format
msgid "Coordinate expression had a close parenthesis with no open parenthesis"
msgstr "Koordinatuttrykket hadde en parantes slutt uten parantes start"
#: ../src/ui/theme.c:2551
#: ../src/ui/theme.c:2588
#, c-format
msgid "Coordinate expression had an open parenthesis with no close parenthesis"
msgstr "Koordinatuttrykket hadde en åpen parantes uten en avsluttende parantes"
#: ../src/ui/theme.c:2562
#: ../src/ui/theme.c:2599
#, c-format
msgid "Coordinate expression doesn't seem to have any operators or operands"
msgstr ""
"Koordinatuttrykket ser ikke ut til å ha noen operatorer eller operander"
#: ../src/ui/theme.c:2775 ../src/ui/theme.c:2795 ../src/ui/theme.c:2815
#: ../src/ui/theme.c:2812 ../src/ui/theme.c:2832 ../src/ui/theme.c:2852
#, c-format
msgid "Theme contained an expression that resulted in an error: %s\n"
msgstr "Tema inneholdt et uttrykk som resulterte i en feil: %s\n"
#: ../src/ui/theme.c:4055
#: ../src/ui/theme.c:4455
#, c-format
msgid ""
"<button function=\"%s\" state=\"%s\" draw_ops=\"whatever\"/> must be "
@ -833,25 +833,25 @@ msgstr ""
"<button function=«%s» state=«%s» draw_ops=«ett-eller-annet»/> må "
"spesifiseres for denne rammestilen"
#: ../src/ui/theme.c:4570 ../src/ui/theme.c:4595
#: ../src/ui/theme.c:4970 ../src/ui/theme.c:4995
#, c-format
msgid ""
"Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"
msgstr ""
"Mangler <frame state=«%s» resize=«%s» focus=«%s» stil=«ett-eller-annet»/>"
#: ../src/ui/theme.c:4641
#: ../src/ui/theme.c:5041
#, c-format
msgid "Failed to load theme \"%s\": %s\n"
msgstr "Klarte ikke å laste tema «%s»: %s\n"
#: ../src/ui/theme.c:4777 ../src/ui/theme.c:4784 ../src/ui/theme.c:4791
#: ../src/ui/theme.c:4798 ../src/ui/theme.c:4805
#: ../src/ui/theme.c:5177 ../src/ui/theme.c:5184 ../src/ui/theme.c:5191
#: ../src/ui/theme.c:5198 ../src/ui/theme.c:5205
#, c-format
msgid "No <%s> set for theme \"%s\""
msgstr "<%s> er ikke satt for tema «%s»"
#: ../src/ui/theme.c:4813
#: ../src/ui/theme.c:5213
#, c-format
msgid ""
"No frame style set for window type \"%s\" in theme \"%s\", add a <window "
@ -860,14 +860,14 @@ msgstr ""
"Ingen rammestil satt for vindutype «%s» i tema «%s», legg til et <window "
"type=«%s» style_set=«ett-eller-annet»/>-element"
#: ../src/ui/theme.c:5220 ../src/ui/theme.c:5282 ../src/ui/theme.c:5345
#: ../src/ui/theme.c:5620 ../src/ui/theme.c:5682 ../src/ui/theme.c:5745
#, c-format
msgid ""
"User-defined constants must begin with a capital letter; \"%s\" does not"
msgstr ""
"Brukerdefinerte konstanter må begynne med stor bokstav; «%s» gjør ikke det"
#: ../src/ui/theme.c:5228 ../src/ui/theme.c:5290 ../src/ui/theme.c:5353
#: ../src/ui/theme.c:5628 ../src/ui/theme.c:5690 ../src/ui/theme.c:5753
#, c-format
msgid "Constant \"%s\" has already been defined"
msgstr "Konstant «%s» er allerede definert"
@ -930,13 +930,13 @@ msgstr "Bolske verdier må være «sann» eller «usann» ikke «%s»"
msgid "Angle must be between 0.0 and 360.0, was %g\n"
msgstr "Vinkelen må være mellom 0.0 og 360.0, var %g\n"
#: ../src/ui/theme-parser.c:797
#: ../src/ui/theme-parser.c:800
#, c-format
msgid "Alpha must be between 0.0 (invisible) and 1.0 (fully opaque), was %g\n"
msgstr ""
"Alpha må være mellom 0.0 (usynlig) og 1.0 (helt ugjennomsiktig), var %g\n"
#: ../src/ui/theme-parser.c:862
#: ../src/ui/theme-parser.c:865
#, c-format
msgid ""
"Invalid title scale \"%s\" (must be one of xx-small,x-small,small,medium,"
@ -945,58 +945,58 @@ msgstr ""
"Ugyldig skalering av tittel «%s» (må være en av xx-small,x-small,small,"
"medium,large,x-large,xx-large)\n"
#: ../src/ui/theme-parser.c:1018 ../src/ui/theme-parser.c:1081
#: ../src/ui/theme-parser.c:1115 ../src/ui/theme-parser.c:1218
#: ../src/ui/theme-parser.c:1021 ../src/ui/theme-parser.c:1084
#: ../src/ui/theme-parser.c:1118 ../src/ui/theme-parser.c:1221
#, c-format
msgid "<%s> name \"%s\" used a second time"
msgstr "<%s> navn «%s» brukt på nytt"
#: ../src/ui/theme-parser.c:1030 ../src/ui/theme-parser.c:1127
#: ../src/ui/theme-parser.c:1230
#: ../src/ui/theme-parser.c:1033 ../src/ui/theme-parser.c:1130
#: ../src/ui/theme-parser.c:1233
#, c-format
msgid "<%s> parent \"%s\" has not been defined"
msgstr "<%s> opphav «%s» er ikke definert"
#: ../src/ui/theme-parser.c:1140
#: ../src/ui/theme-parser.c:1143
#, c-format
msgid "<%s> geometry \"%s\" has not been defined"
msgstr "<%s> geometri «%s» er ikke definert"
#: ../src/ui/theme-parser.c:1153
#: ../src/ui/theme-parser.c:1156
#, c-format
msgid "<%s> must specify either a geometry or a parent that has a geometry"
msgstr "<%s> må spesifisere enten en geometri eller et opphav som har geometri"
#: ../src/ui/theme-parser.c:1195
#: ../src/ui/theme-parser.c:1198
msgid "You must specify a background for an alpha value to be meaningful"
msgstr "Du må oppgi en bakgrunn for at en alpha-verdi skal ha mening"
#: ../src/ui/theme-parser.c:1263
#: ../src/ui/theme-parser.c:1266
#, c-format
msgid "Unknown type \"%s\" on <%s> element"
msgstr "Ukjent type «%s» på <%s>-element"
#: ../src/ui/theme-parser.c:1274
#: ../src/ui/theme-parser.c:1277
#, c-format
msgid "Unknown style_set \"%s\" on <%s> element"
msgstr "Ukjent style_set «%s» på <%s>-element"
#: ../src/ui/theme-parser.c:1282
#: ../src/ui/theme-parser.c:1285
#, c-format
msgid "Window type \"%s\" has already been assigned a style set"
msgstr "Vindutype «%s» er allerede tildelt et stilsett"
#: ../src/ui/theme-parser.c:1312 ../src/ui/theme-parser.c:1376
#: ../src/ui/theme-parser.c:1602 ../src/ui/theme-parser.c:2821
#: ../src/ui/theme-parser.c:2867 ../src/ui/theme-parser.c:3017
#: ../src/ui/theme-parser.c:3253 ../src/ui/theme-parser.c:3291
#: ../src/ui/theme-parser.c:3329 ../src/ui/theme-parser.c:3367
#: ../src/ui/theme-parser.c:1315 ../src/ui/theme-parser.c:1379
#: ../src/ui/theme-parser.c:1605 ../src/ui/theme-parser.c:2840
#: ../src/ui/theme-parser.c:2886 ../src/ui/theme-parser.c:3036
#: ../src/ui/theme-parser.c:3272 ../src/ui/theme-parser.c:3310
#: ../src/ui/theme-parser.c:3348 ../src/ui/theme-parser.c:3386
#, c-format
msgid "Element <%s> is not allowed below <%s>"
msgstr "Element <%s> er ikke tillatt under <%s>"
#: ../src/ui/theme-parser.c:1426 ../src/ui/theme-parser.c:1440
#: ../src/ui/theme-parser.c:1485
#: ../src/ui/theme-parser.c:1429 ../src/ui/theme-parser.c:1443
#: ../src/ui/theme-parser.c:1488
msgid ""
"Cannot specify both \"button_width\"/\"button_height\" and \"aspect_ratio\" "
"for buttons"
@ -1004,123 +1004,123 @@ msgstr ""
"Kan ikke spesifisere både «button_width»/«button_height» og «aspect_ratio» "
"for knapper"
#: ../src/ui/theme-parser.c:1449
#: ../src/ui/theme-parser.c:1452
#, c-format
msgid "Distance \"%s\" is unknown"
msgstr "Avstand «%s» er ukjent"
#: ../src/ui/theme-parser.c:1494
#: ../src/ui/theme-parser.c:1497
#, c-format
msgid "Aspect ratio \"%s\" is unknown"
msgstr "Aspektrate «%s» er ukjent"
#: ../src/ui/theme-parser.c:1556
#: ../src/ui/theme-parser.c:1559
#, c-format
msgid "Border \"%s\" is unknown"
msgstr "Grense «%s» er ukjent"
#: ../src/ui/theme-parser.c:1867
#: ../src/ui/theme-parser.c:1870
#, c-format
msgid "No \"start_angle\" or \"from\" attribute on element <%s>"
msgstr "Ingen «start_angle» eller «from»-attributt på element <%s>"
#: ../src/ui/theme-parser.c:1874
#: ../src/ui/theme-parser.c:1877
#, c-format
msgid "No \"extent_angle\" or \"to\" attribute on element <%s>"
msgstr "Ingen «extent_angle» eller «to»-attributt <%s>-element"
#: ../src/ui/theme-parser.c:2114
#: ../src/ui/theme-parser.c:2117
#, c-format
msgid "Did not understand value \"%s\" for type of gradient"
msgstr "Forsto ikke verdi «%s» for gradienttype"
#: ../src/ui/theme-parser.c:2189 ../src/ui/theme-parser.c:2551
#: ../src/ui/theme-parser.c:2195 ../src/ui/theme-parser.c:2570
#, c-format
msgid "Did not understand fill type \"%s\" for <%s> element"
msgstr "Forsto ikke fyll-type «%s» for <%s>-element"
#: ../src/ui/theme-parser.c:2343 ../src/ui/theme-parser.c:2426
#: ../src/ui/theme-parser.c:2489
#: ../src/ui/theme-parser.c:2362 ../src/ui/theme-parser.c:2445
#: ../src/ui/theme-parser.c:2508
#, c-format
msgid "Did not understand state \"%s\" for <%s> element"
msgstr "Forsto ikke tilstand «%s» for element <%s>"
#: ../src/ui/theme-parser.c:2353 ../src/ui/theme-parser.c:2436
#: ../src/ui/theme-parser.c:2372 ../src/ui/theme-parser.c:2455
#, c-format
msgid "Did not understand shadow \"%s\" for <%s> element"
msgstr "Forsto ikke skygge «%s» for element <%s>"
#: ../src/ui/theme-parser.c:2363
#: ../src/ui/theme-parser.c:2382
#, c-format
msgid "Did not understand arrow \"%s\" for <%s> element"
msgstr "Forsto ikke pil «%s» for element <%s>"
#: ../src/ui/theme-parser.c:2677 ../src/ui/theme-parser.c:2773
#: ../src/ui/theme-parser.c:2696 ../src/ui/theme-parser.c:2792
#, c-format
msgid "No <draw_ops> called \"%s\" has been defined"
msgstr "Ingen <draw_ops> kalt «%s» er definert"
#: ../src/ui/theme-parser.c:2689 ../src/ui/theme-parser.c:2785
#: ../src/ui/theme-parser.c:2708 ../src/ui/theme-parser.c:2804
#, c-format
msgid "Including draw_ops \"%s\" here would create a circular reference"
msgstr "Hvis du tar med draw_ops «%s» her vil dette lage en sirkulær referanse"
#: ../src/ui/theme-parser.c:2900
#: ../src/ui/theme-parser.c:2919
#, c-format
msgid "Unknown position \"%s\" for frame piece"
msgstr "Ukjent posisjon «%s» for rammesdel"
#: ../src/ui/theme-parser.c:2908
#: ../src/ui/theme-parser.c:2927
#, c-format
msgid "Frame style already has a piece at position %s"
msgstr "Rammestil har allerede en del i posisjon %s"
#: ../src/ui/theme-parser.c:2925 ../src/ui/theme-parser.c:3002
#: ../src/ui/theme-parser.c:2944 ../src/ui/theme-parser.c:3021
#, c-format
msgid "No <draw_ops> with the name \"%s\" has been defined"
msgstr "Ingen <draw_ops> med navn «%s» er definert"
#: ../src/ui/theme-parser.c:2955
#: ../src/ui/theme-parser.c:2974
#, c-format
msgid "Unknown function \"%s\" for button"
msgstr "Ukjent funksjon «%s» for knapp"
#: ../src/ui/theme-parser.c:2965
#: ../src/ui/theme-parser.c:2984
#, c-format
msgid "Button function \"%s\" does not exist in this version (%d, need %d)"
msgstr "Knappefunksjon «%s» eksisterer ikke i denne versjonen (%d, trenger %d)"
#: ../src/ui/theme-parser.c:2977
#: ../src/ui/theme-parser.c:2996
#, c-format
msgid "Unknown state \"%s\" for button"
msgstr "Ukjent tilstand «%s» for knapp"
#: ../src/ui/theme-parser.c:2985
#: ../src/ui/theme-parser.c:3004
#, c-format
msgid "Frame style already has a button for function %s state %s"
msgstr "Rammestil har allerede en knapp for funksjon %s tilstand %s"
#: ../src/ui/theme-parser.c:3056
#: ../src/ui/theme-parser.c:3075
#, c-format
msgid "\"%s\" is not a valid value for focus attribute"
msgstr "«%s» er ikke en gyldig verdi for fokusattributt"
#: ../src/ui/theme-parser.c:3065
#: ../src/ui/theme-parser.c:3084
#, c-format
msgid "\"%s\" is not a valid value for state attribute"
msgstr "«%s» er ikke en gyldig verdi for tilstandsattributt"
#: ../src/ui/theme-parser.c:3075
#: ../src/ui/theme-parser.c:3094
#, c-format
msgid "A style called \"%s\" has not been defined"
msgstr "En stil med navn «%s» er ikke definert"
#: ../src/ui/theme-parser.c:3096 ../src/ui/theme-parser.c:3119
#: ../src/ui/theme-parser.c:3115 ../src/ui/theme-parser.c:3138
#, c-format
msgid "\"%s\" is not a valid value for resize attribute"
msgstr "«%s» er ikke en gyldig verdi for attributt for endring av størrelse"
#: ../src/ui/theme-parser.c:3130
#: ../src/ui/theme-parser.c:3149
#, c-format
msgid ""
"Should not have \"resize\" attribute on <%s> element for maximized/shaded "
@ -1129,27 +1129,27 @@ msgstr ""
"Skal ikke være noen «resize»-attributt på <%s>-element for maksimert/"
"skyggelagt tilstand"
#: ../src/ui/theme-parser.c:3144
#: ../src/ui/theme-parser.c:3163
#, c-format
msgid ""
"Should not have \"resize\" attribute on <%s> element for maximized states"
msgstr ""
"Skal ikke være noen «resize»-attributt på <%s>-element for maksimert tilstand"
#: ../src/ui/theme-parser.c:3158 ../src/ui/theme-parser.c:3202
#: ../src/ui/theme-parser.c:3177 ../src/ui/theme-parser.c:3221
#, c-format
msgid "Style has already been specified for state %s resize %s focus %s"
msgstr ""
"Stil er allerede spesifisert for tilstand %s størrelsesendring %s fokus %s"
#: ../src/ui/theme-parser.c:3169 ../src/ui/theme-parser.c:3180
#: ../src/ui/theme-parser.c:3191 ../src/ui/theme-parser.c:3213
#: ../src/ui/theme-parser.c:3224 ../src/ui/theme-parser.c:3235
#: ../src/ui/theme-parser.c:3188 ../src/ui/theme-parser.c:3199
#: ../src/ui/theme-parser.c:3210 ../src/ui/theme-parser.c:3232
#: ../src/ui/theme-parser.c:3243 ../src/ui/theme-parser.c:3254
#, c-format
msgid "Style has already been specified for state %s focus %s"
msgstr "Stil er allerede spesifisert for tilstand %s fokus %s"
#: ../src/ui/theme-parser.c:3274
#: ../src/ui/theme-parser.c:3293
msgid ""
"Can't have a two draw_ops for a <piece> element (theme specified a draw_ops "
"attribute and also a <draw_ops> element, or specified two elements)"
@ -1158,7 +1158,7 @@ msgstr ""
"draw_ops-attributt i tillegg til et <draw_ops>-element, eller så "
"spesifiserte det to elementer)"
#: ../src/ui/theme-parser.c:3312
#: ../src/ui/theme-parser.c:3331
msgid ""
"Can't have a two draw_ops for a <button> element (theme specified a draw_ops "
"attribute and also a <draw_ops> element, or specified two elements)"
@ -1167,7 +1167,7 @@ msgstr ""
"draw_ops-attributt i tillegg til et <draw_ops>-element, eller det "
"spesifiserte to elementer)"
#: ../src/ui/theme-parser.c:3350
#: ../src/ui/theme-parser.c:3369
msgid ""
"Can't have a two draw_ops for a <menu_icon> element (theme specified a "
"draw_ops attribute and also a <draw_ops> element, or specified two elements)"
@ -1176,12 +1176,12 @@ msgstr ""
"draw_ops-attributt i tillegg til et <draw_ops>-element, eller det "
"spesifiserte to elementer)"
#: ../src/ui/theme-parser.c:3414
#: ../src/ui/theme-parser.c:3433
#, c-format
msgid "Bad version specification '%s'"
msgstr "Ugyldig versjonspesifikasjon «%s»"
#: ../src/ui/theme-parser.c:3487
#: ../src/ui/theme-parser.c:3506
msgid ""
"\"version\" attribute cannot be used in metacity-theme-1.xml or metacity-"
"theme-2.xml"
@ -1189,66 +1189,66 @@ msgstr ""
"«version»-attributt kan ikke brukes i metacity-theme-1.xml eller metacity-"
"theme-2.xml"
#: ../src/ui/theme-parser.c:3510
#: ../src/ui/theme-parser.c:3529
#, c-format
msgid "Theme requires version %s but latest supported theme version is %d.%d"
msgstr "Tema krever versjon %s men siste støttede temaversjon er %d.%d"
#: ../src/ui/theme-parser.c:3542
#: ../src/ui/theme-parser.c:3561
#, c-format
msgid "Outermost element in theme must be <metacity_theme> not <%s>"
msgstr "Ytterste element i temaet må være <metacity_theme> ikke <%s>"
#: ../src/ui/theme-parser.c:3562
#: ../src/ui/theme-parser.c:3581
#, c-format
msgid ""
"Element <%s> is not allowed inside a name/author/date/description element"
msgstr ""
"Element <%s> er ikke tillatt inne i et name/author/date/description element"
#: ../src/ui/theme-parser.c:3567
#: ../src/ui/theme-parser.c:3586
#, c-format
msgid "Element <%s> is not allowed inside a <constant> element"
msgstr "Element <%s> er ikke tillatt inne i et <constand> element"
#: ../src/ui/theme-parser.c:3579
#: ../src/ui/theme-parser.c:3598
#, c-format
msgid ""
"Element <%s> is not allowed inside a distance/border/aspect_ratio element"
msgstr "Element <%s> er ikke tillatt inne i et avstand/kant/aspektrate-element"
#: ../src/ui/theme-parser.c:3601
#: ../src/ui/theme-parser.c:3620
#, c-format
msgid "Element <%s> is not allowed inside a draw operation element"
msgstr "Element <%s> er ikke tillatt inne i et element for tegneoperasjon"
#: ../src/ui/theme-parser.c:3611 ../src/ui/theme-parser.c:3641
#: ../src/ui/theme-parser.c:3646 ../src/ui/theme-parser.c:3651
#: ../src/ui/theme-parser.c:3630 ../src/ui/theme-parser.c:3660
#: ../src/ui/theme-parser.c:3665 ../src/ui/theme-parser.c:3670
#, c-format
msgid "Element <%s> is not allowed inside a <%s> element"
msgstr "Element <%s> er ikke tillatt inne i et <%s>-element"
#: ../src/ui/theme-parser.c:3879
#: ../src/ui/theme-parser.c:3898
msgid "No draw_ops provided for frame piece"
msgstr "Ingen draw_ops tilbys for rammedelen"
#: ../src/ui/theme-parser.c:3894
#: ../src/ui/theme-parser.c:3913
msgid "No draw_ops provided for button"
msgstr "Ingen draw_ops tilbys for knappen"
#: ../src/ui/theme-parser.c:3948
#: ../src/ui/theme-parser.c:3967
#, c-format
msgid "No text is allowed inside element <%s>"
msgstr "Ingen tekst er tillatt inne i element <%s>"
#: ../src/ui/theme-parser.c:4006 ../src/ui/theme-parser.c:4018
#: ../src/ui/theme-parser.c:4030 ../src/ui/theme-parser.c:4042
#: ../src/ui/theme-parser.c:4054
#: ../src/ui/theme-parser.c:4025 ../src/ui/theme-parser.c:4037
#: ../src/ui/theme-parser.c:4049 ../src/ui/theme-parser.c:4061
#: ../src/ui/theme-parser.c:4073
#, c-format
msgid "<%s> specified twice for this theme"
msgstr "<%s> spesifisert to ganger for dette temaet"
#: ../src/ui/theme-parser.c:4316
#: ../src/ui/theme-parser.c:4335
#, c-format
msgid "Failed to find a valid file for theme %s\n"
msgstr "Fant ikke en gyldig fil for tema %s\n"
@ -1261,7 +1261,10 @@ msgstr ""
"Disse vinduene støtter ikke &quot;lagre aktiv konfigurasjon&quot;og vil "
"måtte startes på nytt manuelt neste gang du logger inn."
#: ../src/x11/window-props.c:558
#: ../src/x11/window-props.c:515
#, c-format
msgid "%s (on %s)"
msgstr "%s (på %s)"
#~ msgid "background texture could not be created from file"
#~ msgstr "bakgrunnstekstur kunne ikke lages fra fil"

1443
po/sk.po

File diff suppressed because it is too large Load Diff

1214
po/sl.po

File diff suppressed because it is too large Load Diff

1940
po/tr.po

File diff suppressed because it is too large Load Diff

View File

@ -41,9 +41,11 @@ endif
# Some random test programs for bits of the code
testboxes_SOURCES = core/testboxes.c
testgradient_SOURCES = ui/testgradient.c
testasyncgetprop_SOURCES = x11/testasyncgetprop.c
noinst_PROGRAMS+=testboxes testasyncgetprop
noinst_PROGRAMS+=testboxes testgradient testasyncgetprop
testboxes_LDADD = $(MUTTER_LIBS) libmutter.la
testgradient_LDADD = $(MUTTER_LIBS) libmutter.la
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la

View File

@ -6,7 +6,6 @@ lib_LTLIBRARIES = libmutter.la
SUBDIRS=compositor/plugins
EXTRA_DIST =
NULL =
AM_CPPFLAGS = \
-DCLUTTER_ENABLE_COMPOSITOR_API \
@ -32,30 +31,26 @@ AM_CPPFLAGS = \
-DMUTTER_PKGLIBDIR=\"$(pkglibdir)\" \
-DMUTTER_PLUGIN_DIR=\"$(MUTTER_PLUGIN_DIR)\" \
-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \
-DXWAYLAND_PATH=\"$(XWAYLAND_PATH)\" \
$(NULL)
-DXWAYLAND_PATH=\"$(XWAYLAND_PATH)\"
mutter_built_sources = \
$(dbus_idle_built_sources) \
$(dbus_display_config_built_sources) \
$(dbus_login1_built_sources) \
mutter-enum-types.h \
mutter-enum-types.c \
$(NULL)
mutter-enum-types.c
if HAVE_WAYLAND
mutter_built_sources += \
gtk-shell-protocol.c \
gtk-shell-server-protocol.h \
xdg-shell-protocol.c \
xdg-shell-server-protocol.h \
$(NULL)
xdg-shell-server-protocol.h
endif
wayland_protocols = \
wayland_protocols = \
wayland/protocol/gtk-shell.xml \
wayland/protocol/xdg-shell.xml \
$(NULL)
wayland/protocol/xdg-shell.xml
libmutter_la_SOURCES = \
backends/meta-backend.c \
@ -167,6 +162,8 @@ libmutter_la_SOURCES = \
meta/errors.h \
core/frame.c \
core/frame.h \
ui/gradient.c \
meta/gradient.h \
core/meta-gesture-tracker.c \
core/meta-gesture-tracker-private.h \
core/keybindings.c \
@ -225,8 +222,7 @@ libmutter_la_SOURCES = \
x11/window-x11-private.h \
x11/xprops.c \
x11/xprops.h \
x11/mutter-Xatomtype.h \
$(NULL)
x11/mutter-Xatomtype.h
if HAVE_WAYLAND
libmutter_la_SOURCES += \
@ -259,8 +255,7 @@ libmutter_la_SOURCES += \
wayland/meta-wayland-outputs.c \
wayland/meta-wayland-outputs.h \
wayland/window-wayland.c \
wayland/window-wayland.h \
$(NULL)
wayland/window-wayland.h
endif
if HAVE_NATIVE_BACKEND
@ -276,11 +271,11 @@ libmutter_la_SOURCES += \
backends/native/meta-launcher.c \
backends/native/meta-launcher.h \
backends/native/dbus-utils.c \
backends/native/dbus-utils.h \
$(NULL)
backends/native/dbus-utils.h
endif
nodist_libmutter_la_SOURCES = $(mutter_built_sources)
nodist_libmutter_la_SOURCES = \
$(mutter_built_sources)
libmutter_la_LDFLAGS = -no-undefined
libmutter_la_LIBADD = $(MUTTER_LIBS) $(MUTTER_NATIVE_BACKEND_LIBS)
@ -295,6 +290,7 @@ libmutterinclude_headers = \
meta/compositor.h \
meta/display.h \
meta/errors.h \
meta/gradient.h \
meta/group.h \
meta/keybindings.h \
meta/main.h \
@ -315,8 +311,7 @@ libmutterinclude_headers = \
meta/types.h \
meta/util.h \
meta/window.h \
meta/workspace.h \
$(NULL)
meta/workspace.h
libmutterinclude_built_headers = \
meta/meta-version.h
@ -397,15 +392,14 @@ DISTCLEANFILES = \
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libmutter.pc
EXTRA_DIST += \
$(wayland_protocols) \
libmutter.pc.in \
mutter-enum-types.h.in \
mutter-enum-types.c.in \
org.freedesktop.login1.xml \
EXTRA_DIST += \
$(wayland_protocols) \
libmutter.pc.in \
mutter-enum-types.h.in \
mutter-enum-types.c.in \
org.freedesktop.login1.xml \
org.gnome.Mutter.DisplayConfig.xml \
org.gnome.Mutter.IdleMonitor.xml \
$(NULL)
org.gnome.Mutter.IdleMonitor.xml
BUILT_SOURCES = \
$(mutter_built_sources) \

View File

@ -27,9 +27,7 @@
* pointer abstraction"
*/
#include "config.h"
#include "meta-cursor-tracker-private.h"
#include <config.h>
#include <string.h>
#include <meta/main.h>
#include <meta/util.h>
@ -40,10 +38,11 @@
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <X11/extensions/Xfixes.h>
#include "meta-backend-private.h"
#include "meta-cursor-private.h"
#include "meta-cursor-tracker-private.h"
G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);

View File

@ -34,7 +34,6 @@
#include "config.h"
#include "boxes-private.h"
#include "meta-monitor-config.h"
#include <string.h>
@ -68,7 +67,6 @@ typedef struct {
} MetaOutputConfig;
typedef struct {
guint refcount;
MetaOutputKey *keys;
MetaOutputConfig *outputs;
unsigned int n_outputs;
@ -79,6 +77,7 @@ struct _MetaMonitorConfig {
GHashTable *configs;
MetaConfiguration *current;
gboolean current_is_stored;
gboolean current_is_for_laptop_lid;
MetaConfiguration *previous;
@ -125,29 +124,11 @@ config_clear (MetaConfiguration *config)
g_free (config->outputs);
}
static MetaConfiguration *
config_ref (MetaConfiguration *config)
{
config->refcount++;
return config;
}
static void
config_unref (MetaConfiguration *config)
config_free (gpointer config)
{
if (--config->refcount == 0)
{
config_clear (config);
g_slice_free (MetaConfiguration, config);
}
}
static MetaConfiguration *
config_new (void)
{
MetaConfiguration *config = g_slice_new0 (MetaConfiguration);
config->refcount = 1;
return config;
config_clear (config);
g_slice_free (MetaConfiguration, config);
}
static unsigned long
@ -239,7 +220,7 @@ meta_monitor_config_init (MetaMonitorConfig *self)
const char *filename;
char *path;
self->configs = g_hash_table_new_full (config_hash, config_equal, NULL, (GDestroyNotify) config_unref);
self->configs = g_hash_table_new_full (config_hash, config_equal, NULL, config_free);
filename = g_getenv ("MUTTER_MONITOR_FILENAME");
if (filename == NULL)
@ -849,45 +830,73 @@ meta_monitor_config_get_stored (MetaMonitorConfig *self,
return stored;
}
static void
set_current (MetaMonitorConfig *self,
MetaConfiguration *config)
{
g_clear_pointer (&self->previous, (GDestroyNotify) config_unref);
self->previous = self->current;
self->current = config_ref (config);
}
static gboolean
apply_configuration (MetaMonitorConfig *self,
MetaConfiguration *config,
MetaMonitorManager *manager)
MetaMonitorManager *manager,
gboolean stored)
{
GPtrArray *crtcs, *outputs;
gboolean ret = FALSE;
crtcs = g_ptr_array_new_full (config->n_outputs, (GDestroyNotify)meta_crtc_info_free);
outputs = g_ptr_array_new_full (config->n_outputs, (GDestroyNotify)meta_output_info_free);
if (!meta_monitor_config_assign_crtcs (config, manager, crtcs, outputs))
goto out;
{
g_ptr_array_unref (crtcs);
g_ptr_array_unref (outputs);
if (!stored)
config_free (config);
return FALSE;
}
meta_monitor_manager_apply_configuration (manager,
(MetaCRTCInfo**)crtcs->pdata, crtcs->len,
(MetaOutputInfo**)outputs->pdata, outputs->len);
set_current (self, config);
/* Stored (persistent) configurations override the previous one always.
Also, we clear the previous configuration if the current one (which is
about to become previous) is stored, or if the current one has
different outputs.
*/
if (stored ||
(self->current && self->current_is_stored))
{
if (self->previous)
config_free (self->previous);
self->previous = NULL;
}
else
{
/* Despite the name, config_equal() only checks the set of outputs,
not their modes
*/
if (self->current && config_equal (self->current, config))
{
self->previous = self->current;
}
else
{
if (self->current)
config_free (self->current);
self->previous = NULL;
}
}
self->current = config;
self->current_is_stored = stored;
/* If true, we'll be overridden at the end of this call
* inside turn_off_laptop_display / apply_configuration_with_lid */
inside turn_off_laptop_display()
*/
self->current_is_for_laptop_lid = FALSE;
ret = TRUE;
if (self->current == self->previous)
self->previous = NULL;
out:
g_ptr_array_unref (crtcs);
g_ptr_array_unref (outputs);
return ret;
return TRUE;
}
static gboolean
@ -939,7 +948,7 @@ make_laptop_lid_config (MetaConfiguration *reference)
g_assert (multiple_outputs_are_enabled (reference));
new = config_new ();
new = g_slice_new0 (MetaConfiguration);
new->n_outputs = reference->n_outputs;
new->keys = g_new0 (MetaOutputKey, reference->n_outputs);
new->outputs = g_new0 (MetaOutputConfig, reference->n_outputs);
@ -994,32 +1003,6 @@ make_laptop_lid_config (MetaConfiguration *reference)
return new;
}
static gboolean
apply_configuration_with_lid (MetaMonitorConfig *self,
MetaConfiguration *config,
MetaMonitorManager *manager)
{
if (self->lid_is_closed &&
multiple_outputs_are_enabled (config) &&
laptop_display_is_on (config))
{
MetaConfiguration *laptop_lid_config = make_laptop_lid_config (config);
if (apply_configuration (self, laptop_lid_config, manager))
{
self->current_is_for_laptop_lid = TRUE;
config_unref (laptop_lid_config);
return TRUE;
}
else
{
config_unref (laptop_lid_config);
return FALSE;
}
}
else
return apply_configuration (self, config, manager);
}
gboolean
meta_monitor_config_apply_stored (MetaMonitorConfig *self,
MetaMonitorManager *manager)
@ -1032,7 +1015,23 @@ meta_monitor_config_apply_stored (MetaMonitorConfig *self,
stored = meta_monitor_config_get_stored (self, outputs, n_outputs);
if (stored)
return apply_configuration_with_lid (self, stored, manager);
{
if (self->lid_is_closed &&
multiple_outputs_are_enabled (stored) &&
laptop_display_is_on (stored))
{
if (apply_configuration (self, make_laptop_lid_config (stored),
manager, FALSE))
{
self->current_is_for_laptop_lid = TRUE;
return TRUE;
}
else
return FALSE;
}
else
return apply_configuration (self, stored, manager, TRUE);
}
else
return FALSE;
}
@ -1082,123 +1081,47 @@ find_primary_output (MetaOutput *outputs,
return best;
}
static void
init_config_from_preferred_mode (MetaOutputConfig *config,
MetaOutput *output)
static MetaConfiguration *
make_default_config (MetaMonitorConfig *self,
MetaOutput *outputs,
unsigned n_outputs,
int max_width,
int max_height)
{
config->enabled = TRUE;
config->rect.x = 0;
config->rect.y = 0;
config->rect.width = output->preferred_mode->width;
config->rect.height = output->preferred_mode->height;
config->refresh_rate = output->preferred_mode->refresh_rate;
config->transform = META_MONITOR_TRANSFORM_NORMAL;
config->is_primary = FALSE;
config->is_presentation = FALSE;
}
/* This function handles configuring the outputs when the driver provides a
* suggested layout position for each output. This is done in recent versions
* of qxl and allows displays to be aligned on the guest in the same order as
* they are aligned on the client.
*/
static gboolean
make_suggested_config (MetaMonitorConfig *self,
MetaOutput *outputs,
unsigned n_outputs,
int max_width,
int max_height,
MetaConfiguration *config)
{
unsigned int i;
MetaOutput *primary;
GList *region = NULL;
g_return_val_if_fail (config != NULL, FALSE);
primary = find_primary_output (outputs, n_outputs);
for (i = 0; i < n_outputs; i++)
{
gboolean is_primary = (&outputs[i] == primary);
if (outputs[i].suggested_x < 0 || outputs[i].suggested_y < 0)
return FALSE;
init_config_from_preferred_mode (&config->outputs[i], &outputs[i]);
config->outputs[i].is_primary = is_primary;
config->outputs[i].rect.x = outputs[i].suggested_x;
config->outputs[i].rect.y = outputs[i].suggested_y;
/* Reject the configuration if the suggested positions result in
* overlapping displays */
if (meta_rectangle_overlaps_with_region (region, &config->outputs[i].rect))
{
g_warning ("Overlapping outputs, rejecting suggested configuration");
g_list_free (region);
return FALSE;
}
region = g_list_prepend (region, &config->outputs[i].rect);
}
g_list_free (region);
return TRUE;
}
static void
make_linear_config (MetaMonitorConfig *self,
MetaOutput *outputs,
unsigned n_outputs,
int max_width,
int max_height,
MetaConfiguration *config)
{
MetaOutput *primary;
unsigned i;
int x;
g_return_if_fail (config != NULL);
primary = find_primary_output (outputs, n_outputs);
x = primary->preferred_mode->width;
for (i = 0; i < n_outputs; i++)
{
gboolean is_primary = (&outputs[i] == primary);
init_config_from_preferred_mode (&config->outputs[i], &outputs[i]);
config->outputs[i].is_primary = is_primary;
if (is_primary)
{
config->outputs[i].rect.x = 0;
}
else
{
config->outputs[i].rect.x = x;
x += config->outputs[i].rect.width;
}
}
}
/* Search for a configuration that includes one less screen, then add the new
* one as a presentation screen in preferred mode.
*
* XXX: but presentation mode is not implemented in the control-center or in
* mutter core, so let's do extended for now.
*/
static gboolean
extend_stored_config (MetaMonitorConfig *self,
MetaOutput *outputs,
unsigned n_outputs,
int max_width,
int max_height,
MetaConfiguration *config)
{
int x, y;
unsigned i, j;
int x, y;
MetaConfiguration *ret;
MetaOutput *primary;
ret = g_slice_new (MetaConfiguration);
make_config_key (ret, outputs, n_outputs, -1);
ret->outputs = g_new0 (MetaOutputConfig, n_outputs);
/* Special case the simple case: one output, primary at preferred mode,
nothing else to do */
if (n_outputs == 1)
{
ret->outputs[0].enabled = TRUE;
ret->outputs[0].rect.x = 0;
ret->outputs[0].rect.y = 0;
ret->outputs[0].rect.width = outputs[0].preferred_mode->width;
ret->outputs[0].rect.height = outputs[0].preferred_mode->height;
ret->outputs[0].refresh_rate = outputs[0].preferred_mode->refresh_rate;
ret->outputs[0].transform = META_MONITOR_TRANSFORM_NORMAL;
ret->outputs[0].is_primary = TRUE;
return ret;
}
/* If we reach this point, this is either the first time mutter runs
on this system ever, or we just hotplugged a new screen.
In the latter case, search for a configuration that includes one
less screen, then add the new one as a presentation screen
in preferred mode.
XXX: but presentation mode is not implemented in the control-center
or in mutter core, so let's do extended for now.
*/
x = 0;
y = 0;
for (i = 0; i < n_outputs; i++)
@ -1216,80 +1139,69 @@ extend_stored_config (MetaMonitorConfig *self,
{
if (j < i)
{
g_assert (output_key_equal (&config->keys[j], &ref->keys[j]));
config->outputs[j] = ref->outputs[j];
g_assert (output_key_equal (&ret->keys[j], &ref->keys[j]));
ret->outputs[j] = ref->outputs[j];
x = MAX (x, ref->outputs[j].rect.x + ref->outputs[j].rect.width);
y = MAX (y, ref->outputs[j].rect.y + ref->outputs[j].rect.height);
}
else if (j > i)
{
g_assert (output_key_equal (&config->keys[j], &ref->keys[j - 1]));
config->outputs[j] = ref->outputs[j - 1];
g_assert (output_key_equal (&ret->keys[j], &ref->keys[j - 1]));
ret->outputs[j] = ref->outputs[j - 1];
x = MAX (x, ref->outputs[j - 1].rect.x + ref->outputs[j - 1].rect.width);
y = MAX (y, ref->outputs[j - 1].rect.y + ref->outputs[j - 1].rect.height);
}
else
{
init_config_from_preferred_mode (&config->outputs[j], &outputs[0]);
ret->outputs[j].enabled = TRUE;
ret->outputs[j].rect.x = 0;
ret->outputs[j].rect.y = 0;
ret->outputs[j].rect.width = outputs[0].preferred_mode->width;
ret->outputs[j].rect.height = outputs[0].preferred_mode->height;
ret->outputs[j].refresh_rate = outputs[0].preferred_mode->refresh_rate;
ret->outputs[j].transform = META_MONITOR_TRANSFORM_NORMAL;
ret->outputs[j].is_primary = FALSE;
ret->outputs[j].is_presentation = FALSE;
}
}
/* Place the new output at the right end of the screen, if it fits,
otherwise below it, otherwise disable it (or apply_configuration will fail) */
if (x + config->outputs[i].rect.width <= max_width)
config->outputs[i].rect.x = x;
else if (y + config->outputs[i].rect.height <= max_height)
config->outputs[i].rect.y = y;
if (x + ret->outputs[i].rect.width <= max_width)
ret->outputs[i].rect.x = x;
else if (y + ret->outputs[i].rect.height <= max_height)
ret->outputs[i].rect.y = y;
else
config->outputs[i].enabled = FALSE;
ret->outputs[i].enabled = FALSE;
return TRUE;
return ret;
}
}
return FALSE;
}
/* No previous configuration found, try with a really default one, which
is one primary that goes first and the rest to the right of it, extended.
*/
primary = find_primary_output (outputs, n_outputs);
static MetaConfiguration *
make_default_config (MetaMonitorConfig *self,
MetaOutput *outputs,
unsigned n_outputs,
int max_width,
int max_height,
gboolean use_stored_config)
{
MetaConfiguration *ret = NULL;
unsigned i;
ret = config_new ();
make_config_key (ret, outputs, n_outputs, -1);
ret->outputs = g_new0 (MetaOutputConfig, n_outputs);
/* Special case the simple case: one output, primary at preferred mode,
nothing else to do */
if (n_outputs == 1)
{
init_config_from_preferred_mode (&ret->outputs[0], &outputs[0]);
ret->outputs[0].is_primary = TRUE;
goto check_limits;
}
if (make_suggested_config (self, outputs, n_outputs, max_width, max_height, ret))
goto check_limits;
if (use_stored_config &&
extend_stored_config (self, outputs, n_outputs, max_width, max_height, ret))
goto check_limits;
make_linear_config (self, outputs, n_outputs, max_width, max_height, ret);
check_limits:
/* Disable outputs that would go beyond framebuffer limits */
x = primary->preferred_mode->width;
for (i = 0; i < n_outputs; i++)
{
if ((ret->outputs[i].rect.x + ret->outputs[i].rect.width > max_width)
|| (ret->outputs[i].rect.y + ret->outputs[i].rect.height > max_height))
ret->outputs[i].enabled = FALSE;
MetaOutput *output = &outputs[i];
ret->outputs[i].enabled = TRUE;
ret->outputs[i].rect.x = (output == primary) ? 0 : x;
ret->outputs[i].rect.y = 0;
ret->outputs[i].rect.width = output->preferred_mode->width;
ret->outputs[i].rect.height = output->preferred_mode->height;
ret->outputs[i].refresh_rate = output->preferred_mode->refresh_rate;
ret->outputs[i].transform = META_MONITOR_TRANSFORM_NORMAL;
ret->outputs[i].is_primary = (output == primary);
/* Disable outputs that would go beyond framebuffer limits */
if (ret->outputs[i].rect.x + ret->outputs[i].rect.width > max_width)
ret->outputs[i].enabled = FALSE;
else if (output != primary)
x += output->preferred_mode->width;
}
return ret;
@ -1301,7 +1213,7 @@ ensure_at_least_one_output (MetaMonitorConfig *self,
MetaOutput *outputs,
unsigned n_outputs)
{
MetaConfiguration *config;
MetaConfiguration *ret;
MetaOutput *primary;
unsigned i;
@ -1312,29 +1224,34 @@ ensure_at_least_one_output (MetaMonitorConfig *self,
/* Oh no, we don't! Activate the primary one and disable everything else */
config = config_new ();
make_config_key (config, outputs, n_outputs, -1);
config->outputs = g_new0 (MetaOutputConfig, n_outputs);
ret = g_slice_new (MetaConfiguration);
make_config_key (ret, outputs, n_outputs, -1);
ret->outputs = g_new0 (MetaOutputConfig, n_outputs);
primary = find_primary_output (outputs, n_outputs);
for (i = 0; i < n_outputs; i++)
{
gboolean is_primary = (&outputs[i] == primary);
MetaOutput *output = &outputs[i];
if (is_primary)
if (output == primary)
{
init_config_from_preferred_mode (&config->outputs[i], &outputs[0]);
config->outputs[i].is_primary = TRUE;
ret->outputs[i].enabled = TRUE;
ret->outputs[i].rect.x = 0;
ret->outputs[i].rect.y = 0;
ret->outputs[i].rect.width = output->preferred_mode->width;
ret->outputs[i].rect.height = output->preferred_mode->height;
ret->outputs[i].refresh_rate = output->preferred_mode->refresh_rate;
ret->outputs[i].transform = META_MONITOR_TRANSFORM_NORMAL;
ret->outputs[i].is_primary = TRUE;
}
else
{
config->outputs[i].enabled = FALSE;
ret->outputs[i].enabled = FALSE;
}
}
apply_configuration (self, config, manager);
config_unref (config);
apply_configuration (self, ret, manager, FALSE);
return FALSE;
}
@ -1345,9 +1262,8 @@ meta_monitor_config_make_default (MetaMonitorConfig *self,
MetaOutput *outputs;
MetaConfiguration *default_config;
unsigned n_outputs;
gboolean ok = FALSE;
gboolean ok;
int max_width, max_height;
gboolean use_stored_config;
outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
meta_monitor_manager_get_screen_limits (manager, &max_width, &max_height);
@ -1358,21 +1274,23 @@ meta_monitor_config_make_default (MetaMonitorConfig *self,
return;
}
/* if the device has hotplug_mode_update, it's possible that the
* current display configuration does not match a stored configuration.
* Since extend_existing_config() tries to build a configuration that is
* based on a previously-stored configuration, it's quite likely that the
* resulting config will fail. Even if it doesn't fail, it may result in
* an unexpected configuration, so don't attempt to use a stored config
* in this situation. */
use_stored_config = !meta_monitor_manager_has_hotplug_mode_update (manager);
default_config = make_default_config (self, outputs, n_outputs, max_width, max_height, use_stored_config);
default_config = make_default_config (self, outputs, n_outputs, max_width, max_height);
if (default_config != NULL)
{
ok = apply_configuration_with_lid (self, default_config, manager);
config_unref (default_config);
if (self->lid_is_closed &&
multiple_outputs_are_enabled (default_config) &&
laptop_display_is_on (default_config))
{
ok = apply_configuration (self, make_laptop_lid_config (default_config),
manager, FALSE);
config_free (default_config);
}
else
ok = apply_configuration (self, default_config, manager, FALSE);
}
else
ok = FALSE;
if (!ok)
{
@ -1409,7 +1327,7 @@ meta_monitor_config_update_current (MetaMonitorConfig *self,
outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
current = config_new ();
current = g_slice_new (MetaConfiguration);
current->n_outputs = n_outputs;
current->outputs = g_new0 (MetaOutputConfig, n_outputs);
current->keys = g_new0 (MetaOutputKey, n_outputs);
@ -1422,11 +1340,15 @@ meta_monitor_config_update_current (MetaMonitorConfig *self,
if (self->current && config_equal_full (current, self->current))
{
config_unref (current);
config_free (current);
return;
}
set_current (self, current);
if (self->current && !self->current_is_stored)
config_free (self->current);
self->current = current;
self->current_is_stored = FALSE;
}
void
@ -1434,17 +1356,7 @@ meta_monitor_config_restore_previous (MetaMonitorConfig *self,
MetaMonitorManager *manager)
{
if (self->previous)
{
/* The user chose to restore the previous configuration. In this
* case, restore the previous configuration. */
MetaConfiguration *prev_config = config_ref (self->previous);
apply_configuration (self, prev_config, manager);
config_unref (prev_config);
/* After this, self->previous contains the rejected configuration.
* Since it was rejected, nuke it. */
g_clear_pointer (&self->previous, (GDestroyNotify) config_unref);
}
apply_configuration (self, self->previous, manager, FALSE);
else
{
if (!meta_monitor_config_apply_stored (self, manager))
@ -1462,8 +1374,7 @@ turn_off_laptop_display (MetaMonitorConfig *self,
return;
new = make_laptop_lid_config (self->current);
apply_configuration (self, new, manager);
config_unref (new);
apply_configuration (self, new, manager, FALSE);
self->current_is_for_laptop_lid = TRUE;
}
@ -1622,7 +1533,16 @@ meta_monitor_config_save (MetaMonitorConfig *self)
void
meta_monitor_config_make_persistent (MetaMonitorConfig *self)
{
g_hash_table_replace (self->configs, self->current, config_ref (self->current));
if (self->current_is_stored)
return;
self->current_is_stored = TRUE;
g_hash_table_replace (self->configs, self->current, self->current);
if (self->previous)
config_free (self->previous);
self->previous = NULL;
meta_monitor_config_save (self);
}

View File

@ -58,6 +58,14 @@ meta_monitor_manager_init (MetaMonitorManager *manager)
{
}
static void
read_current_config (MetaMonitorManager *manager)
{
manager->serial++;
META_MONITOR_MANAGER_GET_CLASS (manager)->read_current (manager);
}
/*
* make_logical_config:
*
@ -190,7 +198,7 @@ meta_monitor_manager_constructed (GObject *object)
manager->config = meta_monitor_config_new ();
meta_monitor_manager_read_current_config (manager);
read_current_config (manager);
if (!meta_monitor_config_apply_stored (manager->config, manager))
meta_monitor_config_make_default (manager->config, manager);
@ -203,7 +211,24 @@ meta_monitor_manager_constructed (GObject *object)
so this is not needed.
*/
if (META_IS_MONITOR_MANAGER_XRANDR (manager))
meta_monitor_manager_read_current_config (manager);
{
MetaOutput *old_outputs;
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
unsigned int n_old_outputs, n_old_modes;
old_outputs = manager->outputs;
n_old_outputs = manager->n_outputs;
old_modes = manager->modes;
n_old_modes = manager->n_modes;
old_crtcs = manager->crtcs;
read_current_config (manager);
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
g_free (old_crtcs);
}
make_logical_config (manager);
initialize_dbus_interface (manager);
@ -211,7 +236,7 @@ meta_monitor_manager_constructed (GObject *object)
manager->in_init = FALSE;
}
static void
void
meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
int n_old_outputs)
{
@ -234,7 +259,7 @@ meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
g_free (old_outputs);
}
static void
void
meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
int n_old_modes)
{
@ -1137,31 +1162,6 @@ meta_monitor_manager_get_screen_limits (MetaMonitorManager *manager,
*height = manager->max_screen_height;
}
void
meta_monitor_manager_read_current_config (MetaMonitorManager *manager)
{
MetaOutput *old_outputs;
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
unsigned int n_old_outputs, n_old_modes;
/* Some implementations of read_current use the existing information
* we have available, so don't free the old configuration until after
* read_current finishes. */
old_outputs = manager->outputs;
n_old_outputs = manager->n_outputs;
old_modes = manager->modes;
n_old_modes = manager->n_modes;
old_crtcs = manager->crtcs;
manager->serial++;
META_MONITOR_MANAGER_GET_CLASS (manager)->read_current (manager);
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
g_free (old_crtcs);
}
void
meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager)
{
@ -1179,22 +1179,3 @@ meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager)
g_free (old_monitor_infos);
}
void
meta_monitor_manager_on_hotplug (MetaMonitorManager *manager)
{
gboolean applied_config = FALSE;
/* If the monitor has hotplug_mode_update (which is used by VMs), don't bother
* applying our stored configuration, because it's likely the user just resizing
* the window.
*/
if (!meta_monitor_manager_has_hotplug_mode_update (manager))
{
if (meta_monitor_config_apply_stored (manager->config, manager))
applied_config = TRUE;
}
/* If we haven't applied any configuration, apply the default configuration. */
if (!applied_config)
meta_monitor_config_make_default (manager->config, manager);
}

View File

@ -116,8 +116,6 @@ struct _MetaOutput
/* get a new preferred mode on hotplug events, to handle dynamic guest resizing */
gboolean hotplug_mode_update;
gint suggested_x;
gint suggested_y;
};
struct _MetaCRTC
@ -341,9 +339,11 @@ void meta_monitor_manager_confirm_configuration (MetaMonitorManag
void meta_crtc_info_free (MetaCRTCInfo *info);
void meta_output_info_free (MetaOutputInfo *info);
void meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
int n_old_outputs);
void meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
int n_old_modes);
gboolean meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager);
void meta_monitor_manager_read_current_config (MetaMonitorManager *manager);
void meta_monitor_manager_on_hotplug (MetaMonitorManager *manager);
/* Returns true if transform causes width and height to be inverted
This is true for the odd transforms in the enum */

View File

@ -130,8 +130,8 @@ take_device (Login1Session *session_proxy,
{
gboolean ret = FALSE;
GVariant *fd_variant = NULL;
GUnixFDList *fd_list = NULL;
int fd = -1;
GUnixFDList *fd_list;
if (!login1_session_call_take_device_sync (session_proxy,
dev_major,

View File

@ -24,7 +24,6 @@
#include "config.h"
#include "meta-monitor-manager-kms.h"
#include "meta-monitor-config.h"
#include <string.h>
#include <stdlib.h>
@ -41,8 +40,6 @@
#include <meta/errors.h>
#include "edid.h"
#include <gudev/gudev.h>
typedef struct {
drmModeConnector *connector;
@ -71,8 +68,6 @@ struct _MetaMonitorManagerKms
unsigned int n_encoders;
drmModeEncoder *current_encoder;
GUdevClient *udev;
};
struct _MetaMonitorManagerKmsClass
@ -415,8 +410,6 @@ meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
meta_output->name = make_output_name (connector);
meta_output->width_mm = connector->mmWidth;
meta_output->height_mm = connector->mmHeight;
meta_output->suggested_x = -1;
meta_output->suggested_y = -1;
switch (connector->subpixel)
{
@ -900,23 +893,6 @@ meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager,
drmModeCrtcSetGamma (manager_kms->fd, crtc->crtc_id, size, red, green, blue);
}
static void
on_uevent (GUdevClient *client,
const char *action,
GUdevDevice *device,
gpointer user_data)
{
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (user_data);
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
if (!g_udev_device_get_property_as_boolean (device, "HOTPLUG"))
return;
meta_monitor_manager_read_current_config (manager);
meta_monitor_manager_on_hotplug (manager);
}
static void
meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
{
@ -931,21 +907,6 @@ meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
cogl_renderer = cogl_display_get_renderer (cogl_display);
manager_kms->fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
const char *subsystems[2] = { "drm", NULL };
manager_kms->udev = g_udev_client_new (subsystems);
g_signal_connect (manager_kms->udev, "uevent",
G_CALLBACK (on_uevent), manager_kms);
}
static void
meta_monitor_manager_kms_dispose (GObject *object)
{
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object);
g_clear_object (&manager_kms->udev);
G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->dispose (object);
}
static void
@ -964,7 +925,6 @@ meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass)
MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = meta_monitor_manager_kms_dispose;
object_class->finalize = meta_monitor_manager_kms_finalize;
manager_class->read_current = meta_monitor_manager_kms_read_current;

View File

@ -26,8 +26,6 @@
#include "meta-cursor-renderer-x11.h"
#include <X11/extensions/Xfixes.h>
#include "meta-backend-x11.h"
#include "meta-stage.h"

View File

@ -57,6 +57,7 @@ struct _MetaMonitorManagerXrandr
Display *xdisplay;
XRRScreenResources *resources;
int time;
int rr_event_base;
int rr_error_base;
};
@ -139,34 +140,6 @@ meta_monitor_transform_from_xrandr_all (Rotation rotation)
return ret;
}
static gboolean
output_get_integer_property (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output, const char *propname,
gint *value)
{
gboolean exists = FALSE;
Atom atom, actual_type;
int actual_format;
unsigned long nitems, bytes_after;
unsigned char *buffer;
atom = XInternAtom (manager_xrandr->xdisplay, propname, False);
XRRGetOutputProperty (manager_xrandr->xdisplay,
(XID)output->winsys_id,
atom,
0, G_MAXLONG, False, False, XA_INTEGER,
&actual_type, &actual_format,
&nitems, &bytes_after, &buffer);
exists = (actual_type == XA_INTEGER && actual_format == 32 && nitems == 1);
if (exists && value != NULL)
*value = ((int*)buffer)[0];
XFree (buffer);
return exists;
}
static gboolean
output_get_property_exists (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output, const char *propname)
@ -384,28 +357,6 @@ output_get_hotplug_mode_update (MetaMonitorManagerXrandr *manager_xrandr,
return output_get_property_exists (manager_xrandr, output, "hotplug_mode_update");
}
static gint
output_get_suggested_x (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output)
{
gint val;
if (output_get_integer_property (manager_xrandr, output, "suggested X", &val))
return val;
return -1;
}
static gint
output_get_suggested_y (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output)
{
gint val;
if (output_get_integer_property (manager_xrandr, output, "suggested Y", &val))
return val;
return -1;
}
static char *
get_xmode_name (XRRModeInfo *xmode)
{
@ -486,6 +437,7 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
return;
manager_xrandr->resources = resources;
manager_xrandr->time = resources->configTimestamp;
manager->n_outputs = resources->noutput;
manager->n_crtcs = resources->ncrtc;
manager->n_modes = resources->nmode;
@ -593,8 +545,6 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
meta_output->height_mm = output->mm_height;
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
meta_output->hotplug_mode_update = output_get_hotplug_mode_update (manager_xrandr, meta_output);
meta_output->suggested_x = output_get_suggested_x (manager_xrandr, meta_output);
meta_output->suggested_y = output_get_suggested_y (manager_xrandr, meta_output);
meta_output->n_modes = output->nmode;
meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes);
@ -821,7 +771,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
XRRSetCrtcConfig (manager_xrandr->xdisplay,
manager_xrandr->resources,
(XID)crtc->crtc_id,
CurrentTime,
manager_xrandr->time,
0, 0,
None,
RR_Rotate_0,
@ -851,7 +801,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
XRRSetCrtcConfig (manager_xrandr->xdisplay,
manager_xrandr->resources,
(XID)crtc->crtc_id,
CurrentTime,
manager_xrandr->time,
0, 0,
None,
RR_Rotate_0,
@ -888,26 +838,12 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
unsigned int j, n_outputs;
int width, height;
Status ok;
unsigned long old_controlled_mask;
unsigned long new_controlled_mask;
mode = crtc_info->mode;
n_outputs = crtc_info->outputs->len;
outputs = g_new (XID, n_outputs);
old_controlled_mask = 0;
for (j = 0; j < manager->n_outputs; j++)
{
MetaOutput *output;
output = &manager->outputs[j];
if (output->crtc == crtc)
old_controlled_mask |= 1UL << j;
}
new_controlled_mask = 0;
for (j = 0; j < n_outputs; j++)
{
MetaOutput *output;
@ -916,25 +852,14 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
output->is_dirty = TRUE;
output->crtc = crtc;
new_controlled_mask |= 1UL << j;
outputs[j] = output->winsys_id;
}
if (crtc->current_mode == mode &&
crtc->rect.x == crtc_info->x &&
crtc->rect.y == crtc_info->y &&
crtc->transform == crtc_info->transform &&
old_controlled_mask == new_controlled_mask)
{
/* No change */
goto next;
}
ok = XRRSetCrtcConfig (manager_xrandr->xdisplay,
manager_xrandr->resources,
(XID)crtc->crtc_id,
CurrentTime,
manager_xrandr->time,
crtc_info->x, crtc_info->y,
(XID)mode->mode_id,
meta_monitor_transform_to_xrandr (crtc_info->transform),
@ -1075,6 +1000,16 @@ meta_monitor_manager_xrandr_set_crtc_gamma (MetaMonitorManager *manager,
XRRFreeGamma (gamma);
}
static void
meta_monitor_manager_xrandr_rebuild_derived (MetaMonitorManager *manager)
{
/* This will be a no-op if the change was from our side, as
we already called it in the DBus method handler */
meta_monitor_config_update_current (manager->config, manager);
meta_monitor_manager_rebuild_derived (manager);
}
static void
meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr)
{
@ -1134,30 +1069,57 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
XEvent *event)
{
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
gboolean hotplug;
Time old_timestamp;
MetaOutput *old_outputs;
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
unsigned int n_old_outputs, n_old_modes;
gboolean new_config;
gboolean applied_config = FALSE;
if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
return FALSE;
XRRUpdateConfiguration (event);
old_timestamp = manager_xrandr->resources->timestamp;
/* Save the old structures, so they stay valid during the update */
old_outputs = manager->outputs;
n_old_outputs = manager->n_outputs;
old_modes = manager->modes;
n_old_modes = manager->n_modes;
old_crtcs = manager->crtcs;
meta_monitor_manager_read_current_config (manager);
manager->serial++;
meta_monitor_manager_xrandr_read_current (manager);
hotplug = manager_xrandr->resources->timestamp < manager_xrandr->resources->configTimestamp;
if (hotplug)
new_config = manager_xrandr->resources->timestamp >= manager_xrandr->resources->configTimestamp;
/* If this is the X server telling us we set a new configuration,
* we can simply short-cut to rebuilding our logical configuration.
*/
if (new_config)
{
/* This is a hotplug event, so go ahead and build a new configuration. */
meta_monitor_manager_on_hotplug (manager);
meta_monitor_manager_xrandr_rebuild_derived (manager);
goto out;
}
else
/* If the monitor has hotplug_mode_update (which is used by VMs), don't bother
* applying our stored configuration, because it's likely the user just resizing
* the window.
*/
if (!meta_monitor_manager_has_hotplug_mode_update (manager))
{
/* If something else changed -- tell the world about it. */
if (old_timestamp < manager_xrandr->resources->timestamp)
meta_monitor_manager_rebuild_derived (manager);
if (meta_monitor_config_apply_stored (manager->config, manager))
applied_config = TRUE;
}
/* If we haven't applied any configuration, apply the default configuration. */
if (!applied_config)
meta_monitor_config_make_default (manager->config, manager);
out:
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
g_free (old_crtcs);
return TRUE;
}

View File

@ -614,6 +614,7 @@ set_unredirected_window (MetaCompositor *compositor,
meta_window_actor_set_unredirected (window_actor, FALSE);
}
meta_shape_cow_for_window (compositor, window);
compositor->unredirected_window = window;
if (compositor->unredirected_window != NULL)
@ -621,8 +622,6 @@ set_unredirected_window (MetaCompositor *compositor,
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (compositor->unredirected_window));
meta_window_actor_set_unredirected (window_actor, TRUE);
}
meta_shape_cow_for_window (compositor, compositor->unredirected_window);
}
void

View File

@ -115,7 +115,7 @@ typedef enum {
#define FRAGMENT_SHADER_CODE \
"float t = 2.0 * length(position);\n" \
"t = min(t, 1.0);\n" \
"float pixel_brightness = 1 - t * vignette_sharpness;\n" \
"float pixel_brightness = 1.0 - t * vignette_sharpness;\n" \
"cogl_color_out.rgb = cogl_color_out.rgb * pixel_brightness;\n" \
typedef struct _MetaBackgroundLayer MetaBackgroundLayer;

View File

@ -53,7 +53,7 @@ struct _MetaBackgroundImageCacheClass
struct _MetaBackgroundImage
{
GObject parent_instance;
GFile *file;
char *filename;
MetaBackgroundImageCache *cache;
gboolean in_cache;
gboolean loaded;
@ -70,7 +70,7 @@ G_DEFINE_TYPE (MetaBackgroundImageCache, meta_background_image_cache, G_TYPE_OBJ
static void
meta_background_image_cache_init (MetaBackgroundImageCache *cache)
{
cache->images = g_hash_table_new (g_file_hash, (GEqualFunc) g_file_equal);
cache->images = g_hash_table_new (g_str_hash, g_str_equal);
}
static void
@ -124,17 +124,9 @@ load_file (GTask *task,
{
GError *error = NULL;
GdkPixbuf *pixbuf;
GFileInputStream *stream;
stream = g_file_read (image->file, NULL, &error);
if (stream == NULL)
{
g_task_return_error (task, error);
return;
}
pixbuf = gdk_pixbuf_new_from_stream (G_INPUT_STREAM (stream), NULL, &error);
g_object_unref (stream);
pixbuf = gdk_pixbuf_new_from_file (image->filename,
&error);
if (pixbuf == NULL)
{
@ -164,11 +156,9 @@ file_loaded (GObject *source_object,
if (pixbuf == NULL)
{
char *uri = g_file_get_uri (image->file);
g_warning ("Failed to load background '%s': %s",
uri, error->message);
image->filename, error->message);
g_clear_error (&error);
g_free (uri);
goto out;
}
@ -205,7 +195,7 @@ out:
/**
* meta_background_image_cache_load:
* @cache: a #MetaBackgroundImageCache
* @file: #GFile to load
* @filename: filename to load
*
* Loads an image to use as a background, or returns a reference to an
* image that is already in the process of loading or loaded. In either
@ -219,23 +209,23 @@ out:
*/
MetaBackgroundImage *
meta_background_image_cache_load (MetaBackgroundImageCache *cache,
GFile *file)
const char *filename)
{
MetaBackgroundImage *image;
GTask *task;
g_return_val_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache), NULL);
g_return_val_if_fail (file != NULL, NULL);
g_return_val_if_fail (filename != NULL, NULL);
image = g_hash_table_lookup (cache->images, file);
image = g_hash_table_lookup (cache->images, filename);
if (image != NULL)
return g_object_ref (image);
image = g_object_new (META_TYPE_BACKGROUND_IMAGE, NULL);
image->cache = cache;
image->in_cache = TRUE;
image->file = g_object_ref (file);
g_hash_table_insert (cache->images, image->file, image);
image->filename = g_strdup (filename);
g_hash_table_insert (cache->images, image->filename, image);
task = g_task_new (image, NULL, file_loaded, NULL);
@ -248,25 +238,25 @@ meta_background_image_cache_load (MetaBackgroundImageCache *cache,
/**
* meta_background_image_cache_purge:
* @cache: a #MetaBackgroundImageCache
* @file: file to remove from the cache
* @filename: filename to remove from the cache
*
* Remove an entry from the cache; this would be used if monitoring
* showed that the file changed.
*/
void
meta_background_image_cache_purge (MetaBackgroundImageCache *cache,
GFile *file)
const char *filename)
{
MetaBackgroundImage *image;
g_return_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache));
g_return_if_fail (file != NULL);
g_return_if_fail (filename != NULL);
image = g_hash_table_lookup (cache->images, file);
image = g_hash_table_lookup (cache->images, filename);
if (image == NULL)
return;
g_hash_table_remove (cache->images, image->file);
g_hash_table_remove (cache->images, image->filename);
image->in_cache = FALSE;
}
@ -283,12 +273,12 @@ meta_background_image_finalize (GObject *object)
MetaBackgroundImage *image = META_BACKGROUND_IMAGE (object);
if (image->in_cache)
g_hash_table_remove (image->cache->images, image->file);
g_hash_table_remove (image->cache->images, image->filename);
if (image->texture)
cogl_object_unref (image->texture);
if (image->file)
g_object_unref (image->file);
if (image->filename)
g_free (image->filename);
G_OBJECT_CLASS (meta_background_image_parent_class)->finalize (object);
}

View File

@ -50,9 +50,9 @@ struct _MetaBackgroundPrivate
ClutterColor color;
ClutterColor second_color;
GFile *file1;
char *filename1;
MetaBackgroundImage *background_image1;
GFile *file2;
char *filename2;
MetaBackgroundImage *background_image2;
CoglTexture *color_texture;
@ -71,6 +71,8 @@ enum
G_DEFINE_TYPE (MetaBackground, meta_background, G_TYPE_OBJECT)
static GSList *all_backgrounds = NULL;
static void
free_fbos (MetaBackground *self)
{
@ -241,28 +243,16 @@ on_background_loaded (MetaBackgroundImage *image,
mark_changed (self);
}
static gboolean
file_equal0 (GFile *file1,
GFile *file2)
{
if (file1 == file2)
return TRUE;
if ((file1 == NULL) || (file2 == NULL))
return FALSE;
return g_file_equal (file1, file2);
}
static void
set_file (MetaBackground *self,
GFile **filep,
MetaBackgroundImage **imagep,
GFile *file)
set_filename (MetaBackground *self,
char **filenamep,
MetaBackgroundImage **imagep,
const char *filename)
{
if (!file_equal0 (*filep, file))
if (g_strcmp0 (filename, *filenamep) != 0)
{
g_clear_object (filep);
g_free (*filenamep);
*filenamep = g_strdup (filename);
if (*imagep)
{
@ -273,12 +263,10 @@ set_file (MetaBackground *self,
*imagep = NULL;
}
if (file)
if (filename)
{
MetaBackgroundImageCache *cache = meta_background_image_cache_get_default ();
*filep = g_object_ref (file);
*imagep = meta_background_image_cache_load (cache, file);
*imagep = meta_background_image_cache_load (cache, filename);
g_signal_connect (*imagep, "loaded",
G_CALLBACK (on_background_loaded), self);
}
@ -294,8 +282,8 @@ meta_background_dispose (GObject *object)
free_color_texture (self);
free_wallpaper_texture (self);
set_file (self, &priv->file1, &priv->background_image1, NULL);
set_file (self, &priv->file2, &priv->background_image2, NULL);
set_filename (self, &priv->filename1, &priv->background_image1, NULL);
set_filename (self, &priv->filename2, &priv->background_image2, NULL);
set_screen (self, NULL);
@ -305,6 +293,8 @@ meta_background_dispose (GObject *object)
static void
meta_background_finalize (GObject *object)
{
all_backgrounds = g_slist_remove (all_backgrounds, object);
G_OBJECT_CLASS (meta_background_parent_class)->finalize (object);
}
@ -347,6 +337,7 @@ meta_background_init (MetaBackground *self)
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
META_TYPE_BACKGROUND,
MetaBackgroundPrivate);
all_backgrounds = g_slist_prepend (all_backgrounds, self);
}
static void
@ -881,19 +872,19 @@ meta_background_set_gradient (MetaBackground *self,
}
void
meta_background_set_file (MetaBackground *self,
GFile *file,
GDesktopBackgroundStyle style)
meta_background_set_filename (MetaBackground *self,
const char *filename,
GDesktopBackgroundStyle style)
{
g_return_if_fail (META_IS_BACKGROUND (self));
meta_background_set_blend (self, file, NULL, 0.0, style);
meta_background_set_blend (self, filename, NULL, 0.0, style);
}
void
meta_background_set_blend (MetaBackground *self,
GFile *file1,
GFile *file2,
const char *filename1,
const char *filename2,
double blend_factor,
GDesktopBackgroundStyle style)
{
@ -904,8 +895,8 @@ meta_background_set_blend (MetaBackground *self,
priv = self->priv;
set_file (self, &priv->file1, &priv->background_image1, file1);
set_file (self, &priv->file2, &priv->background_image2, file2);
set_filename (self, &priv->filename1, &priv->background_image1, filename1);
set_filename (self, &priv->filename2, &priv->background_image2, filename2);
priv->blend_factor = blend_factor;
priv->style = style;
@ -913,3 +904,12 @@ meta_background_set_blend (MetaBackground *self,
free_wallpaper_texture (self);
mark_changed (self);
}
void
meta_background_refresh_all (void)
{
GSList *l;
for (l = all_backgrounds; l; l = l->next)
mark_changed (l->data);
}

View File

@ -49,8 +49,6 @@ meta_surface_actor_pick (ClutterActor *actor,
{
MetaSurfaceActor *self = META_SURFACE_ACTOR (actor);
MetaSurfaceActorPrivate *priv = self->priv;
ClutterActorIter iter;
ClutterActor *child;
if (!clutter_actor_should_pick_paint (actor))
return;
@ -94,11 +92,6 @@ meta_surface_actor_pick (ClutterActor *actor,
cogl_framebuffer_draw_rectangles (fb, pipeline, rectangles, n_rects);
cogl_object_unref (pipeline);
}
clutter_actor_iter_init (&iter, actor);
while (clutter_actor_iter_next (&iter, &child))
clutter_actor_paint (child);
}
static void

View File

@ -100,7 +100,7 @@ struct _MetaWindowActorPrivate
guint disposed : 1;
/* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN
* client message using the most recent frame in ->frames */
* client message for one or more messages in ->frames */
guint needs_frame_drawn : 1;
guint repaint_scheduled : 1;
@ -118,10 +118,21 @@ struct _MetaWindowActorPrivate
typedef struct _FrameData FrameData;
/* Each time the application updates the sync request counter to a new even value
* value, we queue a frame into the windows list of frames. Once we're painting
* an update "in response" to the window, we fill in frame_counter with the
* Cogl counter for that frame, and send _NET_WM_FRAME_DRAWN at the end of the
* frame. _NET_WM_FRAME_TIMINGS is sent when we get a frame_complete callback.
*
* As an exception, if a window is completely obscured, we try to throttle drawning
* to a slower frame rate. In this case, frame_counter stays -1 until
* send_frame_message_timeout() runs, at which point we send both the
* _NET_WM_FRAME_DRAWN and _NET_WM_FRAME_TIMINGS messages.
*/
struct _FrameData
{
int64_t frame_counter;
guint64 sync_request_serial;
int64_t frame_counter;
gint64 frame_drawn_time;
};
@ -655,6 +666,30 @@ clip_shadow_under_window (MetaWindowActor *self)
return is_non_opaque (self) && priv->window->frame;
}
static void
assign_frame_counter_to_frames (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
GList *l;
/* If the window is obscured, then we're expecting to deal with sending
* frame messages in a timeout, rather than in this paint cycle.
*/
if (priv->send_frame_messages_timer != 0)
return;
for (l = priv->frames; l; l = l->next)
{
FrameData *frame = l->data;
if (frame->frame_counter == -1)
{
CoglOnscreen *onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer());
frame->frame_counter = cogl_onscreen_get_frame_counter (onscreen);
}
}
}
static void
meta_window_actor_paint (ClutterActor *actor)
{
@ -671,6 +706,8 @@ meta_window_actor_paint (ClutterActor *actor)
{
g_source_remove (priv->send_frame_messages_timer);
priv->send_frame_messages_timer = 0;
assign_frame_counter_to_frames (self);
}
if (shadow != NULL)
@ -873,16 +910,27 @@ send_frame_messages_timeout (gpointer data)
{
MetaWindowActor *self = (MetaWindowActor *) data;
MetaWindowActorPrivate *priv = self->priv;
FrameData *frame = g_slice_new0 (FrameData);
GList *l;
frame->sync_request_serial = priv->window->sync_request_serial;
for (l = priv->frames; l;)
{
GList *l_next = l->next;
FrameData *frame = l->data;
do_send_frame_drawn (self, frame);
do_send_frame_timings (self, frame, 0, 0);
if (frame->frame_counter == -1)
{
do_send_frame_drawn (self, frame);
do_send_frame_timings (self, frame, 0, 0);
priv->frames = g_list_delete_link (priv->frames, l);
frame_data_free (frame);
}
l = l_next;
}
priv->needs_frame_drawn = FALSE;
priv->send_frame_messages_timer = 0;
frame_data_free (frame);
return FALSE;
}
@ -891,6 +939,10 @@ static void
queue_send_frame_messages_timeout (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
if (priv->send_frame_messages_timer != 0)
return;
MetaDisplay *display = meta_window_get_display (priv->window);
gint64 current_time = meta_compositor_monotonic_time_to_server_time (display, g_get_monotonic_time ());
MetaMonitorManager *monitor_manager = meta_monitor_manager_get ();
@ -933,6 +985,7 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
return;
frame = g_slice_new0 (FrameData);
frame->frame_counter = -1;
priv->needs_frame_drawn = TRUE;
@ -1905,24 +1958,12 @@ meta_window_actor_handle_updates (MetaWindowActor *self)
void
meta_window_actor_pre_paint (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
GList *l;
if (meta_window_actor_is_destroyed (self))
return;
meta_window_actor_handle_updates (self);
for (l = priv->frames; l != NULL; l = l->next)
{
FrameData *frame = l->data;
if (frame->frame_counter == 0)
{
CoglOnscreen *onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer());
frame->frame_counter = cogl_onscreen_get_frame_counter (onscreen);
}
}
assign_frame_counter_to_frames (self);
}
static void
@ -1963,16 +2004,23 @@ meta_window_actor_post_paint (MetaWindowActor *self)
if (meta_window_actor_is_destroyed (self))
return;
/* This window had damage, but wasn't actually redrawn because
* it is obscured. So we should wait until timer expiration
* before sending _NET_WM_FRAME_* messages.
*/
if (priv->send_frame_messages_timer != 0)
return;
if (priv->needs_frame_drawn)
/* If the window had damage, but wasn't actually redrawn because
* it is obscured, we should wait until timer expiration before
* sending _NET_WM_FRAME_* messages.
*/
if (priv->send_frame_messages_timer == 0 &&
priv->needs_frame_drawn)
{
do_send_frame_drawn (self, priv->frames->data);
GList *l;
for (l = priv->frames; l; l = l->next)
{
FrameData *frame = l->data;
if (frame->frame_drawn_time == 0)
do_send_frame_drawn (self, frame);
}
priv->needs_frame_drawn = FALSE;
}
@ -2057,15 +2105,20 @@ meta_window_actor_frame_complete (MetaWindowActor *self,
{
GList *l_next = l->next;
FrameData *frame = l->data;
gint64 frame_counter = cogl_frame_info_get_frame_counter (frame_info);
if (frame->frame_counter == cogl_frame_info_get_frame_counter (frame_info))
if (frame->frame_counter != -1 && frame->frame_counter <= frame_counter)
{
if (frame->frame_drawn_time != 0)
{
priv->frames = g_list_delete_link (priv->frames, l);
send_frame_timings (self, frame, frame_info, presentation_time);
frame_data_free (frame);
}
if (G_UNLIKELY (frame->frame_drawn_time == 0))
g_warning ("%s: Frame has assigned frame counter but no frame drawn time",
priv->window->desc);
if (G_UNLIKELY (frame->frame_counter < frame_counter))
g_warning ("%s: frame_complete callback never occurred for frame %" G_GINT64_FORMAT,
priv->window->desc, frame->frame_counter);
priv->frames = g_list_delete_link (priv->frames, l);
send_frame_timings (self, frame, frame_info, presentation_time);
frame_data_free (frame);
}
l = l_next;

View File

@ -1017,7 +1017,6 @@ constrain_aspect_ratio (MetaWindow *window,
double best_width, best_height;
double alt_width, alt_height;
MetaRectangle *start_rect;
MetaRectangle client_rect;
if (priority > PRIORITY_ASPECT_RATIO)
return TRUE;
@ -1069,18 +1068,15 @@ constrain_aspect_ratio (MetaWindow *window,
fudge = 1;
break;
}
meta_window_frame_rect_to_client_rect (window, &info->current, &client_rect);
constraint_already_satisfied =
client_rect.width - (client_rect.height * minr ) > -minr*fudge &&
client_rect.width - (client_rect.height * maxr ) < maxr*fudge;
info->current.width - (info->current.height * minr ) > -minr*fudge &&
info->current.width - (info->current.height * maxr ) < maxr*fudge;
if (check_only || constraint_already_satisfied)
return constraint_already_satisfied;
/*** Enforce constraint ***/
new_width = client_rect.width;
new_height = client_rect.height;
new_width = info->current.width;
new_height = info->current.height;
switch (info->resize_gravity)
{
@ -1127,14 +1123,6 @@ constrain_aspect_ratio (MetaWindow *window,
break;
}
{
client_rect.width = new_width;
client_rect.height = new_height;
meta_window_client_rect_to_frame_rect (window, &client_rect, &client_rect);
new_width = client_rect.width;
new_height = client_rect.height;
}
/* Figure out what original rect to pass to meta_rectangle_resize_with_gravity
* See bug 448183
*/

View File

@ -1214,7 +1214,7 @@ meta_grab_op_is_moving (MetaGrabOp op)
if (!grab_op_is_window (op))
return FALSE;
return (op & META_GRAB_OP_WINDOW_DIR_MASK) == 0;
return !meta_grab_op_is_resizing (op);
}
/**
@ -1953,11 +1953,6 @@ meta_display_end_grab_op (MetaDisplay *display,
g_signal_emit (display, display_signals[GRAB_OP_END], 0,
display->screen, grab_window, grab_op);
/* We need to reset this early, since the
* meta_window_grab_op_ended callback relies on this being
* up to date. */
display->grab_op = META_GRAB_OP_NONE;
if (display->event_route == META_EVENT_ROUTE_WINDOW_OP)
{
/* Clear out the edge cache */
@ -1990,6 +1985,7 @@ meta_display_end_grab_op (MetaDisplay *display,
}
display->event_route = META_EVENT_ROUTE_NORMAL;
display->grab_op = META_GRAB_OP_NONE;
display->grab_window = NULL;
display->grab_tile_mode = META_TILE_NONE;
display->grab_tile_monitor_number = -1;

View File

@ -151,6 +151,23 @@ sequence_is_pointer_emulated (MetaDisplay *display,
return FALSE;
}
static void
meta_display_update_pointer_emulating_sequence (MetaDisplay *display,
const ClutterEvent *event)
{
ClutterEventSequence *sequence;
sequence = clutter_event_get_event_sequence (event);
if (event->type == CLUTTER_TOUCH_BEGIN &&
!display->pointer_emulating_sequence &&
sequence_is_pointer_emulated (display, event))
display->pointer_emulating_sequence = sequence;
else if (event->type == CLUTTER_TOUCH_END &&
display->pointer_emulating_sequence == sequence)
display->pointer_emulating_sequence = NULL;
}
static gboolean
meta_display_handle_event (MetaDisplay *display,
const ClutterEvent *event)
@ -159,15 +176,8 @@ meta_display_handle_event (MetaDisplay *display,
gboolean bypass_clutter = FALSE;
G_GNUC_UNUSED gboolean bypass_wayland = FALSE;
MetaGestureTracker *tracker;
ClutterEventSequence *sequence;
sequence = clutter_event_get_event_sequence (event);
/* Set the pointer emulating sequence on touch begin, if eligible */
if (event->type == CLUTTER_TOUCH_BEGIN &&
!display->pointer_emulating_sequence &&
sequence_is_pointer_emulated (display, event))
display->pointer_emulating_sequence = sequence;
meta_display_update_pointer_emulating_sequence (display, event);
#ifdef HAVE_WAYLAND
MetaWaylandCompositor *compositor = NULL;
@ -304,11 +314,6 @@ meta_display_handle_event (MetaDisplay *display,
}
#endif
/* Unset the pointer emulating sequence after its end event is processed */
if (event->type == CLUTTER_TOUCH_END &&
display->pointer_emulating_sequence == sequence)
display->pointer_emulating_sequence = NULL;
display->current_time = CurrentTime;
return bypass_clutter;
}

View File

@ -1660,14 +1660,13 @@ meta_window_ungrab_all_keys (MetaWindow *window, guint32 timestamp)
}
void
meta_display_freeze_keyboard (MetaDisplay *display, guint32 timestamp)
meta_display_freeze_keyboard (MetaDisplay *display, Window window, guint32 timestamp)
{
MetaBackend *backend = meta_get_backend ();
if (!META_IS_BACKEND_X11 (backend))
return;
Window window = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend));
grab_keyboard (window, timestamp, XIGrabModeSync);
}

View File

@ -779,7 +779,8 @@ meta_window_place (MetaWindow *window,
if (w != window &&
meta_window_showing_on_its_workspace (w) &&
meta_window_located_on_workspace (w, window->workspace))
(window->on_all_workspaces ||
meta_window_located_on_workspace (w, window->workspace)))
windows = g_list_prepend (windows, w);
tmp = tmp->next;

View File

@ -3213,9 +3213,7 @@ meta_window_unmake_fullscreen (MetaWindow *window)
/* Window's size hints may have changed while maximized, making
* saved_rect invalid. #329152
*/
meta_window_frame_rect_to_client_rect (window, &target_rect, &target_rect);
ensure_size_hints_satisfied (&target_rect, &window->size_hints);
meta_window_client_rect_to_frame_rect (window, &target_rect, &target_rect);
/* Need to update window->has_resize_func before we move_resize()
*/
@ -5853,7 +5851,7 @@ update_resize (MetaWindow *window,
int new_w, new_h;
int gravity;
MetaRectangle old;
double remaining = 0;
double remaining;
MetaMaximizeFlags new_unmaximize;
window->display->grab_latest_motion_x = x;
@ -6112,8 +6110,10 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window,
case CLUTTER_BUTTON_RELEASE:
if (event->button.button == 1 ||
event->button.button == (unsigned int) meta_prefs_get_mouse_button_resize ())
end_grab_op (window, event);
{
end_grab_op (window, event);
return FALSE;
}
return TRUE;
case CLUTTER_TOUCH_BEGIN:

View File

@ -173,6 +173,7 @@ void meta_display_unmanage_screen (MetaDisplay *display,
void meta_display_clear_mouse_mode (MetaDisplay *display);
void meta_display_freeze_keyboard (MetaDisplay *display,
Window window,
guint32 timestamp);
void meta_display_ungrab_keyboard (MetaDisplay *display,
guint32 timestamp);

71
src/meta/gradient.h Normal file
View File

@ -0,0 +1,71 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter gradient rendering */
/*
* Copyright (C) 2001 Havoc Pennington, 99% copied from wrlib in
* WindowMaker, Copyright (C) 1997-2000 Dan Pascu and Alfredo Kojima
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>. */
#ifndef META_GRADIENT_H
#define META_GRADIENT_H
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gdk/gdk.h>
/**
* MetaGradientType:
* @META_GRADIENT_VERTICAL: Vertical gradient
* @META_GRADIENT_HORIZONTAL: Horizontal gradient
* @META_GRADIENT_DIAGONAL: Diagonal gradient
* @META_GRADIENT_LAST: Marks the end of the #MetaGradientType enumeration
*
*/
typedef enum
{
META_GRADIENT_VERTICAL,
META_GRADIENT_HORIZONTAL,
META_GRADIENT_DIAGONAL,
META_GRADIENT_LAST
} MetaGradientType;
GdkPixbuf* meta_gradient_create_simple (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to,
MetaGradientType style);
GdkPixbuf* meta_gradient_create_multi (int width,
int height,
const GdkRGBA *colors,
int n_colors,
MetaGradientType style);
GdkPixbuf* meta_gradient_create_interwoven (int width,
int height,
const GdkRGBA colors1[2],
int thickness1,
const GdkRGBA colors2[2],
int thickness2);
/* Generate an alpha gradient and multiply it with the existing alpha
* channel of the given pixbuf
*/
void meta_gradient_add_alpha (GdkPixbuf *pixbuf,
const guchar *alphas,
int n_alphas,
MetaGradientType type);
#endif

View File

@ -69,8 +69,8 @@ MetaBackgroundImageCache *meta_background_image_cache_get_default (void);
GType meta_background_image_cache_get_type (void);
MetaBackgroundImage *meta_background_image_cache_load (MetaBackgroundImageCache *cache,
GFile *file);
const char *filename);
void meta_background_image_cache_purge (MetaBackgroundImageCache *cache,
GFile *file);
const char *filename);
#endif /* __META_BACKGROUND_IMAGE_H__ */

View File

@ -57,6 +57,8 @@ struct _MetaBackground
MetaBackgroundPrivate *priv;
};
void meta_background_refresh_all (void);
GType meta_background_get_type (void);
MetaBackground *meta_background_new (MetaScreen *screen);
@ -67,12 +69,12 @@ void meta_background_set_gradient (MetaBackground *self,
GDesktopBackgroundShading shading_direction,
ClutterColor *color,
ClutterColor *second_color);
void meta_background_set_file (MetaBackground *self,
GFile *file,
void meta_background_set_filename (MetaBackground *self,
const char *filename,
GDesktopBackgroundStyle style);
void meta_background_set_blend (MetaBackground *self,
GFile *file1,
GFile *file2,
const char *filename1,
const char *filename2,
double blend_factor,
GDesktopBackgroundStyle style);

902
src/ui/gradient.c Normal file
View File

@ -0,0 +1,902 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2001 Havoc Pennington, 99% copied from wrlib in
* WindowMaker, Copyright (C) 1997-2000 Dan Pascu and Alfredo Kojima
* Copyright (C) 2005 Elijah Newren
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>. */
/**
* SECTION:gradient
* @title: Gradients
* @short_description: Metacity gradient rendering
*/
#include <meta/gradient.h>
#include <meta/util.h>
#include <string.h>
/* This is all Alfredo's and Dan's usual very nice WindowMaker code,
* slightly GTK-ized
*/
static GdkPixbuf* meta_gradient_create_horizontal (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to);
static GdkPixbuf* meta_gradient_create_vertical (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to);
static GdkPixbuf* meta_gradient_create_diagonal (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to);
static GdkPixbuf* meta_gradient_create_multi_horizontal (int width,
int height,
const GdkRGBA *colors,
int count);
static GdkPixbuf* meta_gradient_create_multi_vertical (int width,
int height,
const GdkRGBA *colors,
int count);
static GdkPixbuf* meta_gradient_create_multi_diagonal (int width,
int height,
const GdkRGBA *colors,
int count);
/* Used as the destroy notification function for gdk_pixbuf_new() */
static void
free_buffer (guchar *pixels, gpointer data)
{
g_free (pixels);
}
static GdkPixbuf*
blank_pixbuf (int width, int height)
{
guchar *buf;
int rowstride;
g_return_val_if_fail (width > 0, NULL);
g_return_val_if_fail (height > 0, NULL);
/* Always align rows to 32-bit boundaries */
rowstride = 4 * ((4 * width + 4) / 4);
buf = g_try_malloc (height * rowstride);
if (!buf)
return NULL;
return gdk_pixbuf_new_from_data (buf, GDK_COLORSPACE_RGB,
TRUE, 8,
width, height, rowstride,
free_buffer, NULL);
}
/**
* meta_gradient_create_simple:
* @width: Width in pixels
* @height: Height in pixels
* @from: Starting color
* @to: Ending color
* @style: Gradient style
*
* Returns: (transfer full): A new linear gradient
*/
GdkPixbuf*
meta_gradient_create_simple (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to,
MetaGradientType style)
{
switch (style)
{
case META_GRADIENT_HORIZONTAL:
return meta_gradient_create_horizontal (width, height,
from, to);
case META_GRADIENT_VERTICAL:
return meta_gradient_create_vertical (width, height,
from, to);
case META_GRADIENT_DIAGONAL:
return meta_gradient_create_diagonal (width, height,
from, to);
case META_GRADIENT_LAST:
break;
}
g_assert_not_reached ();
return NULL;
}
/**
* meta_gradient_create_multi:
* @width: Width in pixels
* @height: Height in pixels
* @colors: (array length=n_colors): Array of colors
* @n_colors: Number of colors
* @style: Gradient style
*
* Returns: (transfer full): A new multi-step linear gradient
*/
GdkPixbuf*
meta_gradient_create_multi (int width,
int height,
const GdkRGBA *colors,
int n_colors,
MetaGradientType style)
{
if (n_colors > 2)
{
switch (style)
{
case META_GRADIENT_HORIZONTAL:
return meta_gradient_create_multi_horizontal (width, height, colors, n_colors);
case META_GRADIENT_VERTICAL:
return meta_gradient_create_multi_vertical (width, height, colors, n_colors);
case META_GRADIENT_DIAGONAL:
return meta_gradient_create_multi_diagonal (width, height, colors, n_colors);
case META_GRADIENT_LAST:
g_assert_not_reached ();
break;
}
}
else if (n_colors > 1)
{
return meta_gradient_create_simple (width, height, &colors[0], &colors[1],
style);
}
else if (n_colors > 0)
{
return meta_gradient_create_simple (width, height, &colors[0], &colors[0],
style);
}
g_assert_not_reached ();
return NULL;
}
/**
* meta_gradient_create_interwoven: (skip)
* @width: Width in pixels
* @height: Height in pixels
* @colors1: Array of colors
* @thickness1: Thickness
* @colors2: Array of colors
* @thickness2: Thickness
*
* Interwoven essentially means we have two vertical gradients,
* cut into horizontal strips of the given thickness, and then the strips
* are alternated. I'm not sure what it's good for, just copied since
* WindowMaker had it.
*/
GdkPixbuf*
meta_gradient_create_interwoven (int width,
int height,
const GdkRGBA colors1[2],
int thickness1,
const GdkRGBA colors2[2],
int thickness2)
{
int i, j, k, l, ll;
long r1, g1, b1, a1, dr1, dg1, db1, da1;
long r2, g2, b2, a2, dr2, dg2, db2, da2;
GdkPixbuf *pixbuf;
unsigned char *ptr;
unsigned char *pixels;
int rowstride;
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
r1 = (long)(colors1[0].red*0xffffff);
g1 = (long)(colors1[0].green*0xffffff);
b1 = (long)(colors1[0].blue*0xffffff);
a1 = (long)(colors1[0].alpha*0xffffff);
r2 = (long)(colors2[0].red*0xffffff);
g2 = (long)(colors2[0].green*0xffffff);
b2 = (long)(colors2[0].blue*0xffffff);
a2 = (long)(colors2[0].alpha*0xffffff);
dr1 = ((colors1[1].red-colors1[0].red)*0xffffff)/(int)height;
dg1 = ((colors1[1].green-colors1[0].green)*0xffffff)/(int)height;
db1 = ((colors1[1].blue-colors1[0].blue)*0xffffff)/(int)height;
da1 = ((colors1[1].alpha-colors1[0].alpha)*0xffffff)/(int)height;
dr2 = ((colors2[1].red-colors2[0].red)*0xffffff)/(int)height;
dg2 = ((colors2[1].green-colors2[0].green)*0xffffff)/(int)height;
db2 = ((colors2[1].blue-colors2[0].blue)*0xffffff)/(int)height;
da2 = ((colors2[1].alpha-colors2[0].alpha)*0xffffff)/(int)height;
for (i=0,k=0,l=0,ll=thickness1; i<height; i++)
{
ptr = pixels + i * rowstride;
if (k == 0)
{
ptr[0] = (unsigned char) (r1>>16);
ptr[1] = (unsigned char) (g1>>16);
ptr[2] = (unsigned char) (b1>>16);
ptr[3] = (unsigned char) (a1>>16);
}
else
{
ptr[0] = (unsigned char) (r2>>16);
ptr[1] = (unsigned char) (g2>>16);
ptr[2] = (unsigned char) (b2>>16);
ptr[3] = (unsigned char) (a2>>16);
}
for (j=1; j <= width/2; j *= 2)
memcpy (&(ptr[j*4]), ptr, j*4);
memcpy (&(ptr[j*4]), ptr, (width - j)*4);
if (++l == ll)
{
if (k == 0)
{
k = 1;
ll = thickness2;
}
else
{
k = 0;
ll = thickness1;
}
l = 0;
}
r1+=dr1;
g1+=dg1;
b1+=db1;
a1+=da1;
r2+=dr2;
g2+=dg2;
b2+=db2;
a2+=da2;
}
return pixbuf;
}
/*
*----------------------------------------------------------------------
* meta_gradient_create_horizontal--
* Renders a horizontal linear gradient of the specified size in the
* GdkPixbuf format with a border of the specified type.
*
* Returns:
* A 24bit GdkPixbuf with the gradient (no alpha channel).
*
* Side effects:
* None
*----------------------------------------------------------------------
*/
static GdkPixbuf*
meta_gradient_create_horizontal (int width, int height,
const GdkRGBA *from,
const GdkRGBA *to)
{
int i;
long r, g, b, a, dr, dg, db, da;
GdkPixbuf *pixbuf;
unsigned char *ptr;
unsigned char *pixels;
int r0, g0, b0, a0;
int rf, gf, bf, af;
int rowstride;
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
ptr = pixels;
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
r0 = (guchar) (from->red * 0xff);
g0 = (guchar) (from->green * 0xff);
b0 = (guchar) (from->blue * 0xff);
a0 = (guchar) (from->alpha * 0xff);
rf = (guchar) (to->red * 0xff);
gf = (guchar) (to->green * 0xff);
bf = (guchar) (to->blue * 0xff);
af = (guchar) (to->alpha * 0xff);
r = r0 << 16;
g = g0 << 16;
b = b0 << 16;
a = a0 << 16;
dr = ((rf-r0)<<16)/(int)width;
dg = ((gf-g0)<<16)/(int)width;
db = ((bf-b0)<<16)/(int)width;
da = ((af-a0)<<16)/(int)width;
/* render the first line */
for (i=0; i<width; i++)
{
*(ptr++) = (unsigned char)(r>>16);
*(ptr++) = (unsigned char)(g>>16);
*(ptr++) = (unsigned char)(b>>16);
*(ptr++) = (unsigned char)(a>>16);
r += dr;
g += dg;
b += db;
a += da;
}
/* copy the first line to the other lines */
for (i=1; i<height; i++)
{
memcpy (&(pixels[i*rowstride]), pixels, rowstride);
}
return pixbuf;
}
/*
*----------------------------------------------------------------------
* meta_gradient_create_vertical--
* Renders a vertical linear gradient of the specified size in the
* GdkPixbuf format with a border of the specified type.
*
* Returns:
* A 24bit GdkPixbuf with the gradient (no alpha channel).
*
* Side effects:
* None
*----------------------------------------------------------------------
*/
static GdkPixbuf*
meta_gradient_create_vertical (int width, int height,
const GdkRGBA *from,
const GdkRGBA *to)
{
int i, j;
long r, g, b, a, dr, dg, db, da;
GdkPixbuf *pixbuf;
unsigned char *ptr;
int r0, g0, b0, a0;
int rf, gf, bf, af;
int rowstride;
unsigned char *pixels;
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
r0 = (guchar) (from->red * 0xff);
g0 = (guchar) (from->green * 0xff);
b0 = (guchar) (from->blue * 0xff);
a0 = (guchar) (from->alpha * 0xff);
rf = (guchar) (to->red * 0xff);
gf = (guchar) (to->green * 0xff);
bf = (guchar) (to->blue * 0xff);
af = (guchar) (to->alpha * 0xff);
r = r0<<16;
g = g0<<16;
b = b0<<16;
a = a0<<16;
dr = ((rf-r0)<<16)/(int)height;
dg = ((gf-g0)<<16)/(int)height;
db = ((bf-b0)<<16)/(int)height;
da = ((af-a0)<<16)/(int)height;
for (i=0; i<height; i++)
{
ptr = pixels + i * rowstride;
ptr[0] = (unsigned char)(r>>16);
ptr[1] = (unsigned char)(g>>16);
ptr[2] = (unsigned char)(b>>16);
ptr[3] = (unsigned char)(a>>16);
for (j=1; j <= width/2; j *= 2)
memcpy (&(ptr[j*4]), ptr, j*4);
memcpy (&(ptr[j*4]), ptr, (width - j)*4);
r+=dr;
g+=dg;
b+=db;
a+=da;
}
return pixbuf;
}
/*
*----------------------------------------------------------------------
* meta_gradient_create_diagonal--
* Renders a diagonal linear gradient of the specified size in the
* GdkPixbuf format with a border of the specified type.
*
* Returns:
* A 24bit GdkPixbuf with the gradient (no alpha channel).
*
* Side effects:
* None
*----------------------------------------------------------------------
*/
static GdkPixbuf*
meta_gradient_create_diagonal (int width, int height,
const GdkRGBA *from,
const GdkRGBA *to)
{
GdkPixbuf *pixbuf, *tmp;
int j;
float a, offset;
unsigned char *ptr;
unsigned char *pixels;
int rowstride;
if (width == 1)
return meta_gradient_create_vertical (width, height, from, to);
else if (height == 1)
return meta_gradient_create_horizontal (width, height, from, to);
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
tmp = meta_gradient_create_horizontal (2*width-1, 1, from, to);
if (!tmp)
{
g_object_unref (G_OBJECT (pixbuf));
return NULL;
}
ptr = gdk_pixbuf_get_pixels (tmp);
a = ((float)(width - 1))/((float)(height - 1));
width = width * 4;
/* copy the first line to the other lines with corresponding offset */
for (j=0, offset=0.0; j<rowstride*height; j += rowstride)
{
memcpy (&(pixels[j]), &ptr[4*(int)offset], width);
offset += a;
}
g_object_unref (G_OBJECT (tmp));
return pixbuf;
}
static GdkPixbuf*
meta_gradient_create_multi_horizontal (int width, int height,
const GdkRGBA *colors,
int count)
{
int i, j, k;
long r, g, b, a, dr, dg, db, da;
GdkPixbuf *pixbuf;
unsigned char *ptr;
unsigned char *pixels;
int width2;
int rowstride;
g_return_val_if_fail (count > 2, NULL);
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
ptr = pixels;
if (count > width)
count = width;
if (count > 1)
width2 = width/(count-1);
else
width2 = width;
k = 0;
r = (long)(colors[0].red * 0xffffff);
g = (long)(colors[0].green * 0xffffff);
b = (long)(colors[0].blue * 0xffffff);
a = (long)(colors[0].alpha * 0xffffff);
/* render the first line */
for (i=1; i<count; i++)
{
dr = (int)((colors[i].red - colors[i-1].red) *0xffffff)/(int)width2;
dg = (int)((colors[i].green - colors[i-1].green)*0xffffff)/(int)width2;
db = (int)((colors[i].blue - colors[i-1].blue) *0xffffff)/(int)width2;
da = (int)((colors[i].alpha - colors[i-1].alpha) *0xffffff)/(int)width2;
for (j=0; j<width2; j++)
{
*ptr++ = (unsigned char)(r>>16);
*ptr++ = (unsigned char)(g>>16);
*ptr++ = (unsigned char)(b>>16);
*ptr++ = (unsigned char)(a>>16);
r += dr;
g += dg;
b += db;
a += da;
k++;
}
r = (long)(colors[i].red * 0xffffff);
g = (long)(colors[i].green * 0xffffff);
b = (long)(colors[i].blue * 0xffffff);
a = (long)(colors[i].alpha * 0xffffff);
}
for (j=k; j<width; j++)
{
*ptr++ = (unsigned char)(r>>16);
*ptr++ = (unsigned char)(g>>16);
*ptr++ = (unsigned char)(b>>16);
*ptr++ = (unsigned char)(a>>16);
}
/* copy the first line to the other lines */
for (i=1; i<height; i++)
{
memcpy (&(pixels[i*rowstride]), pixels, rowstride);
}
return pixbuf;
}
static GdkPixbuf*
meta_gradient_create_multi_vertical (int width, int height,
const GdkRGBA *colors,
int count)
{
int i, j, k;
long r, g, b, a, dr, dg, db, da;
GdkPixbuf *pixbuf;
unsigned char *ptr, *tmp, *pixels;
int height2;
int x;
int rowstride;
g_return_val_if_fail (count > 2, NULL);
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
ptr = pixels;
if (count > height)
count = height;
if (count > 1)
height2 = height/(count-1);
else
height2 = height;
k = 0;
r = (long)(colors[0].red * 0xffffff);
g = (long)(colors[0].green * 0xffffff);
b = (long)(colors[0].blue * 0xffffff);
a = (long)(colors[0].alpha * 0xffffff);
for (i=1; i<count; i++)
{
dr = (int)((colors[i].red - colors[i-1].red) *0xffffff)/(int)height2;
dg = (int)((colors[i].green - colors[i-1].green)*0xffffff)/(int)height2;
db = (int)((colors[i].blue - colors[i-1].blue) *0xffffff)/(int)height2;
da = (int)((colors[i].alpha - colors[i-1].alpha) *0xffffff)/(int)height2;
for (j=0; j<height2; j++)
{
ptr[0] = (unsigned char)(r>>16);
ptr[1] = (unsigned char)(g>>16);
ptr[2] = (unsigned char)(b>>16);
ptr[3] = (unsigned char)(a>>16);
for (x=1; x <= width/2; x *= 2)
memcpy (&(ptr[x*4]), ptr, x*4);
memcpy (&(ptr[x*4]), ptr, (width - x)*4);
ptr += rowstride;
r += dr;
g += dg;
b += db;
a += da;
k++;
}
r = (long)(colors[i].red * 0xffffff);
g = (long)(colors[i].green * 0xffffff);
b = (long)(colors[i].blue * 0xffffff);
a = (long)(colors[i].alpha * 0xffffff);
}
if (k<height)
{
tmp = ptr;
ptr[0] = (unsigned char) (r>>16);
ptr[1] = (unsigned char) (g>>16);
ptr[2] = (unsigned char) (b>>16);
ptr[3] = (unsigned char) (a>>16);
for (x=1; x <= width/2; x *= 2)
memcpy (&(ptr[x*4]), ptr, x*4);
memcpy (&(ptr[x*4]), ptr, (width - x)*4);
ptr += rowstride;
for (j=k+1; j<height; j++)
{
memcpy (ptr, tmp, rowstride);
ptr += rowstride;
}
}
return pixbuf;
}
static GdkPixbuf*
meta_gradient_create_multi_diagonal (int width, int height,
const GdkRGBA *colors,
int count)
{
GdkPixbuf *pixbuf, *tmp;
float a, offset;
int j;
unsigned char *ptr;
unsigned char *pixels;
int rowstride;
g_return_val_if_fail (count > 2, NULL);
if (width == 1)
return meta_gradient_create_multi_vertical (width, height, colors, count);
else if (height == 1)
return meta_gradient_create_multi_horizontal (width, height, colors, count);
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
if (count > width)
count = width;
if (count > height)
count = height;
if (count > 2)
tmp = meta_gradient_create_multi_horizontal (2*width-1, 1, colors, count);
else
/* wrlib multiplies these colors by 256 before passing them in, but
* I think it's a bug in wrlib, so changed here. I could be wrong
* though, if we notice two-color multi diagonals not working.
*/
tmp = meta_gradient_create_horizontal (2*width-1, 1,
&colors[0], &colors[1]);
if (!tmp)
{
g_object_unref (G_OBJECT (pixbuf));
return NULL;
}
ptr = gdk_pixbuf_get_pixels (tmp);
a = ((float)(width - 1))/((float)(height - 1));
width = width * 3;
/* copy the first line to the other lines with corresponding offset */
for (j=0, offset=0; j<rowstride*height; j += rowstride)
{
memcpy (&(pixels[j]), &ptr[3*(int)offset], width);
offset += a;
}
g_object_unref (G_OBJECT (tmp));
return pixbuf;
}
static void
simple_multiply_alpha (GdkPixbuf *pixbuf,
guchar alpha)
{
guchar *pixels;
int rowstride;
int height;
int row;
g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
if (alpha == 255)
return;
g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
row = 0;
while (row < height)
{
guchar *p;
guchar *end;
p = pixels + row * rowstride;
end = p + rowstride;
while (p != end)
{
p += 3; /* skip RGB */
/* multiply the two alpha channels. not sure this is right.
* but some end cases are that if the pixbuf contains 255,
* then it should be modified to contain "alpha"; if the
* pixbuf contains 0, it should remain 0.
*/
/* ((*p / 255.0) * (alpha / 255.0)) * 255; */
*p = (guchar) (((int) *p * (int) alpha) / (int) 255);
++p; /* skip A */
}
++row;
}
}
static void
meta_gradient_add_alpha_horizontal (GdkPixbuf *pixbuf,
const unsigned char *alphas,
int n_alphas)
{
int i, j;
long a, da;
unsigned char *p;
unsigned char *pixels;
int width2;
int rowstride;
int width, height;
unsigned char *gradient;
unsigned char *gradient_p;
unsigned char *gradient_end;
g_return_if_fail (n_alphas > 0);
if (n_alphas == 1)
{
/* Optimize this */
simple_multiply_alpha (pixbuf, alphas[0]);
return;
}
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
gradient = g_new (unsigned char, width);
gradient_end = gradient + width;
if (n_alphas > width)
n_alphas = width;
if (n_alphas > 1)
width2 = width / (n_alphas - 1);
else
width2 = width;
a = alphas[0] << 8;
gradient_p = gradient;
/* render the gradient into an array */
for (i = 1; i < n_alphas; i++)
{
da = (((int)(alphas[i] - (int) alphas[i-1])) << 8) / (int) width2;
for (j = 0; j < width2; j++)
{
*gradient_p++ = (a >> 8);
a += da;
}
a = alphas[i] << 8;
}
/* get leftover pixels */
while (gradient_p != gradient_end)
{
*gradient_p++ = a >> 8;
}
/* Now for each line of the pixbuf, fill in with the gradient */
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
p = pixels;
i = 0;
while (i < height)
{
unsigned char *row_end = p + rowstride;
gradient_p = gradient;
p += 3;
while (gradient_p != gradient_end)
{
/* multiply the two alpha channels. not sure this is right.
* but some end cases are that if the pixbuf contains 255,
* then it should be modified to contain "alpha"; if the
* pixbuf contains 0, it should remain 0.
*/
/* ((*p / 255.0) * (alpha / 255.0)) * 255; */
*p = (guchar) (((int) *p * (int) *gradient_p) / (int) 255);
p += 4;
++gradient_p;
}
p = row_end;
++i;
}
g_free (gradient);
}
void
meta_gradient_add_alpha (GdkPixbuf *pixbuf,
const guchar *alphas,
int n_alphas,
MetaGradientType type)
{
g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
g_return_if_fail (gdk_pixbuf_get_has_alpha (pixbuf));
g_return_if_fail (n_alphas > 0);
switch (type)
{
case META_GRADIENT_HORIZONTAL:
meta_gradient_add_alpha_horizontal (pixbuf, alphas, n_alphas);
break;
case META_GRADIENT_VERTICAL:
g_printerr ("metacity: vertical alpha channel gradient not implemented yet\n");
break;
case META_GRADIENT_DIAGONAL:
g_printerr ("metacity: diagonal alpha channel gradient not implemented yet\n");
break;
case META_GRADIENT_LAST:
g_assert_not_reached ();
break;
}
}

315
src/ui/testgradient.c Normal file
View File

@ -0,0 +1,315 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter gradient test program */
/*
* Copyright (C) 2002 Havoc Pennington
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>. */
#include <meta/gradient.h>
#include <gtk/gtk.h>
typedef void (* RenderGradientFunc) (cairo_t *cr,
int width,
int height);
static void
draw_checkerboard (cairo_t *cr,
int width,
int height)
{
gint i, j, xcount, ycount;
GdkRGBA color1, color2;
#define CHECK_SIZE 10
#define SPACING 2
color1.red = 30000. / 65535.;
color1.green = 30000. / 65535.;
color1.blue = 30000. / 65535.;
color1.alpha = 1.0;
color2.red = 50000. / 65535.;
color2.green = 50000. / 65535.;
color2.blue = 50000. / 65535.;
color2.alpha = 1.0;
xcount = 0;
i = SPACING;
while (i < width)
{
j = SPACING;
ycount = xcount % 2; /* start with even/odd depending on row */
while (j < height)
{
if (ycount % 2)
gdk_cairo_set_source_rgba (cr, &color1);
else
gdk_cairo_set_source_rgba (cr, &color2);
/* If we're outside event->area, this will do nothing.
* It might be mildly more efficient if we handled
* the clipping ourselves, but again we're feeling lazy.
*/
cairo_rectangle (cr, i, j, CHECK_SIZE, CHECK_SIZE);
cairo_fill (cr);
j += CHECK_SIZE + SPACING;
++ycount;
}
i += CHECK_SIZE + SPACING;
++xcount;
}
}
static void
render_simple (cairo_t *cr,
int width, int height,
MetaGradientType type,
gboolean with_alpha)
{
GdkPixbuf *pixbuf;
GdkRGBA from, to;
gdk_rgba_parse (&from, "blue");
gdk_rgba_parse (&to, "green");
pixbuf = meta_gradient_create_simple (width, height,
&from, &to,
type);
if (with_alpha)
{
const unsigned char alphas[] = { 0xff, 0xaa, 0x2f, 0x0, 0xcc, 0xff, 0xff };
if (!gdk_pixbuf_get_has_alpha (pixbuf))
{
GdkPixbuf *new_pixbuf;
new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
g_object_unref (G_OBJECT (pixbuf));
pixbuf = new_pixbuf;
}
meta_gradient_add_alpha (pixbuf,
alphas, G_N_ELEMENTS (alphas),
META_GRADIENT_HORIZONTAL);
draw_checkerboard (cr , width, height);
}
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
g_object_unref (G_OBJECT (pixbuf));
}
static void
render_vertical_func (cairo_t *cr,
int width, int height)
{
render_simple (cr, width, height, META_GRADIENT_VERTICAL, FALSE);
}
static void
render_horizontal_func (cairo_t *cr,
int width, int height)
{
render_simple (cr, width, height, META_GRADIENT_HORIZONTAL, FALSE);
}
static void
render_diagonal_func (cairo_t *cr,
int width, int height)
{
render_simple (cr, width, height, META_GRADIENT_DIAGONAL, FALSE);
}
static void
render_diagonal_alpha_func (cairo_t *cr,
int width, int height)
{
render_simple (cr, width, height, META_GRADIENT_DIAGONAL, TRUE);
}
static void
render_multi (cairo_t *cr,
int width, int height,
MetaGradientType type)
{
GdkPixbuf *pixbuf;
#define N_COLORS 5
GdkRGBA colors[N_COLORS];
gdk_rgba_parse (&colors[0], "red");
gdk_rgba_parse (&colors[1], "blue");
gdk_rgba_parse (&colors[2], "orange");
gdk_rgba_parse (&colors[3], "pink");
gdk_rgba_parse (&colors[4], "green");
pixbuf = meta_gradient_create_multi (width, height,
colors, N_COLORS,
type);
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
g_object_unref (G_OBJECT (pixbuf));
#undef N_COLORS
}
static void
render_vertical_multi_func (cairo_t *cr,
int width, int height)
{
render_multi (cr, width, height, META_GRADIENT_VERTICAL);
}
static void
render_horizontal_multi_func (cairo_t *cr,
int width, int height)
{
render_multi (cr, width, height, META_GRADIENT_HORIZONTAL);
}
static void
render_diagonal_multi_func (cairo_t *cr,
int width, int height)
{
render_multi (cr, width, height, META_GRADIENT_DIAGONAL);
}
static void
render_interwoven_func (cairo_t *cr,
int width, int height)
{
GdkPixbuf *pixbuf;
#define N_COLORS 4
GdkRGBA colors[N_COLORS];
gdk_rgba_parse (&colors[0], "red");
gdk_rgba_parse (&colors[1], "blue");
gdk_rgba_parse (&colors[2], "pink");
gdk_rgba_parse (&colors[3], "green");
pixbuf = meta_gradient_create_interwoven (width, height,
colors, height / 10,
colors + 2, height / 14);
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
g_object_unref (G_OBJECT (pixbuf));
}
static gboolean
draw_callback (GtkWidget *widget,
cairo_t *cr,
gpointer data)
{
RenderGradientFunc func = data;
GtkStyleContext *style;
GdkRGBA color;
style = gtk_widget_get_style_context (widget);
gtk_style_context_save (style);
gtk_style_context_set_state (style, gtk_widget_get_state_flags (widget));
gtk_style_context_lookup_color (style, "foreground-color", &color);
gtk_style_context_restore (style);
gdk_cairo_set_source_rgba (cr, &color);
(* func) (cr,
gtk_widget_get_allocated_width (widget),
gtk_widget_get_allocated_height (widget));
return FALSE;
}
static GtkWidget*
create_gradient_window (const char *title,
RenderGradientFunc func)
{
GtkWidget *window;
GtkWidget *drawing_area;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), title);
drawing_area = gtk_drawing_area_new ();
gtk_widget_set_size_request (drawing_area, 1, 1);
gtk_window_set_default_size (GTK_WINDOW (window), 175, 175);
g_signal_connect (G_OBJECT (drawing_area),
"draw",
G_CALLBACK (draw_callback),
func);
gtk_container_add (GTK_CONTAINER (window), drawing_area);
gtk_widget_show_all (window);
return window;
}
static void
meta_gradient_test (void)
{
create_gradient_window ("Simple vertical",
render_vertical_func);
create_gradient_window ("Simple horizontal",
render_horizontal_func);
create_gradient_window ("Simple diagonal",
render_diagonal_func);
create_gradient_window ("Multi vertical",
render_vertical_multi_func);
create_gradient_window ("Multi horizontal",
render_horizontal_multi_func);
create_gradient_window ("Multi diagonal",
render_diagonal_multi_func);
create_gradient_window ("Interwoven",
render_interwoven_func);
create_gradient_window ("Simple diagonal with horizontal multi alpha",
render_diagonal_alpha_func);
}
int
main (int argc, char **argv)
{
gtk_init (&argc, &argv);
meta_gradient_test ();
gtk_main ();
return 0;
}

View File

@ -774,6 +774,9 @@ parse_alpha (const char *str,
n_alphas = i;
/* FIXME allow specifying horizontal/vertical/diagonal in theme format,
* once we implement vertical/diagonal in gradient.c
*/
spec = meta_alpha_gradient_spec_new (META_GRADIENT_HORIZONTAL,
n_alphas);
@ -2147,9 +2150,11 @@ parse_draw_op_element (GMarkupParseContext *context,
const char *width;
const char *height;
const char *alpha;
const char *colorize;
const char *fill_type;
MetaAlphaGradientSpec *alpha_spec;
GdkPixbuf *pixbuf;
MetaColorSpec *colorize_spec = NULL;
MetaImageFillType fill_type_val;
int h, w, c;
int pixbuf_width, pixbuf_height, pixbuf_n_channels, pixbuf_rowstride;
@ -2160,6 +2165,7 @@ parse_draw_op_element (GMarkupParseContext *context,
"!x", &x, "!y", &y,
"!width", &width, "!height", &height,
"alpha", &alpha, "!filename", &filename,
"colorize", &colorize,
"fill_type", &fill_type,
NULL))
return;
@ -2205,6 +2211,18 @@ parse_draw_op_element (GMarkupParseContext *context,
return;
}
if (colorize)
{
colorize_spec = parse_color (info->theme, colorize, error);
if (colorize_spec == NULL)
{
add_context_to_error (error, context);
g_object_unref (G_OBJECT (pixbuf));
return;
}
}
alpha_spec = NULL;
if (alpha && !parse_alpha (alpha, &alpha_spec, context, error))
{
@ -2215,6 +2233,7 @@ parse_draw_op_element (GMarkupParseContext *context,
op = meta_draw_op_new (META_DRAW_IMAGE);
op->data.image.pixbuf = pixbuf;
op->data.image.colorize_spec = colorize_spec;
op->data.image.x = meta_draw_spec_new (info->theme, x, NULL);
op->data.image.y = meta_draw_spec_new (info->theme, y, NULL);

View File

@ -23,6 +23,7 @@
#define META_THEME_PRIVATE_H
#include <meta/boxes.h>
#include <meta/gradient.h>
#include <meta/theme.h>
#include <meta/common.h>
#include <gtk/gtk.h>
@ -272,14 +273,6 @@ typedef enum
META_IMAGE_FILL_TILE
} MetaImageFillType;
typedef enum
{
META_GRADIENT_VERTICAL,
META_GRADIENT_HORIZONTAL,
META_GRADIENT_DIAGONAL,
META_GRADIENT_LAST
} MetaGradientType;
typedef enum
{
META_COLOR_SPEC_BASIC,
@ -545,6 +538,7 @@ struct _MetaDrawOp
} gradient;
struct {
MetaColorSpec *colorize_spec;
MetaAlphaGradientSpec *alpha_spec;
GdkPixbuf *pixbuf;
MetaDrawSpec *x;
@ -552,6 +546,8 @@ struct _MetaDrawOp
MetaDrawSpec *width;
MetaDrawSpec *height;
guint32 colorize_cache_pixel;
GdkPixbuf *colorize_cache_pixbuf;
MetaImageFillType fill_type;
unsigned int vertical_stripes : 1;
unsigned int horizontal_stripes : 1;
@ -976,12 +972,8 @@ gboolean meta_draw_op_list_contains (MetaDrawOpList *op_list,
MetaGradientSpec* meta_gradient_spec_new (MetaGradientType type);
void meta_gradient_spec_free (MetaGradientSpec *desc);
void meta_gradient_spec_render (const MetaGradientSpec *spec,
const MetaAlphaGradientSpec *alpha_spec,
cairo_t *cr,
GtkStyleContext *style,
int x,
int y,
GdkPixbuf* meta_gradient_spec_render (const MetaGradientSpec *desc,
GtkStyleContext *gtk_style,
int width,
int height);
gboolean meta_gradient_spec_validate (MetaGradientSpec *spec,

View File

@ -38,6 +38,7 @@
#include "theme-private.h"
#include "frames.h" /* for META_TYPE_FRAMES */
#include "util-private.h"
#include <meta/gradient.h>
#include <meta/prefs.h>
#include <gtk/gtk.h>
#include <string.h>
@ -74,6 +75,84 @@ static void hls_to_rgb (gdouble *h,
*/
static MetaTheme *meta_current_theme = NULL;
static GdkPixbuf *
colorize_pixbuf (GdkPixbuf *orig,
GdkRGBA *new_color)
{
GdkPixbuf *pixbuf;
double intensity;
int x, y;
const guchar *src;
guchar *dest;
int orig_rowstride;
int dest_rowstride;
int width, height;
gboolean has_alpha;
const guchar *src_pixels;
guchar *dest_pixels;
pixbuf = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (orig), gdk_pixbuf_get_has_alpha (orig),
gdk_pixbuf_get_bits_per_sample (orig),
gdk_pixbuf_get_width (orig), gdk_pixbuf_get_height (orig));
if (pixbuf == NULL)
return NULL;
orig_rowstride = gdk_pixbuf_get_rowstride (orig);
dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
has_alpha = gdk_pixbuf_get_has_alpha (orig);
src_pixels = gdk_pixbuf_get_pixels (orig);
dest_pixels = gdk_pixbuf_get_pixels (pixbuf);
for (y = 0; y < height; y++)
{
src = src_pixels + y * orig_rowstride;
dest = dest_pixels + y * dest_rowstride;
for (x = 0; x < width; x++)
{
double dr, dg, db;
intensity = INTENSITY (src[0], src[1], src[2]) / 255.0;
if (intensity <= 0.5)
{
/* Go from black at intensity = 0.0 to new_color at intensity = 0.5 */
dr = new_color->red * intensity * 2.0;
dg = new_color->green * intensity * 2.0;
db = new_color->blue * intensity * 2.0;
}
else
{
/* Go from new_color at intensity = 0.5 to white at intensity = 1.0 */
dr = new_color->red + (1.0 - new_color->red) * (intensity - 0.5) * 2.0;
dg = new_color->green + (1.0 - new_color->green) * (intensity - 0.5) * 2.0;
db = new_color->blue + (1.0 - new_color->blue) * (intensity - 0.5) * 2.0;
}
dest[0] = CLAMP_UCHAR (255 * dr);
dest[1] = CLAMP_UCHAR (255 * dg);
dest[2] = CLAMP_UCHAR (255 * db);
if (has_alpha)
{
dest[3] = src[3];
src += 4;
dest += 4;
}
else
{
src += 3;
dest += 3;
}
}
}
return pixbuf;
}
static void
color_composite (const GdkRGBA *bg,
const GdkRGBA *fg,
@ -931,84 +1010,42 @@ meta_gradient_spec_free (MetaGradientSpec *spec)
g_free (spec);
}
static cairo_pattern_t *
meta_gradient_spec_pattern (const MetaGradientSpec *spec,
const MetaAlphaGradientSpec *alpha_spec,
GtkStyleContext *style)
GdkPixbuf*
meta_gradient_spec_render (const MetaGradientSpec *spec,
GtkStyleContext *style,
int width,
int height)
{
cairo_pattern_t *pattern;
int n_colors;
GSList *l;
GdkRGBA *colors;
GSList *tmp;
int i;
if (spec->type == META_GRADIENT_HORIZONTAL)
pattern = cairo_pattern_create_linear (0, 0, 1, 0);
if (spec->type == META_GRADIENT_VERTICAL)
pattern = cairo_pattern_create_linear (0, 0, 0, 1);
else if (spec->type == META_GRADIENT_DIAGONAL)
pattern = cairo_pattern_create_linear (0, 0, 1, 1);
else
g_assert_not_reached ();
GdkPixbuf *pixbuf;
n_colors = g_slist_length (spec->color_specs);
if (n_colors == 0)
return NULL;
if (alpha_spec != NULL)
g_assert (n_colors == alpha_spec->n_alphas);
colors = g_new (GdkRGBA, n_colors);
i = 0;
for (l = spec->color_specs; l != NULL; l = l->next)
tmp = spec->color_specs;
while (tmp != NULL)
{
MetaColorSpec *color_spec = l->data;
GdkRGBA color;
meta_color_spec_render (tmp->data, style, &colors[i]);
meta_color_spec_render (color_spec, style, &color);
if (alpha_spec != NULL)
color.alpha *= alpha_spec->alphas[i];
cairo_pattern_add_color_stop_rgba (pattern,
i / (float) n_colors,
color.red,
color.green,
color.blue,
color.alpha);
tmp = tmp->next;
++i;
}
return pattern;
}
pixbuf = meta_gradient_create_multi (width, height,
colors, n_colors,
spec->type);
void
meta_gradient_spec_render (const MetaGradientSpec *spec,
const MetaAlphaGradientSpec *alpha_spec,
cairo_t *cr,
GtkStyleContext *style,
int x,
int y,
int width,
int height)
{
cairo_pattern_t *pattern;
g_free (colors);
cairo_save (cr);
pattern = meta_gradient_spec_pattern (spec, alpha_spec, style);
if (pattern == NULL)
return;
cairo_rectangle (cr, x, y, width, height);
cairo_translate (cr, x, y);
cairo_scale (cr, width, height);
cairo_set_source (cr, pattern);
cairo_fill (cr);
cairo_pattern_destroy (pattern);
cairo_restore (cr);
return pixbuf;
}
gboolean
@ -3015,6 +3052,12 @@ meta_draw_op_free (MetaDrawOp *op)
if (op->data.image.pixbuf)
g_object_unref (G_OBJECT (op->data.image.pixbuf));
if (op->data.image.colorize_spec)
meta_color_spec_free (op->data.image.colorize_spec);
if (op->data.image.colorize_cache_pixbuf)
g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf));
meta_draw_spec_free (op->data.image.x);
meta_draw_spec_free (op->data.image.y);
meta_draw_spec_free (op->data.image.width);
@ -3089,6 +3132,413 @@ meta_draw_op_free (MetaDrawOp *op)
g_free (op);
}
static GdkPixbuf*
apply_alpha (GdkPixbuf *pixbuf,
MetaAlphaGradientSpec *spec,
gboolean force_copy)
{
GdkPixbuf *new_pixbuf;
gboolean needs_alpha;
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
needs_alpha = spec && (spec->n_alphas > 1 ||
spec->alphas[0] != 0xff);
if (!needs_alpha)
return pixbuf;
if (!gdk_pixbuf_get_has_alpha (pixbuf))
{
new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
g_object_unref (G_OBJECT (pixbuf));
pixbuf = new_pixbuf;
}
else if (force_copy)
{
new_pixbuf = gdk_pixbuf_copy (pixbuf);
g_object_unref (G_OBJECT (pixbuf));
pixbuf = new_pixbuf;
}
g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
meta_gradient_add_alpha (pixbuf, spec->alphas, spec->n_alphas, spec->type);
return pixbuf;
}
static GdkPixbuf*
pixbuf_tile (GdkPixbuf *tile,
int width,
int height)
{
GdkPixbuf *pixbuf;
int tile_width;
int tile_height;
int i, j;
tile_width = gdk_pixbuf_get_width (tile);
tile_height = gdk_pixbuf_get_height (tile);
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
gdk_pixbuf_get_has_alpha (tile),
8, width, height);
i = 0;
while (i < width)
{
j = 0;
while (j < height)
{
int w, h;
w = MIN (tile_width, width - i);
h = MIN (tile_height, height - j);
gdk_pixbuf_copy_area (tile,
0, 0,
w, h,
pixbuf,
i, j);
j += tile_height;
}
i += tile_width;
}
return pixbuf;
}
static GdkPixbuf *
replicate_rows (GdkPixbuf *src,
int src_x,
int src_y,
int width,
int height)
{
unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
* n_channels);
unsigned char *dest_pixels;
GdkPixbuf *result;
unsigned int dest_rowstride;
int i;
result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
width, height);
dest_rowstride = gdk_pixbuf_get_rowstride (result);
dest_pixels = gdk_pixbuf_get_pixels (result);
for (i = 0; i < height; i++)
memcpy (dest_pixels + dest_rowstride * i, pixels, n_channels * width);
return result;
}
static GdkPixbuf *
replicate_cols (GdkPixbuf *src,
int src_x,
int src_y,
int width,
int height)
{
unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
* n_channels);
unsigned char *dest_pixels;
GdkPixbuf *result;
unsigned int dest_rowstride;
int i, j;
result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
width, height);
dest_rowstride = gdk_pixbuf_get_rowstride (result);
dest_pixels = gdk_pixbuf_get_pixels (result);
for (i = 0; i < height; i++)
{
unsigned char *p = dest_pixels + dest_rowstride * i;
unsigned char *q = pixels + src_rowstride * i;
unsigned char r = *(q++);
unsigned char g = *(q++);
unsigned char b = *(q++);
if (n_channels == 4)
{
unsigned char a;
a = *(q++);
for (j = 0; j < width; j++)
{
*(p++) = r;
*(p++) = g;
*(p++) = b;
*(p++) = a;
}
}
else
{
for (j = 0; j < width; j++)
{
*(p++) = r;
*(p++) = g;
*(p++) = b;
}
}
}
return result;
}
static GdkPixbuf*
scale_and_alpha_pixbuf (GdkPixbuf *src,
MetaAlphaGradientSpec *alpha_spec,
MetaImageFillType fill_type,
int width,
int height,
gboolean vertical_stripes,
gboolean horizontal_stripes)
{
GdkPixbuf *pixbuf;
GdkPixbuf *temp_pixbuf;
pixbuf = NULL;
pixbuf = src;
if (gdk_pixbuf_get_width (pixbuf) == width &&
gdk_pixbuf_get_height (pixbuf) == height)
{
g_object_ref (G_OBJECT (pixbuf));
}
else
{
if (fill_type == META_IMAGE_FILL_TILE)
{
pixbuf = pixbuf_tile (pixbuf, width, height);
}
else
{
int src_h, src_w, dest_h, dest_w;
src_h = gdk_pixbuf_get_height (src);
src_w = gdk_pixbuf_get_width (src);
/* prefer to replicate_cols if possible, as that
* is faster (no memory reads)
*/
if (horizontal_stripes)
{
dest_w = gdk_pixbuf_get_width (src);
dest_h = height;
}
else if (vertical_stripes)
{
dest_w = width;
dest_h = gdk_pixbuf_get_height (src);
}
else
{
dest_w = width;
dest_h = height;
}
if (dest_w == src_w && dest_h == src_h)
{
temp_pixbuf = src;
g_object_ref (G_OBJECT (temp_pixbuf));
}
else
{
temp_pixbuf = gdk_pixbuf_scale_simple (src,
dest_w, dest_h,
GDK_INTERP_BILINEAR);
}
/* prefer to replicate_cols if possible, as that
* is faster (no memory reads)
*/
if (horizontal_stripes)
{
pixbuf = replicate_cols (temp_pixbuf, 0, 0, width, height);
g_object_unref (G_OBJECT (temp_pixbuf));
}
else if (vertical_stripes)
{
pixbuf = replicate_rows (temp_pixbuf, 0, 0, width, height);
g_object_unref (G_OBJECT (temp_pixbuf));
}
else
{
pixbuf = temp_pixbuf;
}
}
}
if (pixbuf)
pixbuf = apply_alpha (pixbuf, alpha_spec, pixbuf == src);
return pixbuf;
}
static GdkPixbuf*
draw_op_as_pixbuf (const MetaDrawOp *op,
GtkStyleContext *context,
const MetaDrawInfo *info,
int width,
int height)
{
/* Try to get the op as a pixbuf, assuming w/h in the op
* matches the width/height passed in. return NULL
* if the op can't be converted to an equivalent pixbuf.
*/
GdkPixbuf *pixbuf;
pixbuf = NULL;
switch (op->type)
{
case META_DRAW_TINT:
{
GdkRGBA color;
guint32 rgba;
gboolean has_alpha;
meta_color_spec_render (op->data.rectangle.color_spec,
context,
&color);
has_alpha =
op->data.tint.alpha_spec &&
(op->data.tint.alpha_spec->n_alphas > 1 ||
op->data.tint.alpha_spec->alphas[0] != 0xff);
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
has_alpha,
8, width, height);
if (!has_alpha)
{
rgba = GDK_COLOR_RGBA (color);
gdk_pixbuf_fill (pixbuf, rgba);
}
else if (op->data.tint.alpha_spec->n_alphas == 1)
{
rgba = GDK_COLOR_RGBA (color);
rgba &= ~0xff;
rgba |= op->data.tint.alpha_spec->alphas[0];
gdk_pixbuf_fill (pixbuf, rgba);
}
else
{
rgba = GDK_COLOR_RGBA (color);
gdk_pixbuf_fill (pixbuf, rgba);
meta_gradient_add_alpha (pixbuf,
op->data.tint.alpha_spec->alphas,
op->data.tint.alpha_spec->n_alphas,
op->data.tint.alpha_spec->type);
}
}
break;
case META_DRAW_GRADIENT:
{
pixbuf = meta_gradient_spec_render (op->data.gradient.gradient_spec,
context, width, height);
pixbuf = apply_alpha (pixbuf,
op->data.gradient.alpha_spec,
FALSE);
}
break;
case META_DRAW_IMAGE:
{
if (op->data.image.colorize_spec)
{
GdkRGBA color;
meta_color_spec_render (op->data.image.colorize_spec,
context, &color);
if (op->data.image.colorize_cache_pixbuf == NULL ||
op->data.image.colorize_cache_pixel != GDK_COLOR_RGB (color))
{
if (op->data.image.colorize_cache_pixbuf)
g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf));
/* const cast here */
((MetaDrawOp*)op)->data.image.colorize_cache_pixbuf =
colorize_pixbuf (op->data.image.pixbuf,
&color);
((MetaDrawOp*)op)->data.image.colorize_cache_pixel =
GDK_COLOR_RGB (color);
}
if (op->data.image.colorize_cache_pixbuf)
{
pixbuf = scale_and_alpha_pixbuf (op->data.image.colorize_cache_pixbuf,
op->data.image.alpha_spec,
op->data.image.fill_type,
width, height,
op->data.image.vertical_stripes,
op->data.image.horizontal_stripes);
}
}
else
{
pixbuf = scale_and_alpha_pixbuf (op->data.image.pixbuf,
op->data.image.alpha_spec,
op->data.image.fill_type,
width, height,
op->data.image.vertical_stripes,
op->data.image.horizontal_stripes);
}
break;
}
case META_DRAW_ICON:
if (info->mini_icon &&
width <= gdk_pixbuf_get_width (info->mini_icon) &&
height <= gdk_pixbuf_get_height (info->mini_icon))
pixbuf = scale_and_alpha_pixbuf (info->mini_icon,
op->data.icon.alpha_spec,
op->data.icon.fill_type,
width, height,
FALSE, FALSE);
else if (info->icon)
pixbuf = scale_and_alpha_pixbuf (info->icon,
op->data.icon.alpha_spec,
op->data.icon.fill_type,
width, height,
FALSE, FALSE);
break;
case META_DRAW_LINE:
case META_DRAW_RECTANGLE:
case META_DRAW_ARC:
case META_DRAW_CLIP:
case META_DRAW_GTK_ARROW:
case META_DRAW_GTK_BOX:
case META_DRAW_GTK_VLINE:
case META_DRAW_TITLE:
case META_DRAW_OP_LIST:
case META_DRAW_TILE:
break;
}
return pixbuf;
}
static void
fill_env (MetaPositionExprEnv *env,
const MetaDrawInfo *info,
@ -3128,86 +3578,6 @@ fill_env (MetaPositionExprEnv *env,
env->theme = meta_current_theme;
}
static cairo_pattern_t *
meta_alpha_gradient_spec_pattern (const MetaAlphaGradientSpec *alpha_spec)
{
/* Hardcoded in theme-parser.c */
g_assert (alpha_spec->type == META_GRADIENT_HORIZONTAL);
int n_alphas = alpha_spec->n_alphas;
if (n_alphas == 0)
return NULL;
else if (n_alphas == 1)
return cairo_pattern_create_rgba (0, 0, 0, alpha_spec->alphas[0]);
else
{
cairo_pattern_t *pattern = cairo_pattern_create_linear (0, 0, 1, 0);
int i;
for (i = 0; i < n_alphas; i++)
cairo_pattern_add_color_stop_rgba (pattern,
i / (float) n_alphas,
0, 0, 0, alpha_spec->alphas[i]);
return pattern;
}
}
static void
draw_image (cairo_t *cr,
GdkPixbuf *src,
MetaImageFillType fill_type,
MetaAlphaGradientSpec *alpha_spec,
int x,
int y,
int width,
int height)
{
cairo_save (cr);
cairo_rectangle (cr, x, y, width, height);
if (fill_type == META_IMAGE_FILL_TILE)
{
gdk_cairo_set_source_pixbuf (cr, src, 0, 0);
cairo_pattern_set_extend (cairo_get_source (cr),
CAIRO_EXTEND_REPEAT);
}
else
{
float pixbuf_width, pixbuf_height;
pixbuf_width = gdk_pixbuf_get_width (src);
pixbuf_height = gdk_pixbuf_get_height (src);
cairo_save (cr);
cairo_translate (cr, x, y);
cairo_scale (cr,
pixbuf_width / width,
pixbuf_height / height);
gdk_cairo_set_source_pixbuf (cr, src, 0, 0);
cairo_restore (cr);
}
if (alpha_spec)
{
cairo_translate (cr, x, y);
cairo_scale (cr, width, height);
cairo_pattern_t *pattern = meta_alpha_gradient_spec_pattern (alpha_spec);
cairo_mask (cr, pattern);
cairo_pattern_destroy (pattern);
}
else
{
cairo_fill (cr);
}
cairo_restore (cr);
}
/* This code was originally rendering anti-aliased using X primitives, and
* now has been switched to draw anti-aliased using cairo. In general, the
@ -3231,6 +3601,7 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
GdkRGBA color;
cairo_save (cr);
gtk_style_context_save (style_gtk);
cairo_set_line_width (cr, 1.0);
@ -3388,63 +3759,94 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
case META_DRAW_TINT:
{
int rx, ry, rwidth, rheight;
gboolean needs_alpha;
needs_alpha = op->data.tint.alpha_spec &&
(op->data.tint.alpha_spec->n_alphas > 1 ||
op->data.tint.alpha_spec->alphas[0] != 0xff);
rx = parse_x_position_unchecked (op->data.tint.x, env);
ry = parse_y_position_unchecked (op->data.tint.y, env);
rwidth = parse_size_unchecked (op->data.tint.width, env);
rheight = parse_size_unchecked (op->data.tint.height, env);
meta_color_spec_render (op->data.tint.color_spec,
style_gtk, &color);
if (!needs_alpha)
{
meta_color_spec_render (op->data.tint.color_spec,
style_gtk, &color);
gdk_cairo_set_source_rgba (cr, &color);
if (op->data.tint.alpha_spec &&
op->data.tint.alpha_spec->n_alphas == 1)
color.alpha = op->data.tint.alpha_spec->alphas[0];
cairo_rectangle (cr, rx, ry, rwidth, rheight);
cairo_fill (cr);
}
else
{
GdkPixbuf *pixbuf;
gdk_cairo_set_source_rgba (cr, &color);
pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
rwidth, rheight);
cairo_rectangle (cr, rx, ry, rwidth, rheight);
cairo_fill (cr);
if (pixbuf)
{
gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
cairo_paint (cr);
g_object_unref (G_OBJECT (pixbuf));
}
}
}
break;
case META_DRAW_GRADIENT:
{
int rx, ry, rwidth, rheight;
GdkPixbuf *pixbuf;
rx = parse_x_position_unchecked (op->data.gradient.x, env);
ry = parse_y_position_unchecked (op->data.gradient.y, env);
rwidth = parse_size_unchecked (op->data.gradient.width, env);
rheight = parse_size_unchecked (op->data.gradient.height, env);
meta_gradient_spec_render (op->data.gradient.gradient_spec,
op->data.gradient.alpha_spec,
cr, style_gtk,
rx, ry, rwidth, rheight);
pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
rwidth, rheight);
if (pixbuf)
{
gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
cairo_paint (cr);
g_object_unref (G_OBJECT (pixbuf));
}
}
break;
case META_DRAW_IMAGE:
{
int rx, ry, rwidth, rheight;
GdkPixbuf *pixbuf;
if (op->data.image.pixbuf == NULL)
break;
env->object_width = gdk_pixbuf_get_width (op->data.image.pixbuf);
env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf);
rx = parse_x_position_unchecked (op->data.image.x, env);
ry = parse_y_position_unchecked (op->data.image.y, env);
if (op->data.image.pixbuf)
{
env->object_width = gdk_pixbuf_get_width (op->data.image.pixbuf);
env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf);
}
rwidth = parse_size_unchecked (op->data.image.width, env);
rheight = parse_size_unchecked (op->data.image.height, env);
draw_image (cr,
op->data.image.pixbuf,
op->data.image.fill_type,
op->data.image.alpha_spec,
rx, ry, rwidth, rheight);
pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
rwidth, rheight);
if (pixbuf)
{
rx = parse_x_position_unchecked (op->data.image.x, env);
ry = parse_y_position_unchecked (op->data.image.y, env);
gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
cairo_paint (cr);
g_object_unref (G_OBJECT (pixbuf));
}
}
break;
@ -3514,27 +3916,24 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
case META_DRAW_ICON:
{
int rx, ry, rwidth, rheight;
GdkPixbuf *src;
GdkPixbuf *pixbuf;
rwidth = parse_size_unchecked (op->data.icon.width, env);
rheight = parse_size_unchecked (op->data.icon.height, env);
if (info->mini_icon &&
rwidth < gdk_pixbuf_get_width (info->mini_icon) &&
rheight < gdk_pixbuf_get_height (info->mini_icon))
src = info->mini_icon;
else if (info->icon)
src = info->icon;
else
break;
pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
rwidth, rheight);
rx = parse_x_position_unchecked (op->data.icon.x, env);
ry = parse_y_position_unchecked (op->data.icon.y, env);
if (pixbuf)
{
rx = parse_x_position_unchecked (op->data.icon.x, env);
ry = parse_y_position_unchecked (op->data.icon.y, env);
draw_image (cr, src,
op->data.icon.fill_type,
op->data.icon.alpha_spec,
rx, ry, rwidth, rheight);
gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
cairo_paint (cr);
g_object_unref (G_OBJECT (pixbuf));
}
}
break;
@ -3654,6 +4053,7 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
}
cairo_restore (cr);
gtk_style_context_restore (style_gtk);
}
void

View File

@ -547,16 +547,9 @@ data_device_set_selection (struct wl_client *client,
meta_wayland_data_device_set_selection (data_device, source, serial);
}
static void
data_device_release(struct wl_client *client, struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
static const struct wl_data_device_interface data_device_interface = {
data_device_start_drag,
data_device_set_selection,
data_device_release,
};
static void

View File

@ -75,14 +75,6 @@ compute_scale (MetaOutput *output)
output->crtc->rect.width >= SMALLEST_4K_WIDTH)
goto out;
/* Somebody encoded the aspect ratio (16/9 or 16/10)
* instead of the physical size */
if ((output->width_mm == 160 && output->height_mm == 90) ||
(output->width_mm == 160 && output->height_mm == 100) ||
(output->width_mm == 16 && output->height_mm == 9) ||
(output->width_mm == 16 && output->height_mm == 10))
goto out;
if (output->width_mm > 0 && output->height_mm > 0)
{
double dpi_x, dpi_y;

View File

@ -65,33 +65,6 @@ unbind_resource (struct wl_resource *resource)
wl_list_remove (wl_resource_get_link (resource));
}
static void
sync_focus_surface (MetaWaylandPointer *pointer)
{
MetaDisplay *display = meta_get_display ();
switch (display->event_route)
{
case META_EVENT_ROUTE_WINDOW_OP:
case META_EVENT_ROUTE_COMPOSITOR_GRAB:
/* The compositor has a grab, so remove our focus... */
meta_wayland_pointer_set_focus (pointer, NULL);
break;
case META_EVENT_ROUTE_NORMAL:
case META_EVENT_ROUTE_WAYLAND_POPUP:
{
const MetaWaylandPointerGrabInterface *interface = pointer->grab->interface;
interface->focus (pointer->grab, pointer->current);
}
break;
default:
g_assert_not_reached ();
}
}
static void
set_cursor_surface (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface)
@ -206,7 +179,7 @@ default_grab_button (MetaWaylandPointerGrab *grab,
}
if (pointer->button_count == 0 && event_type == CLUTTER_BUTTON_RELEASE)
sync_focus_surface (pointer);
meta_wayland_pointer_set_focus (pointer, pointer->current);
}
static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = {
@ -274,6 +247,36 @@ count_buttons (const ClutterEvent *event)
return count;
}
static void
sync_focus_surface (MetaWaylandPointer *pointer)
{
MetaDisplay *display = meta_get_display ();
MetaWaylandSurface *focus_surface;
switch (display->event_route)
{
case META_EVENT_ROUTE_WINDOW_OP:
/* Don't update the focus surface while we're grabbing a window. */
return;
case META_EVENT_ROUTE_COMPOSITOR_GRAB:
/* The compositor has focus, so remove our focus... */
focus_surface = NULL;
break;
case META_EVENT_ROUTE_NORMAL:
case META_EVENT_ROUTE_WAYLAND_POPUP:
focus_surface = pointer->current;
break;
default:
g_assert_not_reached ();
}
const MetaWaylandPointerGrabInterface *interface = pointer->grab->interface;
interface->focus (pointer->grab, focus_surface);
}
static void
repick_for_event (MetaWaylandPointer *pointer,
const ClutterEvent *for_event)
@ -304,7 +307,6 @@ repick_for_event (MetaWaylandPointer *pointer,
pointer->current = NULL;
sync_focus_surface (pointer);
meta_wayland_pointer_update_cursor_surface (pointer);
}
void
@ -516,11 +518,10 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
clutter_input_device_get_coords (pointer->device, NULL, &pos);
if (pointer->focus_surface->window)
meta_window_handle_enter (pointer->focus_surface->window,
/* XXX -- can we reliably get a timestamp for setting focus? */
clutter_get_current_event_time (),
pos.x, pos.y);
meta_window_handle_enter (pointer->focus_surface->window,
/* XXX -- can we reliably get a timestamp for setting focus? */
clutter_get_current_event_time (),
pos.x, pos.y);
move_resources_for_client (&pointer->focus_resource_list,
&pointer->resource_list,

View File

@ -36,7 +36,7 @@
/* Global/master objects (version exported by wl_registry and negotiated through bind) */
#define META_WL_COMPOSITOR_VERSION 3
#define META_WL_DATA_DEVICE_MANAGER_VERSION 2
#define META_WL_DATA_DEVICE_MANAGER_VERSION 1
#define META_XDG_SHELL_VERSION 1
#define META_WL_SHELL_VERSION 1
#define META_WL_SEAT_VERSION 4

View File

@ -1073,9 +1073,10 @@ meta_window_x11_move_resize_internal (MetaWindow *window,
/* Compute new frame size */
new_w = window->rect.width + borders.invisible.left + borders.invisible.right;
new_h = borders.invisible.top + borders.invisible.bottom;
if (!window->shaded)
new_h += window->rect.height;
if (window->shaded)
new_h = borders.total.top + borders.total.bottom;
else
new_h = window->rect.height + borders.invisible.top + borders.invisible.bottom;
if (new_w != window->frame->rect.width ||
new_h != window->frame->rect.height)