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