Skip to content

Commit

Permalink
This feature adds a screenshot alert to Sugar.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
iamutkarshtiwari committed Apr 8, 2016
1 parent 0056589 commit 02636de
Show file tree
Hide file tree
Showing 6 changed files with 449 additions and 4 deletions.
4 changes: 2 additions & 2 deletions extensions/deviceicon/display.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

from jarabe.frame.frameinvoker import FrameWidgetInvoker
from jarabe.model import brightness
from jarabe.model.screenshot import take_screenshot
from jarabe.screenshotpanel.gui import ScreenshotPanel
from jarabe import frame


Expand Down Expand Up @@ -230,7 +230,7 @@ def __screenshot_cb(self, palette):
def __take_screenshot_cb(self, frame_):
if frame_.is_visible():
return True
take_screenshot()
panel = ScreenshotPanel()
frame_.show()
return False

Expand Down
4 changes: 2 additions & 2 deletions extensions/globalkey/screenshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

from jarabe.model.screenshot import take_screenshot
from jarabe.screenshotpanel.gui import ScreenshotPanel

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


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

import os
import dbus
import cairo
import logging
import StringIO
import tempfile
from gettext import gettext as _

from gi.repository import GObject
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import Gio

from sugar3 import env

from sugar3.datastore import datastore
from sugar3.graphics.icon import Icon
from sugar3.graphics import style
from sugar3.graphics.alert import Alert, TimeoutAlert
from sugar3.graphics import iconentry


from jarabe.model.session import get_session_manager
from jarabe.screenshotpanel.toolbar import MainToolbar
from jarabe import config
from jarabe.model import shell


_logger = logging.getLogger('ScreenshotPanel')


class ScreenshotPanel(Gtk.Window):
'''
Generates a pop papel to allow user to save the
screenshot by the name of his choice
'''

__gtype_name__ = 'ScreenshotPanel'


def __init__(self):
Gtk.Window.__init__(self)

self.modify_bg(Gtk.StateType.NORMAL,
style.COLOR_BLACK.get_gdk_color())
self._set_screensize()
self.set_border_width(style.LINE_WIDTH)
self.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
self.set_decorated(False)
self.set_resizable(False)
self.set_modal(True)
self.set_can_focus(True)

self.connect('key-press-event', self.__key_press_event_cb)

self._toolbar = None
self._canvas = None
self._table = None
self._scrolledwindow = None
self._separator = None
self._section_view = None
self._section_toolbar = None
self._main_toolbar = None

self._vbox = Gtk.VBox()
self._hbox = Gtk.HBox()
self._vbox.pack_start(self._hbox, True, True, 0)
self._hbox.show()

self._main_view = Gtk.EventBox()
self._hbox.pack_start(self._main_view, True, True, 0)
self._main_view.modify_bg(Gtk.StateType.NORMAL,
style.COLOR_BLACK.get_gdk_color())
self._main_view.show()

self.add(self._vbox)
self._vbox.show()
self._setup_main()
self._show_main_view()

# Generates the thumbnail
preview_image, activity_title = generate_thumbnail()
self._main_view.add(preview_image)
preview_image.show()
self.screenshot_surface, self.file_path = take_screenshot()

self._vbox = Gtk.VBox()
self._hbox.pack_start(self._vbox, True, True, 0)
self._vbox.show()

# Name label
name_label = Gtk.Label()
name_label.set_alignment(0.5, 1)
name_label.set_use_markup(True)
name_label.set_markup("<b>"+_('Name')+"</b>")
name_label.modify_bg(Gtk.StateType.NORMAL,
style.COLOR_BLACK.get_gdk_color())
name_label.modify_fg(Gtk.StateType.NORMAL, Gdk.color_parse("yellow"))
self._vbox.pack_start(name_label, True, True, 0)
name_label.show()

# Name entry box
self._name_view = Gtk.EventBox()
self._name_view.modify_bg(Gtk.StateType.NORMAL,
style.COLOR_BLACK.get_gdk_color())
self._name_view.show()

# Entry box
self._search_entry = Gtk.Entry()
halign = Gtk.Alignment.new(0.5, 0, 0, 0)
halign.add(self._name_view)
halign.show()

self._vbox.pack_start(halign, True, True, 0)
self._name_view.add(self._search_entry)
self._search_entry.show()
self._search_entry.set_text(_(activity_title))
self._search_entry.grab_focus()
self.show()

def _set_cursor(self, cursor):
self.get_window().set_cursor(cursor)
Gdk.flush()

def _set_screensize(self):
'''
Sets the size of the popup based on
the screen resolution.
'''
width = Gdk.Screen.width() / 4
height = Gdk.Screen.height() / 4
self.set_size_request(width, height)

def _set_toolbar(self, toolbar):
'''
Sets up the toolbar on the popup.
'''
if self._toolbar:
self._vbox.remove(self._toolbar)
self._vbox.pack_start(toolbar, False, False, 0)
self._vbox.reorder_child(toolbar, 0)
self._toolbar = toolbar
if not self._separator:
self._separator = Gtk.HSeparator()
self._vbox.pack_start(self._separator, False, False, 0)
self._vbox.reorder_child(self._separator, 1)
self._separator.show()

def _setup_main(self):
self._main_toolbar = MainToolbar()
self._main_toolbar.connect('stop-clicked',
self.__stop_clicked_cb)
self._main_toolbar.connect('ok-clicked', self.__ok_clicked_cb)

def _show_main_view(self):
self._set_toolbar(self._main_toolbar)
self._main_toolbar.show()
self._main_view.modify_bg(Gtk.StateType.NORMAL,
style.COLOR_BLACK.get_gdk_color())

def __key_press_event_cb(self, window, event):
# if the user clicked out of the window - fix SL #3188
if not self.is_active():
self.present()
return False

def __stop_clicked_cb(self, widget):
self.destroy()

def __ok_clicked_cb(self, widget):
self.save_screenshot(self._search_entry.get_text())
self.destroy()

def save_screenshot(self, title):
settings = Gio.Settings('org.sugarlabs.user')
color = settings.get_string('color')

jobject = datastore.create()
try:
jobject.metadata['title'] = title
jobject.metadata['keep'] = '0'
jobject.metadata['buddies'] = ''
jobject.metadata['preview'] = _get_preview_data(self.screenshot_surface)
jobject.metadata['icon-color'] = color
jobject.metadata['mime_type'] = 'image/png'
jobject.file_path = self.file_path
datastore.write(jobject, transfer_ownership=True)
finally:
jobject.destroy()
del jobject


def generate_thumbnail():
'''
Generates the thumbnail to be displayed
on the screenshot alert popup
'''
window = Gdk.get_default_root_window()
width, height = window.get_width(), window.get_height()
thumb_width, thumb_height = style.zoom(200), style.zoom(160)

thumb_surface = Gdk.Window.create_similar_surface(
window, cairo.CONTENT_COLOR, thumb_width, thumb_height)

cairo_context = cairo.Context(thumb_surface)
thumb_scale_w = thumb_width * 1.0 / width
thumb_scale_h = thumb_height * 1.0 / height
cairo_context.scale(thumb_scale_w, thumb_scale_h)
Gdk.cairo_set_source_window(cairo_context, window, 0, 0)
cairo_context.paint()

link_width, link_height = style.zoom(200), style.zoom(160)
link_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
link_width, link_height)

cairo_context = cairo.Context(link_surface)
dest_x = style.zoom(0)
dest_y = style.zoom(0)
cairo_context.set_source_surface(thumb_surface, dest_x, dest_y)
thumb_width, thumb_height = style.zoom(200), style.zoom(160)
cairo_context.rectangle(dest_x, dest_y, thumb_width, thumb_height)
cairo_context.fill()

bg_width, bg_height = style.zoom(200), style.zoom(160)
pixbuf_bg = Gdk.pixbuf_get_from_surface(link_surface, 0, 0,
bg_width, bg_height)

preview_image = Gtk.Image()
preview_image.set_from_pixbuf(pixbuf_bg)

# Set's the default title
content_title = None
shell_model = shell.get_model()
zoom_level = shell_model.zoom_level

# TRANS: Nouns of what a screenshot contains
if zoom_level == shell_model.ZOOM_MESH:
content_title = _('Mesh')
elif zoom_level == shell_model.ZOOM_GROUP:
content_title = _('Group')
elif zoom_level == shell_model.ZOOM_HOME:
content_title = _('Home')
elif zoom_level == shell_model.ZOOM_ACTIVITY:
activity = shell_model.get_active_activity()
if activity is not None:
content_title = activity.get_title()
if content_title is None:
content_title = _('Activity')

if content_title is None:
title = _('Screenshot')
else:
title = _('Screenshot of \"%s\"') % content_title

return preview_image, title


def take_screenshot():
'''
Captures a screenshot and saves
it to a temp dir.
'''
tmp_dir = os.path.join(env.get_profile_path(), 'data')
fd, file_path = tempfile.mkstemp(dir=tmp_dir)
os.close(fd)

window = Gdk.get_default_root_window()
width, height = window.get_width(), window.get_height()

screenshot_surface = Gdk.Window.create_similar_surface(
window, cairo.CONTENT_COLOR, width, height)

cr = cairo.Context(screenshot_surface)
Gdk.cairo_set_source_window(cr, window, 0, 0)
cr.paint()
screenshot_surface.write_to_png(file_path)

return screenshot_surface, file_path


def _get_preview_data(screenshot_surface):
screenshot_width = screenshot_surface.get_width()
screenshot_height = screenshot_surface.get_height()

preview_width, preview_height = style.zoom(300), style.zoom(225)
preview_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
preview_width, preview_height)
cr = cairo.Context(preview_surface)

scale_w = preview_width * 1.0 / screenshot_width
scale_h = preview_height * 1.0 / screenshot_height
scale = min(scale_w, scale_h)

translate_x = int((preview_width - (screenshot_width * scale)) / 2)
translate_y = int((preview_height - (screenshot_height * scale)) / 2)

cr.translate(translate_x, translate_y)
cr.scale(scale, scale)

cr.set_source_rgba(1, 1, 1, 0)
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.paint()
cr.set_source_surface(screenshot_surface)
cr.paint()

preview_str = StringIO.StringIO()
preview_surface.write_to_png(preview_str)

return dbus.ByteArray(preview_str.getvalue())
Loading

0 comments on commit 02636de

Please sign in to comment.