Skip to content

Commit 02636de

Browse files
This feature adds a screenshot alert to Sugar.
On pressing <Alt>+1 key or selecting 'Take a screenshot' option from bottom toolbar generates a popup alert where user can change the default name of that screenshot. The popup can be dismissed by clicking 'X' button or by pressing 'Escape' key. Currently there is no notification on screen capture in Sugar. The user wants to rename the screenshot, he has to go back to Journal to do it.
1 parent 0056589 commit 02636de

File tree

6 files changed

+449
-4
lines changed

6 files changed

+449
-4
lines changed

extensions/deviceicon/display.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434

3535
from jarabe.frame.frameinvoker import FrameWidgetInvoker
3636
from jarabe.model import brightness
37-
from jarabe.model.screenshot import take_screenshot
37+
from jarabe.screenshotpanel.gui import ScreenshotPanel
3838
from jarabe import frame
3939

4040

@@ -230,7 +230,7 @@ def __screenshot_cb(self, palette):
230230
def __take_screenshot_cb(self, frame_):
231231
if frame_.is_visible():
232232
return True
233-
take_screenshot()
233+
panel = ScreenshotPanel()
234234
frame_.show()
235235
return False
236236

extensions/globalkey/screenshot.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
# along with this program; if not, write to the Free Software
1616
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1717

18-
from jarabe.model.screenshot import take_screenshot
18+
from jarabe.screenshotpanel.gui import ScreenshotPanel
1919

2020
BOUND_KEYS = ['<alt>1', 'Print']
2121

2222

2323
def handle_key_press(key):
24-
take_screenshot()
24+
panel = ScreenshotPanel()
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
sugardir = $(pythondir)/jarabe/screenshotpanel
2+
sugar_PYTHON = \
3+
__init__.py \
4+
gui.py \
5+
toolbar.py
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Copyright (C) 2016 Utkarsh Tiwari
5+
#
6+
# This program is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
#
19+
# Contact information:
20+
# Utkarsh Tiwari [email protected]

src/jarabe/screenshotpanel/gui.py

Lines changed: 330 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,330 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Copyright (C) 2016 Utkarsh Tiwari
5+
#
6+
# This program is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
#
19+
# Contact information:
20+
# Utkarsh Tiwari [email protected]
21+
22+
import os
23+
import dbus
24+
import cairo
25+
import logging
26+
import StringIO
27+
import tempfile
28+
from gettext import gettext as _
29+
30+
from gi.repository import GObject
31+
from gi.repository import Gtk
32+
from gi.repository import Gdk
33+
from gi.repository import Gio
34+
35+
from sugar3 import env
36+
37+
from sugar3.datastore import datastore
38+
from sugar3.graphics.icon import Icon
39+
from sugar3.graphics import style
40+
from sugar3.graphics.alert import Alert, TimeoutAlert
41+
from sugar3.graphics import iconentry
42+
43+
44+
from jarabe.model.session import get_session_manager
45+
from jarabe.screenshotpanel.toolbar import MainToolbar
46+
from jarabe import config
47+
from jarabe.model import shell
48+
49+
50+
_logger = logging.getLogger('ScreenshotPanel')
51+
52+
53+
class ScreenshotPanel(Gtk.Window):
54+
'''
55+
Generates a pop papel to allow user to save the
56+
screenshot by the name of his choice
57+
'''
58+
59+
__gtype_name__ = 'ScreenshotPanel'
60+
61+
62+
def __init__(self):
63+
Gtk.Window.__init__(self)
64+
65+
self.modify_bg(Gtk.StateType.NORMAL,
66+
style.COLOR_BLACK.get_gdk_color())
67+
self._set_screensize()
68+
self.set_border_width(style.LINE_WIDTH)
69+
self.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
70+
self.set_decorated(False)
71+
self.set_resizable(False)
72+
self.set_modal(True)
73+
self.set_can_focus(True)
74+
75+
self.connect('key-press-event', self.__key_press_event_cb)
76+
77+
self._toolbar = None
78+
self._canvas = None
79+
self._table = None
80+
self._scrolledwindow = None
81+
self._separator = None
82+
self._section_view = None
83+
self._section_toolbar = None
84+
self._main_toolbar = None
85+
86+
self._vbox = Gtk.VBox()
87+
self._hbox = Gtk.HBox()
88+
self._vbox.pack_start(self._hbox, True, True, 0)
89+
self._hbox.show()
90+
91+
self._main_view = Gtk.EventBox()
92+
self._hbox.pack_start(self._main_view, True, True, 0)
93+
self._main_view.modify_bg(Gtk.StateType.NORMAL,
94+
style.COLOR_BLACK.get_gdk_color())
95+
self._main_view.show()
96+
97+
self.add(self._vbox)
98+
self._vbox.show()
99+
self._setup_main()
100+
self._show_main_view()
101+
102+
# Generates the thumbnail
103+
preview_image, activity_title = generate_thumbnail()
104+
self._main_view.add(preview_image)
105+
preview_image.show()
106+
self.screenshot_surface, self.file_path = take_screenshot()
107+
108+
self._vbox = Gtk.VBox()
109+
self._hbox.pack_start(self._vbox, True, True, 0)
110+
self._vbox.show()
111+
112+
# Name label
113+
name_label = Gtk.Label()
114+
name_label.set_alignment(0.5, 1)
115+
name_label.set_use_markup(True)
116+
name_label.set_markup("<b>"+_('Name')+"</b>")
117+
name_label.modify_bg(Gtk.StateType.NORMAL,
118+
style.COLOR_BLACK.get_gdk_color())
119+
name_label.modify_fg(Gtk.StateType.NORMAL, Gdk.color_parse("yellow"))
120+
self._vbox.pack_start(name_label, True, True, 0)
121+
name_label.show()
122+
123+
# Name entry box
124+
self._name_view = Gtk.EventBox()
125+
self._name_view.modify_bg(Gtk.StateType.NORMAL,
126+
style.COLOR_BLACK.get_gdk_color())
127+
self._name_view.show()
128+
129+
# Entry box
130+
self._search_entry = Gtk.Entry()
131+
halign = Gtk.Alignment.new(0.5, 0, 0, 0)
132+
halign.add(self._name_view)
133+
halign.show()
134+
135+
self._vbox.pack_start(halign, True, True, 0)
136+
self._name_view.add(self._search_entry)
137+
self._search_entry.show()
138+
self._search_entry.set_text(_(activity_title))
139+
self._search_entry.grab_focus()
140+
self.show()
141+
142+
def _set_cursor(self, cursor):
143+
self.get_window().set_cursor(cursor)
144+
Gdk.flush()
145+
146+
def _set_screensize(self):
147+
'''
148+
Sets the size of the popup based on
149+
the screen resolution.
150+
'''
151+
width = Gdk.Screen.width() / 4
152+
height = Gdk.Screen.height() / 4
153+
self.set_size_request(width, height)
154+
155+
def _set_toolbar(self, toolbar):
156+
'''
157+
Sets up the toolbar on the popup.
158+
'''
159+
if self._toolbar:
160+
self._vbox.remove(self._toolbar)
161+
self._vbox.pack_start(toolbar, False, False, 0)
162+
self._vbox.reorder_child(toolbar, 0)
163+
self._toolbar = toolbar
164+
if not self._separator:
165+
self._separator = Gtk.HSeparator()
166+
self._vbox.pack_start(self._separator, False, False, 0)
167+
self._vbox.reorder_child(self._separator, 1)
168+
self._separator.show()
169+
170+
def _setup_main(self):
171+
self._main_toolbar = MainToolbar()
172+
self._main_toolbar.connect('stop-clicked',
173+
self.__stop_clicked_cb)
174+
self._main_toolbar.connect('ok-clicked', self.__ok_clicked_cb)
175+
176+
def _show_main_view(self):
177+
self._set_toolbar(self._main_toolbar)
178+
self._main_toolbar.show()
179+
self._main_view.modify_bg(Gtk.StateType.NORMAL,
180+
style.COLOR_BLACK.get_gdk_color())
181+
182+
def __key_press_event_cb(self, window, event):
183+
# if the user clicked out of the window - fix SL #3188
184+
if not self.is_active():
185+
self.present()
186+
return False
187+
188+
def __stop_clicked_cb(self, widget):
189+
self.destroy()
190+
191+
def __ok_clicked_cb(self, widget):
192+
self.save_screenshot(self._search_entry.get_text())
193+
self.destroy()
194+
195+
def save_screenshot(self, title):
196+
settings = Gio.Settings('org.sugarlabs.user')
197+
color = settings.get_string('color')
198+
199+
jobject = datastore.create()
200+
try:
201+
jobject.metadata['title'] = title
202+
jobject.metadata['keep'] = '0'
203+
jobject.metadata['buddies'] = ''
204+
jobject.metadata['preview'] = _get_preview_data(self.screenshot_surface)
205+
jobject.metadata['icon-color'] = color
206+
jobject.metadata['mime_type'] = 'image/png'
207+
jobject.file_path = self.file_path
208+
datastore.write(jobject, transfer_ownership=True)
209+
finally:
210+
jobject.destroy()
211+
del jobject
212+
213+
214+
def generate_thumbnail():
215+
'''
216+
Generates the thumbnail to be displayed
217+
on the screenshot alert popup
218+
'''
219+
window = Gdk.get_default_root_window()
220+
width, height = window.get_width(), window.get_height()
221+
thumb_width, thumb_height = style.zoom(200), style.zoom(160)
222+
223+
thumb_surface = Gdk.Window.create_similar_surface(
224+
window, cairo.CONTENT_COLOR, thumb_width, thumb_height)
225+
226+
cairo_context = cairo.Context(thumb_surface)
227+
thumb_scale_w = thumb_width * 1.0 / width
228+
thumb_scale_h = thumb_height * 1.0 / height
229+
cairo_context.scale(thumb_scale_w, thumb_scale_h)
230+
Gdk.cairo_set_source_window(cairo_context, window, 0, 0)
231+
cairo_context.paint()
232+
233+
link_width, link_height = style.zoom(200), style.zoom(160)
234+
link_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
235+
link_width, link_height)
236+
237+
cairo_context = cairo.Context(link_surface)
238+
dest_x = style.zoom(0)
239+
dest_y = style.zoom(0)
240+
cairo_context.set_source_surface(thumb_surface, dest_x, dest_y)
241+
thumb_width, thumb_height = style.zoom(200), style.zoom(160)
242+
cairo_context.rectangle(dest_x, dest_y, thumb_width, thumb_height)
243+
cairo_context.fill()
244+
245+
bg_width, bg_height = style.zoom(200), style.zoom(160)
246+
pixbuf_bg = Gdk.pixbuf_get_from_surface(link_surface, 0, 0,
247+
bg_width, bg_height)
248+
249+
preview_image = Gtk.Image()
250+
preview_image.set_from_pixbuf(pixbuf_bg)
251+
252+
# Set's the default title
253+
content_title = None
254+
shell_model = shell.get_model()
255+
zoom_level = shell_model.zoom_level
256+
257+
# TRANS: Nouns of what a screenshot contains
258+
if zoom_level == shell_model.ZOOM_MESH:
259+
content_title = _('Mesh')
260+
elif zoom_level == shell_model.ZOOM_GROUP:
261+
content_title = _('Group')
262+
elif zoom_level == shell_model.ZOOM_HOME:
263+
content_title = _('Home')
264+
elif zoom_level == shell_model.ZOOM_ACTIVITY:
265+
activity = shell_model.get_active_activity()
266+
if activity is not None:
267+
content_title = activity.get_title()
268+
if content_title is None:
269+
content_title = _('Activity')
270+
271+
if content_title is None:
272+
title = _('Screenshot')
273+
else:
274+
title = _('Screenshot of \"%s\"') % content_title
275+
276+
return preview_image, title
277+
278+
279+
def take_screenshot():
280+
'''
281+
Captures a screenshot and saves
282+
it to a temp dir.
283+
'''
284+
tmp_dir = os.path.join(env.get_profile_path(), 'data')
285+
fd, file_path = tempfile.mkstemp(dir=tmp_dir)
286+
os.close(fd)
287+
288+
window = Gdk.get_default_root_window()
289+
width, height = window.get_width(), window.get_height()
290+
291+
screenshot_surface = Gdk.Window.create_similar_surface(
292+
window, cairo.CONTENT_COLOR, width, height)
293+
294+
cr = cairo.Context(screenshot_surface)
295+
Gdk.cairo_set_source_window(cr, window, 0, 0)
296+
cr.paint()
297+
screenshot_surface.write_to_png(file_path)
298+
299+
return screenshot_surface, file_path
300+
301+
302+
def _get_preview_data(screenshot_surface):
303+
screenshot_width = screenshot_surface.get_width()
304+
screenshot_height = screenshot_surface.get_height()
305+
306+
preview_width, preview_height = style.zoom(300), style.zoom(225)
307+
preview_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
308+
preview_width, preview_height)
309+
cr = cairo.Context(preview_surface)
310+
311+
scale_w = preview_width * 1.0 / screenshot_width
312+
scale_h = preview_height * 1.0 / screenshot_height
313+
scale = min(scale_w, scale_h)
314+
315+
translate_x = int((preview_width - (screenshot_width * scale)) / 2)
316+
translate_y = int((preview_height - (screenshot_height * scale)) / 2)
317+
318+
cr.translate(translate_x, translate_y)
319+
cr.scale(scale, scale)
320+
321+
cr.set_source_rgba(1, 1, 1, 0)
322+
cr.set_operator(cairo.OPERATOR_SOURCE)
323+
cr.paint()
324+
cr.set_source_surface(screenshot_surface)
325+
cr.paint()
326+
327+
preview_str = StringIO.StringIO()
328+
preview_surface.write_to_png(preview_str)
329+
330+
return dbus.ByteArray(preview_str.getvalue())

0 commit comments

Comments
 (0)