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/README.md
ADDED
data/Rakefile
ADDED
data/exe/wmadd
ADDED
data/lib/wmadd/x.rb
ADDED
@@ -0,0 +1,658 @@
|
|
1
|
+
require 'fiddle/import'
|
2
|
+
|
3
|
+
class Wmadd
|
4
|
+
module X11
|
5
|
+
extend Fiddle::Importer
|
6
|
+
dlload 'libX11.so.6'
|
7
|
+
typealias 'XID', 'unsigned long'
|
8
|
+
typealias 'Window', 'XID'
|
9
|
+
typealias 'Pixmap', 'XID'
|
10
|
+
typealias 'Colormap', 'XID'
|
11
|
+
typealias 'Drawable', 'XID'
|
12
|
+
typealias 'Font', 'XID'
|
13
|
+
typealias 'Status', 'int'
|
14
|
+
typealias 'Atom', 'unsigned long'
|
15
|
+
typealias 'Bool', 'int'
|
16
|
+
typealias 'GC', 'void*'
|
17
|
+
typealias 'Time', 'unsigned long'
|
18
|
+
|
19
|
+
def self.struct(members)
|
20
|
+
klass = super
|
21
|
+
|
22
|
+
h = members.map.to_h do |member|
|
23
|
+
if member =~ /\A(.*\*\s*)(\w+)\z/
|
24
|
+
name = $2
|
25
|
+
pointer = true
|
26
|
+
elsif member =~ /(\w+)\z/
|
27
|
+
name = $1
|
28
|
+
pointer = false
|
29
|
+
end
|
30
|
+
[name.intern, pointer]
|
31
|
+
end
|
32
|
+
|
33
|
+
klass.define_singleton_method :attributes do
|
34
|
+
h.keys
|
35
|
+
end
|
36
|
+
|
37
|
+
klass.define_method :to_h do
|
38
|
+
super().transform_values{|v| v.is_a?(Fiddle::Pointer) && v.null? ? nil : v}
|
39
|
+
end
|
40
|
+
|
41
|
+
klass.define_method :inspect do
|
42
|
+
h = to_h.transform_values{|v| v.is_a?(Fiddle::Pointer) ? "(pointer)" : v}
|
43
|
+
"#<#{klass.name}: #{h.inspect}>"
|
44
|
+
end
|
45
|
+
|
46
|
+
klass
|
47
|
+
end
|
48
|
+
|
49
|
+
Screen = struct [
|
50
|
+
'XExtData *ext_data',
|
51
|
+
'struct _XDisplay *display',
|
52
|
+
'Window root',
|
53
|
+
'int width',
|
54
|
+
'int height',
|
55
|
+
'int mwidth',
|
56
|
+
'int mheight',
|
57
|
+
'int ndepths',
|
58
|
+
'Depth *depths',
|
59
|
+
'int root_depth',
|
60
|
+
'Visual *root_visual',
|
61
|
+
'GC default_gc',
|
62
|
+
'Colormap cmap',
|
63
|
+
'unsigned long white_pixel',
|
64
|
+
'unsigned long black_pixel',
|
65
|
+
'int max_maps',
|
66
|
+
'int min_maps',
|
67
|
+
'int backing_store',
|
68
|
+
'Bool save_unders',
|
69
|
+
'long root_input_mask',
|
70
|
+
]
|
71
|
+
|
72
|
+
Window = struct ['Window window']
|
73
|
+
Pointer = struct ['void *ptr']
|
74
|
+
XClassHint = struct ['char *name', 'char *class_name']
|
75
|
+
XSizeHints = struct [
|
76
|
+
'long flags', 'int x', 'int y', 'int width', 'int height',
|
77
|
+
'int min_width', 'int min_height', 'int max_width', 'int max_height',
|
78
|
+
'int width_inc', 'int height_inc',
|
79
|
+
'int min_aspect_x', 'int min_aspect_y', 'int max_aspect_x', 'int max_aspect_y',
|
80
|
+
'int base_width', 'int base_height',
|
81
|
+
'int win_gravity',
|
82
|
+
]
|
83
|
+
XTextProperty = struct ['unsigned char *value', 'Atom encoding', 'int format', 'unsigned long nitems']
|
84
|
+
XCreateWindowEvent = struct [
|
85
|
+
'int type',
|
86
|
+
'unsigned long serial',
|
87
|
+
'Bool send_event',
|
88
|
+
'Display *display',
|
89
|
+
'Window parent',
|
90
|
+
'Window window',
|
91
|
+
'int x',
|
92
|
+
'int y',
|
93
|
+
'int width',
|
94
|
+
'int height',
|
95
|
+
'int border_width',
|
96
|
+
'Bool override_redirect',
|
97
|
+
]
|
98
|
+
XConfigureEvent = struct [
|
99
|
+
'int type',
|
100
|
+
'unsigned long serial',
|
101
|
+
'Bool send_event',
|
102
|
+
'Display *display',
|
103
|
+
'Window event',
|
104
|
+
'Window window',
|
105
|
+
'int x',
|
106
|
+
'int y',
|
107
|
+
'int width',
|
108
|
+
'int height',
|
109
|
+
'int border_width',
|
110
|
+
'Window above',
|
111
|
+
'Bool override_redirect',
|
112
|
+
]
|
113
|
+
XExposeEvent = struct [
|
114
|
+
'int type',
|
115
|
+
'unsigned long serial',
|
116
|
+
'Bool send_event',
|
117
|
+
'Display *display',
|
118
|
+
'Window window',
|
119
|
+
'int x',
|
120
|
+
'int y',
|
121
|
+
'int width',
|
122
|
+
'int height',
|
123
|
+
'int count',
|
124
|
+
]
|
125
|
+
XPropertyEvent = struct [
|
126
|
+
'int type',
|
127
|
+
'unsigned long serial',
|
128
|
+
'Bool send_event',
|
129
|
+
'Display *display',
|
130
|
+
'Window window',
|
131
|
+
'Atom atom',
|
132
|
+
'Time time',
|
133
|
+
'int state',
|
134
|
+
]
|
135
|
+
XWMHints = struct [
|
136
|
+
'long flags',
|
137
|
+
'Bool input',
|
138
|
+
'int initial_state',
|
139
|
+
'Pixmap icon_pixmap',
|
140
|
+
'Window icon_window',
|
141
|
+
'int icon_x',
|
142
|
+
'int icon_y',
|
143
|
+
'Pixmap icon_mask',
|
144
|
+
'XID window_group',
|
145
|
+
]
|
146
|
+
XWindowAttributes = struct [
|
147
|
+
'int x',
|
148
|
+
'int y',
|
149
|
+
'int width',
|
150
|
+
'int height',
|
151
|
+
'int border_width',
|
152
|
+
'int depth',
|
153
|
+
'Visual *visual',
|
154
|
+
'Window root',
|
155
|
+
'int c_class',
|
156
|
+
'int bit_gravity',
|
157
|
+
'int win_gravity',
|
158
|
+
'int backing_store',
|
159
|
+
'unsigned long backing_planes',
|
160
|
+
'unsigned long backing_pixel',
|
161
|
+
'Bool save_under',
|
162
|
+
'Colormap colormap',
|
163
|
+
'Bool map_installed',
|
164
|
+
'int map_state',
|
165
|
+
'long all_event_masks',
|
166
|
+
'long your_event_mask',
|
167
|
+
'long do_not_propagate_mask',
|
168
|
+
'Bool override_redirect',
|
169
|
+
'Screen *screen',
|
170
|
+
]
|
171
|
+
|
172
|
+
Int = struct ['int n']
|
173
|
+
UnsignedLong = struct ['unsigned long n']
|
174
|
+
|
175
|
+
extern 'Display* XOpenDisplay(char*)'
|
176
|
+
extern 'Window XDefaultRootWindow(Display*)'
|
177
|
+
extern 'int XGetInputFocus(Display*, Window*, int*)'
|
178
|
+
extern 'int XGetClassHint(Display*, Window, XClassHint*)'
|
179
|
+
extern 'Status XQueryTree(Display*, Window, Window*, Window*, Window**, unsigned int*)'
|
180
|
+
extern 'Status XGetWMName(Display*, Window, XTextProperty*)'
|
181
|
+
extern 'Status XGetWMNormalHints(Display*, Window, XSizeHints*, long*)'
|
182
|
+
extern 'XWMHints* XGetWMHints(Display*, Window)'
|
183
|
+
extern 'int Xutf8TextPropertyToTextList(Display*, XTextProperty*, char***, int*)'
|
184
|
+
extern 'int XFree(void*)'
|
185
|
+
extern 'void XFreeStringList(char**)'
|
186
|
+
extern 'int XSelectInput(Display*, Window, unsigned long)'
|
187
|
+
extern 'int XNextEvent(Display*, XEvent*)'
|
188
|
+
extern 'int XGetGeometry(Display*, Window, Window*, int*, int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*)'
|
189
|
+
extern 'void* XSetErrorHandler(int (*)(Display*, XErrorEvent*))'
|
190
|
+
extern 'Window XCreateSimpleWindow(Display*, Window, int, int, unsigned int, unsigned int, unsigned int, unsigned long, unsigned long)'
|
191
|
+
extern 'int XMoveWindow(Display*, Window, int, int)'
|
192
|
+
extern 'int XMapWindow(Display*, Window)'
|
193
|
+
extern 'int XUnmapWindow(Display*, Window)'
|
194
|
+
extern 'int XUnmapSubwindows(Display*, Window)'
|
195
|
+
extern 'int XChangeProperty(Display*, Window, Atom, Atom, int, int, unsigned char*, int)'
|
196
|
+
extern 'Atom XInternAtom(Display*, char*, char)'
|
197
|
+
extern 'void XFlush(Display*)'
|
198
|
+
extern 'Status XGetWindowAttributes(Display*, Window, XWindowAttributes*)'
|
199
|
+
extern 'GC XCreateGC(Display*, Drawable, unsigned long, XGCValues*)'
|
200
|
+
extern 'int XSetForeground(Display*, GC, unsigned long)'
|
201
|
+
extern 'int XSetBackground(Display*, GC, unsigned long)'
|
202
|
+
extern 'int XSetFont(Display*, GC, Font)'
|
203
|
+
extern 'Font XLoadFont(Display*, char*)'
|
204
|
+
extern 'int XDrawString(Display*, Drawable, GC, int, int, char*, int)'
|
205
|
+
extern 'int XFillRectangle(Display*, Drawable, GC, int, int, unsigned int, unsigned int)'
|
206
|
+
extern 'int XClearWindow(Display*, Window)'
|
207
|
+
extern 'int XGetWindowProperty(Display*, Window, Atom, long, long, Bool, Atom, Atom*, int*, unsigned long*, unsigned long*, unsigned char**)'
|
208
|
+
|
209
|
+
ErrorHandler = bind("int error_handler(Display*, XErrorEvent*)") { |*| return 0 }
|
210
|
+
X11::XSetErrorHandler(X11::ErrorHandler)
|
211
|
+
end
|
212
|
+
|
213
|
+
module X
|
214
|
+
# event mask
|
215
|
+
NO_EVENT_MASK = 0
|
216
|
+
KEY_PRESS_MASK = 1 << 0
|
217
|
+
KEY_RELEASE_MASK = 1 << 1
|
218
|
+
BUTTON_PRESS_MASK = 1 << 2
|
219
|
+
BUTTON_RELEASE_MASK = 1 << 3
|
220
|
+
ENTER_WINDOW_MASK = 1 << 4
|
221
|
+
LEAVE_WINDOW_MASK = 1 << 5
|
222
|
+
POINTER_MOTION_MASK = 1 << 6
|
223
|
+
POINTER_MOTION_HINT_MASK = 1 << 7
|
224
|
+
BUTTON1_MOTION_MASK = 1 << 8
|
225
|
+
BUTTON2_MOTION_MASK = 1 << 9
|
226
|
+
BUTTON3_MOTION_MASK = 1 << 10
|
227
|
+
BUTTON4_MOTION_MASK = 1 << 11
|
228
|
+
BUTTON5_MOTION_MASK = 1 << 12
|
229
|
+
BUTTON_MOTION_MASK = 1 << 13
|
230
|
+
KEYMAP_STATE_MASK = 1 << 14
|
231
|
+
EXPOSURE_MASK = 1 << 15
|
232
|
+
VISIBILITY_CHANGE_MASK = 1 << 16
|
233
|
+
STRUCTURE_NOTIFY_MASK = 1 << 17
|
234
|
+
RESIZE_REDIRECT_MASK = 1 << 18
|
235
|
+
SUBSTRUCTURE_NOTIFY_MASK = 1 << 19
|
236
|
+
SUBSTRUCTURE_REDIRECT_MASK = 1 << 20
|
237
|
+
FOCUS_CHANGE_MASK = 1 << 21
|
238
|
+
PROPERTY_CHANGE_MASK = 1 << 22
|
239
|
+
COLORMAP_CHANGE_MASK = 1 << 23
|
240
|
+
OWNER_GRAB_BUTTON_MASK = 1 << 24
|
241
|
+
|
242
|
+
# event type
|
243
|
+
KEY_PRESS = 2
|
244
|
+
KEY_RELEASE = 3
|
245
|
+
BUTTON_PRESS = 4
|
246
|
+
BUTTON_RELEASE = 5
|
247
|
+
MOTION_NOTIFY = 6
|
248
|
+
ENTER_NOTIFY = 7
|
249
|
+
LEAVE_NOTIFY = 8
|
250
|
+
FOCUS_IN = 9
|
251
|
+
FOCUS_OUT = 10
|
252
|
+
KEYMAP_NOTIFY = 11
|
253
|
+
EXPOSE = 12
|
254
|
+
GRAPHICS_EXPOSE = 13
|
255
|
+
NO_EXPOSE = 14
|
256
|
+
VISIBILITY_NOTIFY = 15
|
257
|
+
CREATE_NOTIFY = 16
|
258
|
+
DESTROY_NOTIFY = 17
|
259
|
+
UNMAP_NOTIFY = 18
|
260
|
+
MAP_NOTIFY = 19
|
261
|
+
MAP_REQUEST = 20
|
262
|
+
REPARENT_NOTIFY = 21
|
263
|
+
CONFIGURE_NOTIFY = 22
|
264
|
+
CONFIGURE_REQUEST = 23
|
265
|
+
GRAVITY_NOTIFY = 24
|
266
|
+
RESIZE_REQUEST = 25
|
267
|
+
CIRCULATE_NOTIFY = 26
|
268
|
+
CIRCULATE_REQUEST = 27
|
269
|
+
PROPERTY_NOTIFY = 28
|
270
|
+
SELECTION_CLEAR = 29
|
271
|
+
SELECTION_REQUEST = 30
|
272
|
+
SELECTION_NOTIFY = 31
|
273
|
+
COLORMAP_NOTIFY = 32
|
274
|
+
CLIENT_MESSAGE = 33
|
275
|
+
MAPPING_NOTIFY = 34
|
276
|
+
GENERIC_EVENT = 35
|
277
|
+
|
278
|
+
|
279
|
+
# property mode
|
280
|
+
PROP_MODE_REPLACE = 0
|
281
|
+
PROP_MODE_PREPEND = 1
|
282
|
+
PROP_MODE_APPEND = 2
|
283
|
+
|
284
|
+
# map state
|
285
|
+
IS_UNMAPPED = 0
|
286
|
+
IS_UNVIEWABLE = 1
|
287
|
+
IS_VIEWABLE = 2
|
288
|
+
|
289
|
+
# atom
|
290
|
+
ANY_PROPERTY_TYPE = 0
|
291
|
+
XA_PRIMARY = 1
|
292
|
+
XA_SECONDARY = 2
|
293
|
+
XA_ARC = 3
|
294
|
+
XA_ATOM = 4
|
295
|
+
XA_BITMAP = 5
|
296
|
+
XA_CARDINAL = 6
|
297
|
+
XA_COLORMAP = 7
|
298
|
+
XA_CURSOR = 8
|
299
|
+
XA_CUT_BUFFER0 = 9
|
300
|
+
XA_CUT_BUFFER1 = 10
|
301
|
+
XA_CUT_BUFFER2 = 11
|
302
|
+
XA_CUT_BUFFER3 = 12
|
303
|
+
XA_CUT_BUFFER4 = 13
|
304
|
+
XA_CUT_BUFFER5 = 14
|
305
|
+
XA_CUT_BUFFER6 = 15
|
306
|
+
XA_CUT_BUFFER7 = 16
|
307
|
+
XA_DRAWABLE = 17
|
308
|
+
XA_FONT = 18
|
309
|
+
XA_INTEGER = 19
|
310
|
+
XA_PIXMAP = 20
|
311
|
+
XA_POINT = 21
|
312
|
+
XA_RECTANGLE = 22
|
313
|
+
XA_RESOURCE_MANAGER = 23
|
314
|
+
XA_RGB_COLOR_MAP = 24
|
315
|
+
XA_RGB_BEST_MAP = 25
|
316
|
+
XA_RGB_BLUE_MAP = 26
|
317
|
+
XA_RGB_DEFAULT_MAP = 27
|
318
|
+
XA_RGB_GRAY_MAP = 28
|
319
|
+
XA_RGB_GREEN_MAP = 29
|
320
|
+
XA_RGB_RED_MAP = 30
|
321
|
+
XA_STRING = 31
|
322
|
+
XA_VISUALID = 32
|
323
|
+
XA_WINDOW = 33
|
324
|
+
XA_WM_COMMAND = 34
|
325
|
+
XA_WM_HINTS = 35
|
326
|
+
XA_WM_CLIENT_MACHINE = 36
|
327
|
+
XA_WM_ICON_NAME = 37
|
328
|
+
XA_WM_ICON_SIZE = 38
|
329
|
+
XA_WM_NAME = 39
|
330
|
+
XA_WM_NORMAL_HINTS = 40
|
331
|
+
XA_WM_SIZE_HINTS = 41
|
332
|
+
XA_WM_ZOOM_HINTS = 42
|
333
|
+
XA_MIN_SPACE = 43
|
334
|
+
XA_NORM_SPACE = 44
|
335
|
+
XA_MAX_SPACE = 45
|
336
|
+
XA_END_SPACE = 46
|
337
|
+
XA_SUPERSCRIPT_X = 47
|
338
|
+
XA_SUPERSCRIPT_Y = 48
|
339
|
+
XA_SUBSCRIPT_X = 49
|
340
|
+
XA_SUBSCRIPT_Y = 50
|
341
|
+
XA_UNDERLINE_POSITION = 51
|
342
|
+
XA_UNDERLINE_THICKNESS = 52
|
343
|
+
XA_STRIKEOUT_ASCENT = 53
|
344
|
+
XA_STRIKEOUT_DESCENT = 54
|
345
|
+
XA_ITALIC_ANGLE = 55
|
346
|
+
XA_X_HEIGHT = 56
|
347
|
+
XA_QUAD_WIDTH = 57
|
348
|
+
XA_WEIGHT = 58
|
349
|
+
XA_POINT_SIZE = 59
|
350
|
+
XA_RESOLUTION = 60
|
351
|
+
XA_COPYRIGHT = 61
|
352
|
+
XA_NOTICE = 62
|
353
|
+
XA_FONT_NAME = 63
|
354
|
+
XA_FAMILY_NAME = 64
|
355
|
+
XA_FULL_NAME = 65
|
356
|
+
XA_CAP_HEIGHT = 66
|
357
|
+
XA_WM_CLASS = 67
|
358
|
+
XA_WM_TRANSIENT_FOR = 68
|
359
|
+
|
360
|
+
class Display
|
361
|
+
attr_reader :display
|
362
|
+
|
363
|
+
# @param display [String]
|
364
|
+
def initialize(display=nil)
|
365
|
+
display ||= ENV['DISPLAY']
|
366
|
+
@display = X11::XOpenDisplay(display) or raise "Cannot open display: #{display}"
|
367
|
+
end
|
368
|
+
|
369
|
+
def default_screen
|
370
|
+
X11::DefaultScreen(@display)
|
371
|
+
end
|
372
|
+
|
373
|
+
def width(screen)
|
374
|
+
X11::DisplayWidth(@display, screen)
|
375
|
+
end
|
376
|
+
|
377
|
+
def height(screen)
|
378
|
+
X11::DisplayHeight(@display, screen)
|
379
|
+
end
|
380
|
+
|
381
|
+
def default_root_window
|
382
|
+
Window.new(self, X11::XDefaultRootWindow(@display))
|
383
|
+
end
|
384
|
+
|
385
|
+
def flush
|
386
|
+
X11::XFlush(@display)
|
387
|
+
end
|
388
|
+
|
389
|
+
def load_font(font)
|
390
|
+
X11::XLoadFont(@display, font)
|
391
|
+
end
|
392
|
+
|
393
|
+
def next_event
|
394
|
+
ev_buf = ' ' * 8 * 24
|
395
|
+
ev_ptr = Fiddle::Pointer[ev_buf]
|
396
|
+
while true
|
397
|
+
X11::XNextEvent(@display, ev_ptr)
|
398
|
+
ev_type = ev_buf.unpack1('i')
|
399
|
+
case ev_type
|
400
|
+
when CREATE_NOTIFY
|
401
|
+
return CreateWindowEvent.new(**X11::XCreateWindowEvent.new(ev_ptr).to_h)
|
402
|
+
when CONFIGURE_NOTIFY
|
403
|
+
return ConfigureEvent.new(**X11::XConfigureEvent.new(ev_ptr).to_h)
|
404
|
+
when EXPOSE
|
405
|
+
return ExposeEvent.new(**X11::XExposeEvent.new(ev_ptr).to_h)
|
406
|
+
when PROPERTY_NOTIFY
|
407
|
+
return PropertyEvent.new(**X11::XPropertyEvent.new(ev_ptr).to_h)
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
def wm_window_types
|
413
|
+
@wm_window_types ||= {
|
414
|
+
X11::XInternAtom(@display, '_NET_WM_WINDOW_TYPE_DESKTOP', 0) => :desktop,
|
415
|
+
X11::XInternAtom(@display, '_NET_WM_WINDOW_TYPE_DOCK', 0) => :dock,
|
416
|
+
X11::XInternAtom(@display, '_NET_WM_WINDOW_TYPE_TOOLBAR', 0) => :toolbar,
|
417
|
+
X11::XInternAtom(@display, '_NET_WM_WINDOW_TYPE_MENU', 0) => :menu,
|
418
|
+
X11::XInternAtom(@display, '_NET_WM_WINDOW_TYPE_UTILITY', 0) => :utility,
|
419
|
+
X11::XInternAtom(@display, '_NET_WM_WINDOW_TYPE_SPLASH', 0) => :splash,
|
420
|
+
X11::XInternAtom(@display, '_NET_WM_WINDOW_TYPE_DIALOG', 0) => :dialog,
|
421
|
+
X11::XInternAtom(@display, '_NET_WM_WINDOW_TYPE_NORMAL', 0) => :normal,
|
422
|
+
}
|
423
|
+
end
|
424
|
+
|
425
|
+
def intern_atom(sym, f=0)
|
426
|
+
X11::XInternAtom(@display, sym.to_s, f)
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
ClassHint = Data.define(*X11::XClassHint.attributes)
|
431
|
+
WMHints = Data.define(*X11::XWMHints.attributes)
|
432
|
+
SizeHints = Data.define(*X11::XSizeHints.attributes)
|
433
|
+
WindowAttributes = Data.define(*X11::XWindowAttributes.attributes)
|
434
|
+
CreateWindowEvent = Data.define(*X11::XCreateWindowEvent.attributes)
|
435
|
+
ConfigureEvent = Data.define(*X11::XConfigureEvent.attributes)
|
436
|
+
ExposeEvent = Data.define(*X11::XExposeEvent.attributes)
|
437
|
+
PropertyEvent = Data.define(*X11::XPropertyEvent.attributes)
|
438
|
+
Geometry = Data.define(:x, :y, :width, :height, :border_width, :depth)
|
439
|
+
|
440
|
+
class Window
|
441
|
+
def initialize(display_obj, id)
|
442
|
+
@display_obj = display_obj
|
443
|
+
@display = display_obj.display
|
444
|
+
@window = id
|
445
|
+
end
|
446
|
+
|
447
|
+
def inspect
|
448
|
+
"#<#{self.class.name}: 0x#{id.to_s(16)}: #{class_hint&.class_name}: #{wm_name}>"
|
449
|
+
end
|
450
|
+
|
451
|
+
def id
|
452
|
+
@window
|
453
|
+
end
|
454
|
+
|
455
|
+
def hash
|
456
|
+
id.hash
|
457
|
+
end
|
458
|
+
|
459
|
+
def eql?(other)
|
460
|
+
id == other.id
|
461
|
+
end
|
462
|
+
|
463
|
+
def class_hint
|
464
|
+
class_hint = X11::XClassHint.malloc(Fiddle::RUBY_FREE)
|
465
|
+
ret = X11::XGetClassHint(@display, @window, class_hint)
|
466
|
+
ret == 0 ? nil : ClassHint.new(name: class_hint.name.to_s, class_name: class_hint.class_name.to_s)
|
467
|
+
end
|
468
|
+
|
469
|
+
def geometry
|
470
|
+
root = X11::UnsignedLong.malloc(Fiddle::RUBY_FREE)
|
471
|
+
x = X11::Int.malloc(Fiddle::RUBY_FREE)
|
472
|
+
y = X11::Int.malloc(Fiddle::RUBY_FREE)
|
473
|
+
width = X11::UnsignedLong.malloc(Fiddle::RUBY_FREE)
|
474
|
+
height = X11::UnsignedLong.malloc(Fiddle::RUBY_FREE)
|
475
|
+
border_width = X11::UnsignedLong.malloc(Fiddle::RUBY_FREE)
|
476
|
+
depth = X11::UnsignedLong.malloc(Fiddle::RUBY_FREE)
|
477
|
+
|
478
|
+
X11::XGetGeometry(@display, @window, root, x, y, width, height, border_width, depth)
|
479
|
+
Geometry.new(x: x.n, y: y.n, width: width.n, height: height.n, border_width: border_width.n, depth: depth.n)
|
480
|
+
end
|
481
|
+
|
482
|
+
def wm_hints
|
483
|
+
hints = X11::XGetWMHints(@display, @window)
|
484
|
+
return nil if hints.null?
|
485
|
+
WMHints.new(**X11::XWMHints.new(hints).to_h)
|
486
|
+
ensure
|
487
|
+
X11::XFree(hints) unless hints.null?
|
488
|
+
end
|
489
|
+
|
490
|
+
def wm_normal_hints
|
491
|
+
hints = X11::XSizeHints.malloc(Fiddle::RUBY_FREE)
|
492
|
+
ret = X11::XGetWMNormalHints(@display, @window, hints, ' '*8)
|
493
|
+
ret == 0 ? nil : SizeHints.new(**hints.to_h)
|
494
|
+
end
|
495
|
+
|
496
|
+
def wm_name
|
497
|
+
prop = X11::XTextProperty.malloc(Fiddle::RUBY_FREE)
|
498
|
+
text_list = X11::Pointer.malloc(Fiddle::RUBY_FREE)
|
499
|
+
X11::XGetWMName(@display, @window, prop)
|
500
|
+
X11::Xutf8TextPropertyToTextList(@display, prop, text_list, ' '*8)
|
501
|
+
ptr = text_list.ptr
|
502
|
+
if ptr.null?
|
503
|
+
nil
|
504
|
+
else
|
505
|
+
ptr.ptr.to_s.force_encoding('utf-8')
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
def select_input(mask)
|
510
|
+
X11::XSelectInput(@display, @window, mask)
|
511
|
+
end
|
512
|
+
|
513
|
+
def parent
|
514
|
+
root = ' '*8
|
515
|
+
parent = X11::UnsignedLong.malloc(Fiddle::RUBY_FREE)
|
516
|
+
nchildren = X11::Int.malloc(Fiddle::RUBY_FREE)
|
517
|
+
children_p = X11::Pointer.malloc(Fiddle::RUBY_FREE)
|
518
|
+
ret = X11::XQueryTree(@display, @window, root, parent, children_p, nchildren)
|
519
|
+
return if ret == 0
|
520
|
+
|
521
|
+
Window.new(@display_obj, parent.n)
|
522
|
+
end
|
523
|
+
|
524
|
+
def query_tree
|
525
|
+
root = ' '*8
|
526
|
+
parent = ' '*8
|
527
|
+
nchildren = X11::Int.malloc(Fiddle::RUBY_FREE)
|
528
|
+
children_p = X11::Pointer.malloc(Fiddle::RUBY_FREE)
|
529
|
+
ret = X11::XQueryTree(@display, @window, root, parent, children_p, nchildren)
|
530
|
+
return if ret == 0
|
531
|
+
|
532
|
+
nchildren.n.times.map do |i|
|
533
|
+
win = children_p.ptr[X11::Window.size * i, X11::Window.size].unpack1('L!')
|
534
|
+
Window.new(@display_obj, win)
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
def create_simple_window(x, y, width, height, border_width, border, background)
|
539
|
+
win = X11::XCreateSimpleWindow(@display, @window, x, y, width, height, border_width, border, background)
|
540
|
+
Window.new(@display_obj, win)
|
541
|
+
end
|
542
|
+
|
543
|
+
def move_window(x, y)
|
544
|
+
X11::XMoveWindow(@display, @window, x, y)
|
545
|
+
end
|
546
|
+
|
547
|
+
def map_window
|
548
|
+
X11::XMapWindow(@display, @window)
|
549
|
+
end
|
550
|
+
|
551
|
+
def unmap_window
|
552
|
+
X11::XUnmapWindow(@display, @window)
|
553
|
+
end
|
554
|
+
|
555
|
+
def unmap_subwindows
|
556
|
+
X11::XUnmapSubwindows(@display, @window)
|
557
|
+
end
|
558
|
+
|
559
|
+
def change_property_atom(property, mode, data)
|
560
|
+
prop_ = X11::XInternAtom(@display, property.to_s, 0)
|
561
|
+
data_ = [X11::XInternAtom(@display, data.to_s, 0)].pack('L!')
|
562
|
+
X11::XChangeProperty(@display, @window, prop_, X::XA_ATOM, 32, mode, data_, 1)
|
563
|
+
end
|
564
|
+
|
565
|
+
def change_property_cardinal(property, mode, data)
|
566
|
+
prop_ = X11::XInternAtom(@display, property.to_s, 0)
|
567
|
+
data_ = X11::UnsignedLong.malloc
|
568
|
+
data_.n = data
|
569
|
+
X11::XChangeProperty(@display, @window, prop_, X::XA_CARDINAL, 32, mode, data_, 1)
|
570
|
+
end
|
571
|
+
|
572
|
+
def window_attributes
|
573
|
+
attr = X11::XWindowAttributes.malloc(Fiddle::RUBY_FREE)
|
574
|
+
X11::XGetWindowAttributes(@display, @window, attr)
|
575
|
+
WindowAttributes.new(**attr.to_h)
|
576
|
+
end
|
577
|
+
|
578
|
+
def screen
|
579
|
+
X11::Screen.new(window_attributes.screen)
|
580
|
+
end
|
581
|
+
|
582
|
+
def create_gc
|
583
|
+
gc = X11::XCreateGC(@display, @window, 0, nil)
|
584
|
+
GC.new(@display, @window, gc)
|
585
|
+
end
|
586
|
+
|
587
|
+
def clear
|
588
|
+
X11::XClearWindow(@display, @window)
|
589
|
+
end
|
590
|
+
|
591
|
+
def window_type
|
592
|
+
net_wm_window_type = X11::XInternAtom(@display, '_NET_WM_WINDOW_TYPE', 0)
|
593
|
+
|
594
|
+
property = net_wm_window_type
|
595
|
+
actual_type = X11::UnsignedLong.malloc(Fiddle::RUBY_FREE)
|
596
|
+
actual_format = X11::Int.malloc(Fiddle::RUBY_FREE)
|
597
|
+
nitems = X11::UnsignedLong.malloc(Fiddle::RUBY_FREE)
|
598
|
+
bytes = X11::UnsignedLong.malloc(Fiddle::RUBY_FREE)
|
599
|
+
prop = X11::Pointer.malloc(Fiddle::RUBY_FREE)
|
600
|
+
|
601
|
+
X11::XGetWindowProperty(@display, @window, property, 0, ~0, 0, ANY_PROPERTY_TYPE, actual_type, actual_format, nitems, bytes, prop)
|
602
|
+
return nil if actual_type.n != XA_ATOM
|
603
|
+
raise "invalid format: #{actual_format.n}" unless actual_format.n == 32
|
604
|
+
type = X11::UnsignedLong.new(prop.ptr)
|
605
|
+
@display_obj.wm_window_types[type.n]
|
606
|
+
ensure
|
607
|
+
X11::XFree(prop.ptr) unless prop.ptr.null?
|
608
|
+
end
|
609
|
+
|
610
|
+
def active_window
|
611
|
+
net_active_window = X11::XInternAtom(@display, '_NET_ACTIVE_WINDOW', 1)
|
612
|
+
|
613
|
+
actual_type = X11::UnsignedLong.malloc(Fiddle::RUBY_FREE)
|
614
|
+
actual_format = X11::Int.malloc(Fiddle::RUBY_FREE)
|
615
|
+
nitems = X11::UnsignedLong.malloc(Fiddle::RUBY_FREE)
|
616
|
+
bytes = X11::UnsignedLong.malloc(Fiddle::RUBY_FREE)
|
617
|
+
prop = X11::Pointer.malloc(Fiddle::RUBY_FREE)
|
618
|
+
X11::XGetWindowProperty(@display, @window, net_active_window, 0, ~0, 0, ANY_PROPERTY_TYPE, actual_type, actual_format, nitems, bytes, prop)
|
619
|
+
raise "invalid format: #{actual_format.n}" unless actual_format.n == 32
|
620
|
+
raise "invalid nitems: #{nitems.n}" unless nitems.n > 0
|
621
|
+
|
622
|
+
win = X11::UnsignedLong.new(prop.ptr).n
|
623
|
+
return nil if win == 0
|
624
|
+
Window.new(@display_obj, win)
|
625
|
+
ensure
|
626
|
+
X11::XFree(prop.ptr) unless prop.ptr.null?
|
627
|
+
end
|
628
|
+
end
|
629
|
+
|
630
|
+
class GC
|
631
|
+
def initialize(display, window, gc)
|
632
|
+
@display = display
|
633
|
+
@window = window
|
634
|
+
@gc = gc
|
635
|
+
end
|
636
|
+
|
637
|
+
def set_background(color)
|
638
|
+
X11::XSetBackground(@display, @gc, color)
|
639
|
+
end
|
640
|
+
|
641
|
+
def set_foreground(color)
|
642
|
+
X11::XSetForeground(@display, @gc, color)
|
643
|
+
end
|
644
|
+
|
645
|
+
def set_font(font)
|
646
|
+
X11::XSetFont(@display, @gc, font)
|
647
|
+
end
|
648
|
+
|
649
|
+
def draw_string(x, y, string)
|
650
|
+
X11::XDrawString(@display, @window, @gc, x, y, string, string.length)
|
651
|
+
end
|
652
|
+
|
653
|
+
def fill_rectangle(x, y, width, height)
|
654
|
+
X11::XFillRectangle(@display, @window, @gc, x, y, width, height)
|
655
|
+
end
|
656
|
+
end
|
657
|
+
end
|
658
|
+
end
|