totalspaces2 2.0

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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a133c5d3f23844aa9ca70332146796499c6e3b9e
4
+ data.tar.gz: 342ceaf3ec96f133b4e6b0a06e8f1a7400c24a4c
5
+ SHA512:
6
+ metadata.gz: 4455a450a3c33fa50fce7162d9ebca2285fcb10d1828132cdbbf99d9aa2c36f02f6e01d354a0efd6f58f89bb749429e35b400e7ad48ec1dedb79d8cac14d7ac6
7
+ data.tar.gz: 2f025c0a21fc74d0f166ed95d7cb0bab5c0d1ec955a7ce743a0e5893267353f7e0d01a31446d36c3f232bd73fec51bd785dc48f0aefe66ee073759f479d70408
@@ -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,65 @@
1
+ = TotalSpaces2 - Ruby API bindings for TotalSpaces2 from BinaryAge
2
+
3
+ == PRERELEASE: You will be able to use the API with versions 2.1 and above of totalspaces.
4
+
5
+ This gem enables you to get information from and to control {TotalSpaces2}[link:http://totalspaces.binaryage.com]
6
+
7
+ It is the officially supported way of using the API library libtotalspaces2api, 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
+ You'll need a sane ruby and compilation environment to install ruby-ffi - it probably won't install immediately with the
10
+ ruby that comes with Mavericks because none of the compilation tools are present. We use {homebrew}[link:http://mxcl.github.com/homebrew/]
11
+ and {rbenv}[link:https://github.com/sstephenson/rbenv/] to manage our ruby scripting environment.
12
+
13
+ You may use this gem in various ways. For instance, you could:
14
+
15
+ * Display a message or alert when a particular space is moved to
16
+
17
+ * Automatically change the name of spaces depending on what apps are in them
18
+
19
+ * Record which spaces certain windows are on, and restoring those windows to those spaces when the owning app restarts
20
+
21
+ * Trigger moving certain windows between spaces
22
+
23
+ API support, and support for this gem starts with TotalSpaces2 v2.0.12 The API is a premium feature,
24
+ and will only work with registered versions of TotalSpaces2.
25
+
26
+ == Download and installation
27
+
28
+ The latest version of the TotalSpaces2 gem can be installed with RubyGems:
29
+
30
+ % [sudo] gem install totalspaces2
31
+
32
+ Source code can be downloaded on GitHub
33
+
34
+ * https://github.com/binaryage/totalspaces2-api
35
+
36
+
37
+ == Documentation
38
+
39
+ {module TotalSpaces2}[link:http://binaryage.github.io/totalspaces2-api/ruby/rdoc/TotalSpaces2.html]
40
+
41
+ == Examples
42
+ require 'totalspaces2'
43
+
44
+ TotalSpaces2.on_space_change {|from, to, display_id| puts "Moving from space #{from} to space #{to}";}
45
+
46
+ TotalSpaces2.move_to_space(1)
47
+
48
+ current_space = TotalSpaces2.current_space
49
+ puts "Current space number: #{current_space}"
50
+ puts "Current space is called: #{TotalSpaces2.name_for_space(current_space)}"
51
+
52
+ TotalSpaces2.set_name_for_space(1, "Home")
53
+
54
+ == License
55
+
56
+ The TotalSpaces2 gem is released under the MIT license:
57
+
58
+ * http://www.opensource.org/licenses/MIT
59
+
60
+ The source code of the dylib is not available at this time.
61
+
62
+
63
+ == Support and feature requests
64
+
65
+ * http://discuss.binaryage.com
@@ -0,0 +1,256 @@
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
+ #define TSAPI_MAX_SPACES 32
17
+
18
+ /*
19
+ * In case of comm error, all the functions apart from tsapi_libTotalSpacesVersion() will
20
+ * return an empty string, zero, false or a pointer to a struct containing zero spaces (in
21
+ * the case of tsapi_windowList).
22
+ * It is recommended to check that comms to TotalSpaces are working by, for instance,
23
+ * checking that tsapi_apiVersion() matches tsapi_libTotalSpacesVersion() when you initialize
24
+ * your app.
25
+ *
26
+ * Some actions such as renaming a space will cause the overview grid to be exited if it
27
+ * is showing at the time.
28
+ */
29
+
30
+ /*
31
+ * The version of the API present in TotalSpaces.app.
32
+ *
33
+ * You must call tsapi_freeString when you have finished with the returned string.
34
+ */
35
+ const char *tsapi_apiVersion();
36
+
37
+ /*
38
+ * The version number of TotalSpaces itself.
39
+ *
40
+ * You must call tsapi_freeString when you have finished with the returned string.
41
+ */
42
+ const char *tsapi_totalSpacesVersion();
43
+
44
+ /*
45
+ * The version of the API dylib. This should match the string returned
46
+ * by tsapi_apiVersion().
47
+ *
48
+ * You must call tsapi_freeString when you have finished with the returned string.
49
+ */
50
+ const char *tsapi_libTotalSpacesVersion();
51
+
52
+ /*
53
+ * Struct containing info about a display.
54
+ */
55
+ struct tsapi_display {
56
+ CGDirectDisplayID displayId;
57
+ char *displayName;
58
+ size_t width;
59
+ size_t height;
60
+ };
61
+
62
+ /*
63
+ * Struct containing the count of spaces and a pointer to an
64
+ * array of CGDirectDisplayIDs.
65
+ */
66
+ struct tsapi_displays {
67
+ unsigned int displaysCount;
68
+ struct tsapi_display *displays;
69
+ };
70
+
71
+ /*
72
+ * Return a pointer to a tsapi_displays struct containing information about all the displays.
73
+ *
74
+ * The first display in the list will be the main display. The main display is the display
75
+ * with its screen location at (0,0) in the global display coordinate space. In a system
76
+ * without display mirroring, the display with the menu bar is typically the main display.
77
+ *
78
+ * You must call tsapi_freeDisplayList when you have finished with this.
79
+ */
80
+ struct tsapi_displays *tsapi_displayList();
81
+
82
+ /*
83
+ * Free a previously returned tsapi_displays struct
84
+ */
85
+ void tsapi_freeDisplayList(struct tsapi_displays *displayList);
86
+
87
+ /*
88
+ * The number of the current space.
89
+ *
90
+ * If the current space is the dashboard, 0 is returned.
91
+ */
92
+ unsigned int tsapi_currentSpaceNumberOnDisplay(CGDirectDisplayID displayID);
93
+
94
+ /*
95
+ * The name for the given space number.
96
+ *
97
+ * You must call tsapi_freeString when you have finished with the returned string.
98
+ */
99
+ const char *tsapi_spaceNameForSpaceNumberOnDisplay(unsigned int spaceNumber, CGDirectDisplayID displayID);
100
+
101
+ /*
102
+ * The total number of spaces.
103
+ * This includes the dashboard if you have it set as a space, and any
104
+ * fullscreen apps.
105
+ */
106
+ unsigned int tsapi_numberOfSpacesOnDisplay(CGDirectDisplayID displayID);
107
+
108
+ /*
109
+ * The number of columns defined in TotalSpaces layout preferences.
110
+ */
111
+ unsigned int tsapi_definedColumnsOnDisplay(CGDirectDisplayID displayID);
112
+
113
+ /*
114
+ * Sets the number of columns in the TotalSpaces grid.
115
+ * Returns true on success, false if the new grid would exceed TSAPI_MAX_SPACES
116
+ * or if columns is zero.
117
+ * Note that the actual number of desktops present in the system is unchanged,
118
+ * you should call tsapi_addDesktops or tsapi_removeDesktops after calling this
119
+ * function.
120
+ */
121
+ bool tsapi_setDefinedColumnsOnDisplay(unsigned int columns, CGDirectDisplayID displayID);
122
+
123
+ /*
124
+ * Call this to free strings returned by the TotalSpaces API.
125
+ */
126
+ void tsapi_freeString(char *str);
127
+
128
+ /*
129
+ * Switch the display to the given space.
130
+ * Returns false if the space number is invalid.
131
+ */
132
+ bool tsapi_moveToSpaceOnDisplay(unsigned int spaceNumber, CGDirectDisplayID displayID);
133
+
134
+ /*
135
+ * Set the name of a space.
136
+ * The maximum length is 255 bytes. The name should be in UTF-8.
137
+ * Returns true on success, false if the name was too long or the space number was invalid.
138
+ */
139
+ bool tsapi_setNameForSpaceOnDisplay(unsigned int spaceNumber, char *name, CGDirectDisplayID displayID);
140
+
141
+ /*
142
+ * Type for space change callback.
143
+ */
144
+ typedef void (*space_change_callback_t)(unsigned int fromSpaceNumber, unsigned int toSpaceNumber, CGDirectDisplayID displayID);
145
+
146
+ /*
147
+ * Set the function that will be called when the visible space changes.
148
+ * There is only one callback per process, registering a new callback will supercede any previous one.
149
+ */
150
+ void tsapi_setSpaceWillChangeCallback(space_change_callback_t callback);
151
+
152
+ /*
153
+ * Cancel space change callbacks
154
+ */
155
+ void tsapi_unsetSpaceWillChangeCallback();
156
+
157
+ /*
158
+ * Type for layout change callback
159
+ */
160
+ typedef void (*space_layout_changed_callback_t)(void);
161
+
162
+ /*
163
+ * Set the function that will be called when the layout changes.
164
+ * This could be any change - for instance adding or removing a fullscreen, changing the name of a space,
165
+ * or a change of rows or columns.
166
+ * It indicates that you should re-request any information you are holding on the spaces.
167
+ * There is only one callback per process, registering a new callback will supercede any previous one.
168
+ */
169
+ void tsapi_setLayoutChangedCallback(space_layout_changed_callback_t callback);
170
+
171
+ /*
172
+ * Cancel layout change callbacks.
173
+ */
174
+ void tsapi_unsetLayoutChangedCallback();
175
+
176
+ /*
177
+ * Struct containing information about a window.
178
+ */
179
+ struct tsapi_window {
180
+ char *appName;
181
+ unsigned int windowId;
182
+ bool isOnAllSpaces;
183
+ char *title;
184
+ char *frame;
185
+ CGDirectDisplayID displayID;
186
+ unsigned int spaceNumber;
187
+ };
188
+
189
+ /*
190
+ * Struct containing information about windows.
191
+ * Contains a pointer to an array of tsapi_window structs.
192
+ */
193
+ struct tsapi_windows {
194
+ unsigned int windowCount;
195
+ struct tsapi_window *windows;
196
+ };
197
+
198
+ /*
199
+ * Return a pointer to a tsapi_windows struct containing information about all the windows
200
+ * in all spaces.
201
+ *
202
+ * The windows are listed in space order for each display, and within each space
203
+ * the windows are listed front to back, so earlier windows in the array are frontmost.
204
+ *
205
+ * You must call tsapi_freeWindowList when you have finished with this.
206
+ */
207
+ struct tsapi_windows *tsapi_windowList();
208
+
209
+ /*
210
+ * Free a previously returned tsapi_spaces struct
211
+ */
212
+ void tsapi_freeWindowList(struct tsapi_windows *windowList);
213
+
214
+ /*
215
+ * Move a window to a different space
216
+ * The windowId must be one that has been returned in a tsapi_window struct
217
+ *
218
+ * Returns true on success, false if the windowID or spaceNumber was invalid
219
+ */
220
+ bool tsapi_moveWindowToSpaceOnDisplay(unsigned int windowID, unsigned int spaceNumber, CGDirectDisplayID displayID);
221
+
222
+ /*
223
+ * Move a space to another position
224
+ * You cannot move space 1 when displays have separate spaces is turned off.
225
+ *
226
+ * Returns true on success, false if the spaceNumber or positionNumber was
227
+ * invalid
228
+ */
229
+ bool tsapi_moveSpaceToPositionOnDisplay(unsigned int spaceNumber, unsigned int positionNumber, CGDirectDisplayID displayID);
230
+
231
+ /*
232
+ * Add desktops
233
+ * There can usually be at most 16 desktops, unless desktops have migrated
234
+ * from another monitor.
235
+ *
236
+ * Returns the number of desktops actually added.
237
+ */
238
+ unsigned int tsapi_addDesktopsOnDisplay(unsigned int numberToAdd, CGDirectDisplayID displayID);
239
+
240
+ /*
241
+ * Remove desktops
242
+ * Removes numberToRemove desktops. The highest numbered desktops are removed.
243
+ *
244
+ * Removing a desktop you are currently on will result in TotalSpaces switching to
245
+ * another dektop.
246
+ *
247
+ * Any windows present on a desktop being removed will be moved to one of the
248
+ * remaining desktops.
249
+ *
250
+ * Returns true on success, false if numberToRemove was zero or would result in less
251
+ * than 1 desktop remaining.
252
+ */
253
+ bool tsapi_removeDesktopsOnDisplay(unsigned int numberToRemove, CGDirectDisplayID displayID);
254
+
255
+ #endif
256
+
@@ -0,0 +1,575 @@
1
+ # = TotalSpaces2 - Ruby API bindings for TotalSpaces2 from BinaryAge
2
+ #
3
+ # This gem enables you to get information from and to control {TotalSpaces2}[link:http://totalspaces.binaryage.com]
4
+ #
5
+ # It is the officially supported way of using the API library libtotalspaces2api, and the required dylib
6
+ # comes bundled with this gem. This gem uses {Ruby-FFI}[link:https://github.com/ffi/ffi] to call the functions in the dylib.
7
+ # You'll need a sane ruby and compilation environment to install ruby-ffi - it probably won't install immediately with the
8
+ # ruby that comes with OSX because none of the compilation tools are present. We use {homebrew}[link:http://mxcl.github.com/homebrew/]
9
+ # and {rbenv}[link:https://github.com/sstephenson/rbenv/] to manage our ruby scripting environment.
10
+ #
11
+ # You may use this gem in various ways. For instance, you could:
12
+ #
13
+ # * Display a message or alert when a particular space is moved to
14
+ #
15
+ # * Automatically change the name of spaces depending on what apps are in them
16
+ #
17
+ # * Record which spaces certain windows are on, and restoring those windows to those spaces when the owning app restarts
18
+ #
19
+ # * Trigger moving certain windows between spaces
20
+ #
21
+ # API support, and support for this gem starts with TotalSpaces2 v2.1.0. The API is a premium feature,
22
+ # and will only work with registered versions of TotalSpaces2.
23
+ #
24
+ # == Download and installation
25
+ #
26
+ # The latest version of the TotalSpaces2 gem can be installed with RubyGems:
27
+ #
28
+ # % [sudo] gem install totalspaces2
29
+ #
30
+ # Source code can be downloaded on GitHub
31
+ #
32
+ # * https://github.com/binaryage/totalspaces2-api
33
+ #
34
+ #
35
+ # == Documentation
36
+ #
37
+ # * http://binaryage.github.io/totalspaces2-api/ruby/rdoc/TotalSpaces2.html
38
+ #
39
+ # == License
40
+ #
41
+ # The TotalSpaces gem is released under the MIT license:
42
+ #
43
+ # * http://www.opensource.org/licenses/MIT
44
+ #
45
+ # The source code of the dylib is not available at this time.
46
+ #
47
+ #
48
+ # == Support and feature requests
49
+ #
50
+ # * http://discuss.binaryage.com
51
+ #
52
+ #
53
+ # == Examples
54
+ # require 'totalspaces2'
55
+ #
56
+ # TotalSpaces2.on_space_change {|from, to, display_id| puts "Moving from space #{from} to space #{to}";}
57
+ #
58
+ # TotalSpaces2.move_to_space(1)
59
+ #
60
+ # current_space = TotalSpaces2.current_space
61
+ # puts "Current space number: #{current_space}"
62
+ # puts "Current space is called: #{TotalSpaces2.name_for_space(current_space)}"
63
+ #
64
+ # TotalSpaces2.set_name_for_space(1, "Home")
65
+ #
66
+
67
+ require 'ffi'
68
+
69
+ module TSApi #:nodoc:
70
+ extend FFI::Library
71
+ ffi_lib File.join(File.dirname(__FILE__), "libtotalspaces2api.dylib")
72
+
73
+ attach_function :tsapi_freeString, [:pointer], :void
74
+
75
+ attach_function :tsapi_libTotalSpacesVersion, [], :pointer
76
+ attach_function :tsapi_apiVersion, [], :pointer
77
+ attach_function :tsapi_totalSpacesVersion, [], :pointer
78
+
79
+ attach_function :tsapi_displayList, [], :pointer
80
+ attach_function :tsapi_freeDisplayList, [:pointer], :void
81
+
82
+ attach_function :tsapi_currentSpaceNumberOnDisplay, [:uint], :uint
83
+ attach_function :tsapi_spaceNameForSpaceNumberOnDisplay, [:uint, :uint], :pointer
84
+ attach_function :tsapi_numberOfSpacesOnDisplay, [:uint], :uint
85
+
86
+ attach_function :tsapi_definedColumnsOnDisplay, [:uint], :uint
87
+
88
+ attach_function :tsapi_setDefinedColumnsOnDisplay, [:uint, :uint], :bool
89
+
90
+ attach_function :tsapi_moveToSpaceOnDisplay, [:uint, :uint], :bool
91
+ attach_function :tsapi_setNameForSpaceOnDisplay, [:uint, :string, :uint], :bool
92
+
93
+ callback :space_change_function, [:uint, :uint, :uint], :void
94
+ attach_function :tsapi_setSpaceWillChangeCallback, [:space_change_function], :void
95
+ attach_function :tsapi_unsetSpaceWillChangeCallback, [], :void
96
+
97
+ callback :layout_changed_function, [], :void
98
+ attach_function :tsapi_setLayoutChangedCallback, [:layout_changed_function], :void
99
+ attach_function :tsapi_unsetLayoutChangedCallback, [], :void
100
+
101
+ attach_function :tsapi_windowList, [], :pointer
102
+ attach_function :tsapi_freeWindowList, [:pointer], :void
103
+
104
+ attach_function :tsapi_moveWindowToSpaceOnDisplay, [:uint, :uint, :uint], :bool
105
+
106
+ attach_function :tsapi_moveSpaceToPositionOnDisplay, [:uint, :uint, :uint], :bool
107
+
108
+ attach_function :tsapi_addDesktopsOnDisplay, [:uint, :uint], :uint
109
+ attach_function :tsapi_removeDesktopsOnDisplay, [:uint, :uint], :bool
110
+ end
111
+
112
+ module TotalSpaces2
113
+
114
+ MAX_DESKTOPS = 16
115
+
116
+ #--
117
+ # See TSLib.h for the structures returned by the C API
118
+ #++
119
+
120
+ class Display < FFI::Struct #:nodoc:
121
+ layout :displayID, :uint32,
122
+ :display_name, :string,
123
+ :width, :size_t,
124
+ :height, :size_t
125
+ end
126
+
127
+ class Displays < FFI::Struct #:nodoc:
128
+ layout :count, :uint,
129
+ :displays_array, :pointer
130
+
131
+ def display_info
132
+ displays = []
133
+ displays_array = self[:displays_array]
134
+ (0...self[:count]).each do |n|
135
+ display = Display.new(displays_array + n * Display.size)
136
+ info = {
137
+ display_id: display[:displayID],
138
+ display_name: display[:display_name],
139
+ width: display[:width],
140
+ height: display[:height]
141
+ }
142
+ displays << info
143
+ end
144
+
145
+ displays
146
+ end
147
+ end
148
+
149
+ class Windows < FFI::Struct #:nodoc:
150
+ layout :count, :uint,
151
+ :windows_array, :pointer
152
+ end
153
+
154
+ class Window < FFI::Struct #:nodoc:
155
+ layout :app_name, :string,
156
+ :window_id, :uint,
157
+ :is_on_all_spaces, :bool,
158
+ :title, :string,
159
+ :frame, :string,
160
+ :display_id, :uint,
161
+ :space_number, :uint
162
+ end
163
+
164
+ class << self
165
+ private
166
+ def string_and_free(cstr_pointer) #:nodoc:
167
+ str = cstr_pointer.get_string(0)
168
+ TSApi.tsapi_freeString(cstr_pointer)
169
+ str
170
+ end
171
+
172
+ public
173
+
174
+ # Returns the version of the dylib, a string such as "1.0"
175
+ # You should be using the same dylib major version number as that returned by the api_version call
176
+ #
177
+ # puts "libTotalSpaces2 version: #{TotalSpaces2.lib_total_spaces_version}"
178
+ #
179
+ # if TotalSpaces2.lib_total_spaces_version.split('.')[0] != TotalSpaces2.api_version.split('.')[0]
180
+ # puts "Comms error!"
181
+ # exit(1)
182
+ # end
183
+ #
184
+ #
185
+ def lib_total_spaces_version
186
+ string_and_free(TSApi.tsapi_libTotalSpacesVersion)
187
+ end
188
+
189
+ # Returns the version of the api present in TotalSpaces2, a string such as "1.0"
190
+ # You should be using the same dylib version as that returned by the this call
191
+ #
192
+ # puts "TotalSpaces2 API version: #{TotalSpaces2.api_version}"
193
+ #
194
+ # if TotalSpaces2.lib_total_spaces_version.split('.')[0] != TotalSpaces2.api_version.split('.')[0]
195
+ # puts "Comms error!"
196
+ # exit(1)
197
+ # end
198
+ #
199
+ def api_version
200
+ string_and_free(TSApi.tsapi_apiVersion)
201
+ end
202
+
203
+ # Returns the version of TotalSpaces2 running on the system, a string such as "2.0.12"
204
+ #
205
+ # puts "TotalSpaces2 version: #{TotalSpaces2.total_spaces_version}"
206
+ #
207
+ def total_spaces_version
208
+ string_and_free(TSApi.tsapi_totalSpacesVersion)
209
+ end
210
+
211
+ # Returns an array of hashes with information about attached displays. The ids returned
212
+ # from this call can be used where a display id is required in the other calls in this library.
213
+ #
214
+ # puts "Attached displays: #{TotalSpaces2.display_list}"
215
+ #
216
+ # [{:display_id=>69679040, :display_name=>"Color LCD", :width=>1440, :height=>900},
217
+ # {:display_id=>69514913, :display_name=>"LED Cinema Display", :width=>2560, :height=>1440}]
218
+ #
219
+ def display_list
220
+ list = TSApi.tsapi_displayList
221
+ displays = Displays.new(list)
222
+ result = displays.null? ? [] : displays.display_info
223
+ TSApi.tsapi_freeDisplayList(list)
224
+ result
225
+ end
226
+
227
+ # Returns information about the main display.
228
+ # Methods that do not take a display id always operate on this display.
229
+ #
230
+ # puts "Main display id: #{TotalSpaces2.main_display_id}"
231
+ #
232
+ # {:display_id=>69679040, :display_name=>"Color LCD", :width=>1440, :height=>900}
233
+ #
234
+ def main_display
235
+ self.display_list[0]
236
+ end
237
+
238
+ # Returns the number of the current space on the main display. Numbering starts at 1.
239
+ #
240
+ # puts "Current space number: #{TotalSpaces2.current_space}"
241
+ #
242
+ def current_space
243
+ TSApi.tsapi_currentSpaceNumberOnDisplay(0)
244
+ end
245
+
246
+ # Returns the number of the current space on the given display.
247
+ # Space numbering starts at 1
248
+ #
249
+ # display_id = TotalSpaces2.displays[0]
250
+ # puts "Current space number: #{TotalSpaces2.current_space_on_display(display_id)}"
251
+ #
252
+ def current_space_on_display(display_id)
253
+ TSApi.tsapi_currentSpaceNumberOnDisplay(display_id)
254
+ end
255
+
256
+ # Returns the name for a space on the main display. The returned string will be empty
257
+ # if the space number is not valid
258
+ #
259
+ # current_space = TotalSpaces2.current_space
260
+ # puts "Current space is called: #{TotalSpaces2.name_for_space(current_space)}"
261
+ #
262
+ def name_for_space(space_number)
263
+ name = string_and_free(TSApi.tsapi_spaceNameForSpaceNumberOnDisplay(space_number, 0))
264
+ name.force_encoding("UTF-8")
265
+ end
266
+
267
+ # Returns the name for a space. The returned string will be empty if the space number is
268
+ # not valid
269
+ #
270
+ # current_space = TotalSpaces2.current_space
271
+ # display_id = TotalSpaces2.main_display[:display_id]
272
+ # puts "Current space is called: #{TotalSpaces2.name_for_space_on_display(current_space, display_id)}"
273
+ #
274
+ def name_for_space_on_display(space_number, display_id)
275
+ name = string_and_free(TSApi.tsapi_spaceNameForSpaceNumberOnDisplay(space_number, display_id))
276
+ name.force_encoding("UTF-8")
277
+ end
278
+
279
+ # Returns the total number of spaces including fullscreens, dashboard (if it's a space).
280
+ #
281
+ # puts "Total number of spaces: #{TotalSpaces2.number_of_spaces}"
282
+ #
283
+ def number_of_spaces
284
+ TSApi.tsapi_numberOfSpacesOnDisplay(0)
285
+ end
286
+
287
+ # Returns the total number of spaces including fullscreens, dashboard (if it's a space).
288
+ #
289
+ # display_id = TotalSpaces2.main_display[:display_id]
290
+ # puts "Total number of spaces: #{TotalSpaces2.number_of_spaces_on_display(display_id)}"
291
+ #
292
+ def number_of_spaces_on_display(display_id)
293
+ TSApi.tsapi_numberOfSpacesOnDisplay(display_id)
294
+ end
295
+
296
+ # Returns the number of columns defined in TotalSpaces2 for the main display
297
+ #
298
+ # puts "Number of columns: #{TotalSpaces2.grid_columns}"
299
+ #
300
+ def grid_columns
301
+ TSApi.tsapi_definedColumnsOnDisplay(0)
302
+ end
303
+
304
+ # Returns the number of columns defined in TotalSpaces2
305
+ #
306
+ # display_id = TotalSpaces2.main_display[:display_id]
307
+ # puts "Number of columns: #{TotalSpaces2.grid_columns_on_display(display_id)}"
308
+ #
309
+ def grid_columns_on_display(display_id)
310
+ TSApi.tsapi_definedColumnsOnDisplay(display_id)
311
+ end
312
+
313
+ # Sets the number of columns defined in TotalSpaces2 for the main display.
314
+ #
315
+ # This does not change the actual number of desktops present, you should
316
+ # call add_desktops or remove_desktops as appropriate after changing the number
317
+ # of columns.
318
+ #
319
+ # TotalSpaces2.set_grid_columns(3)
320
+ #
321
+ def set_grid_columns(columns)
322
+ TSApi.tsapi_setDefinedColumnsOnDisplay(columns, 0)
323
+ end
324
+
325
+ # Sets the number of columns defined in TotalSpaces2.
326
+ #
327
+ # This does not change the actual number of desktops present, you should
328
+ # call add_desktops_on_display or remove_desktops_on_display as appropriate
329
+ # after changing the number of columns.
330
+ #
331
+ # display_id = TotalSpaces2.main_display[:display_id]
332
+ # TotalSpaces2.set_grid_columns_on_display(3, display_id)
333
+ #
334
+ def set_grid_columns_on_display(columns, display_id)
335
+ TSApi.tsapi_setDefinedColumnsOnDisplay(columns, display_id)
336
+ end
337
+
338
+ # Command TotalSpaces2 to switch to the given space number on the main display.
339
+ # Returns false if the space number was invalid.
340
+ # The on_space_change notification will be sent.
341
+ #
342
+ # TotalSpaces2.move_to_space(1)
343
+ #
344
+ def move_to_space(space_number)
345
+ TSApi.tsapi_moveToSpaceOnDisplay(space_number, 0)
346
+ end
347
+
348
+ # Command TotalSpaces2 to switch to the given space number.
349
+ # Returns false if the space number was invalid.
350
+ # The on_space_change notification will be sent.
351
+ #
352
+ # display_id = TotalSpaces2.main_display[:display_id]
353
+ # TotalSpaces2.move_to_space_on_Display(1, display_id)
354
+ #
355
+ def move_to_space_on_display(space_number, display_id)
356
+ TSApi.tsapi_moveToSpaceOnDisplay(space_number, display_id)
357
+ end
358
+
359
+ # Set the name for a space on the main display.
360
+ # Note that using this command will cause a layout change notification to be sent
361
+ # if the new name was different from that previously set.
362
+ # The maximum length for a name is 255 bytes.
363
+ #
364
+ # TotalSpaces2.set_name_for_space(1, "Home")
365
+ #
366
+ def set_name_for_space(space_number, name)
367
+ TSApi.tsapi_setNameForSpaceOnDisplay(space_number, name, 0)
368
+ end
369
+
370
+ # Set the name for a space.
371
+ # Note that using this command will cause a layout change notification to be sent
372
+ # if the new name was different from that previously set.
373
+ # The maximum length for a name is 255 bytes.
374
+ #
375
+ # display_id = TotalSpaces2.main_display[:display_id]
376
+ # TotalSpaces2.set_name_for_space_on_display(1, "Home", display_id)
377
+ #
378
+ def set_name_for_space_on_display(space_number, name, display_id)
379
+ TSApi.tsapi_setNameForSpaceOnDisplay(space_number, name, display_id)
380
+ end
381
+
382
+ # Register for notifications on space change.
383
+ # The given block will be called whenever you move from one space to another. The arguments are
384
+ # the space number you moved from, and the one you are moving to.
385
+ #
386
+ # TotalSpaces2.on_space_change {|from, to, displayID| puts "Moving from space #{from} to space #{to}"}
387
+ #
388
+ # sleep
389
+ #
390
+ # There can only be one block registered at any time, the most recently registered one will
391
+ # be called.
392
+ # This callback is called just before the space actually changes - current_space will still
393
+ # report the from space.
394
+ #
395
+ def on_space_change(&block)
396
+ $tsapi_on_space_change_block = block # prevent GC
397
+ TSApi.tsapi_setSpaceWillChangeCallback(block)
398
+ end
399
+
400
+ # Cancel the on_space_change notification.
401
+ #
402
+ def cancel_on_space_change
403
+ $tsapi_on_space_change_block = nil
404
+ TSApi.tsapi_unsetSpaceWillChangeCallback
405
+ end
406
+
407
+ # Register for notifications on layout change.
408
+ # The given block will be called whenever the layout changes - this could be due to making an app
409
+ # fullscreen, changing a space name, or changing the layout of the TotalSpaces2 grid. There are no
410
+ # arguments passed to the block.
411
+ #
412
+ #
413
+ # TotalSpaces.on_layout_change {puts "Spaces changed"}
414
+ #
415
+ # sleep
416
+ #
417
+ # When you get a notification from this method, you should re-fetch any information about the spaces
418
+ # that you may be storing.
419
+ #
420
+ # There can only be one block registered at any time, the most recently registered one will
421
+ # be called.
422
+ #
423
+ def on_layout_change(&block)
424
+ $tsapi_on_layout_change_block = block # prevent GC
425
+ TSApi.tsapi_setLayoutChangedCallback(block)
426
+ end
427
+
428
+ # Cancel the layout change notification
429
+ #
430
+ def cancel_on_layout_change
431
+ $tsapi_on_layout_change_block = nil
432
+ TSApi.tsapi_unsetLayoutChangedCallback
433
+ end
434
+
435
+ # Get a list of all the windows on your mac
436
+ # It returns an array containing a hash for each window.
437
+ # The hash contains the display id (key :display_id) and space number (key :space_number)
438
+ # and details for each window.
439
+ # The windows are in front to back order within each space.
440
+ # Each window hash also contains a window_id, title, frame, app_name and is_on_all_spaces flag
441
+ #
442
+ # The below example would move the frontmost window to the next space to the right.
443
+ #
444
+ # windows = TotalSpaces2.window_list
445
+ # current_space = TotalSpaces2.current_space
446
+ # main_display_id = TotalSpaces2.main_display[:display_id]
447
+ # if !windows.empty?
448
+ # current_space_windows = windows.select {|window| window[:display_id] == main_display_id
449
+ # && window[:space_number] == current_space}
450
+ # front_window = current_space_windows[0]
451
+ # TotalSpaces2.move_window_to_space(front_window[:window_id], TotalSpaces.current_space + 1)
452
+ # end
453
+ #
454
+ def window_list
455
+ result = []
456
+ list = TSApi.tsapi_windowList
457
+ main_array = Windows.new(list)
458
+
459
+ (0...main_array[:count]).each do |n|
460
+ window = Window.new(main_array[:windows_array] + n * Window.size)
461
+ window_hash = {}
462
+ window_hash[:window_id] = window[:window_id]
463
+ window_hash[:title] = window[:title].dup.force_encoding("UTF-8")
464
+ window_hash[:frame] = window[:frame].dup.force_encoding("UTF-8")
465
+ window_hash[:is_on_all_spaces] = window[:is_on_all_spaces]
466
+ window_hash[:app_name] = window[:app_name].dup.force_encoding("UTF-8")
467
+ window_hash[:display_id] = window[:display_id]
468
+ window_hash[:space_number] = window[:space_number]
469
+ result << window_hash
470
+ end
471
+
472
+ TSApi.tsapi_freeWindowList(list)
473
+
474
+ result
475
+ end
476
+
477
+ # Move a window to a given space
478
+ # The window_id parameter must be fetched using window_list.
479
+ # Returns false if the space_number or window_id is invalid.
480
+ #
481
+ def move_window_to_space(window_id, space_number)
482
+ TSApi.tsapi_moveWindowToSpaceOnDisplay(window_id, space_number, 0)
483
+ end
484
+
485
+ # Move a window to a given space on the main display
486
+ # The window_id parameter must be fetched using window_list.
487
+ # Returns false if the space_number or window_id is invalid.
488
+ #
489
+ def move_window_to_space_on_display(window_id, space_number, display_id)
490
+ TSApi.tsapi_moveWindowToSpaceOnDisplay(window_id, space_number, display_id)
491
+ end
492
+
493
+ # Move space to a new position in the grid on the main display.
494
+ #
495
+ # Returns false if the space_number or position_number is not valid.
496
+ #
497
+ # TotalSpaces2.move_space_to_position(4, 2)
498
+ #
499
+ def move_space_to_position(space_number, position_number)
500
+ TSApi.tsapi_moveSpaceToPositionOnDisplay(space_number, position_number)
501
+ end
502
+
503
+ # Move space to a new position in the grid. Spaces can only be moved
504
+ # within their own display.
505
+ #
506
+ # Returns false if the space_number or position_number is not valid.
507
+ #
508
+ # display_id = TotalSpaces2.main_display[:display_id]
509
+ # TotalSpaces2.move_space_to_position_on_display(4, 2, display_id)
510
+ #
511
+ def move_space_to_position_on_display(space_number, position_number, display_id)
512
+ TSApi.tsapi_moveSpaceToPositionOnDisplay(space_number, position_number, display_id)
513
+ end
514
+
515
+ # Add desktops
516
+ # There can be at most 16 desktops unless the display has collected some when
517
+ # a secondary display has been unplugged.
518
+ # Returns true on success, false if number_to_add was zero, or would result
519
+ # in more than 16 desktops.
520
+ # The on_layout_change notification will be sent if a changed was made.
521
+ #
522
+ # TotalSpaces2.add_desktops(1)
523
+ #
524
+ def add_desktops(number_to_add)
525
+ TSApi.tsapi_addDesktopsOnDisplay(number_to_add, 0)
526
+ end
527
+
528
+ # Add desktops
529
+ # There can be at most 16 desktops unless the display has collected some when
530
+ # a secondary display has been unplugged.
531
+ # Returns true on success, false if number_to_add was zero, or would result
532
+ # in more than 16 desktops.
533
+ # The on_layout_change notification will be sent if a changed was made.
534
+ #
535
+ # display_id = TotalSpaces2.main_display[:display_id]
536
+ # TotalSpaces2.add_desktops_on_display(1, display_id)
537
+ #
538
+ def add_desktops_on_display(number_to_add, display_id)
539
+ TSApi.tsapi_addDesktopsOnDisplay(number_to_add, display_id)
540
+ end
541
+
542
+ # Remove desktops
543
+ # The highest numbered desktops are removed.
544
+ # Removing a desktop you are currently on will result in TotalSpaces2 switching to
545
+ # another dektop.
546
+ # Any windows present on a desktop being removed will be moved to one of the
547
+ # remaining desktops.
548
+ # Returns true on success, false if number_to_remove was zero or would result in less
549
+ # than 1 desktop remaining.
550
+ # The on_layout_change notification will be sent if a change was made.
551
+ #
552
+ # TotalSpaces2.remove_desktops(1)
553
+ #
554
+ def remove_desktops(number_to_remove)
555
+ TSApi.tsapi_removeDesktopsOnDisplay(number_to_remove, 0)
556
+ end
557
+
558
+ # Remove desktops
559
+ # The highest numbered desktops are removed.
560
+ # Removing a desktop you are currently on will result in TotalSpaces2 switching to
561
+ # another dektop.
562
+ # Any windows present on a desktop being removed will be moved to one of the
563
+ # remaining desktops.
564
+ # Returns true on success, false if number_to_remove was zero or would result in less
565
+ # than 1 desktop remaining.
566
+ # The on_layout_change notification will be sent if a change was made.
567
+ #
568
+ # display_id = TotalSpaces2.main_display[:display_id]
569
+ # TotalSpaces2.remove_desktops_on_display(1, display_id)
570
+ #
571
+ def remove_desktops_on_display(number_to_remove, display_id)
572
+ TSApi.tsapi_removeDesktopsOnDisplay(number_to_remove, display_id)
573
+ end
574
+ end
575
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: totalspaces2
3
+ version: !ruby/object:Gem::Version
4
+ version: '2.0'
5
+ platform: ruby
6
+ authors:
7
+ - Stephen Sykes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.11
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.11
27
+ description: This allows you to control the TotalSpaces2 desktop manager for mac from
28
+ ruby.
29
+ email: stephen@binaryage.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - README.rdoc
35
+ - MIT_LICENCE
36
+ - lib/totalspaces2.rb
37
+ - lib/libtotalspaces2api.dylib
38
+ - lib/TSLib.h
39
+ homepage: https://github.com/binaryage/totalspaces2-api/tree/master/ruby
40
+ licenses: []
41
+ metadata: {}
42
+ post_install_message:
43
+ rdoc_options:
44
+ - --charset=UTF-8
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project:
59
+ rubygems_version: 2.0.3
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: TotalSpaces2 control from ruby
63
+ test_files: []