fusuma-plugin-appmatcher 0.1.6 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6bc3fbffcc3befbf8fc3d63baa992e737d0fa52233bbf47c0cb0645f4ab3f720
4
- data.tar.gz: c6b3fcac639693631347643f479b950202a9e001fdc1bf0ed6d9fc2591b0ebde
3
+ metadata.gz: 7821bcc57ed92ff1ab9a45afc0e760dec0e852678b2db2a0c6d8cb6b39604ba8
4
+ data.tar.gz: 4d335957d70eee1cb86294a3f57219020cbf42b713dc105c91ae205ed6677ee0
5
5
  SHA512:
6
- metadata.gz: ee31ba4d167fc3f13bf64cbac3063776e6eb34b64b8f60524b5580470db313f1fc48ec165c278554401ccc633a59c15e60b4634ccf7534bb2260fb2af71811e8
7
- data.tar.gz: df1e4f4624a4c71da254adc2a25a91e04be6b7fe7569eaa64763cd4202d18d80c007e35078088b7d959809fdc21e40bcfa6b817330e0e9e6cb35e23d2b44811f
6
+ metadata.gz: fc4ccfbb2450075a702f9909bebbf5be21650b44794e07f71720a39abd80a221c27b59b39d958ecc37c54c2c8c9b2bf81df04417d8cbdd9a4641f4bd26fc774c
7
+ data.tar.gz: bf37777c2cb5304aa59b8a66c1cb788fc8ef923f5cda1ca5020eb39991fa07156786e6aaa7ff6bc0245c98060bcf0abe1baa7a1e568a4e2795114f390d05d1bb
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Fusuma::Plugin::Appmatcher [![Gem Version](https://badge.fury.io/rb/fusuma-plugin-appmatcher.svg)](https://badge.fury.io/rb/fusuma-plugin-appmatcher) [![Build Status](https://travis-ci.com/iberianpig/fusuma-plugin-appmatcher.svg?branch=master)](https://travis-ci.com/iberianpig/fusuma-plugin-appmatcher)
1
+ # Fusuma::Plugin::Appmatcher [![Gem Version](https://badge.fury.io/rb/fusuma-plugin-appmatcher.svg)](https://badge.fury.io/rb/fusuma-plugin-appmatcher) [![Build Status](https://github.com/iberianpig/fusuma/actions/workflows/ubuntu.yml/badge.svg)](https://github.com/iberianpig/fusuma/actions/workflows/ubuntu.yml)
2
2
 
3
3
  [Fusuma](https://github.com/iberianpig/fusuma) plugin configure app-specific gestures
4
4
 
@@ -16,6 +16,17 @@ Run the following code in your terminal.
16
16
  $ sudo gem install fusuma-plugin-appmatcher
17
17
  ```
18
18
 
19
+ ### Install Appmatcher GNOME Shell Extensions on Wayland
20
+
21
+ Gnome Wayland version 41 and later does not allow to access information about window or application like focused app.
22
+ So fusuma-plugin-appmatcher solves this problem via Appmatcher gnome-extension.
23
+
24
+ ```sh
25
+ $ fusuma-appmatcher --install-gnome-extension
26
+ ```
27
+
28
+ Restart your session(logout/login), then activate Appmatcher on gnome-extensions-app
29
+
19
30
  ## List Running Application names
20
31
 
21
32
  `$ fusuma-appmatcher -l` prints Running Application names.
@@ -16,8 +16,31 @@ opt.on('--version', 'Show version') do |v|
16
16
  option[:version] = v
17
17
  end
18
18
 
19
+ opt.on('--install-gnome-extension',
20
+ 'Install GNOME extension for appmatcher') do |v|
21
+ option[:install_gnome_extension] = v
22
+ end
23
+
24
+ opt.on('--uninstall-gnome-extension',
25
+ 'Uninstall GNOME extension for appmatcher') do |v|
26
+ option[:uninstall_gnome_extension] = v
27
+ end
28
+
19
29
  opt.parse!(ARGV)
20
30
 
31
+ if option[:install_gnome_extension]
32
+ require_relative '../lib/fusuma/plugin/appmatcher/gnome_extensions/installer.rb'
33
+ Fusuma::Plugin::Appmatcher::GnomeExtensions::Installer.new.install
34
+ return
35
+ end
36
+
37
+ if option[:uninstall_gnome_extension]
38
+ require_relative '../lib/fusuma/plugin/appmatcher/gnome_extensions/installer.rb'
39
+ Fusuma::Plugin::Appmatcher::GnomeExtensions::Installer.new.uninstall
40
+ return
41
+ end
42
+
43
+
21
44
  if option[:list]
22
45
  matcher = Fusuma::Plugin::Appmatcher.backend_klass::Matcher.new
23
46
  puts matcher.running_applications
@@ -1,29 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path('lib', __dir__)
3
+ lib = File.expand_path("lib", __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require 'fusuma/plugin/appmatcher/version'
5
+ require "fusuma/plugin/appmatcher/version"
6
6
 
7
7
  Gem::Specification.new do |spec|
8
- spec.name = 'fusuma-plugin-appmatcher'
8
+ spec.name = "fusuma-plugin-appmatcher"
9
9
  spec.version = Fusuma::Plugin::Appmatcher::VERSION
10
- spec.authors = ['iberianpig']
11
- spec.email = ['yhkyky@gmail.com']
10
+ spec.authors = ["iberianpig"]
11
+ spec.email = ["yhkyky@gmail.com"]
12
12
 
13
- spec.summary = 'Fusuma plugin to assign gesture mapping per application'
14
- spec.description = 'fusuma-plugin-appmatcher is Fusuma plugin for assigning gesture mapping per application.'
15
- spec.homepage = 'https://github.com/iberianpig/fusuma-plugin-appmatcher'
16
- spec.license = 'MIT'
13
+ spec.summary = "Fusuma plugin to assign gesture mapping per application"
14
+ spec.description = "fusuma-plugin-appmatcher is Fusuma plugin for assigning gesture mapping per application."
15
+ spec.homepage = "https://github.com/iberianpig/fusuma-plugin-appmatcher"
16
+ spec.license = "MIT"
17
17
 
18
18
  # Specify which files should be added to the gem when it is released.
19
- spec.files = Dir['{bin,lib,exe}/**/*', 'LICENSE*', 'README*', '*.gemspec']
20
- spec.test_files = Dir['{test,spec,features}/**/*']
21
- spec.bindir = 'exe'
19
+ spec.files = Dir["{bin,lib,exe}/**/*", "LICENSE*", "README*", "*.gemspec"]
20
+ spec.test_files = Dir["{test,spec,features}/**/*"]
21
+ spec.bindir = "exe"
22
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
- spec.require_paths = ['lib']
23
+ spec.require_paths = ["lib"]
24
24
 
25
- spec.add_dependency "rexml" # ruby-dbus doesn't resolve dependency
26
- spec.add_runtime_dependency 'ruby-dbus'
25
+ spec.add_dependency "rexml" # ruby-dbus doesn't resolve dependency
26
+ spec.add_runtime_dependency "ruby-dbus"
27
27
 
28
- spec.add_dependency 'fusuma', '~> 2.0'
28
+ spec.add_dependency "fusuma", "~> 2.3"
29
+ spec.metadata["rubygems_mfa_required"] = "true"
30
+
31
+ spec.required_ruby_version = ">= 2.5.1" # https://packages.ubuntu.com/search?keywords=ruby&searchon=names&exact=1&suite=all&section=main
32
+ # support bionic (18.04LTS) 2.5.1
29
33
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'json'
4
- require 'dbus'
5
- require_relative './user_switcher'
3
+ require "json"
4
+ require "dbus"
5
+ require_relative "./user_switcher"
6
6
 
7
7
  module Fusuma
8
8
  module Plugin
@@ -21,7 +21,7 @@ module Fusuma
21
21
  @watch_start ||= begin
22
22
  pid = UserSwitcher.new.as_user do |user|
23
23
  @reader.close
24
- ENV['DBUS_SESSION_BUS_ADDRESS'] = "unix:path=/run/user/#{user.uid}/bus"
24
+ ENV["DBUS_SESSION_BUS_ADDRESS"] = "unix:path=/run/user/#{user.uid}/bus"
25
25
  register_on_application_changed(Matcher.new)
26
26
  end
27
27
  Process.detach(pid)
@@ -50,8 +50,8 @@ module Fusuma
50
50
  class Matcher
51
51
  def initialize
52
52
  session_bus = DBus.session_bus
53
- service = session_bus.service('org.gnome.Shell')
54
- @interface = service['/org/gnome/Shell']['org.gnome.Shell']
53
+ service = session_bus.service("org.gnome.Shell")
54
+ @interface = service["/org/gnome/Shell"]["org.gnome.Shell"]
55
55
  rescue DBus::Error => e
56
56
  MultiLogger.error "DBus::Error: #{e.message}"
57
57
 
@@ -116,7 +116,7 @@ module Fusuma
116
116
  new_application = active_application
117
117
  next if @old_application == new_application
118
118
 
119
- yield(new_application || 'NOT FOUND') if block_given?
119
+ yield(new_application || "NOT FOUND") if block_given?
120
120
  @old_application = new_application
121
121
  end
122
122
  end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "dbus"
5
+ require_relative "./user_switcher"
6
+
7
+ module Fusuma
8
+ module Plugin
9
+ module Appmatcher
10
+ # Search Active Window's Name
11
+ class GnomeExtension
12
+ attr_reader :matcher, :reader, :writer
13
+
14
+ def initialize
15
+ @reader, @writer = IO.pipe
16
+ end
17
+
18
+ # fork process and watch signal
19
+ # @return [Integer] Process id
20
+ def watch_start
21
+ @watch_start ||= begin
22
+ pid = UserSwitcher.new.as_user do |user|
23
+ @reader.close
24
+ ENV["DBUS_SESSION_BUS_ADDRESS"] = "unix:path=/run/user/#{user.uid}/bus"
25
+ register_on_application_changed(Matcher.new)
26
+ end
27
+ Process.detach(pid)
28
+ pid
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ # @param matcher [Matcher]
35
+ def register_on_application_changed(matcher)
36
+ # NOTE: push current application to pipe before start
37
+ @writer.puts(matcher.active_application)
38
+
39
+ matcher.on_active_application_changed do |name|
40
+ notify(name)
41
+ end
42
+
43
+ execute_loop(matcher)
44
+ end
45
+
46
+ def notify(name)
47
+ @writer.puts(name)
48
+ rescue Errno::EPIPE
49
+ exit 0
50
+ rescue StandardError => e
51
+ MultiLogger.error e.message
52
+ exit 1
53
+ end
54
+
55
+ def execute_loop(matcher)
56
+ loop = DBus::Main.new
57
+ loop << matcher.session_bus
58
+ loop.run
59
+ end
60
+
61
+ # Look up application name using dbus
62
+ class Matcher
63
+ attr_reader :session_bus
64
+
65
+ def initialize
66
+ @session_bus = DBus.session_bus
67
+ service = session_bus.service("org.gnome.Shell")
68
+ @interface = service["/dev/iberianpig/Appmatcher"]["dev.iberianpig.Appmatcher"]
69
+ rescue DBus::Error => e
70
+ MultiLogger.error "DBus::Error: #{e.message}"
71
+ MultiLogger.error "Have you installed GNOME extension?"
72
+ MultiLogger.error "$ fusuma-appmatcher --install-gnome-extension"
73
+ MultiLogger.error "Then Restart your session"
74
+
75
+ exit 1
76
+ end
77
+
78
+ # @return [Array<String>]
79
+ def running_applications
80
+ applications = JSON.parse(@interface.ListWindows, object_class: Application)
81
+ applications.map(&:wm_class)
82
+ rescue JSON::ParserError => e
83
+ MultiLogger.error e.message
84
+ nil
85
+ end
86
+
87
+ # @return [String]
88
+ def active_application
89
+ app = JSON.parse(@interface.ActiveWindow, object_class: Application)
90
+ app&.wm_class
91
+ rescue JSON::ParserError => e
92
+ MultiLogger.error e.message
93
+ nil
94
+ end
95
+
96
+ def on_active_application_changed
97
+ @interface.on_signal("ActiveWindowChanged") do |json|
98
+ # if app is is not found, fetch active_application_id
99
+ app =
100
+ begin
101
+ JSON.parse(json, object_class: Application)
102
+ rescue JSON::ParserError => e
103
+ MultiLogger.error e.message
104
+ nil
105
+ end
106
+
107
+ yield(app&.wm_class || "NOT FOUND") if block_given?
108
+ end
109
+ end
110
+ end
111
+
112
+ # Focused Application
113
+ class Application
114
+ attr_reader :wm_class, :pid, :id, :title, :focus
115
+
116
+ # to specify as object_class in JSON.parse
117
+ def []=(key, value)
118
+ instance_variable_set("@#{key}", value)
119
+ end
120
+
121
+ def inspect
122
+ "wm_class: #{wm_class}, pid: #{pid}, id: #{id}, title: #{title}, focus: #{focus}"
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,75 @@
1
+ const { Gio, GLib } = imports.gi;
2
+
3
+ const DBUS_INTERFACE = `
4
+ <node>
5
+ <interface name="dev.iberianpig.Appmatcher">
6
+ <method name="ActiveWindow">
7
+ <arg type="s" direction="out" name="win"/>
8
+ </method>
9
+ <method name="ListWindows">
10
+ <arg type="s" direction="out" name="wins"/>
11
+ </method>
12
+ <signal name="ActiveWindowChanged">
13
+ <arg type="s" name="new_win"/>
14
+ </signal>
15
+ </interface>
16
+ </node>`;
17
+
18
+ class Extension {
19
+ constructor() {
20
+ }
21
+
22
+ enable() {
23
+ this._dbus = Gio.DBusExportedObject.wrapJSObject(DBUS_INTERFACE, this);
24
+ this._dbus.export(Gio.DBus.session, '/dev/iberianpig/Appmatcher');
25
+ this._callback_id = global.display.connect('notify::focus-window', ()=> {
26
+ this.activeWindowChanged()
27
+ })
28
+
29
+ }
30
+
31
+ disable() {
32
+ this._dbus.flush();
33
+ this._dbus.unexport();
34
+ if (this._callback_id) {
35
+ global.display.disconnect(this._callback_id);
36
+ delete this._callback_id
37
+ }
38
+ delete this._dbus;
39
+ }
40
+
41
+ activeWindowChanged() {
42
+ const w = global.display.get_focus_window();
43
+ if(!w) { return; }
44
+
45
+ try {
46
+ const obj = { wm_class: w.get_wm_class(), pid: w.get_pid(), id: w.get_id(), title: w.get_title(), focus: w.has_focus()}
47
+ this._dbus.emit_signal('ActiveWindowChanged', new GLib.Variant('(s)', [JSON.stringify(obj)]));
48
+ } catch (e) {
49
+ global.logError(e, 'failed to Emit DBus signal');
50
+ }
51
+ }
52
+
53
+ ListWindows() {
54
+ const wins = global.get_window_actors()
55
+ .map(a => a.meta_window)
56
+ .map(w => ({ wm_class: w.get_wm_class(), pid: w.get_pid(), id: w.get_id(), title: w.get_title(), focus: w.has_focus()}));
57
+ return JSON.stringify(wins);
58
+ }
59
+
60
+ ActiveWindow() {
61
+ const actor = global.get_window_actors().find(a=>a.meta_window.has_focus()===true)
62
+ if(!actor) { return '{}'; }
63
+ const w = actor.get_meta_window()
64
+ try {
65
+ const obj = { wm_class: w.get_wm_class(), pid: w.get_pid(), id: w.get_id(), title: w.get_title(), focus: w.has_focus()}
66
+ return JSON.stringify(obj);
67
+ } catch (e) {
68
+ global.logError(e, 'failed to fetch ActiveWindow()');
69
+ }
70
+ }
71
+ }
72
+
73
+ function init() {
74
+ return new Extension();
75
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "Appmatcher",
3
+ "description": "notify focused application using D-Bus",
4
+ "shell-version" : [
5
+ "3.36",
6
+ "3.38",
7
+ "40",
8
+ "41"
9
+ ],
10
+ "url" : "https://github.com/iberianpig/fusuma-plugin-appmatcher",
11
+ "uuid": "appmatcher@iberianpig.dev",
12
+ "version" : 1
13
+ }
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../user_switcher"
4
+ require "fileutils"
5
+
6
+ module Fusuma
7
+ module Plugin
8
+ module Appmatcher
9
+ module GnomeExtensions
10
+ # Install Gnome Extension
11
+ class Installer
12
+ EXTENSION = "./appmatcher@iberianpig.dev"
13
+
14
+ def install
15
+ pid = UserSwitcher.new.as_user do |user|
16
+ FileUtils.cp_r(source_path, user_extension_dir(user.username))
17
+ puts "Installed Appmatcher Gnome Shell Extension to #{user_extension_dir(user.username)}"
18
+ puts "Restart your session, then activate Appmatcher on gnome-extensions-app"
19
+ end
20
+ Process.waitpid(pid)
21
+ end
22
+
23
+ def uninstall
24
+ return puts "Appmatcher Gnome Shell Extension is not installed in #{user_extension_dir}/" unless installed?
25
+
26
+ pid = UserSwitcher.new.as_user do |user|
27
+ FileUtils.rm_r(install_path(user.username))
28
+ puts "Uninstalled Appmatcher Gnome Shell Extension from #{install_path(user.username)}"
29
+ end
30
+ Process.waitpid(pid)
31
+ end
32
+
33
+ def installed?
34
+ File.exist?(install_path)
35
+ end
36
+
37
+ private
38
+
39
+ def user_extension_dir(username = login_username)
40
+ File.expand_path("#{Dir.home(username)}/.local/share/gnome-shell/extensions/")
41
+ end
42
+
43
+ def install_path(username = login_username)
44
+ File.expand_path("#{Dir.home(username)}/.local/share/gnome-shell/extensions/#{EXTENSION}")
45
+ end
46
+
47
+ def source_path
48
+ File.expand_path(EXTENSION, __dir__)
49
+ end
50
+
51
+ def login_username
52
+ UserSwitcher.new.login_user.username
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -1,16 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'fusuma/custom_process'
4
- require 'etc'
3
+ require "fusuma/custom_process"
4
+ require "etc"
5
5
 
6
6
  module Fusuma
7
7
  module Plugin
8
8
  module Appmatcher
9
+ # Drop sudo privileges
9
10
  class UserSwitcher
10
11
  include CustomProcess
11
12
  User = Struct.new(:username, :uid, :gid)
13
+
14
+ attr_reader :login_user
15
+
12
16
  def initialize
13
- username = ENV['SUDO_USER'] || Etc.getlogin
17
+ username = ENV["SUDO_USER"] || Etc.getlogin
14
18
  uid = `id -u #{username}`.chomp.to_i
15
19
  gid = `id -g #{username}`.chomp.to_i
16
20
  @login_user = User.new(username, uid, gid)
@@ -3,7 +3,7 @@
3
3
  module Fusuma
4
4
  module Plugin
5
5
  module Appmatcher
6
- VERSION = '0.1.6'
6
+ VERSION = "0.2.3"
7
7
  end
8
8
  end
9
9
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'open3'
4
- require_relative './user_switcher'
5
- require 'fusuma/multi_logger'
6
- require 'fusuma/custom_process'
3
+ require "open3"
4
+ require_relative "./user_switcher"
5
+ require "fusuma/multi_logger"
6
+ require "fusuma/custom_process"
7
7
 
8
8
  module Fusuma
9
9
  module Plugin
@@ -50,7 +50,7 @@ module Fusuma
50
50
  class Matcher
51
51
  # @return [Array<String>]
52
52
  def running_applications
53
- `xprop -root _NET_CLIENT_LIST_STACKING`.split(', ')
53
+ `xprop -root _NET_CLIENT_LIST_STACKING`.split(", ")
54
54
  .map { |id_str| id_str.match(/0x[\da-z]{2,}/).to_s }
55
55
  .map { |id| active_application(id) }
56
56
  end
@@ -59,16 +59,16 @@ module Fusuma
59
59
  # @return [NilClass]
60
60
  def active_application(id = active_window_id)
61
61
  @cache ||= {}
62
- @cache[id] ||= begin
63
- return if id.nil?
64
-
65
- `xprop -id #{id} WM_CLASS | cut -d "=" -f 2 | tr -d '"'`.strip.split(', ').last
66
- end
62
+ @cache[id] ||= if id.nil?
63
+ nil
64
+ else
65
+ `xprop -id #{id} WM_CLASS | cut -d "=" -f 2 | tr -d '"'`.strip.split(", ").last
66
+ end
67
67
  end
68
68
 
69
69
  def on_active_application_changed
70
70
  active_window_id(watch: true) do |id|
71
- yield(active_application(id) || 'NOT FOUND')
71
+ yield(active_application(id) || "NOT FOUND")
72
72
  end
73
73
  end
74
74
 
@@ -99,7 +99,7 @@ module Fusuma
99
99
  # @param spy [TrueClass, FalseClass]
100
100
  # @return [String]
101
101
  def xprop_active_window_id(spy)
102
- spy_option = '-spy' if spy
102
+ spy_option = "-spy" if spy
103
103
  "xprop #{spy_option} -root _NET_ACTIVE_WINDOW"
104
104
  end
105
105
  end
@@ -1,9 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'fusuma/plugin/appmatcher/version'
3
+ require "fusuma/plugin/appmatcher/version"
4
4
 
5
- require_relative 'appmatcher/x11'
6
- require_relative 'appmatcher/gnome'
5
+ require_relative "appmatcher/x11"
6
+ require_relative "appmatcher/gnome"
7
+ require_relative "appmatcher/gnome_extension"
8
+ require_relative "appmatcher/gnome_extensions/installer"
7
9
 
8
10
  module Fusuma
9
11
  module Plugin
@@ -17,24 +19,34 @@ module Fusuma
17
19
  when /x11/
18
20
  return X11
19
21
  when /wayland/
20
- return Gnome if xdg_current_desktop =~ /GNOME/
22
+ case xdg_current_desktop
23
+ when /GNOME/
24
+ return GnomeExtension if GnomeExtensions::Installer.new.installed?
25
+
26
+ return Gnome
27
+ end
21
28
  end
22
- MultiLogger.error(
23
- <<~ERROR
24
- appmatcher doesn't support
25
- XDG_CURRENT_DESKTOP: '#{xdg_current_desktop}'
26
- XDG_SESSION_TYPE: '#{xdg_session_type}'"
27
- ERROR
28
- )
29
+
30
+ error_message_not_supported
29
31
  exit 1
30
32
  end
31
33
 
32
34
  def xdg_session_type
33
- ENV.fetch('XDG_SESSION_TYPE', '')
35
+ ENV.fetch("XDG_SESSION_TYPE", "")
34
36
  end
35
37
 
36
38
  def xdg_current_desktop
37
- ENV.fetch('XDG_CURRENT_DESKTOP', '')
39
+ ENV.fetch("XDG_CURRENT_DESKTOP", "")
40
+ end
41
+
42
+ def error_message_not_supported
43
+ MultiLogger.error(
44
+ <<~ERROR
45
+ appmatcher doesn't support
46
+ XDG_CURRENT_DESKTOP: '#{xdg_current_desktop}'
47
+ XDG_SESSION_TYPE: '#{xdg_session_type}'"
48
+ ERROR
49
+ )
38
50
  end
39
51
  end
40
52
  end
@@ -5,7 +5,7 @@ module Fusuma
5
5
  module Buffers
6
6
  # Buffer events having KeypressRecord
7
7
  class AppmatcherBuffer < Buffer
8
- DEFAULT_SOURCE = 'appmatcher_parser'
8
+ DEFAULT_SOURCE = "appmatcher_parser"
9
9
 
10
10
  # @param event [Event]
11
11
  def buffer(event)
@@ -5,9 +5,8 @@ module Fusuma
5
5
  module Detectors
6
6
  # Detect KeypressEvent from KeypressBuffer
7
7
  class AppmatcherDetector < Detector
8
- SOURCES = ['appmatcher']
9
- BUFFER_TYPE = 'appmatcher'
10
- DEFAULT_NAME = 'global'
8
+ SOURCES = ["appmatcher"].freeze
9
+ BUFFER_TYPE = "appmatcher"
11
10
 
12
11
  # Always watch buffers and detect them.
13
12
  def watch?
@@ -25,7 +24,7 @@ module Fusuma
25
24
  record = buffer.events.last.record
26
25
 
27
26
  context_record = Events::Records::ContextRecord.new(
28
- name: 'application',
27
+ name: "application",
29
28
  value: record.name
30
29
  )
31
30
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../appmatcher.rb'
3
+ require_relative "../appmatcher"
4
4
 
5
5
  module Fusuma
6
6
  module Plugin
@@ -13,12 +13,12 @@ module Fusuma
13
13
  @backend ||= Appmatcher.backend_klass.new
14
14
 
15
15
  @pid ||= begin
16
- pid = @backend.watch_start
17
- # NOTE: Closing the parent process's pipe
18
- @backend.writer.close
16
+ pid = @backend.watch_start
17
+ # NOTE: Closing the parent process's pipe
18
+ @backend.writer.close
19
19
 
20
- pid
21
- end
20
+ pid
21
+ end
22
22
 
23
23
  @backend.reader
24
24
  end
@@ -5,7 +5,7 @@ module Fusuma
5
5
  module Parsers
6
6
  # Generate AppmatcherRecord from libinput_command_input
7
7
  class AppmatcherParser < Parser
8
- DEFAULT_SOURCE = 'appmatcher_input'
8
+ DEFAULT_SOURCE = "appmatcher_input"
9
9
 
10
10
  # @param record [String]
11
11
  # @return [Records::Gesture, nil]
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ module Fusuma
6
+ module Plugin
7
+ module Appmatcher
8
+ module GnomeExtensions
9
+ RSpec.describe Installer do
10
+ describe "#install" do
11
+ it "should copy file to users dir"
12
+ end
13
+ describe "#uninstall" do
14
+ context "when extension is NOT installed" do
15
+ it "should remove file to users dir"
16
+ end
17
+ context "when extension is NOT installed" do
18
+ it "should NOT execute"
19
+ end
20
+ end
21
+ describe "#installed?" do
22
+ it "check extension is in the installed path"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
- require './lib/fusuma/plugin/appmatcher/gnome'
3
+ require "spec_helper"
4
+ require "./lib/fusuma/plugin/appmatcher/gnome"
5
5
 
6
6
  module Fusuma
7
7
  module Plugin
8
8
  module Appmatcher
9
9
  RSpec.describe Gnome do
10
- it 'requires ruby-dbus' do
10
+ it "requires ruby-dbus" do
11
11
  expect(DBus).not_to be nil
12
12
  end
13
13
  end
@@ -1,36 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
3
+ require "spec_helper"
4
4
 
5
5
  module Fusuma
6
6
  module Plugin
7
7
  RSpec.describe Appmatcher do
8
- it 'has a version number' do
8
+ it "has a version number" do
9
9
  expect(Appmatcher::VERSION).not_to be nil
10
10
  end
11
11
 
12
- describe '#backend_klass' do
13
- context 'when XDG_CURRENT_DESKTOP is UNKNOWN' do
14
- before { allow(Appmatcher).to receive(:xdg_current_desktop).and_return('UNKNOWN') }
15
- it { expect { Appmatcher.backend_klass }.to raise_error }
12
+ describe "#backend_klass" do
13
+ subject { Appmatcher.backend_klass }
14
+ context "when XDG_SESSION_TYPE is x11" do
15
+ before { allow(Appmatcher).to receive(:xdg_session_type).and_return("x11") }
16
+ it { is_expected.to eq Appmatcher::X11 }
16
17
  end
17
18
 
18
- context 'when XDG_SESSION_TYPE is x11' do
19
- before { allow(Appmatcher).to receive(:xdg_session_type).and_return('x11') }
20
- it { expect(Appmatcher.backend_klass).to eq Appmatcher::X11 }
21
- end
19
+ context "when XDG_SESSION_TYPE is wayland" do
20
+ before { allow(Appmatcher).to receive(:xdg_session_type).and_return("wayland") }
21
+
22
+ context "when XDG_CURRENT_DESKTOP is ubuntu:GNOME" do
23
+ before { allow(Appmatcher).to receive(:xdg_current_desktop).and_return("ubuntu:GNOME") }
22
24
 
23
- context 'when XDG_SESSION_TYPE is wayland' do
24
- before { allow(Appmatcher).to receive(:xdg_session_type).and_return('wayland') }
25
+ context "when gnome-extension is installed" do
26
+ before do
27
+ allow_any_instance_of(Appmatcher::GnomeExtensions::Installer).to receive(:installed?).and_return(true)
28
+ end
29
+ it { is_expected.to eq Appmatcher::GnomeExtension }
30
+ end
25
31
 
26
- context 'when XDG_CURRENT_DESKTOP is ubuntu:GNOME' do
27
- before { allow(Appmatcher).to receive(:xdg_current_desktop).and_return('ubuntu:GNOME') }
28
- it { expect(Appmatcher.backend_klass).to eq Appmatcher::Gnome }
32
+ context "when gnome-extension is NOT installed" do
33
+ before do
34
+ allow_any_instance_of(Appmatcher::GnomeExtensions::Installer).to receive(:installed?).and_return(false)
35
+ end
36
+ it { is_expected.to eq Appmatcher::Gnome }
37
+ end
29
38
  end
30
39
 
31
- context 'when XDG_CURRENT_DESKTOP is UNKNOWN' do
32
- before { allow(Appmatcher).to receive(:xdg_current_desktop).and_return('UNKNOWN') }
33
- it { expect { Appmatcher.backend_klass }.to raise_error }
40
+ context "when XDG_CURRENT_DESKTOP is UNKNOWN" do
41
+ before do
42
+ allow(Appmatcher).to receive(:xdg_current_desktop).and_return("UNKNOWN")
43
+ allow(MultiLogger).to receive(:error)
44
+ end
45
+ it { expect { subject }.to raise_error(SystemExit) }
34
46
  end
35
47
  end
36
48
  end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
3
+ require "spec_helper"
4
4
 
5
- require 'fusuma/plugin/detectors/detector'
6
- require 'fusuma/plugin/buffers/buffer'
5
+ require "fusuma/plugin/detectors/detector"
6
+ require "fusuma/plugin/buffers/buffer"
7
7
 
8
- require './lib/fusuma/plugin/buffers/appmatcher_buffer'
9
- require './lib/fusuma/plugin/detectors/appmatcher_detector'
8
+ require "./lib/fusuma/plugin/buffers/appmatcher_buffer"
9
+ require "./lib/fusuma/plugin/detectors/appmatcher_detector"
10
10
 
11
11
  module Fusuma
12
12
  module Plugin
@@ -17,8 +17,8 @@ module Fusuma
17
17
  @buffer = Buffers::AppmatcherBuffer.new
18
18
  end
19
19
 
20
- describe '#detector' do
21
- context 'with no appmatcher event in buffer' do
20
+ describe "#detector" do
21
+ context "with no appmatcher event in buffer" do
22
22
  before do
23
23
  @buffer.clear
24
24
  end
@@ -27,39 +27,39 @@ module Fusuma
27
27
  end
28
28
  end
29
29
 
30
- context 'with appmatcher events in buffer' do
30
+ context "with appmatcher events in buffer" do
31
31
  before do
32
- record = Events::Records::AppmatcherRecord.new(name: 'dummy')
33
- event = Events::Event.new(tag: 'appmatcher_parser', record: record)
32
+ record = Events::Records::AppmatcherRecord.new(name: "dummy")
33
+ event = Events::Event.new(tag: "appmatcher_parser", record: record)
34
34
 
35
35
  @buffer.buffer(event)
36
36
  end
37
37
  it { expect(@detector.detect([@buffer])).to be_a Events::Event }
38
- it 'should detect ContextRecord' do
38
+ it "should detect ContextRecord" do
39
39
  expect(@detector.detect([@buffer]).record).to be_a Events::Records::ContextRecord
40
40
  end
41
- it 'should detect context: { application: dummy }' do
41
+ it "should detect context: { application: dummy }" do
42
42
  record = @detector.detect([@buffer]).record
43
43
  expect(record.name).to eq :application
44
- expect(record.value).to eq 'dummy'
44
+ expect(record.value).to eq "dummy"
45
45
  end
46
46
  end
47
47
 
48
- context 'with two different appmatcher events in buffer' do
48
+ context "with two different appmatcher events in buffer" do
49
49
  before do
50
- record1 = Events::Records::AppmatcherRecord.new(name: 'dummy1')
51
- record2 = Events::Records::AppmatcherRecord.new(name: 'dummy2')
52
- event1 = Events::Event.new(tag: 'appmatcher_parser', record: record1)
53
- event2 = Events::Event.new(tag: 'appmatcher_parser', record: record2)
50
+ record1 = Events::Records::AppmatcherRecord.new(name: "dummy1")
51
+ record2 = Events::Records::AppmatcherRecord.new(name: "dummy2")
52
+ event1 = Events::Event.new(tag: "appmatcher_parser", record: record1)
53
+ event2 = Events::Event.new(tag: "appmatcher_parser", record: record2)
54
54
 
55
55
  @buffer.buffer(event1)
56
56
  @buffer.buffer(event2)
57
57
  end
58
58
 
59
- it 'should detect latest application' do
59
+ it "should detect latest application" do
60
60
  record = @detector.detect([@buffer]).record
61
61
  expect(record.name).to eq :application
62
- expect(record.value).to eq 'dummy2'
62
+ expect(record.value).to eq "dummy2"
63
63
  end
64
64
  end
65
65
  end
data/spec/spec_helper.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bundler/setup'
4
- require 'fusuma/plugin/appmatcher'
3
+ require "bundler/setup"
4
+ require "fusuma/plugin/appmatcher"
5
5
 
6
6
  RSpec.configure do |config|
7
7
  # Enable flags like --only-failures and --next-failure
8
- config.example_status_persistence_file_path = '.rspec_status'
8
+ config.example_status_persistence_file_path = ".rspec_status"
9
9
 
10
10
  # Disable RSpec exposing methods globally on `Module` and `main`
11
11
  config.disable_monkey_patching!
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fusuma-plugin-appmatcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - iberianpig
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-02 00:00:00.000000000 Z
11
+ date: 2022-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rexml
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '2.0'
47
+ version: '2.3'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '2.0'
54
+ version: '2.3'
55
55
  description: fusuma-plugin-appmatcher is Fusuma plugin for assigning gesture mapping
56
56
  per application.
57
57
  email:
@@ -69,6 +69,10 @@ files:
69
69
  - fusuma-plugin-appmatcher.gemspec
70
70
  - lib/fusuma/plugin/appmatcher.rb
71
71
  - lib/fusuma/plugin/appmatcher/gnome.rb
72
+ - lib/fusuma/plugin/appmatcher/gnome_extension.rb
73
+ - lib/fusuma/plugin/appmatcher/gnome_extensions/appmatcher@iberianpig.dev/extension.js
74
+ - lib/fusuma/plugin/appmatcher/gnome_extensions/appmatcher@iberianpig.dev/metadata.json
75
+ - lib/fusuma/plugin/appmatcher/gnome_extensions/installer.rb
72
76
  - lib/fusuma/plugin/appmatcher/user_switcher.rb
73
77
  - lib/fusuma/plugin/appmatcher/version.rb
74
78
  - lib/fusuma/plugin/appmatcher/x11.rb
@@ -77,14 +81,16 @@ files:
77
81
  - lib/fusuma/plugin/events/records/appmatcher_record.rb
78
82
  - lib/fusuma/plugin/inputs/appmatcher_input.rb
79
83
  - lib/fusuma/plugin/parsers/appmatcher_parser.rb
84
+ - spec/fusuma/plugin/appmatcher/gnome_extensions/installer_spec.rb
80
85
  - spec/fusuma/plugin/appmatcher/gnome_spec.rb
81
86
  - spec/fusuma/plugin/appmatcher_spec.rb
82
- - spec/fusuma/plugin/inputs/appmatcher_detector_spec.rb
87
+ - spec/fusuma/plugin/detectors/appmatcher_detector_spec.rb
83
88
  - spec/spec_helper.rb
84
89
  homepage: https://github.com/iberianpig/fusuma-plugin-appmatcher
85
90
  licenses:
86
91
  - MIT
87
- metadata: {}
92
+ metadata:
93
+ rubygems_mfa_required: 'true'
88
94
  post_install_message:
89
95
  rdoc_options: []
90
96
  require_paths:
@@ -93,19 +99,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
93
99
  requirements:
94
100
  - - ">="
95
101
  - !ruby/object:Gem::Version
96
- version: '0'
102
+ version: 2.5.1
97
103
  required_rubygems_version: !ruby/object:Gem::Requirement
98
104
  requirements:
99
105
  - - ">="
100
106
  - !ruby/object:Gem::Version
101
107
  version: '0'
102
108
  requirements: []
103
- rubygems_version: 3.2.15
109
+ rubygems_version: 3.0.3.1
104
110
  signing_key:
105
111
  specification_version: 4
106
112
  summary: Fusuma plugin to assign gesture mapping per application
107
113
  test_files:
108
- - spec/fusuma/plugin/appmatcher/gnome_spec.rb
109
114
  - spec/fusuma/plugin/appmatcher_spec.rb
110
- - spec/fusuma/plugin/inputs/appmatcher_detector_spec.rb
115
+ - spec/fusuma/plugin/appmatcher/gnome_extensions/installer_spec.rb
116
+ - spec/fusuma/plugin/appmatcher/gnome_spec.rb
117
+ - spec/fusuma/plugin/detectors/appmatcher_detector_spec.rb
111
118
  - spec/spec_helper.rb