2
#This file is part of Xdo.
3
#Copyright © 2009, 2010 Marvin Gülker
4
# Initia in potestate nostra sunt, de eventu fortuna iudicat.
6
# Modified by Gerry Boland <gerry dot boland at canonical dot com>
7
require File.join(File.dirname(__FILE__), '_xdo')
12
#This class represents a window on the screen. Each window is uniquely identified by
13
#an internal ID; before you can create a reference to a window (a XWindow object) you
14
#have to obtain the internal ID of that window and pass it into XWindow.new.
15
#Or you use the class methods of this class, notably XWindow.active_window.
17
#Via the XWindow object you get you can manipulate a window in serveral ways, e.g.
18
#you can move or resize it. Some methods are not available on every window
19
#manager: XWindow.active_window, XWindow.desktop_num, XWindow.desktop_num=, XWindow.desktop,
20
#XWindow.desktop=, XWindow.from_active, #raise, #activate, #desktop, #desktop=.
21
#Some of them may be available, some not. On my machine (an Ubuntu Lucid) for
22
#example I can use active_window, desktop_num and #activate, but not #raise or #desktop=.
23
#Those methods are tagged with the sentence "Part of the EWMH standard XY". Not all
24
#parts of the EWMH standard are provided by every window manager.
26
#As of version 0.0.4 the way to search for window is about to change. The old version
27
#where you passed a hash with symbols has been deprecated (and you get warnings
28
#about this if you use it) in favor of passing those symbols as a rest argument. See
29
#XWindow.search for more details.
31
#You should also be aware of the fact that XDo is about to support Regexp objects
32
#in XWindow.search. In future versions (i.e. after the next minor release) strings
33
#*always* mean an exact title/class/whatever match. For parts, you have to use
34
#Regular Expressions. There is a culprit, though. +xdotool+ doesn't use Ruby's
35
#Regular Expressions engine Oniguruma and expects C-style regexps. I don't know
36
#about the differences - but if you're absolutely sure your window title matches
37
#that wonderful three-line extended regexp and +xdotool+ doesn't find it, you
38
#may email me at sutniuq@@gmx@net explaining which construct defeats +xdotool+.
39
#I will then setup a list over time which states which constructs don't work.
41
#Be <i>very careful</i> with the methods that are part of the two desktop EWMH standards.
42
#After I set the number of desktops and changed the current desktop, I had to reboot my
43
#system to get the original configuration back. I don't know if I'm not using +xdotool+ correct,
44
#but neither my library nor +xdotool+ itself could rescue my desktop settings. Btw, that's the
45
#reason why it's not in XDo's unit tests (but it should work; at least in one way...).
47
#The internal ID of the window.
52
#Checks if a window exists.
54
#[+name+] The name of the window to look for. Either a string or a Regular Expression; however, there's no guaranty that +xdotool+ gets the regexp right. Simple ones should work, though.
55
#[<tt>*opts</tt> (<tt>[:name, :class, :classname]</tt>) Search parameters. See XWindow.search.
59
# p XWindow.exists?("gedit") #=> true
60
# p XWindow.exists?(/^gedit/) #=> false
62
#It may be a good idea to pass :onlyvisible as a search parameter.
63
def exists?(name, *opts)
64
if opts.first.kind_of?(Hash)
65
warn("#{caller.first}: Deprecation Warning: Using a hash as further arguments is deprecated. Pass the symbols directly.")
66
opts = opts.first.keys
69
!search(name, *opts).empty?
72
#Checks wheather the given ID exists or not.
74
#[+id+] The ID to check for.
78
# p XWindow.id_exits?(29360674) #=> true
79
# p XWindow.id_exists?(123456) #=> false
82
Open3.popen3("#{XDo::XWININFO} -id #{id}"){|stdin, stdout, stderr| err << stderr.read}
83
return false unless err.empty?
87
#Waits for a window name to exist.
89
#[+name+] The name of the window to look for. Either a string or a Regular Expression; however, there's no guaranty that +xdotool+ gets the regexp right. Simple ones should work, though.
90
#[<tt>*opts</tt> (<tt>[:name, :class, :classname]</tt>) Search parameters. See XWindow.search.
92
#The ID of the newly appeared window.
94
# #Wait for a window with "gedit" somewhere in it's title:
95
# XDo::XWindow.wait_for_window("gedit")
96
# #Wait for a window that ends with "ends_with_this":
97
# XDo::XWindow.wait_for_window(/ends_with_this$/)
98
# #It's useful to combine this method with the Timeout module:
100
# Timeout.timeout(3){XDo::XWindow.wait_for_window("gedit")}
102
#Returns immediately if the window does already exist.
103
def wait_for_window(name, *opts)
104
if opts.first.kind_of?(Hash)
105
warn("#{caller.first}: Deprecation Warning: Using a hash as further arguments is deprecated. Pass the symbols directly.")
106
opts = opts.first.keys
109
loop{break if exists?(name, *opts);sleep(0.5)}
110
search(name, *opts).first
113
#Waits for a window to close.
115
#[+name+] The name of the window to look for. Either a string or a Regular Expression; however, there's no guaranty that +xdotool+ gets the regexp right. Simple ones should work, though.
116
#[<tt>*opts</tt> (<tt>[:name, :class, :classname]</tt>) Search parameters. See XWindow.search.
120
# #Wait for a window with "gedit" somewhere in it's title
121
# XDo::XWindow.wait_for_close("gedit")
122
# #Waits for a window whose title ends with "ends_with_this":
123
# XDo::XWindow.wait_for_close(/ends_with_this$/)
124
# #It's quite useful to combine this method with the Timeout module:
126
# Timeout.timeout(3){XDo::XWindow.wait_for_close("gedit")}
127
def wait_for_close(name, *opts)
128
if opts.first.kind_of?(Hash)
129
warn("#{caller.first}: Deprecation Warning: Using a hash as further arguments is deprecated. Pass the symbols directly.")
130
opts = opts.first.keys
133
loop{break if !exists?(name, *opts);sleep(0.5)}
137
#Search for a window name to get the internal ID of a window.
139
#[+str+] The name of the window to look for. Either a string or a Regular Expression; however, there's no guaranty that +xdotool+ gets the regexp right. Simple ones should work, though.
140
#[<tt>*opts</tt> (<tt>[:name, :class, :classname]</tt>) Search parameters.
141
#====Possible search parameters
142
#Copied from the +xdotool+ manpage:
143
#[class] Match against the window class.
144
#[classname] Match against the window classname.
145
#[name] Match against the window name. This is the same string that is displayed in the window titlebar.
146
#[onlyvisible] Show only visible windows in the results. This means ones with map state IsViewable.
148
#An array containing the IDs of all found windows or an empty array
151
# #Look for every window with "gedit" in it's title, class or classname
152
# XDo::XWindow.search("gedit")
153
# #Look for every window whose title, class or classname ends with "SciTE"
154
# XDo::XWindow.search(/SciTE$/)
155
# #Explicitly only search the titles of visible windows
156
# XDo::XWindow.search("gedit", :name, :onlyvisible)
157
def search(str, *opts)
158
if opts.first.kind_of?(Hash)
159
warn("#{caller.first}: Deprecation Warning: Using a hash as further arguments is deprecated. Pass the symbols directly.")
160
opts = opts.first.keys
162
opts = [:name, :class, :classname] if opts.empty?
164
#Allow Regular Expressions. Since I can't pass them directly to the command line,
165
#I need to get their source. Otherwise we want an exact match, therefore the line
166
#begin and line end anchors need to be set around the given string.
167
str = str.source if str.kind_of?(Regexp)
169
#The following is the new behaviour that will be activated with the next minor version.
171
#str = if str.kind_of?(Regexp)
177
cmd = "#{XDo::XDOTOOL} search "
178
opts.each{|sym| cmd << "--#{sym} "}
179
cmd << "'" << str << "'"
180
#Don't handle errors since we want an empty array in case of an error
181
Open3.popen3(cmd){|stdin, stdout, stderr| stdin.close_write; stdout.read}.lines.to_a.collect{|l| l.strip.to_i}
184
#Returns the internal ID of the currently focused window.
186
#[+notice_children+] (false) If true, childwindows are noticed and you may get a child window instead of a toplevel window.
188
#The internal ID of the found window.
190
#[XError] Error invoking +xdotool+.
192
# p XDo::XWindow.focused_window #=> 41943073
193
# p XDo::XWindow.focused_window(true) #=> 41943074
195
#This method may find an invisible window, see active_window for a more reliable method.
196
def focused_window(notice_children = false)
199
Open3.popen3("#{XDo::XDOTOOL} getwindowfocus #{notice_children ? "-f" : ""}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
200
raise(XDo::XError, err) unless err.empty?
204
#Returns the internal ID of the currently focused window.
206
#The ID of the found window.
208
#[XError] Error invoking +xdotool+.
210
# p XDo::XWindow.active_window #=> 41943073
212
#This method is more reliable than #focused_window, but never finds an invisible window.
214
#Part of the EWMH standard ACTIVE_WINDOW.
218
Open3.popen3("#{XDo::XDOTOOL} getactivewindow"){|stdin, stdout, stderr| out = stdout.read; err = stderr.read}
219
raise(XDo::XError, err) unless err.empty?
223
#Set the number of working desktops.
225
#[+num+] The number of desktops you want to exist.
229
#[XError] Error invoking +xdotool+.
231
# XDo::XWindow.desktop_num = 2
233
#Although Ubuntu systems seem to have several desktops, that isn't completely true. An usual Ubuntu system only
234
#has a single working desktop, on which Ubuntu sets up an arbitrary number of other "desktop views" (usually 4).
235
#That's kind of cheating, but I have not yet find out why it is like that. Maybe it's due to the nice cube rotating effect?
236
#That's the reason, why the desktop-related methods don't work with Ubuntu.
238
#Part of the EWMH standard WM_DESKTOP.
239
def desktop_num=(num)
241
Open3.popen3("#{XDo::XDOTOOL} set_num_desktops #{num}"){|stdin, stdout, stderr| err << stderr.read}
242
raise(XDo::Error, err) unless err.empty?
246
#Get the number of working desktops.
248
#The number of desktops.
250
#[XError] Error invoking +xdotool+.
252
# p XDo::XWindow.desktop_num = 1
254
#Although Ubuntu systems seem to have several desktops, that isn't completely true. An usual Ubuntu system only
255
#has a single working desktop, on which Ubuntu sets up an arbitrary number of other "desktop views" (usually 4).
256
#That's kind of cheating, but I have not yet find out why it is like that. Maybe it's due to the nice cube rotating effect?
257
#That's the reason, why the desktop-related methods don't work with Ubuntu.
259
#Part of the EWMH standard WM_DESKTOP.
263
Open3.popen3("#{XDo::XDOTOOL} get_num_desktops"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
264
raise(XDo::XError, err) unless err.empty?
268
#Change the view to desktop +num+.
270
#[+num+] The 0-based index of the desktop you want to switch to.
274
#[XError] Error invoking +xdotool+.
276
# XDo::XWindow.desktop = 1
278
#Although Ubuntu systems seem to have several desktops, that isn't completely true. An usual Ubuntu system only
279
#has a single working desktop, on which Ubuntu sets up an arbitrary number of other "desktop views" (usually 4).
280
#That's kind of cheating, but I have not yet find out why it is like that. Maybe it's due to the nice cube rotating effect?
281
#That's the reason, why the desktop-related methods don't work with Ubuntu.
283
#Part of the EWMH standard CURRENT_DESKTOP.
286
Open3.popen3("#{XDo::XDOTOOL} set_desktop #{num}"){|stdin, stdout, stderr| err << stderr.read}
287
raise(XDo::XError, err) unless err.empty?
291
#Returns the number of the active desktop.
293
#The number of the currently shown desktop.
295
#[XError] Error invoking +xdotool+.
297
# p XDo::XWindow.desktop #=> 0
299
#Although Ubuntu systems seem to have several desktops, that isn't completely true. An usual Ubuntu system only
300
#has a single working desktop, on which Ubuntu sets up an arbitrary number of other "desktop views" (usually 4).
301
#That's kind of cheating, but I have not yet find out why it is like that. Maybe it's due to the nice cube rotating effect?
302
#That's the reason, why the desktop-related methods don't work with Ubuntu.
304
#Part of the EWMH standard CURRENT_DESKTOP.
308
Open3.popen3("#{XDo::XDOTOOL} get_desktop"){|stdin, stdout, stderr| out = stdout.read; err = stderr.read}
309
raise(XDo::XError, err) unless err.empty?
313
#Creates a XWindow by calling search with the given parameters.
314
#The window is created from the first ID found.
316
#[+name+] The name of the window to look for. Either a string or a Regular Expression; however, there's no guaranty that +xdotool+ gets the regexp right. Simple ones should work, though.
317
#[<tt>*opts</tt> (<tt>[:name, :class, :classname]</tt>) Search parameters. See XWindow.search.
319
#The created XWindow object.
321
#[XError] Error invoking +xdotool+.
323
# #Exact title/class/classname match
324
# xwin = XDo::XWindow.from_search("xwindow.rb - SciTE")
325
# #Part match via regexp
326
# xwin = XDo::XWindow.from_search(/SciTE/)
327
# #Part match via string - DEPRECATED.
328
# xwin = XDo::XWindow.from_search("SciTE")
329
# #Only search the window classes
330
# xwin = XDo::XWindow.from_search(/SciTE/, :class)
331
def from_search(name, *opts)
332
if opts.first.kind_of?(Hash)
333
warn("#{caller.first}: Deprecation Warning: Using a hash as further arguments is deprecated. Pass the symbols directly.")
334
opts = opts.first.keys
337
ids = search(name, *opts)
338
raise(XDo::XError, "The window '#{name}' wasn't found!") if ids.empty?
342
#_Deprecated_. Use XWindow.from_search or XWindow.from_title instead.
343
def from_name(name, *opts)
344
warn("#{caller.first}: Deprecation Warning: ::from_name is deprecated. Use ::from_search if you want the old behaviour with the ability to specify all search parameters, or ::from_title if you just want to look through the window titles.")
345
from_search(name, *opts)
348
#Same as XWindow.from_search, but only looks for the window's titles to match.
350
#[+title+] The title of the window to look for. Either a string or a Regular Expression; however, there's no guaranty that +xdotool+ gets the regexp right. Simple ones should work, though.
352
#A XWindow object made up from the first window ID found.
354
#[XError] Error invoking +xdotool+.
356
# #Exact string match
357
# xwin = XDo::XWindow.from_title("xwindow.rb - SciTE")
358
# #Part match via regexp
359
# xwin = XDo::XWindow.from_title(/SciTE/)
360
# #Part match via string - DEPRECATED.
361
# xwin = XDo::XWindow.from_title("SciTE")
362
def from_title(title)
363
from_search(title, :name)
366
#Creates a XWindow by calling XWindow.focused_window with the given parameter.
368
#[+notice_children+] (false) If true, you may get a child window as the active window.
370
#The newly created XWindow objects.
372
# xwin = XDo::XWindow.from_focused
374
#The XWindow.focused_window method is a bit dangerous, since it may
375
#find an invisible window. Use XWindow.from_active if you don't want that.
376
def from_focused(notice_childs = false)
377
new(focused_window(notice_childs))
380
#Creates a XWindow by calling active_window.
382
#The newly created XWindow object.
384
# xwin = XDo::XWindow.from_active
386
#This method does not find invisible nor child windows; if you want that,
387
#you should take a look at XWindow.from_focused.
392
#Returns the ID of the root window.
394
#The ID of the root window.
396
# p XDo::XWindow.root_id #=> 346
400
Open3.popen3("#{XDo::XWININFO} -root"){|stdin, stdout, stderr| out << stdout.read.strip; err << stderr.read.strip}
401
Kernel.raise(XDo::XError, err) unless err.empty?
402
Integer(out.lines.to_a[0].match(/Window id:(.*?)\(/)[1].strip)
405
#Creates a XWindow refering to the root window.
407
#The newly created XWindow object.
409
# rwin = XDo::XWindow.from_root
414
#Creates a invalid XWindow.
416
#The newly created XWindow object.
418
# nwin = XDo::XWindow.from_null
420
#The handle the returned XWindow object uses is zero and
421
#therefore invalid. You can't call #move, #resize or other
422
#methods on it, but it may be useful for unsetting focus.
423
#See also the XWindow.unfocus method.
425
new(0) #Zero never is a valid window ID. Even the root window has another ID.
428
#Unsets the input focus by setting it to the invalid
431
#[+sync+] (true) If true, this method blocks until the input focus has been unset.
435
# win = XDo::XWindow.from_active
437
# XDo::XWindow.unfocus
438
def unfocus(sync = true)
439
from_null.focus(sync)
443
def desktop_name=(name)
444
warn("#{caller.first}: Deprecation warning: XWindow.desktop_name= doesn't do anything anymore.")
449
warn("#{caller.first}: Deprecation warning: XWindow.desktop_name doesn't do anything anymore.")
453
#Deprecated. Just calls XWindow.unfocus internally.
455
warn("#{caller.first}: Deprecation warning: XWindow.focus_desktop is deprecated. Use XWindow.unfocus instead.")
458
alias activate_desktop focus_desktop
460
#Minimize all windows (or restore, if already) by sending key combination
461
#either [CTRL]+[ALT]+[D] or [SUPER]+[D]. Check with window manager which one.
462
#Available after requireing "xdo/keyboard".
466
#[NotImplementedError] You didn't require 'xdo/keyboard'.
467
#[LoadError] Unable to get gconf value, check key set and gconftool-2 installed
469
# #Everything will be minimized:
470
# XDo::XWindow.toggle_minimize_all
471
# #And now we'll restore everything.
472
# XDo::XWindow.toggle_minimize_all
473
def toggle_minimize_all
474
raise(NotImplementedError, "You have to require 'xdo/keyboard' before you can use #{__method__}!") unless defined? XDo::Keyboard
475
#Emit window manager keystroke for minimize all/show desktop
476
XDo::Keyboard.key(get_window_manager_keystroke('show_desktop'))
479
#Minimizes the active window. There's no way to restore a specific minimized window.
480
#Available after requireing "xdo/keyboard".
484
#[NotImplementedError] You didn't require 'xdo/keyboard'.
485
#[LoadError] Unable to get gconf value, check key set and gconftool-2 installed
487
# XDo::XWindow.minimize
489
raise(NotImplementedError, "You have to require 'xdo/keyboard' before you can use #{__method__}!") unless defined? XDo::Keyboard
490
#Emit window manager keystroke to minimize window
491
XDo::Keyboard.key(get_window_manager_keystroke('minimize'))
494
#Maximize or normalize the active window if already maximized.
495
#Available after requireing "xdo/keyboard".
499
#[NotImplementedError] You didn't require 'xdo/keyboard'.
500
#[LoadError] Unable to get gconf value, check key set and gconftool-2 installed
502
# XDo::XWindow.minimize
503
# XDo::XWindow.toggle_maximize
505
raise(NotImplementedError, "You have to require 'xdo/keyboard' before you can use #{__method__}!") unless defined? XDo::Keyboard
506
#Get window manager keystroke to maximize window
507
XDo::Keyboard.key(get_window_manager_keystroke('maximize'))
510
#Returns keystroke string to control window manager (maximise, show desktop...)
511
#Currently only supports Metacity, and hence reads gconf settings.
512
def get_window_manager_keystroke(name)
513
#Get Metacity keystroke from gconf. Need to check 2 directories for keys
514
dirs = ['window_keybindings', 'global_keybindings']
515
root = '/apps/metacity'
519
error_message = "Unable to determine #{name} keyboard shortcut from Metacity - check that gconftool-2 is installed\n"
522
key = "#{root}/#{d}/#{name}"
523
Open3.popen3("#{GCONFTOOL} -g #{key}"){|stdin, stdout, stderr| out << stdout.read.strip; err << stderr.read.strip}
524
#If key doesn't exist, gconftool prints a message (including the requested key) saying so.
525
if err.empty? or !out.empty?
531
#Bail if no keystroke found
532
Kernel.raise(LoadError, error_message) if keystroke.empty?
534
#+xdotool+ doesn't recognise '<Mod4>', use '<Super>' instead
535
keystroke.gsub!('<Mod4>','<Super>')
536
#Edit keystroke string to suit +xdotool+'s Keyboard.key command
537
keystroke.gsub!('<','').gsub!('>','+')
548
#Changes a window's title.
550
#[+str+] The new title.
554
#[XError] Error invoking +xdotool+.
556
# xwin.title = "Ruby is awesome!"
559
# :method: icon_title=
564
#Changes the window's icon title, i.e. the string that is displayed in
565
#the task bar or panel where all open windows show up.
567
#[+str+] The string you want to set.
571
#[XError] Error invoking +xdotool+.
573
# xwin.icon_title = "This is minimized."
576
# :method: classname=
580
#Sets a window's classname.
582
#[+str+] The window's new classname.
586
#[XError] Error invoking +xdotool+.
588
# xwin.classname = "MyNewClass"
590
#Creates a new XWindow object from an internal ID.
592
#[+id+] The internal ID to create the window from.
594
#The newly created XWindow object.
596
# id = XWindow.search(/edit/)[1]
597
# xwin = XWindow.new(id)
599
#See also many class methods of the XWindow class which allow
600
#you to forget about the internal ID of a window.
605
#Human-readable output of form
606
# <XDo::XWindow: "title" (window_id)>
608
%Q|<#{self.class}: "#{title}" (#{id})>|
611
#Set the size of a window.
613
#[+width+] The new width, usually in pixels.
614
#[+height+] The new height, usually in pixels.
615
#[+use_hints+] (false) If true, window sizing hints are used if they're available. This is usually done when resizing terminal windows to a specific number of rows and columns.
616
#[+sync+] (true) If true, this method blocks until the window has finished resizing.
620
#[XError] Error executing +xdotool+.
622
# #Resize a window to 400x300px
623
# xwin.resize(400, 300)
624
# #Resize a terminal window to 100 rows and 100 columns
625
# xtermwin.resize(100, 100, true)
627
#This has no effect on maximized winwows.
628
def resize(width, height, use_hints = false, sync = true)
631
opts << "--usehints" if use_hints
632
opts << "--sync" if sync
633
Open3.popen3("#{XDo::XDOTOOL} windowsize #{opts.join(" ")} #{@id} #{width} #{height}"){|stdin, stdout, stderr| err << stderr.read}
634
Kernel.raise(XDo::XError, err) unless err.empty?
637
#Moves a window. +xdotool+ is not really exact with the coordinates,
638
#special windows like Ubuntu's panels make it placing wrong.
640
#[+x+] The goal X coordinate.
641
#[+y+] The goal Y coordinate.
642
#[+sync+] (true) If true, this method blocks until the window has finished moving.
646
#[XError] Error executing +xdotool+.
648
# xwin.move(100, 100)
649
# p xwin.abs_position #=> [101, 101]
650
def move(x, y, sync = true)
653
opts << "--sync" if sync
654
Open3.popen3("#{XDo::XDOTOOL} windowmove #{opts.join(" ")} #{@id} #{x} #{y}"){|stdin, stdout, stderr| err << stderr.read}
655
Kernel.raise(XDo::XError, err) unless err.empty?
658
#Set the input focus to the window (but don't bring it to the front).
660
#[+sync+] (true) If true, this method blocks until the window got the input focus.
664
#[XError] Error invoking +xdotool+.
668
#This method may not work on every window manager. You should use
669
##activate, which is supported by more window managers.
670
def focus(sync = true)
673
opts << "--sync" if sync
674
Open3.popen3("#{XDo::XDOTOOL} windowfocus #{opts.join(" ")} #{@id}"){|stdin, stdout, stderr| err << stderr.read}
675
Kernel.raise(XDo::XError, err) unless err.empty?
678
#The window loses the input focus by setting it to an invalid window.
680
#[+sync+] (true) If true, this method blocks until the focus has been set to nothing.
686
def unfocus(sync = true)
687
XDo::XWindow.unfocus(sync)
690
#Maps a window to the screen (makes it visible).
692
#[+sync+] (true) If true, this method blocks until the window has been mapped.
696
#[XError] Error invoking +xdotool+.
698
# xwin.unmap #Windows are usually mapped
703
opts << "--sync" if sync
704
Open3.popen3("#{XDo::XDOTOOL} windowmap #{opts.join(" ")} #{@id}"){|stdin, stdout, stderr| err << stderr.read}
705
Kernel.raise(XDo::XError, err) unless err.empty?
708
#Unmap a window from the screen (make it invisible).
710
#[+sync+] (true) If true, this method blocks until the window has been unmapped.
714
#[XError] Error executing +xdotool+.
717
def unmap(sync = true)
720
opts << "--sync" if sync
721
Open3.popen3("#{XDo::XDOTOOL} windowunmap #{opts.join(" ")} #{@id}"){|stdin, stdout, stderr| err << stderr.read}
722
Kernel.raise(XDo::XError, err) unless err.empty?
725
#Bring a window to the front (but don't give it the input focus).
726
#Not implemented in all window managers.
730
#[XError] Error executing +xdotool+.
735
Open3.popen3("#{XDo::XDOTOOL} windowraise #{@id}"){|stdin, stdout, stderr| err << stderr.read}
736
Kernel.raise(XDo::XError, err) unless err.empty?
739
#Activate a window. That is, bring it to top and give it the input focus.
741
#[+sync+] (true) If true, this method blocks until the window has been activated.
745
#[XError] Error executing +xdotool+.
749
#This is the recommanded method to give a window the input focus, since
750
#it works on more window managers than #focus and also works across
753
#Part of the EWMH standard ACTIVE_WINDOW.
754
def activate(sync = true)
759
opts << "--sync" if sync
760
Open3.popen3("#{XDo::XDOTOOL} windowactivate #{opts.join(" ")} #{@id}"){|stdin, stdout, stderr| err << stderr.read}
761
Kernel.raise(XDo::XError, err) unless err.empty?
763
#If no window is active, xdotool's windowactivate fails,
764
#because it tries to determine which is the currently active window.
775
#Move a window to a desktop.
777
#[+num+] The 0-based index of the desktop you want the window to move to.
781
#[XError] Error executing +xdotool+.
785
#Although Ubuntu systems seem to have several desktops, that isn't completely true. An usual Ubuntu system only
786
#has a single working desktop, on which Ubuntu sets up an arbitrary number of other "desktop views" (usually 4).
787
#That's kind of cheating, but I have not yet find out why it is like that. Maybe it's due to the nice cube rotating effect?
788
#That's the reason, why the desktop-related methods don't work with Ubuntu.
790
#Part of the EWMH standard CURRENT_DESKTOP.
793
Open3.popen3("#{XDo::XDOTOOL} set_desktop_for_window #{@id} #{num}"){|stdin, stdout, stderr| err << stderr.read}
794
Kernel.raise(XDo::XError, err) unless err.empty?
797
#Get the desktop the window is on.
799
#The 0-based index of the desktop this window resides on.
801
#[XError] Error executing +xdotool+.
803
# p xwin.desktop #=> 0
805
#Although Ubuntu systems seem to have several desktops, that isn't completely true. An usual Ubuntu system only
806
#has a single working desktop, on which Ubuntu sets up an arbitrary number of other "desktop views" (usually 4).
807
#That's kind of cheating, but I have not yet find out why it is like that. Maybe it's due to the nice cube rotating effect?
808
#That's the reason, why the desktop-related methods don't work with Ubuntu.
810
#Part of the EWMH standard CURRENT_DESKTOP.
814
Open3.popen3("#{XDo::XDOTOOL} get_desktop_for_window #{@id}"){|stdin, stdout, stderr| out = stdout.read; err << stderr.read}
815
Kernel.raise(XDo::XError, err) unless err.empty?
819
#The title of the window or nil if it doesn't have a title.
821
#The window's title, encoded as UTF-8, or nil if the window doesn't have a title.
823
#[XError] Error executing +xwininfo+.
825
# p xwin.title #=> "xwindow.rb SciTE"
829
if @id == XWindow.root_id #This is the root window
830
return "(the root window)"
832
return "(NULL window)"
834
Open3.popen3("#{XDo::XWININFO} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
836
Kernel.raise(XDo::XError, err) unless err.empty?
837
title = out.strip.lines.to_a[0].match(/"(.*)"/)[1] rescue Kernel.raise(XDo::XError, "No window with ID #{@id} found!")
838
return title #Kann auch nil sein, dann ist das Fenster namenlos.
841
#The absolute position of the window on the screen.
843
#A two-element array of form <tt>[x, y]</tt>.
845
#[XError] Error executing +xwininfo+.
847
# p xwin.abs_position #=> [0, 51]
851
Open3.popen3("#{XDo::XWININFO} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
852
Kernel.raise(XDo::XError, err) unless err.empty?
853
out = out.strip.lines.to_a
854
x = out[2].match(/:\s+(\d+)/)[1]
855
y = out[3].match(/:\s+(\d+)/)[1]
858
alias position abs_position
860
#The position of the window relative to it's parent window.
862
#A two-element array of form <tt>[x, y]</tt>.
864
#[XError] Error executing +xdotool+.
866
# p xwin.rel_position => [0, 51]
870
Open3.popen3("#{XDo::XWININFO} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
871
Kernel.raise(XDo::XError, err) unless err.empty?
872
out = out.strip.lines.to_a
873
x = out[4].match(/:\s+(\d+)/)[1]
874
y = out[5].match(/:\s+(\d+)/)[1]
878
#The size of the window.
880
#A two-element array of form <tt>[width, height]</tt>.
882
#[XError] Error executing +xwininfo+.
884
# p xwin.size #=> [1280, 948]
888
Open3.popen3("#{XDo::XWININFO} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
889
out = out.strip.lines.to_a
890
Kernel.raise(XDo::XError, err) unless err.empty?
891
width = out[6].match(/:\s+(\d+)/)[1]
892
height = out[7].match(/:\s+(\d+)/)[1]
893
[width.to_i, height.to_i]
896
#true if the window is mapped to the screen.
898
#nil if the window is not mapped, an integer value otherwise.
900
#[XError] Error executing +xwininfo+.
902
# p xwin.visible? #=> 470
904
# p xwin.visible? #=> nil
908
Open3.popen3("#{XDo::XWININFO} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
910
Kernel.raise(XDo::XError, err) unless err.empty?
911
return out =~ /IsViewable/
914
#Returns true if the window exists.
918
# p xwin.exists? #=> true
920
XDo::XWindow.id_exists?(@id)
923
#Closes a window by activating it, and sending it the close keystroke (obtained
924
#from the window manager's settings, usually [ALT] + [F4]).
928
#[NotImplementedError] You didn't require "xdo/keyboard".
929
#[LoadError] Unable to get gconf value, check key set and gconftool-2 installed
933
#A program could ask to save data.
935
#Use #kill! to kill the process running the window.
937
#Available after requireing "xdo/keyboard".
939
Kernel.raise(NotImplementedError, "You have to require 'xdo/keyboard' before you can use #{__method__}!") unless defined? XDo::Keyboard
941
XDo::Keyboard.char(self.class.get_window_manager_keystroke('close'))
946
#More aggressive variant of #close. Think of +close!+ as
947
#the middle between #close and #kill!. It first tries
948
#to close the window by calling #close and if that
949
#does not succeed (within +timeout+ seconds), it will call #kill!.
951
#[+timeout+] (2) The time to wait before using #kill!, in seconds.
955
#[XError] Error executing +xkill+.
959
#Available after requireing "xdo/keyboard".
960
def close!(timeout = 2)
961
Kernel.raise(NotImplementedError, "You have to require 'xdo/keyboard' before you can use #{__method__}!") unless defined? XDo::Keyboard
962
#Try to close normally
964
#Check if it's deleted
966
#If not, wait some seconds and then check again
969
#If it's not deleted after some time, force it to close.
975
#Kills the process that runs a window. The window will be
976
#terminated immediatly, if that isn't what you want, have
981
#[XError] Error executing +xkill+.
987
Open3.popen3("#{XDo::XKILL} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
988
Kernel.raise(XDo::XError, err) unless err.empty?
992
#Returns the window's internal ID.
994
#An integer describing the window's internal ID.
996
# p xwin.to_i #=> 29361095
1001
#Returns a window's title.
1003
#The window's title.
1005
# p xwin.to_s #=> "xwindow.rb * SciTE"
1010
#true if the internal ID is zero.
1014
# p xwin.zero? #=> false
1019
#true if the internal ID is not zero.
1021
#nil or the internal ID.
1023
# p xwin.nonzero? #=> 29361095
1028
[:"name=", :"icon_name=", :"classname="].each do |sym|
1029
define_method(sym) do |str|
1030
set_window(sym.to_s[0..-2].gsub("_", "-"), str.encode("UTF-8"))
1035
alias icon_title= icon_name=
1039
#Calls +xdotool+'s set_window command with the given options.
1040
def set_window(option, value)
1042
Open3.popen3("#{XDOTOOL} set_window --#{option} '#{value}' #{@id}"){|stdin, stdout, stderr| err << stderr.read}
1043
Kernel.raise(XDo::XError, err) unless err.empty?