wmadd 0.1.0
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 +7 -0
- data/.rspec +3 -0
- data/LICENSE.txt +674 -0
- data/README.md +18 -0
- data/Rakefile +8 -0
- data/exe/wmadd +5 -0
- data/lib/wmadd/version.rb +5 -0
- data/lib/wmadd/x.rb +658 -0
- data/lib/wmadd.rb +160 -0
- data/sig/window_geometry.rbs +4 -0
- metadata +67 -0
data/lib/wmadd.rb
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'wmadd/version'
|
4
|
+
require_relative 'wmadd/x'
|
5
|
+
require 'tmtms/timer'
|
6
|
+
require 'timeout'
|
7
|
+
|
8
|
+
# Wmadd
|
9
|
+
class Wmadd
|
10
|
+
DEFAULT_OPACITY = 0xFFFFFFFF
|
11
|
+
OVERWRAP_OPACITY = 0x80000000
|
12
|
+
|
13
|
+
def self.start
|
14
|
+
self.new.start
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@display = X::Display.new
|
19
|
+
@root = @display.default_root_window
|
20
|
+
@timer = Tmtms::Timer.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def start
|
24
|
+
window_list.each do |w|
|
25
|
+
watch_resize_event(w)
|
26
|
+
end
|
27
|
+
|
28
|
+
@root.select_input(X::SUBSTRUCTURE_NOTIFY_MASK | X::PROPERTY_CHANGE_MASK)
|
29
|
+
@osd = @root.create_simple_window(100, 100, 200, 50, 0, 0, 0xe0e0e0)
|
30
|
+
@osd.change_property_atom(:_NET_WM_WINDOW_TYPE, X::PROP_MODE_REPLACE, :_NET_WM_WINDOW_TYPE_NOTIFICATION)
|
31
|
+
@osd.select_input(X::EXPOSURE_MASK)
|
32
|
+
@gc = @osd.create_gc
|
33
|
+
@gc.set_background(0xe0e0e0)
|
34
|
+
@gc.set_foreground(0)
|
35
|
+
@gc.set_font(@display.load_font("fixed"))
|
36
|
+
|
37
|
+
while true
|
38
|
+
ev = @display.next_event
|
39
|
+
case ev
|
40
|
+
when X::CreateWindowEvent
|
41
|
+
window_list.each do |w|
|
42
|
+
watch_resize_event(w)
|
43
|
+
end
|
44
|
+
when X::ExposeEvent
|
45
|
+
display_osd if ev.window == @osd.id
|
46
|
+
when X::PropertyEvent
|
47
|
+
if ev.atom == @display.intern_atom(:_NET_ACTIVE_WINDOW)
|
48
|
+
reset_opacity
|
49
|
+
end
|
50
|
+
when X::ConfigureEvent
|
51
|
+
lazy_reset_opacity
|
52
|
+
win = X::Window.new(@display, ev.window)
|
53
|
+
display_osd(win)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def display_osd(win=nil)
|
59
|
+
if win
|
60
|
+
wm_win = wm_window(win) or return
|
61
|
+
hints = wm_win.wm_normal_hints or return
|
62
|
+
top_win = top_window(win) or return
|
63
|
+
|
64
|
+
x, y = top_win.geometry.then{[_1.x, _1.y]}
|
65
|
+
width, height = win.geometry.then{[_1.width, _1.height]}
|
66
|
+
|
67
|
+
@osd_x = x + ((width - 200) / 2)
|
68
|
+
@osd_y = y + ((height - 50) / 2)
|
69
|
+
@osd_str = "#{width} x #{height} +#{x}+#{y}"
|
70
|
+
if hints.width_inc > 0 && hints.height_inc > 0
|
71
|
+
width -= hints.base_width
|
72
|
+
height -= hints.base_height
|
73
|
+
@osd_str += " (#{width / hints.width_inc} x #{height / hints.height_inc})"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
@osd.map_window
|
78
|
+
@osd.clear
|
79
|
+
@gc.draw_string(10, 30, @osd_str)
|
80
|
+
@osd.move_window(@osd_x, @osd_y)
|
81
|
+
@display.flush
|
82
|
+
@job&.cancel
|
83
|
+
@job = @timer.set(1) do
|
84
|
+
@osd.unmap_window
|
85
|
+
@display.flush
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def lazy_reset_opacity
|
90
|
+
@reset_opacity_job&.cancel
|
91
|
+
@reset_opacity_job = @timer.set(0.1){reset_opacity}
|
92
|
+
end
|
93
|
+
|
94
|
+
def top_window(win)
|
95
|
+
top = win
|
96
|
+
while top.parent.id != @root.id
|
97
|
+
top = top.parent
|
98
|
+
end
|
99
|
+
top
|
100
|
+
end
|
101
|
+
|
102
|
+
def wm_window(win)
|
103
|
+
while win && win.parent&.id != @root.id
|
104
|
+
if win.window_attributes.map_state == X::IS_VIEWABLE && win.window_type == :normal
|
105
|
+
return win
|
106
|
+
end
|
107
|
+
win = win.parent
|
108
|
+
end
|
109
|
+
nil
|
110
|
+
end
|
111
|
+
|
112
|
+
def reset_opacity
|
113
|
+
return unless @root.active_window
|
114
|
+
active_win = wm_window(@root.active_window) or return
|
115
|
+
|
116
|
+
f = false
|
117
|
+
window_list.each do |w|
|
118
|
+
if active_win.id == w.id
|
119
|
+
f = true
|
120
|
+
set_default_opacity(w)
|
121
|
+
next
|
122
|
+
end
|
123
|
+
if f && overwrap?(w, active_win)
|
124
|
+
set_overwrap_opacity(w)
|
125
|
+
next
|
126
|
+
end
|
127
|
+
set_default_opacity(w)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def overwrap?(w1, w2)
|
132
|
+
g1 = top_window(w1).geometry
|
133
|
+
g2 = top_window(w2).geometry
|
134
|
+
g1.x < g2.x+g2.width && g1.x+g1.width > g2.x && g1.y < g2.y+g2.height && g1.y+g1.height > g2.y
|
135
|
+
end
|
136
|
+
|
137
|
+
def set_default_opacity(win)
|
138
|
+
win.change_property_cardinal(:_NET_WM_WINDOW_OPACITY, X::PROP_MODE_REPLACE, DEFAULT_OPACITY)
|
139
|
+
end
|
140
|
+
|
141
|
+
def set_overwrap_opacity(win)
|
142
|
+
win.change_property_cardinal(:_NET_WM_WINDOW_OPACITY, X::PROP_MODE_REPLACE, OVERWRAP_OPACITY)
|
143
|
+
end
|
144
|
+
|
145
|
+
def window_list(win=@root)
|
146
|
+
list = []
|
147
|
+
win.query_tree&.each do |w|
|
148
|
+
if w.window_attributes.map_state == X::IS_VIEWABLE && w.window_type == :normal
|
149
|
+
list.push w
|
150
|
+
else
|
151
|
+
list.push window_list(w)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
list.flatten
|
155
|
+
end
|
156
|
+
|
157
|
+
def watch_resize_event(win)
|
158
|
+
win.select_input(X::STRUCTURE_NOTIFY_MASK)
|
159
|
+
end
|
160
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: wmadd
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- TOMITA Masahiro
|
8
|
+
bindir: exe
|
9
|
+
cert_chain: []
|
10
|
+
date: 2024-10-06 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: tmtms_timer
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '0'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '0'
|
26
|
+
description: show window geometry
|
27
|
+
email:
|
28
|
+
- tommy@tmtm.org
|
29
|
+
executables:
|
30
|
+
- wmadd
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- ".rspec"
|
35
|
+
- LICENSE.txt
|
36
|
+
- README.md
|
37
|
+
- Rakefile
|
38
|
+
- exe/wmadd
|
39
|
+
- lib/wmadd.rb
|
40
|
+
- lib/wmadd/version.rb
|
41
|
+
- lib/wmadd/x.rb
|
42
|
+
- sig/window_geometry.rbs
|
43
|
+
homepage: https://gitlab.com/tmtms/wmadd
|
44
|
+
licenses:
|
45
|
+
- GPLv3
|
46
|
+
metadata:
|
47
|
+
homepage_uri: https://gitlab.com/tmtms/wmadd
|
48
|
+
source_code_uri: https://gitlab.com/tmtms/wmadd
|
49
|
+
rubygems_mfa_required: 'true'
|
50
|
+
rdoc_options: []
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 3.3.0
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
requirements: []
|
64
|
+
rubygems_version: 3.6.0.dev
|
65
|
+
specification_version: 4
|
66
|
+
summary: show window geometry
|
67
|
+
test_files: []
|