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