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