fusuma-plugin-appmatcher 0.1.6 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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