Class: XDo::XWindow

Inherits:
Object
  • Object
show all
Extended by:
Open3
Includes:
Open3
Defined in:
lib/xdo/xwindow.rb

Overview

This class represents a window on the screen. Each window is uniquely identified by an internal ID; before you can create a reference to a window (a XWindow object) you have to obtain the internal ID of that window and pass it into XWindow.new. Or you use the class methods of this class, notably XWindow.active_window.

Via the XWindow object you get you can manipulate a window in serveral ways, e.g. you can move or resize it. Some methods are not available on every window manager: XWindow.active_window, XWindow.desktop_num, XWindow.desktop_num=, XWindow.desktop, XWindow.desktop=, XWindow.from_active, #raise, #activate, #desktop, #desktop=. Some of them may be available, some not. On my machine (an Ubuntu Jaunty) for example I can use active_window, desktop_num and #activate, but not #raise or #desktop=. Those methods are tagged with the sentence “Part of the EWMH standard XY”. Not all parts of the EWMH standard are provided by every window manager.

Many methods accept a name parameter; be aware that this name is not the whole name of a window, but a pattern to match. So, if you pass in “edit”, it will even match “gedit”. xdotool handles that parameter with C style regexps.

The opt parameter of many methods is a hash that can have the following keys:

Key          | Effect if true
=============+====================================
:title       | Window titles are searched. 
-------------+------------------------------------
:name        | Window names are searched. 
-------------+------------------------------------
:class       | Window classes are searched. 
-------------+------------------------------------
:onlyvisible | Only visible windows are searched.

The default values for them depend on the method you want to use. See the method’s argument list to find out if a parameter is set to true or, if it isn’t mentioned, to nil.

Be very careful with the methods that are part of the two desktop EWMH standards. After I set the number of desktops and changed the current desktop, I had to reboot my system to get the original configuration back. I don’t know if I’m not using xdotool correct, but neither my library nor xdotool itself could rescue my desktop settings. Btw, that’s the reason why it’s not in XDo’s unit tests (but it should work; at least in one way…).

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id) ⇒ XWindow

Creates a new XWindow object from an internal ID. See the XWindow class methods.



218
219
220
# File 'lib/xdo/xwindow.rb', line 218

def initialize(id)
  @id = id.to_i
end

Instance Attribute Details

#idObject (readonly)

The internal ID of the window.



48
49
50
# File 'lib/xdo/xwindow.rb', line 48

def id
  @id
end

Class Method Details

.active_windowObject

Returns the internal ID of the currently focused window. This method is more reliable than focused_window. Part of the EWMH standard ACTIVE_WINDOW.

Raises:



112
113
114
115
116
117
118
# File 'lib/xdo/xwindow.rb', line 112

def active_window
  err = ""
  out = ""
  popen3("#{XDo::XDOTOOL} getactivewindow"){|stdin, stdout, stderr| out = stdout.read; err = stderr.read}
  raise(XDo::XError, err) unless err.empty?
  return Integer(out)
end

.desktopObject

Output the number of the active desktop. Part of the EWMH standard CURRENT_DESKTOP.

Raises:



150
151
152
153
154
155
156
# File 'lib/xdo/xwindow.rb', line 150

def desktop
  err = ""
  out = ""
  popen3("#{XDo::XDOTOOL} get_desktop"){|stdin, stdout, stderr| out = stdout.read; err = stderr.read}
  raise(XDo::XError, err) unless err.empty?
  Integer(out)
end

.desktop=(num) ⇒ Object

Change the view to desktop num. Part of the EWMH standard CURRENT_DESKTOP.

Raises:



141
142
143
144
145
146
# File 'lib/xdo/xwindow.rb', line 141

def desktop=(num)
  err = ""
  popen3("#{XDo::XDOTOOL} set_desktop #{num}"){|stdin, stdout, stderr| err << stderr.read}
  raise(XDo::XError, err) unless err.empty?
  num
end

.desktop_nameObject

Name of the desktop window. Default is “x-nautilus-desktop”.



182
183
184
# File 'lib/xdo/xwindow.rb', line 182

def desktop_name
  @desktop_name ||= "x-nautilus-desktop"
end

.desktop_name=(name) ⇒ Object

Set this to the name of your desktop window.



177
178
179
# File 'lib/xdo/xwindow.rb', line 177

def desktop_name=(name)
  @desktop_name = name
end

.desktop_numObject

Get the number of working desktops. Part of the EWMH standard WM_DESKTOP.

Raises:



131
132
133
134
135
136
137
# File 'lib/xdo/xwindow.rb', line 131

def desktop_num
  err = ""
  out = ""
  popen3("#{XDo::XDOTOOL} get_num_desktops"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
  raise(XDo::XError, err) unless err.empty?
  Integer(out)
end

.desktop_num=(num) ⇒ Object

Set the number of working desktops. Part of the EWMH standard WM_DESKTOP.

Raises:

  • (XDo::Error)


122
123
124
125
126
127
# File 'lib/xdo/xwindow.rb', line 122

def desktop_num=(num)
  err = ""
  popen3("#{XDo::XDOTOOL} set_num_desktops #{num}"){|stdin, stdout, stderr| err << stderr.read}
  raise(XDo::Error, err) unless err.empty?
  num
end

.exists?(name, opts = {title: true, name: true, :class => true}) ⇒ Boolean

Checks if a window whose name matches name exists. Think about passing :onlyvisible in the opt hash.

Returns:

  • (Boolean)


54
55
56
57
58
59
60
# File 'lib/xdo/xwindow.rb', line 54

def exists?(name, opts = {title: true, name: true, :class => true})
  begin
    !search(name, opts).empty?
  rescue
    false
  end
end

.focus_desktopObject Also known as: activate_desktop

Activate the desktop



187
188
189
190
191
# File 'lib/xdo/xwindow.rb', line 187

def focus_desktop
  desktop = from_name(desktop_name)
  desktop.focus
  desktop.activate
end

.focused_window(notice_childs = false) ⇒ Object

Returns the internal ID of the currently focused window. If the notice_childs parameter is true, also childwindows are noticed. This method may find an invisible window, see active_window for a more reliable method.

Raises:



101
102
103
104
105
106
107
# File 'lib/xdo/xwindow.rb', line 101

def focused_window(notice_childs = false)
  err = ""
  out = ""
  popen3("#{XDo::XDOTOOL} getwindowfocus #{notice_childs ? "-f" : ""}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
  raise(XDo::XError, err) unless err.empty?
  return out.to_i
end

.from_activeObject

Creates a XWindow by calling active_window.



172
173
174
# File 'lib/xdo/xwindow.rb', line 172

def from_active
  new(active_window)
end

.from_focused(notice_childs = false) ⇒ Object

Creates a XWindow by calling focused_window with the given parameter.



167
168
169
# File 'lib/xdo/xwindow.rb', line 167

def from_focused(notice_childs = false)
  new(focused_window(notice_childs))
end

.from_name(name, opts = {title: true, name: true, :class => true}) ⇒ Object

Creates a XWindow by calling search with the given parameters. The window is created from the first ID found.

Raises:



160
161
162
163
164
# File 'lib/xdo/xwindow.rb', line 160

def from_name(name, opts = {title: true, name: true, :class => true})
  ids = search(name, opts)
  raise(XDo::XError, "The window '#{name}' wasn't found!") if ids.empty?
  new(ids.first)
end

.id_exists?(id) ⇒ Boolean

Returns true if the given window ID exists, false otherwise.

Returns:

  • (Boolean)


63
64
65
66
67
68
# File 'lib/xdo/xwindow.rb', line 63

def id_exists?(id)
  err = ""
  popen3("#{XDo::XWININFO} -id #{id}"){|stdin, stdout, stderr| err << stderr.read}
  return false unless err.empty?
  return true
end

.minimizeObject

Minimizes the active window. There’s no way to restore a specific minimized window. Available after requireing “xdo/keyboard”.

Raises:

  • (NotImplementedError)


203
204
205
206
# File 'lib/xdo/xwindow.rb', line 203

def minimize
  raise(NotImplementedError, "You have to require 'xdo/keyboard' before you can use #{__method__}!") unless defined? XDo::Keyboard
  XDo::Keyboard.key("Alt+F9")
end

.search(name, opts = {title: true, name: true, :class => true}) ⇒ Object

Search for a window name to get the internal ID of a window. Return value is an array containing all found IDs or an empty array if none is found.



88
89
90
91
92
93
94
95
# File 'lib/xdo/xwindow.rb', line 88

def search(name, opts = {title: true, name: true, :class => true})
  cmd = "#{XDo::XDOTOOL} search "
  opts.each_pair{|key, value| cmd << "--#{key} " if value}
  cmd << '"' << name << '"'
  #Error wird nicht behandelt, weil im Fehlerfall einfach nur ein leeres Array zurückkommen soll
  out = `#{cmd}`
  out.lines.to_a.collect{|l| l.strip.to_i}
end

.toggle_maximizeObject

Maximize or normalize the active window if already maximized. Available after requireing “xdo/keyboard”.

Raises:

  • (NotImplementedError)


210
211
212
213
# File 'lib/xdo/xwindow.rb', line 210

def toggle_maximize
  raise(NotImplementedError, "You have to require 'xdo/keyboard' before you can use #{__method__}!") unless defined? XDo::Keyboard
  XDo::Keyboard.key("Alt+F10")
end

.toggle_minimize_allObject

Minimize all windows (or restore, if already) by sending [CTRL][ALT][D]. Available after requireing “xdo/keyboard”.

Raises:

  • (NotImplementedError)


196
197
198
199
# File 'lib/xdo/xwindow.rb', line 196

def toggle_minimize_all
  raise(NotImplementedError, "You have to require 'xdo/keyboard' before you can use #{__method__}!") unless defined? XDo::Keyboard
  XDo::Keyboard.ctrl_alt_d
end

.wait_for_close(name, opts = {title: true, name: true, :class => true, :onlyvisible => true}) ⇒ Object

Waits for a window to close. If the window does not exists when calling wait_for_close, the method returns immediately.



80
81
82
83
# File 'lib/xdo/xwindow.rb', line 80

def wait_for_close(name, opts = {title: true, name: true, :class => true, :onlyvisible => true})
  loop{break if !exists?(name, opts);sleep(0.5)}
  nil
end

.wait_for_window(name, opts = {title: true, name: true, :class => true, :onlyvisible => true}) ⇒ Object

Waits for a window name to exist and returns the ID of that window. Returns immediately if the window does already exist.



72
73
74
75
76
# File 'lib/xdo/xwindow.rb', line 72

def wait_for_window(name, opts = {title: true, name: true, :class => true, :onlyvisible => true})
  loop{break if exists?(name, opts);sleep(0.5)}
  sleep 1 #To ensure it's really there
  search(name, opts).first
end

Instance Method Details

#abs_positionObject Also known as: position

The absolute position of the window on the screen.



315
316
317
318
319
320
321
322
323
324
# File 'lib/xdo/xwindow.rb', line 315

def abs_position
  out = ""
  err = ""
  popen3("#{XDo::XWININFO} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
  Kernel.raise(XDo::XError, err) unless err.empty?
  out = out.strip.lines.to_a
  x = out[2].match(/:\s+(\d+)/)[1]
  y = out[3].match(/:\s+(\d+)/)[1]
  [x.to_i, y.to_i]
end

#activateObject

Activate a window. That is, bring it to top and give it the input focus. Part of the EWMH standard ACTIVE_WINDOW.



280
281
282
283
284
# File 'lib/xdo/xwindow.rb', line 280

def activate
  err = ""
  popen3("#{XDo::XDOTOOL} windowactivate #{@id}"){|stdin, stdout, stderr| err << stderr.read}
  Kernel.raise(XDo::XError, err) unless err.empty?
end

#closeObject

Closes a window by activating it and then sending [ALT] + [F4]. A program could ask to save data. Use #kill! to kill the process running the window. Available after requireing “xdo/keyboard”



370
371
372
373
374
375
376
377
# File 'lib/xdo/xwindow.rb', line 370

def close
  Kernel.raise(NotImplementedError, "You have to require 'xdo/keyboard' before you can use #{__method__}!") unless defined? XDo::Keyboard
  activate
  sleep 0.5
  XDo::Keyboard.char("Alt+F4")
  sleep 0.5
  nil
end

#close!(timeout = 2) ⇒ Object

More aggressive variant of #close. Think of close! as the middle between #close and #kill!. It first tries to close the window by calling #close and if that does not succeed (within timeout seconds), it will call #kill!. Available after requireing “xdo/keyboard”.



384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
# File 'lib/xdo/xwindow.rb', line 384

def close!(timeout = 2)
  Kernel.raise(NotImplementedError, "You have to require 'xdo/keyboard' before you can use #{__method__}!") unless defined? XDo::Keyboard
  #Try to close normally
  close
  #Check if it's deleted
  if exists?
    #If not, wait some seconds and then check again
    sleep timeout
    if exists?
      #If it's not deleted after some time, force it to close. 
      kill!
    else
      return
    end
  else
    return
  end
end

#desktopObject

Get the desktop the window is on. Part of the EWMH standard CURRENT_DESKTOP.



296
297
298
299
300
301
302
# File 'lib/xdo/xwindow.rb', line 296

def desktop
  err = ""
  out = ""
  popen3("#{XDo::XDOTOOL} get_desktop_for_window #{@id}"){|stdin, stdout, stderr| out = stdout.read; err << stderr.read}
  Kernel.raise(XDo::XError, err) unless err.empty?
  Integer(out)
end

#desktop=(num) ⇒ Object

Move a window to a desktop. Part of the EWMH standard CURRENT_DESKTOP.



288
289
290
291
292
# File 'lib/xdo/xwindow.rb', line 288

def desktop=(num)
  err = ""
  popen3("#{XDo::XDOTOOL} set_desktop_for_window #{@id} #{num}"){|stdin, stdout, stderr| err << stderr.read}
  Kernel.raise(XDo::XError, err) unless err.empty?
end

#exists?Boolean

Returns true if the window exists.

Returns:

  • (Boolean)


362
363
364
# File 'lib/xdo/xwindow.rb', line 362

def exists?
  XDo::XWindow.exists?(@id)
end

#focusObject

Set the input focus to the window (but don’t bring it to the front).



245
246
247
248
249
# File 'lib/xdo/xwindow.rb', line 245

def focus
  err = ""
  popen3("#{XDo::XDOTOOL} windowfocus #{@id}"){|stdin, stdout, stderr| err << stderr.read}
  Kernel.raise(XDo::XError, err) unless err.empty?
end

#inspectObject

Human-readable output of form

<XDo::XWindow: "title" (window_id)>


224
225
226
# File 'lib/xdo/xwindow.rb', line 224

def inspect
  %Q|<XDo::XWindow: "#{title}" (#{id})>|
end

#kill!Object

Kills the process that runs a window. The window will be terminated immediatly, if that isn’t what you want, have a look at #close.



406
407
408
409
410
411
412
# File 'lib/xdo/xwindow.rb', line 406

def kill!
  out = ""
  err = ""
  popen3("#{XDo::XKILL} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
  Kernel.raise(XDo::XError, err) unless err.empty?
  nil
end

#mapObject

Map a window to the screen (make it visible).



257
258
259
260
261
# File 'lib/xdo/xwindow.rb', line 257

def map
  err = ""
  popen3("#{XDo::XDOTOOL} windowmap #{@id}"){|stdin, stdout, stderr| err << stderr.read}
  Kernel.raise(XDo::XError, err) unless err.empty?
end

#move(x, y) ⇒ Object

Moves a window. xdotool is not really exact with the coordinates, the window will be within a range of +-10 pixels.



238
239
240
241
242
# File 'lib/xdo/xwindow.rb', line 238

def move(x, y)
  err = ""
  popen3("#{XDo::XDOTOOL} windowmove #{@id} #{x} #{y}"){|stdin, stdout, stderr| err << stderr.read}
  Kernel.raise(XDo::XError, err) unless err.empty?
end

#raiseObject

Bring a window to the front (but don’t give it the input focus). Not implemented in all window managers.



272
273
274
275
276
# File 'lib/xdo/xwindow.rb', line 272

def raise
  err = ""
  popen3("#{XDo::XDOTOOL} windowraise #{@id}"){|stdin, stdout, stderr| err << stderr.read}
  Kernel.raise(XDo::XError, err) unless err.empty?
end

#rel_positionObject

The position of the window relative to it’s parent window.



328
329
330
331
332
333
334
335
336
337
# File 'lib/xdo/xwindow.rb', line 328

def rel_position
  out = ""
  err = ""
  popen3("#{XDo::XWININFO} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
  Kernel.raise(XDo::XError, err) unless err.empty?
  out = out.strip.lines.to_a
  x = out[4].match(/:\s+(\d+)/)[1]
  y = out[5].match(/:\s+(\d+)/)[1]
  [x.to_i, y.to_i]
end

#resize(width, height, use_hints = false) ⇒ Object

Set the size of a window. This has no effect on maximized winwows.



229
230
231
232
233
234
# File 'lib/xdo/xwindow.rb', line 229

def resize(width, height, use_hints = false)
  err = ""
  cmd = "#{XDo::XDOTOOL} windowsize #{use_hints ? "--usehints " : ""}#{@id} #{width} #{height}"
  popen3("#{cmd}"){|stdin, stdout, stderr| err << stderr.read}
  Kernel.raise(XDo::XError, err) unless err.empty?
end

#sizeObject

The size of the window.



340
341
342
343
344
345
346
347
348
349
# File 'lib/xdo/xwindow.rb', line 340

def size
  out = ""
  err = ""
  popen3("#{XDo::XWININFO} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
  out = out.strip.lines.to_a
  Kernel.raise(XDo::XError, err) unless err.empty?
  width = out[6].match(/:\s+(\d+)/)[1]
  height = out[7].match(/:\s+(\d+)/)[1]
  [width.to_i, height.to_i]
end

#titleObject

The title of the window or nil if it doesn’t have a title.



305
306
307
308
309
310
311
312
# File 'lib/xdo/xwindow.rb', line 305

def title
  err = ""
  out = ""
  popen3("#{XDo::XWININFO} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
  Kernel.raise(XDo::XError, err) unless err.empty?
  title = out.strip.lines.to_a[0].match(/"(.*)"/)[1] rescue Kernel.raise(XDo::XError, "No window with ID #{@id} found!")
  return title #Kann auch nil sein, dann ist das Fenster namenlos. 
end

#unfocusObject

The window loses the input focus by setting it to the desktop.



252
253
254
# File 'lib/xdo/xwindow.rb', line 252

def unfocus
  XDo::XWindow.focus_desktop
end

#unmapObject

Unmap a window from the screen (make it invisible).



264
265
266
267
268
# File 'lib/xdo/xwindow.rb', line 264

def unmap
  err = ""
  popen3("#{XDo::XDOTOOL} windowunmap #{@id}"){|stdin, stdout, stderr| err << stderr.read}
  Kernel.raise(XDo::XError, err) unless err.empty?
end

#visible?Boolean

true if the window is mapped to the screen.

Returns:

  • (Boolean)


352
353
354
355
356
357
358
359
# File 'lib/xdo/xwindow.rb', line 352

def visible?
  err = ""
  out = ""
  popen3("#{XDo::XWININFO} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
  out = out.strip.lines.to_a
  Kernel.raise(XDo::XError, err) unless err.empty?
  return out[17].match(/:\s+(\w+)/)[1] == "IsViewable" ? true : false
end