Merge lp:~henrikno/lookit/trunk into lp:lookit

Proposed by Henrik Nordvik
Status: Needs review
Proposed branch: lp:~henrikno/lookit/trunk
Merge into: lp:lookit
Diff against target: 378 lines (+166/-79)
5 files modified
src/lookit/data/pref.xml (+33/-0)
src/lookit/lookit (+15/-12)
src/lookit/prefdlg.py (+8/-0)
src/lookit/screencapper.py (+94/-65)
src/lookit/uploader.py (+16/-2)
To merge this branch: bzr merge lp:~henrikno/lookit/trunk
Reviewer Review Type Date Requested Status
Zach Tibbitts Pending
Review via email: mp+26013@code.launchpad.net
To post a comment you must log in.
lp:~henrikno/lookit/trunk updated
9. By Henrik Nordvik

Avoid errors when not dragging a selection area.

10. By Henrik Nordvik

Added an option to select directory to save screenshots.

11. By Henrik Nordvik

Using Xlib and grab_pointer to get window/area selection.

Unmerged revisions

11. By Henrik Nordvik

Using Xlib and grab_pointer to get window/area selection.

10. By Henrik Nordvik

Added an option to select directory to save screenshots.

9. By Henrik Nordvik

Avoid errors when not dragging a selection area.

8. By Henrik Nordvik

Added some error checking code.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/lookit/data/pref.xml'
--- src/lookit/data/pref.xml 2010-05-25 23:53:57 +0000
+++ src/lookit/data/pref.xml 2010-05-30 06:56:26 +0000
@@ -52,6 +52,39 @@
52 </packing>52 </packing>
53 </child>53 </child>
54 <child>54 <child>
55 <object class="GtkHBox" id="hbox2">
56 <property name="visible">True</property>
57 <child>
58 <object class="GtkLabel" id="label10">
59 <property name="visible">True</property>
60 <property name="tooltip_text" translatable="yes">Select a directory to save the screenshots to.</property>
61 <property name="label" translatable="yes">Directory:</property>
62 </object>
63 <packing>
64 <property name="expand">False</property>
65 <property name="position">0</property>
66 </packing>
67 </child>
68 <child>
69 <object class="GtkFileChooserButton" id="savedir">
70 <property name="visible">True</property>
71 <property name="action">select-folder</property>
72 <property name="title" translatable="yes">Select A Directory to save Screenshots</property>
73 </object>
74 <packing>
75 <property name="position">1</property>
76 </packing>
77 </child>
78 </object>
79 <packing>
80 <property name="expand">False</property>
81 <property name="position">2</property>
82 </packing>
83 </child>
84 <child>
85 <placeholder/>
86 </child>
87 <child>
55 <placeholder/>88 <placeholder/>
56 </child>89 </child>
57 </object>90 </object>
5891
=== modified file 'src/lookit/lookit'
--- src/lookit/lookit 2010-05-25 23:53:57 +0000
+++ src/lookit/lookit 2010-05-30 06:56:26 +0000
@@ -28,18 +28,18 @@
28import urllib28import urllib
29import urlparse29import urlparse
3030
31try:31#try:
32 # Try to import these from current directory, in case running from src32 # Try to import these from current directory, in case running from src
33 import aboutdlg33import aboutdlg
34 import prefdlg34import prefdlg
35 import screencapper35import screencapper
36 import uploader36import uploader
37except ImportError:37#except ImportError:
38 # Then fall back to globally installed versions38 ## Then fall back to globally installed versions
39 from lookit import aboutdlg39 #from lookit import aboutdlg
40 from lookit import prefdlg40 #from lookit import prefdlg
41 from lookit import screencapper41 #from lookit import screencapper
42 from lookit import uploader42 #from lookit import uploader
4343
44CONF_FILE = os.path.expanduser('~/.config/lookit.conf')44CONF_FILE = os.path.expanduser('~/.config/lookit.conf')
45TRASH_DIR = os.path.expanduser('~/.local/share/Trash/files')45TRASH_DIR = os.path.expanduser('~/.local/share/Trash/files')
@@ -142,7 +142,7 @@
142 if pb != None:142 if pb != None:
143 m = hashlib.md5()143 m = hashlib.md5()
144 m.update(pb.get_pixels())144 m.update(pb.get_pixels())
145 hashstring = m.hexdigest() + '.png'145 hashstring = self.prefs['savedir'] + '/' + m.hexdigest() + '.png'
146 pb.save(hashstring, 'png')146 pb.save(hashstring, 'png')
147 self.upload_image(hashstring)147 self.upload_image(hashstring)
148 else:148 else:
@@ -170,6 +170,9 @@
170 )170 )
171 elif proto == 'Imgur':171 elif proto == 'Imgur':
172 success, data = uploader.upload_file_imgur(image)172 success, data = uploader.upload_file_imgur(image)
173 elif proto == 'None':
174 self.show_notification('Image saved', image)
175 return
173 else:176 else:
174 success = False177 success = False
175 data = "Error: no such protocol: {0}".format(proto)178 data = "Error: no such protocol: {0}".format(proto)
176179
=== modified file 'src/lookit/prefdlg.py'
--- src/lookit/prefdlg.py 2010-05-25 23:53:57 +0000
+++ src/lookit/prefdlg.py 2010-05-30 06:56:26 +0000
@@ -1,4 +1,5 @@
1import gtk1import gtk
2import gio
2import os3import os
3import sys4import sys
45
@@ -29,6 +30,7 @@
29 30
30 self.combobox = builder.get_object("combobox")31 self.combobox = builder.get_object("combobox")
31 connections = gtk.ListStore(str)32 connections = gtk.ListStore(str)
33 connections.append(['None'])
32 for connection in CONNECTION_TYPES:34 for connection in CONNECTION_TYPES:
33 connections.append([connection])35 connections.append([connection])
34 self.combobox.set_model(connections)36 self.combobox.set_model(connections)
@@ -43,6 +45,7 @@
43 self.password = builder.get_object("password")45 self.password = builder.get_object("password")
44 self.directory = builder.get_object("directory")46 self.directory = builder.get_object("directory")
45 self.url = builder.get_object("url") 47 self.url = builder.get_object("url")
48 self.savedir = builder.get_object("savedir")
4649
47 builder.connect_signals(self)50 builder.connect_signals(self)
4851
@@ -61,6 +64,7 @@
61 self.password.set_text(prefs['password'])64 self.password.set_text(prefs['password'])
62 self.directory.set_text(prefs['directory'])65 self.directory.set_text(prefs['directory'])
63 self.url.set_text(prefs['url'])66 self.url.set_text(prefs['url'])
67 self.savedir.set_current_folder_file(gio.File(prefs['savedir']))
64 except KeyError:68 except KeyError:
65 if 'Imgur' in CONNECTION_TYPES:69 if 'Imgur' in CONNECTION_TYPES:
66 self.combobox.set_active(70 self.combobox.set_active(
@@ -90,10 +94,13 @@
90 self.port.get_adjustment().set_value(21)94 self.port.get_adjustment().set_value(21)
91 elif proto == 'SSH':95 elif proto == 'SSH':
92 self.port.get_adjustment().set_value(22)96 self.port.get_adjustment().set_value(22)
97 else:
98 self.port.get_adjustment().set_value(21)
93 99
94 100
95101
96 def on_pref_dialog_response(self, widget, data=None):102 def on_pref_dialog_response(self, widget, data=None):
103 print "on_pref_dialog_response"
97 if data == 1:104 if data == 1:
98 self.prefs['trash'] = self.trash.get_active()105 self.prefs['trash'] = self.trash.get_active()
99 self.prefs['shortenurl'] = self.shortenurl.get_active()106 self.prefs['shortenurl'] = self.shortenurl.get_active()
@@ -104,6 +111,7 @@
104 self.prefs['password'] = self.password.get_text()111 self.prefs['password'] = self.password.get_text()
105 self.prefs['directory'] = self.directory.get_text()112 self.prefs['directory'] = self.directory.get_text()
106 self.prefs['url'] = self.url.get_text()113 self.prefs['url'] = self.url.get_text()
114 self.prefs['savedir'] = self.savedir.get_current_folder_file().get_path()
107 else:115 else:
108 self.prefs = dict()116 self.prefs = dict()
109 self.dialog.destroy()117 self.dialog.destroy()
110118
=== modified file 'src/lookit/screencapper.py'
--- src/lookit/screencapper.py 2010-05-25 01:21:09 +0000
+++ src/lookit/screencapper.py 2010-05-30 06:56:26 +0000
@@ -1,50 +1,18 @@
1import gtk1import gtk
2import gtk.gdk2import gtk.gdk
33
4from Xlib.display import Display
5from Xlib import X
6from Xlib import XK
7from Xlib import Xcursorfont
8import Xlib
9
4class ScreenCapper:10class ScreenCapper:
5 def __init__(self):11 def __init__(self):
12 self.pixbuf = None
6 self.root = gtk.gdk.get_default_root_window()13 self.root = gtk.gdk.get_default_root_window()
7 self.size = self.root.get_size()14 self.size = self.root.get_size()
815
9 def on_key_press(self, widget, event):
10 if event.keyval == gtk.keysyms.Escape:
11 self.pixbuf = None
12 self.overlay.destroy()
13 gtk.main_quit()
14
15 def on_mouse_up(self, widget, event):
16 self.x2 = int(event.x)
17 self.y2 = int(event.y)
18
19 sz_x = abs(self.x1 - self.x2)
20 sz_y = abs(self.y1 - self.y2)
21
22 print sz_x, sz_y, self.x1, self.x2, self.y1, self.y2
23
24 if sz_x == 0 and sz_y == 0:
25 # TODO: We should capture the window that was clicked
26 self.pixbuf = None
27 self.overlay.destroy()
28 gtk.main_quit()
29
30 self.pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,
31 False, 8, sz_x, sz_y)
32 self.pixbuf.get_from_drawable(self.root,
33 self.root.get_colormap(),
34 min(self.x1, self.x2),
35 min(self.y1, self.y2),
36 0, 0, sz_x, sz_y)
37
38 self.overlay.destroy()
39 gtk.main_quit()
40
41 def on_mouse_down(self, widget, event):
42 self.x1 = int(event.x)
43 self.y1 = int(event.y)
44
45 def realize_area(self, widget):
46 self.overlay.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.CROSS))
47
48 def capture_screen(self):16 def capture_screen(self):
49 self.pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8,17 self.pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8,
50 self.size[0], self.size[1])18 self.size[0], self.size[1])
@@ -54,31 +22,92 @@
54 self.size[0], self.size[1])22 self.size[0], self.size[1])
55 return self.pixbuf23 return self.pixbuf
56 24
25 def grab_area(self, start_x, start_y, width, height):
26 self.pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8,
27 width, height)
28 self.pixbuf.get_from_drawable(self.root, self.root.get_colormap(),
29 start_x, start_y, 0, 0, width, height)
30
57 def capture_area(self):31 def capture_area(self):
58 self.has_result = False32 try:
59 33 display = Display()
60 self.overlay = gtk.Window()34 root = display.screen().root
61 35 cursor_font = display.open_font('cursor')
62 self.overlay.connect("key_press_event", self.on_key_press)36 mycursor = cursor_font.create_glyph_cursor(cursor_font,
63 self.overlay.connect("button_press_event", self.on_mouse_down)37 Xcursorfont.crosshair,
64 self.overlay.connect("button_release_event", self.on_mouse_up)38 Xcursorfont.crosshair+1, (0,0,0),
65 self.overlay.connect("realize", self.realize_area)39 (0xFFFF, 0xFFFF, 0xFFFF))
6640 root.grab_pointer(True, X.ButtonPressMask | X.ButtonReleaseMask |
67 self.overlay.set_events(gtk.gdk.BUTTON_PRESS_MASK |41 X.PointerMotionMask, X.GrabModeAsync, X.GrabModeAsync, 0,
68 gtk.gdk.BUTTON_RELEASE_MASK |42 mycursor, X.CurrentTime)
69 gtk.gdk.KEY_PRESS_MASK)43 root.grab_keyboard(True, X.GrabModeAsync, X.GrabModeAsync,
7044 X.CurrentTime)
71 warning = gtk.Label('Warning: You must be using a window ' +45 colormap = display.screen().default_colormap
72 'manager that supports compositing. Press Esc to ' +46
73 'exit.')47 # (r,g,b) blue = (0,0,65535)
74 warning.show()48 color = colormap.alloc_color(0, 0, 65535)
75 self.overlay.add(warning)49 # Xor it because we'll draw with X.GXxor function
7650 xor_color = color.pixel ^ 0xffffff
77 self.overlay.set_opacity(0)51
78 self.overlay.fullscreen()52 print hex(color.pixel), hex(xor_color)
79 53
80 self.overlay.show()54 self.gc = root.create_gc(
8155 line_width = 1,
82 gtk.main()56 line_style = X.LineSolid,
8357 fill_style = X.FillSolid,
58 fill_rule = X.WindingRule,
59 cap_style = X.CapButt,
60 join_style = X.JoinMiter,
61 foreground = xor_color,
62 background = display.screen().black_pixel,
63 function = X.GXxor,
64 graphics_exposures = False,
65 subwindow_mode = X.IncludeInferiors,
66 )
67
68 pressed = False
69 done = False
70 lastx, lasty = None, None
71 while not done:
72 event = display.next_event()
73 if event.type == X.DestroyNotify:
74 self.pixbuf = None
75 done = True
76 if event.type == X.KeyPress:
77 self.pixbuf = None
78 done = True
79 if event.type == X.MotionNotify:
80 if pressed:
81 if lastx and lasty:
82 ax = abs(startx - lastx)
83 ay = abs(starty - lasty)
84 root.rectangle(self.gc, min(startx, lastx), min(starty, lasty), ax, ay)
85 lastx, lasty = event.root_x, event.root_y
86 ax = abs(startx - event.root_x)
87 ay = abs(starty - event.root_y)
88 root.rectangle(self.gc, min(startx, event.root_x), min(starty, event.root_y), ax, ay)
89
90 elif event.type == X.ButtonPress and event.child != X.NONE:
91 startx, starty = event.event_x, event.event_y
92 pressed = True
93
94 elif event.type == X.ButtonRelease and event.child != X.NONE:
95 endx, endy = event.event_x, event.event_y
96 geometry = event.child.get_geometry()
97 width, height = geometry.width, geometry.height
98 window_x, window_y = geometry.x, geometry.y
99 diff_x = abs(startx - endx)
100 diff_y = abs(starty - endy)
101
102 if diff_x == 0 and diff_y == 0:
103 self.grab_area(window_x, window_y, width, height)
104 else:
105 self.grab_area(startx, starty, diff_x, diff_y)
106 done = True
107 except:
108 raise
109 finally:
110 display.ungrab_pointer(X.CurrentTime)
111 display.ungrab_keyboard(X.CurrentTime)
112 display.flush()
84 return self.pixbuf113 return self.pixbuf
85114
=== modified file 'src/lookit/uploader.py'
--- src/lookit/uploader.py 2010-05-25 01:21:09 +0000
+++ src/lookit/uploader.py 2010-05-30 06:56:26 +0000
@@ -71,6 +71,10 @@
71 return PROTO_LIST71 return PROTO_LIST
7272
73def upload_file_ftp(f, hostname, port, username, password, directory, url):73def upload_file_ftp(f, hostname, port, username, password, directory, url):
74 if not 'FTP' in PROTO_LIST:
75 errormsg = 'Error: FTP support not installed. Install \'ftplib\' package.'
76 print errormsg
77 return False, errormsg
74 i = open(f, 'r')78 i = open(f, 'r')
7579
76 try:80 try:
@@ -88,6 +92,10 @@
88 return True, None92 return True, None
8993
90def upload_file_sftp(f, hostname, port, username, password, directory, url):94def upload_file_sftp(f, hostname, port, username, password, directory, url):
95 if not 'SSH' in PROTO_LIST:
96 errormsg = 'Error: SSH support not installed. Install \'paramiko\' package.'
97 print errormsg
98 return False, errormsg
91 t = paramiko.Transport((hostname, port))99 t = paramiko.Transport((hostname, port))
92 t.connect(username=username, password=password)100 t.connect(username=username, password=password)
93 sftp = paramiko.SFTPClient.from_transport(t)101 sftp = paramiko.SFTPClient.from_transport(t)
@@ -102,10 +110,16 @@
102110
103def upload_file_imgur(f):111def upload_file_imgur(f):
104 if not 'Imgur' in PROTO_LIST:112 if not 'Imgur' in PROTO_LIST:
105 print 'Error: Imgur not supported'113 errormsg = 'Error: Imgur support not installed. Install \'pycurl\' package.'
114 print errormsg
115 return False, errormsg
106 i = ImgurUploader()116 i = ImgurUploader()
107 i.upload(f)117 i.upload(f)
108 return True, i.mapping118 print i.mapping
119 if not 'error_msg' in i.mapping:
120 return True, i.mapping
121 else:
122 return False, i.mapping.get('error_msg')
109123
110def upload_file_ubuntuone(f):124def upload_file_ubuntuone(f):
111 pass125 pass

Subscribers

People subscribed via source and target branches