wmadd 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,4 @@
1
+ module Wmadd
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ 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: []