~ubuntu-branches/ubuntu/precise/unity-2d/precise-security

« back to all changes in this revision

Viewing changes to tests/misc/lib/xdo/xwindow.rb

  • Committer: Package Import Robot
  • Author(s): Didier Roche, Didier Roche, Aurélien Gâteau
  • Date: 2012-01-13 09:12:36 UTC
  • mfrom: (1.1.25)
  • Revision ID: package-import@ubuntu.com-20120113091236-844z32uco10hs6ym
Tags: 5.2.0-0ubuntu1
[ Didier Roche ]
* New upstream release:
  - Select quicklist items with just one right click (LP: #688830)
  - Launcher - Dragging and dropping a running application in to the Trash
    should quit the application and (if the app is pinned to the Launcher)
    un-pin the application from the Launcher (LP: #870143)
  - Dash - "See more..." line should be base-aligned with section header
    (LP: #748101)
  - right click on the dash icon should display a list of the lenses
    (LP: #868452)
  - Top Bar - rename the "Desktop" title in the Top Bar (displayed when no
    window has focus)  to "Ubuntu Desktop" (LP: #869873)
  - Application title on quicklist should be bold (or more visible)
    (LP: #900400)
  - unity-2d-launcher crashed with SIGSEGV  when opening a folder on a CD
    (LP: #831868)
  - unity-2d-places crashed with SIGSEGV in QScriptValue::call()
    (LP: #836498)
  - unity-2d-launcher crashed with SIGSEGV in geis_finish() (LP: #850893)
  - unity-2d-places crashed with SIGABRT in raise() (LP: #857575)
  - unity-2d-launcher crashed with SIGSEGV in exit() (LP: #859596)
  - [spread] layout broken since bzr revision 799 of lp:unity-2d
    (LP: #900895)
  - [workspace switcher] keyboard navigation of workspace switcher broken
    for accessibility (LP: #744978)
  - [spread] workspace switcher performance is poor, especially on low
    powered CPUs (LP: #745764)
  - Launcher - the rendering of the BFB and Lens squircle does not match the
    design (LP: #838708)
  - [dash] Huge performance hit when scrolling search results with
    accessibility enabled (LP: #862956)
  - DBUS_STARTER_ADDRESS and DBUS_STARTER_BUS_TYPE aren't always unset from
    environment making gedit and possibly others fail to start (LP: #873027)
  - Win Key can not be disabled in Unity-2d (LP: #873580)
  - [dash] Unity-2d dash very slow to open (LP: #881756)
  - [tests] LauncherViewTest hanging (LP: #894380)
  - [tests] Unit tests failing due to lack of Xserver (LP: #894381)
  - [launcher] Alt+F1 broken: does not give the focus to the launcher's
    content (LP: #901505)
  - [tests] Add Automated User Experience testing (LP: #903495)
  - [workspace switcher] Performance can be poor when using the opengl
    backend because of window texture sizes that are not limited
    (LP: #808716)
  - [dash] no way to unmaximize (LP: #860400)
  - [launcher] In non-composite mode, background is black (LP: #879288)
  - [dash] Unity 2D shows 'Search' instead of 'Run Command' on ALT + F2
    (LP: #883392)
  - [launcher] Removing icon from launcher makes it hide immediately
    (LP: #884410)
  - OpenGL disabled regardless of use-opengl setting (LP: #887957)
  - if libdir does not equal lib (LP: #888164)
  - [launcher] Launcher stuck open while mouse moved to left corner of panel
    (LP: #892004)
  - [dash] Long results label are truncated instead of elided and a few
    pixels of the next line is visible (LP: #901491)
  - [launcher] Dash icon missing in PPA (LP: #903182)
  - [launcher] Tile context menu should appear at mouse click down event
    (LP: #813036)
  - [launcher] Trash tile highlight is truncated top and bottom
    (LP: #876589)
  - [dash] Text highlighting color is wrong (LP: #880222)
  - [launcher] left edge of panel should not reveal launcher (LP: #891636)
  - [dash] Word "Filter results" has underline when highlighted
    (LP: #893061)
  - [launcher] Alt+F1, change desktop, Alt+F1, hit Esc: launcher doesn't
    give away focus (LP: #897640)
  - Top Bar - rename the "Desktop" title in the Top Bar (displayed when no
    window has focus)  to "Ubuntu Desktop" (LP: #869873)
  - [launcher] Show desktop doesn't show launcher (LP: #898161)
  - [launcher] Context menu/tooltip not positioned at Tile center
    (LP: #898349)
  - The QT_LAYOUT_DIRECTION string needs a translator comment (LP: #863058)
  - unity panel menus don't stay open when clicked on second monitor
    (LP: #869196)
  - Dash- More fixes to layout and alignments (LP: #906235)
* debian/control:
  - bump libunitycore build-dep to 5.0.

[ Aurélien Gâteau ]
* debian/control:
  - bump build-dep versions.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#Encoding: UTF-8
 
2
#This file is part of Xdo.
 
3
#Copyright © 2009, 2010 Marvin Gülker
 
4
#  Initia in potestate nostra sunt, de eventu fortuna iudicat.
 
5
#
 
6
# Modified by Gerry Boland <gerry dot boland at canonical dot com> 
 
7
require File.join(File.dirname(__FILE__), '_xdo')
 
8
require "open3"
 
9
 
 
10
module XDo
 
11
  
 
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.
 
16
  #
 
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.
 
25
  #
 
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.
 
30
  #
 
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.
 
40
  #
 
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...).
 
46
  class XWindow
 
47
    #The internal ID of the window.
 
48
    attr_reader :id
 
49
    
 
50
    class << self
 
51
      
 
52
      #Checks if a window exists.
 
53
      #===Parameters
 
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.
 
56
      #===Return value
 
57
      #true or false.
 
58
      #===Example
 
59
      #  p XWindow.exists?("gedit") #=> true
 
60
      #  p XWindow.exists?(/^gedit/) #=> false
 
61
      #===Remarks
 
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
 
67
        end
 
68
        
 
69
        !search(name, *opts).empty?
 
70
      end
 
71
      
 
72
      #Checks wheather the given ID exists or not.
 
73
      #===Parameters
 
74
      #[+id+] The ID to check for.
 
75
      #===Return value
 
76
      #true or false.
 
77
      #===Example
 
78
      #  p XWindow.id_exits?(29360674) #=> true
 
79
      #  p XWindow.id_exists?(123456) #=> false
 
80
      def id_exists?(id)
 
81
        err = ""
 
82
        Open3.popen3("#{XDo::XWININFO} -id #{id}"){|stdin, stdout, stderr| err << stderr.read}
 
83
        return false unless err.empty?
 
84
        return true
 
85
      end
 
86
      
 
87
      #Waits for a window name to exist.
 
88
      #===Parameters
 
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.
 
91
      #===Return value
 
92
      #The ID of the newly appeared window.
 
93
      #===Example
 
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:
 
99
      #  require "timeout"
 
100
      #  Timeout.timeout(3){XDo::XWindow.wait_for_window("gedit")}
 
101
      #===Remarks
 
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
 
107
        end
 
108
        
 
109
        loop{break if exists?(name, *opts);sleep(0.5)}
 
110
        search(name, *opts).first
 
111
      end
 
112
      
 
113
      #Waits for a window to close.
 
114
      #===Parameters
 
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.
 
117
      #===Return value
 
118
      #nil.
 
119
      #===Example
 
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:
 
125
      #  require "timeout"
 
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
 
131
        end
 
132
        
 
133
        loop{break if !exists?(name, *opts);sleep(0.5)}
 
134
        nil
 
135
      end
 
136
      
 
137
      #Search for a window name to get the internal ID of a window.
 
138
      #===Parameters
 
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.
 
147
      #===Return value
 
148
      #An array containing the IDs of all found windows or an empty array
 
149
      #if none was found.
 
150
      #===Example
 
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
 
161
        end
 
162
        opts = [:name, :class, :classname] if opts.empty?
 
163
        
 
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)
 
168
        #TODO
 
169
        #The following is the new behaviour that will be activated with the next minor version.
 
170
        #See DEPRECATE.rdoc.
 
171
        #str = if str.kind_of?(Regexp)
 
172
          #str.source
 
173
        #else
 
174
          #"^#{str.to_str}$"
 
175
        #end
 
176
        
 
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}
 
182
      end
 
183
      
 
184
      #Returns the internal ID of the currently focused window.
 
185
      #===Parameters
 
186
      #[+notice_children+] (false) If true, childwindows are noticed and you may get a child window instead of a toplevel window.
 
187
      #===Return value
 
188
      #The internal ID of the found window.
 
189
      #===Raises
 
190
      #[XError] Error invoking +xdotool+.
 
191
      #===Example
 
192
      #  p XDo::XWindow.focused_window #=> 41943073
 
193
      #  p XDo::XWindow.focused_window(true) #=> 41943074
 
194
      #===Remarks
 
195
      #This method may find an invisible window, see active_window for a more reliable method.
 
196
      def focused_window(notice_children = false)
 
197
        err = ""
 
198
        out = ""
 
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?
 
201
        return out.to_i
 
202
      end
 
203
      
 
204
      #Returns the internal ID of the currently focused window.
 
205
      #===Return value
 
206
      #The ID of the found window.
 
207
      #===Raises
 
208
      #[XError] Error invoking +xdotool+.
 
209
      #===Example
 
210
      #  p XDo::XWindow.active_window #=> 41943073
 
211
      #===Remarks
 
212
      #This method is more reliable than #focused_window, but never finds an invisible window.
 
213
      #
 
214
      #Part of the EWMH standard ACTIVE_WINDOW.
 
215
      def active_window
 
216
        err = ""
 
217
        out = ""
 
218
        Open3.popen3("#{XDo::XDOTOOL} getactivewindow"){|stdin, stdout, stderr| out = stdout.read; err = stderr.read}
 
219
        raise(XDo::XError, err) unless err.empty?
 
220
        return Integer(out)
 
221
      end
 
222
      
 
223
      #Set the number of working desktops.
 
224
      #===Parameters
 
225
      #[+num+] The number of desktops you want to exist.
 
226
      #===Return value
 
227
      #+num+.
 
228
      #===Raises
 
229
      #[XError] Error invoking +xdotool+.
 
230
      #===Example
 
231
      #  XDo::XWindow.desktop_num = 2
 
232
      #===Remarks
 
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.
 
237
      #
 
238
      #Part of the EWMH standard WM_DESKTOP.
 
239
      def desktop_num=(num)
 
240
        err = ""
 
241
        Open3.popen3("#{XDo::XDOTOOL} set_num_desktops #{num}"){|stdin, stdout, stderr| err << stderr.read}
 
242
        raise(XDo::Error, err) unless err.empty?
 
243
        num
 
244
      end
 
245
      
 
246
      #Get the number of working desktops.
 
247
      #===Return value
 
248
      #The number of desktops.
 
249
      #===Raises
 
250
      #[XError] Error invoking +xdotool+.
 
251
      #===Example
 
252
      #  p XDo::XWindow.desktop_num = 1
 
253
      #===Remarks
 
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.
 
258
      #
 
259
      #Part of the EWMH standard WM_DESKTOP.
 
260
      def desktop_num
 
261
        err = ""
 
262
        out = ""
 
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?
 
265
        Integer(out)
 
266
      end
 
267
      
 
268
      #Change the view to desktop +num+.
 
269
      #===Parameters
 
270
      #[+num+] The 0-based index of the desktop you want to switch to.
 
271
      #===Return value
 
272
      #+num+.
 
273
      #===Raises
 
274
      #[XError] Error invoking +xdotool+.
 
275
      #===Example
 
276
      #  XDo::XWindow.desktop = 1
 
277
      #===Remarks
 
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.
 
282
      #
 
283
      #Part of the EWMH standard CURRENT_DESKTOP.
 
284
      def desktop=(num)
 
285
        err = ""
 
286
        Open3.popen3("#{XDo::XDOTOOL} set_desktop #{num}"){|stdin, stdout, stderr| err << stderr.read}
 
287
        raise(XDo::XError, err) unless err.empty?
 
288
        num
 
289
      end
 
290
      
 
291
      #Returns the number of the active desktop.
 
292
      #===Return value
 
293
      #The number of the currently shown desktop.
 
294
      #===Raises
 
295
      #[XError] Error invoking +xdotool+.
 
296
      #===Example
 
297
      #  p XDo::XWindow.desktop #=> 0
 
298
      #===Remarks
 
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.
 
303
      #
 
304
      #Part of the EWMH standard CURRENT_DESKTOP.
 
305
      def desktop
 
306
        err = ""
 
307
        out = ""
 
308
        Open3.popen3("#{XDo::XDOTOOL} get_desktop"){|stdin, stdout, stderr| out = stdout.read; err = stderr.read}
 
309
        raise(XDo::XError, err) unless err.empty?
 
310
        Integer(out)
 
311
      end
 
312
      
 
313
      #Creates a XWindow by calling search with the given parameters.
 
314
      #The window is created from the first ID found.
 
315
      #===Parameters
 
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.
 
318
      #===Return value
 
319
      #The created XWindow object.
 
320
      #===Raises
 
321
      #[XError] Error invoking +xdotool+.
 
322
      #===Example
 
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
 
335
        end
 
336
        
 
337
        ids = search(name, *opts)
 
338
        raise(XDo::XError, "The window '#{name}' wasn't found!") if ids.empty?
 
339
        new(ids.first)
 
340
      end
 
341
      
 
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)
 
346
      end
 
347
      
 
348
      #Same as XWindow.from_search, but only looks for the window's titles to match.
 
349
      #===Parameters
 
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.
 
351
      #===Return value
 
352
      #A XWindow object made up from the first window ID found.
 
353
      #===Raises
 
354
      #[XError] Error invoking +xdotool+.
 
355
      #===Example
 
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)
 
364
      end
 
365
      
 
366
      #Creates a XWindow by calling XWindow.focused_window with the given parameter.
 
367
      #===Parameters
 
368
      #[+notice_children+] (false) If true, you may get a child window as the active window.
 
369
      #===Return value
 
370
      #The newly created XWindow objects.
 
371
      #===Example
 
372
      #  xwin = XDo::XWindow.from_focused
 
373
      #===Remarks
 
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))
 
378
      end
 
379
      
 
380
      #Creates a XWindow by calling active_window.
 
381
      #===Return value
 
382
      #The newly created XWindow object.
 
383
      #===Example
 
384
      #  xwin = XDo::XWindow.from_active
 
385
      #===Remarks
 
386
      #This method does not find invisible nor child windows; if you want that,
 
387
      #you should take a look at XWindow.from_focused.
 
388
      def from_active
 
389
        new(active_window)
 
390
      end
 
391
      
 
392
      #Returns the ID of the root window.
 
393
      #===Return value
 
394
      #The ID of the root window.
 
395
      #===Example
 
396
      #  p XDo::XWindow.root_id #=> 346
 
397
      def root_id
 
398
        out = ""
 
399
        err = ""
 
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)
 
403
      end
 
404
      
 
405
      #Creates a XWindow refering to the root window.
 
406
      #===Return value
 
407
      #The newly created XWindow object.
 
408
      #===Example
 
409
      #  rwin = XDo::XWindow.from_root
 
410
      def from_root
 
411
        new(root_id)
 
412
      end
 
413
      
 
414
      #Creates a invalid XWindow.
 
415
      #===Return value
 
416
      #The newly created XWindow object.
 
417
      #===Example
 
418
      #  nwin = XDo::XWindow.from_null
 
419
      #===Remarks
 
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.
 
424
      def from_null
 
425
        new(0) #Zero never is a valid window ID. Even the root window has another ID.
 
426
      end
 
427
      
 
428
      #Unsets the input focus by setting it to the invalid
 
429
      #NULL window.
 
430
      #===Parameters
 
431
      #[+sync+] (true) If true, this method blocks until the input focus has been unset. 
 
432
      #===Return value
 
433
      #nil.
 
434
      #===Example
 
435
      #  win = XDo::XWindow.from_active
 
436
      #  win.focus
 
437
      #  XDo::XWindow.unfocus
 
438
      def unfocus(sync = true)
 
439
        from_null.focus(sync)
 
440
      end
 
441
      
 
442
      #Deprecated.
 
443
      def desktop_name=(name)
 
444
        warn("#{caller.first}: Deprecation warning: XWindow.desktop_name= doesn't do anything anymore.")
 
445
      end
 
446
      
 
447
      #Deprecated.
 
448
      def desktop_name
 
449
        warn("#{caller.first}: Deprecation warning: XWindow.desktop_name doesn't do anything anymore.")
 
450
        "x-nautilus-desktop"
 
451
      end
 
452
      
 
453
      #Deprecated. Just calls XWindow.unfocus internally.
 
454
      def focus_desktop
 
455
        warn("#{caller.first}: Deprecation warning: XWindow.focus_desktop is deprecated. Use XWindow.unfocus instead.")
 
456
        unfocus
 
457
      end
 
458
      alias activate_desktop focus_desktop
 
459
      
 
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".
 
463
      #===Return value
 
464
      #Undefined.
 
465
      #===Raises
 
466
      #[NotImplementedError] You didn't require 'xdo/keyboard'.
 
467
      #[LoadError] Unable to get gconf value, check key set and gconftool-2 installed
 
468
      #===Example
 
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'))
 
477
      end
 
478
      
 
479
      #Minimizes the active window. There's no way to restore a specific minimized window.
 
480
      #Available after requireing "xdo/keyboard".
 
481
      #===Return value
 
482
      #Undefined.
 
483
      #===Raises
 
484
      #[NotImplementedError] You didn't require 'xdo/keyboard'.
 
485
      #[LoadError] Unable to get gconf value, check key set and gconftool-2 installed
 
486
      #===Example
 
487
      #  XDo::XWindow.minimize
 
488
      def 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'))
 
492
      end
 
493
      
 
494
      #Maximize or normalize the active window if already maximized.
 
495
      #Available after requireing "xdo/keyboard".
 
496
      #===Return value
 
497
      #Undefined.
 
498
      #===Raises
 
499
      #[NotImplementedError] You didn't require 'xdo/keyboard'.
 
500
      #[LoadError] Unable to get gconf value, check key set and gconftool-2 installed
 
501
      #===Example
 
502
      #  XDo::XWindow.minimize
 
503
      #  XDo::XWindow.toggle_maximize
 
504
      def 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'))
 
508
      end
 
509
 
 
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'
 
516
      keystroke = ''
 
517
      out = ''
 
518
      err = ''
 
519
      error_message = "Unable to determine #{name} keyboard shortcut from Metacity - check that gconftool-2 is installed\n"
 
520
 
 
521
      dirs.each do |d|
 
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?
 
526
          keystroke = out.to_s
 
527
          break
 
528
        end
 
529
      end
 
530
 
 
531
      #Bail if no keystroke found
 
532
      Kernel.raise(LoadError, error_message) if keystroke.empty?
 
533
 
 
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!('>','+')
 
538
      return keystroke
 
539
    end
 
540
    end
 
541
    
 
542
    ##
 
543
    #  :method: title=
 
544
    #call-seq:
 
545
    #  title = str
 
546
    #  name = str
 
547
    #
 
548
    #Changes a window's title.
 
549
    #===Parameters
 
550
    #[+str+] The new title.
 
551
    #===Return value
 
552
    #+str+.
 
553
    #===Raises
 
554
    #[XError] Error invoking +xdotool+.
 
555
    #===Example
 
556
    #  xwin.title = "Ruby is awesome!"
 
557
    
 
558
    ##
 
559
    # :method: icon_title=
 
560
    #call-seq:
 
561
    #  icon_title = str
 
562
    #  icon_name = str
 
563
    #
 
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.
 
566
    #===Parameters
 
567
    #[+str+] The string you want to set.
 
568
    #===Return value
 
569
    #+str+.
 
570
    #===Raises
 
571
    #[XError] Error invoking +xdotool+.
 
572
    #===Example
 
573
    #  xwin.icon_title = "This is minimized."
 
574
    
 
575
    ##
 
576
    #  :method: classname=
 
577
    #call-seq:
 
578
    #  classname = str
 
579
    #
 
580
    #Sets a window's classname.
 
581
    #===Parameters
 
582
    #[+str+] The window's new classname.
 
583
    #===Return value
 
584
    #+str+.
 
585
    #===Raises
 
586
    #[XError] Error invoking +xdotool+.
 
587
    #===Example
 
588
    #  xwin.classname = "MyNewClass"
 
589
    
 
590
    #Creates a new XWindow object from an internal ID.
 
591
    #===Parameters
 
592
    #[+id+] The internal ID to create the window from.
 
593
    #===Return value
 
594
    #The newly created XWindow object.
 
595
    #===Example
 
596
    #  id = XWindow.search(/edit/)[1]
 
597
    #  xwin = XWindow.new(id)
 
598
    #===Remarks
 
599
    #See also many class methods of the XWindow class which allow
 
600
    #you to forget about the internal ID of a window.
 
601
    def initialize(id)
 
602
      @id = id.to_i
 
603
    end
 
604
    
 
605
    #Human-readable output of form
 
606
    #  <XDo::XWindow: "title" (window_id)>
 
607
    def inspect
 
608
      %Q|<#{self.class}: "#{title}" (#{id})>|
 
609
    end
 
610
    
 
611
    #Set the size of a window.
 
612
    #===Parameters
 
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. 
 
617
    #===Return value
 
618
    #Undefined.
 
619
    #===Raises
 
620
    #[XError] Error executing +xdotool+.
 
621
    #===Example
 
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)
 
626
    #===Remarks
 
627
    #This has no effect on maximized winwows.
 
628
    def resize(width, height, use_hints = false, sync = true)
 
629
      err = ""
 
630
      opts = []
 
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?
 
635
    end
 
636
    
 
637
    #Moves a window. +xdotool+ is not really exact with the coordinates,
 
638
    #special windows like Ubuntu's panels make it placing wrong. 
 
639
    #===Parameters
 
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. 
 
643
    #===Return value
 
644
    #Undefined.
 
645
    #===Raises
 
646
    #[XError] Error executing +xdotool+.
 
647
    #===Example
 
648
    #  xwin.move(100, 100)
 
649
    #  p xwin.abs_position #=> [101, 101]
 
650
    def move(x, y, sync = true)
 
651
      err = ""
 
652
      opts = []
 
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?
 
656
    end
 
657
    
 
658
    #Set the input focus to the window (but don't bring it to the front).
 
659
    #===Parameters
 
660
    #[+sync+] (true) If true, this method blocks until the window got the input focus. 
 
661
    #===Return value
 
662
    #Undefined.
 
663
    #===Raises
 
664
    #[XError] Error invoking +xdotool+.
 
665
    #===Example
 
666
    #  xwin.focus
 
667
    #===Remarks
 
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)
 
671
      err = ""
 
672
      opts = []
 
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?
 
676
    end
 
677
    
 
678
    #The window loses the input focus by setting it to an invalid window.
 
679
    #Parameters
 
680
    #[+sync+] (true) If true, this method blocks until the focus has been set to nothing. 
 
681
    #===Return value
 
682
    #Undefined.
 
683
    #===Example
 
684
    #  xwin.focus
 
685
    #  xwin.unfocus    
 
686
    def unfocus(sync = true)
 
687
      XDo::XWindow.unfocus(sync)
 
688
    end
 
689
    
 
690
    #Maps a window to the screen (makes it visible).
 
691
    #===Parameters
 
692
    #[+sync+] (true) If true, this method blocks until the window has been mapped. 
 
693
    #===Return value
 
694
    #Undefined.
 
695
    #===Raises
 
696
    #[XError] Error invoking +xdotool+.
 
697
    #===Example
 
698
    #  xwin.unmap #Windows are usually mapped
 
699
    #  xwin.map
 
700
    def map(sync = true)
 
701
      err = ""
 
702
      opts = []
 
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?
 
706
    end
 
707
    
 
708
    #Unmap a window from the screen (make it invisible).
 
709
    #===Parameters
 
710
    #[+sync+] (true) If true, this method blocks until the window has been unmapped. 
 
711
    #===Return value
 
712
    #Undefined.
 
713
    #===Raises
 
714
    #[XError] Error executing +xdotool+.
 
715
    #===Example
 
716
    #  xwin.unmap
 
717
    def unmap(sync = true)
 
718
      err = ""
 
719
      opts = []
 
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?
 
723
    end
 
724
    
 
725
    #Bring a window to the front (but don't give it the input focus).
 
726
    #Not implemented in all window managers.
 
727
    #===Return value
 
728
    #Undefined.
 
729
    #===Raises
 
730
    #[XError] Error executing +xdotool+.
 
731
    #===Example
 
732
    #  xwin.raise
 
733
    def raise
 
734
      err = ""
 
735
      Open3.popen3("#{XDo::XDOTOOL} windowraise #{@id}"){|stdin, stdout, stderr| err << stderr.read}
 
736
      Kernel.raise(XDo::XError, err) unless err.empty?
 
737
    end
 
738
    
 
739
    #Activate a window. That is, bring it to top and give it the input focus.
 
740
    #===Parameters
 
741
    #[+sync+] (true) If true, this method blocks until the window has been activated. 
 
742
    #===Return value
 
743
    #Undefined.
 
744
    #===Raises
 
745
    #[XError] Error executing +xdotool+.
 
746
    #===Example
 
747
    #  xwin.activate
 
748
    #===Remarks
 
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
 
751
    #desktops.
 
752
    #
 
753
    #Part of the EWMH standard ACTIVE_WINDOW.
 
754
    def activate(sync = true)
 
755
      tried_focus = false
 
756
      begin
 
757
        err = ""
 
758
        opts = []
 
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?
 
762
      rescue XDo::XError
 
763
        #If no window is active, xdotool's windowactivate fails, 
 
764
        #because it tries to determine which is the currently active window. 
 
765
        unless tried_focus
 
766
          tried_focus = true
 
767
          focus
 
768
          retry
 
769
        else
 
770
          raise
 
771
        end
 
772
      end
 
773
    end
 
774
    
 
775
    #Move a window to a desktop.
 
776
    #===Parameters
 
777
    #[+num+] The 0-based index of the desktop you want the window to move to.
 
778
    #===Return value
 
779
    #Undefined.
 
780
    #===Raises
 
781
    #[XError] Error executing +xdotool+.
 
782
    #===Example
 
783
    #  xwin.desktop = 3
 
784
    #===Remarks
 
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.
 
789
    #
 
790
    #Part of the EWMH standard CURRENT_DESKTOP.
 
791
    def desktop=(num)
 
792
      err = ""
 
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?
 
795
    end
 
796
    
 
797
    #Get the desktop the window is on.
 
798
    #===Return value
 
799
    #The 0-based index of the desktop this window resides on.
 
800
    #===Raises
 
801
    #[XError] Error executing +xdotool+.
 
802
    #===Example
 
803
    #  p xwin.desktop #=> 0
 
804
    #===Remarks
 
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.
 
809
    #
 
810
    #Part of the EWMH standard CURRENT_DESKTOP.
 
811
    def desktop
 
812
      err = ""
 
813
      out = ""
 
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?
 
816
      Integer(out)
 
817
    end
 
818
    
 
819
    #The title of the window or nil if it doesn't have a title.
 
820
    #===Return value
 
821
    #The window's title, encoded as UTF-8, or nil if the window doesn't have a title.
 
822
    #===Raises
 
823
    #[XError] Error executing +xwininfo+.
 
824
    #===Example
 
825
    #  p xwin.title #=> "xwindow.rb SciTE"
 
826
    def title
 
827
      err = ""
 
828
      out = ""
 
829
      if @id == XWindow.root_id #This is the root window
 
830
        return "(the root window)"
 
831
      elsif @id.zero?
 
832
        return "(NULL window)"
 
833
      else
 
834
        Open3.popen3("#{XDo::XWININFO} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
 
835
      end
 
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.
 
839
    end
 
840
    
 
841
    #The absolute position of the window on the screen.
 
842
    #===Return value
 
843
    #A two-element array of form <tt>[x, y]</tt>.
 
844
    #===Raises
 
845
    #[XError] Error executing +xwininfo+.
 
846
    #===Example
 
847
    #  p xwin.abs_position #=> [0, 51]
 
848
    def abs_position
 
849
      out = ""
 
850
      err = ""
 
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]
 
856
      [x.to_i, y.to_i]
 
857
    end
 
858
    alias position abs_position
 
859
    
 
860
    #The position of the window relative to it's parent window.
 
861
    #===Return value
 
862
    #A two-element array of form <tt>[x, y]</tt>.
 
863
    #===Raises
 
864
    #[XError] Error executing +xdotool+.
 
865
    #===Example
 
866
    #  p xwin.rel_position => [0, 51]
 
867
    def rel_position
 
868
      out = ""
 
869
      err = ""
 
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]
 
875
      [x.to_i, y.to_i]
 
876
    end
 
877
    
 
878
    #The size of the window.
 
879
    #===Return value
 
880
    #A two-element array of form <tt>[width, height]</tt>.
 
881
    #===Raises
 
882
    #[XError] Error executing +xwininfo+.
 
883
    #===Example
 
884
    #  p xwin.size #=> [1280, 948]
 
885
    def size
 
886
      out = ""
 
887
      err = ""
 
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]
 
894
    end
 
895
    
 
896
    #true if the window is mapped to the screen.
 
897
    #===Return value
 
898
    #nil if the window is not mapped, an integer value otherwise.
 
899
    #===Raises
 
900
    #[XError] Error executing +xwininfo+.
 
901
    #===Example
 
902
    #  p xwin.visible? #=> 470
 
903
    #  xwin.unmap
 
904
    #  p xwin.visible? #=> nil
 
905
    def visible?
 
906
      err = ""
 
907
      out = ""
 
908
      Open3.popen3("#{XDo::XWININFO} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
 
909
      out = out.strip
 
910
      Kernel.raise(XDo::XError, err) unless err.empty?
 
911
      return out =~ /IsViewable/
 
912
    end
 
913
    
 
914
    #Returns true if the window exists.
 
915
    #===Return value
 
916
    #true or false.
 
917
    #===Example
 
918
    #  p xwin.exists? #=> true
 
919
    def exists?
 
920
      XDo::XWindow.id_exists?(@id)
 
921
    end
 
922
    
 
923
    #Closes a window by activating it, and sending it the close keystroke (obtained
 
924
    #from the window manager's settings, usually [ALT] + [F4]).
 
925
    #===Return value
 
926
    #nil.
 
927
    #===Raises
 
928
    #[NotImplementedError] You didn't require "xdo/keyboard".
 
929
    #[LoadError] Unable to get gconf value, check key set and gconftool-2 installed
 
930
    #===Example
 
931
    #  xwin.close
 
932
    #===Remarks
 
933
    #A program could ask to save data.
 
934
    #
 
935
    #Use #kill! to kill the process running the window.
 
936
    #
 
937
    #Available after requireing "xdo/keyboard".
 
938
    def close
 
939
      Kernel.raise(NotImplementedError, "You have to require 'xdo/keyboard' before you can use #{__method__}!") unless defined? XDo::Keyboard
 
940
      activate
 
941
      XDo::Keyboard.char(self.class.get_window_manager_keystroke('close'))
 
942
      sleep 0.5
 
943
      nil
 
944
    end
 
945
    
 
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!.
 
950
    #===Paramters
 
951
    #[+timeout+] (2) The time to wait before using #kill!, in seconds.
 
952
    #===Return value
 
953
    #Undefined.
 
954
    #===Raises
 
955
    #[XError] Error executing +xkill+.
 
956
    #===Example
 
957
    #  xwin.close!
 
958
    #===Remarks
 
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
 
963
      close
 
964
      #Check if it's deleted
 
965
      if exists?
 
966
        #If not, wait some seconds and then check again
 
967
        sleep timeout
 
968
        if exists?
 
969
          #If it's not deleted after some time, force it to close.
 
970
          kill!
 
971
        end
 
972
      end
 
973
    end
 
974
    
 
975
    #Kills the process that runs a window. The window will be
 
976
    #terminated immediatly, if that isn't what you want, have
 
977
    #a look at #close.
 
978
    #===Return value
 
979
    #nil.
 
980
    #===Raises
 
981
    #[XError] Error executing +xkill+.
 
982
    #===Example
 
983
    #  xwin.kill!
 
984
    def kill!
 
985
      out = ""
 
986
      err = ""
 
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?
 
989
      nil
 
990
    end
 
991
    
 
992
    #Returns the window's internal ID.
 
993
    #===Return value
 
994
    #An integer describing the window's internal ID.
 
995
    #===Example
 
996
    #  p xwin.to_i #=> 29361095
 
997
    def to_i
 
998
      @id
 
999
    end
 
1000
    
 
1001
    #Returns a window's title.
 
1002
    #===Return value
 
1003
    #The window's title.
 
1004
    #===Example
 
1005
    #  p xwin.to_s #=> "xwindow.rb * SciTE"
 
1006
    def to_s
 
1007
      title
 
1008
    end
 
1009
    
 
1010
    #true if the internal ID is zero.
 
1011
    #===Return value
 
1012
    #true or false.
 
1013
    #===Example
 
1014
    #  p xwin.zero? #=> false
 
1015
    def zero?
 
1016
      @id.zero?
 
1017
    end
 
1018
    
 
1019
    #true if the internal ID is not zero.
 
1020
    #===Return value
 
1021
    #nil or the internal ID.
 
1022
    #===Example
 
1023
    #  p xwin.nonzero? #=> 29361095
 
1024
    def nonzero?
 
1025
      @id.nonzero?
 
1026
    end
 
1027
    
 
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"))
 
1031
        str
 
1032
      end
 
1033
    end
 
1034
    alias title= name=
 
1035
    alias icon_title= icon_name=
 
1036
    
 
1037
    private
 
1038
    
 
1039
    #Calls +xdotool+'s set_window command with the given options.
 
1040
    def set_window(option, value)
 
1041
      err = ""
 
1042
      Open3.popen3("#{XDOTOOL} set_window --#{option} '#{value}' #{@id}"){|stdin, stdout, stderr| err << stderr.read}
 
1043
      Kernel.raise(XDo::XError, err) unless err.empty?
 
1044
    end
 
1045
    
 
1046
  end
 
1047
  
 
1048
end