Compare commits
47 Commits
3.34.4
...
gnome-3-34
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a416bed34c | ||
|
|
80c0a470e7 | ||
|
|
8802f7f0d8 | ||
|
|
8b3f1117be | ||
|
|
48ffbb5824 | ||
|
|
129d134704 | ||
|
|
4078ba1828 | ||
|
|
fd8ccbac82 | ||
|
|
93417d0ceb | ||
|
|
3bafd23424 | ||
|
|
e328fcc379 | ||
|
|
e845bbd579 | ||
|
|
025730349d | ||
|
|
f6d0af0c93 | ||
|
|
8acff5309d | ||
|
|
0ab8b17433 | ||
|
|
50f383d2e9 | ||
|
|
7fbba4ad14 | ||
|
|
eb6189d6b6 | ||
|
|
668d13ffb5 | ||
|
|
02947e7872 | ||
|
|
ebfe5e44c2 | ||
|
|
8f64b3dcad | ||
|
|
8de5b95123 | ||
|
|
cedab9442f | ||
|
|
7cc5ed96fc | ||
|
|
bb831f04c5 | ||
|
|
c92267feb2 | ||
|
|
8240aba80f | ||
|
|
5f34a0f245 | ||
|
|
83eeb3dbd2 | ||
|
|
c25011ffba | ||
|
|
abd67819fe | ||
|
|
6f3b7b733a | ||
|
|
e2c61f2739 | ||
|
|
1a3dfd8110 | ||
|
|
aeb781acd6 | ||
|
|
092591b872 | ||
|
|
57992f37cc | ||
|
|
7655a63af6 | ||
|
|
a5b5e95ad9 | ||
|
|
11da42b2f8 | ||
|
|
2709a4ffb1 | ||
|
|
c65db40178 | ||
|
|
011ff15603 | ||
|
|
c3d2f3f399 | ||
|
|
053bb5901a |
27
NEWS
27
NEWS
@@ -1,3 +1,30 @@
|
||||
3.34.6
|
||||
======
|
||||
* Fix various clipboard issues [Carlos; !1198, !1203, !1204, !1186, !1206]
|
||||
* Fix locate-pointer feature interfering with keybindings [Carlos; !1014]
|
||||
* Fix overview key on X11 when using multiple keyboard layouts [Olivier; !1219]
|
||||
* Preserve keyboard state on VT switch [Olivier; !1185]
|
||||
* Fixed crashes [Florian; #1083]
|
||||
* Plugged memory leaks [Sebastian; !1001]
|
||||
* Misc. bug fixes and cleanups [Pekka, Laurent; !1209, #1074]
|
||||
|
||||
Contributors:
|
||||
Laurent Bigonville, Olivier Fourdan, Carlos Garnacho, Sebastian Keller,
|
||||
Florian Müllner, Pekka Paalanen
|
||||
|
||||
3.34.5
|
||||
======
|
||||
* Fix visibility of initially hidden windows [Jonas; !1066]
|
||||
* Fix hardware cursor on GPU hotplug [Pekka; !1097]
|
||||
* Fix pasting images from wayland [Robert, Carlos; !1141, #1065]
|
||||
* Fixed crashes [Florian, Olivier, Jonas; #1029, !1073, !1121, !1120]
|
||||
|
||||
Contributors:
|
||||
Olivier Fourdan, Carlos Garnacho, Robert Mader, Florian Müllner,
|
||||
Pekka Paalanen, Jonas Ådahl
|
||||
|
||||
Translators:
|
||||
Yi-Jyun Pan [zh_TW]
|
||||
3.34.4
|
||||
======
|
||||
* Handle mode set race conditions more gracefully [Jonas; !1007]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
project('mutter', 'c',
|
||||
version: '3.34.4',
|
||||
version: '3.34.6',
|
||||
meson_version: '>= 0.50.0',
|
||||
license: 'GPLv2+'
|
||||
)
|
||||
|
||||
158
po/zh_TW.po
158
po/zh_TW.po
@@ -10,8 +10,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: metacity 3.3.4\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/mutter/issues\n"
|
||||
"POT-Creation-Date: 2019-02-04 17:52+0000\n"
|
||||
"PO-Revision-Date: 2019-02-17 23:15+0800\n"
|
||||
"POT-Creation-Date: 2019-11-21 15:22+0000\n"
|
||||
"PO-Revision-Date: 2019-11-23 13:58+0800\n"
|
||||
"Last-Translator: pan93412 <pan93412@gmail.com>\n"
|
||||
"Language-Team: Chinese <zh-l10n@linux.org.tw>\n"
|
||||
"Language: zh_TW\n"
|
||||
@@ -19,7 +19,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Generator: Lokalize 18.12.2\n"
|
||||
"X-Generator: Lokalize 19.11.80\n"
|
||||
|
||||
#: data/50-mutter-navigation.xml:6
|
||||
msgid "Navigation"
|
||||
@@ -371,6 +371,16 @@ msgid "Enable experimental features"
|
||||
msgstr "啟用試驗性功能"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:108
|
||||
#| msgid ""
|
||||
#| "To enable experimental features, add the feature keyword to the list. "
|
||||
#| "Whether the feature requires restarting the compositor depends on the "
|
||||
#| "given feature. Any experimental feature is not required to still be "
|
||||
#| "available, or configurable. Don’t expect adding anything in this setting "
|
||||
#| "to be future proof. Currently possible keywords: • “scale-monitor-"
|
||||
#| "framebuffer” — makes mutter default to layout logical monitors in a "
|
||||
#| "logical pixel coordinate space, while scaling monitor framebuffers "
|
||||
#| "instead of window content, to manage HiDPI monitors. Does not require a "
|
||||
#| "restart."
|
||||
msgid ""
|
||||
"To enable experimental features, add the feature keyword to the list. "
|
||||
"Whether the feature requires restarting the compositor depends on the given "
|
||||
@@ -379,27 +389,41 @@ msgid ""
|
||||
"proof. Currently possible keywords: • “scale-monitor-framebuffer” — makes "
|
||||
"mutter default to layout logical monitors in a logical pixel coordinate "
|
||||
"space, while scaling monitor framebuffers instead of window content, to "
|
||||
"manage HiDPI monitors. Does not require a restart."
|
||||
"manage HiDPI monitors. Does not require a restart. • “rt-scheduler” — makes "
|
||||
"mutter request a low priority real-time scheduling. The executable or user "
|
||||
"must have CAP_SYS_NICE. Requires a restart. • “autostart-xwayland” — "
|
||||
"initializes Xwayland lazily if there are X11 clients. Requires restart."
|
||||
msgstr ""
|
||||
"若要啟用實驗性功能,請將功能關鍵字加入列表中。置於該功能是否須要重新啟動混成"
|
||||
"器則視給予的功能而定。任何實驗性功能不一定能用、或是可以調整設定。請不要預期"
|
||||
"在此設定中加入的任何東西未來都能存在。目前可用的關鍵字有: • “scale-monitor-"
|
||||
"framebuffer” — 讓 mutter 預設採用邏輯像素座標空間的配置邏輯螢幕,而縮放螢幕 "
|
||||
"framebuffer 則取代視窗內容以管理 HiDPI 螢幕。不須要重新啟動。"
|
||||
"在此設定中加入的任何東西未來都能存在。目前可用的關鍵字有:"
|
||||
"• 「scale-monitor-framebuffer」— 讓 mutter 預設採用邏輯像素座標空間的"
|
||||
"配置邏輯螢幕,而縮放螢幕 framebuffer 則取代視窗內容以管理 HiDPI 螢幕。不需要重新啟動。"
|
||||
"• 「rt-scheduler」— 讓 mutter 請求低優先級的即時排程。可執行檔或使用者必須要有"
|
||||
"CAP_SYS_NICE。需要重新啟動。"
|
||||
"• 「autostart-xwayland」— 如果有 X11 用戶端就延遲初始化 Xwayland。需要重新啟動。"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:141
|
||||
#: data/org.gnome.mutter.gschema.xml.in:134
|
||||
msgid "Modifier to use to locate the pointer"
|
||||
msgstr "要用來定位指標的輔助鍵"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:135
|
||||
msgid "This key will initiate the “locate pointer” action."
|
||||
msgstr "這個按鍵將會「定位指標」。"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:155
|
||||
msgid "Select window from tab popup"
|
||||
msgstr "從分頁彈出項選擇視窗"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:146
|
||||
#: data/org.gnome.mutter.gschema.xml.in:160
|
||||
msgid "Cancel tab popup"
|
||||
msgstr "取消分頁彈出項"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:151
|
||||
#: data/org.gnome.mutter.gschema.xml.in:165
|
||||
msgid "Switch monitor configurations"
|
||||
msgstr "切換螢幕組態"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:156
|
||||
#: data/org.gnome.mutter.gschema.xml.in:170
|
||||
msgid "Rotates the built-in monitor configuration"
|
||||
msgstr "旋轉切換內建螢幕組態"
|
||||
|
||||
@@ -456,26 +480,38 @@ msgid "Re-enable shortcuts"
|
||||
msgstr "重新啟用快捷鍵"
|
||||
|
||||
#: data/org.gnome.mutter.wayland.gschema.xml.in:64
|
||||
msgid "Allow grabs with Xwayland"
|
||||
msgstr "在 Xwayland 允許抓取"
|
||||
#| msgid "Allow grabs with Xwayland"
|
||||
msgid "Allow X11 grabs to lock keyboard focus with Xwayland"
|
||||
msgstr "允許 X11 抓取以使用 Xwayland 鎖定鍵盤焦點"
|
||||
|
||||
#: data/org.gnome.mutter.wayland.gschema.xml.in:65
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Allow keyboard grabs issued by X11 applications running in Xwayland to be "
|
||||
#| "taken into account. For a X11 grab to be taken into account under "
|
||||
#| "Wayland, the client must also either send a specific X11 ClientMessage to "
|
||||
#| "the root window or be among the applications white-listed in key "
|
||||
#| "“xwayland-grab-access-rules”."
|
||||
msgid ""
|
||||
"Allow keyboard grabs issued by X11 applications running in Xwayland to be "
|
||||
"taken into account. For a X11 grab to be taken into account under Wayland, "
|
||||
"the client must also either send a specific X11 ClientMessage to the root "
|
||||
"window or be among the applications white-listed in key “xwayland-grab-"
|
||||
"access-rules”."
|
||||
"Allow all keyboard events to be routed to X11 “override redirect” windows "
|
||||
"with a grab when running in Xwayland. This option is to support X11 clients "
|
||||
"which map an “override redirect” window (which do not receive keyboard "
|
||||
"focus) and issue a keyboard grab to force all keyboard events to that "
|
||||
"window. This option is seldom used and has no effect on regular X11 windows "
|
||||
"which can receive keyboard focus under normal circumstances. For a X11 grab "
|
||||
"to be taken into account under Wayland, the client must also either send a "
|
||||
"specific X11 ClientMessage to the root window or be among the applications "
|
||||
"white-listed in key “xwayland-grab-access-rules”."
|
||||
msgstr ""
|
||||
"考慮到在 Xwayland 中執行的 X11 應用程序發出的鍵盤抓取。對於在 Wayland 下考慮"
|
||||
"的 X11 抓取,客戶端也必須送出一個特定的 X11 ClientMessage 到 root 視窗或者在 "
|
||||
"xwayland-grab-access-rules 鍵白名單其中的應用程式。"
|
||||
"xwayland-grab-access-rules 鍵白名單其中的應用程式"
|
||||
|
||||
#: data/org.gnome.mutter.wayland.gschema.xml.in:77
|
||||
#: data/org.gnome.mutter.wayland.gschema.xml.in:84
|
||||
msgid "Xwayland applications allowed to issue keyboard grabs"
|
||||
msgstr "Xwayland 應用程式允許發出鍵盤抓取"
|
||||
|
||||
#: data/org.gnome.mutter.wayland.gschema.xml.in:78
|
||||
#: data/org.gnome.mutter.wayland.gschema.xml.in:85
|
||||
msgid ""
|
||||
"List the resource names or resource class of X11 windows either allowed or "
|
||||
"not allowed to issue X11 keyboard grabs under Xwayland. The resource name or "
|
||||
@@ -499,7 +535,7 @@ msgstr ""
|
||||
#. TRANSLATORS: This string refers to a button that switches between
|
||||
#. * different modes.
|
||||
#.
|
||||
#: src/backends/meta-input-settings.c:2423
|
||||
#: src/backends/meta-input-settings.c:2532
|
||||
#, c-format
|
||||
msgid "Mode Switch (Group %d)"
|
||||
msgstr "模式切換( 群組 %d)"
|
||||
@@ -507,121 +543,124 @@ msgstr "模式切換( 群組 %d)"
|
||||
#. TRANSLATORS: This string refers to an action, cycles drawing tablets'
|
||||
#. * mapping through the available outputs.
|
||||
#.
|
||||
#: src/backends/meta-input-settings.c:2446
|
||||
#: src/backends/meta-input-settings.c:2555
|
||||
msgid "Switch monitor"
|
||||
msgstr "切換螢幕"
|
||||
|
||||
#: src/backends/meta-input-settings.c:2448
|
||||
#: src/backends/meta-input-settings.c:2557
|
||||
msgid "Show on-screen help"
|
||||
msgstr "顯示螢幕求助"
|
||||
|
||||
#: src/backends/meta-monitor-manager.c:954
|
||||
#: src/backends/meta-monitor.c:223
|
||||
msgid "Built-in display"
|
||||
msgstr "內建顯示"
|
||||
|
||||
#: src/backends/meta-monitor-manager.c:986
|
||||
#: src/backends/meta-monitor.c:252
|
||||
msgid "Unknown"
|
||||
msgstr "不明"
|
||||
|
||||
#: src/backends/meta-monitor-manager.c:988
|
||||
#: src/backends/meta-monitor.c:254
|
||||
msgid "Unknown Display"
|
||||
msgstr "不明的顯示器"
|
||||
|
||||
#: src/backends/meta-monitor-manager.c:996
|
||||
#: src/backends/meta-monitor.c:262
|
||||
#, c-format
|
||||
#| msgid "%s %s"
|
||||
msgctxt ""
|
||||
"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'"
|
||||
msgid "%s %s"
|
||||
msgstr "%s %s"
|
||||
|
||||
#: src/backends/meta-monitor-manager.c:1004
|
||||
#: src/backends/meta-monitor.c:270
|
||||
#, c-format
|
||||
#| msgid "%s %s"
|
||||
msgctxt ""
|
||||
"This is a monitor vendor name followed by product/model name where size in "
|
||||
"inches could not be calculated, e.g. Dell U2414H"
|
||||
msgid "%s %s"
|
||||
msgstr "%s %s"
|
||||
|
||||
#. Translators: this string will appear in Sysprof
|
||||
#: src/backends/meta-profiler.c:82
|
||||
msgid "Compositor"
|
||||
msgstr "合成器"
|
||||
|
||||
# FIXME: I'm still unclear about the meaning of XGetSelectionOwner -- Abel
|
||||
#. 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:482
|
||||
#: src/compositor/compositor.c:509
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Another compositing manager is already running on screen %i on display “%s”."
|
||||
msgstr "在畫面「%2$s」中的第 %1$i 個螢幕中已啟動另一個組合視窗管理員。"
|
||||
|
||||
#: src/core/bell.c:252
|
||||
#: src/core/bell.c:192
|
||||
msgid "Bell event"
|
||||
msgstr "響鈴事件"
|
||||
|
||||
#: src/core/main.c:185
|
||||
#: src/core/main.c:190
|
||||
msgid "Disable connection to session manager"
|
||||
msgstr "停用到作業階段管理員的連線"
|
||||
|
||||
#: src/core/main.c:191
|
||||
#: src/core/main.c:196
|
||||
msgid "Replace the running window manager"
|
||||
msgstr "取代執行中的視窗管理員"
|
||||
|
||||
#: src/core/main.c:197
|
||||
#: src/core/main.c:202
|
||||
msgid "Specify session management ID"
|
||||
msgstr "指定作業階段管理 ID"
|
||||
|
||||
#: src/core/main.c:202
|
||||
#: src/core/main.c:207
|
||||
msgid "X Display to use"
|
||||
msgstr "使用的 X 畫面"
|
||||
|
||||
#: src/core/main.c:208
|
||||
#: src/core/main.c:213
|
||||
msgid "Initialize session from savefile"
|
||||
msgstr "以 savefile 初始化作業階段"
|
||||
|
||||
#: src/core/main.c:214
|
||||
#: src/core/main.c:219
|
||||
msgid "Make X calls synchronous"
|
||||
msgstr "使用同步方式調用 X 函式"
|
||||
|
||||
#: src/core/main.c:221
|
||||
#: src/core/main.c:226
|
||||
msgid "Run as a wayland compositor"
|
||||
msgstr "以 wayland 組合器執行"
|
||||
|
||||
#: src/core/main.c:227
|
||||
#: src/core/main.c:232
|
||||
msgid "Run as a nested compositor"
|
||||
msgstr "以巢狀組合器執行"
|
||||
|
||||
#: src/core/main.c:233
|
||||
#: src/core/main.c:238
|
||||
msgid "Run wayland compositor without starting Xwayland"
|
||||
msgstr "在不啟動 Xwayland 的情況下開啟 Wayland 合成器"
|
||||
|
||||
#: src/core/main.c:241
|
||||
#: src/core/main.c:246
|
||||
msgid "Run as a full display server, rather than nested"
|
||||
msgstr "以完全顯示伺服器執行,而非巢狀"
|
||||
|
||||
#: src/core/main.c:247
|
||||
#: src/core/main.c:252
|
||||
msgid "Run with X11 backend"
|
||||
msgstr "透過 X11 後端執行"
|
||||
|
||||
#. Translators: %s is a window title
|
||||
#: src/core/meta-close-dialog-default.c:150
|
||||
#: src/core/meta-close-dialog-default.c:151
|
||||
#, c-format
|
||||
msgid "“%s” is not responding."
|
||||
msgstr "「%s」沒有回應。"
|
||||
|
||||
#: src/core/meta-close-dialog-default.c:152
|
||||
#: src/core/meta-close-dialog-default.c:153
|
||||
msgid "Application is not responding."
|
||||
msgstr "應用程式沒有回應。"
|
||||
|
||||
#: src/core/meta-close-dialog-default.c:157
|
||||
#: src/core/meta-close-dialog-default.c:158
|
||||
msgid ""
|
||||
"You may choose to wait a short while for it to continue or force the "
|
||||
"application to quit entirely."
|
||||
msgstr "您可以選擇稍等一下讓它繼續,或者強制完全退出程式。"
|
||||
|
||||
#: src/core/meta-close-dialog-default.c:164
|
||||
#: src/core/meta-close-dialog-default.c:165
|
||||
msgid "_Force Quit"
|
||||
msgstr "強制退出(_F)"
|
||||
|
||||
#: src/core/meta-close-dialog-default.c:164
|
||||
#: src/core/meta-close-dialog-default.c:165
|
||||
msgid "_Wait"
|
||||
msgstr "等待(_W)"
|
||||
|
||||
@@ -648,21 +687,21 @@ msgid "Mutter plugin to use"
|
||||
msgstr "要使用的 Mutter 外掛程式"
|
||||
|
||||
# (Abel) take care of the same string in libwnck
|
||||
#: src/core/prefs.c:1786
|
||||
#: src/core/prefs.c:1849
|
||||
#, c-format
|
||||
msgid "Workspace %d"
|
||||
msgstr "工作區 %d"
|
||||
|
||||
#: src/core/util.c:121
|
||||
#: src/core/util.c:122
|
||||
msgid "Mutter was compiled without support for verbose mode\n"
|
||||
msgstr "編譯 Mutter 時並沒有加入詳細偵錯模式的支援\n"
|
||||
|
||||
#: src/wayland/meta-wayland-tablet-pad.c:567
|
||||
#: src/wayland/meta-wayland-tablet-pad.c:568
|
||||
#, c-format
|
||||
msgid "Mode Switch: Mode %d"
|
||||
msgstr "模式切換:模式 %d"
|
||||
|
||||
#: src/x11/meta-x11-display.c:666
|
||||
#: src/x11/meta-x11-display.c:679
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Display “%s” already has a window manager; try using the --replace option to "
|
||||
@@ -671,27 +710,32 @@ msgstr ""
|
||||
"畫面「%s」已經有了視窗管理員;請嘗試使用 --replace 選項來替換目前的視窗管理"
|
||||
"員。"
|
||||
|
||||
#: src/x11/meta-x11-display.c:1008
|
||||
#: src/x11/meta-x11-display.c:1040
|
||||
msgid "Failed to initialize GDK\n"
|
||||
msgstr "無法初始化 GDK\n"
|
||||
|
||||
#: src/x11/meta-x11-display.c:1032
|
||||
#: src/x11/meta-x11-display.c:1064
|
||||
#, c-format
|
||||
msgid "Failed to open X Window System display “%s”\n"
|
||||
msgstr "無法開啟 X Window 系統畫面「%s」\n"
|
||||
|
||||
#: src/x11/meta-x11-display.c:1115
|
||||
#: src/x11/meta-x11-display.c:1147
|
||||
#, c-format
|
||||
msgid "Screen %d on display “%s” is invalid\n"
|
||||
msgstr "畫面「%2$s」中的第 %1$d 個螢幕無效\n"
|
||||
|
||||
#: src/x11/meta-x11-selection-input-stream.c:445
|
||||
#, c-format
|
||||
msgid "Format %s not supported"
|
||||
msgstr "不支援 %s 格式"
|
||||
|
||||
#: src/x11/session.c:1821
|
||||
msgid ""
|
||||
"These windows do not support “save current setup” and will have to be "
|
||||
"restarted manually next time you log in."
|
||||
msgstr "這些視窗不支援「儲存目前的設定」,必須在下次登入後自行啟動。"
|
||||
|
||||
#: src/x11/window-props.c:568
|
||||
#: src/x11/window-props.c:569
|
||||
#, c-format
|
||||
msgid "%s (on %s)"
|
||||
msgstr "%s(在 %s)"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Red Hat
|
||||
* Copyright 2020 DisplayLink (UK) Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@@ -1176,6 +1177,42 @@ on_monitors_changed (MetaMonitorManager *monitors,
|
||||
force_update_hw_cursor (native);
|
||||
}
|
||||
|
||||
static void
|
||||
init_hw_cursor_support_for_gpu (MetaGpuKms *gpu_kms)
|
||||
{
|
||||
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
|
||||
int kms_fd;
|
||||
struct gbm_device *gbm_device;
|
||||
uint64_t width, height;
|
||||
|
||||
gbm_device = meta_gbm_device_from_gpu (gpu_kms);
|
||||
if (!gbm_device)
|
||||
return;
|
||||
|
||||
cursor_renderer_gpu_data =
|
||||
meta_create_cursor_renderer_native_gpu_data (gpu_kms);
|
||||
|
||||
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
|
||||
if (drmGetCap (kms_fd, DRM_CAP_CURSOR_WIDTH, &width) == 0 &&
|
||||
drmGetCap (kms_fd, DRM_CAP_CURSOR_HEIGHT, &height) == 0)
|
||||
{
|
||||
cursor_renderer_gpu_data->cursor_width = width;
|
||||
cursor_renderer_gpu_data->cursor_height = height;
|
||||
}
|
||||
else
|
||||
{
|
||||
cursor_renderer_gpu_data->cursor_width = 64;
|
||||
cursor_renderer_gpu_data->cursor_height = 64;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_gpu_added_for_cursor (MetaBackend *backend,
|
||||
MetaGpuKms *gpu_kms)
|
||||
{
|
||||
init_hw_cursor_support_for_gpu (gpu_kms);
|
||||
}
|
||||
|
||||
static void
|
||||
init_hw_cursor_support (MetaCursorRendererNative *cursor_renderer_native)
|
||||
{
|
||||
@@ -1188,30 +1225,8 @@ init_hw_cursor_support (MetaCursorRendererNative *cursor_renderer_native)
|
||||
for (l = gpus; l; l = l->next)
|
||||
{
|
||||
MetaGpuKms *gpu_kms = l->data;
|
||||
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
|
||||
int kms_fd;
|
||||
struct gbm_device *gbm_device;
|
||||
uint64_t width, height;
|
||||
|
||||
gbm_device = meta_gbm_device_from_gpu (gpu_kms);
|
||||
if (!gbm_device)
|
||||
continue;
|
||||
|
||||
cursor_renderer_gpu_data =
|
||||
meta_create_cursor_renderer_native_gpu_data (gpu_kms);
|
||||
|
||||
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
|
||||
if (drmGetCap (kms_fd, DRM_CAP_CURSOR_WIDTH, &width) == 0 &&
|
||||
drmGetCap (kms_fd, DRM_CAP_CURSOR_HEIGHT, &height) == 0)
|
||||
{
|
||||
cursor_renderer_gpu_data->cursor_width = width;
|
||||
cursor_renderer_gpu_data->cursor_height = height;
|
||||
}
|
||||
else
|
||||
{
|
||||
cursor_renderer_gpu_data->cursor_width = 64;
|
||||
cursor_renderer_gpu_data->cursor_height = 64;
|
||||
}
|
||||
init_hw_cursor_support_for_gpu (gpu_kms);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1231,6 +1246,8 @@ meta_cursor_renderer_native_new (MetaBackend *backend)
|
||||
g_signal_connect_object (monitor_manager, "monitors-changed-internal",
|
||||
G_CALLBACK (on_monitors_changed),
|
||||
cursor_renderer_native, 0);
|
||||
g_signal_connect (backend, "gpu-added",
|
||||
G_CALLBACK (on_gpu_added_for_cursor), NULL);
|
||||
|
||||
priv->backend = backend;
|
||||
priv->hw_state_invalidated = TRUE;
|
||||
|
||||
@@ -326,6 +326,16 @@ meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device)
|
||||
meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl_device->impl));
|
||||
|
||||
drm_resources = drmModeGetResources (impl_device->fd);
|
||||
if (!drm_resources)
|
||||
{
|
||||
g_list_free_full (impl_device->planes, g_object_unref);
|
||||
g_list_free_full (impl_device->crtcs, g_object_unref);
|
||||
g_list_free_full (impl_device->connectors, g_object_unref);
|
||||
impl_device->planes = NULL;
|
||||
impl_device->crtcs = NULL;
|
||||
impl_device->connectors = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
update_connectors (impl_device, drm_resources);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Red Hat
|
||||
* Copyright (C) 2019 DisplayLink (UK) Ltd.
|
||||
* Copyright (C) 2019-2020 DisplayLink (UK) Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@@ -650,6 +650,9 @@ process_page_flip (MetaKmsImpl *impl,
|
||||
meta_kms_page_flip_data_ref (page_flip_data));
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
meta_kms_page_flip_data_unref (page_flip_data);
|
||||
|
||||
if (ret == -EBUSY)
|
||||
{
|
||||
CachedModeSet *cached_mode_set;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Red Hat
|
||||
* Copyright 2020 DisplayLink (UK) Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@@ -385,6 +386,7 @@ meta_kms_add_source_in_impl (MetaKms *kms,
|
||||
simple_impl_source->kms = kms;
|
||||
|
||||
g_source_set_callback (source, func, user_data, user_data_destroy);
|
||||
g_source_set_ready_time (source, 0);
|
||||
g_source_attach (source, g_main_context_get_thread_default ());
|
||||
|
||||
return source;
|
||||
|
||||
@@ -859,6 +859,7 @@ meta_backend_x11_class_init (MetaBackendX11Class *klass)
|
||||
static void
|
||||
meta_backend_x11_init (MetaBackendX11 *x11)
|
||||
{
|
||||
XInitThreads ();
|
||||
}
|
||||
|
||||
Display *
|
||||
|
||||
@@ -896,12 +896,16 @@ meta_stage_x11_translate_event (MetaStageX11 *stage_x11,
|
||||
g_debug ("Client message for stage, win:0x%x",
|
||||
(unsigned int) xevent->xany.window);
|
||||
|
||||
if (handle_wm_protocols_event (backend_x11, stage_x11, xevent))
|
||||
if (xevent->xclient.message_type == backend_x11->atom_WM_PROTOCOLS)
|
||||
{
|
||||
event->any.type = CLUTTER_DELETE;
|
||||
event->any.stage = stage;
|
||||
res = TRUE;
|
||||
if (handle_wm_protocols_event (backend_x11, stage_x11, xevent))
|
||||
{
|
||||
event->any.type = CLUTTER_DELETE;
|
||||
event->any.stage = stage;
|
||||
res = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -63,7 +63,6 @@
|
||||
#include "clutter/clutter-mutter.h"
|
||||
#include "cogl/cogl-trace.h"
|
||||
#include "compositor/meta-window-actor-x11.h"
|
||||
#include "compositor/meta-window-actor-wayland.h"
|
||||
#include "compositor/meta-window-actor-private.h"
|
||||
#include "compositor/meta-window-group-private.h"
|
||||
#include "core/core.h"
|
||||
@@ -83,6 +82,7 @@
|
||||
#include "x11/meta-x11-display-private.h"
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
#include "compositor/meta-window-actor-wayland.h"
|
||||
#include "wayland/meta-wayland-private.h"
|
||||
#endif
|
||||
|
||||
@@ -607,6 +607,7 @@ meta_compositor_add_window (MetaCompositor *compositor,
|
||||
|
||||
window_actor = g_object_new (window_actor_type,
|
||||
"meta-window", window,
|
||||
"show-on-set-parent", FALSE,
|
||||
NULL);
|
||||
|
||||
if (window->layer == META_LAYER_OVERRIDE_REDIRECT)
|
||||
|
||||
@@ -63,6 +63,15 @@
|
||||
#define META_KEY_BINDING_PRIMARY_LAYOUT 0
|
||||
#define META_KEY_BINDING_SECONDARY_LAYOUT 1
|
||||
|
||||
/* Only for special modifier keys */
|
||||
#define IGNORED_MODIFIERS (CLUTTER_LOCK_MASK | \
|
||||
CLUTTER_MOD2_MASK | \
|
||||
CLUTTER_BUTTON1_MASK | \
|
||||
CLUTTER_BUTTON2_MASK | \
|
||||
CLUTTER_BUTTON3_MASK | \
|
||||
CLUTTER_BUTTON4_MASK | \
|
||||
CLUTTER_BUTTON5_MASK)
|
||||
|
||||
static gboolean add_builtin_keybinding (MetaDisplay *display,
|
||||
const char *name,
|
||||
GSettings *settings,
|
||||
@@ -2114,6 +2123,7 @@ process_special_modifier_key (MetaDisplay *display,
|
||||
return TRUE;
|
||||
}
|
||||
else if (event->type == CLUTTER_KEY_PRESS &&
|
||||
((event->modifier_state & ~(IGNORED_MODIFIERS)) & CLUTTER_MODIFIER_MASK) == 0 &&
|
||||
resolved_key_combo_has_keycode (resolved_key_combo,
|
||||
event->hardware_keycode))
|
||||
{
|
||||
|
||||
@@ -32,12 +32,12 @@ static struct {
|
||||
const char *mimetype_glob;
|
||||
ssize_t max_transfer_size;
|
||||
} supported_mimetypes[] = {
|
||||
{ "image/tiff", MAX_IMAGE_SIZE },
|
||||
{ "image/bmp", MAX_IMAGE_SIZE },
|
||||
{ "image/gif", MAX_IMAGE_SIZE },
|
||||
{ "image/jpeg", MAX_IMAGE_SIZE },
|
||||
{ "image/webp", MAX_IMAGE_SIZE },
|
||||
{ "image/png", MAX_IMAGE_SIZE },
|
||||
{ "image/bmp", MAX_IMAGE_SIZE },
|
||||
{ "image/tiff", MAX_IMAGE_SIZE },
|
||||
{ "image/svg+xml", MAX_IMAGE_SIZE },
|
||||
{ "text/plain", MAX_TEXT_SIZE },
|
||||
{ "text/plain;charset=utf-8", MAX_TEXT_SIZE },
|
||||
|
||||
32
src/core/meta-selection-private.h
Normal file
32
src/core/meta-selection-private.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Red Hat
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Written by:
|
||||
* Carlos Garnacho <carlosg@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef META_SELECTION_PRIVATE_H
|
||||
#define META_SELECTION_PRIVATE_H
|
||||
|
||||
#include "meta/meta-selection.h"
|
||||
|
||||
MetaSelectionSource *
|
||||
meta_selection_get_current_owner (MetaSelection *selection,
|
||||
MetaSelectionType selection_type);
|
||||
|
||||
#endif /* META_SELECTION_PRIVATE_H */
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "core/meta-selection-private.h"
|
||||
#include "meta/meta-selection.h"
|
||||
|
||||
typedef struct TransferRequest TransferRequest;
|
||||
@@ -50,6 +51,9 @@ static guint signals[N_SIGNALS] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE (MetaSelection, meta_selection, G_TYPE_OBJECT)
|
||||
|
||||
static void read_selection_source_async (GTask *task,
|
||||
TransferRequest *request);
|
||||
|
||||
static void
|
||||
meta_selection_class_init (MetaSelectionClass *klass)
|
||||
{
|
||||
@@ -198,6 +202,7 @@ write_cb (GOutputStream *stream,
|
||||
GAsyncResult *result,
|
||||
GTask *task)
|
||||
{
|
||||
TransferRequest *request;
|
||||
GError *error = NULL;
|
||||
|
||||
g_output_stream_write_bytes_finish (stream, result, &error);
|
||||
@@ -208,8 +213,17 @@ write_cb (GOutputStream *stream,
|
||||
return;
|
||||
}
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
request = g_task_get_task_data (task);
|
||||
|
||||
if (request->len > 0)
|
||||
{
|
||||
read_selection_source_async (task, request);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -228,8 +242,26 @@ read_cb (GInputStream *stream,
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
else if (g_bytes_get_size (bytes) == 0)
|
||||
{
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
request = g_task_get_task_data (task);
|
||||
|
||||
if (request->len < g_bytes_get_size (bytes))
|
||||
{
|
||||
GBytes *copy;
|
||||
|
||||
/* Trim content */
|
||||
copy = g_bytes_new_from_bytes (bytes, 0, request->len);
|
||||
g_bytes_unref (bytes);
|
||||
bytes = copy;
|
||||
}
|
||||
|
||||
request->len -= g_bytes_get_size (bytes);
|
||||
g_output_stream_write_bytes_async (request->ostream,
|
||||
bytes,
|
||||
G_PRIORITY_DEFAULT,
|
||||
@@ -239,6 +271,18 @@ read_cb (GInputStream *stream,
|
||||
g_bytes_unref (bytes);
|
||||
}
|
||||
|
||||
static void
|
||||
read_selection_source_async (GTask *task,
|
||||
TransferRequest *request)
|
||||
{
|
||||
g_input_stream_read_bytes_async (request->istream,
|
||||
(gsize) request->len,
|
||||
G_PRIORITY_DEFAULT,
|
||||
g_task_get_cancellable (task),
|
||||
(GAsyncReadyCallback) read_cb,
|
||||
task);
|
||||
}
|
||||
|
||||
static void
|
||||
source_read_cb (MetaSelectionSource *source,
|
||||
GAsyncResult *result,
|
||||
@@ -271,12 +315,7 @@ source_read_cb (MetaSelectionSource *source,
|
||||
}
|
||||
else
|
||||
{
|
||||
g_input_stream_read_bytes_async (request->istream,
|
||||
(gsize) request->len,
|
||||
G_PRIORITY_DEFAULT,
|
||||
g_task_get_cancellable (task),
|
||||
(GAsyncReadyCallback) read_cb,
|
||||
task);
|
||||
read_selection_source_async (task, request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,3 +384,13 @@ meta_selection_transfer_finish (MetaSelection *selection,
|
||||
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
MetaSelectionSource *
|
||||
meta_selection_get_current_owner (MetaSelection *selection,
|
||||
MetaSelectionType selection_type)
|
||||
{
|
||||
g_return_val_if_fail (META_IS_SELECTION (selection), NULL);
|
||||
g_return_val_if_fail (selection_type < META_N_SELECTION_TYPES, NULL);
|
||||
|
||||
return selection->owners[selection_type];
|
||||
}
|
||||
|
||||
@@ -1289,7 +1289,10 @@ _meta_window_shared_new (MetaDisplay *display,
|
||||
window->initial_workspace);
|
||||
}
|
||||
|
||||
set_workspace_state (window, on_all_workspaces, workspace);
|
||||
/* Ignore when a window requests to be placed on a non-existent workspace
|
||||
*/
|
||||
if (on_all_workspaces || workspace != NULL)
|
||||
set_workspace_state (window, on_all_workspaces, workspace);
|
||||
}
|
||||
|
||||
/* override-redirect windows are subtly different from other windows
|
||||
@@ -1308,7 +1311,7 @@ _meta_window_shared_new (MetaDisplay *display,
|
||||
|
||||
g_warn_if_fail (!window->transient_for->override_redirect);
|
||||
set_workspace_state (window,
|
||||
should_be_on_all_workspaces (window->transient_for),
|
||||
window->transient_for->on_all_workspaces,
|
||||
window->transient_for->workspace);
|
||||
}
|
||||
else if (window->on_all_workspaces)
|
||||
|
||||
@@ -108,6 +108,30 @@ static struct wl_resource * create_and_send_primary_offer (MetaWaylandDataDevi
|
||||
struct wl_resource *target);
|
||||
static struct wl_resource * meta_wayland_data_source_get_resource (MetaWaylandDataSource *source);
|
||||
|
||||
static void
|
||||
move_resources (struct wl_list *destination,
|
||||
struct wl_list *source)
|
||||
{
|
||||
wl_list_insert_list (destination, source);
|
||||
wl_list_init (source);
|
||||
}
|
||||
|
||||
static void
|
||||
move_resources_for_client (struct wl_list *destination,
|
||||
struct wl_list *source,
|
||||
struct wl_client *client)
|
||||
{
|
||||
struct wl_resource *resource, *tmp;
|
||||
wl_resource_for_each_safe (resource, tmp, source)
|
||||
{
|
||||
if (wl_resource_get_client (resource) == client)
|
||||
{
|
||||
wl_list_remove (wl_resource_get_link (resource));
|
||||
wl_list_insert (destination, wl_resource_get_link (resource));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
unbind_resource (struct wl_resource *resource)
|
||||
{
|
||||
@@ -143,16 +167,8 @@ data_offer_choose_action (MetaWaylandDataOffer *offer)
|
||||
WL_DATA_OFFER_ACTION_SINCE_VERSION)
|
||||
return WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
|
||||
|
||||
if (wl_resource_get_version (meta_wayland_data_source_get_resource (source)) <
|
||||
WL_DATA_SOURCE_ACTION_SINCE_VERSION)
|
||||
{
|
||||
actions = user_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
|
||||
}
|
||||
else
|
||||
{
|
||||
actions = meta_wayland_data_source_get_actions (source);
|
||||
user_action = meta_wayland_data_source_get_user_action (source);
|
||||
}
|
||||
actions = meta_wayland_data_source_get_actions (source);
|
||||
user_action = meta_wayland_data_source_get_user_action (source);
|
||||
|
||||
available_actions = actions & offer->dnd_actions;
|
||||
|
||||
@@ -608,11 +624,7 @@ destroy_data_offer (struct wl_resource *resource)
|
||||
if (wl_resource_get_version (offer->resource) <
|
||||
WL_DATA_OFFER_ACTION_SINCE_VERSION)
|
||||
meta_wayland_data_source_notify_finish (offer->source);
|
||||
else if (meta_wayland_data_source_get_drop_performed (offer->source) &&
|
||||
meta_wayland_data_source_get_resource(offer->source) &&
|
||||
wl_resource_get_version(
|
||||
meta_wayland_data_source_get_resource(offer->source)) >=
|
||||
WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION)
|
||||
else if (meta_wayland_data_source_get_drop_performed (offer->source))
|
||||
meta_wayland_source_cancel (offer->source);
|
||||
}
|
||||
else
|
||||
@@ -913,6 +925,12 @@ meta_wayland_drag_grab_set_focus (MetaWaylandDragGrab *drag_grab,
|
||||
client = wl_resource_get_client (surface->resource);
|
||||
|
||||
data_device_resource = wl_resource_find_for_client (&seat->data_device.resource_list, client);
|
||||
if (!data_device_resource)
|
||||
{
|
||||
data_device_resource =
|
||||
wl_resource_find_for_client (&seat->data_device.focus_resource_list,
|
||||
client);
|
||||
}
|
||||
|
||||
if (source && data_device_resource)
|
||||
offer = create_and_send_dnd_offer (source, data_device_resource);
|
||||
@@ -1343,20 +1361,8 @@ static void
|
||||
selection_data_source_destroyed (gpointer data, GObject *object_was_here)
|
||||
{
|
||||
MetaWaylandDataDevice *data_device = data;
|
||||
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
|
||||
struct wl_resource *data_device_resource;
|
||||
struct wl_client *focus_client = NULL;
|
||||
|
||||
data_device->selection_data_source = NULL;
|
||||
|
||||
focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
|
||||
if (focus_client)
|
||||
{
|
||||
data_device_resource = wl_resource_find_for_client (&data_device->resource_list, focus_client);
|
||||
if (data_device_resource)
|
||||
wl_data_device_send_selection (data_device_resource, NULL);
|
||||
}
|
||||
|
||||
unset_selection_source (data_device, META_SELECTION_CLIPBOARD);
|
||||
}
|
||||
|
||||
@@ -1388,8 +1394,10 @@ meta_wayland_source_cancel (MetaWaylandDataSource *source)
|
||||
MetaWaylandDataSourcePrivate *priv =
|
||||
meta_wayland_data_source_get_instance_private (source);
|
||||
|
||||
if (priv->resource)
|
||||
wl_data_source_send_cancelled (priv->resource);
|
||||
if (!priv->resource)
|
||||
return;
|
||||
|
||||
wl_data_source_send_cancelled (priv->resource);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1410,11 +1418,12 @@ meta_wayland_source_drop_performed (MetaWaylandDataSource *source)
|
||||
MetaWaylandDataSourcePrivate *priv =
|
||||
meta_wayland_data_source_get_instance_private (source);
|
||||
|
||||
priv->drop_performed = TRUE;
|
||||
|
||||
if (wl_resource_get_version (priv->resource) >=
|
||||
WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION)
|
||||
wl_data_source_send_dnd_drop_performed (priv->resource);
|
||||
{
|
||||
priv->drop_performed = TRUE;
|
||||
wl_data_source_send_dnd_drop_performed (priv->resource);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1655,8 +1664,6 @@ meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
|
||||
guint32 serial)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
|
||||
struct wl_resource *data_device_resource;
|
||||
struct wl_client *focus_client;
|
||||
MetaSelectionSource *selection_source;
|
||||
|
||||
if (data_device->selection_data_source &&
|
||||
@@ -1665,7 +1672,6 @@ meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
|
||||
|
||||
if (data_device->selection_data_source)
|
||||
{
|
||||
meta_wayland_data_source_cancel (data_device->selection_data_source);
|
||||
g_object_weak_unref (G_OBJECT (data_device->selection_data_source),
|
||||
selection_data_source_destroyed,
|
||||
data_device);
|
||||
@@ -1692,18 +1698,6 @@ meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
|
||||
set_selection_source (data_device, META_SELECTION_CLIPBOARD,
|
||||
selection_source);
|
||||
g_object_unref (selection_source);
|
||||
|
||||
focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
|
||||
if (focus_client)
|
||||
{
|
||||
data_device_resource = wl_resource_find_for_client (&data_device->resource_list, focus_client);
|
||||
if (data_device_resource)
|
||||
{
|
||||
struct wl_resource *offer;
|
||||
offer = create_and_send_clipboard_offer (data_device, data_device_resource);
|
||||
wl_data_device_send_selection (data_device_resource, offer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1754,21 +1748,8 @@ primary_source_destroyed (gpointer data,
|
||||
GObject *object_was_here)
|
||||
{
|
||||
MetaWaylandDataDevice *data_device = data;
|
||||
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
|
||||
struct wl_client *focus_client = NULL;
|
||||
|
||||
data_device->primary_data_source = NULL;
|
||||
|
||||
focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
|
||||
if (focus_client)
|
||||
{
|
||||
struct wl_resource *data_device_resource;
|
||||
|
||||
data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
|
||||
if (data_device_resource)
|
||||
gtk_primary_selection_device_send_selection (data_device_resource, NULL);
|
||||
}
|
||||
|
||||
unset_selection_source (data_device, META_SELECTION_PRIMARY);
|
||||
}
|
||||
|
||||
@@ -1778,8 +1759,6 @@ meta_wayland_data_device_set_primary (MetaWaylandDataDevice *data_device,
|
||||
guint32 serial)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
|
||||
struct wl_resource *data_device_resource;
|
||||
struct wl_client *focus_client;
|
||||
MetaSelectionSource *selection_source;
|
||||
|
||||
g_assert (!source || META_IS_WAYLAND_DATA_SOURCE_PRIMARY (source));
|
||||
@@ -1790,7 +1769,6 @@ meta_wayland_data_device_set_primary (MetaWaylandDataDevice *data_device,
|
||||
|
||||
if (data_device->primary_data_source)
|
||||
{
|
||||
meta_wayland_data_source_cancel (data_device->primary_data_source);
|
||||
g_object_weak_unref (G_OBJECT (data_device->primary_data_source),
|
||||
primary_source_destroyed,
|
||||
data_device);
|
||||
@@ -1816,18 +1794,6 @@ meta_wayland_data_device_set_primary (MetaWaylandDataDevice *data_device,
|
||||
set_selection_source (data_device, META_SELECTION_PRIMARY,
|
||||
selection_source);
|
||||
g_object_unref (selection_source);
|
||||
|
||||
focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
|
||||
if (focus_client)
|
||||
{
|
||||
data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
|
||||
if (data_device_resource)
|
||||
{
|
||||
struct wl_resource *offer;
|
||||
offer = create_and_send_primary_offer (data_device, data_device_resource);
|
||||
gtk_primary_selection_device_send_selection (data_device_resource, offer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1892,10 +1858,7 @@ owner_changed_cb (MetaSelection *selection,
|
||||
|
||||
if (selection_type == META_SELECTION_PRIMARY)
|
||||
{
|
||||
data_device_resource =
|
||||
wl_resource_find_for_client (&data_device->primary_resource_list,
|
||||
focus_client);
|
||||
if (data_device_resource)
|
||||
wl_resource_for_each (data_device_resource, &data_device->primary_focus_resource_list)
|
||||
{
|
||||
struct wl_resource *offer = NULL;
|
||||
|
||||
@@ -1911,10 +1874,7 @@ owner_changed_cb (MetaSelection *selection,
|
||||
}
|
||||
else if (selection_type == META_SELECTION_CLIPBOARD)
|
||||
{
|
||||
data_device_resource =
|
||||
wl_resource_find_for_client (&data_device->resource_list, focus_client);
|
||||
|
||||
if (data_device_resource)
|
||||
wl_resource_for_each (data_device_resource, &data_device->focus_resource_list)
|
||||
{
|
||||
struct wl_resource *offer = NULL;
|
||||
|
||||
@@ -2049,7 +2009,9 @@ void
|
||||
meta_wayland_data_device_init (MetaWaylandDataDevice *data_device)
|
||||
{
|
||||
wl_list_init (&data_device->resource_list);
|
||||
wl_list_init (&data_device->focus_resource_list);
|
||||
wl_list_init (&data_device->primary_resource_list);
|
||||
wl_list_init (&data_device->primary_focus_resource_list);
|
||||
}
|
||||
|
||||
static struct wl_resource *
|
||||
@@ -2131,22 +2093,34 @@ meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_device)
|
||||
return;
|
||||
|
||||
data_device->focus_client = focus_client;
|
||||
move_resources (&data_device->resource_list,
|
||||
&data_device->focus_resource_list);
|
||||
move_resources (&data_device->primary_resource_list,
|
||||
&data_device->primary_focus_resource_list);
|
||||
|
||||
if (!focus_client)
|
||||
return;
|
||||
|
||||
data_device_resource = wl_resource_find_for_client (&data_device->resource_list, focus_client);
|
||||
if (data_device_resource)
|
||||
move_resources_for_client (&data_device->focus_resource_list,
|
||||
&data_device->resource_list,
|
||||
focus_client);
|
||||
|
||||
wl_resource_for_each (data_device_resource, &data_device->focus_resource_list)
|
||||
{
|
||||
struct wl_resource *offer;
|
||||
|
||||
offer = create_and_send_clipboard_offer (data_device, data_device_resource);
|
||||
wl_data_device_send_selection (data_device_resource, offer);
|
||||
}
|
||||
|
||||
data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
|
||||
if (data_device_resource)
|
||||
move_resources_for_client (&data_device->primary_focus_resource_list,
|
||||
&data_device->primary_resource_list,
|
||||
focus_client);
|
||||
|
||||
wl_resource_for_each (data_device_resource, &data_device->primary_focus_resource_list)
|
||||
{
|
||||
struct wl_resource *offer;
|
||||
|
||||
offer = create_and_send_primary_offer (data_device, data_device_resource);
|
||||
gtk_primary_selection_device_send_selection (data_device_resource, offer);
|
||||
}
|
||||
@@ -2188,11 +2162,19 @@ meta_wayland_data_source_new (struct wl_resource *resource)
|
||||
{
|
||||
MetaWaylandDataSource *source =
|
||||
g_object_new (META_TYPE_WAYLAND_DATA_SOURCE, NULL);
|
||||
MetaWaylandDataSourcePrivate *priv =
|
||||
meta_wayland_data_source_get_instance_private (source);
|
||||
|
||||
meta_wayland_data_source_set_resource (source, resource);
|
||||
wl_resource_set_implementation (resource, &data_source_interface,
|
||||
source, destroy_data_source);
|
||||
|
||||
if (wl_resource_get_version (resource) < WL_DATA_SOURCE_ACTION_SINCE_VERSION)
|
||||
{
|
||||
priv->dnd_actions = priv->user_dnd_action =
|
||||
WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,9 @@ struct _MetaWaylandDataDevice
|
||||
MetaWaylandDataSource *primary_data_source;
|
||||
struct wl_listener selection_data_source_listener;
|
||||
struct wl_list resource_list;
|
||||
struct wl_list focus_resource_list;
|
||||
struct wl_list primary_resource_list;
|
||||
struct wl_list primary_focus_resource_list;
|
||||
MetaWaylandDragGrab *current_grab;
|
||||
struct wl_client *focus_client;
|
||||
|
||||
|
||||
@@ -599,7 +599,6 @@ meta_wayland_keyboard_disable (MetaWaylandKeyboard *keyboard)
|
||||
|
||||
meta_wayland_keyboard_end_grab (keyboard);
|
||||
meta_wayland_keyboard_set_focus (keyboard, NULL);
|
||||
meta_wayland_xkb_info_destroy (&keyboard->xkb_info);
|
||||
|
||||
wl_list_remove (&keyboard->resource_list);
|
||||
wl_list_init (&keyboard->resource_list);
|
||||
@@ -913,7 +912,18 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard)
|
||||
keyboard_handle_focus_surface_destroy;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_keyboard_finalize (GObject *object)
|
||||
{
|
||||
MetaWaylandKeyboard *keyboard = META_WAYLAND_KEYBOARD (object);
|
||||
|
||||
meta_wayland_xkb_info_destroy (&keyboard->xkb_info);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_keyboard_class_init (MetaWaylandKeyboardClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_wayland_keyboard_finalize;
|
||||
}
|
||||
|
||||
@@ -434,7 +434,7 @@ zxdg_toplevel_v6_set_fullscreen (struct wl_client *client,
|
||||
if (output_resource)
|
||||
{
|
||||
MetaWaylandOutput *output = wl_resource_get_user_data (output_resource);
|
||||
if (output)
|
||||
if (output && output->logical_monitor)
|
||||
meta_window_move_to_monitor (window, output->logical_monitor->number);
|
||||
}
|
||||
|
||||
|
||||
@@ -431,7 +431,7 @@ xdg_toplevel_set_fullscreen (struct wl_client *client,
|
||||
{
|
||||
MetaWaylandOutput *output = wl_resource_get_user_data (output_resource);
|
||||
|
||||
if (output)
|
||||
if (output && output->logical_monitor)
|
||||
{
|
||||
meta_window_move_to_monitor (window,
|
||||
output->logical_monitor->number);
|
||||
|
||||
@@ -57,12 +57,15 @@ struct _MetaX11SelectionOutputStreamPrivate
|
||||
|
||||
guint incr : 1;
|
||||
guint delete_pending : 1;
|
||||
guint pipe_error : 1;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaX11SelectionOutputStream,
|
||||
meta_x11_selection_output_stream,
|
||||
G_TYPE_OUTPUT_STREAM);
|
||||
|
||||
static size_t get_element_size (int format);
|
||||
|
||||
static void
|
||||
meta_x11_selection_output_stream_notify_selection (MetaX11SelectionOutputStream *stream)
|
||||
{
|
||||
@@ -100,6 +103,9 @@ meta_x11_selection_output_stream_can_flush (MetaX11SelectionOutputStream *stream
|
||||
|
||||
if (priv->delete_pending)
|
||||
return FALSE;
|
||||
if (!g_output_stream_is_closing (G_OUTPUT_STREAM (stream)) &&
|
||||
priv->data->len < get_element_size (priv->format))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -113,7 +119,7 @@ get_max_request_size (MetaX11Display *display)
|
||||
if (size <= 0)
|
||||
size = XMaxRequestSize (display->xdisplay);
|
||||
|
||||
return size - 100;
|
||||
return (size - 100) * 4;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -123,7 +129,12 @@ meta_x11_selection_output_stream_needs_flush_unlocked (MetaX11SelectionOutputStr
|
||||
meta_x11_selection_output_stream_get_instance_private (stream);
|
||||
|
||||
if (priv->data->len == 0)
|
||||
return FALSE;
|
||||
{
|
||||
if (priv->incr)
|
||||
return g_output_stream_is_closing (G_OUTPUT_STREAM (stream));
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (g_output_stream_is_closing (G_OUTPUT_STREAM (stream)))
|
||||
return TRUE;
|
||||
@@ -171,13 +182,34 @@ get_element_size (int format)
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_x11_selection_output_stream_check_pipe (MetaX11SelectionOutputStream *stream,
|
||||
GError **error)
|
||||
{
|
||||
MetaX11SelectionOutputStreamPrivate *priv =
|
||||
meta_x11_selection_output_stream_get_instance_private (stream);
|
||||
|
||||
if (priv->pipe_error)
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_BROKEN_PIPE,
|
||||
"Connection with client was broken");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *stream)
|
||||
{
|
||||
MetaX11SelectionOutputStreamPrivate *priv =
|
||||
meta_x11_selection_output_stream_get_instance_private (stream);
|
||||
Display *xdisplay;
|
||||
size_t element_size, n_elements;
|
||||
size_t element_size, n_elements, max_size;
|
||||
gboolean first_chunk = FALSE;
|
||||
int error_code;
|
||||
|
||||
g_assert (!priv->delete_pending);
|
||||
|
||||
@@ -190,8 +222,12 @@ meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *st
|
||||
|
||||
element_size = get_element_size (priv->format);
|
||||
n_elements = priv->data->len / element_size;
|
||||
max_size = get_max_request_size (priv->x11_display);
|
||||
|
||||
if (!g_output_stream_is_closing (G_OUTPUT_STREAM (stream)))
|
||||
if (!priv->incr)
|
||||
first_chunk = TRUE;
|
||||
|
||||
if (!priv->incr && priv->data->len > max_size)
|
||||
{
|
||||
XWindowAttributes attrs;
|
||||
|
||||
@@ -207,14 +243,22 @@ meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *st
|
||||
XChangeProperty (xdisplay,
|
||||
priv->xwindow,
|
||||
priv->xproperty,
|
||||
XInternAtom (priv->x11_display->xdisplay, "INCR", True),
|
||||
XInternAtom (priv->x11_display->xdisplay, "INCR", False),
|
||||
32,
|
||||
PropModeReplace,
|
||||
(guchar *) &(long) { n_elements },
|
||||
1);
|
||||
priv->delete_pending = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t copy_n_elements;
|
||||
|
||||
if (priv->incr && priv->data->len > 0)
|
||||
priv->delete_pending = TRUE;
|
||||
|
||||
copy_n_elements = MIN (n_elements, max_size / element_size);
|
||||
|
||||
XChangeProperty (xdisplay,
|
||||
priv->xwindow,
|
||||
priv->xproperty,
|
||||
@@ -222,30 +266,45 @@ meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *st
|
||||
priv->format,
|
||||
PropModeReplace,
|
||||
priv->data->data,
|
||||
n_elements);
|
||||
g_byte_array_remove_range (priv->data, 0, n_elements * element_size);
|
||||
if (priv->data->len < element_size)
|
||||
priv->flush_requested = FALSE;
|
||||
copy_n_elements);
|
||||
g_byte_array_remove_range (priv->data, 0, copy_n_elements * element_size);
|
||||
}
|
||||
|
||||
meta_x11_selection_output_stream_notify_selection (stream);
|
||||
if (first_chunk)
|
||||
meta_x11_selection_output_stream_notify_selection (stream);
|
||||
|
||||
priv->delete_pending = TRUE;
|
||||
g_cond_broadcast (&priv->cond);
|
||||
g_mutex_unlock (&priv->mutex);
|
||||
|
||||
/* XXX: handle failure here and report EPIPE for future operations on the stream? */
|
||||
if (meta_x11_error_trap_pop_with_return (priv->x11_display))
|
||||
g_warning ("Failed to flush selection output stream");
|
||||
error_code = meta_x11_error_trap_pop_with_return (priv->x11_display);
|
||||
|
||||
if (priv->pending_task)
|
||||
if (error_code != Success)
|
||||
{
|
||||
char error_str[100];
|
||||
|
||||
priv->flush_requested = FALSE;
|
||||
priv->delete_pending = FALSE;
|
||||
priv->pipe_error = TRUE;
|
||||
|
||||
if (priv->pending_task)
|
||||
{
|
||||
XGetErrorText (xdisplay, error_code, error_str, sizeof (error_str));
|
||||
g_task_return_new_error (priv->pending_task,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_BROKEN_PIPE,
|
||||
"Failed to flush selection output stream: %s",
|
||||
error_str);
|
||||
g_clear_object (&priv->pending_task);
|
||||
}
|
||||
}
|
||||
else if (priv->pending_task && priv->data->len == 0 && !priv->delete_pending)
|
||||
{
|
||||
size_t result;
|
||||
|
||||
priv->flush_requested = FALSE;
|
||||
result = GPOINTER_TO_SIZE (g_task_get_task_data (priv->pending_task));
|
||||
g_task_return_int (priv->pending_task, result);
|
||||
g_object_unref (priv->pending_task);
|
||||
priv->pending_task = NULL;
|
||||
g_clear_object (&priv->pending_task);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,12 +313,17 @@ meta_x11_selection_output_stream_invoke_flush (gpointer data)
|
||||
{
|
||||
MetaX11SelectionOutputStream *stream =
|
||||
META_X11_SELECTION_OUTPUT_STREAM (data);
|
||||
MetaX11SelectionOutputStreamPrivate *priv =
|
||||
meta_x11_selection_output_stream_get_instance_private (stream);
|
||||
|
||||
if (meta_x11_selection_output_stream_needs_flush (stream) &&
|
||||
meta_x11_selection_output_stream_can_flush (stream))
|
||||
meta_x11_selection_output_stream_perform_flush (stream);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
if (priv->delete_pending || priv->data->len > 0)
|
||||
return G_SOURCE_CONTINUE;
|
||||
else
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gssize
|
||||
@@ -274,6 +338,9 @@ meta_x11_selection_output_stream_write (GOutputStream *output_stream,
|
||||
MetaX11SelectionOutputStreamPrivate *priv =
|
||||
meta_x11_selection_output_stream_get_instance_private (stream);
|
||||
|
||||
if (!meta_x11_selection_output_stream_check_pipe (stream, error))
|
||||
return -1;
|
||||
|
||||
g_mutex_lock (&priv->mutex);
|
||||
g_byte_array_append (priv->data, buffer, count);
|
||||
g_mutex_unlock (&priv->mutex);
|
||||
@@ -301,12 +368,19 @@ meta_x11_selection_output_stream_write_async (GOutputStream *output_stream
|
||||
META_X11_SELECTION_OUTPUT_STREAM (output_stream);
|
||||
MetaX11SelectionOutputStreamPrivate *priv =
|
||||
meta_x11_selection_output_stream_get_instance_private (stream);
|
||||
GError *error = NULL;
|
||||
GTask *task;
|
||||
|
||||
task = g_task_new (stream, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, meta_x11_selection_output_stream_write_async);
|
||||
g_task_set_priority (task, io_priority);
|
||||
|
||||
if (!meta_x11_selection_output_stream_check_pipe (stream, &error))
|
||||
{
|
||||
g_task_return_error (task, error);
|
||||
return;
|
||||
}
|
||||
|
||||
g_mutex_lock (&priv->mutex);
|
||||
g_byte_array_append (priv->data, buffer, count);
|
||||
g_mutex_unlock (&priv->mutex);
|
||||
@@ -317,16 +391,11 @@ meta_x11_selection_output_stream_write_async (GOutputStream *output_stream
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
else if (!meta_x11_selection_output_stream_can_flush (stream))
|
||||
{
|
||||
g_assert (priv->pending_task == NULL);
|
||||
priv->pending_task = task;
|
||||
g_task_set_task_data (task, GSIZE_TO_POINTER (count), NULL);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_x11_selection_output_stream_perform_flush (stream);
|
||||
if (meta_x11_selection_output_stream_can_flush (stream))
|
||||
meta_x11_selection_output_stream_perform_flush (stream);
|
||||
|
||||
g_task_return_int (task, count);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
@@ -354,7 +423,7 @@ meta_x11_selection_output_request_flush (MetaX11SelectionOutputStream *stream)
|
||||
|
||||
g_mutex_lock (&priv->mutex);
|
||||
|
||||
if (priv->data->len >= get_element_size (priv->format))
|
||||
if (priv->data->len > 0)
|
||||
priv->flush_requested = TRUE;
|
||||
|
||||
needs_flush = meta_x11_selection_output_stream_needs_flush_unlocked (stream);
|
||||
@@ -373,6 +442,8 @@ meta_x11_selection_output_stream_flush (GOutputStream *output_stream,
|
||||
MetaX11SelectionOutputStreamPrivate *priv =
|
||||
meta_x11_selection_output_stream_get_instance_private (stream);
|
||||
|
||||
if (!meta_x11_selection_output_stream_check_pipe (stream, error))
|
||||
return FALSE;
|
||||
if (!meta_x11_selection_output_request_flush (stream))
|
||||
return TRUE;
|
||||
|
||||
@@ -398,12 +469,19 @@ meta_x11_selection_output_stream_flush_async (GOutputStream *output_stream
|
||||
META_X11_SELECTION_OUTPUT_STREAM (output_stream);
|
||||
MetaX11SelectionOutputStreamPrivate *priv =
|
||||
meta_x11_selection_output_stream_get_instance_private (stream);
|
||||
GError *error = NULL;
|
||||
GTask *task;
|
||||
|
||||
task = g_task_new (stream, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, meta_x11_selection_output_stream_flush_async);
|
||||
g_task_set_priority (task, io_priority);
|
||||
|
||||
if (!meta_x11_selection_output_stream_check_pipe (stream, &error))
|
||||
{
|
||||
g_task_return_error (task, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!meta_x11_selection_output_stream_can_flush (stream))
|
||||
{
|
||||
if (meta_x11_selection_output_request_flush (stream))
|
||||
@@ -420,10 +498,9 @@ meta_x11_selection_output_stream_flush_async (GOutputStream *output_stream
|
||||
}
|
||||
}
|
||||
|
||||
g_assert (priv->pending_task == NULL);
|
||||
priv->pending_task = task;
|
||||
meta_x11_selection_output_stream_perform_flush (stream);
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
#include <gdk/gdkx.h>
|
||||
|
||||
#include "core/meta-selection-private.h"
|
||||
#include "meta/meta-selection-source-memory.h"
|
||||
#include "x11/meta-selection-source-x11-private.h"
|
||||
#include "x11/meta-x11-selection-output-stream-private.h"
|
||||
#include "x11/meta-x11-selection-private.h"
|
||||
@@ -30,6 +32,13 @@
|
||||
#define UTF8_STRING_MIMETYPE "text/plain;charset=utf-8"
|
||||
#define STRING_MIMETYPE "text/plain"
|
||||
|
||||
/* Set an arbitrary (although generous) threshold to determine whether a
|
||||
* XFixesSelectionNotify corresponds to a XSetSelectionOwner from another
|
||||
* client. The selection timestamp is not updated if the owner client is
|
||||
* closed.
|
||||
*/
|
||||
#define SELECTION_CLEARED_BY_CLIENT(e) (e->timestamp - e->selection_timestamp < 50)
|
||||
|
||||
static gboolean
|
||||
atom_to_selection_type (Display *xdisplay,
|
||||
Atom selection,
|
||||
@@ -295,8 +304,9 @@ source_new_cb (GObject *object,
|
||||
source = meta_selection_source_x11_new_finish (res, &error);
|
||||
if (source)
|
||||
{
|
||||
meta_selection_set_owner (selection, selection_type, source);
|
||||
g_set_object (&x11_display->selection.owners[selection_type], source);
|
||||
meta_selection_set_owner (selection, selection_type, source);
|
||||
g_object_unref (source);
|
||||
}
|
||||
else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
{
|
||||
@@ -329,16 +339,27 @@ meta_x11_selection_handle_xfixes_selection_notify (MetaX11Display *x11_display,
|
||||
|
||||
x11_display->selection.cancellables[selection_type] = g_cancellable_new ();
|
||||
|
||||
if (event->owner == None)
|
||||
if (event->owner == None && x11_display->selection.owners[selection_type])
|
||||
{
|
||||
if (x11_display->selection.owners[selection_type])
|
||||
if (SELECTION_CLEARED_BY_CLIENT (event))
|
||||
{
|
||||
MetaSelectionSource *source;
|
||||
|
||||
/* Replace with an empty owner */
|
||||
source = g_object_new (META_TYPE_SELECTION_SOURCE_MEMORY, NULL);
|
||||
g_set_object (&x11_display->selection.owners[selection_type], source);
|
||||
meta_selection_set_owner (selection, selection_type, source);
|
||||
g_object_unref (source);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* An X client went away, clear the selection */
|
||||
meta_selection_unset_owner (selection, selection_type,
|
||||
x11_display->selection.owners[selection_type]);
|
||||
g_clear_object (&x11_display->selection.owners[selection_type]);
|
||||
}
|
||||
}
|
||||
else if (event->owner != x11_display->selection.xwindow)
|
||||
else if (event->owner != None && event->owner != x11_display->selection.xwindow)
|
||||
{
|
||||
SourceNewData *data;
|
||||
|
||||
@@ -372,14 +393,13 @@ meta_x11_selection_handle_event (MetaX11Display *x11_display,
|
||||
}
|
||||
|
||||
static void
|
||||
owner_changed_cb (MetaSelection *selection,
|
||||
MetaSelectionType selection_type,
|
||||
MetaSelectionSource *new_owner,
|
||||
MetaX11Display *x11_display)
|
||||
notify_selection_owner (MetaX11Display *x11_display,
|
||||
MetaSelectionType selection_type,
|
||||
MetaSelectionSource *new_owner)
|
||||
{
|
||||
Display *xdisplay = x11_display->xdisplay;
|
||||
|
||||
if (new_owner && !META_IS_SELECTION_SOURCE_X11 (new_owner))
|
||||
if (new_owner && new_owner != x11_display->selection.owners[selection_type])
|
||||
{
|
||||
if (x11_display->selection.cancellables[selection_type])
|
||||
{
|
||||
@@ -402,6 +422,7 @@ meta_x11_selection_init (MetaX11Display *x11_display)
|
||||
{
|
||||
XSetWindowAttributes attributes = { 0 };
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
MetaSelection *selection;
|
||||
guint mask, i;
|
||||
|
||||
attributes.event_mask = PropertyChangeMask | SubstructureNotifyMask;
|
||||
@@ -422,18 +443,24 @@ meta_x11_selection_init (MetaX11Display *x11_display)
|
||||
XFixesSelectionWindowDestroyNotifyMask |
|
||||
XFixesSelectionClientCloseNotifyMask;
|
||||
|
||||
selection = meta_display_get_selection (display);
|
||||
|
||||
for (i = 0; i < META_N_SELECTION_TYPES; i++)
|
||||
{
|
||||
MetaSelectionSource *owner;
|
||||
|
||||
XFixesSelectSelectionInput (x11_display->xdisplay,
|
||||
x11_display->selection.xwindow,
|
||||
selection_to_atom (i, x11_display->xdisplay),
|
||||
mask);
|
||||
owner = meta_selection_get_current_owner (selection, i);
|
||||
notify_selection_owner (x11_display, i, owner);
|
||||
}
|
||||
|
||||
g_signal_connect (meta_display_get_selection (display),
|
||||
"owner-changed",
|
||||
G_CALLBACK (owner_changed_cb),
|
||||
x11_display);
|
||||
g_signal_connect_swapped (selection,
|
||||
"owner-changed",
|
||||
G_CALLBACK (notify_selection_owner),
|
||||
x11_display);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -442,7 +469,7 @@ meta_x11_selection_shutdown (MetaX11Display *x11_display)
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
|
||||
g_signal_handlers_disconnect_by_func (meta_display_get_selection (display),
|
||||
owner_changed_cb,
|
||||
notify_selection_owner,
|
||||
x11_display);
|
||||
if (x11_display->selection.xwindow != None)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user