Merge lp:~bkerensa/ubuntu/raring/kazam/new-upstream into lp:ubuntu/raring/kazam
- Raring (13.04)
- new-upstream
- Merge into raring
Proposed by
Benjamin Kerensa
Status: | Merged |
---|---|
Merge reported by: | Charlie_Smotherman |
Merged at revision: | not available |
Proposed branch: | lp:~bkerensa/ubuntu/raring/kazam/new-upstream |
Merge into: | lp:ubuntu/raring/kazam |
Diff against target: |
61072 lines (+48637/-8979) 195 files modified
AUTHORS (+4/-0) NEWS (+36/-0) README (+62/-37) TODO (+11/-5) bin/kazam (+83/-16) build/lib.linux-x86_64-2.7/kazam/__init__.py (+1/-0) build/lib.linux-x86_64-2.7/kazam/app.py (+748/-0) build/lib.linux-x86_64-2.7/kazam/backend/__init__.py (+1/-0) build/lib.linux-x86_64-2.7/kazam/backend/config.py (+128/-0) build/lib.linux-x86_64-2.7/kazam/backend/constants.py (+152/-0) build/lib.linux-x86_64-2.7/kazam/backend/export.py (+194/-0) build/lib.linux-x86_64-2.7/kazam/backend/ffmpeg.py (+132/-0) build/lib.linux-x86_64-2.7/kazam/backend/grabber.py (+166/-0) build/lib.linux-x86_64-2.7/kazam/backend/gstreamer.py (+416/-0) build/lib.linux-x86_64-2.7/kazam/backend/prefs.py (+232/-0) build/lib.linux-x86_64-2.7/kazam/frontend/__init__.py (+1/-0) build/lib.linux-x86_64-2.7/kazam/frontend/about_dialog.py (+70/-0) build/lib.linux-x86_64-2.7/kazam/frontend/combobox.py (+116/-0) build/lib.linux-x86_64-2.7/kazam/frontend/done_recording.py (+159/-0) build/lib.linux-x86_64-2.7/kazam/frontend/export.py (+269/-0) build/lib.linux-x86_64-2.7/kazam/frontend/indicator.py (+311/-0) build/lib.linux-x86_64-2.7/kazam/frontend/main_menu.py (+88/-0) build/lib.linux-x86_64-2.7/kazam/frontend/preferences.py (+375/-0) build/lib.linux-x86_64-2.7/kazam/frontend/save_dialog.py (+62/-0) build/lib.linux-x86_64-2.7/kazam/frontend/widgets.py (+60/-0) build/lib.linux-x86_64-2.7/kazam/frontend/window_area.py (+202/-0) build/lib.linux-x86_64-2.7/kazam/frontend/window_countdown.py (+140/-0) build/lib.linux-x86_64-2.7/kazam/frontend/window_region.py (+200/-0) build/lib.linux-x86_64-2.7/kazam/frontend/window_select.py (+181/-0) build/lib.linux-x86_64-2.7/kazam/instant.py (+142/-0) build/lib.linux-x86_64-2.7/kazam/pulseaudio/__init__.py (+1/-0) build/lib.linux-x86_64-2.7/kazam/pulseaudio/ctypes_pulseaudio.py (+197/-0) build/lib.linux-x86_64-2.7/kazam/pulseaudio/error_handling.py (+27/-0) build/lib.linux-x86_64-2.7/kazam/pulseaudio/pulseaudio.py (+345/-0) build/lib.linux-x86_64-2.7/kazam/utils.py (+47/-0) build/lib.linux-x86_64-2.7/kazam/version.py (+5/-0) build/scripts-2.7/kazam (+144/-0) build/share/applications/kazam.desktop (+134/-0) data/icons/dark/all-screens.svg (+81/-0) data/icons/dark/area.svg (+81/-0) data/icons/dark/fullscreen.svg (+81/-0) data/icons/dark/photo.svg (+81/-0) data/icons/dark/screencast-2-dark.svg (+98/-0) data/icons/dark/screencast.svg (+81/-0) data/icons/dark/screenshot-1.svg (+90/-0) data/icons/dark/screenshot-2.svg (+90/-0) data/icons/dark/sound.svg (+82/-0) data/icons/dark/video.svg (+81/-0) data/icons/dark/window.svg (+81/-0) data/icons/light/all-screens.svg (+81/-0) data/icons/light/area.svg (+81/-0) data/icons/light/fullscreen.svg (+81/-0) data/icons/light/photo.svg (+81/-0) data/icons/light/screencast.svg (+81/-0) data/icons/light/screenshot-1.svg (+90/-0) data/icons/light/screenshot-2.svg (+90/-0) data/icons/light/sound.svg (+82/-0) data/icons/light/video.svg (+81/-0) data/icons/light/window.svg (+81/-0) data/ui/kazam.ui (+337/-0) data/ui/preferences.ui (+607/-0) debian/changelog (+5/-6) debian/files (+1/-0) debian/kazam.debhelper.log (+44/-0) debian/kazam.postinst.debhelper (+7/-0) debian/kazam.prerm.debhelper (+12/-0) debian/kazam.substvars (+3/-0) debian/kazam/DEBIAN/control (+16/-0) debian/kazam/DEBIAN/md5sums (+138/-0) debian/kazam/DEBIAN/postinst (+9/-0) debian/kazam/DEBIAN/prerm (+14/-0) debian/kazam/usr/bin/kazam (+144/-0) debian/kazam/usr/share/applications/kazam.desktop (+134/-0) debian/kazam/usr/share/doc/kazam/TODO (+14/-0) debian/kazam/usr/share/doc/kazam/copyright (+36/-0) debian/kazam/usr/share/kazam/icons/128.svg (+2059/-0) debian/kazam/usr/share/kazam/icons/16.svg (+1568/-0) debian/kazam/usr/share/kazam/icons/22.svg (+1500/-0) debian/kazam/usr/share/kazam/icons/24.svg (+1557/-0) debian/kazam/usr/share/kazam/icons/300.svg (+4801/-0) debian/kazam/usr/share/kazam/icons/32.svg (+1567/-0) debian/kazam/usr/share/kazam/icons/48.svg (+1560/-0) debian/kazam/usr/share/kazam/icons/96.svg (+1878/-0) debian/kazam/usr/share/kazam/icons/text-black.svg (+75/-0) debian/kazam/usr/share/kazam/icons/text-bling.svg (+904/-0) debian/kazam/usr/share/kazam/icons/text-white.svg (+65/-0) debian/kazam/usr/share/kazam/ui/authenticate.ui (+234/-0) debian/kazam/usr/share/kazam/ui/done-recording.ui (+190/-0) debian/kazam/usr/share/kazam/ui/export.ui (+344/-0) debian/kazam/usr/share/kazam/ui/kazam.ui (+337/-0) debian/kazam/usr/share/kazam/ui/preferences.ui (+607/-0) debian/kazam/usr/share/kazam/ui/start.ui (+178/-0) debian/kazam/usr/share/pyshared/kazam-1.3.99_0ubuntu1.egg-info (+171/-0) debian/kazam/usr/share/pyshared/kazam/__init__.py (+1/-0) debian/kazam/usr/share/pyshared/kazam/app.py (+748/-0) debian/kazam/usr/share/pyshared/kazam/backend/__init__.py (+1/-0) debian/kazam/usr/share/pyshared/kazam/backend/config.py (+128/-0) debian/kazam/usr/share/pyshared/kazam/backend/constants.py (+152/-0) debian/kazam/usr/share/pyshared/kazam/backend/export.py (+194/-0) debian/kazam/usr/share/pyshared/kazam/backend/ffmpeg.py (+132/-0) debian/kazam/usr/share/pyshared/kazam/backend/grabber.py (+166/-0) debian/kazam/usr/share/pyshared/kazam/backend/gstreamer.py (+416/-0) debian/kazam/usr/share/pyshared/kazam/backend/prefs.py (+232/-0) debian/kazam/usr/share/pyshared/kazam/frontend/__init__.py (+1/-0) debian/kazam/usr/share/pyshared/kazam/frontend/about_dialog.py (+70/-0) debian/kazam/usr/share/pyshared/kazam/frontend/combobox.py (+116/-0) debian/kazam/usr/share/pyshared/kazam/frontend/done_recording.py (+159/-0) debian/kazam/usr/share/pyshared/kazam/frontend/export.py (+269/-0) debian/kazam/usr/share/pyshared/kazam/frontend/indicator.py (+311/-0) debian/kazam/usr/share/pyshared/kazam/frontend/main_menu.py (+88/-0) debian/kazam/usr/share/pyshared/kazam/frontend/preferences.py (+375/-0) debian/kazam/usr/share/pyshared/kazam/frontend/save_dialog.py (+62/-0) debian/kazam/usr/share/pyshared/kazam/frontend/widgets.py (+60/-0) debian/kazam/usr/share/pyshared/kazam/frontend/window_area.py (+202/-0) debian/kazam/usr/share/pyshared/kazam/frontend/window_countdown.py (+140/-0) debian/kazam/usr/share/pyshared/kazam/frontend/window_region.py (+200/-0) debian/kazam/usr/share/pyshared/kazam/frontend/window_select.py (+181/-0) debian/kazam/usr/share/pyshared/kazam/instant.py (+142/-0) debian/kazam/usr/share/pyshared/kazam/pulseaudio/__init__.py (+1/-0) debian/kazam/usr/share/pyshared/kazam/pulseaudio/ctypes_pulseaudio.py (+197/-0) debian/kazam/usr/share/pyshared/kazam/pulseaudio/error_handling.py (+27/-0) debian/kazam/usr/share/pyshared/kazam/pulseaudio/pulseaudio.py (+345/-0) debian/kazam/usr/share/pyshared/kazam/utils.py (+47/-0) debian/kazam/usr/share/pyshared/kazam/version.py (+5/-0) kazam/app.py (+621/-567) kazam/backend/config.py (+29/-12) kazam/backend/constants.py (+96/-3) kazam/backend/grabber.py (+166/-0) kazam/backend/gstreamer.py (+274/-219) kazam/backend/prefs.py (+232/-0) kazam/frontend/combobox.py (+20/-7) kazam/frontend/done_recording.py (+8/-8) kazam/frontend/indicator.py (+184/-56) kazam/frontend/main_menu.py (+11/-0) kazam/frontend/preferences.py (+375/-0) kazam/frontend/save_dialog.py (+15/-34) kazam/frontend/widgets.py (+60/-0) kazam/frontend/window_area.py (+202/-0) kazam/frontend/window_countdown.py (+29/-15) kazam/frontend/window_select.py (+181/-0) kazam/instant.py (+142/-0) kazam/pulseaudio/ctypes_pulseaudio.py (+4/-4) kazam/pulseaudio/pulseaudio.py (+40/-28) kazam/tests/__init__.py (+1/-0) kazam/tests/test_app.py (+53/-0) kazam/utils.py (+14/-0) kazam/version.py (+4/-3) po/POTFILES.in (+12/-7) po/ar.po (+290/-226) po/bg.po (+274/-210) po/bn.po (+241/-212) po/ca.po (+278/-214) po/cs.po (+285/-219) po/da.po (+287/-0) po/de.po (+280/-217) po/el.po (+243/-211) po/en_AU.po (+285/-0) po/en_CA.po (+253/-221) po/en_GB.po (+255/-221) po/eo.po (+198/-212) po/es.po (+281/-216) po/eu.po (+266/-0) po/fi.po (+271/-213) po/fo.po (+252/-0) po/fr.po (+287/-222) po/gl.po (+247/-215) po/hr.po (+317/-0) po/hu.po (+286/-222) po/id.po (+249/-218) po/is.po (+241/-212) po/it.po (+278/-216) po/kazam.pot (+239/-178) po/ko.po (+239/-0) po/lt.po (+285/-0) po/lv.po (+286/-222) po/ml.po (+221/-217) po/ms.po (+254/-220) po/nl.po (+290/-226) po/oc.po (+239/-0) po/pl.po (+271/-216) po/pt.po (+245/-213) po/pt_BR.po (+280/-214) po/pt_PT.po (+210/-211) po/ro.po (+284/-221) po/ru.po (+282/-218) po/sk.po (+245/-213) po/sl.po (+274/-210) po/sr.po (+228/-222) po/sv.po (+247/-213) po/te.po (+317/-0) po/tr.po (+284/-220) po/uk.po (+288/-222) po/zh_CN.po (+286/-222) po/zh_TW.po (+236/-169) setup.py (+8/-8) |
To merge this branch: | bzr merge lp:~bkerensa/ubuntu/raring/kazam/new-upstream |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Charlie_Smotherman (community) | Needs Fixing | ||
Ubuntu branches | Pending | ||
Review via email: mp+134426@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Bryce Harrington (bryce) wrote : | # |
Set status back to Needs Review once the requested fix is made.
Revision history for this message
Benjamin Kerensa (bkerensa) wrote : | # |
> Set status back to Needs Review once the requested fix is made.
Any advice on a fix... I am not too familiar with watch file formats so I'm not sure where to begin to fix this but I definately want to fix it and get this into quantal.
Thanks
Revision history for this message
Charlie_Smotherman (cjsmo) wrote : | # |
Had to make some additional changes to the packaging so I went ahead and fixed the watchfile while I was there :) Uploaded to raring. If you would like to get kazam 1.3.4 into quantal please have a look at
https:/
https:/
Thank you for your contribution to Ubuntu
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'AUTHORS' |
2 | --- AUTHORS 2012-02-09 21:56:49 +0000 |
3 | +++ AUTHORS 2012-11-15 10:17:01 +0000 |
4 | @@ -9,4 +9,8 @@ |
5 | K.Vishnoo Charan Reddy - Artwork, Bughelp, Design |
6 | Gary Lasker - Coding |
7 | David Klasinc - Coding |
8 | +Georgi Karavasilev - Design, Testing |
9 | +Alan Pope - Testing |
10 | +Mattew Paul Thomas - Design, Testing |
11 | +Ken VanDine - Packaging |
12 | |
13 | |
14 | === added file 'NEWS' |
15 | --- NEWS 1970-01-01 00:00:00 +0000 |
16 | +++ NEWS 2012-11-15 10:17:01 +0000 |
17 | @@ -0,0 +1,36 @@ |
18 | +Kazam 1.3.4 - NCC-2893 (Stargazer Edition) |
19 | + |
20 | +- Instant mode, to capture screenshots from command line, use |
21 | + the following switches: |
22 | + -f / --fullscreen capture full screen |
23 | + -w / --window capture currently active window |
24 | + -a / --area capture a preselected screen area |
25 | + -g / --godmode disable sounds, use automatic file saving and |
26 | + capture full screen & active window at the same |
27 | + time |
28 | + |
29 | +- New area and window selection screens. |
30 | +- Unity Launcher quicklist added. |
31 | + |
32 | +Kazam 1.3.1 - NCC-2893 (Stargazer Edition) |
33 | +------------------------------------------ |
34 | + |
35 | +- GStreamer 1.0 support, Kazam will no longer work with older versions |
36 | + of GStreamer. This includes 0.11 (1.0 alpha/beta/rc) version. Some |
37 | + encoders were changed in transition from beta to final release which |
38 | + messed up a lot of things. |
39 | + |
40 | +- Completely new GUI. Designed by https://launchpad.net/~kokoto-java with |
41 | + the omnipresent guiding hand of https://launchpad.net/~mpt |
42 | + |
43 | +- Support for taking still screen captures, also known as screenshots. |
44 | + |
45 | +- Support for automatic file saving. You can set the prefix filename |
46 | + separately for screenshots and screencasts. |
47 | + |
48 | +- Support for selecting a single window to screencast. Screenshots are |
49 | + still limited to full screen and/or area selection. |
50 | + |
51 | +- Theme-able shutter sounds. Right now you can choose between Canon 7D |
52 | + and Nikon D80. ;) |
53 | + |
54 | |
55 | === modified file 'README' |
56 | --- README 2012-04-25 16:49:23 +0000 |
57 | +++ README 2012-11-15 10:17:01 +0000 |
58 | @@ -1,5 +1,5 @@ |
59 | |
60 | - Kazam Screencaster v1.0.6 "NCC-1701D" |
61 | + Kazam Screencaster v1.3.1 "NCC-2893" |
62 | |
63 | |
64 | Introduction |
65 | @@ -18,15 +18,25 @@ |
66 | |
67 | Kazam is always available from Launchpad under https://launchpad.net/kazam |
68 | |
69 | -Right now there are only unstable versions available, the project is still |
70 | -in development and a stable release is planned for Ubuntu 12.04. |
71 | - |
72 | - |
73 | -Installation |
74 | ------------- |
75 | - |
76 | -For Ubuntu, the best way to install is to add a PPA repository and then |
77 | -use apt-get command or Software Centre. |
78 | +Latest stable release is 1.0.6. |
79 | +Latest unstable release is 1.3.1 - Stargazer edition |
80 | + |
81 | + |
82 | +Installation - stable release |
83 | +----------------------------- |
84 | + |
85 | +If you are using Ubuntu 12.04 or 12.10 then stable version (1.0.x) |
86 | +is available from universe repository. You can find it in Ubuntu Softare |
87 | +Center or install it from the terminal with the following command: |
88 | + |
89 | +$ sudo apt-get install kazam |
90 | + |
91 | +For Ubuntu 11.10 - Oneiric Ocelot, the best way to install Kazam is to add |
92 | +a PPA repository and then use apt-get command or Software Centre. |
93 | + |
94 | +$ sudo add-apt-repository ppa:kazam-team/stable-series |
95 | +$ sudo apt-get update |
96 | +$ sudo apt-get install kazam |
97 | |
98 | For distribution independent installation you will have to get the latest |
99 | tarball release from Launchpad: |
100 | @@ -43,6 +53,9 @@ |
101 | # python setup.py install |
102 | |
103 | |
104 | +Installation - development version |
105 | +---------------------------------- |
106 | + |
107 | If you want bleeding edge, development version then you will have to get |
108 | source code from Launchpad by running the following command: |
109 | |
110 | @@ -57,6 +70,39 @@ |
111 | path is /usr/local. |
112 | |
113 | |
114 | +Running Kazam |
115 | +------------- |
116 | + |
117 | +If you want to run Kazam from the source tree, there are a few limitations |
118 | +that you have to take into account. Right now Ubuntu App indicator will not |
119 | +allow setting custom icons. Every icon has to be taken from currently |
120 | +installed icon theme. See https://bugs.launchpad.net/kazam/+bug/657857 for |
121 | +more information. |
122 | + |
123 | +To run Kazam simply execute te following commands in the source tree: |
124 | + |
125 | +$ cd bin |
126 | +$ ./kazam |
127 | + |
128 | +If you already have Kazam installed then Kazam icon will show in the |
129 | +indicator, if not, the only way to get to the menu is to click on one |
130 | +of the icons in the indicator and then move around with the cursor keys. |
131 | + |
132 | +Keyboard shortcuts |
133 | +------------------ |
134 | + |
135 | +If you have keybinder3.0 from the unstable PPA installed, then you can |
136 | +use these keyboard shortcuts for controlling Kazam: |
137 | + |
138 | +SUPER-CTRL-Q - Quit |
139 | +SUPER-CTRL-W - Show/Hide main window |
140 | +SUPER-CTRL-R - Start Recording |
141 | +SUPER-CTRL-F - Finish Recording |
142 | + |
143 | +Keyboard shortcuts will work if you installed Kazam 1.3.1 from a PPA, |
144 | +keybinder 3.0 is now a dependency and will be installed automatically. |
145 | + |
146 | + |
147 | Known Issues |
148 | ------------ |
149 | |
150 | @@ -67,30 +113,14 @@ |
151 | - Placing Region selector outside of screen borders will produce unknown |
152 | results and you will probably end up with no video. |
153 | |
154 | -- Two warnings appear during the normal usage: |
155 | - |
156 | -/usr/lib/python2.7/dist-packages/gobject/constants.py:24: Warning: |
157 | -g_boxed_type_register_static: assertion `g_type_from_name (name) == 0' failed |
158 | - |
159 | -This happens when Gtk.GObject was imported before importing gst in python |
160 | -and is still being investigated. So far it appears to be mostly harmless. |
161 | - |
162 | -Second warning comes from Gtk.FileChooser(): |
163 | - |
164 | -kazam:5144): Gtk-WARNING **: Unable to retrieve the file info for <file> |
165 | -Error stating file <file> : No such file or directory |
166 | - |
167 | -This happens when you confirm file save in the dialog box. This is an error |
168 | -in Gtk.FileChooser and in Precise Pangolin it is fixed. |
169 | - |
170 | - Trouble with recording from certain Monitor sources. I noticed this with |
171 | Logitech G110 USB Keyboard that can play audio. Pulse Audio will see two |
172 | devices: USP PnP Stereo Device and Monitor of USB PnP Stereo Device. When |
173 | recording from the monitor, volume controls for both devices will affect |
174 | the volume in the final recording. |
175 | |
176 | -- I have no idea where to put Mute/Unmute button, so you'll have to check |
177 | -that in pavucontrol or sound settings. :) |
178 | +- I have no idea where to put Mute/Unmute button, so right now every audio |
179 | +source you select is automatically unmuted. |
180 | |
181 | - It was reported that sound is disappearing after couple of minutes into |
182 | the recording. I wasn't able to reproduce this bug and any more info is |
183 | @@ -100,10 +130,9 @@ |
184 | Recording Tips |
185 | -------------- |
186 | |
187 | -Framerates above 20fps are unlikely to work because of software and hardware |
188 | -limitations. If you increase framerate and in resulting video |
189 | -framerate actually drops, that is because encoder can't keep up with |
190 | -the framerate. |
191 | +Framerates above 20fps are unlikely to work well because of software and |
192 | +hardware limitations. If you increase framerate and framerate in |
193 | +resulting video drops, that is because encoder can't keep up. |
194 | |
195 | Always do a sound check. Especially if you are recording a live commentary |
196 | with background sound. I got the best results when I used earphones to listen |
197 | @@ -117,9 +146,5 @@ |
198 | If you encounter a bug or any kind of unexpected behavior please try to |
199 | reproduce it while you run Kazam from standard terminal with --debug option. |
200 | Use Launchpad to report bugs (https://bugs.launchpad.net/kazam/+filebug) and |
201 | -include generated output. It will also be helpful if you can attach generated |
202 | -'dot' file. You will find this file in /tmp/kazam_debug.dot. |
203 | - |
204 | -If you have graphviz package installed there is also /tmp/kazam_pipeline.png |
205 | -file and you can inspect GStreamer pipeline if everything checks out ok. |
206 | +include generated output. |
207 | |
208 | |
209 | === modified file 'TODO' |
210 | --- TODO 2012-02-29 20:43:50 +0000 |
211 | +++ TODO 2012-11-15 10:17:01 +0000 |
212 | @@ -1,8 +1,14 @@ |
213 | TODO |
214 | ---- |
215 | -Short term: |
216 | - - Make a list of new features |
217 | - |
218 | -Long(er) term: |
219 | - - Implement new features ;) |
220 | + |
221 | +Whishlist (by BigWhale) and reasons why is something still on a whishlist |
222 | + |
223 | +- Frame marking the capture area while recording is in progress |
224 | + A transparent window with no input mask is required on screen. However, |
225 | + for that to work, Gdk.cairo_region_create_from_surface() is required. For |
226 | + some reason, this fuction still isn't introspected. See: |
227 | + |
228 | + http://askubuntu.com/questions/97789/creating-a-gtk-window-with-input-shape-mask-in-python |
229 | + |
230 | + (This is still an issue ... :'( ) |
231 | |
232 | |
233 | === modified file 'bin/kazam' |
234 | --- bin/kazam 2012-02-29 20:43:50 +0000 |
235 | +++ bin/kazam 2012-11-15 10:17:01 +0000 |
236 | @@ -30,25 +30,36 @@ |
237 | |
238 | if __name__ == "__main__": |
239 | |
240 | - log = logging.getLogger() |
241 | - log.name = "Kazam" |
242 | + logger = logging.getLogger() |
243 | + logger.name = "Kazam" |
244 | handler = logging.StreamHandler() |
245 | - formatter = logging.Formatter('%(levelname)s %(name)-10s - %(message)s') |
246 | + formatter = logging.Formatter('%(levelname)s %(name)s - %(message)s') |
247 | handler.setFormatter(formatter) |
248 | - log.addHandler(handler) |
249 | + logger.addHandler(handler) |
250 | + logger.setLevel(logging.INFO) |
251 | |
252 | - log.info("Logger intialized.") |
253 | + logger.info("Logger intialized.") |
254 | |
255 | if os.path.exists("../data"): |
256 | - log.info("Running locally, AppIndicator icons might be missing.") |
257 | + logger.info("Running locally, AppIndicator icons might be missing.") |
258 | datadir = "../data" |
259 | sys.path.insert(0, "..") |
260 | else: |
261 | # A bit more flexible setting of datadir, it works |
262 | # when base install path is not /usr |
263 | curpath = os.path.abspath(__file__) |
264 | + curpath = os.path.realpath(curpath) |
265 | datadir = curpath.split('bin/')[0] + "share/kazam/" |
266 | |
267 | + try: |
268 | + import platform |
269 | + dist = platform.linux_distribution() |
270 | + logger.info("Running on: {0} {1}".format(dist[0], dist[1])) |
271 | + except: |
272 | + # Fallback to the almighty Ubuntu 12.10 ;) |
273 | + dist = ('Ubuntu', '12.10', 'quantal') |
274 | + logger.warning("Failed to correctly detect operating system.") |
275 | + |
276 | from kazam.version import * |
277 | version = "%(prog)s {0} '{1}'".format(VERSION, CODENAME) |
278 | parser = ArgumentParser(description = "Screen recording program.") |
279 | @@ -62,16 +73,72 @@ |
280 | action = "version", |
281 | version = version) |
282 | |
283 | + parser.add_argument("-t", "--test", |
284 | + action = "store_true", |
285 | + help = "generate test video signal", |
286 | + default = False) |
287 | + |
288 | + parser.add_argument("-n", "--nosound", |
289 | + action = "store_true", |
290 | + help = "disable PulseAudio", |
291 | + default = False) |
292 | + |
293 | + parser.add_argument("-s", "--silent", |
294 | + action = "store_true", |
295 | + help = "silent start", |
296 | + default = False) |
297 | + |
298 | + parser.add_argument("-f", "--fullscreen", |
299 | + action = "store_true", |
300 | + help = "instant screenshot of full screen", |
301 | + default = False) |
302 | + |
303 | + parser.add_argument("-a", "--area", |
304 | + action = "store_true", |
305 | + help = "instant screenshot of preselected screen area", |
306 | + default = False) |
307 | + |
308 | + parser.add_argument("-w", "--window", |
309 | + action = "store_true", |
310 | + help = "instant screenshot of active window", |
311 | + default = False) |
312 | + |
313 | + parser.add_argument("-p", "--preferences", |
314 | + action = "store_true", |
315 | + help = "show preferences window", |
316 | + default = False) |
317 | + |
318 | + parser.add_argument("-g", "--godmode", |
319 | + action = "store_true", |
320 | + help = "god mode of capture", |
321 | + default = False) |
322 | + |
323 | args = parser.parse_args() |
324 | if args.debug: |
325 | - log.setLevel(logging.DEBUG) |
326 | - else: |
327 | - log.setLevel(logging.INFO) |
328 | - |
329 | - from kazam.app import KazamApp |
330 | - |
331 | - log.debug("Starting ...") |
332 | - appWindow = KazamApp(datadir, args.debug) |
333 | - appWindow.show_all() |
334 | + logger.setLevel(logging.DEBUG) |
335 | + else: |
336 | + logger.setLevel(logging.INFO) |
337 | + |
338 | + logger.debug("Starting ...") |
339 | + |
340 | + if args.fullscreen: |
341 | + from kazam.instant import InstantApp |
342 | + app = InstantApp(datadir, dist, args.debug, 1) # MODE_ALL |
343 | + elif args.area: |
344 | + from kazam.instant import InstantApp |
345 | + app = InstantApp(datadir, dist, args.debug, 2) # MODE_AREA |
346 | + elif args.window: |
347 | + from kazam.instant import InstantApp |
348 | + app = InstantApp(datadir, dist, args.debug, 4) # MODE_ACTIVE |
349 | + elif args.godmode: |
350 | + from kazam.instant import InstantApp |
351 | + app = InstantApp(datadir, dist, args.debug, 666) # MODE_ACTIVE |
352 | + elif args.preferences: |
353 | + from kazam.instant import InstantApp |
354 | + app = InstantApp(datadir, dist, args.debug, 0, preferences=True) |
355 | + else: |
356 | + from kazam.app import KazamApp |
357 | + appWindow = KazamApp(datadir, dist, args.debug, args.test, args.nosound, args.silent) |
358 | + |
359 | Gtk.main() |
360 | - log.debug("Finishing ...") |
361 | + logger.debug("Finishing ...") |
362 | |
363 | === added directory 'build' |
364 | === added directory 'build/lib.linux-x86_64-2.7' |
365 | === added directory 'build/lib.linux-x86_64-2.7/kazam' |
366 | === added file 'build/lib.linux-x86_64-2.7/kazam/__init__.py' |
367 | --- build/lib.linux-x86_64-2.7/kazam/__init__.py 1970-01-01 00:00:00 +0000 |
368 | +++ build/lib.linux-x86_64-2.7/kazam/__init__.py 2012-11-15 10:17:01 +0000 |
369 | @@ -0,0 +1,1 @@ |
370 | + |
371 | |
372 | === added file 'build/lib.linux-x86_64-2.7/kazam/app.py' |
373 | --- build/lib.linux-x86_64-2.7/kazam/app.py 1970-01-01 00:00:00 +0000 |
374 | +++ build/lib.linux-x86_64-2.7/kazam/app.py 2012-11-15 10:17:01 +0000 |
375 | @@ -0,0 +1,748 @@ |
376 | +# -*- coding: utf-8 -*- |
377 | +# |
378 | +# app.py |
379 | +# |
380 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
381 | +# Copyright 2010 Andrew <andrew@karmic-desktop> |
382 | +# |
383 | +# This program is free software; you can redistribute it and/or modify |
384 | +# it under the terms of the GNU General Public License as published by |
385 | +# the Free Software Foundation; either version 3 of the License, or |
386 | +# (at your option) any later version. |
387 | +# |
388 | +# This program is distributed in the hope that it will be useful, |
389 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
390 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
391 | +# GNU General Public License for more details. |
392 | +# |
393 | +# You should have received a copy of the GNU General Public License |
394 | +# along with this program; if not, write to the Free Software |
395 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
396 | +# MA 02110-1301, USA. |
397 | + |
398 | +import os |
399 | +import sys |
400 | +import locale |
401 | +import shutil |
402 | +import gettext |
403 | +import logging |
404 | + |
405 | +from subprocess import Popen |
406 | +from gi.repository import Gtk, Gdk, GObject |
407 | +from gettext import gettext as _ |
408 | + |
409 | +from kazam.utils import * |
410 | +from kazam.backend.prefs import * |
411 | +from kazam.backend.constants import * |
412 | +from kazam.backend.grabber import Grabber |
413 | +from kazam.frontend.main_menu import MainMenu |
414 | +from kazam.frontend.window_area import AreaWindow |
415 | +from kazam.backend.gstreamer import Screencast |
416 | +from kazam.frontend.preferences import Preferences |
417 | +from kazam.frontend.about_dialog import AboutDialog |
418 | +from kazam.frontend.indicator import KazamIndicator |
419 | +from kazam.frontend.window_select import SelectWindow |
420 | +from kazam.frontend.done_recording import DoneRecording |
421 | +from kazam.frontend.window_countdown import CountdownWindow |
422 | + |
423 | +logger = logging.getLogger("Main") |
424 | + |
425 | +# |
426 | +# Detect GStreamer version and bail out if lower than 1.0 and no GI |
427 | +# |
428 | +try: |
429 | + from gi.repository import Gst |
430 | + gst_gi = Gst.version() |
431 | + if not gst_gi[0]: |
432 | + logger.critical("Gstreamer 1.0 or higher requred, bailing out.") |
433 | + gst_gi = None |
434 | + sys.exit(0) |
435 | + else: |
436 | + logger.debug("Gstreamer version detected: {0}.{1}.{2}.{3}".format(gst_gi[0], |
437 | + gst_gi[1], |
438 | + gst_gi[2], |
439 | + gst_gi[3])) |
440 | +except ImportError: |
441 | + logger.critical("Gstreamer 1.0 or higher requred, bailing out.") |
442 | + sys.exit(0) |
443 | + |
444 | +class KazamApp(GObject.GObject): |
445 | + |
446 | + def __init__(self, datadir, dist, debug, test, sound, silent): |
447 | + GObject.GObject.__init__(self) |
448 | + logger.debug("Setting variables.") |
449 | + |
450 | + prefs.datadir = datadir |
451 | + prefs.get_sound_files() |
452 | + |
453 | + self.startup = True |
454 | + prefs.debug = debug |
455 | + prefs.test = test |
456 | + prefs.dist = dist |
457 | + prefs.silent = silent |
458 | + prefs.sound = not sound # Parameter is called nosound and if true, then we don't have sound. |
459 | + # Tricky parameters are tricky! |
460 | + |
461 | + self.setup_translations() |
462 | + |
463 | + if prefs.sound: |
464 | + try: |
465 | + from kazam.pulseaudio.pulseaudio import pulseaudio_q |
466 | + prefs.sound = True |
467 | + except: |
468 | + logger.warning("Pulse Audio Failed to load. Sound recording disabled.") |
469 | + prefs.sound = False |
470 | + |
471 | + self.icons = Gtk.IconTheme.get_default() |
472 | + self.icons.append_search_path(os.path.join(prefs.datadir,"icons", "48x48", "apps")) |
473 | + self.icons.append_search_path(os.path.join(prefs.datadir,"icons", "16x16", "apps")) |
474 | + |
475 | + try: |
476 | + from gi.repository import Unity, Dbusmenu |
477 | + launcher = Unity.LauncherEntry.get_for_desktop_id("kazam.desktop") |
478 | + ql = Dbusmenu.Menuitem.new() |
479 | + ql_item1 = Dbusmenu.Menuitem.new() |
480 | + ql_item1.property_set(Dbusmenu.MENUITEM_PROP_LABEL, _("Record screencast")) |
481 | + ql_item1.property_set_bool(Dbusmenu.MENUITEM_PROP_VISIBLE, True) |
482 | + ql_item1.connect("item-activated", self.cb_ql_screencast) |
483 | + ql.child_append(ql_item1) |
484 | + ql_item2 = Dbusmenu.Menuitem.new() |
485 | + ql_item2.property_set(Dbusmenu.MENUITEM_PROP_LABEL, _("Take screenshot")) |
486 | + ql_item2.property_set_bool(Dbusmenu.MENUITEM_PROP_VISIBLE, True) |
487 | + ql_item2.connect("item-activated", self.cb_ql_screenshot) |
488 | + ql.child_append(ql_item2) |
489 | + ql_item3 = Dbusmenu.Menuitem.new() |
490 | + ql_item3.property_set(Dbusmenu.MENUITEM_PROP_LABEL, _("Preferences")) |
491 | + ql_item3.property_set_bool(Dbusmenu.MENUITEM_PROP_VISIBLE, True) |
492 | + ql_item3.connect("item-activated", self.cb_ql_preferences) |
493 | + ql.child_append(ql_item3) |
494 | + launcher.set_property("quicklist", ql) |
495 | + except ImportError: |
496 | + logger.warning("Unity and Dbusmenu not found. Skipping launcher integration.") |
497 | + |
498 | + # Initialize all the variables |
499 | + |
500 | + self.main_x = 0 |
501 | + self.main_y = 0 |
502 | + self.countdown = None |
503 | + self.tempfile = "" |
504 | + self.recorder = None |
505 | + self.area_window = None |
506 | + self.old_vid_path = None |
507 | + self.old_pic_path = None |
508 | + self.in_countdown = False |
509 | + self.recording_paused = False |
510 | + self.recording = False |
511 | + self.main_mode = 0 |
512 | + self.record_mode = 0 |
513 | + self.last_mode = None |
514 | + |
515 | + if prefs.sound: |
516 | + prefs.pa_q = pulseaudio_q() |
517 | + prefs.pa_q.start() |
518 | + |
519 | + self.mainmenu = MainMenu() |
520 | + |
521 | + logger.debug("Connecting indicator signals.") |
522 | + logger.debug("Starting in silent mode: {0}".format(prefs.silent)) |
523 | + self.indicator = KazamIndicator(prefs.silent) |
524 | + self.indicator.connect("indicator-quit-request", self.cb_quit_request) |
525 | + self.indicator.connect("indicator-show-request", self.cb_show_request) |
526 | + self.indicator.connect("indicator-start-request", self.cb_start_request) |
527 | + self.indicator.connect("indicator-stop-request", self.cb_stop_request) |
528 | + self.indicator.connect("indicator-pause-request", self.cb_pause_request) |
529 | + self.indicator.connect("indicator-unpause-request", self.cb_unpause_request) |
530 | + self.indicator.connect("indicator-about-request", self.cb_about_request) |
531 | + |
532 | + self.mainmenu.connect("file-quit", self.cb_quit_request) |
533 | + self.mainmenu.connect("file-preferences", self.cb_preferences_request) |
534 | + self.mainmenu.connect("help-about", self.cb_help_about) |
535 | + |
536 | + # |
537 | + # Setup UI |
538 | + # |
539 | + logger.debug("Main Window UI setup.") |
540 | + |
541 | + self.builder = Gtk.Builder() |
542 | + self.builder.add_from_file(os.path.join(prefs.datadir, "ui", "kazam.ui")) |
543 | + self.builder.connect_signals(self) |
544 | + for w in self.builder.get_objects(): |
545 | + if issubclass(type(w), Gtk.Buildable): |
546 | + name = Gtk.Buildable.get_name(w) |
547 | + setattr(self, name, w) |
548 | + else: |
549 | + logger.debug("Unable to get name for '%s'" % w) |
550 | + |
551 | + # Main Menu |
552 | + self.MainGrid.attach(self.mainmenu.menubar, 0, 0, 1, 1) |
553 | + |
554 | + self.context = self.toolbar_main.get_style_context() |
555 | + self.context.add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR) |
556 | + |
557 | + self.btn_cast = Gtk.RadioToolButton(group=None) |
558 | + self.btn_cast.set_label(_("Screencast")) |
559 | + self.btn_cast.set_tooltip_text(_("Record a video of your desktop.")) |
560 | + img1 = Gtk.Image.new_from_file(os.path.join(prefs.datadir, "icons", "light", "screencast.png")) |
561 | + self.btn_cast.set_icon_widget(img1) |
562 | + self.btn_cast.set_active(True) |
563 | + self.btn_cast.set_name("MAIN_SCREENCAST") |
564 | + self.btn_cast.connect("toggled", self.cb_main_toggled) |
565 | + |
566 | + self.btn_shot = Gtk.RadioToolButton(group=self.btn_cast) |
567 | + self.btn_shot.set_label(_("Screenshot")) |
568 | + self.btn_shot.set_tooltip_text(_("Record a picture of your desktop.")) |
569 | + img2 = Gtk.Image.new_from_file(os.path.join(prefs.datadir, "icons", "light", "screenshot-1.png")) |
570 | + self.btn_shot.set_icon_widget(img2) |
571 | + self.btn_shot.set_name("MAIN_SCREENSHOT") |
572 | + self.btn_shot.connect("toggled", self.cb_main_toggled) |
573 | + |
574 | + self.sep_1 = Gtk.SeparatorToolItem() |
575 | + self.sep_1.set_draw(False) |
576 | + self.sep_1.set_expand(True) |
577 | + self.toolbar_main.insert(self.sep_1, -1) |
578 | + self.toolbar_main.insert(self.btn_cast, -1) |
579 | + self.toolbar_main.insert(self.btn_shot, -1) |
580 | + self.toolbar_main.insert(self.sep_1, -1) |
581 | + |
582 | + # Auxiliary toolbar |
583 | + self.btn_full = Gtk.RadioToolButton(group=None) |
584 | + self.btn_full.set_label(_("Fullscreen")) |
585 | + self.btn_full.set_tooltip_text(_("Capture contents of the current screen.")) |
586 | + img3 = Gtk.Image.new_from_file(os.path.join(prefs.datadir, "icons", "dark", "fullscreen.png")) |
587 | + self.btn_full.set_icon_widget(img3) |
588 | + self.btn_full.set_active(True) |
589 | + self.btn_full.set_name("MODE_FULL") |
590 | + self.btn_full.connect("toggled", self.cb_record_mode_toggled) |
591 | + |
592 | + self.btn_allscreens = Gtk.RadioToolButton(group=self.btn_full) |
593 | + self.btn_allscreens.set_label(_("All Screens")) |
594 | + self.btn_allscreens.set_tooltip_text(_("Capture contents of all of your screens.")) |
595 | + img4 = Gtk.Image.new_from_file(os.path.join(prefs.datadir, "icons", "dark", "all-screens.png")) |
596 | + self.btn_allscreens.set_icon_widget(img4) |
597 | + self.btn_allscreens.set_name("MODE_ALL") |
598 | + self.btn_allscreens.connect("toggled", self.cb_record_mode_toggled) |
599 | + |
600 | + self.btn_window = Gtk.RadioToolButton(group=self.btn_full) |
601 | + self.btn_window.set_label(_("Window")) |
602 | + self.btn_window.set_tooltip_text(_("Capture contents of a single window.")) |
603 | + img5 = Gtk.Image.new_from_file(os.path.join(prefs.datadir, "icons", "dark", "window.png")) |
604 | + self.btn_window.set_icon_widget(img5) |
605 | + self.btn_window.set_name("MODE_WIN") |
606 | + self.btn_window.connect("toggled", self.cb_record_mode_toggled) |
607 | + self.btn_window.connect("clicked", self.cb_record_window_clicked) |
608 | + |
609 | + self.btn_area = Gtk.RadioToolButton(group=self.btn_full) |
610 | + self.btn_area.set_label(_("Area")) |
611 | + self.btn_area.set_tooltip_text(_("Capture a pre-selected area of your screen.")) |
612 | + img6 = Gtk.Image.new_from_file(os.path.join(prefs.datadir, "icons", "dark", "area.png")) |
613 | + self.btn_area.set_icon_widget(img6) |
614 | + self.btn_area.set_name("MODE_AREA") |
615 | + self.btn_area.connect("toggled", self.cb_record_mode_toggled) |
616 | + self.btn_area.connect("clicked", self.cb_record_area_clicked) |
617 | + |
618 | + self.sep_2 = Gtk.SeparatorToolItem() |
619 | + self.sep_2.set_draw(False) |
620 | + self.sep_2.set_expand(True) |
621 | + #self.toolbar_aux.insert(self.sep_2, -1) |
622 | + self.toolbar_aux.insert(self.btn_full, -1) |
623 | + self.toolbar_aux.insert(self.btn_allscreens, -1) |
624 | + self.toolbar_aux.insert(self.btn_window, -1) |
625 | + self.toolbar_aux.insert(self.btn_area, -1) |
626 | + #self.toolbar_aux.insert(self.sep_2, -1) |
627 | + |
628 | + self.ntb_main.set_current_page(0) |
629 | + |
630 | + # |
631 | + # Take care of screen size changes. |
632 | + # |
633 | + self.default_screen = Gdk.Screen.get_default() |
634 | + self.default_screen.connect("size-changed", self.cb_screen_size_changed) |
635 | + self.window.connect("configure-event", self.cb_configure_event) |
636 | + |
637 | + # Fetch sources info, take care of all the widgets and saved settings and show main window |
638 | + if prefs.sound: |
639 | + prefs.get_audio_sources() |
640 | + |
641 | + if not prefs.silent: |
642 | + self.window.show_all() |
643 | + else: |
644 | + logger.info("""Starting in silent mode:\n""" |
645 | + """ SUPER-CTRL-W to toggle main window.\n""" |
646 | + """ SUPER-CTRL-R to start recording.\n""" |
647 | + """ SUPER-CTRL-F to finish recording.\n""" |
648 | + """ SUPER-CTRL-P to pause/resume recording.\n""" |
649 | + """ SUPER-CTRL-Q to quit.\n""" |
650 | + ) |
651 | + |
652 | + self.restore_UI() |
653 | + |
654 | + if not prefs.sound: |
655 | + self.combobox_audio.set_sensitive(False) |
656 | + self.combobox_audio2.set_sensitive(False) |
657 | + self.volumebutton_audio.set_sensitive(False) |
658 | + self.volumebutton_audio2.set_sensitive(False) |
659 | + |
660 | + HW.get_current_screen(self.window) |
661 | + self.startup = False |
662 | + |
663 | + # |
664 | + # Callbacks, go down here ... |
665 | + # |
666 | + |
667 | + # |
668 | + # Mode of operation toggles |
669 | + # |
670 | + |
671 | + def cb_main_toggled(self, widget): |
672 | + name = widget.get_name() |
673 | + if name == "MAIN_SCREENCAST" and widget.get_active(): |
674 | + logger.debug("Main toggled: {0}".format(name)) |
675 | + self.main_mode = MODE_SCREENCAST |
676 | + self.ntb_main.set_current_page(0) |
677 | + self.indicator.menuitem_start.set_label(_("Start recording")) |
678 | + |
679 | + elif name == "MAIN_SCREENSHOT" and widget.get_active(): |
680 | + logger.debug("Main toggled: {0}".format(name)) |
681 | + self.main_mode = MODE_SCREENSHOT |
682 | + self.ntb_main.set_current_page(1) |
683 | + if self.record_mode == MODE_WIN: |
684 | + self.last_mode.set_active(True) |
685 | + self.indicator.menuitem_start.set_label(_("Take screenshot")) |
686 | + |
687 | + # |
688 | + # Record mode toggles |
689 | + # |
690 | + def cb_record_mode_toggled(self, widget): |
691 | + if widget.get_active(): |
692 | + self.current_mode = widget |
693 | + else: |
694 | + self.last_mode = widget |
695 | + |
696 | + if widget.get_name() == "MODE_AREA" and widget.get_active(): |
697 | + logger.debug("Area ON.") |
698 | + self.area_window = AreaWindow() |
699 | + self.tmp_sig1 = self.area_window.connect("area-selected", self.cb_area_selected) |
700 | + self.tmp_sig2 = self.area_window.connect("area-canceled", self.cb_area_canceled) |
701 | + self.record_mode = MODE_AREA |
702 | + |
703 | + if widget.get_name() == "MODE_AREA" and not widget.get_active(): |
704 | + logger.debug("Area OFF.") |
705 | + if self.area_window: |
706 | + self.area_window.disconnect(self.tmp_sig1) |
707 | + self.area_window.disconnect(self.tmp_sig2) |
708 | + self.area_window.window.destroy() |
709 | + self.area_window = None |
710 | + |
711 | + if widget.get_name() == "MODE_FULL" and widget.get_active(): |
712 | + logger.debug("Capture full screen.") |
713 | + self.record_mode = MODE_FULL |
714 | + |
715 | + if widget.get_name() == "MODE_ALL" and widget.get_active(): |
716 | + logger.debug("Capture all screens.") |
717 | + self.record_mode = MODE_ALL |
718 | + |
719 | + if widget.get_name() == "MODE_WIN" and widget.get_active(): |
720 | + logger.debug("Window capture ON.") |
721 | + self.select_window = SelectWindow() |
722 | + self.tmp_sig3 = self.select_window.connect("window-selected", self.cb_window_selected) |
723 | + self.tmp_sig4 = self.select_window.connect("window-canceled", self.cb_window_canceled) |
724 | + self.record_mode = MODE_WIN |
725 | + |
726 | + if widget.get_name() == "MODE_WIN" and not widget.get_active(): |
727 | + logger.debug("Window capture OFF.") |
728 | + if self.select_window: |
729 | + self.select_window.disconnect(self.tmp_sig3) |
730 | + self.select_window.disconnect(self.tmp_sig4) |
731 | + self.select_window.window.destroy() |
732 | + self.select_window = None |
733 | + |
734 | + |
735 | + # |
736 | + # Unity quick list callbacks |
737 | + # |
738 | + |
739 | + def cb_ql_screencast(self, menu, data): |
740 | + logger.debug("Screencast quicklist activated.") |
741 | + self.btn_cast.set_active(True) |
742 | + self.run_counter() |
743 | + |
744 | + def cb_ql_screenshot(self, menu, data): |
745 | + logger.debug("Screenshot quicklist activated.") |
746 | + self.btn_shot.set_active(True) |
747 | + self.run_counter() |
748 | + |
749 | + def cb_ql_preferences(self, menu, data): |
750 | + logger.debug("Preferences quicklist activated.") |
751 | + self.cb_preferences_request(None) |
752 | + |
753 | + def cb_record_area_clicked(self, widget): |
754 | + if self.area_window: |
755 | + logger.debug("Area mode clicked.") |
756 | + self.area_window.window.show_all() |
757 | + self.window.set_sensitive(False) |
758 | + |
759 | + def cb_record_window_clicked(self, widget): |
760 | + if self.select_window: |
761 | + logger.debug("Window mode clicked.") |
762 | + self.select_window.window.show_all() |
763 | + self.window.set_sensitive(False) |
764 | + |
765 | + def cb_area_selected(self, widget): |
766 | + logger.debug("Area selected: SX: {0}, SY: {1}, EX: {2}, EY: {3}".format( |
767 | + self.area_window.startx, |
768 | + self.area_window.starty, |
769 | + self.area_window.endx, |
770 | + self.area_window.endy)) |
771 | + self.window.set_sensitive(True) |
772 | + prefs.area = (self.area_window.startx, |
773 | + self.area_window.starty, |
774 | + self.area_window.endx, |
775 | + self.area_window.endy, |
776 | + self.area_window.width, |
777 | + self.area_window.height) |
778 | + |
779 | + def cb_area_canceled(self, widget): |
780 | + logger.debug("Area selection canceled.") |
781 | + self.window.set_sensitive(True) |
782 | + self.last_mode.set_active(True) |
783 | + |
784 | + def cb_window_selected(self, widget): |
785 | + prefs.xid = self.select_window.xid |
786 | + prefs.xid_geometry = self.select_window.geometry |
787 | + logger.debug("Window selected: {0} - {1}".format(self.select_window.win_name, prefs.xid)) |
788 | + logger.debug("Window geometry: {0}".format(self.select_window.geometry)) |
789 | + self.window.set_sensitive(True) |
790 | + |
791 | + def cb_window_canceled(self, widget): |
792 | + logger.debug("Window selection canceled.") |
793 | + self.window.set_sensitive(True) |
794 | + self.last_mode.set_active(True) |
795 | + |
796 | + def cb_screen_size_changed(self, screen): |
797 | + logger.debug("Screen size changed.") |
798 | + HW.get_screens() |
799 | + # |
800 | + # I combined screen was set to none, turn off the button for all screens |
801 | + # |
802 | + if HW.combined_screen: |
803 | + self.btn_allscreens.set_sensitive(True) |
804 | + else: |
805 | + self.btn_allscreens.set_sensitive(False) |
806 | + |
807 | + |
808 | + def cb_configure_event(self, widget, event): |
809 | + if event.type == Gdk.EventType.CONFIGURE: |
810 | + prefs.main_x = event.x |
811 | + prefs.main_y = event.y |
812 | + |
813 | + def cb_quit_request(self, indicator): |
814 | + logger.debug("Quit requested.") |
815 | + (prefs.main_x, prefs.main_y) = self.window.get_position() |
816 | + try: |
817 | + os.remove(self.recorder.tempfile) |
818 | + os.remove("{0}.mux".format(self.recorder.tempfile)) |
819 | + except OSError: |
820 | + logger.info("Unable to delete one of the temporary files. Check your temporary directory.") |
821 | + except AttributeError: |
822 | + pass |
823 | + |
824 | + prefs.save_config() |
825 | + |
826 | + if prefs.sound: |
827 | + prefs.pa_q.end() |
828 | + |
829 | + Gtk.main_quit() |
830 | + |
831 | + def cb_preferences_request(self, indicator): |
832 | + logger.debug("Preferences requested.") |
833 | + self.preferences_window = Preferences() |
834 | + self.preferences_window.open() |
835 | + |
836 | + def cb_show_request(self, indicator): |
837 | + if not self.window.get_property("visible"): |
838 | + logger.debug("Show requested, raising window.") |
839 | + self.window.show_all() |
840 | + self.window.present() |
841 | + self.window.move(prefs.main_x, prefs.main_y) |
842 | + else: |
843 | + self.window.hide() |
844 | + |
845 | + def cb_close_clicked(self, indicator): |
846 | + (prefs.main_x, prefs.main_y) = self.window.get_position() |
847 | + self.window.hide() |
848 | + |
849 | + def cb_about_request(self, activated): |
850 | + AboutDialog(self.icons) |
851 | + |
852 | + def cb_delete_event(self, widget, user_data): |
853 | + self.cb_quit_request(None) |
854 | + |
855 | + def cb_start_request(self, widget): |
856 | + logger.debug("Start recording selected.") |
857 | + self.run_counter() |
858 | + |
859 | + def cb_record_clicked(self, widget): |
860 | + logger.debug("Record clicked, invoking Screencast.") |
861 | + self.run_counter() |
862 | + |
863 | + def cb_counter_finished(self, widget): |
864 | + logger.debug("Counter finished.") |
865 | + self.in_countdown = False |
866 | + self.countdown = None |
867 | + self.indicator.blink_set_state(BLINK_STOP) |
868 | + if self.main_mode == MODE_SCREENCAST: |
869 | + self.indicator.menuitem_finish.set_label(_("Finish recording")) |
870 | + self.indicator.menuitem_pause.set_sensitive(True) |
871 | + self.indicator.start_recording() |
872 | + self.recorder.start_recording() |
873 | + elif self.main_mode == MODE_SCREENSHOT: |
874 | + self.indicator.hide_it() |
875 | + self.grabber.grab() |
876 | + self.indicator.show_it() |
877 | + |
878 | + def cb_stop_request(self, widget): |
879 | + self.recording = False |
880 | + if self.in_countdown: |
881 | + logger.debug("Cancel countdown request.") |
882 | + self.countdown.cancel_countdown() |
883 | + self.countdown = None |
884 | + self.indicator.menuitem_finish.set_label(_("Finish recording")) |
885 | + self.window.set_sensitive(True) |
886 | + self.window.show() |
887 | + self.window.present() |
888 | + else: |
889 | + if self.recording_paused: |
890 | + self.recorder.unpause_recording() |
891 | + logger.debug("Stop request.") |
892 | + self.recorder.stop_recording() |
893 | + self.tempfile = self.recorder.get_tempfile() |
894 | + logger.debug("Recorded tmp file: {0}".format(self.tempfile)) |
895 | + logger.debug("Waiting for data to flush.") |
896 | + |
897 | + def cb_flush_done(self, widget): |
898 | + if self.main_mode == MODE_SCREENCAST and prefs.autosave_video: |
899 | + logger.debug("Autosaving enabled.") |
900 | + fname = get_next_filename(prefs.video_dest, |
901 | + prefs.autosave_video_file, |
902 | + CODEC_LIST[prefs.codec][3]) |
903 | + |
904 | + shutil.move(self.tempfile, fname) |
905 | + |
906 | + self.window.set_sensitive(True) |
907 | + self.window.show() |
908 | + self.window.present() |
909 | + elif self.main_mode == MODE_SCREENCAST: |
910 | + self.done_recording = DoneRecording(self.icons, |
911 | + self.tempfile, |
912 | + prefs.codec, |
913 | + self.old_vid_path) |
914 | + logger.debug("Done Recording initialized.") |
915 | + self.done_recording.connect("save-done", self.cb_save_done) |
916 | + self.done_recording.connect("save-cancel", self.cb_save_cancel) |
917 | + self.done_recording.connect("edit-request", self.cb_edit_request) |
918 | + logger.debug("Done recording signals connected.") |
919 | + self.done_recording.show_all() |
920 | + self.window.set_sensitive(False) |
921 | + |
922 | + elif self.main_mode == MODE_SCREENSHOT: |
923 | + self.grabber.connect("save-done", self.cb_save_done) |
924 | + self.indicator.recording = False |
925 | + self.indicator.menuitem_start.set_sensitive(True) |
926 | + self.indicator.menuitem_pause.set_sensitive(False) |
927 | + self.indicator.menuitem_pause.set_active(False) |
928 | + self.indicator.menuitem_finish.set_sensitive(False) |
929 | + self.indicator.menuitem_show.set_sensitive(True) |
930 | + self.indicator.menuitem_quit.set_sensitive(True) |
931 | + |
932 | + if prefs.autosave_picture: |
933 | + fname = get_next_filename(prefs.picture_dest, prefs.autosave_picture_file, ".png") |
934 | + self.grabber.autosave(fname) |
935 | + else: |
936 | + self.grabber.save_capture(self.old_pic_path) |
937 | + |
938 | + |
939 | + def cb_pause_request(self, widget): |
940 | + logger.debug("Pause requested.") |
941 | + self.recording_paused = True |
942 | + self.recorder.pause_recording() |
943 | + |
944 | + def cb_unpause_request(self, widget): |
945 | + logger.debug("Unpause requested.") |
946 | + self.recording_paused = False |
947 | + self.recorder.unpause_recording() |
948 | + |
949 | + def cb_save_done(self, widget, result): |
950 | + logger.debug("Save Done, result: {0}".format(result)) |
951 | + if self.main_mode == MODE_SCREENCAST: |
952 | + self.old_vid_path = result |
953 | + else: |
954 | + self.old_pic_path = result |
955 | + |
956 | + self.window.set_sensitive(True) |
957 | + self.window.show_all() |
958 | + self.window.present() |
959 | + self.window.move(prefs.main_x, prefs.main_y) |
960 | + |
961 | + def cb_save_cancel(self, widget): |
962 | + try: |
963 | + logger.debug("Save canceled, removing {0}".format(self.tempfile)) |
964 | + os.remove(self.tempfile) |
965 | + except OSError: |
966 | + logger.info("Failed to remove tempfile {0}".format(self.tempfile)) |
967 | + except AttributeError: |
968 | + logger.info("Failed to remove tempfile {0}".format(self.tempfile)) |
969 | + pass |
970 | + |
971 | + self.window.set_sensitive(True) |
972 | + self.window.show_all() |
973 | + self.window.present() |
974 | + self.window.move(prefs.main_x, prefs.main_y) |
975 | + |
976 | + def cb_help_about(self, widget): |
977 | + AboutDialog(self.icons) |
978 | + |
979 | + def cb_edit_request(self, widget, data): |
980 | + (command, arg_list) = data |
981 | + arg_list.insert(0, command) |
982 | + # |
983 | + # Even if we're not autosaving get the next autosave file and move currently recorded file there |
984 | + # In case user might lost it. |
985 | + # |
986 | + fname = get_next_filename(prefs.video_dest, |
987 | + prefs.autosave_video_file, |
988 | + CODEC_LIST[prefs.codec][3]) |
989 | + |
990 | + shutil.move(self.tempfile, fname) |
991 | + arg_list.append(fname) |
992 | + logger.debug("Edit request, cmd: {0}".format(arg_list)) |
993 | + try: |
994 | + Popen(arg_list) |
995 | + except: |
996 | + logger.warning("Failed to open selected editor. Have no ") |
997 | + self.window.set_sensitive(True) |
998 | + self.window.show_all() |
999 | + |
1000 | + def cb_check_cursor(self, widget): |
1001 | + prefs.capture_cursor = widget.get_active() |
1002 | + logger.debug("Capture cursor: {0}.".format(prefs.capture_cursor)) |
1003 | + |
1004 | + def cb_check_cursor_pic(self, widget): |
1005 | + prefs.capture_cursor_pic = widget.get_active() |
1006 | + logger.debug("Capture cursor_pic: {0}.".format(prefs.capture_cursor_pic)) |
1007 | + |
1008 | + def cb_check_borders_pic(self, widget): |
1009 | + prefs.capture_borders_pic = widget.get_active() |
1010 | + logger.debug("Capture borders_pic: {0}.".format(prefs.capture_borders_pic)) |
1011 | + |
1012 | + def cb_check_speakers(self, widget): |
1013 | + prefs.capture_speakers = widget.get_active() |
1014 | + logger.debug("Capture speakers: {0}.".format(prefs.capture_speakers)) |
1015 | + |
1016 | + def cb_check_microphone(self, widget): |
1017 | + prefs.capture_microphone = widget.get_active() |
1018 | + logger.debug("Capture microphone: {0}.".format(prefs.capture_microphone)) |
1019 | + |
1020 | + def cb_spinbutton_delay_change(self, widget): |
1021 | + prefs.countdown_timer = widget.get_value_as_int() |
1022 | + logger.debug("Start delay now: {0}".format(prefs.countdown_timer)) |
1023 | + |
1024 | + # |
1025 | + # Other somewhat useful stuff ... |
1026 | + # |
1027 | + |
1028 | + def run_counter(self): |
1029 | + # |
1030 | + # Annoyances with the menus |
1031 | + # |
1032 | + (main_x, main_y) = self.window.get_position() |
1033 | + if main_x and main_y: |
1034 | + prefs.main_x = main_x |
1035 | + prefs.main_y = main_y |
1036 | + |
1037 | + self.indicator.recording = True |
1038 | + self.indicator.menuitem_start.set_sensitive(False) |
1039 | + self.indicator.menuitem_pause.set_sensitive(False) |
1040 | + self.indicator.menuitem_finish.set_sensitive(True) |
1041 | + self.indicator.menuitem_show.set_sensitive(False) |
1042 | + self.indicator.menuitem_quit.set_sensitive(False) |
1043 | + self.indicator.menuitem_finish.set_label(_("Cancel countdown")) |
1044 | + self.in_countdown = True |
1045 | + |
1046 | + self.indicator.blink_set_state(BLINK_START) |
1047 | + |
1048 | + if self.main_mode == MODE_SCREENCAST and prefs.sound: |
1049 | + if prefs.capture_speakers and prefs.audio_source > 0: |
1050 | + audio_source = prefs.audio_sources[prefs.audio_source][1] |
1051 | + else: |
1052 | + audio_source = None |
1053 | + |
1054 | + if prefs.capture_microphone and prefs.audio2_source > 0: |
1055 | + audio2_source = prefs.audio_sources[prefs.audio2_source][1] |
1056 | + else: |
1057 | + audio2_source = None |
1058 | + else: |
1059 | + audio_source = None |
1060 | + audio2_source = None |
1061 | + |
1062 | + # |
1063 | + # Get appropriate coordinates for recording |
1064 | + # |
1065 | + |
1066 | + video_source = None |
1067 | + |
1068 | + if self.record_mode == MODE_FULL: |
1069 | + screen = HW.get_current_screen(self.window) |
1070 | + video_source = HW.screens[screen] |
1071 | + else: |
1072 | + video_source = HW.combined_screen |
1073 | + |
1074 | + if self.main_mode == MODE_SCREENCAST: |
1075 | + self.recorder = Screencast() |
1076 | + self.recorder.setup_sources(video_source, |
1077 | + audio_source, |
1078 | + audio2_source, |
1079 | + prefs.area if self.record_mode == MODE_AREA else None, |
1080 | + prefs.xid if self.record_mode == MODE_WIN else None) |
1081 | + |
1082 | + self.recorder.connect("flush-done", self.cb_flush_done) |
1083 | + |
1084 | + elif self.main_mode == MODE_SCREENSHOT: |
1085 | + self.grabber = Grabber() |
1086 | + self.grabber.setup_sources(video_source, |
1087 | + prefs.area if self.record_mode == MODE_AREA else None, |
1088 | + prefs.xid if self.record_mode == MODE_WIN else None) |
1089 | + self.grabber.connect("flush-done", self.cb_flush_done) |
1090 | + |
1091 | + |
1092 | + self.countdown = CountdownWindow(self.indicator, show_window = prefs.countdown_splash) |
1093 | + self.countdown.connect("counter-finished", self.cb_counter_finished) |
1094 | + self.countdown.run(prefs.countdown_timer) |
1095 | + self.recording = True |
1096 | + logger.debug("Hiding main window.") |
1097 | + self.window.hide() |
1098 | + |
1099 | + def setup_translations(self): |
1100 | + gettext.bindtextdomain("kazam", "/usr/share/locale") |
1101 | + gettext.textdomain("kazam") |
1102 | + try: |
1103 | + locale.setlocale(locale.LC_ALL, "") |
1104 | + except Exception as e: |
1105 | + logger.exception("EXCEPTION: Setlocale failed, no language support.") |
1106 | + |
1107 | + |
1108 | + def restore_UI (self): |
1109 | + self.window.move(prefs.main_x, prefs.main_y) |
1110 | + self.chk_cursor.set_active(prefs.capture_cursor) |
1111 | + self.chk_speakers.set_active(prefs.capture_speakers) |
1112 | + self.chk_microphone.set_active(prefs.capture_microphone) |
1113 | + self.chk_cursor_pic.set_active(prefs.capture_cursor_pic) |
1114 | + self.chk_borders_pic.set_active(prefs.capture_borders_pic) |
1115 | + self.spinbutton_delay.set_value(prefs.countdown_timer) |
1116 | + |
1117 | + # |
1118 | + # Turn off the combined screen icon if we don't have more than one screen. |
1119 | + # |
1120 | + if HW.combined_screen: |
1121 | + self.btn_allscreens.set_sensitive(True) |
1122 | + else: |
1123 | + self.btn_allscreens.set_sensitive(False) |
1124 | |
1125 | === added directory 'build/lib.linux-x86_64-2.7/kazam/backend' |
1126 | === added file 'build/lib.linux-x86_64-2.7/kazam/backend/__init__.py' |
1127 | --- build/lib.linux-x86_64-2.7/kazam/backend/__init__.py 1970-01-01 00:00:00 +0000 |
1128 | +++ build/lib.linux-x86_64-2.7/kazam/backend/__init__.py 2012-11-15 10:17:01 +0000 |
1129 | @@ -0,0 +1,1 @@ |
1130 | + |
1131 | |
1132 | === added file 'build/lib.linux-x86_64-2.7/kazam/backend/config.py' |
1133 | --- build/lib.linux-x86_64-2.7/kazam/backend/config.py 1970-01-01 00:00:00 +0000 |
1134 | +++ build/lib.linux-x86_64-2.7/kazam/backend/config.py 2012-11-15 10:17:01 +0000 |
1135 | @@ -0,0 +1,128 @@ |
1136 | +# -*- coding: utf-8 -*- |
1137 | +# |
1138 | +# config.py |
1139 | +# |
1140 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
1141 | +# Copyright 2010 Andrew <andrew@karmic-desktop> |
1142 | +# |
1143 | +# This program is free software; you can redistribute it and/or modify |
1144 | +# it under the terms of the GNU General Public License as published by |
1145 | +# the Free Software Foundation; either version 3 of the License, or |
1146 | +# (at your option) any later version. |
1147 | +# |
1148 | +# This program is distributed in the hope that it will be useful, |
1149 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1150 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1151 | +# GNU General Public License for more details. |
1152 | +# |
1153 | +# You should have received a copy of the GNU General Public License |
1154 | +# along with this program; if not, write to the Free Software |
1155 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
1156 | +# MA 02110-1301, USA. |
1157 | + |
1158 | +import os |
1159 | +from ConfigParser import SafeConfigParser, NoSectionError, NoOptionError |
1160 | +from xdg.BaseDirectory import xdg_config_home |
1161 | + |
1162 | +class KazamConfig(SafeConfigParser): |
1163 | + |
1164 | + DEFAULTS = [{ |
1165 | + "name": "main", |
1166 | + "keys": { |
1167 | + "video_toggled" : "True", |
1168 | + "video_source" : "0", |
1169 | + "audio_toggled" : "False", |
1170 | + "audio_source" : "0", |
1171 | + "audio_volume" : "0", |
1172 | + "audio2_toggled" : "False", |
1173 | + "audio2_source" : "0", |
1174 | + "audio2_volume" : "0", |
1175 | + "codec" : "0", |
1176 | + "counter" : "5", |
1177 | + "capture_cursor" : "True", |
1178 | + "capture_microphone" : "False", |
1179 | + "capture_speakers" : "False", |
1180 | + "capture_cursor_pic" : "True", |
1181 | + "capture_borders_pic" : "True", |
1182 | + "framerate" : "15", |
1183 | + "countdown_splash" : "True", |
1184 | + "last_x" : "60", |
1185 | + "last_y" : "25", |
1186 | + "advanced" : "0", |
1187 | + "silent" : "0", |
1188 | + "autosave_video" : "False", |
1189 | + "autosave_video_dir" : "", |
1190 | + "autosave_video_file" : "Kazam_screencast", |
1191 | + "autosave_picture" : "False", |
1192 | + "autosave_picture_dir" : "", |
1193 | + "autosave_picture_file" : "Kazam_screenshot", |
1194 | + "shutter_sound" : "True", |
1195 | + "shutter_type" : "0", |
1196 | + }, |
1197 | + }, |
1198 | + { |
1199 | + "name": "keyboard_shortcuts", |
1200 | + "keys": { |
1201 | + "pause": "<Shift><Control>p", |
1202 | + "finish": "<Shift><Control>f", |
1203 | + "show": "<Shift><Control>s", |
1204 | + "quit": "<Shift><Control>q", |
1205 | + }, |
1206 | + }] |
1207 | + |
1208 | + CONFIGDIR = os.path.join(xdg_config_home, "kazam") |
1209 | + CONFIGFILE = os.path.join(CONFIGDIR, "kazam.conf") |
1210 | + |
1211 | + def __init__(self): |
1212 | + SafeConfigParser.__init__(self, self.DEFAULTS[0]['keys']) |
1213 | + if not os.path.isdir(self.CONFIGDIR): |
1214 | + os.makedirs(self.CONFIGDIR) |
1215 | + if not os.path.isfile(self.CONFIGFILE): |
1216 | + self.create_default() |
1217 | + self.write() |
1218 | + self.read(self.CONFIGFILE) |
1219 | + |
1220 | + def create_default(self): |
1221 | + # For every section |
1222 | + for section in self.DEFAULTS: |
1223 | + # Add the section |
1224 | + self.add_section(section["name"]) |
1225 | + # And add every key in it, with its default value |
1226 | + for key in section["keys"]: |
1227 | + value = section["keys"][key] |
1228 | + self.set(section["name"], key, value) |
1229 | + |
1230 | + def find_default(self, section, key): |
1231 | + for d_section in self.DEFAULTS: |
1232 | + if d_section["name"] == section: |
1233 | + for d_key in d_section["keys"]: |
1234 | + if d_key == key: |
1235 | + return d_section["keys"][key] |
1236 | + |
1237 | + def get(self, section, key): |
1238 | + try: |
1239 | + return SafeConfigParser.get(self, section, key) |
1240 | + except NoSectionError: |
1241 | + default = self.find_default(section, key) |
1242 | + self.set(section, key, default) |
1243 | + self.write() |
1244 | + return default |
1245 | + except NoOptionError: |
1246 | + default = self.find_default(section, key) |
1247 | + self.set(section, key, default) |
1248 | + self.write() |
1249 | + return default |
1250 | + |
1251 | + def set(self, section, option, value): |
1252 | + # If the section referred to doesn't exist (rare case), |
1253 | + # then create it |
1254 | + if not self.has_section(section): |
1255 | + self.add_section(section) |
1256 | + SafeConfigParser.set(self, section, option, str(value)) |
1257 | + |
1258 | + def write(self): |
1259 | + file_ = open(self.CONFIGFILE, "w") |
1260 | + SafeConfigParser.write(self, file_) |
1261 | + file_.close() |
1262 | + |
1263 | + |
1264 | |
1265 | === added file 'build/lib.linux-x86_64-2.7/kazam/backend/constants.py' |
1266 | --- build/lib.linux-x86_64-2.7/kazam/backend/constants.py 1970-01-01 00:00:00 +0000 |
1267 | +++ build/lib.linux-x86_64-2.7/kazam/backend/constants.py 2012-11-15 10:17:01 +0000 |
1268 | @@ -0,0 +1,152 @@ |
1269 | +# -*- coding: utf-8 -*- |
1270 | +# |
1271 | +# constants.py |
1272 | +# |
1273 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
1274 | +# |
1275 | +# This program is free software; you can redistribute it and/or modify |
1276 | +# it under the terms of the GNU General Public License as published by |
1277 | +# the Free Software Foundation; either version 3 of the License, or |
1278 | +# (at your option) any later version. |
1279 | +# |
1280 | +# This program is distributed in the hope that it will be useful, |
1281 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1282 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1283 | +# GNU General Public License for more details. |
1284 | +# |
1285 | +# You should have received a copy of the GNU General Public License |
1286 | +# along with this program; if not, write to the Free Software |
1287 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
1288 | +# MA 02110-1301, USA. |
1289 | + |
1290 | + |
1291 | +# Codecs |
1292 | + |
1293 | +CODEC_RAW = 0 |
1294 | +CODEC_VP8 = 1 |
1295 | +CODEC_H264 = 2 |
1296 | +CODEC_HUFF = 3 |
1297 | +CODEC_JPEG = 4 |
1298 | + |
1299 | +# |
1300 | +# Number, gstreamer element name, string description, file extension, advanced |
1301 | +# |
1302 | + |
1303 | +CODEC_LIST = [ |
1304 | + [0, None, 'RAW / AVI', '.avi', True], |
1305 | + [1, 'vp8enc', 'VP8 / WEBM', '.webm', False], |
1306 | + [2, 'x264enc', 'H264 / MP4', '.mp4', False], |
1307 | + [3, 'ffenc_huffyuv', 'HUFFYUV / AVI', '.avi', True], |
1308 | + [4, 'ffenc_ljpeg', 'Lossless JPEG / AVI', '.avi', True], |
1309 | + ] |
1310 | + |
1311 | +# PulseAudio Error Codes |
1312 | +PA_LOAD_ERROR = 1 |
1313 | +PA_GET_STATE_ERROR = 2 |
1314 | +PA_STARTUP_ERROR = 3 |
1315 | +PA_UNABLE_TO_CONNECT = 4 |
1316 | +PA_UNABLE_TO_CONNECT2 = 5 |
1317 | +PA_MAINLOOP_START_ERROR = 6 |
1318 | +PA_GET_SOURCES_ERROR = 7 |
1319 | +PA_GET_SOURCES_TIMEOUT = 8 |
1320 | +PA_GET_SOURCE_ERROR = 9 |
1321 | +PA_GET_SOURCE_TIMEOUT = 10 |
1322 | +PA_MAINLOOP_END_ERROR = 11 |
1323 | + |
1324 | + |
1325 | +# PulseAudio Status Codes |
1326 | +PA_STOPPED = 0 |
1327 | +PA_WORKING = 1 |
1328 | +PA_FINISHED = 2 |
1329 | +PA_ERROR = 3 |
1330 | + |
1331 | +# PulseAudio State Codes |
1332 | +PA_STATE_READY = 0 |
1333 | +PA_STATE_BUSY = 1 |
1334 | +PA_STATE_FAILED = 2 |
1335 | +PA_STATE_WORKING = 3 |
1336 | + |
1337 | + |
1338 | +# Various actions |
1339 | +ACTION_SAVE = 0 |
1340 | +ACTION_EDIT = 1 |
1341 | + |
1342 | +# Blink modes and states |
1343 | +BLINK_STOP = 0 |
1344 | +BLINK_START = 1 |
1345 | +BLINK_SLOW = 2 |
1346 | +BLINK_FAST = 3 |
1347 | +BLINK_STOP_ICON = 4 |
1348 | +BLINK_READY_ICON = 5 |
1349 | + |
1350 | +# Main modes |
1351 | +MODE_SCREENCAST = 0 |
1352 | +MODE_SCREENSHOT = 1 |
1353 | + |
1354 | +# Record modes |
1355 | +MODE_FULL = 0 |
1356 | +MODE_ALL = 1 |
1357 | +MODE_AREA = 2 |
1358 | +MODE_WIN = 3 |
1359 | +MODE_ACTIVE = 4 |
1360 | +MODE_GOD = 666 |
1361 | + |
1362 | +import logging |
1363 | + |
1364 | +from gi.repository import Gdk, GdkX11 |
1365 | + |
1366 | +class hw: |
1367 | + def __init__(self): |
1368 | + self.logger = logging.getLogger("Constants") |
1369 | + self.logger.debug("Getting hardware specs") |
1370 | + self.screens = None |
1371 | + self.combined_screen = None |
1372 | + |
1373 | + self.get_screens() |
1374 | + |
1375 | + def get_current_screen(self, window = None): |
1376 | + try: |
1377 | + if window: |
1378 | + screen = self.default_screen.get_monitor_at_window(window.get_window()) |
1379 | + else: |
1380 | + disp = GdkX11.X11Display.get_default() |
1381 | + dm = Gdk.Display.get_device_manager(disp) |
1382 | + pntr_device = dm.get_client_pointer() |
1383 | + (src, x, y) = pntr_device.get_position() |
1384 | + screen = self.default_screen.get_monitor_at_point(x, y) |
1385 | + except: |
1386 | + screen = 0 |
1387 | + return screen |
1388 | + |
1389 | + def get_screens(self): |
1390 | + try: |
1391 | + self.logger.debug("Getting Video sources.") |
1392 | + self.screens = [] |
1393 | + self.default_screen = Gdk.Screen.get_default() |
1394 | + self.logger.debug("Found {0} monitors.".format(self.default_screen.get_n_monitors())) |
1395 | + |
1396 | + for i in range(self.default_screen.get_n_monitors()): |
1397 | + rect = self.default_screen.get_monitor_geometry(i) |
1398 | + self.logger.debug(" Monitor {0} - X: {1}, Y: {2}, W: {3}, H: {4}".format(i, |
1399 | + rect.x, |
1400 | + rect.y, |
1401 | + rect.width, |
1402 | + rect.height)) |
1403 | + self.screens.append({"x": rect.x, |
1404 | + "y": rect.y, |
1405 | + "width": rect.width, |
1406 | + "height": rect.height}) |
1407 | + |
1408 | + if self.default_screen.get_n_monitors() > 1: |
1409 | + self.combined_screen = {"x": 0, "y": 0, |
1410 | + "width": self.default_screen.get_width(), |
1411 | + "height": self.default_screen.get_height()} |
1412 | + self.logger.debug(" Combined screen - X: 0, Y: 0, W: {0}, H: {1}".format(self.default_screen.get_width(), |
1413 | + self.default_screen.get_height())) |
1414 | + else: |
1415 | + self.combined_screen = None |
1416 | + |
1417 | + except: |
1418 | + self.logger.warning("Unable to find any video sources.") |
1419 | + |
1420 | +HW = hw() |
1421 | |
1422 | === added file 'build/lib.linux-x86_64-2.7/kazam/backend/export.py' |
1423 | --- build/lib.linux-x86_64-2.7/kazam/backend/export.py 1970-01-01 00:00:00 +0000 |
1424 | +++ build/lib.linux-x86_64-2.7/kazam/backend/export.py 2012-11-15 10:17:01 +0000 |
1425 | @@ -0,0 +1,194 @@ |
1426 | +# -*- coding: utf-8 -*- |
1427 | +# |
1428 | +# export_backend.py |
1429 | +# |
1430 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
1431 | +# Copyright 2010 Andrew <andrew@karmic-desktop> |
1432 | +# |
1433 | +# This program is free software; you can redistribute it and/or modify |
1434 | +# it under the terms of the GNU General Public License as published by |
1435 | +# the Free Software Foundation; either version 3 of the License, or |
1436 | +# (at your option) any later version. |
1437 | +# |
1438 | +# This program is distributed in the hope that it will be useful, |
1439 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1440 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1441 | +# GNU General Public License for more details. |
1442 | +# |
1443 | +# You should have received a copy of the GNU General Public License |
1444 | +# along with this program; if not, write to the Free Software |
1445 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
1446 | +# MA 02110-1301, USA. |
1447 | + |
1448 | +import os |
1449 | + |
1450 | +from gi.repository import GObject |
1451 | + |
1452 | +import kazam.backend.export_sources |
1453 | +from kazam.utils import * |
1454 | + |
1455 | +class ExportBackend(GObject.GObject): |
1456 | + |
1457 | + __gsignals__ = { |
1458 | + "authenticate-requested" : (GObject.SIGNAL_RUN_LAST, |
1459 | + GObject.TYPE_NONE, |
1460 | + ([GObject.TYPE_PYOBJECT, |
1461 | + GObject.TYPE_PYOBJECT, |
1462 | + GObject.TYPE_PYOBJECT]),), |
1463 | + "login-started" : (GObject.SIGNAL_RUN_LAST, |
1464 | + GObject.TYPE_NONE, |
1465 | + ( ),), |
1466 | + "login-completed" : (GObject.SIGNAL_RUN_LAST, |
1467 | + GObject.TYPE_NONE, |
1468 | + ([bool]),), |
1469 | + "convert-started" : (GObject.SIGNAL_RUN_LAST, |
1470 | + GObject.TYPE_NONE, |
1471 | + ( ),), |
1472 | + "convert-completed" : (GObject.SIGNAL_RUN_LAST, |
1473 | + GObject.TYPE_NONE, |
1474 | + ([bool]),), |
1475 | + "upload-started" : (GObject.SIGNAL_RUN_LAST, |
1476 | + GObject.TYPE_NONE, |
1477 | + ( ),), |
1478 | + "upload-completed" : (GObject.SIGNAL_RUN_LAST, |
1479 | + GObject.TYPE_NONE, |
1480 | + ([bool, str]),), |
1481 | + } |
1482 | + |
1483 | + def __init__(self, frontend, datadir): |
1484 | + super(ExportBackend, self).__init__() |
1485 | + |
1486 | + self.frontend = frontend |
1487 | + self.frontend.connect("export-requested", self.cb_export_requested) |
1488 | + |
1489 | + self.datadir = datadir |
1490 | + self.active_export_object = None |
1491 | + |
1492 | + self.error = False |
1493 | + |
1494 | + export_module_files = self._get_export_module_files() |
1495 | + self.export_objects = self._create_export_objects(export_module_files) |
1496 | + |
1497 | + def _get_export_module_files(self): |
1498 | + """ |
1499 | + Returns a list of export source files |
1500 | + """ |
1501 | + export_module_list = [] |
1502 | + # For each directory that provides kazam.export_sources |
1503 | + for path in kazam.backend.export_sources.__path__: |
1504 | + directory = os.path.abspath(path) |
1505 | + # List files in that directory |
1506 | + for f in os.listdir(directory): |
1507 | + # If the file is a python file append the file to our list |
1508 | + if f[-3:] == ".py": |
1509 | + export_module_list.append(f) |
1510 | + |
1511 | + # Remove __init__.py and any duplicates |
1512 | + export_module_list.remove("__init__.py") |
1513 | + export_module_list = remove_list_dups(export_module_list) |
1514 | + |
1515 | + return export_module_list |
1516 | + |
1517 | + def _import_export_module(self, name): |
1518 | + """ |
1519 | + Import an export_source module and return the module |
1520 | + """ |
1521 | + return getattr(__import__("kazam.backend.export_sources", globals(), |
1522 | + locals(), [name], -1), name) |
1523 | + |
1524 | + def _create_export_objects(self, export_module_files): |
1525 | + """ |
1526 | + Return a list of export objects |
1527 | + """ |
1528 | + export_objects = [] |
1529 | + for f in export_module_files: |
1530 | + f = f[:-3] |
1531 | + # Find and import the module for each file |
1532 | + module = self._import_export_module(f) |
1533 | + # Append an instance of it, to our export_objects list |
1534 | + upload_source = module.UploadSource() |
1535 | + upload_source.gui_extra(self.datadir) |
1536 | + export_objects.append(upload_source) |
1537 | + return export_objects |
1538 | + |
1539 | + def get_export_objects(self): |
1540 | + return self.export_objects |
1541 | + |
1542 | + def set_active_export_object(self, i): |
1543 | + self.active_export_object = self.export_objects[i] |
1544 | + return self.active_export_object |
1545 | + |
1546 | + def get_active_export_object(self): |
1547 | + return self.active_export_object |
1548 | + |
1549 | + def get_export_meta(self): |
1550 | + return self.export_object.META |
1551 | + |
1552 | + def cb_export_requested(self, frontend): |
1553 | + self.error = False |
1554 | + self.login() |
1555 | + if not self.error: |
1556 | + self.create_meta() |
1557 | + if not self.error: |
1558 | + self.convert() |
1559 | + if not self.error: |
1560 | + self.upload() |
1561 | + |
1562 | + def login(self): |
1563 | + if self.active_export_object.authentication == True: |
1564 | + self.emit("authenticate-requested", |
1565 | + self.active_export_object.ICONS, |
1566 | + self.active_export_object.NAME, |
1567 | + self.active_export_object.REGISTER_URL) |
1568 | + else: |
1569 | + self.details = (None, None) |
1570 | + if hasattr(self, "details"): |
1571 | + try: |
1572 | + self.emit("login-started") |
1573 | + (username, password) = self.details |
1574 | + self.active_export_object.login_pre(username, password) |
1575 | + create_wait_thread(self.active_export_object.login_in) |
1576 | + self.active_export_object.login_post() |
1577 | + success = True |
1578 | + except Exception, e: |
1579 | + print e |
1580 | + self.error = True |
1581 | + success = False |
1582 | + else: |
1583 | + success = False |
1584 | + self.error = True |
1585 | + self.emit("login-completed", success) |
1586 | + |
1587 | + def create_meta(self): |
1588 | + self.active_export_object.create_meta(**self.frontend.get_meta()) |
1589 | + |
1590 | + def convert(self): |
1591 | + self.emit("convert-started") |
1592 | + try: |
1593 | + screencast = self.frontend.get_screencast() |
1594 | + screencast.convert(self.active_export_object.FFMPEG_OPTIONS, |
1595 | + self.active_export_object.FFMPEG_FILE_EXTENSION, |
1596 | + self.frontend.get_video_quality(), |
1597 | + self.frontend.get_audio_quality()) |
1598 | + while not hasattr(screencast, "converted_file"): |
1599 | + gtk.main_iteration() |
1600 | + self.converted_file_path = screencast.converted_file |
1601 | + self.emit("convert-completed", True) |
1602 | + except Exception, e: |
1603 | + print e |
1604 | + self.error = True |
1605 | + self.emit("convert-completed", False) |
1606 | + |
1607 | + def upload(self): |
1608 | + self.emit("upload-started") |
1609 | + url = "" |
1610 | + try: |
1611 | + self.active_export_object.upload_pre() |
1612 | + create_wait_thread(self.active_export_object.upload_in, (self.converted_file_path,)) |
1613 | + url = self.active_export_object.upload_post() |
1614 | + success = True |
1615 | + except Exception, e: |
1616 | + print e |
1617 | + self.error = True |
1618 | + success = False |
1619 | + self.emit("upload-completed", success, url) |
1620 | |
1621 | === added file 'build/lib.linux-x86_64-2.7/kazam/backend/ffmpeg.py' |
1622 | --- build/lib.linux-x86_64-2.7/kazam/backend/ffmpeg.py 1970-01-01 00:00:00 +0000 |
1623 | +++ build/lib.linux-x86_64-2.7/kazam/backend/ffmpeg.py 2012-11-15 10:17:01 +0000 |
1624 | @@ -0,0 +1,132 @@ |
1625 | +#!/usr/bin/env python |
1626 | +# -*- coding: utf-8 -*- |
1627 | +# |
1628 | +# recording.py |
1629 | +# |
1630 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
1631 | +# Copyright 2010 Andrew <andrew@karmic-desktop> |
1632 | +# |
1633 | +# This program is free software; you can redistribute it and/or modify |
1634 | +# it under the terms of the GNU General Public License as published by |
1635 | +# the Free Software Foundation; either version 3 of the License, or |
1636 | +# (at your option) any later version. |
1637 | +# |
1638 | +# This program is distributed in the hope that it will be useful, |
1639 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1640 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1641 | +# GNU General Public License for more details. |
1642 | +# |
1643 | +# You should have received a copy of the GNU General Public License |
1644 | +# along with this program; if not, write to the Free Software |
1645 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
1646 | +# MA 02110-1301, USA. |
1647 | + |
1648 | +from subprocess import Popen |
1649 | +import tempfile |
1650 | +import os |
1651 | +import gobject |
1652 | +import glib |
1653 | +import signal |
1654 | + |
1655 | +class Screencast(object): |
1656 | + def __init__(self): |
1657 | + self.tempfile = tempfile.mktemp(prefix="kazam_", suffix=".mkv") |
1658 | + |
1659 | + def setup_sources(self, video_source, audio_source): |
1660 | + self.audio_source = audio_source |
1661 | + self.video_source = video_source |
1662 | + |
1663 | + # TODO: use gstreamer instead (see gstreamer.py for start) |
1664 | + self.args_list = ["ffmpeg"] |
1665 | + |
1666 | + # Add the audio source if selected |
1667 | + if audio_source: |
1668 | + self.args_list += ["-f", "alsa", "-i", "pulse"] |
1669 | + |
1670 | + # Add the video source |
1671 | + if video_source: |
1672 | + x = video_source.x |
1673 | + y = video_source.y |
1674 | + width = video_source.width |
1675 | + height = video_source.height |
1676 | + display = video_source.display |
1677 | + self.args_list += ["-f", "x11grab", "-r", "30", "-s", |
1678 | + "%sx%s" % (width, height), "-i", |
1679 | + "%s+%s,%s" % (display, x, y)] |
1680 | + if audio_source: |
1681 | + self.args_list += ["-ac", "2", "-acodec", "flac", "-ab", "128k"] |
1682 | + |
1683 | + if video_source: |
1684 | + self.args_list += ["-vcodec", "libx264", |
1685 | + "-crf", "0", |
1686 | + "-preset", "fast", |
1687 | + "-tune", "stillimage", |
1688 | + "-vf", "unsharp=3:3:0.5:3:3:0.0" |
1689 | + |
1690 | + ] |
1691 | + self.args_list += ["-threads", "0", self.tempfile] |
1692 | + |
1693 | + arg_string = "" |
1694 | + for arg in self.args_list: |
1695 | + arg_string += " %s" % arg |
1696 | + print arg_string |
1697 | + |
1698 | + def start_recording(self): |
1699 | + self.recording_command = Popen(self.args_list) |
1700 | + |
1701 | + def pause_recording(self): |
1702 | + self.recording_command.send_signal(signal.SIGTSTP) |
1703 | + |
1704 | + def unpause_recording(self): |
1705 | + self.recording_command.send_signal(signal.SIGCONT) |
1706 | + |
1707 | + def stop_recording(self): |
1708 | + self.recording_command.send_signal(signal.SIGINT) |
1709 | + |
1710 | + def get_recording_filename(self): |
1711 | + return self.tempfile |
1712 | + |
1713 | + def get_audio_recorded(self): |
1714 | + return self.audio_source |
1715 | + |
1716 | + def get_video_recorded(self): |
1717 | + return self.video_source |
1718 | + |
1719 | + def convert(self, options, converted_file_extension, video_quality=None, |
1720 | + audio_quality=None): |
1721 | + |
1722 | + self.converted_file_extension = converted_file_extension |
1723 | + |
1724 | + # Create our ffmpeg arguments list |
1725 | + args_list = ["ffmpeg"] |
1726 | + # Add the input file |
1727 | + args_list += ["-i", self.tempfile] |
1728 | + # Add any UploadSource specific options |
1729 | + args_list += options |
1730 | + |
1731 | + # Configure the quality as selected by the user |
1732 | + # If the quality slider circle is at the right-most position |
1733 | + # use the same quality option |
1734 | + if video_quality == 6001: |
1735 | + args_list += ["-sameq"] |
1736 | + elif video_quality: |
1737 | + args_list += ["-b", "%sk" % video_quality] |
1738 | + if audio_quality: |
1739 | + args_list += ["-ab", "%sk" % audio_quality] |
1740 | + # Finally add the desired output file |
1741 | + args_list += ["%s%s" %(self.tempfile[:-4], converted_file_extension)] |
1742 | + |
1743 | + # Run the ffmpeg command and when it is done, set a variable to |
1744 | + # show we have finished |
1745 | + command = Popen(args_list) |
1746 | + glib.timeout_add(100, self._poll, command) |
1747 | + |
1748 | + def _poll(self, command): |
1749 | + ret = command.poll() |
1750 | + if ret is None: |
1751 | + # Keep monitoring |
1752 | + return True |
1753 | + else: |
1754 | + self.converted_file = "%s%s" %(self.tempfile[:-4], self.converted_file_extension) |
1755 | + return False |
1756 | + |
1757 | |
1758 | === added file 'build/lib.linux-x86_64-2.7/kazam/backend/grabber.py' |
1759 | --- build/lib.linux-x86_64-2.7/kazam/backend/grabber.py 1970-01-01 00:00:00 +0000 |
1760 | +++ build/lib.linux-x86_64-2.7/kazam/backend/grabber.py 2012-11-15 10:17:01 +0000 |
1761 | @@ -0,0 +1,166 @@ |
1762 | +# -*- coding: utf-8 -*- |
1763 | +# |
1764 | +# grabber.py |
1765 | +# |
1766 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
1767 | +# |
1768 | +# This program is free software; you can redistribute it and/or modify |
1769 | +# it under the terms of the GNU General Public License as published by |
1770 | +# the Free Software Foundation; either version 3 of the License, or |
1771 | +# (at your option) any later version. |
1772 | +# |
1773 | +# This program is distributed in the hope that it will be useful, |
1774 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1775 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1776 | +# GNU General Public License for more details. |
1777 | +# |
1778 | +# You should have received a copy of the GNU General Public License |
1779 | +# along with this program; if not, write to the Free Software |
1780 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
1781 | +# MA 02110-1301, USA. |
1782 | + |
1783 | + |
1784 | +import os |
1785 | +import subprocess |
1786 | +import logging |
1787 | +logger = logging.getLogger("Grabber") |
1788 | + |
1789 | +from gi.repository import GObject, Gtk, Gdk, GdkPixbuf, GdkX11 |
1790 | + |
1791 | +from kazam.backend.prefs import * |
1792 | +from kazam.backend.constants import * |
1793 | +from kazam.frontend.save_dialog import SaveDialog |
1794 | +from gettext import gettext as _ |
1795 | + |
1796 | +class Grabber(GObject.GObject): |
1797 | + __gsignals__ = { |
1798 | + "save-done" : (GObject.SIGNAL_RUN_LAST, |
1799 | + None, |
1800 | + [GObject.TYPE_PYOBJECT],), |
1801 | + "flush-done" : (GObject.SIGNAL_RUN_LAST, |
1802 | + None, |
1803 | + (),), |
1804 | + } |
1805 | + |
1806 | + def __init__(self): |
1807 | + GObject.GObject.__init__(self) |
1808 | + logger.debug("Starting Grabber.") |
1809 | + |
1810 | + |
1811 | + def setup_sources(self, video_source, area, xid, active = False, god = False): |
1812 | + self.video_source = video_source |
1813 | + self.area = area |
1814 | + self.xid = xid |
1815 | + self.god = god |
1816 | + if active: |
1817 | + from gi.repository import GdkX11 |
1818 | + active_win = HW.default_screen.get_active_window() |
1819 | + self.xid = GdkX11.X11Window.get_xid(active_win) |
1820 | + |
1821 | + logger.debug("Grabber source: {0}, {1}, {2}, {3}".format(self.video_source['x'], |
1822 | + self.video_source['y'], |
1823 | + self.video_source['width'], |
1824 | + self.video_source['height'])) |
1825 | + |
1826 | + def grab(self): |
1827 | + self.pixbuf = None |
1828 | + disp = GdkX11.X11Display.get_default() |
1829 | + dm = Gdk.Display.get_device_manager(disp) |
1830 | + pntr_device = dm.get_client_pointer() |
1831 | + |
1832 | + # |
1833 | + # Rewrite this, because it sucks |
1834 | + # |
1835 | + if prefs.shutter_sound and (not self.god): |
1836 | + soundfile = os.path.join(prefs.datadir, 'sounds', prefs.sound_files[prefs.shutter_type]) |
1837 | + subprocess.call(['/usr/bin/canberra-gtk-play', '-f', soundfile]) |
1838 | + |
1839 | + if self.xid: |
1840 | + if prefs.capture_borders_pic: |
1841 | + app_win = GdkX11.X11Window.foreign_new_for_display(disp, self.xid) |
1842 | + (rx, ry, rw, rh) = app_win.get_geometry() |
1843 | + area = app_win.get_frame_extents() |
1844 | + (fx, fy, fw, fh) = (area.x, area.y, area.width, area.height) |
1845 | + win = Gdk.get_default_root_window() |
1846 | + logger.debug("Coordinates RX {0} RY {1} RW {2} RH {3}".format(rx, ry, rw, rh)) |
1847 | + logger.debug("Coordinates FX {0} FY {1} FW {2} FH {3}".format(fx, fy, fw, fh)) |
1848 | + dx = fw - rw |
1849 | + dy = fh - rh |
1850 | + (x, y, w, h) = (fx, fy, fw, fh) |
1851 | + logger.debug("Coordinates delta: DX {0} DY {1}".format(dx, dy)) |
1852 | + else: |
1853 | + win = GdkX11.X11Window.foreign_new_for_display(disp, self.xid) |
1854 | + (x, y, w, h) = win.get_geometry() |
1855 | + else: |
1856 | + win = Gdk.get_default_root_window() |
1857 | + (x, y, w, h) = (self.video_source['x'], |
1858 | + self.video_source['y'], |
1859 | + self.video_source['width'], |
1860 | + self.video_source['height']) |
1861 | + |
1862 | + logger.debug("Coordinates X {0} Y {1} W {2} H {3}".format(x, y, w, h)) |
1863 | + self.pixbuf = Gdk.pixbuf_get_from_window(win, x, y, w, h) |
1864 | + |
1865 | + if prefs.capture_cursor_pic: |
1866 | + logger.debug("Adding cursor.") |
1867 | + |
1868 | + cursor = Gdk.Cursor.new_for_display(Gdk.Display.get_default(), Gdk.CursorType.LEFT_PTR) |
1869 | + c_picbuf = Gdk.Cursor.get_image(cursor) |
1870 | + |
1871 | + if self.xid and prefs.capture_borders_pic: |
1872 | + pointer = app_win.get_device_position(pntr_device) |
1873 | + (px, py) = (pointer[1], pointer[2]) |
1874 | + c_picbuf.composite(self.pixbuf, rx, ry, rw, rh, |
1875 | + px + dx - 6, |
1876 | + py + dy - 2, |
1877 | + 1.0, |
1878 | + 1.0, |
1879 | + GdkPixbuf.InterpType.BILINEAR, |
1880 | + 255) |
1881 | + else: |
1882 | + pointer = win.get_device_position(pntr_device) |
1883 | + (px, py) = (pointer[1], pointer[2]) |
1884 | + # |
1885 | + # Cursor is offseted by 6 pixels to the right and 2 down |
1886 | + # |
1887 | + c_picbuf.composite(self.pixbuf, x, y, w, h, |
1888 | + px - 6, |
1889 | + py - 2, |
1890 | + 1.0, |
1891 | + 1.0, |
1892 | + GdkPixbuf.InterpType.BILINEAR, |
1893 | + 255) |
1894 | + |
1895 | + logger.debug("Cursor coords: {0} {1}".format(px, py)) |
1896 | + |
1897 | + if self.area is not None: |
1898 | + logger.debug("Cropping image.") |
1899 | + self.area_buf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True, 8, self.area[4], self.area[5]) |
1900 | + self.pixbuf.copy_area(self.area[0], self.area[1], self.area[4], self.area[5], self.area_buf, 0, 0) |
1901 | + self.pixbuf = None |
1902 | + self.pixbuf = self.area_buf |
1903 | + |
1904 | + self.emit("flush-done") |
1905 | + |
1906 | + def save(self, filename): |
1907 | + if self.pixbuf is not None: |
1908 | + self.pixbuf.savev(filename, "png", "", "") |
1909 | + |
1910 | + def save_capture(self, old_path): |
1911 | + logger.debug("Saving screenshot.") |
1912 | + self.old_path = old_path |
1913 | + (dialog, result, self.old_path) = SaveDialog(_("Save capture"), |
1914 | + self.old_path, None, main_mode=MODE_SCREENSHOT) |
1915 | + |
1916 | + if result == Gtk.ResponseType.OK: |
1917 | + uri = os.path.join(dialog.get_current_folder(), dialog.get_filename()) |
1918 | + |
1919 | + self.save(uri) |
1920 | + |
1921 | + dialog.destroy() |
1922 | + self.emit("save-done", self.old_path) |
1923 | + |
1924 | + def autosave(self, filename): |
1925 | + logger.debug("Autosaving to: {0}".format(filename)) |
1926 | + self.save(filename) |
1927 | + self.emit("save-done", filename) |
1928 | |
1929 | === added file 'build/lib.linux-x86_64-2.7/kazam/backend/gstreamer.py' |
1930 | --- build/lib.linux-x86_64-2.7/kazam/backend/gstreamer.py 1970-01-01 00:00:00 +0000 |
1931 | +++ build/lib.linux-x86_64-2.7/kazam/backend/gstreamer.py 2012-11-15 10:17:01 +0000 |
1932 | @@ -0,0 +1,416 @@ |
1933 | +# -*- coding: utf-8 -*- |
1934 | +# |
1935 | +# gstreamer.py |
1936 | +# |
1937 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
1938 | +# |
1939 | +# This program is free software; you can redistribute it and/or modify |
1940 | +# it under the terms of the GNU General Public License as published by |
1941 | +# the Free Software Foundation; either version 3 of the License, or |
1942 | +# (at your option) any later version. |
1943 | +# |
1944 | +# This program is distributed in the hope that it will be useful, |
1945 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1946 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1947 | +# GNU General Public License for more details. |
1948 | +# |
1949 | +# You should have received a copy of the GNU General Public License |
1950 | +# along with this program; if not, write to the Free Software |
1951 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
1952 | +# MA 02110-1301, USA. |
1953 | + |
1954 | +import os |
1955 | +import logging |
1956 | +logger = logging.getLogger("GStreamer-GI") |
1957 | + |
1958 | +import tempfile |
1959 | +import multiprocessing |
1960 | + |
1961 | +# |
1962 | +# This needs to be set before we load GStreamer modules! |
1963 | +# |
1964 | +os.environ["GST_DEBUG_DUMP_DOT_DIR"] = "/tmp" |
1965 | +os.putenv("GST_DEBUG_DUMP_DOT_DIR", "/tmp") |
1966 | + |
1967 | +from gi.repository import GObject, Gst |
1968 | + |
1969 | +from kazam.backend.prefs import * |
1970 | +from kazam.backend.constants import * |
1971 | + |
1972 | +GObject.threads_init() |
1973 | +Gst.init(None) |
1974 | +Gst.debug_set_active(True) |
1975 | + |
1976 | +class Screencast(GObject.GObject): |
1977 | + __gsignals__ = { |
1978 | + "flush-done" : (GObject.SIGNAL_RUN_LAST, |
1979 | + None, |
1980 | + (), |
1981 | + ), |
1982 | + } |
1983 | + def __init__(self): |
1984 | + GObject.GObject.__init__(self) |
1985 | + |
1986 | + self.temp_fh = tempfile.mkstemp(prefix="kazam_", dir=prefs.video_dest, suffix=".movie") |
1987 | + self.tempfile = self.temp_fh[1] |
1988 | + self.muxer_tempfile = "{0}.mux".format(self.tempfile) |
1989 | + self.pipeline = Gst.Pipeline() |
1990 | + self.area = None |
1991 | + self.xid = None |
1992 | + self.crop_vid = False |
1993 | + |
1994 | + def setup_sources(self, |
1995 | + video_source, |
1996 | + audio_source, |
1997 | + audio2_source, |
1998 | + area, |
1999 | + xid): |
2000 | + |
2001 | + |
2002 | + # Get the number of cores available then use all except one for encoding |
2003 | + self.cores = multiprocessing.cpu_count() |
2004 | + |
2005 | + if self.cores > 1: |
2006 | + self.cores -= 1 |
2007 | + |
2008 | + self.audio_source = audio_source |
2009 | + self.audio2_source = audio2_source |
2010 | + self.video_source = video_source |
2011 | + self.area = area |
2012 | + self.xid = xid |
2013 | + |
2014 | + logger.debug("audio_source : {0}".format(audio_source)) |
2015 | + logger.debug("video_source: {0}".format(video_source)) |
2016 | + logger.debug("xid: {0}".format(xid)) |
2017 | + logger.debug("area: {0}".format(area)) |
2018 | + |
2019 | + logger.debug("Capture Cursor: {0}".format(prefs.capture_cursor)) |
2020 | + logger.debug("Framerate : {0}".format(prefs.framerate)) |
2021 | + logger.debug("Codec: {0}".format(CODEC_LIST[prefs.codec][1])) |
2022 | + |
2023 | + if self.video_source or self.area: |
2024 | + self.setup_video_source() |
2025 | + |
2026 | + if self.audio_source: |
2027 | + self.setup_audio_source() |
2028 | + |
2029 | + if self.audio2_source: |
2030 | + self.setup_audio2_source() |
2031 | + |
2032 | + self.setup_filesink() |
2033 | + self.setup_pipeline() |
2034 | + self.setup_links() |
2035 | + |
2036 | + self.bus = self.pipeline.get_bus() |
2037 | + self.bus.add_signal_watch() |
2038 | + self.bus.connect("message", self.on_message) |
2039 | + |
2040 | + def setup_video_source(self): |
2041 | + |
2042 | + if prefs.test: |
2043 | + self.videosrc = Gst.ElementFactory.make("videotestsrc", "video_src") |
2044 | + self.videosrc.set_property("pattern", "smpte") |
2045 | + else: |
2046 | + self.videosrc = Gst.ElementFactory.make("ximagesrc", "video_src") |
2047 | + |
2048 | + if self.area: |
2049 | + logger.debug("Capturing area.") |
2050 | + startx = self.area[0] if self.area[0] > 0 else 0 |
2051 | + starty = self.area[1] if self.area[1] > 0 else 0 |
2052 | + endx = self.area[2] |
2053 | + endy = self.area[3] |
2054 | + else: |
2055 | + startx = self.video_source['x'] |
2056 | + starty = self.video_source['y'] |
2057 | + width = self.video_source['width'] |
2058 | + height = self.video_source['height'] |
2059 | + endx = startx + width - 1 |
2060 | + endy = starty + height - 1 |
2061 | + |
2062 | + # |
2063 | + # H264 requirement is that video dimensions are divisible by 2. |
2064 | + # If they are not, we have to get rid of that extra pixel. |
2065 | + # |
2066 | + if not abs(startx - endx) % 2 and prefs.codec == CODEC_H264: |
2067 | + endx -= 1 |
2068 | + |
2069 | + if not abs(starty - endy) % 2 and prefs.codec == CODEC_H264: |
2070 | + endy -= 1 |
2071 | + |
2072 | + logger.debug("Coordinates SX: {0} SY: {1} EX: {2} EY: {3}".format(startx, starty, endx, endy)) |
2073 | + |
2074 | + if prefs.test: |
2075 | + logger.info("Using test signal instead of screen capture.") |
2076 | + self.vid_caps = Gst.caps_from_string("video/x-raw,format=(x-raw-rgb),framerate={0}/1, width={1}, height={2}".format( |
2077 | + prefs.framerate, |
2078 | + endx - startx, |
2079 | + endy - starty)) |
2080 | + self.vid_caps_filter = Gst.ElementFactory.make("capsfilter", "vid_filter") |
2081 | + self.vid_caps_filter.set_property("caps", self.vid_caps) |
2082 | + else: |
2083 | + logger.debug("testing for xid: {0}".format(self.xid)) |
2084 | + if self.xid: # xid was passed, so we have to capture a single window. |
2085 | + logger.debug("Capturing Window: {0} {1}".format(self.xid, prefs.xid_geometry)) |
2086 | + self.videosrc.set_property("xid", self.xid) |
2087 | + |
2088 | + if prefs.codec == CODEC_H264: |
2089 | + self.videocrop = Gst.ElementFactory.make("videocrop", "cropper") |
2090 | + if prefs.xid_geometry[2] % 2: |
2091 | + self.videocrop.set_property("left", 1) |
2092 | + self.crop_vid = True |
2093 | + if prefs.xid_geometry[3] % 2: |
2094 | + self.videocrop.set_property("bottom", 1) |
2095 | + self.crop_vid = True |
2096 | + else: |
2097 | + self.videosrc.set_property("startx", startx) |
2098 | + self.videosrc.set_property("starty", starty) |
2099 | + self.videosrc.set_property("endx", endx) |
2100 | + self.videosrc.set_property("endy", endy) |
2101 | + |
2102 | + self.videosrc.set_property("use-damage", False) |
2103 | + self.videosrc.set_property("show-pointer", prefs.capture_cursor) |
2104 | + |
2105 | + self.vid_caps = Gst.caps_from_string("video/x-raw,format=(x-raw-rgb),framerate={0}/1".format(prefs.framerate)) |
2106 | + self.vid_caps_filter = Gst.ElementFactory.make("capsfilter", "vid_filter") |
2107 | + self.vid_caps_filter.set_property("caps", self.vid_caps) |
2108 | + |
2109 | + self.videoconvert = Gst.ElementFactory.make("videoconvert", "videoconvert") |
2110 | + self.videorate = Gst.ElementFactory.make("videorate", "video_rate") |
2111 | + |
2112 | + logger.debug("Codec: {0}".format(CODEC_LIST[prefs.codec][2])) |
2113 | + |
2114 | + if prefs.codec is not CODEC_RAW: |
2115 | + self.videnc = Gst.ElementFactory.make(CODEC_LIST[prefs.codec][1], "video_encoder") |
2116 | + |
2117 | + if prefs.codec == CODEC_RAW: |
2118 | + self.mux = Gst.ElementFactory.make("avimux", "muxer") |
2119 | + elif prefs.codec == CODEC_VP8: |
2120 | + self.videnc.set_property("cpu-used", 2) |
2121 | + self.videnc.set_property("end-usage", "vbr") |
2122 | + self.videnc.set_property("target-bitrate", 800000000) |
2123 | + self.videnc.set_property("static-threshold", 1000) |
2124 | + self.videnc.set_property("token-partitions", 2) |
2125 | + self.videnc.set_property("max-quantizer", 30) |
2126 | + self.videnc.set_property("threads", self.cores) |
2127 | + self.mux = Gst.ElementFactory.make("webmmux", "muxer") |
2128 | + elif prefs.codec == CODEC_H264: |
2129 | + self.videnc.set_property("speed-preset", "ultrafast") |
2130 | + self.videnc.set_property("pass", 4) |
2131 | + self.videnc.set_property("quantizer", 15) |
2132 | + # |
2133 | + # x264enc supports maximum of four cores |
2134 | + # |
2135 | + self.videnc.set_property("threads", self.cores if self.cores <= 4 else 4) |
2136 | + self.mux = Gst.ElementFactory.make("mp4mux", "muxer") |
2137 | + self.mux.set_property("faststart", 1) |
2138 | + self.mux.set_property("faststart-file", self.muxer_tempfile) |
2139 | + self.mux.set_property("streamable", 1) |
2140 | + elif prefs.codec == CODEC_HUFF: |
2141 | + self.mux = Gst.ElementFactory.make("avimux", "muxer") |
2142 | + self.videnc.set_property("bitrate", 500000) |
2143 | + elif prefs.codec == CODEC_JPEG: |
2144 | + self.mux = Gst.ElementFactory.make("avimux", "muxer") |
2145 | + |
2146 | + self.vid_in_queue = Gst.ElementFactory.make("queue", "queue_v1") |
2147 | + self.vid_out_queue = Gst.ElementFactory.make("queue", "queue_v2") |
2148 | + |
2149 | + def setup_audio_source(self): |
2150 | + logger.debug("Audio1 Source:\n {0}".format(self.audio_source)) |
2151 | + self.audiosrc = Gst.ElementFactory.make("pulsesrc", "audio_src") |
2152 | + self.audiosrc.set_property("device", self.audio_source) |
2153 | + self.aud_caps = Gst.caps_from_string("audio/x-raw") |
2154 | + self.aud_caps_filter = Gst.ElementFactory.make("capsfilter", "aud_filter") |
2155 | + self.aud_caps_filter.set_property("caps", self.aud_caps) |
2156 | + self.audioconv = Gst.ElementFactory.make("audioconvert", "audio_conv") |
2157 | + if prefs.codec == CODEC_VP8: |
2158 | + self.audioenc = Gst.ElementFactory.make("vorbisenc", "audio_encoder") |
2159 | + self.audioenc.set_property("quality", 1) |
2160 | + else: |
2161 | + self.audioenc = Gst.ElementFactory.make("lamemp3enc", "audio_encoder") |
2162 | + self.audioenc.set_property("quality", 0) |
2163 | + |
2164 | + self.aud_in_queue = Gst.ElementFactory.make("queue", "queue_a_in") |
2165 | + self.aud_out_queue = Gst.ElementFactory.make("queue", "queue_a_out") |
2166 | + |
2167 | + def setup_audio2_source(self): |
2168 | + logger.debug("Audio2 Source:\n {0}".format(self.audio2_source)) |
2169 | + self.audiomixer = Gst.ElementFactory.make("adder", "audiomixer") |
2170 | + self.audio2src = Gst.ElementFactory.make("pulsesrc", "audio2_src") |
2171 | + self.audio2src.set_property("device", self.audio2_source) |
2172 | + self.aud2_caps = Gst.caps_from_string("audio/x-raw") |
2173 | + self.aud2_caps_filter = Gst.ElementFactory.make("capsfilter", "aud2_filter") |
2174 | + self.aud2_caps_filter.set_property("caps", self.aud2_caps) |
2175 | + self.aud2_in_queue = Gst.ElementFactory.make("queue", "queue_a2_in") |
2176 | + self.audio2conv = Gst.ElementFactory.make("audioconvert", "audio2_conv") |
2177 | + |
2178 | + def setup_filesink(self): |
2179 | + logger.debug("Filesink: {0}".format(self.tempfile)) |
2180 | + self.sink = Gst.ElementFactory.make("filesink", "sink") |
2181 | + self.sink.set_property("location", self.tempfile) |
2182 | + self.file_queue = Gst.ElementFactory.make("queue", "queue_file") |
2183 | + |
2184 | + # |
2185 | + # One day, this horrific code will be optimised... I promise! |
2186 | + # |
2187 | + def setup_pipeline(self): |
2188 | + # |
2189 | + # Behold, setup the master pipeline |
2190 | + # |
2191 | + self.pipeline.add(self.videosrc) |
2192 | + self.pipeline.add(self.vid_in_queue) |
2193 | + if self.crop_vid: |
2194 | + self.pipeline.add(self.videocrop) |
2195 | + self.pipeline.add(self.videorate) |
2196 | + self.pipeline.add(self.vid_caps_filter) |
2197 | + self.pipeline.add(self.videoconvert) |
2198 | + self.pipeline.add(self.vid_out_queue) |
2199 | + self.pipeline.add(self.file_queue) |
2200 | + |
2201 | + if prefs.codec is not CODEC_RAW: |
2202 | + self.pipeline.add(self.videnc) |
2203 | + |
2204 | + if self.audio_source: |
2205 | + self.pipeline.add(self.audiosrc) |
2206 | + self.pipeline.add(self.aud_in_queue) |
2207 | + self.pipeline.add(self.aud_caps_filter) |
2208 | + self.pipeline.add(self.aud_out_queue) |
2209 | + self.pipeline.add(self.audioconv) |
2210 | + self.pipeline.add(self.audioenc) |
2211 | + |
2212 | + if self.audio2_source: |
2213 | + self.pipeline.add(self.audiomixer) |
2214 | + self.pipeline.add(self.aud2_in_queue) |
2215 | + self.pipeline.add(self.audio2src) |
2216 | + self.pipeline.add(self.aud2_caps_filter) |
2217 | + |
2218 | + self.pipeline.add(self.mux) |
2219 | + self.pipeline.add(self.sink) |
2220 | + |
2221 | + # gst-launch-1.0 -e ximagesrc endx=1919 endy=1079 use-damage=false show-pointer=true ! \ |
2222 | + # queue ! videorate ! video/x-raw,framerate=15/1 ! videoconvert ! \ |
2223 | + # vp8enc end-usage=vbr target-bitrate=800000000 threads=3 static-threshold=1000 \ |
2224 | + # token-partitions=2 max-quantizer=30 ! queue name=before_mux ! webmmux name=mux ! \ |
2225 | + # queue ! filesink location="test-videorate.webm" |
2226 | + |
2227 | + def setup_links(self): |
2228 | + # Connect everything together |
2229 | + self.videosrc.link(self.vid_in_queue) |
2230 | + if self.crop_vid: |
2231 | + self.vid_in_queue.link(self.videocrop) |
2232 | + self.videocrop.link(self.videorate) |
2233 | + else: |
2234 | + self.vid_in_queue.link(self.videorate) |
2235 | + self.videorate.link(self.vid_caps_filter) |
2236 | + self.vid_caps_filter.link(self.videoconvert) |
2237 | + if prefs.codec is CODEC_RAW: |
2238 | + self.videoconvert.link(self.vid_out_queue) |
2239 | + logger.debug("Linking RAW Video") |
2240 | + else: |
2241 | + logger.debug("Linking Video") |
2242 | + self.videoconvert.link(self.videnc) |
2243 | + self.videnc.link(self.vid_out_queue) |
2244 | + |
2245 | + self.vid_out_queue.link(self.mux) |
2246 | + |
2247 | + if self.audio_source: |
2248 | + logger.debug("Linking Audio") |
2249 | + ret = self.audiosrc.link(self.aud_in_queue) |
2250 | + logger.debug(" Link audiosrc -> aud_in_queue: %s" % ret) |
2251 | + ret = self.aud_in_queue.link(self.aud_caps_filter) |
2252 | + logger.debug(" Link aud_in_queue -> aud_caps_filter: %s" % ret) |
2253 | + |
2254 | + if self.audio2_source: |
2255 | + logger.debug("Linking Audio2") |
2256 | + # Link first audio source to mixer |
2257 | + ret = self.aud_caps_filter.link(self.audiomixer) |
2258 | + logger.debug(" Link aud_caps_filter -> audiomixer: %s" % ret) |
2259 | + |
2260 | + # Link second audio source to mixer |
2261 | + ret = self.audio2src.link(self.aud2_in_queue) |
2262 | + logger.debug(" Link audio2src -> aud2_in_queue: %s" % ret) |
2263 | + ret = self.aud2_in_queue.link(self.aud2_caps_filter) |
2264 | + logger.debug(" Link aud2_in_queue -> aud2_caps_filter: %s" % ret) |
2265 | + ret = self.aud2_caps_filter.link(self.audiomixer) |
2266 | + logger.debug(" Link aud2_caps_filter -> audiomixer: %s" % ret) |
2267 | + |
2268 | + # Link mixer to audio convert |
2269 | + ret = self.audiomixer.link(self.audioconv) |
2270 | + logger.debug(" Link audiomixer -> audioconv: %s" % ret) |
2271 | + |
2272 | + else: |
2273 | + # Link first audio source to audio convert |
2274 | + ret = self.aud_caps_filter.link(self.audioconv) |
2275 | + logger.debug(" Link aud_caps_filter -> audioconv: %s" % ret) |
2276 | + |
2277 | + # Link audio to muxer |
2278 | + ret = self.audioconv.link(self.audioenc) |
2279 | + logger.debug("Link audioconv -> audioenc: %s" % ret) |
2280 | + ret = self.audioenc.link(self.aud_out_queue) |
2281 | + logger.debug("Link audioenc -> aud_out_queue: %s" % ret) |
2282 | + ret = self.aud_out_queue.link(self.mux) |
2283 | + logger.debug("Link aud_out_queue -> mux: %s" % ret) |
2284 | + |
2285 | + ret = self.mux.link(self.file_queue) |
2286 | + logger.debug("Link mux -> file queue: %s" % ret) |
2287 | + ret = self.file_queue.link(self.sink) |
2288 | + logger.debug("Link file queue -> sink: %s" % ret) |
2289 | + |
2290 | + def start_recording(self): |
2291 | + logger.debug("Setting STATE_PLAYING") |
2292 | + self.pipeline.set_state(Gst.State.PLAYING) |
2293 | + |
2294 | + def pause_recording(self): |
2295 | + logger.debug("Setting STATE_PAUSED") |
2296 | + self.pipeline.set_state(Gst.State.PAUSED) |
2297 | + |
2298 | + def unpause_recording(self): |
2299 | + logger.debug("Setting STATE_PLAYING - UNPAUSE") |
2300 | + self.pipeline.set_state(Gst.State.PLAYING) |
2301 | + |
2302 | + def stop_recording(self): |
2303 | + logger.debug("Sending new EOS event") |
2304 | + self.pipeline.send_event(Gst.Event.new_eos()) |
2305 | + |
2306 | + def get_tempfile(self): |
2307 | + return self.tempfile |
2308 | + |
2309 | + def get_audio_recorded(self): |
2310 | + return self.audio |
2311 | + |
2312 | + def on_message(self, bus, message): |
2313 | + t = message.type |
2314 | + if t == Gst.MessageType.EOS: |
2315 | + logger.debug("Received EOS, setting pipeline to NULL.") |
2316 | + self.pipeline.set_state(Gst.State.NULL) |
2317 | + logger.debug("Emitting flush-done.") |
2318 | + self.emit("flush-done") |
2319 | + elif t == Gst.MessageType.ERROR: |
2320 | + logger.debug("Received an error message: %s", message.parse_error()[1]) |
2321 | + |
2322 | + |
2323 | +def detect_codecs(): |
2324 | + codecs_supported = [] |
2325 | + codec_test = None |
2326 | + for codec in CODEC_LIST: |
2327 | + if codec[0]: |
2328 | + try: |
2329 | + codec_test = Gst.ElementFactory.make(codec[1], "video_encoder") |
2330 | + except: |
2331 | + logger.info("Unable to find {0} GStreamer plugin - support disabled.".format(codec)) |
2332 | + codec_test = None |
2333 | + |
2334 | + if codec_test: |
2335 | + codecs_supported.append(codec[0]) |
2336 | + logger.info("Supported encoder: {0}.".format(codec[2])) |
2337 | + else: |
2338 | + # RAW codec is None, so we don't try to load it. |
2339 | + codecs_supported.append(codec[0]) |
2340 | + logger.info("Supported encoder: {0}.".format(codec[2])) |
2341 | + codec_test = None |
2342 | + return codecs_supported |
2343 | + |
2344 | +def get_codec(codec): |
2345 | + for c in CODEC_LIST: |
2346 | + if c[0] == codec: |
2347 | + return c |
2348 | + return None |
2349 | |
2350 | === added file 'build/lib.linux-x86_64-2.7/kazam/backend/prefs.py' |
2351 | --- build/lib.linux-x86_64-2.7/kazam/backend/prefs.py 1970-01-01 00:00:00 +0000 |
2352 | +++ build/lib.linux-x86_64-2.7/kazam/backend/prefs.py 2012-11-15 10:17:01 +0000 |
2353 | @@ -0,0 +1,232 @@ |
2354 | +# -*- coding: utf-8 -*- |
2355 | +# |
2356 | +# prefs.py |
2357 | +# |
2358 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
2359 | +# |
2360 | +# This program is free software; you can redistribute it and/or modify |
2361 | +# it under the terms of the GNU General Public License as published by |
2362 | +# the Free Software Foundation; either version 3 of the License, or |
2363 | +# (at your option) any later version. |
2364 | +# |
2365 | +# This program is distributed in the hope that it will be useful, |
2366 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2367 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2368 | +# GNU General Public License for more details. |
2369 | +# |
2370 | +# You should have received a copy of the GNU General Public License |
2371 | +# along with this program; if not, write to the Free Software |
2372 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
2373 | +# MA 02110-1301, USA. |
2374 | + |
2375 | +import os |
2376 | +import logging |
2377 | +from gettext import gettext as _ |
2378 | +from xdg.BaseDirectory import xdg_config_home |
2379 | + |
2380 | +from kazam.backend.config import KazamConfig |
2381 | + |
2382 | + |
2383 | +class Prefs(): |
2384 | + def __init__(self): |
2385 | + """Initialize prefs and set all the preference variables to their |
2386 | + default values. |
2387 | + |
2388 | + Args: |
2389 | + None |
2390 | + |
2391 | + Returns: |
2392 | + None |
2393 | + |
2394 | + Raises: |
2395 | + None |
2396 | + """ |
2397 | + self.logger = logging.getLogger("Prefs") |
2398 | + |
2399 | + # |
2400 | + # GUI preferences and stuff |
2401 | + # |
2402 | + self.capture_cursor = False |
2403 | + self.capture_speakers = False |
2404 | + self.capture_microphone = False |
2405 | + |
2406 | + self.capture_cursor_pic = False |
2407 | + self.capture_borders_pic = False |
2408 | + |
2409 | + self.countdown_timer = 5 |
2410 | + |
2411 | + self.speakers_source = None |
2412 | + self.microphone_source = None |
2413 | + |
2414 | + self.speakers_volume = 0 |
2415 | + self.microphone_volume = 0 |
2416 | + |
2417 | + self.countdown_splash = True |
2418 | + self.silent_start = False |
2419 | + |
2420 | + # |
2421 | + # Other stuff |
2422 | + # |
2423 | + self.datadir = None |
2424 | + |
2425 | + # |
2426 | + # Capture related stuff |
2427 | + # |
2428 | + self.codec = None |
2429 | + self.pa_q = None |
2430 | + self.framerate = 15 |
2431 | + self.autosave_video = False |
2432 | + self.autosave_video_file = None |
2433 | + |
2434 | + self.autosave_picture = False |
2435 | + self.autosave_picture_file = None |
2436 | + self.shutter_sound = True |
2437 | + self.shutter_type = 0 |
2438 | + self.shutter_sound_file = "" |
2439 | + |
2440 | + self.area = None |
2441 | + self.xid = None |
2442 | + self.xid_geometry = None |
2443 | + |
2444 | + # |
2445 | + # Audio sources |
2446 | + # - Tuple of all sources |
2447 | + # - Selected first source |
2448 | + # - Selected second source |
2449 | + # |
2450 | + self.audio_sources = None |
2451 | + self.audio_source = None |
2452 | + self.audio2_source = None |
2453 | + |
2454 | + # |
2455 | + # Command line parameters |
2456 | + # |
2457 | + self.debug = False |
2458 | + self.test = False |
2459 | + self.dist = ('Ubuntu', '12.10', 'quantal') |
2460 | + self.silent = False |
2461 | + self.sound = True |
2462 | + |
2463 | + self.config = KazamConfig() |
2464 | + |
2465 | + self.read_config() |
2466 | + |
2467 | + self.get_dirs() |
2468 | + |
2469 | + def get_audio_sources(self): |
2470 | + self.logger.debug("Getting Audio sources.") |
2471 | + try: |
2472 | + self.audio_sources = prefs.pa_q.get_audio_sources() |
2473 | + #self.audio_sources.insert(0, []) |
2474 | + if prefs.debug: |
2475 | + for src in self.audio_sources: |
2476 | + self.logger.debug(" Device found: ") |
2477 | + for item in src: |
2478 | + self.logger.debug(" - {0}".format(item)) |
2479 | + except: |
2480 | + # Something went wrong, just fallback to no-sound |
2481 | + self.logger.warning("Unable to find any audio devices.") |
2482 | + self.audio_sources = [[0, _("Unknown"), _("Unknown")]] |
2483 | + |
2484 | + def get_dirs(self): |
2485 | + paths = {} |
2486 | + f = None |
2487 | + try: |
2488 | + f = open(os.path.join(xdg_config_home, "user-dirs.dirs")) |
2489 | + for la in f: |
2490 | + if la.startswith("XDG_VIDEOS") or la.startswith("XDG_DOCUMENTS") or la.startswith("XDG_PICTURES") : |
2491 | + (idx, val) = la.strip()[:-1].split('="') |
2492 | + paths[idx] = os.path.expandvars(val) |
2493 | + except: |
2494 | + paths['XDG_VIDEOS_DIR'] = os.path.expanduser("~/Videos/") |
2495 | + paths['XDG_PICTURES_DIR'] = os.path.expanduser("~/Pictures/") |
2496 | + paths['XDG_DOCUMENTS_DIR'] = os.path.expanduser("~/Documents/") |
2497 | + finally: |
2498 | + if f is not None: |
2499 | + f.close() |
2500 | + |
2501 | + paths['HOME_DIR'] = os.path.expandvars("$HOME") |
2502 | + |
2503 | + if os.path.isdir(paths['XDG_VIDEOS_DIR']): |
2504 | + self.video_dest = paths['XDG_VIDEOS_DIR'] |
2505 | + elif os.path.isdir(paths['XDG_DOCUMENTS_DIR']): |
2506 | + self.video_dest = paths['XDG_DOCUMENTS_DIR'] |
2507 | + elif os.path.isdir(paths['HOME_DIR']): |
2508 | + self.video_dest = paths['HOME_DIR'] |
2509 | + |
2510 | + if os.path.isdir(paths['XDG_PICTURES_DIR']): |
2511 | + self.picture_dest = paths['XDG_PICTURES_DIR'] |
2512 | + elif os.path.isdir(paths['XDG_DOCUMENTS_DIR']): |
2513 | + self.picture_dest = paths['XDG_DOCUMENTS_DIR'] |
2514 | + elif os.path.isdir(paths['HOME_DIR']): |
2515 | + self.picture_dest = paths['HOME_DIR'] |
2516 | + |
2517 | + |
2518 | + def get_sound_files(self): |
2519 | + self.sound_files = [] |
2520 | + for root, dir, files in os.walk(os.path.join(self.datadir, "sounds")): |
2521 | + for file in files: |
2522 | + if file.endswith('.ogg'): |
2523 | + self.sound_files.append(file) |
2524 | + |
2525 | + |
2526 | + def read_config (self): |
2527 | + self.audio_source = self.config.getint("main", "audio_source") |
2528 | + self.audio2_source = self.config.getint("main", "audio2_source") |
2529 | + |
2530 | + self.main_x = self.config.getint("main", "last_x") |
2531 | + self.main_y = self.config.getint("main", "last_y") |
2532 | + |
2533 | + self.codec = self.config.getint("main", "codec") |
2534 | + |
2535 | + self.countdown_timer = self.config.getfloat("main", "counter") |
2536 | + self.framerate = self.config.getfloat("main", "framerate") |
2537 | + |
2538 | + self.capture_cursor = self.config.getboolean("main", "capture_cursor") |
2539 | + self.capture_microphone = self.config.getboolean("main", "capture_microphone") |
2540 | + self.capture_speakers = self.config.getboolean("main", "capture_speakers") |
2541 | + |
2542 | + self.capture_cursor_pic = self.config.getboolean("main", "capture_cursor_pic") |
2543 | + self.capture_borders_pic = self.config.getboolean("main", "capture_borders_pic") |
2544 | + |
2545 | + self.countdown_splash = self.config.getboolean("main", "countdown_splash") |
2546 | + |
2547 | + self.autosave_video = self.config.getboolean("main", "autosave_video") |
2548 | + self.autosave_video_file = self.config.get("main", "autosave_video_file") |
2549 | + |
2550 | + self.autosave_picture = self.config.getboolean("main", "autosave_picture") |
2551 | + self.autosave_picture_file = self.config.get("main", "autosave_picture_file") |
2552 | + |
2553 | + self.shutter_sound = self.config.getboolean("main", "shutter_sound") |
2554 | + self.shutter_type = self.config.getint("main", "shutter_type") |
2555 | + |
2556 | + |
2557 | + def save_config(self): |
2558 | + self.config.set("main", "capture_cursor", self.capture_cursor) |
2559 | + self.config.set("main", "capture_speakers", self.capture_speakers) |
2560 | + self.config.set("main", "capture_microphone", self.capture_microphone) |
2561 | + |
2562 | + self.config.set("main", "capture_cursor_pic", self.capture_cursor_pic) |
2563 | + self.config.set("main", "capture_borders_pic", self.capture_borders_pic) |
2564 | + |
2565 | + self.config.set("main", "last_x", self.main_x) |
2566 | + self.config.set("main", "last_y", self.main_y) |
2567 | + |
2568 | + if self.sound: |
2569 | + self.config.set("main", "audio_source", self.audio_source) |
2570 | + self.config.set("main", "audio2_source", self.audio2_source) |
2571 | + |
2572 | + self.config.set("main", "countdown_splash", self.countdown_splash) |
2573 | + self.config.set("main", "counter", self.countdown_timer) |
2574 | + self.config.set("main", "codec", self.codec) |
2575 | + self.config.set("main", "framerate", self.framerate) |
2576 | + self.config.set("main", "autosave_video", self.autosave_video) |
2577 | + self.config.set("main", "autosave_video_file", self.autosave_video_file) |
2578 | + self.config.set("main", "autosave_picture", self.autosave_picture) |
2579 | + self.config.set("main", "autosave_picture_file", self.autosave_picture_file) |
2580 | + self.config.set("main", "shutter_sound", self.shutter_sound) |
2581 | + self.config.set("main", "shutter_type", self.shutter_type) |
2582 | + |
2583 | + self.config.write() |
2584 | + |
2585 | +prefs = Prefs() |
2586 | |
2587 | === added directory 'build/lib.linux-x86_64-2.7/kazam/frontend' |
2588 | === added file 'build/lib.linux-x86_64-2.7/kazam/frontend/__init__.py' |
2589 | --- build/lib.linux-x86_64-2.7/kazam/frontend/__init__.py 1970-01-01 00:00:00 +0000 |
2590 | +++ build/lib.linux-x86_64-2.7/kazam/frontend/__init__.py 2012-11-15 10:17:01 +0000 |
2591 | @@ -0,0 +1,1 @@ |
2592 | + |
2593 | |
2594 | === added file 'build/lib.linux-x86_64-2.7/kazam/frontend/about_dialog.py' |
2595 | --- build/lib.linux-x86_64-2.7/kazam/frontend/about_dialog.py 1970-01-01 00:00:00 +0000 |
2596 | +++ build/lib.linux-x86_64-2.7/kazam/frontend/about_dialog.py 2012-11-15 10:17:01 +0000 |
2597 | @@ -0,0 +1,70 @@ |
2598 | +# -*- coding: utf-8 -*- |
2599 | +# |
2600 | +# authenticate.py |
2601 | +# |
2602 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
2603 | +# Copyright 2010 Andrew <andrew@karmic-desktop> |
2604 | +# |
2605 | +# This program is free software; you can redistribute it and/or modify |
2606 | +# it under the terms of the GNU General Public License as published by |
2607 | +# the Free Software Foundation; either version 3 of the License, or |
2608 | +# (at your option) any later version. |
2609 | +# |
2610 | +# This program is distributed in the hope that it will be useful, |
2611 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2612 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2613 | +# GNU General Public License for more details. |
2614 | +# |
2615 | +# You should have received a copy of the GNU General Public License |
2616 | +# along with this program; if not, write to the Free Software |
2617 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
2618 | +# MA 02110-1301, USA. |
2619 | + |
2620 | +from gettext import gettext as _ |
2621 | +from gi.repository import Gtk |
2622 | +from kazam.version import * |
2623 | + |
2624 | +AUTHORS = """ |
2625 | +Andrew Higginson <rugby471@gmail.com> |
2626 | +David Klasinc <bigwhale@lubica.net> |
2627 | +""" |
2628 | + |
2629 | +ARTISTS = """ |
2630 | +Robert McKenna <ttk1opc@yahoo.com> |
2631 | +Andrew Higginson <rugby471@gmail.com> |
2632 | +""" |
2633 | +LICENSE = """ |
2634 | + This program is free software: you can redistribute it and/or modify |
2635 | + it under the terms of the GNU General Public License as published by |
2636 | + the Free Software Foundation, either version 3 of the License, or |
2637 | + (at your option) any later version. |
2638 | + |
2639 | + This program is distributed in the hope that it will be useful, |
2640 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
2641 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2642 | + GNU General Public License for more details. |
2643 | + |
2644 | + You should have received a copy of the GNU General Public License |
2645 | + along with this program. If not, see <http://www.gnu.org/licenses/>. |
2646 | +""" |
2647 | + |
2648 | +def AboutDialog(icons): |
2649 | + dialog = Gtk.AboutDialog() |
2650 | + dialog.set_program_name(_("Kazam Screencaster") + " - \"" + CODENAME + "\"") |
2651 | + dialog.set_comments(_("Record a video of activity on your screen.")) |
2652 | + dialog.set_license(LICENSE) |
2653 | + dialog.set_version(VERSION) |
2654 | + dialog.set_copyright("© 2010 Andrew Higginson, © 2012 David Klasinc") |
2655 | + dialog.set_website("http://launchpad.net/kazam") |
2656 | + dialog.set_authors(AUTHORS.split("\n")) |
2657 | + dialog.set_artists(ARTISTS.split("\n")) |
2658 | + try: |
2659 | + icon = icons.load_icon("kazam", 96, Gtk.IconLookupFlags.GENERIC_FALLBACK) |
2660 | + dialog.set_logo(icon) |
2661 | + except: |
2662 | + # Not important, we just don't get to show our lovely logo.. :) |
2663 | + pass |
2664 | + dialog.show_all() |
2665 | + dialog.set_position(Gtk.WindowPosition.CENTER) |
2666 | + dialog.run() |
2667 | + dialog.hide() |
2668 | |
2669 | === added file 'build/lib.linux-x86_64-2.7/kazam/frontend/combobox.py' |
2670 | --- build/lib.linux-x86_64-2.7/kazam/frontend/combobox.py 1970-01-01 00:00:00 +0000 |
2671 | +++ build/lib.linux-x86_64-2.7/kazam/frontend/combobox.py 2012-11-15 10:17:01 +0000 |
2672 | @@ -0,0 +1,116 @@ |
2673 | +# -*- coding: utf-8 -*- |
2674 | +# |
2675 | +# combobox.py |
2676 | +# |
2677 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
2678 | +# Copyright 2010 Andrew <andrew@karmic-desktop> |
2679 | +# |
2680 | +# This program is free software; you can redistribute it and/or modify |
2681 | +# it under the terms of the GNU General Public License as published by |
2682 | +# the Free Software Foundation; either version 3 of the License, or |
2683 | +# (at your option) any later version. |
2684 | +# |
2685 | +# This program is distributed in the hope that it will be useful, |
2686 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2687 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2688 | +# GNU General Public License for more details. |
2689 | +# |
2690 | +# You should have received a copy of the GNU General Public License |
2691 | +# along with this program; if not, write to the Free Software |
2692 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
2693 | +# MA 02110-1301, USA. |
2694 | + |
2695 | +import os |
2696 | + |
2697 | +from xdg.DesktopEntry import DesktopEntry |
2698 | +from gi.repository import Gtk, GdkPixbuf, GObject |
2699 | + |
2700 | +from kazam.backend.prefs import * |
2701 | + |
2702 | +class EditComboBox(Gtk.ComboBox): |
2703 | + |
2704 | + KDENLIVE_VERSION = [0,8] |
2705 | + |
2706 | + # |
2707 | + # This really needs to be done differently ... |
2708 | + # |
2709 | + if prefs.dist[2] == 'quantal': |
2710 | + EDITORS = { |
2711 | + "/usr/share/app-install/desktop/openshot:openshot.desktop":[], |
2712 | + "/usr/share/app-install/desktop/pitivi:pitivi.desktop":["-i", "-a"], |
2713 | + "/usr/share/app-install/desktop/avidemux:avidemux-gtk.desktop":[], |
2714 | + "/usr/share/app-install/desktop/kdenlive:kde4__kdenlive.desktop":["-i"], |
2715 | + } |
2716 | + else: |
2717 | + EDITORS = { |
2718 | + "/usr/share/applications/openshot.desktop":[], |
2719 | + "/usr/share/applications/pitivi.desktop":["-i", "-a"], |
2720 | + "/usr/share/applications/avidemux-gtk.desktop":[], |
2721 | + "/usr/share/applications/kde4/kdenlive.desktop":["-i"], |
2722 | + } |
2723 | + |
2724 | + def __init__(self, icons): |
2725 | + Gtk.ComboBox.__init__(self) |
2726 | + self.icons = icons |
2727 | + self.empty = True |
2728 | + cr_pixbuf = Gtk.CellRendererPixbuf() |
2729 | + self.pack_start(cr_pixbuf, True) |
2730 | + self.add_attribute(cr_pixbuf, 'pixbuf', 0) |
2731 | + cr_text = Gtk.CellRendererText() |
2732 | + self.pack_start(cr_text, True) |
2733 | + self.add_attribute(cr_text, 'text', 1) |
2734 | + |
2735 | + self.box_model = Gtk.ListStore(GdkPixbuf.Pixbuf, str, |
2736 | + GObject.TYPE_PYOBJECT, |
2737 | + GObject.TYPE_PYOBJECT |
2738 | + ) |
2739 | + self.set_model(self.box_model) |
2740 | + self._populate() |
2741 | + self.set_active(0) |
2742 | + self.set_sensitive(True) |
2743 | + self.show() |
2744 | + |
2745 | + def get_active_value(self): |
2746 | + i = self.get_active() |
2747 | + model = self.get_model() |
2748 | + model_iter = model.get_iter(i) |
2749 | + return (model.get_value(model_iter, 2), |
2750 | + model.get_value(model_iter, 3)) |
2751 | + |
2752 | + def _populate(self): |
2753 | + for item in self.EDITORS: |
2754 | + if os.path.isfile(item): |
2755 | + args = self.EDITORS[item] |
2756 | + desktop_entry = DesktopEntry(item) |
2757 | + command = desktop_entry.getExec() |
2758 | + |
2759 | + # For .desktop files with ' %U' or ' # %F' |
2760 | + command = command.split(" ")[0] |
2761 | + |
2762 | + name = desktop_entry.getName() |
2763 | + icon_name = desktop_entry.getIcon() |
2764 | + |
2765 | + self._add_item(icon_name, name, command, args) |
2766 | + |
2767 | + if len(self.get_model()): |
2768 | + self.empty = False |
2769 | + else: |
2770 | + self.empty = True |
2771 | + |
2772 | + def _add_item(self, icon_name, name, command, args): |
2773 | + liststore = self.get_model() |
2774 | + try: |
2775 | + pixbuf = self.icons.load_icon(icon_name, 16, Gtk.IconLookupFlags.GENERIC_FALLBACK) |
2776 | + except: |
2777 | + pixbuf = self.icons.load_icon("application-x-executable", 16, Gtk.IconLookupFlags.GENERIC_FALLBACK) |
2778 | + |
2779 | + liststore.append([pixbuf, name, command, args]) |
2780 | + |
2781 | + def _version_is_gte(self, required_version, current_version): |
2782 | + i = 0 |
2783 | + for digit in current_version: |
2784 | + required_digit = required_version[i] |
2785 | + current_digit = int(digit) |
2786 | + if current_digit < required_digit: |
2787 | + return False |
2788 | + return True |
2789 | |
2790 | === added file 'build/lib.linux-x86_64-2.7/kazam/frontend/done_recording.py' |
2791 | --- build/lib.linux-x86_64-2.7/kazam/frontend/done_recording.py 1970-01-01 00:00:00 +0000 |
2792 | +++ build/lib.linux-x86_64-2.7/kazam/frontend/done_recording.py 2012-11-15 10:17:01 +0000 |
2793 | @@ -0,0 +1,159 @@ |
2794 | +# -*- coding: utf-8 -*- |
2795 | +# |
2796 | +# app.py |
2797 | +# |
2798 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
2799 | +# Copyright 2010 Andrew <andrew@karmic-desktop> |
2800 | +# |
2801 | +# This program is free software; you can redistribute it and/or modify |
2802 | +# it under the terms of the GNU General Public License as published by |
2803 | +# the Free Software Foundation; either version 3 of the License, or |
2804 | +# (at your option) any later version. |
2805 | +# |
2806 | +# This program is distributed in the hope that it will be useful, |
2807 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2808 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2809 | +# GNU General Public License for more details. |
2810 | +# |
2811 | +# You should have received a copy of the GNU General Public License |
2812 | +# along with this program; if not, write to the Free Software |
2813 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
2814 | +# MA 02110-1301, USA. |
2815 | + |
2816 | +import os |
2817 | +import shutil |
2818 | +import logging |
2819 | +logger = logging.getLogger("Done Recording") |
2820 | + |
2821 | +from gettext import gettext as _ |
2822 | +from gi.repository import Gtk, GObject |
2823 | + |
2824 | +from kazam.backend.constants import * |
2825 | +from kazam.frontend.combobox import EditComboBox |
2826 | +from kazam.frontend.save_dialog import SaveDialog |
2827 | + |
2828 | +class DoneRecording(Gtk.Window): |
2829 | + |
2830 | + __gsignals__ = { |
2831 | + "save-done" : (GObject.SIGNAL_RUN_LAST, |
2832 | + None, |
2833 | + [GObject.TYPE_PYOBJECT],), |
2834 | + "edit-request" : (GObject.SIGNAL_RUN_LAST, |
2835 | + None, |
2836 | + [GObject.TYPE_PYOBJECT],), |
2837 | + "save-cancel" : (GObject.SIGNAL_RUN_LAST, |
2838 | + None, |
2839 | + (),) |
2840 | + } |
2841 | + |
2842 | + def __init__(self, icons, tempfile, codec, old_path): |
2843 | + Gtk.Window.__init__(self, title=_("Kazam Screencaster - Recording finished")) |
2844 | + self.icons = icons |
2845 | + self.tempfile = tempfile |
2846 | + self.codec = codec |
2847 | + self.action = ACTION_SAVE |
2848 | + self.old_path = old_path |
2849 | + self.set_position(Gtk.WindowPosition.NONE) |
2850 | + |
2851 | + # Setup UI |
2852 | + self.set_border_width(10) |
2853 | + self.vbox = Gtk.Box(spacing = 20, orientation = Gtk.Orientation.VERTICAL) |
2854 | + self.label_box = Gtk.Box() |
2855 | + self.done_label = Gtk.Label(_("Kazam finished recording.\nWhat do you want to do now?")) |
2856 | + self.label_box.add(self.done_label) |
2857 | + self.grid = Gtk.Grid(row_spacing = 10, column_spacing = 5) |
2858 | + self.radiobutton_edit = Gtk.RadioButton.new_with_label_from_widget(None, _("Edit with:")) |
2859 | + self.combobox_editor = EditComboBox(self.icons) |
2860 | + self.grid.add(self.radiobutton_edit) |
2861 | + self.grid.attach_next_to(self.combobox_editor, |
2862 | + self.radiobutton_edit, |
2863 | + Gtk.PositionType.RIGHT, |
2864 | + 1, 1) |
2865 | + self.radiobutton_save = Gtk.RadioButton.new_from_widget(self.radiobutton_edit) |
2866 | + self.radiobutton_save.set_label(_("Save for later")) |
2867 | + |
2868 | + if self.combobox_editor.empty: |
2869 | + self.radiobutton_edit.set_active(False) |
2870 | + self.radiobutton_edit.set_sensitive(False) |
2871 | + |
2872 | + self.radiobutton_save.set_active(True) |
2873 | + |
2874 | + self.radiobutton_save.connect("toggled", self.cb_radiobutton_save_toggled) |
2875 | + self.radiobutton_edit.connect("toggled", self.cb_radiobutton_edit_toggled) |
2876 | + self.btn_cancel = Gtk.Button(label = _("Cancel")) |
2877 | + self.btn_cancel.set_size_request(100, -1) |
2878 | + self.btn_continue = Gtk.Button(label = _("Continue")) |
2879 | + self.btn_continue.set_size_request(100, -1) |
2880 | + |
2881 | + self.btn_continue.connect("clicked", self.cb_continue_clicked) |
2882 | + self.btn_cancel.connect("clicked", self.cb_cancel_clicked) |
2883 | + |
2884 | + self.hbox = Gtk.Box(spacing = 10) |
2885 | + self.left_hbox = Gtk.Box() |
2886 | + self.right_hbox = Gtk.Box(spacing = 5) |
2887 | + |
2888 | + self.right_hbox.pack_start(self.btn_cancel, False, True, 0) |
2889 | + self.right_hbox.pack_start(self.btn_continue, False, True, 0) |
2890 | + |
2891 | + self.hbox.pack_start(self.left_hbox, True, True, 0) |
2892 | + self.hbox.pack_start(self.right_hbox, False, False, 0) |
2893 | + |
2894 | + self.vbox.pack_start(self.label_box, True, True, 0) |
2895 | + self.vbox.pack_start(self.grid, True, True, 0) |
2896 | + self.vbox.pack_start(self.radiobutton_save, True, True, 0) |
2897 | + self.vbox.pack_start(self.hbox, True, True, 0) |
2898 | + self.add(self.vbox) |
2899 | + self.connect("delete-event", self.cb_delete_event) |
2900 | + self.show_all() |
2901 | + self.present() |
2902 | + |
2903 | + |
2904 | + def cb_continue_clicked(self, widget): |
2905 | + if self.action == ACTION_EDIT: |
2906 | + logger.debug("Continue - Edit.") |
2907 | + (command, args) = self.combobox_editor.get_active_value() |
2908 | + self.emit("edit-request", (command, args)) |
2909 | + self.destroy() |
2910 | + else: |
2911 | + self.set_sensitive(False) |
2912 | + logger.debug("Continue - Save ({0}).".format(self.codec)) |
2913 | + (dialog, result, self.old_path) = SaveDialog(_("Save screencast"), |
2914 | + self.old_path, self.codec) |
2915 | + |
2916 | + if result == Gtk.ResponseType.OK: |
2917 | + uri = os.path.join(dialog.get_current_folder(), dialog.get_filename()) |
2918 | + |
2919 | + if not uri.endswith(CODEC_LIST[self.codec][3]): |
2920 | + uri += CODEC_LIST[self.codec][3] |
2921 | + |
2922 | + shutil.move(self.tempfile, uri) |
2923 | + dialog.destroy() |
2924 | + self.emit("save-done", self.old_path) |
2925 | + self.destroy() |
2926 | + else: |
2927 | + self.set_sensitive(True) |
2928 | + dialog.destroy() |
2929 | + |
2930 | + |
2931 | + def cb_cancel_clicked(self, widget): |
2932 | + self.emit("save-cancel") |
2933 | + self.destroy() |
2934 | + |
2935 | + def cb_delete_event(self, widget, data): |
2936 | + self.emit("save-cancel") |
2937 | + self.destroy() |
2938 | + |
2939 | + def cb_radiobutton_save_toggled(self, widget): |
2940 | + if not widget.get_active(): |
2941 | + return |
2942 | + else: |
2943 | + self.action = ACTION_SAVE |
2944 | + self.combobox_editor.set_sensitive(False) |
2945 | + |
2946 | + def cb_radiobutton_edit_toggled(self, widget): |
2947 | + if not widget.get_active(): |
2948 | + return |
2949 | + else: |
2950 | + self.action = ACTION_EDIT |
2951 | + self.combobox_editor.set_sensitive(True) |
2952 | + |
2953 | |
2954 | === added file 'build/lib.linux-x86_64-2.7/kazam/frontend/export.py' |
2955 | --- build/lib.linux-x86_64-2.7/kazam/frontend/export.py 1970-01-01 00:00:00 +0000 |
2956 | +++ build/lib.linux-x86_64-2.7/kazam/frontend/export.py 2012-11-15 10:17:01 +0000 |
2957 | @@ -0,0 +1,269 @@ |
2958 | +# -*- coding: utf-8 -*- |
2959 | +# |
2960 | +# export_frontend.py |
2961 | +# |
2962 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
2963 | +# Copyright 2010 Andrew <andrew@karmic-desktop> |
2964 | +# |
2965 | +# This program is free software; you can redistribute it and/or modify |
2966 | +# it under the terms of the GNU General Public License as published by |
2967 | +# the Free Software Foundation; either version 3 of the License, or |
2968 | +# (at your option) any later version. |
2969 | +# |
2970 | +# This program is distributed in the hope that it will be useful, |
2971 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2972 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2973 | +# GNU General Public License for more details. |
2974 | +# |
2975 | +# You should have received a copy of the GNU General Public License |
2976 | +# along with this program; if not, write to the Free Software |
2977 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
2978 | +# MA 02110-1301, USA. |
2979 | + |
2980 | +import logging |
2981 | +import os |
2982 | + |
2983 | +from gettext import gettext as _ |
2984 | +from gi.repository import Gtk, GObject |
2985 | + |
2986 | +from kazam.utils import * |
2987 | +from kazam.backend.export import ExportBackend |
2988 | + |
2989 | +class ExportFrontend(GObject.GObject): |
2990 | + |
2991 | + __gsignals__ = { |
2992 | + "back-requested" : (GObject.SIGNAL_RUN_LAST, |
2993 | + GObject.TYPE_NONE, |
2994 | + ( ),), |
2995 | + "export-requested" : (GObject.SIGNAL_RUN_LAST, |
2996 | + GObject.TYPE_NONE, |
2997 | + ( ),) |
2998 | + } |
2999 | + |
3000 | + def __init__(self, datadir, icons, recorder): |
3001 | + GObject.GObject.__init__(self) |
3002 | + |
3003 | + self.recorder = recorder |
3004 | + |
3005 | + # Setup Backend |
3006 | + self.backend = ExportBackend(self, datadir) |
3007 | + self.backend.connect("authenticate-requested", self.cb_authenticate_requested) |
3008 | + self.backend.connect("login-started", self.cb_login_started) |
3009 | + self.backend.connect("login-completed", self.cb_login_completed) |
3010 | + self.backend.connect("convert-started", self.cb_convert_started) |
3011 | + self.backend.connect("convert-completed", self.cb_convert_completed) |
3012 | + self.backend.connect("upload-started", self.cb_upload_started) |
3013 | + self.backend.connect("upload-completed", self.cb_upload_completed) |
3014 | + |
3015 | + self.active_alignment = None |
3016 | + |
3017 | + # Setup UI |
3018 | + builder = Gtk.Builder() |
3019 | + builder.add_from_file(os.path.join(datadir, "ui", "export.ui")) |
3020 | + |
3021 | + # Get window |
3022 | + self.window = builder.get_object("window_export") |
3023 | + self.window.connect("delete-event", Gtk.main_quit) |
3024 | + |
3025 | + # Setup quality sliders |
3026 | + self.setup_quality_sliders() |
3027 | + |
3028 | + # Export combobox setup |
3029 | + export_objects = self.backend.get_export_objects() |
3030 | + export_object_details = [] |
3031 | + for obj in export_objects: |
3032 | + name = obj.NAME |
3033 | + icon = obj.ICONS[0] |
3034 | + tup = (icon, name) |
3035 | + export_object_details.append(tup) |
3036 | + |
3037 | + self.combobox_export = ExportCombobox(self.icons, export_object_details) |
3038 | + self.combobox_export.connect("changed", self.on_combobox_export_changed) |
3039 | + self.hbox_export.pack_start(self.combobox_export, False, True) |
3040 | + self.hbox_export.reorder_child(self.combobox_export, 1) |
3041 | + self.on_combobox_export_changed(None) |
3042 | + |
3043 | + def run(self): |
3044 | + self.window.show_all() |
3045 | + |
3046 | + def setup_quality_sliders(self): |
3047 | + |
3048 | + if self.screencast.get_video_recorded(): |
3049 | + # Video Quality Slider |
3050 | + self.adjustment_quality_video = Gtk.Adjustment(3000, 200, 6001, 1) |
3051 | + self.hscale_quality_video = Gtk.HScale(self.adjustment_quality_video) |
3052 | + self.hscale_quality_video.set_draw_value(False) |
3053 | + self.hbox_quality_video.pack_start(self.hscale_quality_video) |
3054 | + else: |
3055 | + self.vbox_quality_video.destroy() |
3056 | + |
3057 | + # (If audio was recorded) Audio Quality Slider |
3058 | + if self.screencast.get_audio_recorded(): |
3059 | + self.adjustment_quality_audio = Gtk.Adjustment(140, 32, 256, 1) |
3060 | + self.hscale_quality_audio = Gtk.HScale(self.adjustment_quality_audio) |
3061 | + self.hscale_quality_audio.set_draw_value(False) |
3062 | + self.hbox_quality_audio.pack_start(self.hscale_quality_audio) |
3063 | + else: |
3064 | + self.vbox_quality_audio.destroy() |
3065 | + |
3066 | + def on_button_back_clicked(self, button): |
3067 | + self.emit("back-requested") |
3068 | + self.window.destroy() |
3069 | + |
3070 | + def on_button_export_clicked(self, button): |
3071 | + self.emit("export-requested") |
3072 | + |
3073 | + def on_combobox_export_changed(self, combobox): |
3074 | + # If we already have an alignment, unpack it |
3075 | + if self.active_alignment: |
3076 | + self.vbox_main.remove(self.active_alignment) |
3077 | + |
3078 | + # Get our current item's object |
3079 | + i = self.combobox_export.get_active() |
3080 | + active_object = self.backend.set_active_export_object(i) |
3081 | + # And its alignment |
3082 | + self.active_alignment = active_object.alignment_properties |
3083 | + |
3084 | + # Run the alignment's expose function |
3085 | + active_object.property_alignment_expose() |
3086 | + |
3087 | + # Pack our alignment |
3088 | + self.vbox_main.pack_start(self.active_alignment, True, True) |
3089 | + self.vbox_main.reorder_child(self.active_alignment, 2) |
3090 | + |
3091 | + def _change_status(self, img, text): |
3092 | + for child in self.hbox_status.get_children(): |
3093 | + child.destroy() |
3094 | + if img == "spinner": |
3095 | + img_widget = gtk.Spinner() |
3096 | + img_widget.start() |
3097 | + else: |
3098 | + img_widget = Gtk.image_new_from_stock(img, Gtk.ICON_SIZE_MENU) |
3099 | + text_widget = Gtk.Label(text) |
3100 | + self.hbox_status.pack_start(img_widget, False, False) |
3101 | + self.hbox_status.pack_start(text_widget, False, False) |
3102 | + self.hbox_status.show_all() |
3103 | + |
3104 | + def get_screencast(self): |
3105 | + return self.screencast |
3106 | + |
3107 | + def get_meta(self): |
3108 | + active_export_object = self.backend.get_active_export_object() |
3109 | + meta = active_export_object.META.copy() |
3110 | + # For every property in the meta dict... |
3111 | + for prop in meta: |
3112 | + # ..get the corresponding widget in the meta dict |
3113 | + widget = getattr(active_export_object, meta[prop]) |
3114 | + # ...get the corresponding widget value and add to the dict |
3115 | + # inplace of the widget |
3116 | + meta[prop] = self.get_property_value(widget) |
3117 | + return meta |
3118 | + |
3119 | + def get_video_quality(self): |
3120 | + if self.screencast.get_video_recorded(): |
3121 | + return self.adjustment_quality_video.get_value() |
3122 | + return False |
3123 | + |
3124 | + def get_audio_quality(self): |
3125 | + if self.screencast.get_audio_recorded(): |
3126 | + return self.adjustment_quality_audio.get_value() |
3127 | + return False |
3128 | + |
3129 | + def get_property_value(self, widget): |
3130 | + # Convenience function to get property value based on widget type |
3131 | + if isinstance(widget, gtk.Entry): |
3132 | + return widget.get_text() |
3133 | + elif isinstance(widget, gtk.TextView): |
3134 | + buf = widget.get_buffer() |
3135 | + return buf.get_text(buf.get_start_iter(), buf.get_end_iter()) |
3136 | + elif isinstance(widget, EasyTextAndObjectComboBox): |
3137 | + tuple_ = (widget.get_active_value(0), widget.get_active_value(1)) |
3138 | + return tuple_ |
3139 | + elif issubclass(widget.__class__, EasyComboBox): |
3140 | + return widget.get_active_value(0) |
3141 | + |
3142 | + def sensitise_content_action_widgets(self, sensitive): |
3143 | + self.active_alignment.set_sensitive(sensitive) |
3144 | + self.button_export.set_sensitive(sensitive) |
3145 | + self.button_back.set_sensitive(sensitive) |
3146 | + self.combobox_export.set_sensitive(sensitive) |
3147 | + self.label_export.set_sensitive(sensitive) |
3148 | + |
3149 | + def cb_authenticate_requested(self, backend, icons, name, register_url): |
3150 | + authenticate_dialog = AuthenticateDialog(self.datadir, name, self.icons, icons, register_url) |
3151 | + authenticate_dialog.window.set_transient_for(self.window) |
3152 | + authenticate_dialog.run() |
3153 | + self.window.set_sensitive(False) |
3154 | + while (not hasattr(authenticate_dialog, "details")): |
3155 | + if authenticate_dialog.action == authenticate_dialog.ACTION_CANCEL: |
3156 | + break |
3157 | + gtk.main_iteration() |
3158 | + self.window.set_sensitive(True) |
3159 | + if authenticate_dialog.action == authenticate_dialog.ACTION_CANCEL: |
3160 | + return |
3161 | + self.backend.details = authenticate_dialog.details |
3162 | + |
3163 | + def cb_login_started(self, backend): |
3164 | + self._change_status("spinner", _("Logging in...")) |
3165 | + # Make buttons, combobox, label and the alignment insensitive |
3166 | + self.sensitise_content_action_widgets(False) |
3167 | + |
3168 | + def cb_login_completed(self, backend, success): |
3169 | + if success: |
3170 | + self._change_status(gtk.STOCK_OK, _("Log-in completed.")) |
3171 | + else: |
3172 | + self._change_status(gtk.STOCK_DIALOG_ERROR, _("There was an error logging in.")) |
3173 | + # Set buttons, combobox and the alignment sensitive |
3174 | + self.sensitise_content_action_widgets(True) |
3175 | + |
3176 | + def cb_convert_started(self, backend): |
3177 | + self._change_status("spinner", _("Converting screencast...")) |
3178 | + |
3179 | + def cb_convert_completed(self, backend, success): |
3180 | + if success: |
3181 | + self._change_status(Gtk.STOCK_OK, _("Screencast converted.")) |
3182 | + else: |
3183 | + self._change_status(Gtk.STOCK_DIALOG_ERROR, _("There was an error converting.")) |
3184 | + # Set buttons, combobox and the alignment sensitive |
3185 | + self.sensitise_content_action_widgets(True) |
3186 | + |
3187 | + def cb_upload_started(self, backend): |
3188 | + self._change_status("spinner", _("Uploading screencast...")) |
3189 | + |
3190 | + def cb_upload_completed(self, backend, success, url): |
3191 | + if success: |
3192 | + self._change_status(Gtk.STOCK_OK, _("Screencast uploaded.")) |
3193 | + # Set buttons, combobox and the alignment sensitive |
3194 | + self.sensitise_content_action_widgets(True) |
3195 | + # Show a dialog with the url of the uploaded file |
3196 | + new_linkbutton_dialog(url, _("Your screencast has uploaded successfully."), |
3197 | + _("It is available at the location below:"), self.window) |
3198 | + else: |
3199 | + self._change_status(Gtk.STOCK_DIALOG_ERROR, _("There was an error uploading.")) |
3200 | + # Set buttons, combobox and the alignment sensitive |
3201 | + self.sensitise_content_action_widgets(True) |
3202 | + |
3203 | + |
3204 | +#if __name__ == "__main__": |
3205 | +# from kazam.backend.ffmpeg import Screencast |
3206 | +# |
3207 | +# if os.path.exists("./data/ui/export.ui"): |
3208 | +# logging.info("Running locally") |
3209 | +# datadir = "./data" |
3210 | +# else: |
3211 | +# datadir = "/usr/share/kazam/" |
3212 | +# icons = gtk.icon_theme_get_default() |
3213 | +# icons.append_search_path(os.path.join(datadir,"icons", "48x48", "apps")) |
3214 | +# icons.append_search_path(os.path.join(datadir,"icons", "16x16", "apps")) |
3215 | + |
3216 | +# screencast = Screencast() |
3217 | +# screencast.audio = True |
3218 | + |
3219 | + # export = ExportFrontend(datadir, icons, screencast) |
3220 | + # export.connect("back-requested", gtk.main_quit) |
3221 | + # export.connect("export-requested", gtk.main_quit) |
3222 | + # export.connect("quit-requested", gtk.main_quit) |
3223 | + # export.run() |
3224 | + # gtk.main() |
3225 | + |
3226 | + |
3227 | |
3228 | === added file 'build/lib.linux-x86_64-2.7/kazam/frontend/indicator.py' |
3229 | --- build/lib.linux-x86_64-2.7/kazam/frontend/indicator.py 1970-01-01 00:00:00 +0000 |
3230 | +++ build/lib.linux-x86_64-2.7/kazam/frontend/indicator.py 2012-11-15 10:17:01 +0000 |
3231 | @@ -0,0 +1,311 @@ |
3232 | +# -*- coding: utf-8 -*- |
3233 | +# |
3234 | +# indicator.py |
3235 | +# |
3236 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
3237 | +# Copyright 2010 Andrew <andrew@karmic-desktop> |
3238 | +# |
3239 | +# This program is free software; you can redistribute it and/or modify |
3240 | +# it under the terms of the GNU General Public License as published by |
3241 | +# the Free Software Foundation; either version 3 of the License, or |
3242 | +# (at your option) any later version. |
3243 | +# |
3244 | +# This program is distributed in the hope that it will be useful, |
3245 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
3246 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3247 | +# GNU General Public License for more details. |
3248 | +# |
3249 | +# You should have received a copy of the GNU General Public License |
3250 | +# along with this program; if not, write to the Free Software |
3251 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
3252 | +# MA 02110-1301, USA. |
3253 | + |
3254 | +import logging |
3255 | +logger = logging.getLogger("Indicator") |
3256 | + |
3257 | +from gettext import gettext as _ |
3258 | +from gi.repository import Gtk, GObject |
3259 | + |
3260 | +from kazam.backend.constants import * |
3261 | + |
3262 | +class KazamSuperIndicator(GObject.GObject): |
3263 | + __gsignals__ = { |
3264 | + "indicator-pause-request" : (GObject.SIGNAL_RUN_LAST, |
3265 | + None, |
3266 | + (), ), |
3267 | + "indicator-unpause-request" : (GObject.SIGNAL_RUN_LAST, |
3268 | + None, |
3269 | + (), ), |
3270 | + "indicator-quit-request" : (GObject.SIGNAL_RUN_LAST, |
3271 | + None, |
3272 | + (), ), |
3273 | + "indicator-show-request" : (GObject.SIGNAL_RUN_LAST, |
3274 | + None, |
3275 | + (), ), |
3276 | + "indicator-stop-request" : (GObject.SIGNAL_RUN_LAST, |
3277 | + None, |
3278 | + (), ), |
3279 | + "indicator-start-request" : (GObject.SIGNAL_RUN_LAST, |
3280 | + None, |
3281 | + (), ), |
3282 | + |
3283 | + "indicator-about-request" : (GObject.SIGNAL_RUN_LAST, |
3284 | + None, |
3285 | + (), ), |
3286 | + } |
3287 | + |
3288 | + def __init__(self, silent = False): |
3289 | + super(KazamSuperIndicator, self).__init__() |
3290 | + self.blink_icon = BLINK_STOP_ICON |
3291 | + self.blink_state = False |
3292 | + self.blink_mode = BLINK_SLOW |
3293 | + self.recording = False |
3294 | + self.silent = silent |
3295 | + logger.debug("Indicatior silent: {0}".format(self.silent)) |
3296 | + |
3297 | + self.menu = Gtk.Menu() |
3298 | + |
3299 | + self.menuitem_start = Gtk.MenuItem(_("Start recording")) |
3300 | + self.menuitem_start.set_sensitive(True) |
3301 | + self.menuitem_start.connect("activate", self.on_menuitem_start_activate) |
3302 | + |
3303 | + self.menuitem_pause = Gtk.CheckMenuItem(_("Pause recording")) |
3304 | + self.menuitem_pause.set_sensitive(False) |
3305 | + self.menuitem_pause.connect("toggled", self.on_menuitem_pause_activate) |
3306 | + |
3307 | + self.menuitem_finish = Gtk.MenuItem(_("Finish recording")) |
3308 | + self.menuitem_finish.set_sensitive(False) |
3309 | + self.menuitem_finish.connect("activate", self.on_menuitem_finish_activate) |
3310 | + |
3311 | + self.menuitem_separator = Gtk.SeparatorMenuItem() |
3312 | + self.menuitem_separator2 = Gtk.SeparatorMenuItem() |
3313 | + |
3314 | + self.menuitem_show = Gtk.MenuItem(_("Record setup")) |
3315 | + self.menuitem_show.connect("activate", self.on_menuitem_show_activate) |
3316 | + |
3317 | + self.menuitem_about = Gtk.MenuItem(_("About")) |
3318 | + self.menuitem_about.connect("activate", self.on_menuitem_about_activate) |
3319 | + |
3320 | + |
3321 | + self.menuitem_quit = Gtk.MenuItem(_("Quit")) |
3322 | + self.menuitem_quit.connect("activate", self.on_menuitem_quit_activate) |
3323 | + |
3324 | + self.menu.append(self.menuitem_start) |
3325 | + self.menu.append(self.menuitem_pause) |
3326 | + self.menu.append(self.menuitem_finish) |
3327 | + self.menu.append(self.menuitem_separator) |
3328 | + self.menu.append(self.menuitem_show) |
3329 | + self.menu.append(self.menuitem_about) |
3330 | + self.menu.append(self.menuitem_separator2) |
3331 | + self.menu.append(self.menuitem_quit) |
3332 | + |
3333 | + self.menu.show_all() |
3334 | + |
3335 | + # |
3336 | + # Setup keybindings - Hardcore way |
3337 | + # |
3338 | + try: |
3339 | + from gi.repository import Keybinder |
3340 | + logger.debug("Trying to bind hotkeys.") |
3341 | + Keybinder.init() |
3342 | + Keybinder.bind("<Super><Ctrl>R", self.cb_hotkeys, "start-request") |
3343 | + Keybinder.bind("<Super><Ctrl>F", self.cb_hotkeys, "stop-request") |
3344 | + Keybinder.bind("<Super><Ctrl>P", self.cb_hotkeys, "pause-request") |
3345 | + Keybinder.bind("<Super><Ctrl>W", self.cb_hotkeys, "show-request") |
3346 | + Keybinder.bind("<Super><Ctrl>Q", self.cb_hotkeys, "quit-request") |
3347 | + self.recording = False |
3348 | + except ImportError: |
3349 | + logger.info("Unable to import Keybinder, hotkeys not available.") |
3350 | + |
3351 | + def cb_hotkeys(self, key, action): |
3352 | + logger.debug("KEY {0}, ACTION {1}".format(key, action)) |
3353 | + if action == "start-request" and not self.recording: |
3354 | + self.on_menuitem_start_activate(None) |
3355 | + elif action == "stop-request" and self.recording: |
3356 | + self.on_menuitem_finish_activate(None) |
3357 | + elif action == "pause-request" and self.recording: |
3358 | + if not self.menuitem_pause.get_active(): |
3359 | + self.menuitem_pause.set_active(True) |
3360 | + else: |
3361 | + self.menuitem_pause.set_active(False) |
3362 | + elif action == "show-request" and not self.recording: |
3363 | + self.emit("indicator-show-request") |
3364 | + elif action == "quit-request" and not self.recording: |
3365 | + self.emit("indicator-quit-request") |
3366 | + |
3367 | + def on_menuitem_pause_activate(self, menuitem): |
3368 | + if self.menuitem_pause.get_active(): |
3369 | + self.emit("indicator-pause-request") |
3370 | + else: |
3371 | + self.emit("indicator-unpause-request") |
3372 | + |
3373 | + def on_menuitem_start_activate(self, menuitem): |
3374 | + self.recording = True |
3375 | + self.emit("indicator-start-request") |
3376 | + |
3377 | + def on_menuitem_finish_activate(self, menuitem): |
3378 | + self.recording = False |
3379 | + self.menuitem_start.set_sensitive(True) |
3380 | + self.menuitem_pause.set_sensitive(False) |
3381 | + self.menuitem_pause.set_active(False) |
3382 | + self.menuitem_finish.set_sensitive(False) |
3383 | + self.menuitem_show.set_sensitive(True) |
3384 | + self.menuitem_quit.set_sensitive(True) |
3385 | + self.emit("indicator-stop-request") |
3386 | + |
3387 | + def on_menuitem_quit_activate(self, menuitem): |
3388 | + self.emit("indicator-quit-request") |
3389 | + |
3390 | + def on_menuitem_show_activate(self, menuitem): |
3391 | + self.emit("indicator-show-request") |
3392 | + |
3393 | + def on_menuitem_about_activate(self, menuitem): |
3394 | + self.emit("indicator-about-request") |
3395 | + |
3396 | +try: |
3397 | + from gi.repository import AppIndicator3 |
3398 | + |
3399 | + class KazamIndicator(KazamSuperIndicator): |
3400 | + def __init__(self, silent = False): |
3401 | + super(KazamIndicator, self).__init__(silent) |
3402 | + self.silent = silent |
3403 | + |
3404 | + self.indicator = AppIndicator3.Indicator.new("kazam", |
3405 | + "kazam-stopped", |
3406 | + AppIndicator3.IndicatorCategory.APPLICATION_STATUS) |
3407 | + |
3408 | + self.indicator.set_menu(self.menu) |
3409 | + self.indicator.set_attention_icon("kazam-recording") |
3410 | + self.indicator.set_icon("kazam-stopped") |
3411 | + |
3412 | + if self.silent: |
3413 | + self.indicator.set_status(AppIndicator3.IndicatorStatus.PASSIVE) |
3414 | + else: |
3415 | + self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE) |
3416 | + |
3417 | + def hide_it(self): |
3418 | + self.indicator.set_status(AppIndicator3.IndicatorStatus.PASSIVE) |
3419 | + |
3420 | + def show_it(self): |
3421 | + self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE) |
3422 | + |
3423 | + def on_menuitem_pause_activate(self, menuitem): |
3424 | + if menuitem.get_active(): |
3425 | + self.indicator.set_attention_icon("kazam-paused") |
3426 | + logger.debug("Recording paused.") |
3427 | + else: |
3428 | + self.indicator.set_attention_icon("kazam-recording") |
3429 | + logger.debug("Recording resumed.") |
3430 | + KazamSuperIndicator.on_menuitem_pause_activate(self, menuitem) |
3431 | + |
3432 | + def on_menuitem_finish_activate(self, menuitem): |
3433 | + logger.debug("Recording stopped.") |
3434 | + if not self.silent: |
3435 | + self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE) |
3436 | + KazamSuperIndicator.on_menuitem_finish_activate(self, menuitem) |
3437 | + |
3438 | + def blink_set_state(self, state): |
3439 | + if state == BLINK_STOP: |
3440 | + self.blink_state = BLINK_STOP |
3441 | + self.indicator.set_icon("kazam-stopped") |
3442 | + elif state == BLINK_START: |
3443 | + self.blink_state = BLINK_SLOW |
3444 | + GObject.timeout_add(500, self.blink) |
3445 | + elif state == BLINK_SLOW: |
3446 | + self.blink_state = BLINK_SLOW |
3447 | + elif state == BLINK_FAST: |
3448 | + self.blink_state = BLINK_FAST |
3449 | + |
3450 | + def blink(self): |
3451 | + if self.blink_state != BLINK_STOP: |
3452 | + if self.blink_icon == BLINK_READY_ICON: |
3453 | + if not self.silent: |
3454 | + self.indicator.set_icon("kazam-stopped") |
3455 | + self.blink_icon = BLINK_STOP_ICON |
3456 | + else: |
3457 | + if not self.silent: |
3458 | + self.indicator.set_icon("kazam-countdown") |
3459 | + self.blink_icon = BLINK_READY_ICON |
3460 | + |
3461 | + if self.blink_state == BLINK_SLOW: |
3462 | + GObject.timeout_add(500, self.blink) |
3463 | + elif self.blink_state == BLINK_FAST: |
3464 | + GObject.timeout_add(200, self.blink) |
3465 | + |
3466 | + def start_recording(self): |
3467 | + logger.debug("Recording started.") |
3468 | + if not self.silent: |
3469 | + self.indicator.set_status(AppIndicator3.IndicatorStatus.ATTENTION) |
3470 | + |
3471 | +except ImportError: |
3472 | + # |
3473 | + # AppIndicator failed to import, not running Ubuntu? |
3474 | + # Fallback to Gtk.StatusIcon. |
3475 | + # |
3476 | + class KazamIndicator(KazamSuperIndicator): |
3477 | + |
3478 | + def __init__(self, silent = False): |
3479 | + super(KazamIndicator, self).__init__() |
3480 | + self.silent = silent |
3481 | + |
3482 | + self.indicator = Gtk.StatusIcon() |
3483 | + self.indicator.set_from_icon_name("kazam-stopped") |
3484 | + self.indicator.connect("popup-menu", self.cb_indicator_popup_menu) |
3485 | + self.indicator.connect("activate", self.cb_indicator_activate) |
3486 | + |
3487 | + if self.silent: |
3488 | + self.indicator.set_visible(False) |
3489 | + |
3490 | + def cb_indicator_activate(self, widget): |
3491 | + def position(menu, widget): |
3492 | + return (Gtk.StatusIcon.position_menu(self.menu, widget)) |
3493 | + self.menu.popup(None, None, position, self.indicator, 0, Gtk.get_current_event_time()) |
3494 | + |
3495 | + def cb_indicator_popup_menu(self, icon, button, time): |
3496 | + def position(menu, icon): |
3497 | + return (Gtk.StatusIcon.position_menu(self.menu, icon)) |
3498 | + self.menu.popup(None, None, position, self.indicator, button, time) |
3499 | + |
3500 | + def on_menuitem_finish_activate(self, menuitem): |
3501 | + logger.debug("Recording stopped.") |
3502 | + self.indicator.set_from_icon_name("kazam-stopped") |
3503 | + KazamSuperIndicator.on_menuitem_finish_activate(self, menuitem) |
3504 | + |
3505 | + def on_menuitem_pause_activate(self, menuitem): |
3506 | + if menuitem.get_active(): |
3507 | + self.indicator.set_from_icon_name("kazam-paused") |
3508 | + logger.debug("Recording paused.") |
3509 | + else: |
3510 | + self.indicator.set_from_icon_name("kazam-recording") |
3511 | + logger.debug("Recording resumed.") |
3512 | + KazamSuperIndicator.on_menuitem_pause_activate(self, menuitem) |
3513 | + |
3514 | + def blink_set_state(self, state): |
3515 | + if state == BLINK_STOP: |
3516 | + self.blink_state = BLINK_STOP |
3517 | + self.indicator.set_from_icon_name("kazam-stopped") |
3518 | + elif state == BLINK_START: |
3519 | + self.blink_state = BLINK_SLOW |
3520 | + GObject.timeout_add(500, self.blink) |
3521 | + elif state == BLINK_SLOW: |
3522 | + self.blink_state = BLINK_SLOW |
3523 | + elif state == BLINK_FAST: |
3524 | + self.blink_state = BLINK_FAST |
3525 | + |
3526 | + def blink(self): |
3527 | + if self.blink_state != BLINK_STOP: |
3528 | + if self.blink_icon == BLINK_READY_ICON: |
3529 | + self.indicator.set_from_icon_name("kazam-stopped") |
3530 | + self.blink_icon = BLINK_STOP_ICON |
3531 | + else: |
3532 | + self.indicator.set_from_icon_name("kazam-countdown") |
3533 | + self.blink_icon = BLINK_READY_ICON |
3534 | + |
3535 | + if self.blink_state == BLINK_SLOW: |
3536 | + GObject.timeout_add(500, self.blink) |
3537 | + elif self.blink_state == BLINK_FAST: |
3538 | + GObject.timeout_add(200, self.blink) |
3539 | + |
3540 | + def start_recording(self): |
3541 | + logger.debug("Recording started.") |
3542 | + self.indicator.set_from_icon_name("kazam-recording") |
3543 | |
3544 | === added file 'build/lib.linux-x86_64-2.7/kazam/frontend/main_menu.py' |
3545 | --- build/lib.linux-x86_64-2.7/kazam/frontend/main_menu.py 1970-01-01 00:00:00 +0000 |
3546 | +++ build/lib.linux-x86_64-2.7/kazam/frontend/main_menu.py 2012-11-15 10:17:01 +0000 |
3547 | @@ -0,0 +1,88 @@ |
3548 | +# -*- coding: utf-8 -*- |
3549 | +# |
3550 | +# main_menu.py |
3551 | +# |
3552 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
3553 | +# |
3554 | +# This program is free software; you can redistribute it and/or modify |
3555 | +# it under the terms of the GNU General Public License as published by |
3556 | +# the Free Software Foundation; either version 3 of the License, or |
3557 | +# (at your option) any later version. |
3558 | +# |
3559 | +# This program is distributed in the hope that it will be useful, |
3560 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
3561 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3562 | +# GNU General Public License for more details. |
3563 | +# |
3564 | +# You should have received a copy of the GNU General Public License |
3565 | +# along with this program; if not, write to the Free Software |
3566 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
3567 | +# MA 02110-1301, USA. |
3568 | + |
3569 | +from gettext import gettext as _ |
3570 | + |
3571 | +from gi.repository import Gtk, GObject |
3572 | + |
3573 | +MENUBAR = """ |
3574 | + <ui> |
3575 | + <menubar name='MenuBar'> |
3576 | + <menu action='FileMenu'> |
3577 | + <menuitem action='FilePreferences' /> |
3578 | + <menuitem action='FileQuit' /> |
3579 | + </menu> |
3580 | + <separator /> |
3581 | + <menu action='HelpMenu'> |
3582 | + <menuitem action='HelpAbout' /> |
3583 | + </menu> |
3584 | + </menubar> |
3585 | +</ui> |
3586 | +""" |
3587 | + |
3588 | +class MainMenu(GObject.GObject): |
3589 | + __gsignals__ = { |
3590 | + "file-preferences" : (GObject.SIGNAL_RUN_LAST, |
3591 | + None, |
3592 | + (), |
3593 | + ), |
3594 | + "file-quit" : (GObject.SIGNAL_RUN_LAST, |
3595 | + None, |
3596 | + (), |
3597 | + ), |
3598 | + "help-about" : (GObject.SIGNAL_RUN_LAST, |
3599 | + None, |
3600 | + (), |
3601 | + ), |
3602 | + } |
3603 | + |
3604 | + def __init__(self): |
3605 | + GObject.GObject.__init__(self) |
3606 | + |
3607 | + self.action_group = Gtk.ActionGroup("kazam_actions") |
3608 | + self.action_group.add_actions([ |
3609 | + ("FileMenu", None, _("File")), |
3610 | + ("FileQuit", Gtk.STOCK_QUIT, _("Quit"), None, _("Quit Kazam"), |
3611 | + self.cb_file_quit), |
3612 | + ("FilePreferences", Gtk.STOCK_PREFERENCES, _("Preferences"), None, _("Open preferences"), |
3613 | + self.cb_file_preferences), |
3614 | + ("HelpMenu", None, _("Help")), |
3615 | + ("HelpAbout", None, _("About"), None , _("About Kazam"), |
3616 | + self.cb_help_about) |
3617 | + ]) |
3618 | + |
3619 | + self.uimanager = Gtk.UIManager() |
3620 | + self.uimanager.add_ui_from_string(MENUBAR) |
3621 | + self.uimanager.insert_action_group(self.action_group) |
3622 | + self.menubar = self.uimanager.get_widget("/MenuBar") |
3623 | + |
3624 | + |
3625 | + def cb_file_quit(self, action): |
3626 | + self.emit("file-quit") |
3627 | + |
3628 | + def cb_file_preferences(self, action): |
3629 | + self.emit("file-preferences") |
3630 | + |
3631 | + def cb_help_about(self, action): |
3632 | + self.emit("help-about") |
3633 | + |
3634 | + |
3635 | + |
3636 | |
3637 | === added file 'build/lib.linux-x86_64-2.7/kazam/frontend/preferences.py' |
3638 | --- build/lib.linux-x86_64-2.7/kazam/frontend/preferences.py 1970-01-01 00:00:00 +0000 |
3639 | +++ build/lib.linux-x86_64-2.7/kazam/frontend/preferences.py 2012-11-15 10:17:01 +0000 |
3640 | @@ -0,0 +1,375 @@ |
3641 | +# -*- coding: utf-8 -*- |
3642 | +# |
3643 | +# preferences.py |
3644 | +# |
3645 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
3646 | +# |
3647 | +# This program is free software; you can redistribute it and/or modify |
3648 | +# it under the terms of the GNU General Public License as published by |
3649 | +# the Free Software Foundation; either version 3 of the License, or |
3650 | +# (at your option) any later version. |
3651 | +# |
3652 | +# This program is distributed in the hope that it will be useful, |
3653 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
3654 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3655 | +# GNU General Public License for more details. |
3656 | +# |
3657 | +# You should have received a copy of the GNU General Public License |
3658 | +# along with this program; if not, write to the Free Software |
3659 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
3660 | +# MA 02110-1301, USA. |
3661 | + |
3662 | +import os |
3663 | +import math |
3664 | +import logging |
3665 | +logger = logging.getLogger("Preferences") |
3666 | + |
3667 | +from gi.repository import Gtk, Gdk, GObject, Pango |
3668 | +from gettext import gettext as _ |
3669 | + |
3670 | +from kazam.utils import * |
3671 | +from kazam.backend.prefs import * |
3672 | +from kazam.backend.constants import * |
3673 | +from kazam.backend.gstreamer import detect_codecs, get_codec |
3674 | + |
3675 | +class Preferences(GObject.GObject): |
3676 | + __gsignals__ = { |
3677 | + "prefs-quit" : (GObject.SIGNAL_RUN_LAST, |
3678 | + None, |
3679 | + (), |
3680 | + ), |
3681 | + } |
3682 | + |
3683 | + def __init__(self): |
3684 | + GObject.GObject.__init__(self) |
3685 | + logger.debug("Preferences Init.") |
3686 | + # |
3687 | + # Setup UI |
3688 | + # |
3689 | + logger.debug("Preferences UI setup.") |
3690 | + |
3691 | + self.audio_source_info = None |
3692 | + self.audio2_source_info = None |
3693 | + |
3694 | + self.builder = Gtk.Builder() |
3695 | + self.builder.add_from_file(os.path.join(prefs.datadir, "ui", "preferences.ui")) |
3696 | + self.builder.connect_signals(self) |
3697 | + for w in self.builder.get_objects(): |
3698 | + if issubclass(type(w), Gtk.Buildable): |
3699 | + name = Gtk.Buildable.get_name(w) |
3700 | + setattr(self, name, w) |
3701 | + else: |
3702 | + logger.debug("Unable to get name for '%s'" % w) |
3703 | + |
3704 | + codec_renderer = Gtk.CellRendererText() |
3705 | + |
3706 | + audio_renderer = Gtk.CellRendererText() |
3707 | + audio_renderer.props.ellipsize = Pango.EllipsizeMode.END |
3708 | + audio_renderer.props.max_width_chars = 40 |
3709 | + |
3710 | + self.combobox_codec.pack_start(codec_renderer, True) |
3711 | + self.combobox_codec.add_attribute(codec_renderer, "text", 1) |
3712 | + |
3713 | + self.combobox_audio.pack_start(audio_renderer, True) |
3714 | + self.combobox_audio.add_attribute(audio_renderer, "text", 0) |
3715 | + |
3716 | + self.combobox_audio2.pack_start(audio_renderer, True) |
3717 | + self.combobox_audio2.add_attribute(audio_renderer, "text", 0) |
3718 | + |
3719 | + self.filechooser_video.set_current_folder(prefs.video_dest) |
3720 | + |
3721 | + self.populate_codecs() |
3722 | + self.populate_audio_sources() |
3723 | + self.populate_shutter_sounds() |
3724 | + |
3725 | + self.restore_UI() |
3726 | + |
3727 | + def open(self): |
3728 | + self.window.show_all() |
3729 | + |
3730 | + def is_separator(self, model, iter, data): |
3731 | + if model.get_value(iter, 0) == 99: |
3732 | + return True |
3733 | + return False |
3734 | + |
3735 | + def populate_codecs(self): |
3736 | + # |
3737 | + # Is this necessary? |
3738 | + # |
3739 | + old_model = self.combobox_codec.get_model() |
3740 | + old_model = None |
3741 | + |
3742 | + codec_model = Gtk.ListStore(int, str) |
3743 | + codecs = detect_codecs() |
3744 | + |
3745 | + # |
3746 | + # I'm sure this could be done without going through the list twice, right? |
3747 | + # Fist, we add basic codecs, then a dummy separator item and then advanced codecs. |
3748 | + # |
3749 | + |
3750 | + for codec in codecs: |
3751 | + if not CODEC_LIST[codec][4]: |
3752 | + codec_model.append([CODEC_LIST[codec][0], CODEC_LIST[codec][2]]) |
3753 | + |
3754 | + codec_model.append([99, "--"]) # Insert dummy item for separator |
3755 | + |
3756 | + for codec in codecs: |
3757 | + if CODEC_LIST[codec][4]: |
3758 | + codec_model.append([CODEC_LIST[codec][0], CODEC_LIST[codec][2]]) |
3759 | + |
3760 | + self.combobox_codec.set_model(codec_model) |
3761 | + self.combobox_codec.set_row_separator_func(self.is_separator, None) |
3762 | + |
3763 | + def populate_audio_sources(self): |
3764 | + audio_source_model = Gtk.ListStore(str) |
3765 | + for source in prefs.audio_sources: |
3766 | + audio_source_model.append([source[2]]) |
3767 | + |
3768 | + self.combobox_audio.set_model(audio_source_model) |
3769 | + self.combobox_audio2.set_model(audio_source_model) |
3770 | + |
3771 | + def populate_shutter_sounds(self): |
3772 | + for file in prefs.sound_files: |
3773 | + self.combobox_shutter_type.append(None, file[:-4]) |
3774 | + |
3775 | + def restore_UI(self): |
3776 | + logger.debug("Restoring UI.") |
3777 | + |
3778 | + if prefs.sound: |
3779 | + self.combobox_audio.set_active(prefs.audio_source) |
3780 | + self.combobox_audio2.set_active(prefs.audio2_source) |
3781 | + else: |
3782 | + self.combobox_audio.set_sensitive(False) |
3783 | + self.combobox_audio2.set_sensitive(False) |
3784 | + self.volumebutton_audio.set_sensitive(False) |
3785 | + self.volumebutton_audio2.set_sensitive(False) |
3786 | + |
3787 | + if prefs.countdown_splash: |
3788 | + self.switch_countdown_splash.set_active(True) |
3789 | + else: |
3790 | + self.switch_countdown_splash.set_active(False) |
3791 | + |
3792 | + self.spinbutton_framerate.set_value(prefs.framerate) |
3793 | + |
3794 | + if prefs.autosave_video: |
3795 | + self.switch_autosave_video.set_active(True) |
3796 | + self.filechooser_video.set_sensitive(True) |
3797 | + self.entry_autosave_video.set_sensitive(True) |
3798 | + else: |
3799 | + self.switch_autosave_video.set_active(False) |
3800 | + self.filechooser_video.set_sensitive(False) |
3801 | + self.entry_autosave_video.set_sensitive(False) |
3802 | + |
3803 | + self.entry_autosave_video.set_text(prefs.autosave_video_file) |
3804 | + |
3805 | + self.filechooser_video.set_current_folder(prefs.video_dest) |
3806 | + |
3807 | + |
3808 | + if prefs.shutter_sound: |
3809 | + self.switch_shutter_sound.set_active(True) |
3810 | + self.combobox_shutter_type.set_sensitive(True) |
3811 | + else: |
3812 | + self.switch_shutter_sound.set_active(False) |
3813 | + self.combobox_shutter_type.set_sensitive(False) |
3814 | + |
3815 | + self.combobox_shutter_type.set_active(prefs.shutter_type) |
3816 | + |
3817 | + if prefs.autosave_picture: |
3818 | + self.switch_autosave_picture.set_active(True) |
3819 | + self.filechooser_picture.set_sensitive(True) |
3820 | + self.entry_autosave_picture.set_sensitive(True) |
3821 | + |
3822 | + else: |
3823 | + self.switch_autosave_picture.set_active(False) |
3824 | + self.filechooser_picture.set_sensitive(False) |
3825 | + self.entry_autosave_picture.set_sensitive(False) |
3826 | + |
3827 | + self.entry_autosave_picture.set_text(prefs.autosave_picture_file) |
3828 | + |
3829 | + self.filechooser_picture.set_current_folder(prefs.picture_dest) |
3830 | + |
3831 | + |
3832 | + # |
3833 | + # Crappy code below ... Can this be done some other way? |
3834 | + # |
3835 | + codec_model = self.combobox_codec.get_model() |
3836 | + cnt = 0 |
3837 | + bingo = False |
3838 | + for entry in codec_model: |
3839 | + if prefs.codec == entry[0]: |
3840 | + bingo = True |
3841 | + break |
3842 | + cnt += 1 |
3843 | + if not bingo: |
3844 | + cnt = 0 |
3845 | + |
3846 | + # |
3847 | + # No, I wasn't kidding ... |
3848 | + # |
3849 | + codec_iter = codec_model.get_iter(cnt) |
3850 | + self.combobox_codec.set_active_iter(codec_iter) |
3851 | + prefs.codec = codec_model.get_value(codec_iter, 0) |
3852 | + |
3853 | + # |
3854 | + # General callbacks |
3855 | + # |
3856 | + |
3857 | + def cb_delete_event(self, widget, user_data): |
3858 | + logger.debug("Deleteting preferences window") |
3859 | + self.emit("prefs-quit") |
3860 | + |
3861 | + def cb_switch_countdown_splash(self, widget, user_data): |
3862 | + prefs.countdown_splash = widget.get_active() |
3863 | + logger.debug("Countdown splash: {0}.".format(prefs.countdown_splash)) |
3864 | + |
3865 | + def cb_audio_changed(self, widget): |
3866 | + logger.debug("Audio Changed.") |
3867 | + prefs.audio_source = self.combobox_audio.get_active() |
3868 | + logger.debug(" - A_1 {0}".format(prefs.audio_source)) |
3869 | + |
3870 | + pa_audio_idx = prefs.audio_sources[prefs.audio_source][0] |
3871 | + prefs.pa_q.set_source_mute_by_index(pa_audio_idx, 0) |
3872 | + |
3873 | + logger.debug(" - PA Audio1 IDX: {0}".format(pa_audio_idx)) |
3874 | + self.audio_source_info = prefs.pa_q.get_source_info_by_index(pa_audio_idx) |
3875 | + if len(self.audio_source_info) > 0: |
3876 | + val = prefs.pa_q.cvolume_to_dB(self.audio_source_info[2]) |
3877 | + if math.isinf(val): |
3878 | + vol = 0 |
3879 | + else: |
3880 | + vol = 60 + val |
3881 | + self.volumebutton_audio.set_value(vol) |
3882 | + else: |
3883 | + logger.debug("Error getting volume info for Audio 1") |
3884 | + if len(self.audio_source_info): |
3885 | + logger.debug("New Audio1: {0}".format(self.audio_source_info[3])) |
3886 | + else: |
3887 | + logger.debug("New Audio1: Error retrieving data.") |
3888 | + |
3889 | + if prefs.audio_source == prefs.audio2_source: |
3890 | + if prefs.audio_source < len(prefs.audio_sources) - 1: |
3891 | + prefs.audio2_source += 1 |
3892 | + else: |
3893 | + prefs.audio2_source = 0 |
3894 | + self.combobox_audio2.set_active(prefs.audio2_source) |
3895 | + |
3896 | + def cb_audio2_changed(self, widget): |
3897 | + logger.debug("Audio2 Changed.") |
3898 | + |
3899 | + prefs.audio2_source = self.combobox_audio2.get_active() |
3900 | + logger.debug(" - A_2 {0}".format(prefs.audio2_source)) |
3901 | + |
3902 | + pa_audio2_idx = prefs.audio_sources[prefs.audio2_source][0] |
3903 | + prefs.pa_q.set_source_mute_by_index(pa_audio2_idx, 0) |
3904 | + |
3905 | + logger.debug(" - PA Audio2 IDX: {0}".format(pa_audio2_idx)) |
3906 | + self.audio2_source_info = prefs.pa_q.get_source_info_by_index(pa_audio2_idx) |
3907 | + |
3908 | + if len(self.audio2_source_info) > 0: |
3909 | + val = prefs.pa_q.cvolume_to_dB(self.audio2_source_info[2]) |
3910 | + if math.isinf(val): |
3911 | + vol = 0 |
3912 | + else: |
3913 | + vol = 60 + val |
3914 | + self.volumebutton_audio2.set_value(vol) |
3915 | + else: |
3916 | + logger.debug("Error getting volume info for Audio 1") |
3917 | + |
3918 | + if len(self.audio2_source_info): |
3919 | + logger.debug("New Audio2:\n {0}".format(self.audio2_source_info[3])) |
3920 | + else: |
3921 | + logger.debug("New Audio2:\n Error retrieving data.") |
3922 | + |
3923 | + if prefs.audio_source == prefs.audio2_source: |
3924 | + if prefs.audio_source < len(prefs.audio_sources) - 1: |
3925 | + prefs.audio2_source += 1 |
3926 | + else: |
3927 | + prefs.audio2_source = 0 |
3928 | + self.combobox_audio2.set_active(prefs.audio2_source) |
3929 | + |
3930 | + def cb_volume_changed(self, widget, value): |
3931 | + logger.debug("Volume 1 changed, new value: {0}".format(value)) |
3932 | + idx = self.combobox_audio.get_active() |
3933 | + pa_idx = prefs.audio_sources[idx][0] |
3934 | + chn = self.audio_source_info[2].channels |
3935 | + cvol = prefs.pa_q.dB_to_cvolume(chn, value-60) |
3936 | + prefs.pa_q.set_source_volume_by_index(pa_idx, cvol) |
3937 | + |
3938 | + def cb_volume2_changed(self, widget, value): |
3939 | + logger.debug("Volume 2 changed, new value: {0}".format(value)) |
3940 | + idx = self.combobox_audio2.get_active() |
3941 | + pa_idx = prefs.audio_sources[idx][0] |
3942 | + chn = self.audio_source_info[2].channels |
3943 | + cvol = prefs.pa_q.dB_to_cvolume(chn, value-60) |
3944 | + prefs.pa_q.set_source_volume_by_index(pa_idx, cvol) |
3945 | + |
3946 | + # |
3947 | + # Screencasting callbacks |
3948 | + # |
3949 | + |
3950 | + def cb_spinbutton_framerate_change(self, widget): |
3951 | + prefs.framerate = widget.get_value_as_int() |
3952 | + logger.debug("Framerate now: {0}".format(prefs.framerate)) |
3953 | + |
3954 | + def cb_codec_changed(self, widget): |
3955 | + i = widget.get_active() |
3956 | + model = widget.get_model() |
3957 | + iter = model.get_iter(i) |
3958 | + prefs.codec = model.get_value(iter, 0) |
3959 | + logger.debug('Codec selected: {0} - {1}'.format(get_codec(prefs.codec)[2], prefs.codec)) |
3960 | + |
3961 | + def cb_switch_autosave_video(self, widget, user_data): |
3962 | + prefs.autosave_video = widget.get_active() |
3963 | + logger.debug("Autosave for Video: {0}.".format(prefs.autosave_video)) |
3964 | + |
3965 | + if prefs.autosave_video: |
3966 | + self.filechooser_video.set_sensitive(True) |
3967 | + self.entry_autosave_video.set_sensitive(True) |
3968 | + else: |
3969 | + self.filechooser_video.set_sensitive(False) |
3970 | + self.entry_autosave_video.set_sensitive(False) |
3971 | + |
3972 | + def cb_filechooser_video(self, widget): |
3973 | + prefs.video_dest = self.filechooser_video.get_current_folder() |
3974 | + logger.debug("Video folder set to: {0}".format(prefs.video_dest)) |
3975 | + |
3976 | + def cb_entry_autosave_video(self, widget): |
3977 | + prefs.autosave_video_file = widget.get_text() |
3978 | + logger.debug("Video autosave file set to: {0}".format(prefs.autosave_video_file)) |
3979 | + |
3980 | + # |
3981 | + # Screenshot callbacks |
3982 | + # |
3983 | + |
3984 | + def cb_switch_shutter_sound(self, widget, user_data): |
3985 | + prefs.shutter_sound = widget.get_active() |
3986 | + logger.debug("Shutter sound: {0}.".format(prefs.shutter_sound)) |
3987 | + |
3988 | + if prefs.shutter_sound: |
3989 | + self.combobox_shutter_type.set_sensitive(True) |
3990 | + else: |
3991 | + self.combobox_shutter_type.set_sensitive(False) |
3992 | + |
3993 | + def cb_shutter_type(self, widget): |
3994 | + prefs.shutter_type = self.combobox_shutter_type.get_active() |
3995 | + logger.debug("Shutter type set to: {0} - {1}".format(prefs.shutter_type, prefs.shutter_sound_file)) |
3996 | + |
3997 | + def cb_switch_autosave_picture(self, widget, user_data): |
3998 | + prefs.autosave_picture = widget.get_active() |
3999 | + logger.debug("Autosave for Picture: {0}.".format(prefs.autosave_picture)) |
4000 | + |
4001 | + if prefs.autosave_picture: |
4002 | + self.filechooser_picture.set_sensitive(True) |
4003 | + self.entry_autosave_picture.set_sensitive(True) |
4004 | + else: |
4005 | + self.filechooser_picture.set_sensitive(False) |
4006 | + self.entry_autosave_picture.set_sensitive(False) |
4007 | + |
4008 | + def cb_filechooser_picture(self, widget): |
4009 | + prefs.picture_dest = self.filechooser_picture.get_current_folder() |
4010 | + logger.debug("Picture folder set to: {0}".format(prefs.picture_dest)) |
4011 | + |
4012 | + def cb_entry_autosave_picture(self, widget): |
4013 | + prefs.autosave_picture_file = widget.get_text() |
4014 | + logger.debug("Picture autosave file set to: {0}".format(prefs.autosave_picture_file)) |
4015 | + |
4016 | |
4017 | === added file 'build/lib.linux-x86_64-2.7/kazam/frontend/save_dialog.py' |
4018 | --- build/lib.linux-x86_64-2.7/kazam/frontend/save_dialog.py 1970-01-01 00:00:00 +0000 |
4019 | +++ build/lib.linux-x86_64-2.7/kazam/frontend/save_dialog.py 2012-11-15 10:17:01 +0000 |
4020 | @@ -0,0 +1,62 @@ |
4021 | +# -*- coding: utf-8 -*- |
4022 | +# |
4023 | +# save_dialog.py |
4024 | +# |
4025 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
4026 | +# Copyright 2010 Andrew <andrew@karmic-desktop> |
4027 | +# |
4028 | +# This program is free software; you can redistribute it and/or modify |
4029 | +# it under the terms of the GNU General Public License as published by |
4030 | +# the Free Software Foundation; either version 3 of the License, or |
4031 | +# (at your option) any later version. |
4032 | +# |
4033 | +# This program is distributed in the hope that it will be useful, |
4034 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
4035 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4036 | +# GNU General Public License for more details. |
4037 | +# |
4038 | +# You should have received a copy of the GNU General Public License |
4039 | +# along with this program; if not, write to the Free Software |
4040 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
4041 | +# MA 02110-1301, USA. |
4042 | + |
4043 | +import os |
4044 | +import logging |
4045 | +logger = logging.getLogger("Save Dialog") |
4046 | + |
4047 | +from gi.repository import Gtk |
4048 | +from gettext import gettext as _ |
4049 | +from datetime import datetime |
4050 | +from kazam.backend.prefs import * |
4051 | +from kazam.backend.constants import * |
4052 | + |
4053 | +def SaveDialog(title, old_path, codec, main_mode=MODE_SCREENCAST): |
4054 | + logger.debug("Save dialog called.") |
4055 | + dialog = Gtk.FileChooserDialog(title, None, |
4056 | + Gtk.FileChooserAction.SAVE, |
4057 | + (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, |
4058 | + _("Save"), Gtk.ResponseType.OK)) |
4059 | + |
4060 | + |
4061 | + dt = datetime.today().strftime("%Y-%m-%d %H:%M:%S") |
4062 | + if main_mode == MODE_SCREENCAST: |
4063 | + dialog.set_current_name("{0} {1}{2}".format(_("Screencast"), dt, CODEC_LIST[codec][3])) |
4064 | + elif main_mode == MODE_SCREENSHOT: |
4065 | + dialog.set_current_name("{0} {1}.png".format(_("Screenshot"), dt)) |
4066 | + |
4067 | + dialog.set_do_overwrite_confirmation(True) |
4068 | + |
4069 | + if old_path and os.path.isdir(old_path): |
4070 | + dialog.set_current_folder(old_path) |
4071 | + else: |
4072 | + if main_mode == MODE_SCREENCAST: |
4073 | + dialog.set_current_folder(prefs.video_dest) |
4074 | + elif main_mode == MODE_SCREENSHOT: |
4075 | + dialog.set_current_folder(prefs.picture_dest) |
4076 | + |
4077 | + |
4078 | + dialog.show_all() |
4079 | + result = dialog.run() |
4080 | + old_path = dialog.get_current_folder() |
4081 | + return dialog, result, old_path |
4082 | + |
4083 | |
4084 | === added file 'build/lib.linux-x86_64-2.7/kazam/frontend/widgets.py' |
4085 | --- build/lib.linux-x86_64-2.7/kazam/frontend/widgets.py 1970-01-01 00:00:00 +0000 |
4086 | +++ build/lib.linux-x86_64-2.7/kazam/frontend/widgets.py 2012-11-15 10:17:01 +0000 |
4087 | @@ -0,0 +1,60 @@ |
4088 | +# -*- coding: utf-8 -*- |
4089 | +# |
4090 | +# widgets.py |
4091 | +# |
4092 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
4093 | +# |
4094 | +# This program is free software; you can redistribute it and/or modify |
4095 | +# it under the terms of the GNU General Public License as published by |
4096 | +# the Free Software Foundation; either version 3 of the License, or |
4097 | +# (at your option) any later version. |
4098 | +# |
4099 | +# This program is distributed in the hope that it will be useful, |
4100 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
4101 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4102 | +# GNU General Public License for more details. |
4103 | +# |
4104 | +# You should have received a copy of the GNU General Public License |
4105 | +# along with this program; if not, write to the Free Software |
4106 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
4107 | +# MA 02110-1301, USA. |
4108 | + |
4109 | +from gi.repository import Gtk, Gdk, Pango, GObject, GdkPixbuf |
4110 | + |
4111 | +class _Tile(object): |
4112 | + def __init__(self): |
4113 | + self.set_focus_on_click(False) |
4114 | + self.set_relief(Gtk.ReliefStyle.NONE) |
4115 | + self.box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) |
4116 | + self.box.set_size_request(62, -1) |
4117 | + self.add(self.box) |
4118 | + |
4119 | + def create_default(self, label, icon): |
4120 | + if icon is not None: |
4121 | + if isinstance(icon, Gtk.Image): |
4122 | + self.image = icon |
4123 | + else: |
4124 | + self.image = Gtk.Image() |
4125 | + self.box.pack_start(self.image, True, True, 0) |
4126 | + |
4127 | + self.label = Gtk.Label.new(label) |
4128 | + self.box.pack_start(self.label, True, True, 0) |
4129 | + |
4130 | +class TileToggleButton(Gtk.RadioButton, _Tile): |
4131 | + def __init__(self): |
4132 | + Gtk.RadioButton.__init__(self) |
4133 | + self.set_mode(False) |
4134 | + _Tile.__init__(self) |
4135 | + |
4136 | +class ModeButton(TileToggleButton): |
4137 | + def __init__(self, label, icon): |
4138 | + TileToggleButton.__init__(self) |
4139 | + html = "<small>%s</small>" % label |
4140 | + self.create_default(html, icon) |
4141 | + self.label.set_use_markup(True) |
4142 | + self.label.set_justify(Gtk.Justification.CENTER) |
4143 | + |
4144 | + #def do_draw(self, cr): |
4145 | + #for child in self: |
4146 | + # self.propagate_draw(child, cr) |
4147 | + |
4148 | |
4149 | === added file 'build/lib.linux-x86_64-2.7/kazam/frontend/window_area.py' |
4150 | --- build/lib.linux-x86_64-2.7/kazam/frontend/window_area.py 1970-01-01 00:00:00 +0000 |
4151 | +++ build/lib.linux-x86_64-2.7/kazam/frontend/window_area.py 2012-11-15 10:17:01 +0000 |
4152 | @@ -0,0 +1,202 @@ |
4153 | +# -*- coding: utf-8 -*- |
4154 | +# |
4155 | +# window_select.py |
4156 | +# |
4157 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
4158 | +# |
4159 | +# This program is free software; you can redistribute it and/or modify |
4160 | +# it under the terms of the GNU General Public License as published by |
4161 | +# the Free Software Foundation; either version 3 of the License, or |
4162 | +# (at your option) any later version. |
4163 | +# |
4164 | +# This program is distributed in the hope that it will be useful, |
4165 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
4166 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4167 | +# GNU General Public License for more details. |
4168 | +# |
4169 | +# You should have received a copy of the GNU General Public License |
4170 | +# along with this program; if not, write to the Free Software |
4171 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
4172 | +# MA 02110-1301, USA. |
4173 | + |
4174 | +import time |
4175 | +import cairo |
4176 | +import logging |
4177 | +logger = logging.getLogger("Window Select") |
4178 | + |
4179 | +from gettext import gettext as _ |
4180 | + |
4181 | +from gi.repository import Gtk, GObject, Gdk, Wnck, GdkX11 |
4182 | + |
4183 | +from kazam.backend.constants import * |
4184 | +class AreaWindow(GObject.GObject): |
4185 | + |
4186 | + __gsignals__ = { |
4187 | + "area-selected" : (GObject.SIGNAL_RUN_LAST, |
4188 | + None, |
4189 | + (), |
4190 | + ), |
4191 | + "area-canceled" : (GObject.SIGNAL_RUN_LAST, |
4192 | + None, |
4193 | + (), |
4194 | + ), |
4195 | + } |
4196 | + |
4197 | + def __init__(self): |
4198 | + super(AreaWindow, self).__init__() |
4199 | + logger.debug("Initializing select window.") |
4200 | + |
4201 | + self.startx = 0 |
4202 | + self.starty = 0 |
4203 | + self.endx = 0 |
4204 | + self.endy = 0 |
4205 | + self.height = 0 |
4206 | + self.width = 0 |
4207 | + |
4208 | + self.window = Gtk.Window() |
4209 | + self.box = Gtk.Box() |
4210 | + self.drawing = Gtk.DrawingArea() |
4211 | + self.box.pack_start(self.drawing, True, True, 0) |
4212 | + self.drawing.set_size_request(500, 500) |
4213 | + self.window.add(self.box) |
4214 | + |
4215 | + self.window.connect("delete-event", Gtk.main_quit) |
4216 | + self.window.connect("key-press-event", self.cb_keypress_event) |
4217 | + |
4218 | + self.drawing.connect("draw", self.cb_draw) |
4219 | + self.drawing.connect("motion-notify-event", self.cb_draw_motion_notify_event) |
4220 | + self.drawing.connect("button-press-event", self.cb_draw_button_press_event) |
4221 | + self.drawing.connect("leave-notify-event", self.cb_leave_notify_event) |
4222 | + self.drawing.add_events(Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.POINTER_MOTION_HINT_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK) |
4223 | + |
4224 | + self.window.set_border_width(0) |
4225 | + self.window.set_app_paintable(True) |
4226 | + self.window.set_has_resize_grip(False) |
4227 | + self.window.set_resizable(True) |
4228 | + self.window.set_decorated(False) |
4229 | + self.window.set_property("skip-taskbar-hint", True) |
4230 | + self.window.set_keep_above(True) |
4231 | + self.screen = self.window.get_screen() |
4232 | + self.visual = self.screen.get_rgba_visual() |
4233 | + |
4234 | + self.disp = GdkX11.X11Display.get_default() |
4235 | + self.dm = Gdk.Display.get_device_manager(self.disp) |
4236 | + self.pntr_device = self.dm.get_client_pointer() |
4237 | + |
4238 | + if self.visual is not None and self.screen.is_composited(): |
4239 | + logger.debug("Compositing window manager detected.") |
4240 | + self.window.set_visual(self.visual) |
4241 | + self.compositing = True |
4242 | + else: |
4243 | + self.compositing = False |
4244 | + |
4245 | + (scr, x, y) = self.pntr_device.get_position() |
4246 | + cur = scr.get_monitor_at_point(x, y) |
4247 | + self.window.move(HW.screens[cur]['x'], |
4248 | + HW.screens[cur]['y']) |
4249 | + self.window.fullscreen() |
4250 | + |
4251 | + crosshair_cursor = Gdk.Cursor(Gdk.CursorType.CROSSHAIR) |
4252 | + self.last_cursor = Gdk.Cursor(Gdk.CursorType.LEFT_PTR) |
4253 | + self.gdk_win = self.window.get_root_window() |
4254 | + self.gdk_win.set_cursor(crosshair_cursor) |
4255 | + |
4256 | + def cb_draw_motion_notify_event(self, widget, event): |
4257 | + (state, x, y, mask) = event.window.get_device_position(self.pntr_device) |
4258 | + if mask & Gdk.ModifierType.BUTTON1_MASK: |
4259 | + self.endx = int(event.x) |
4260 | + self.endy = int(event.y) |
4261 | + self.width = self.endx - self.startx |
4262 | + self.height = self.endy - self.starty |
4263 | + widget.queue_draw() |
4264 | + return True |
4265 | + |
4266 | + def cb_draw_button_press_event(self, widget, event): |
4267 | + self.startx = int(event.x) |
4268 | + self.starty = int(event.y) |
4269 | + self.endx = 0 |
4270 | + self.endy = 0 |
4271 | + self.width = 0 |
4272 | + self.height = 0 |
4273 | + |
4274 | + def cb_leave_notify_event(self, widget, event): |
4275 | + (scr, x, y) = self.pntr_device.get_position() |
4276 | + cur = scr.get_monitor_at_point(x, y) |
4277 | + self.window.unfullscreen() |
4278 | + self.window.move(HW.screens[cur]['x'], |
4279 | + HW.screens[cur]['y']) |
4280 | + self.window.fullscreen() |
4281 | + logger.debug("Move to X: {0} Y: {1}".format(HW.screens[cur]['x'], HW.screens[cur]['y'])) |
4282 | + return True |
4283 | + |
4284 | + def cb_keypress_event(self, widget, event): |
4285 | + (op, keycode) = event.get_keycode() |
4286 | + self.gdk_win.set_cursor(self.last_cursor) |
4287 | + if keycode == 36 or keycode == 104: # Enter |
4288 | + self.window.hide() |
4289 | + self.width = abs(self.width) |
4290 | + self.height = abs(self.height) |
4291 | + self.emit("area-selected") |
4292 | + elif keycode == 9: # ESC |
4293 | + self.window.hide() |
4294 | + self.emit("area-canceled") |
4295 | + |
4296 | + def cb_draw(self, widget, cr): |
4297 | + (w, h) = self.window.get_size() |
4298 | + |
4299 | + if self.compositing: |
4300 | + cr.set_source_rgba(0.0, 0.0, 0.0, 0.45) |
4301 | + else: |
4302 | + cr.set_source_rgb(0.5, 0.5, 0.5) |
4303 | + |
4304 | + cr.set_operator(cairo.OPERATOR_SOURCE) |
4305 | + cr.paint() |
4306 | + |
4307 | + cr.set_operator(cairo.OPERATOR_SOURCE) |
4308 | + |
4309 | + # Draw the selection area |
4310 | + cr.move_to(self.startx, self.starty) |
4311 | + cr.set_source_rgb(1.0, 0.0, 0.0) |
4312 | + cr.rectangle(self.startx, self.starty, self.width, self.height) |
4313 | + cr.stroke() |
4314 | + |
4315 | + if self.compositing: |
4316 | + cr.set_source_rgba(0.0, 0.0, 0.0, 0.0) |
4317 | + else: |
4318 | + cr.set_source_rgb(0.0, 0.0, 0.0) |
4319 | + |
4320 | + cr.rectangle(self.startx, self.starty, self.width, self.height) |
4321 | + cr.fill() |
4322 | + |
4323 | + cr.set_operator(cairo.OPERATOR_OVER) |
4324 | + |
4325 | + self._outline_text(cr, w, h, 30, _("Select an area by clicking and dragging.")) |
4326 | + self._outline_text(cr, w, h + 50, 26, _("Press ENTER to confirm or ESC to cancel")) |
4327 | + |
4328 | + self._outline_text(cr, w, h + 100, 20, "({0} x {1})".format(abs(self.height), abs(self.height))) |
4329 | + cr.set_operator(cairo.OPERATOR_SOURCE) |
4330 | + |
4331 | + def _outline_text(self, cr, w, h, size, text): |
4332 | + cr.set_font_size(size) |
4333 | + try: |
4334 | + cr.select_font_face("Ubuntu", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) |
4335 | + except: |
4336 | + pass |
4337 | + te = cr.text_extents(text) |
4338 | + cr.set_line_width(2.0) |
4339 | + cx = w/2 - te[2]/2 |
4340 | + cy = h/2 - te[3]/2 |
4341 | + if self.compositing: |
4342 | + cr.set_source_rgba(0.4, 0.4, 0.4, 1.0) |
4343 | + else: |
4344 | + cr.set_source_rgb(0.4, 0.4, 0.4) |
4345 | + |
4346 | + cr.move_to(cx, cy) |
4347 | + cr.text_path(text) |
4348 | + cr.stroke() |
4349 | + if self.compositing: |
4350 | + cr.set_source_rgba(1.0, 1.0, 1.0, 1.0) |
4351 | + else: |
4352 | + cr.set_source_rgb(1.0, 1.0, 1.0) |
4353 | + cr.move_to(cx, cy) |
4354 | + cr.show_text(text) |
4355 | |
4356 | === added file 'build/lib.linux-x86_64-2.7/kazam/frontend/window_countdown.py' |
4357 | --- build/lib.linux-x86_64-2.7/kazam/frontend/window_countdown.py 1970-01-01 00:00:00 +0000 |
4358 | +++ build/lib.linux-x86_64-2.7/kazam/frontend/window_countdown.py 2012-11-15 10:17:01 +0000 |
4359 | @@ -0,0 +1,140 @@ |
4360 | +# -*- coding: utf-8 -*- |
4361 | +# |
4362 | +# window_countdown.py |
4363 | +# |
4364 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
4365 | +# Copyright 2010 Andrew <andrew@karmic-desktop> |
4366 | +# |
4367 | +# This program is free software; you can redistribute it and/or modify |
4368 | +# it under the terms of the GNU General Public License as published by |
4369 | +# the Free Software Foundation; either version 3 of the License, or |
4370 | +# (at your option) any later version. |
4371 | +# |
4372 | +# This program is distributed in the hope that it will be useful, |
4373 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
4374 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4375 | +# GNU General Public License for more details. |
4376 | +# |
4377 | +# You should have received a copy of the GNU General Public License |
4378 | +# along with this program; if not, write to the Free Software |
4379 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
4380 | +# MA 02110-1301, USA. |
4381 | + |
4382 | +import cairo |
4383 | + |
4384 | +from gettext import gettext as _ |
4385 | +from gi.repository import Gtk, GObject |
4386 | +from kazam.backend.constants import * |
4387 | + |
4388 | +class CountdownWindow(GObject.GObject): |
4389 | + |
4390 | + __gsignals__ = { |
4391 | + "counter-finished" : (GObject.SIGNAL_RUN_LAST, |
4392 | + None, |
4393 | + (), |
4394 | + ), |
4395 | + } |
4396 | + |
4397 | + def __init__(self, indicator, number = 5, show_window = True): |
4398 | + super(CountdownWindow, self).__init__() |
4399 | + self.indicator = indicator |
4400 | + self.number = number |
4401 | + self.canceled = False |
4402 | + self.show_window = show_window |
4403 | + |
4404 | + self.window = Gtk.Window() |
4405 | + self.window.connect("delete-event", Gtk.main_quit) |
4406 | + self.window.connect("draw", self.cb_draw) |
4407 | + self.width = 600 |
4408 | + self.height = 240 |
4409 | + self.window.set_default_geometry(self.height, self.width) |
4410 | + self.window.set_default_size(self.width, self.height) |
4411 | + self.window.set_position(Gtk.WindowPosition.CENTER) |
4412 | + self.window.set_app_paintable(True) |
4413 | + self.window.set_has_resize_grip(False) |
4414 | + self.window.set_resizable(True) |
4415 | + |
4416 | + self.window.set_decorated(False) |
4417 | + self.window.set_property("skip-taskbar-hint", True) |
4418 | + self.window.set_keep_above(True) |
4419 | + self.screen = self.window.get_screen() |
4420 | + self.visual = self.screen.get_rgba_visual() |
4421 | + |
4422 | + if self.visual is not None and self.screen.is_composited(): |
4423 | + self.window.set_visual(self.visual) |
4424 | + |
4425 | + |
4426 | + def run(self, counter): |
4427 | + if counter > 0: |
4428 | + self.number = counter + 1 |
4429 | + if self.show_window: |
4430 | + self.window.show_all() |
4431 | + else: |
4432 | + self.number = 0 |
4433 | + self.countdown() |
4434 | + |
4435 | + def countdown(self): |
4436 | + if not self.canceled: |
4437 | + if self.number < 5: |
4438 | + self.indicator.blink_set_state(BLINK_FAST) |
4439 | + if self.number > 1: |
4440 | + self.window.queue_draw() |
4441 | + GObject.timeout_add(1000, self.countdown) |
4442 | + self.number -= 1 |
4443 | + else: |
4444 | + self.window.destroy() |
4445 | + GObject.timeout_add(400, self.counter_finished) |
4446 | + |
4447 | + def cancel_countdown(self): |
4448 | + self.indicator.blink_set_state(BLINK_STOP) |
4449 | + self.canceled = True |
4450 | + self.window.destroy() |
4451 | + self.number = 0 |
4452 | + |
4453 | + def counter_finished(self): |
4454 | + self.emit("counter-finished") |
4455 | + return False |
4456 | + |
4457 | + def cb_draw(self, widget, cr): |
4458 | + w = self.width |
4459 | + h = self.height |
4460 | + cr.set_source_rgba(1, 1, 1, 0) |
4461 | + cr.set_operator(cairo.OPERATOR_SOURCE) |
4462 | + cr.paint() |
4463 | + self._draw_rounded(cr, 1, 1, w - 10, h - 10, 20) |
4464 | + cr.set_line_width(1.0) |
4465 | + cr.set_source_rgba(0.0, 0.0, 0.0, 0.4) |
4466 | + cr.stroke_preserve() |
4467 | + cr.fill() |
4468 | + cr.set_operator(cairo.OPERATOR_OVER) |
4469 | + self._outline_text(cr, w, h, 36, _("Recording will start in ...")) |
4470 | + self._outline_text(cr, w, h + 70, 36, _("{0}".format(self.number))) |
4471 | + |
4472 | + def _draw_rounded(self, cr, x, y, w, h, r = 20): |
4473 | + cr.move_to(x + r, y) |
4474 | + cr.line_to(x + w - r, y) |
4475 | + cr.curve_to(x + w,y,x+w,y,x+w,y+r) |
4476 | + cr.line_to(x + w,y+h-r) |
4477 | + cr.curve_to(x + w, y + h, x + w, y + h, x + w - r, y + h) |
4478 | + cr.line_to(x + r, y + h) |
4479 | + cr.curve_to(x, y + h, x, y + h, x, y + h - r) |
4480 | + cr.line_to(x, y + r) |
4481 | + cr.curve_to(x, y, x, y, x + r, y) |
4482 | + |
4483 | + def _outline_text(self, cr, w, h, size, text): |
4484 | + cr.set_font_size(size) |
4485 | + try: |
4486 | + cr.select_font_face("Ubuntu", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) |
4487 | + except: |
4488 | + pass |
4489 | + te = cr.text_extents(text) |
4490 | + cr.set_source_rgba(0.4, 0.4, 0.4, 1.0) |
4491 | + cr.set_line_width(2.0) |
4492 | + cx = w/2 - te[2]/2 |
4493 | + cy = h/2 - te[3]/2 |
4494 | + cr.move_to(cx, cy) |
4495 | + cr.text_path(text) |
4496 | + cr.stroke() |
4497 | + cr.set_source_rgba(1.0, 1.0, 1.0, 1.0) |
4498 | + cr.move_to(cx, cy) |
4499 | + cr.show_text(text) |
4500 | |
4501 | === added file 'build/lib.linux-x86_64-2.7/kazam/frontend/window_region.py' |
4502 | --- build/lib.linux-x86_64-2.7/kazam/frontend/window_region.py 1970-01-01 00:00:00 +0000 |
4503 | +++ build/lib.linux-x86_64-2.7/kazam/frontend/window_region.py 2012-11-15 10:17:01 +0000 |
4504 | @@ -0,0 +1,200 @@ |
4505 | +# -*- coding: utf-8 -*- |
4506 | +# |
4507 | +# window_region.py |
4508 | +# |
4509 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
4510 | +# Copyright 2010 Andrew <andrew@karmic-desktop> |
4511 | +# |
4512 | +# This program is free software; you can redistribute it and/or modify |
4513 | +# it under the terms of the GNU General Public License as published by |
4514 | +# the Free Software Foundation; either version 3 of the License, or |
4515 | +# (at your option) any later version. |
4516 | +# |
4517 | +# This program is distributed in the hope that it will be useful, |
4518 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
4519 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4520 | +# GNU General Public License for more details. |
4521 | +# |
4522 | +# You should have received a copy of the GNU General Public License |
4523 | +# along with this program; if not, write to the Free Software |
4524 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
4525 | +# MA 02110-1301, USA. |
4526 | + |
4527 | +import cairo |
4528 | +import logging |
4529 | +logger = logging.getLogger("Window Region") |
4530 | + |
4531 | +from gettext import gettext as _ |
4532 | + |
4533 | +from gi.repository import Gtk, GObject, Gdk |
4534 | + |
4535 | +class RegionWindow(GObject.GObject): |
4536 | + |
4537 | + __gsignals__ = { |
4538 | + "region-selected" : (GObject.SIGNAL_RUN_LAST, |
4539 | + None, |
4540 | + (), |
4541 | + ), |
4542 | + "region-canceled" : (GObject.SIGNAL_RUN_LAST, |
4543 | + None, |
4544 | + (), |
4545 | + ), |
4546 | + } |
4547 | + |
4548 | + def __init__(self, region = None): |
4549 | + super(RegionWindow, self).__init__() |
4550 | + logger.debug("Initializing region window.") |
4551 | + self.window = Gtk.Window() |
4552 | + self.window.connect("configure-event", self.cb_configure_event) |
4553 | + self.window.connect("delete-event", Gtk.main_quit) |
4554 | + self.window.connect("draw", self.cb_draw) |
4555 | + self.window.connect("key-press-event", self.cb_keypress_event) |
4556 | + self.window.connect("button-press-event", self.cb_button_press_event) |
4557 | + |
4558 | + if region: |
4559 | + logger.debug("Old region defined at: X: {0}, Y: {1}, W: {2}, H: {3}".format(region[0], |
4560 | + region[1], |
4561 | + region[2], |
4562 | + region[3])) |
4563 | + self.startx = region[0] |
4564 | + self.starty = region[1] |
4565 | + self.endx = region[2] |
4566 | + self.endy = region[3] |
4567 | + self.window.move(self.startx, self.starty) |
4568 | + else: |
4569 | + self.startx = 0 |
4570 | + self.starty = 0 |
4571 | + self.endx = 640 |
4572 | + self.endy = 480 |
4573 | + self.window.set_position(Gtk.WindowPosition.CENTER) |
4574 | + |
4575 | + self.width = self.endx - self.startx |
4576 | + self.height = self.endy - self.starty |
4577 | + self.window.set_default_geometry(self.width, self.height) |
4578 | + |
4579 | + self.window.set_border_width(30) |
4580 | + self.window.set_app_paintable(True) |
4581 | + self.window.set_has_resize_grip(False) |
4582 | + self.window.set_resizable(True) |
4583 | + self.window.add_events(Gdk.EventMask.BUTTON_PRESS_MASK) |
4584 | + self.window.set_decorated(False) |
4585 | + self.window.set_property("skip-taskbar-hint", True) |
4586 | + self.window.set_keep_above(True) |
4587 | + self.screen = self.window.get_screen() |
4588 | + self.visual = self.screen.get_rgba_visual() |
4589 | + self.recording = False |
4590 | + |
4591 | + self.window.set_visual(self.visual) |
4592 | + if self.visual is not None and self.screen.is_composited(): |
4593 | + self.window.show_all() |
4594 | + |
4595 | + def cb_button_press_event(self, widget, event): |
4596 | + (op, button) = event.get_button() |
4597 | + if button == 1: |
4598 | + if int(event.x) in range(0, 15) and int(event.y) in range(0,15): |
4599 | + self.window.begin_resize_drag(Gdk.WindowEdge.NORTH_WEST, button, |
4600 | + event.x_root, event.y_root, event.time) |
4601 | + |
4602 | + elif int(event.x) in range(self.width-15, self.width) and int(event.y) in range(0,15): |
4603 | + self.window.begin_resize_drag(Gdk.WindowEdge.NORTH_EAST, button, |
4604 | + event.x_root, event.y_root, event.time) |
4605 | + |
4606 | + elif int(event.x) in range(self.width-15, self.width) and int(event.y) in range(self.height-15,self.height): |
4607 | + self.window.begin_resize_drag(Gdk.WindowEdge.SOUTH_EAST, button, |
4608 | + event.x_root, event.y_root, event.time) |
4609 | + |
4610 | + elif int(event.x) in range(0, 15) and int(event.y) in range(self.height-15, self.height): |
4611 | + self.window.begin_resize_drag(Gdk.WindowEdge.SOUTH_WEST, button, |
4612 | + event.x_root, event.y_root, event.time) |
4613 | + |
4614 | + else: |
4615 | + self.window.begin_move_drag(button, event.x_root, event.y_root, event.time) |
4616 | + |
4617 | + def cb_keypress_event(self, widget, event): |
4618 | + (op, keycode) = event.get_keycode() |
4619 | + if keycode == 36 or keycode == 104: # Enter |
4620 | + self.window.set_default_geometry(self.width, self.height) |
4621 | + (self.startx, self.starty) = self.window.get_position() |
4622 | + self.endx = self.startx + self.width - 1 |
4623 | + self.endy = self.starty + self.height - 1 |
4624 | + self.recording = True |
4625 | + self.window.input_shape_combine_region(None) |
4626 | + # |
4627 | + # When support for masked input is back, remove the hide() call. |
4628 | + # |
4629 | + self.window.hide() |
4630 | + # self.window.queue_draw() |
4631 | + self.emit("region-selected") |
4632 | + elif keycode == 9: # ESC |
4633 | + self.window.hide() |
4634 | + self.emit("region-canceled") |
4635 | + |
4636 | + |
4637 | + def cb_configure_event(self, widget, event): |
4638 | + self.width = event.width |
4639 | + self.height = event.height |
4640 | + |
4641 | + def cb_draw(self, widget, cr): |
4642 | + w = self.width |
4643 | + h = self.height |
4644 | + # |
4645 | + # Drawing a red rectangle around selected area would be extremely nice |
4646 | + # however, cairo.Region is missing from GIR and from pycairo and |
4647 | + # it is needed for input_shape_combine_region(). |
4648 | + # See: https://bugs.freedesktop.org/show_bug.cgi?id=44336 |
4649 | + # |
4650 | + #if self.recording: |
4651 | + # cr.set_source_rgba(0.0, 0.0, 0.0, 0.0) |
4652 | + # cr.set_operator(cairo.OPERATOR_SOURCE) |
4653 | + # cr.paint() |
4654 | + # surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w , h) |
4655 | + # surface_ctx = cairo.Context(surface) |
4656 | + # surface_ctx.set_source_rgba(1.0, 1.0, 1.0, 0.0) |
4657 | + # surface_ctx.set_operator(cairo.OPERATOR_SOURCE) |
4658 | + # surface_ctx.paint() |
4659 | + # reg = Gdk.cairo_region_create_from_surface(surface) |
4660 | + # widget.input_shape_combine_region(reg) |
4661 | + # cr.move_to(0, 0) |
4662 | + # cr.set_source_rgb(1.0, 0.0, 0.0) |
4663 | + # cr.set_line_width(2.0) |
4664 | + # cr.rectangle(0, 0, w, h) |
4665 | + # cr.stroke() |
4666 | + # cr.set_operator(cairo.OPERATOR_OVER) |
4667 | + #else: |
4668 | + cr.set_source_rgba(0.0, 0.0, 0.0, 0.4) |
4669 | + cr.set_operator(cairo.OPERATOR_SOURCE) |
4670 | + cr.paint() |
4671 | + cr.set_source_rgba(1.0, 1.0, 1.0, 1.0) |
4672 | + cr.set_line_width(1.0) |
4673 | + cr.move_to(0, 0) |
4674 | + cr.rectangle(0, 0, 15, 15) |
4675 | + cr.rectangle(w-15, 0, w, 15) |
4676 | + cr.rectangle(0, h-15, 15, h) |
4677 | + cr.rectangle(w-15, h-15, w, h) |
4678 | + cr.fill() |
4679 | + cr.set_source_rgb(0.0, 0.0, 0.0) |
4680 | + cr.rectangle(0, 0, w, h) |
4681 | + cr.stroke() |
4682 | + cr.set_operator(cairo.OPERATOR_OVER) |
4683 | + self._outline_text(cr, w, h, 24, _("Select region by resizing the window")) |
4684 | + self._outline_text(cr, w, h + 50, 24, _("Press ENTER to confirm or ESC to cancel.")) |
4685 | + self._outline_text(cr, w, h + 80, 12, "({0} x {1})".format(w, h)) |
4686 | + |
4687 | + |
4688 | + def _outline_text(self, cr, w, h, size, text): |
4689 | + cr.set_font_size(size) |
4690 | + try: |
4691 | + cr.select_font_face("Ubuntu", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) |
4692 | + except: |
4693 | + pass |
4694 | + te = cr.text_extents(text) |
4695 | + cr.set_line_width(2.0) |
4696 | + cx = w/2 - te[2]/2 |
4697 | + cy = h/2 - te[3]/2 |
4698 | + cr.set_source_rgba(0.4, 0.4, 0.4, 1.0) |
4699 | + cr.move_to(cx, cy) |
4700 | + cr.text_path(text) |
4701 | + cr.stroke() |
4702 | + cr.set_source_rgba(1.0, 1.0, 1.0, 1.0) |
4703 | + cr.move_to(cx, cy) |
4704 | + cr.show_text(text) |
4705 | |
4706 | === added file 'build/lib.linux-x86_64-2.7/kazam/frontend/window_select.py' |
4707 | --- build/lib.linux-x86_64-2.7/kazam/frontend/window_select.py 1970-01-01 00:00:00 +0000 |
4708 | +++ build/lib.linux-x86_64-2.7/kazam/frontend/window_select.py 2012-11-15 10:17:01 +0000 |
4709 | @@ -0,0 +1,181 @@ |
4710 | +# -*- coding: utf-8 -*- |
4711 | +# |
4712 | +# window_select.py |
4713 | +# |
4714 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
4715 | +# Copyright 2010 Andrew <andrew@karmic-desktop> |
4716 | +# |
4717 | +# This program is free software; you can redistribute it and/or modify |
4718 | +# it under the terms of the GNU General Public License as published by |
4719 | +# the Free Software Foundation; either version 3 of the License, or |
4720 | +# (at your option) any later version. |
4721 | +# |
4722 | +# This program is distributed in the hope that it will be useful, |
4723 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
4724 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4725 | +# GNU General Public License for more details. |
4726 | +# |
4727 | +# You should have received a copy of the GNU General Public License |
4728 | +# along with this program; if not, write to the Free Software |
4729 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
4730 | +# MA 02110-1301, USA. |
4731 | + |
4732 | +import time |
4733 | +import cairo |
4734 | +import logging |
4735 | +logger = logging.getLogger("Window Select") |
4736 | + |
4737 | +from gettext import gettext as _ |
4738 | + |
4739 | +from gi.repository import Gtk, GObject, Gdk, Wnck, GdkX11 |
4740 | + |
4741 | +from kazam.backend.constants import * |
4742 | + |
4743 | +class SelectWindow(GObject.GObject): |
4744 | + |
4745 | + __gsignals__ = { |
4746 | + "window-selected" : (GObject.SIGNAL_RUN_LAST, |
4747 | + None, |
4748 | + (), |
4749 | + ), |
4750 | + "window-canceled" : (GObject.SIGNAL_RUN_LAST, |
4751 | + None, |
4752 | + (), |
4753 | + ), |
4754 | + } |
4755 | + |
4756 | + def __init__(self): |
4757 | + super(SelectWindow, self).__init__() |
4758 | + logger.debug("Initializing select window.") |
4759 | + |
4760 | + self.xid = None |
4761 | + |
4762 | + self.window = Gtk.Window() |
4763 | + self.window.connect("delete-event", Gtk.main_quit) |
4764 | + self.window.connect("draw", self.cb_draw) |
4765 | + self.window.connect("key-press-event", self.cb_keypress_event) |
4766 | + self.window.connect("button-press-event", self.cb_button_press_event) |
4767 | + self.window.connect("leave-notify-event", self.cb_leave_notify_event) |
4768 | + |
4769 | + self.window.set_border_width(30) |
4770 | + self.window.set_app_paintable(True) |
4771 | + self.window.set_has_resize_grip(False) |
4772 | + self.window.set_resizable(True) |
4773 | + self.window.add_events(Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK) |
4774 | + self.window.set_decorated(False) |
4775 | + self.window.set_property("skip-taskbar-hint", True) |
4776 | + self.window.set_keep_above(True) |
4777 | + self.screen = self.window.get_screen() |
4778 | + self.visual = self.screen.get_rgba_visual() |
4779 | + self.recording = False |
4780 | + |
4781 | + self.disp = GdkX11.X11Display.get_default() |
4782 | + self.dm = Gdk.Display.get_device_manager(self.disp) |
4783 | + self.pntr_device = self.dm.get_client_pointer() |
4784 | + |
4785 | + if self.visual is not None and self.screen.is_composited(): |
4786 | + logger.debug("Compositing window manager detected.") |
4787 | + self.window.set_visual(self.visual) |
4788 | + self.compositing = True |
4789 | + else: |
4790 | + self.compositing = False |
4791 | + |
4792 | + (scr, x, y) = self.pntr_device.get_position() |
4793 | + cur = scr.get_monitor_at_point(x, y) |
4794 | + self.window.unfullscreen() |
4795 | + self.window.move(HW.screens[cur]['x'], |
4796 | + HW.screens[cur]['y']) |
4797 | + self.window.fullscreen() |
4798 | + crosshair_cursor = Gdk.Cursor(Gdk.CursorType.CROSSHAIR) |
4799 | + self.last_cursor = Gdk.Cursor(Gdk.CursorType.LEFT_PTR) |
4800 | + self.gdk_win = self.window.get_root_window() |
4801 | + self.gdk_win.set_cursor(crosshair_cursor) |
4802 | + |
4803 | + def cb_leave_notify_event(self, widget, event): |
4804 | + (scr, x, y) = self.pntr_device.get_position() |
4805 | + cur = scr.get_monitor_at_point(x, y) |
4806 | + self.window.unfullscreen() |
4807 | + logger.debug("Move to X: {0} Y: {1}".format(HW.screens[cur]['x'], HW.screens[cur]['y'])) |
4808 | + self.window.move(HW.screens[cur]['x'], |
4809 | + HW.screens[cur]['y']) |
4810 | + self.window.fullscreen() |
4811 | + |
4812 | + def cb_button_press_event(self, widget, event): |
4813 | + self.geometry = None |
4814 | + self.win_name = None |
4815 | + self.xid = None |
4816 | + # TODO: Error handling |
4817 | + (op, button) = event.get_button() |
4818 | + if button == 1: |
4819 | + screen = Wnck.Screen.get_default() |
4820 | + screen.force_update() |
4821 | + workspace = screen.get_active_workspace() |
4822 | + wins = screen.get_windows_stacked() |
4823 | + |
4824 | + for win in reversed(wins): |
4825 | + if win.is_visible_on_workspace(workspace) and win.is_in_viewport(workspace): |
4826 | + self.win_name = win.get_name() |
4827 | + if not (self.win_name.lower().startswith("kazam") or self.win_name.lower().startswith("desktop")): |
4828 | + geometry = win.get_client_window_geometry() |
4829 | + self.geometry = geometry |
4830 | + if geometry[0] <= event.x_root <= (geometry[0] + geometry[2]) and geometry[1] <= event.y_root <= (geometry[1] + geometry[3]): |
4831 | + self.xid = win.get_xid() |
4832 | + break |
4833 | + self.gdk_win.set_cursor(self.last_cursor) |
4834 | + self.window.hide() |
4835 | + if self.xid: |
4836 | + self.emit("window-selected") |
4837 | + else: |
4838 | + self.emit("window-canceled") |
4839 | + |
4840 | + def cb_keypress_event(self, widget, event): |
4841 | + (op, keycode) = event.get_keycode() |
4842 | + if keycode == 36 or keycode == 104 or keycode == 9: # Enter or Escape |
4843 | + self.gdk_win.set_cursor(self.last_cursor) |
4844 | + self.window.hide() |
4845 | + self.emit("window-canceled") |
4846 | + |
4847 | + def cb_draw(self, widget, cr): |
4848 | + (w, h) = self.window.get_size() |
4849 | + |
4850 | + |
4851 | + if self.compositing: |
4852 | + cr.set_source_rgba(0.0, 0.0, 0.0, 0.45) |
4853 | + else: |
4854 | + cr.set_source_rgb(0.5, 0.5, 0.5) |
4855 | + |
4856 | + cr.set_operator(cairo.OPERATOR_SOURCE) |
4857 | + cr.paint() |
4858 | + if self.compositing: |
4859 | + cr.set_source_rgba(1.0, 1.0, 1.0, 1.0) |
4860 | + else: |
4861 | + cr.set_source_rgba(1.0, 1.0, 1.0) |
4862 | + |
4863 | + cr.set_operator(cairo.OPERATOR_OVER) |
4864 | + self._outline_text(cr, w, h, 30, _("Select a window by clicking on it.")) |
4865 | + self._outline_text(cr, w, h + 50, 26, _("Press ENTER or ESC to cancel")) |
4866 | + |
4867 | + def _outline_text(self, cr, w, h, size, text): |
4868 | + cr.set_font_size(size) |
4869 | + try: |
4870 | + cr.select_font_face("Ubuntu", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) |
4871 | + except: |
4872 | + pass |
4873 | + te = cr.text_extents(text) |
4874 | + cr.set_line_width(2.0) |
4875 | + cx = w/2 - te[2]/2 |
4876 | + cy = h/2 - te[3]/2 |
4877 | + if self.compositing: |
4878 | + cr.set_source_rgba(0.4, 0.4, 0.4, 1.0) |
4879 | + else: |
4880 | + cr.set_source_rgb(0.4, 0.4, 0.4) |
4881 | + |
4882 | + cr.move_to(cx, cy) |
4883 | + cr.text_path(text) |
4884 | + cr.stroke() |
4885 | + if self.compositing: |
4886 | + cr.set_source_rgba(1.0, 1.0, 1.0, 1.0) |
4887 | + else: |
4888 | + cr.set_source_rgb(1.0, 1.0, 1.0) |
4889 | + cr.move_to(cx, cy) |
4890 | + cr.show_text(text) |
4891 | |
4892 | === added file 'build/lib.linux-x86_64-2.7/kazam/instant.py' |
4893 | --- build/lib.linux-x86_64-2.7/kazam/instant.py 1970-01-01 00:00:00 +0000 |
4894 | +++ build/lib.linux-x86_64-2.7/kazam/instant.py 2012-11-15 10:17:01 +0000 |
4895 | @@ -0,0 +1,142 @@ |
4896 | +#!/usr/bin/env python |
4897 | +# -*- coding: utf-8 -*- |
4898 | +# |
4899 | +# instant.py |
4900 | +# |
4901 | +# Copyright 2012 David Klasinc <bigwhale@lubica.net> |
4902 | +# |
4903 | +# This program is free software; you can redistribute it and/or modify |
4904 | +# it under the terms of the GNU General Public License as published by |
4905 | +# the Free Software Foundation; either version 3 of the License, or |
4906 | +# (at your option) any later version. |
4907 | +# |
4908 | +# This program is distributed in the hope that it will be useful, |
4909 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
4910 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4911 | +# GNU General Public License for more details. |
4912 | +# |
4913 | +# You should have received a copy of the GNU General Public License |
4914 | +# along with this program; if not, write to the Free Software |
4915 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
4916 | +# MA 02110-1301, USA. |
4917 | + |
4918 | +import sys |
4919 | +import logging |
4920 | +from gettext import gettext as _ |
4921 | +from gi.repository import Gtk, GObject |
4922 | + |
4923 | +from kazam.utils import * |
4924 | +from kazam.backend.prefs import * |
4925 | +from kazam.backend.constants import * |
4926 | +from kazam.backend.grabber import Grabber |
4927 | + |
4928 | +logger = logging.getLogger("Instant") |
4929 | + |
4930 | +class InstantApp(GObject.GObject): |
4931 | + |
4932 | + def __init__(self, datadir, dist, debug, mode, preferences=False): |
4933 | + GObject.GObject.__init__(self) |
4934 | + logger.debug("Setting variables.{0}".format(datadir)) |
4935 | + |
4936 | + self.mode = mode |
4937 | + self.take = 0 |
4938 | + |
4939 | + prefs.datadir = datadir |
4940 | + prefs.debug = debug |
4941 | + prefs.dist = dist |
4942 | + prefs.get_sound_files() |
4943 | + |
4944 | + if preferences: |
4945 | + logger.debug("Preferences requested.") |
4946 | + from kazam.frontend.preferences import Preferences |
4947 | + from kazam.pulseaudio.pulseaudio import pulseaudio_q |
4948 | + prefs.pa_q = pulseaudio_q() |
4949 | + prefs.pa_q.start() |
4950 | + prefs.get_audio_sources() |
4951 | + |
4952 | + self.preferences_window = Preferences() |
4953 | + self.preferences_window.connect("prefs-quit", self.cb_prefs_quit) |
4954 | + self.preferences_window.open() |
4955 | + |
4956 | + else: |
4957 | + self.old_path = None |
4958 | + |
4959 | + if HW.combined_screen: |
4960 | + self.video_source = HW.combined_screen |
4961 | + else: |
4962 | + screen = HW.get_current_screen() |
4963 | + self.video_source = HW.screens[screen] |
4964 | + |
4965 | + self.grabber = Grabber() |
4966 | + self.grabber.connect("flush-done", self.cb_flush_done) |
4967 | + self.grabber.connect("save-done", self.cb_save_done) |
4968 | + |
4969 | + if self.mode == MODE_AREA: |
4970 | + logger.debug("Area ON.") |
4971 | + from kazam.frontend.window_area import AreaWindow |
4972 | + self.area_window = AreaWindow() |
4973 | + self.area_window.connect("area-selected", self.cb_area_selected) |
4974 | + self.area_window.connect("area-canceled", self.cb_area_canceled) |
4975 | + self.area_window.window.show_all() |
4976 | + elif self.mode == MODE_ALL: |
4977 | + self.grabber.setup_sources(self.video_source, None, None) |
4978 | + logger.debug("Grabbing screen") |
4979 | + self.grabber.grab() |
4980 | + elif self.mode == MODE_ACTIVE: |
4981 | + self.grabber.setup_sources(self.video_source, None, None, active=True) |
4982 | + logger.debug("Grabbing screen") |
4983 | + self.grabber.grab() |
4984 | + elif self.mode == MODE_GOD: |
4985 | + logger.debug("Grabbing in god mode.") |
4986 | + self.grabber.setup_sources(self.video_source, None, None, god=True) |
4987 | + self.grabber.grab() |
4988 | + self.grabber.setup_sources(self.video_source, None, None, active=True, god=True) |
4989 | + self.grabber.grab() |
4990 | + else: |
4991 | + sys.exit(0) |
4992 | + |
4993 | + def cb_area_selected(self, widget): |
4994 | + logger.debug("Area selected: SX: {0}, SY: {1}, EX: {2}, EY: {3}".format( |
4995 | + self.area_window.startx, |
4996 | + self.area_window.starty, |
4997 | + self.area_window.endx, |
4998 | + self.area_window.endy)) |
4999 | + prefs.area = (self.area_window.startx, |
5000 | + self.area_window.starty, |
The diff has been truncated for viewing.
bzr branch lp:ubuntu/kazam orig-source to retrieve needed tarball. orig-source orig-source (choose from: binary binary-arch binary-indep build build-arch build-indep clean install install-arch install-indep) orig-source] Error 255 orig-source rule failed launchpad. net/kazam/ +download .*/kazam- ([0-9.] +)\.tar\ .gz
...
bzr merge lp:~bkerensa/ubuntu/raring/kazam/new-upstream
...
bzr builddeb -S -- -sa -us -uc
Building using working tree
Building package in normal mode
Looking for a way to retrieve the upstream tarball
Using apt to look for the upstream tarball.
apt could not find the needed tarball.
Trying to use get-packaged-
dh --with python2 get-packaged-
dh: Unknown sequence get-packaged-
make: *** [get-packaged-
Trying to run get-packaged-
Trying to use get-orig-source to retrieve needed tarball (deprecated).
dh --with python2 get-orig-source
dh: Unknown sequence get-orig-source (choose from: binary binary-arch binary-indep build build-arch build-indep clean install install-arch install-indep)
make: *** [get-orig-source] Error 255
Trying to run get-orig-source rule failed
Using uscan to look for the upstream tarball.
uscan warning: In /tmp/tmprFZq6l no matching hrefs for version 1.3.1 in watch line
http://
uscan could not find the needed tarball.
bzr: ERROR: Unable to find the needed upstream tarball for package kazam, version 1.3.1.
Please fix debian/watch :)