42
42
from drawers.PreferencesDrawersDialog import PreferencesDrawersDialog
44
44
(TARGET_ENTRY_TEXT, TARGET_ENTRY_PIXBUF) = range(2)
45
(COLUMN_TEXT, COLUMN_PIXBUF) = range(2)
45
(COLUMN_TEXT, COLUMN_PIXBUF, COLUMN_DISPNAME) = range(3)
46
46
iconpath="/opt/extras.ubuntu.com/drawers/share/drawers/media/"
47
47
settings = Gio.Settings("net.launchpad.drawers")
48
48
NUM_OPEN = settings.get_int("number-open") + 1
49
49
settings.set_int("number-open", NUM_OPEN)
50
50
REMINDER_NUM = settings.get_int("reminder-num")
52
BAD_CHARS=[';','[',']']
52
55
DONATE_URL = 'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=GRXNFZQH5N7JS&lc=US&item_name=Drawers%20Development¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted'.replace('&','&')
53
56
def updateconfig(firstrun=None):
78
83
QUICKLIST_MAX = settings.get_int("quicklist-max")
79
84
DEADREMOVE=settings.get_boolean("dead-remove")
80
85
DEADCONFIRM=settings.get_boolean("dead-confirm")
86
TEXT_ELLIPS=settings.get_int("text-ellips")
87
LIMIT_TEXT=settings.get_boolean("limit-text")
81
88
if firstrun != None:
82
89
settings.set_boolean("first-run", firstrun)
92
99
dbg(debug, "Couldn't get icon_size from compizconfig")
93
100
dbg(debug, repr(e))
98
#conf='/home/'+getpass.getuser()+'/.gconf/apps/compiz-1/plugins/unityshell/screen0/options/%gconf.xml'
99
#with open(conf,'r') as f:
100
#for line in f.readlines():
101
#if 'icon_size' in line:
102
#ind=line.find('value="')
103
#size=line[ind:].split('"')[1]
104
#dbg(debug, "gconf line: "+line)
105
#dbg(debug, "iconsize: "+size)
107
#except Exception as e:
108
#dbg(debug,"Problem reading gconf file: ")
111
#dbg(debug,"Line not found")
112
#Using gconf caused conflict with gsettings/gio module therefore wrote
113
#a function to parse the needed line in gconf xml file
116
104
#Preferences for altering appearance - To be moved to config file
155
143
Gtk.Window.__init__(self)
157
145
dbg(self.debug, "Debugging messages on")
154
#determine which monitor on multimonitor displays
158
155
screen=self.get_screen()
159
#determine which monitor on multimonitor displays
160
156
num_mons = Gdk.Screen.get_n_monitors(screen)
157
dbg(self.debug, "Detected %i monitors" %num_mons)
166
#(w,h)=(Gdk.Screen.get_width(screen),Gdk.Screen.get_height(screen))
168
161
#get position of mouse; assuming mouse doesn't move off monitor when launcher clicked
169
162
display=Gdk.Display.get_default()
170
163
(scr,x,y,modifier)=display.get_pointer()
171
164
activemon=Gdk.Screen.get_monitor_at_point(screen,x,y)
172
#rect=Gdk.Rectangle()
173
166
rect=Gdk.Screen.get_monitor_geometry(screen,activemon)
174
167
self.offset_x = rect.x
175
168
self.offset_y = rect.y
176
#print self.offset_x, self.offset_y
177
170
self.set_visual(screen.get_rgba_visual())
182
#Determine position of launcher --> How will this work with non-Launcher Panel items!?
183
#write functions to get these values from system!
172
#Some settings for Unity Launcher and panel bar
184
173
LF_ICONPADDING=10
187
#Get position (top to bottom) of the opened drawer
176
#Get position (top to bottom) of the opened drawer in Launcher
190
179
self.lf=Unity.LauncherFavorites.get_default().enumerate_ids()
191
180
self.lfpos=self.lf.index(filename.split('/')[-1])+2
192
181
LF_ICONSIZE=get_icon_size(self.debug)
193
182
except Exception as inst:
194
dbg(self.debug, type(inst), inst.args)
183
dbg(self.debug, "%s\n%s"%(repr(inst), inst.args))
203
192
self.anchorpos=(self.lfpos * (LF_ICONSIZE+LF_ICONPADDING))+PANEL_HEIGHT
194
#Start setting up the drawer with the .desktop file
205
195
if filename != None:
206
196
self.filename=filename
208
198
self.df=DesktopEntry(filename) # will parse the .desktop file
209
199
if self.df.hasKey('Actions'):
210
200
self.actions=self.df.get('Actions', 'Desktop Entry').split(';')
211
#function to remove duplicates
212
#self.actions=list(set(self.actions)) #screws up order
213
#self.actions=filter(lambda e: e not in self.actions, self.actions)
201
#function to remove duplicates just in case
214
202
for action in self.actions:
215
203
if self.actions.count(action)>1: self.actions.remove(action)
216
204
if DEADREMOVE: self.deadlinkcheck()
220
208
except Exception as e:
221
209
dbg (self.debug,"Couldn't read desktop file")
222
210
dbg (self.debug,repr(e))
212
#Add any items passed to program if it's not in actions already
225
213
for item in addfile:
226
214
if item !=None and item.rstrip('/').split('/')[-1] not in self.actions:
227
215
self.add_file(item)
228
216
self.builddrawer()
231
self.set_decorated(False)
232
self.set_app_paintable(True)
233
220
self.connect("delete-event", Gtk.main_quit)
234
221
self.connect("key-press-event", self.handle_keypresses)
235
222
self.connect("key-release-event", self.handle_keyrelease)
236
223
self.connect("enter-notify-event", self.on_mouse_enter)
237
225
#Set up dragNdrop to add URIs to open draw
238
#self.connect("drag-motion", self.motion_cb)
239
226
self.connect("drag-drop", self.drop_cb)
240
227
self.connect("drag-data-received", self.got_data_cb)
241
228
self.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
242
229
self.drag_dest_set_target_list(None)
243
230
self.drag_dest_add_uri_targets()
244
#self.drag_dest_add_text_targets()
245
#Format the drawer - not ideal would like to implement more unity
246
#like style that changes with theme
234
self.set_decorated(False)
235
self.set_app_paintable(True)
248
236
css = Gtk.CssProvider()
249
238
#Want the drawer background and font to change with average of desktop background
250
239
self.BG_rgb= [int(i*COLOR_SCALING) for i in self.get_color() ]
251
240
if sum(self.BG_rgb)/3 > 175:
265
254
self.title.get_style_context().add_class('title')
266
255
self.toolbarL.get_style_context().add_class('title')
267
256
self.toolbarR.get_style_context().add_class('title')
268
# self.get_style_context().add_class('background2')
258
#Draw the window with cairo
269
259
self.connect("draw", self.draw_window_cb)
264
#Put the keyboard focus in the iconview
271
265
self.iconview.grab_focus()
267
#Don't draw anything until we've moved to the right spot
272
268
gdkwindow=self.get_window()
274
269
if gdkwindow: gdkwindow.freeze_updates()
275
271
self.set_gravity(Gdk.Gravity.WEST)
276
self.move(MARGIN+self.offset_x, self.anchorpos+self.offset_y)#Gdk.Screen.height()/2)
272
self.x, self.y=(MARGIN+self.offset_x, self.anchorpos+self.offset_y)
273
self.move(self.x,self.y)
277
274
if gdkwindow: gdkwindow.thaw_updates()
278
275
self.queue_draw()
280
278
self.on_help_activate(None)
281
279
updateconfig(False)
415
410
def place_items(self):
416
411
"""Clears the iconview model and iterates through a DesktopEntry to repopulate"""
417
self.model = Gtk.ListStore(str, GdkPixbuf.Pixbuf)
412
self.model = Gtk.ListStore(str, GdkPixbuf.Pixbuf, str)
419
414
if self.df.hasKey('Actions'):
420
415
for action in self.actions:
436
431
self.actions.remove(action)
438
433
#iconview must be reformatted to get correct size_request()
439
self.iconview.set_text_column(COLUMN_TEXT)
434
self.iconview.set_text_column(COLUMN_DISPNAME)
440
435
self.iconview.set_pixbuf_column(COLUMN_PIXBUF)
441
436
self.iconview.set_columns(MAXICONS_ROW)
442
437
self.iconview.set_column_spacing(COLUMN_SPACING)
494
489
pixbuf = Gtk.IconTheme.get_default().load_icon(icon_name, ICONSIZE, 0)
496
self.model.append([text, pixbuf])
491
if LIMIT_TEXT and len(text)>TEXT_ELLIPS:
496
dispname=(text[:TEXT_ELLIPS]+ellips)
499
self.model.append([text, pixbuf, dispname])
509
512
def execute(self, value):
510
513
"""Executes the Exec line of a Desktop Action group"""
511
group='Desktop Action '+value
514
group='Desktop Action '+self.cleanname(value)
512
515
execline=self.df.get("Exec",group)
513
516
args=shlex.split(execline)
514
517
subprocess.Popen(args)
561
564
self.df.addGroup(group)
562
565
for key in groupentry:
563
566
self.df.set(key,groupentry[key],group)
564
self.actions.append(name)
567
self.actions.append(name.replace(';','').replace('[','').replace(']',''))
565
568
self.df.set('Actions', ';'.join(self.actions),'Desktop Entry')
566
569
dbg(self.debug, " Actions: %s"%';'.join(self.actions))
569
572
def delete_selected(self,selection):
570
573
"""Takes an action name and removes it from the .desktop file
571
574
and redraws the iconview"""
572
self.df.removeGroup('Desktop Action ' + selection)
573
self.actions.remove(selection)
575
self.df.removeGroup('Desktop Action ' + self.cleanname(selection))
576
self.actions.remove(self.cleanname(selection))
574
577
if self.actions !=[]:
575
578
self.df.set('Actions', ';'.join(self.actions),'Desktop Entry')
776
782
def on_editname_activate(self, widget, data=None):
777
newname=self.getText(_('Please enter a new name'))
783
selected_name=self.model[self.iconview.get_selected_items()[0]][0]
784
newname=self.getText(_('Please enter a new name'), Entry=selected_name)
778
785
if newname != None:
779
selected_name=self.model[self.iconview.get_selected_items()[0]][0]
780
786
# need to copy keys and create new group with new action link
787
selected_name=self.cleanname(selected_name)
782
789
for key in ['Type','Icon','Exec','OnlyShowIn']:
784
790
groupcopy[key]=self.df.get(key,'Desktop Action '+selected_name)
785
791
groupcopy['Name']=newname
786
self.df.addGroup('Desktop Action '+newname)
792
newname=self.cleanname(newname)
793
#only copy to new group if cleaned up name changes
794
if selected_name != newname:
795
self.df.addGroup('Desktop Action '+newname)
796
dbg(self.debug, "copying group %s to %s"%(selected_name, newname))
797
self.df.removeGroup('Desktop Action '+selected_name)
798
#replace action in list without changing order
799
index=self.actions.index(selected_name)
800
self.actions[index]=newname
801
self.df.set('Actions',';'.join(self.actions),'Desktop Entry')
802
#copy keys even if some are the same because name has changed
787
803
for key in groupcopy:
788
804
self.df.set(key, groupcopy[key], 'Desktop Action '+newname)
789
self.df.removeGroup('Desktop Action '+selected_name)
790
self.actions.remove(selected_name)
791
self.actions.append(newname)
792
self.df.set('Actions',';'.join(self.actions),'Desktop Entry')
794
806
self.place_items()
796
808
def on_editexec_activate(self,widget,data=None):
797
selected_name=self.model[self.iconview.get_selected_items()[0]][0]
809
selected_name=self.cleanname(self.model[self.iconview.get_selected_items()[0]][0])
798
810
selected_exec=self.df.get('Exec','Desktop Action ' + selected_name)
811
dbg(self.debug, "changing exec line from %s"%(selected_exec))
799
812
newexec=self.getText('Please edit execution line',label='Exec',Entry=selected_exec)
800
813
if (newexec != selected_exec) and (newexec != None):
814
dbg(self.debug, " to %s"%(new_exec))
801
815
self.df.set('Exec',newexec,'Desktop Action ' + selected_name)
803
817
self.place_items()
833
847
self.place_items()
834
848
context.finish(True, False, time)
835
849
def window_drag(self, widget, data):
836
self.pos_x, self.pos_y = self.get_position()
838
#print "dragging from: "+str(self.pos_x) +' '+str(self.pos_y)
839
#print data.x, data.y
840
self.move(self.pos_x+int(data.x)-MARGIN,self.pos_y+int(data.y)+self.anchorpos/2)
850
dbg(self.debug, "Starting at: %i, %i"%(self.x,self.y))
851
self.begin_move_drag(1, data.x_root, data.y_root, data.time)
852
self.x, self.y=self.get_position()
843
855
def on_button_clicked(self,widget, data=None):