totalspaces 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Stephen Sykes
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,49 @@
1
+ = TotalSpaces - Ruby API bindings for TotalSpaces from BinaryAge
2
+
3
+ == 2013-02 At present this is pre-release, there is no public version of TotalSpaces containing the API.
4
+
5
+ This gem enables you to get information from and to control {TotalSpaces}[link:http://totalspaces.binaryage.com]
6
+
7
+ It is the officially supported way of using the API library libtotalspacesapi, and the required dylib
8
+ comes bundled with this gem. This gem uses {Ruby-FFI}[link:https://github.com/ffi/ffi] to call the functions in the dylib.
9
+
10
+ You may use this gem in various ways. For instance, you could:
11
+
12
+ * Display a message or alert when a particular space is moved to
13
+
14
+ * Automatically change the name of spaces depending on what apps are in them
15
+
16
+ * Record which spaces certain windows are on, and restoring those windows to those spaces when the owning app restarts
17
+
18
+ * Trigger moving certain windows between spaces
19
+
20
+ API support, and support for this gem starts with TotalSpaces v1.1.4. The API is a premium feature,
21
+ and will only work with registered versions of TotalSpaces.
22
+
23
+ == Download and installation
24
+
25
+ The latest version of the TotalSpaces gem can be installed with RubyGems:
26
+
27
+ % [sudo] gem install totalspaces
28
+
29
+ Source code can be downloaded on GitHub
30
+
31
+ * https://github.com/binaryage/totalspaces-api
32
+
33
+
34
+ == Documentation
35
+
36
+ * In progress
37
+
38
+ == License
39
+
40
+ The TotalSpaces gem is released under the MIT license:
41
+
42
+ * http://www.opensource.org/licenses/MIT
43
+
44
+ The source code of the dylib is not available at this time.
45
+
46
+
47
+ == Support and feature requests
48
+
49
+ * http://support.binaryage.com
@@ -0,0 +1,206 @@
1
+ //
2
+ // TSLib.h
3
+ // totalspacesapi
4
+ //
5
+ // Created by Stephen Sykes on 27/1/13.
6
+ // Copyright (c) 2013 Stephen Sykes. All rights reserved.
7
+ //
8
+ // The API is a premium feature, and will only work with registered versions of TotalSpaces.
9
+ //
10
+
11
+ #ifndef totalspacesapi_tslib
12
+ #define totalspacesapi_tslib_h
13
+
14
+ #import <Foundation/Foundation.h>
15
+
16
+ /*
17
+ * In case of comm error, all the functions apart from tsapi_libTotalSpacesVersion() will
18
+ * return an empty string, zero, false or a pointer to a struct containing zero spaces (in
19
+ * the case of tsapi_windowList).
20
+ * It is recommended to check that comms to TotalSpaces are working by, for instance,
21
+ * checking that tsapi_numberOfSpaces() returns a number greater than zero when you initialize
22
+ * your app.
23
+ */
24
+
25
+ /*
26
+ * The version of the API present in TotalSpaces.app
27
+ *
28
+ * You must call tsapi_freeString when you have finished with the returned string.
29
+ */
30
+ const char *tsapi_apiVersion();
31
+
32
+ /*
33
+ * The version number of TotalSpaces itself
34
+ *
35
+ * You must call tsapi_freeString when you have finished with the returned string.
36
+ */
37
+ const char *tsapi_totalSpacesVersion();
38
+
39
+ /*
40
+ * The version of the API dylib. This should match the string returned
41
+ * by tsapi_apiVersion()
42
+ *
43
+ * You must call tsapi_freeString when you have finished with the returned string.
44
+ */
45
+ const char *tsapi_libTotalSpacesVersion();
46
+
47
+ /*
48
+ * The number of the current space
49
+ *
50
+ * If the current space is the dashboard, 0 is returned.
51
+ */
52
+ unsigned int tsapi_currentSpaceNumber();
53
+
54
+ /*
55
+ * The name for the given space number
56
+ *
57
+ * You must call tsapi_freeString when you have finished with the returned string.
58
+ */
59
+ const char *tsapi_spaceNameForSpaceNumber(unsigned int spaceNumber);
60
+
61
+ /*
62
+ * The total number of spaces
63
+ * This includes the dashboard if you have it set as a space, and any
64
+ * fullscreen apps
65
+ */
66
+ unsigned int tsapi_numberOfSpaces();
67
+
68
+ /*
69
+ * The number of fullscreen apps
70
+ */
71
+ unsigned int tsapi_numberOfFullScreens();
72
+
73
+ /*
74
+ * The number of desktops / normal spaces
75
+ */
76
+ unsigned int tsapi_numberOfDesktops();
77
+
78
+ /*
79
+ * The number of fullscreen apps that are allowed to be present
80
+ * in the grid, defined in advanced preferences
81
+ */
82
+ unsigned int tsapi_numberOfFullScreensInGrid();
83
+
84
+ /*
85
+ * Is the dashboard set to be a space in Mission Control preferences
86
+ */
87
+ bool tsapi_dashboardIsASpace();
88
+
89
+ /*
90
+ * The number of rows defined in TotalSpaces layout preferences
91
+ */
92
+ unsigned int tsapi_definedRows();
93
+
94
+ /*
95
+ * The number of columns defined in TotalSpaces layout preferences
96
+ */
97
+ unsigned int tsapi_definedColumns();
98
+
99
+ /*
100
+ * Call this to free strings returned by the TotalSpaces API
101
+ */
102
+ void tsapi_freeString(char *str);
103
+
104
+ /*
105
+ * Switch the display to the given space
106
+ * Returns false if the space number is invalid
107
+ */
108
+ bool tsapi_moveToSpace(unsigned int spaceNumber);
109
+
110
+ /*
111
+ * Set the name of a space
112
+ * The maximum length is 255 bytes. The name should be in UTF-8
113
+ * Returns true on success, false if the name was too long or the space number was invalid
114
+ */
115
+ bool tsapi_setNameForSpace(unsigned int spaceNumber, char *name);
116
+
117
+ /*
118
+ * Type for space change callback
119
+ */
120
+ typedef void (*space_change_callback_t)(unsigned int fromSpaceNumber, unsigned int toSpaceNumber);
121
+
122
+ /*
123
+ * Set the function that will be called when the visible space changes
124
+ * There is only one callback per process, registering a new callback will supercede any previous one
125
+ */
126
+ void tsapi_setSpaceWillChangeCallback(space_change_callback_t callback);
127
+
128
+ /*
129
+ * Cancel space change callbacks
130
+ */
131
+ void tsapi_unsetSpaceWillChangeCallback();
132
+
133
+ /*
134
+ * Type for layout change callback
135
+ */
136
+ typedef void (*space_layout_changed_callback_t)(void);
137
+
138
+ /*
139
+ * Set the function that will be called when the layout changes
140
+ * This could be any change - for instance adding or removing a fullscreen, changing the name of a space,
141
+ * or a change of rows or columns.
142
+ * It indicates that you should re-request any information you are holding on the spaces
143
+ * There is only one callback per process, registering a new callback will supercede any previous one
144
+ */
145
+ void tsapi_setLayoutChangedCallback(space_layout_changed_callback_t callback);
146
+
147
+ /*
148
+ * Cancel layout change callbacks
149
+ */
150
+ void tsapi_unsetLayoutChangedCallback();
151
+
152
+ /*
153
+ * Struct containing information about a window
154
+ */
155
+ struct tsapi_window {
156
+ char *appName;
157
+ unsigned int windowId;
158
+ bool isOnAllSpaces;
159
+ char *title;
160
+ char *frame;
161
+ };
162
+
163
+ /*
164
+ * Struct containing information about a space
165
+ * Contains a pointer to an array of tsapi_window structs
166
+ */
167
+ struct tsapi_space {
168
+ unsigned int spaceNumber;
169
+ unsigned int windowCount;
170
+ struct tsapi_window *windows;
171
+ };
172
+
173
+ /*
174
+ * Struct containing the count of spaces and a pointer to an
175
+ * array of tsapi_space structs
176
+ */
177
+ struct tsapi_spaces {
178
+ unsigned int spacesCount;
179
+ struct tsapi_space *spaces;
180
+ };
181
+
182
+ /*
183
+ * Return a pointer to a tsapi_spaces struct containing information about all the windows
184
+ * in all spaces
185
+ *
186
+ * The windows are listed front to back, so the first widow in the array is the frontmost
187
+ *
188
+ * You must call tsapi_freeWindowList when you have finished with this
189
+ */
190
+ struct tsapi_spaces *tsapi_windowList();
191
+
192
+ /*
193
+ * Free a previously returned spaceWindowsArray struct
194
+ */
195
+ void tsapi_freeWindowList(struct tsapi_spaces *windowList);
196
+
197
+ /*
198
+ * Move a window to a different space
199
+ * The windowId must be one that has been returned in a tsapi_window struct
200
+ *
201
+ * Returns true on success, false if the windowId or spaceNumber was invalid
202
+ */
203
+ bool tsapi_moveWindowToSpace(unsigned int windowId, unsigned int spaceNumber);
204
+
205
+ #endif
206
+
@@ -0,0 +1,318 @@
1
+ # TotalSpaces - control TotalSpaces from Ruby
2
+ # This gem provides a number of ways to control TotalSpaces. It is intended to be used
3
+ # to add functionality to TotalSpaces, or to use your spaces and desktops in
4
+ # creative ways.
5
+ #
6
+ # === Examples
7
+ # require 'totalspaces'
8
+ #
9
+ # TotalSpaces.on_space_change {|from, to| puts "Moving from space #{from} to space #{to}";}
10
+ #
11
+ # TotalSpaces.move_to_space(1)
12
+ #
13
+ # current_space = TotalSpaces.current_space
14
+ # puts "Current space number: #{current_space}"
15
+ # puts "Current space is called: #{TotalSpaces.name_for_space(current_space)}"
16
+ #
17
+ # TotalSpaces.set_name_for_space(1, "Home")
18
+ #
19
+
20
+ require 'ffi'
21
+
22
+ module TSApi #:nodoc:
23
+ extend FFI::Library
24
+ ffi_lib File.join(File.dirname(__FILE__), "libtotalspacesapi.dylib")
25
+
26
+ attach_function :tsapi_freeString, [:pointer], :void
27
+
28
+ attach_function :tsapi_libTotalSpacesVersion, [], :pointer
29
+ attach_function :tsapi_apiVersion, [], :pointer
30
+ attach_function :tsapi_totalSpacesVersion, [], :pointer
31
+
32
+ attach_function :tsapi_currentSpaceNumber, [], :uint
33
+ attach_function :tsapi_spaceNameForSpaceNumber, [:uint], :pointer
34
+ attach_function :tsapi_numberOfSpaces, [], :uint
35
+ attach_function :tsapi_numberOfFullScreens, [], :uint
36
+ attach_function :tsapi_numberOfFullScreensInGrid, [], :uint
37
+ attach_function :tsapi_numberOfDesktops, [], :uint
38
+ attach_function :tsapi_dashboardIsASpace, [], :bool
39
+ attach_function :tsapi_definedRows, [], :uint
40
+ attach_function :tsapi_definedColumns, [], :uint
41
+
42
+ attach_function :tsapi_moveToSpace, [:uint], :bool
43
+ attach_function :tsapi_setNameForSpace, [:uint, :string], :bool
44
+
45
+ callback :space_change_function, [:uint, :uint], :void
46
+ attach_function :tsapi_setSpaceWillChangeCallback, [:space_change_function], :void
47
+ attach_function :tsapi_unsetSpaceWillChangeCallback, [], :void
48
+
49
+ callback :layout_changed_function, [], :void
50
+ attach_function :tsapi_setLayoutChangedCallback, [:layout_changed_function], :void
51
+ attach_function :tsapi_unsetLayoutChangedCallback, [], :void
52
+
53
+ attach_function :tsapi_windowList, [], :pointer
54
+ attach_function :tsapi_freeWindowList, [:pointer], :void
55
+
56
+ attach_function :tsapi_moveWindowToSpace, [:uint, :uint], :bool
57
+ end
58
+
59
+ module TotalSpaces
60
+
61
+ #--
62
+ # See tslib.h for the structures returned by the C API
63
+ #++
64
+
65
+ class Spaces < FFI::Struct #:nodoc:
66
+ layout :count, :uint,
67
+ :windows_arrays, :pointer
68
+ end
69
+
70
+ class Space < FFI::Struct #:nodoc:
71
+ layout :space_number, :uint,
72
+ :count, :uint,
73
+ :windows_array, :pointer
74
+ end
75
+
76
+ class Window < FFI::Struct #:nodoc:
77
+ layout :app_name, :string,
78
+ :window_id, :uint,
79
+ :is_on_all_spaces, :bool,
80
+ :title, :string,
81
+ :frame, :string
82
+ end
83
+
84
+ class << self
85
+ private
86
+ def string_and_free(cstr_pointer) #:nodoc:
87
+ str = cstr_pointer.get_string(0)
88
+ TSApi.tsapi_freeString(cstr_pointer)
89
+ str
90
+ end
91
+
92
+ public
93
+
94
+ # Returns the version of the dylib, a string such as "1.0"
95
+ # You should be using the same dylib version as that returned by the api_version call
96
+ #
97
+ # puts "libTotalSpaces version: #{TotalSpaces.lib_total_spaces_version}"
98
+ #
99
+ def lib_total_spaces_version
100
+ string_and_free(TSApi.tsapi_libTotalSpacesVersion)
101
+ end
102
+
103
+ # Returns the version of the api present in TotalSpaces, a string such as "1.0"
104
+ # You should be using the same dylib version as that returned by the this call
105
+ #
106
+ # puts "TotalSpaces API version: #{TotalSpaces.api_version}"
107
+ #
108
+ def api_version
109
+ string_and_free(TSApi.tsapi_apiVersion)
110
+ end
111
+
112
+ # Returns the version of TotalSpaces running on the system, a string such as "1.1.4"
113
+ #
114
+ # puts "TotalSpaces version: #{TotalSpaces.total_spaces_version}"
115
+ #
116
+ def total_spaces_version
117
+ string_and_free(TSApi.tsapi_totalSpacesVersion)
118
+ end
119
+
120
+ # Returns the number of the current space. Numbering starts at 1, except if you have
121
+ # the Dashboard enabled as a space, in which case the Dashboard counts as space 0
122
+ #
123
+ # puts "Current space number: #{TotalSpaces.current_space}"
124
+ #
125
+ def current_space
126
+ TSApi.tsapi_currentSpaceNumber
127
+ end
128
+
129
+ # Returns the name for a space. The returned string will be empty if the space number is
130
+ # not valid
131
+ #
132
+ # current_space = TotalSpaces.current_space
133
+ # puts "Current space is called: #{TotalSpaces.name_for_space(current_space)}"
134
+ #
135
+ def name_for_space(space_number)
136
+ name = string_and_free(TSApi.tsapi_spaceNameForSpaceNumber(space_number))
137
+ name.force_encoding("UTF-8")
138
+ end
139
+
140
+ # Returns the total number of spaces including fullscreens, dashboard (if it's a space),
141
+ # and spaces that are unused in the grid
142
+ #
143
+ # puts "Total number of spaces: #{TotalSpaces.number_of_spaces}"
144
+ #
145
+ def number_of_spaces
146
+ TSApi.tsapi_numberOfSpaces
147
+ end
148
+
149
+ # Returns the number of fullscreen apps present
150
+ #
151
+ # puts "Number of fullscreens: #{TotalSpaces.number_of_fullscreens}"
152
+ #
153
+ def number_of_fullscreens
154
+ TSApi.tsapi_numberOfFullScreens
155
+ end
156
+
157
+ # Returns the number of fullscreen apps tht are defined in the grid - this can be defined
158
+ # in Advanced preferences in TotalSpaces.
159
+ # The return value does not depend on how many fullscreens actually exist in the grid - the
160
+ # value is the definition only, there could be fewer than this actually present.
161
+ #
162
+ # puts "Number of fullscreens in the grid: #{TotalSpaces.number_of_fullscreens_in_grid}"
163
+ #
164
+ def number_of_fullscreens_in_grid
165
+ TSApi.tsapi_numberOfFullScreensInGrid
166
+ end
167
+
168
+ # Returns the number of desktops that are present in the system. This may be a bigger number
169
+ # that the rows x columns in the grid if more desktops have been created in Mission Control.
170
+ #
171
+ # puts "Number of desktops: #{TotalSpaces.number_of_desktops}"
172
+ #
173
+ def number_of_desktops
174
+ TSApi.tsapi_numberOfDesktops
175
+ end
176
+
177
+ # Returns true if the dashboard is configured to appear as a space in Mission Control preferences.
178
+ #
179
+ # puts "Dashboard is a space: #{TotalSpaces.dashboard_is_a_space?}"
180
+ #
181
+ def dashboard_is_a_space?
182
+ TSApi.tsapi_dashboardIsASpace
183
+ end
184
+
185
+ # Returns the number of rows defined in TotalSpaces
186
+ #
187
+ # puts "Number of rows: #{TotalSpaces.grid_rows}"
188
+ #
189
+ def grid_rows
190
+ TSApi.tsapi_definedRows
191
+ end
192
+
193
+ # Returns the number of columns defined in TotalSpaces
194
+ #
195
+ # puts "Number of columns: #{TotalSpaces.grid_columns}"
196
+ #
197
+ def grid_columns
198
+ TSApi.tsapi_definedColumns
199
+ end
200
+
201
+ # Command TotalSpaces to switch to the given space number
202
+ # Returns false if the space number was invalid
203
+ # The on_space_change notification will be sent
204
+ #
205
+ # TotalSpaces.move_to_space(1)
206
+ #
207
+ def move_to_space(space_number)
208
+ TSApi.tsapi_moveToSpace(space_number)
209
+ end
210
+
211
+ # Set the name for a space
212
+ # Note that using this command will cause a layout notification to be sent
213
+ # if the new name was different from that previously set
214
+ # The maximum length for a name is 255 bytes
215
+ #
216
+ # TotalSpaces.set_name_for_space(1, "Home")
217
+ #
218
+ def set_name_for_space(space_number, name)
219
+ TSApi.tsapi_setNameForSpace(space_number, name)
220
+ end
221
+
222
+ # Register for notifications on space change
223
+ # The given block will be called whenever you move from one space to another. The arguments are
224
+ # the space number you moved from, and the one you are moving to
225
+ #
226
+ # TotalSpaces.on_space_change {|from, to| puts "Moving from space #{from} to space #{to}";}
227
+ #
228
+ # There can only be one block registered at any time, the most recently registered one will
229
+ # be called.
230
+ #
231
+ def on_space_change(&block)
232
+ $tsapi_on_space_change_block = block # prevent CG
233
+ TSApi.tsapi_setSpaceWillChangeCallback(block)
234
+ end
235
+
236
+ # Cancel the on_space_change notification
237
+ #
238
+ def cancel_on_space_change
239
+ $tsapi_on_space_change_block = nil
240
+ TSApi.tsapi_unsetSpaceWillChangeCallback
241
+ end
242
+
243
+ # Register for notifications on layout change
244
+ # The given block will be called whenever the layout changes - this could be due to making an app
245
+ # fullscreen, changing a space name, or changing the layout of the TotalSpaces grid. There are no
246
+ # arguments passed to the block.
247
+ #
248
+ # TotalSpaces.on_layout_change {puts "Spaces changed"}
249
+ #
250
+ # When you get a notification from this method, you should re-fetch any information about the spaces
251
+ # that you may be storing.
252
+ #
253
+ # There can only be one block registered at any time, the most recently registered one will
254
+ # be called.
255
+ #
256
+ def on_layout_change(&block)
257
+ $tsapi_on_layout_change_block = block # prevent CG
258
+ TSApi.tsapi_setLayoutChangedCallback(block)
259
+ end
260
+
261
+ # Cancel the layout change notification
262
+ #
263
+ def cancel_on_layout_change
264
+ $tsapi_on_layout_change_block = nil
265
+ TSApi.tsapi_unsetLayoutChangedCallback
266
+ end
267
+
268
+ # Get a list of all the windows on your mac
269
+ # It returns an array containing a hash for each space.
270
+ # The hash contains the space number (key :space_number) and an array of hashes, one
271
+ # for each window (key :windows). The windows are in front to back order.
272
+ # Each window hash contains a window_id, title, frame, app_name and is_on_all_spaces flag
273
+ #
274
+ # The below example would move the frontmost window to the next space to the right.
275
+ #
276
+ # windows = TotalSpaces.window_list
277
+ # if !windows.empty?
278
+ # current_space_windows = windows[TotalSpaces.current_space - 1]
279
+ # front_window = current_space_windows[:windows][0]
280
+ # TotalSpaces.move_window_to_space(front_window[:window_id], TotalSpaces.current_space + 1)
281
+ # end
282
+ #
283
+ end
284
+ def window_list
285
+ result = []
286
+ list = TSApi.tsapi_windowList
287
+ main_array = Spaces.new(list)
288
+
289
+ (0...main_array[:count]).each do |n|
290
+ result[n] = {}
291
+ windows_array = Space.new(main_array[:windows_arrays] + n * Space.size)
292
+ result[n][:space_number] = windows_array[:space_number]
293
+ result[n][:windows] = []
294
+ (0...windows_array[:count]).each do |m|
295
+ window_hash = result[n][:windows][m] = {}
296
+ window = Window.new(windows_array[:windows_array] + m * Window.size)
297
+ window_hash[:window_id] = window[:window_id]
298
+ window_hash[:title] = window[:title].dup.force_encoding("UTF-8")
299
+ window_hash[:frame] = window[:frame].dup.force_encoding("UTF-8")
300
+ window_hash[:is_on_all_spaces] = window[:is_on_all_spaces]
301
+ window_hash[:app_name] = window[:app_name].dup.force_encoding("UTF-8")
302
+ end
303
+ end
304
+
305
+ TSApi.tsapi_freeWindowList(list)
306
+
307
+ result
308
+ end
309
+
310
+ # Move a window to a given space
311
+ # The window_id parameter must be fetched using window_list.
312
+ # Returns false if the space_number or window_id is invalid.
313
+ #
314
+ def move_window_to_space(window_id, space_number)
315
+ TSApi.tsapi_moveWindowToSpace(window_id, space_number)
316
+ end
317
+ end
318
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: totalspaces
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Stephen Sykes
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ffi
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.0.11
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.0.11
30
+ description: This allows you to control the TotalSpaces desktop manager for mac from
31
+ ruby.
32
+ email: stephen@binaryage.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - README.rdoc
38
+ - MIT_LICENCE
39
+ - lib/totalspaces.rb
40
+ - lib/libtotalspacesapi.dylib
41
+ - lib/TSLib.h
42
+ homepage: http://github.com/binaryage/totalspaces-api
43
+ licenses: []
44
+ post_install_message:
45
+ rdoc_options:
46
+ - --charset=UTF-8
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubyforge_project:
63
+ rubygems_version: 1.8.23
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: TotalSpaces control from ruby
67
+ test_files: []