/
awn_class.py
1755 lines (1514 loc) · 66.1 KB
/
awn_class.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#
# Copyright (C) 2007 Neil Jagdish Patel <njpatel@gmail.com>
#
# 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 2 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, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Author: Neil Jagdish Patel <njpatel@gmail.com>
# Edited By: Ryan Rushton <ryan@rrdesign.ca>
#
# Notes: Avant Window Navigator preferences window
import sys
import os
import socket
import time
import urllib
import cairo
import array
from ConfigParser import ConfigParser
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
try:
import gobject
import gtk
import gtk.gdk as gdk
import pango
except Exception, e:
sys.stderr.write(str(e) + '\n')
sys.exit(1)
from xdg.DesktopEntry import DesktopEntry
import awn
import awn_defs as defs
from desktopagnostic import config
from desktopagnostic import vfs
from desktopagnostic.config import GROUP_DEFAULT
from desktopagnostic.ui import LauncherEditorDialog
import tarfile
import shutil
import tempfile
import dbus
try:
from bzrlib import branch
from bzrlib.builtins import cmd_branch, cmd_pull
from bzrlib.plugins.launchpad.lp_directory import LaunchpadDirectory
support_bzr = True
except:
support_bzr = False
defs.i18nize(globals())
class AwnListStore(gtk.ListStore, gtk.TreeDragSource, gtk.TreeDragDest):
__gsignals__ = {
# we can't do TreePath easily, so lets use just int
# (change to string representation of TreePath if necessary)
'foreign-drop':
(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
[int, gtk.SelectionData.__gtype__])
}
def do_drag_data_received(self, dest, selection_data):
model, row = None, None
if selection_data.target == 'GTK_TREE_MODEL_ROW':
model, row = selection_data.tree_get_row_drag_data()
if model == self:
# drop from the same widget, handle reorder ourselves
src = row[0]
dst = dest[0]
if (src == dst):
return False
new_array = []
iter = self.get_iter_root()
while iter != None:
iter = self.iter_next(iter)
new_array.append(len(new_array))
# new_array[oldpos] = newpos
if src < dst:
new_array[src] = dst-1
for i in range(src+1, dst):
new_array[i] = i-1
else:
new_array[src] = dst
for i in range(dst, src):
new_array[i] = i+1
# need to map it to > new_order[newpos] = oldpos
new_order = new_array[:]
for i in range(len(new_array)): new_order[new_array[i]] = i
# emit change signals
self.reorder(new_order)
else:
self.emit("foreign-drop", dest[0], selection_data)
return False
def do_row_drop_possible(self, dest_path, selection_data):
return True
def do_drag_data_delete(self, path):
return True
def do_drag_data_get(self, path, selection_data):
# if we return False the default handler will do exactly what we want
return False
gobject.type_register (AwnListStore)
class awnBzr(gobject.GObject):
#Utils Bzr
def lp_path_normalize(self, path):
''' Get a "lp:" format url and return a http url
path: a url from a branch
return: the http format of a lp: format, or the same url
'''
if support_bzr == True:
directory = LaunchpadDirectory()
return directory._resolve(path).replace("bzr+ssh","http")
else:
return path
def read_list(self, file_path):
''' Read a flat file and return the content in a list
file_path : path of the file
return: a list of the elements of the file
'''
flat_list = []
f = open(file_path, 'r')
for line in f:
flat_list.append(line.strip())
f.close()
return flat_list
#Bzr
def create_branch(self, bzr_dir, path):
''' Create a new bzr branch.
path: the path of the branch
bzr_dir: the location of the futur tree.
'''
if support_bzr == False:
print (_("Bzr support is not enable, try to install bzr"))
else:
if os.path.exists(path):
print (_("Error, the path already exist"))
else:
try:
bzr_branch = cmd_branch()
status = StringIO()
status = bzr_branch._setup_outf()
bzr_branch.run(from_location=self.lp_path_normalize(bzr_dir), to_location=path)
except socket.gaierror:
print (_('Socket error, could not create branch.'))
def update_branch(self, path):
''' Update a local branch
path: Location of the branch
Return the output of the command
'''
if support_bzr == False:
print (_("Bzr support is not enable, try to install bzr"))
else:
bzr_pull = cmd_pull()
status = StringIO()
status = bzr_pull._setup_outf()
bzr_pull.run(directory=path)
def get_revision_from_path(self, path):
''' Return the last revision number of the branch
specify with path parameter
'''
if support_bzr == False:
print (_("Bzr support is not enable, try to install bzr"))
return 0
else:
tree = branch.Branch.open(path)
revision_number, revision_id = tree.last_revision_info()
return revision_number
#Sources.list
def dict_from_sources_list(self, config=defs.HOME_CONFIG_DIR):
'''
Return a dictionnay of the sources.list
config: the directory to read sources.list.
'''
sources_dict = {}
sources_list_path = os.path.join(config, "sources.list")
f = open(sources_list_path)
sources_list = f.readlines()
sources_list = [elem.replace("\n","") for elem in sources_list]
sources_list= [elem.split(" ") for elem in sources_list]
for i in sources_list:
sources_dict[i[0]] = i[1]
f.close()
return sources_dict
def list_from_sources_list(self, config=defs.HOME_CONFIG_DIR):
'''
Return a list for the sources.list.
Each element of the list is another list of 2 elements ['sources','directory']
config: the directory to read sources.list.
'''
sources_list = []
sources_list_path = os.path.join(config, "sources.list")
f = open(sources_list_path)
sources_list = f.readlines()
sources_list = [elem.replace("\n","") for elem in sources_list]
sources_list= [elem.split(" ") for elem in sources_list]
f.close()
return sources_list
def sources_from_sources_list(self, config=defs.HOME_CONFIG_DIR):
'''
Return a list of all sources (without the directory)
config: the directory to read sources.list.
'''
list_sources = []
list_sources_list = self.list_from_sources_list(config)
[list_sources.append(elem[0]) for elem in list_sources_list]
return list_sources
def create_sources_list(self, config = defs.HOME_CONFIG_DIR, default = defs.DEFAULT_SOURCES_LIST):
''' Create a sources_list with all the sources (bzr branch or local files)
Should be unique for an installation
config: the directory to write sources.list.
default: the default content of the sources.list
'''
sources_list_path = os.path.join(config,"sources.list")
if not os.path.isfile(sources_list_path):
self.write_default_sources_list(sources_list_path)
else: print (_("Error, a sources.list already exist"))
def write_default_sources_list(self, sources_list_path, config = defs.HOME_CONFIG_DIR, default = defs.DEFAULT_SOURCES_LIST):
''' Write default sources in the sources list
If a sources.list exist, it will write default sources at the
end of the file
'''
if os.path.isfile(sources_list_path):
f = open(sources_list_path, 'a')
else:
f = open(sources_list_path, 'w')
[f.write(i[0] + " " + i[1] + "\n")
for i
in default if i[0] <> '']
f.close()
def update_sources_list(self, directories = defs.HOME_THEME_DIR, progressbar = None):
'''
Update all sources of the sources list
If the directory doesn't exist, a new branch will be create
directories = default locations of the local branches to update
progress = A widget of a progress bar to update.
'''
if progressbar is not None:
progressbar.pulse()
progressbar.show()
sources_list = self.list_from_sources_list()
sources_to_update = []
[ sources_to_update.append(elem)
for elem in sources_list
if not elem[0].startswith("/") or not elem[1] == "local" ]
total = len(sources_to_update)
counter = 0
for elem in sources_to_update:
if not os.path.isdir(os.path.join(directories , elem[1])):
print self.create_branch(elem[0], os.path.join(directories , elem[1]))
else:
print self.update_branch(os.path.join(directories , elem[1]))
counter = counter+1
if progressbar is not None:
progressbar.set_fraction(int(counter) / int(total))
def add_source(self, path, source_type="web", config = defs.HOME_CONFIG_DIR, directories = defs.HOME_THEME_DIR):
''' Add a source to the sources list.
path: path to the branch
source_type: type of source web or local
config: the directory to write sources.list.
directories = the directory to write sources
'''
if not self.sources_check_sanity(path):
if source_type == "local":
path = path +" "+"local"+"\n"
elif source_type == "web":
number = len(os.listdir(directories))
path = path +" "+"web-sources-"+str(number)+"\n"
source = os.path.join(config,"sources.list")
f = open(source, 'a')
f.write(path)
f.close()
else:
print (_("Error, the path is empty or already exist"))
def remove_source(self, source, config = defs.HOME_CONFIG_DIR):
''' Remove a source from the sources.list
path is the path of the source (url or local path)
'''
list_sources = self.list_from_sources_list(config)
sources_list_path = os.path.join(config,"sources.list")
new_sources_list = []
for elem in list_sources :
if not elem[0] == source:
new_sources_list.append(elem)
print list_sources
print new_sources_list
f = open(sources_list_path, 'w')
[f.write(i[0] + " " + i[1] + "\n")
for i
in new_sources_list if i[0] <> '']
f.close()
def create_branch_config_directory(self, source):
'''
Create the directory of a source in config directory.
source is a dictionnary of 1 entry {'url','directory'}.
source is 1 line of the sources list.
'''
if not source[0].startswith("/") or source[1] == "local":
self.create_branch((source[0], source[1]))
else:
print "Error, this is a local path"
def sources_list_check_double_path(self, path):
''' Check if a path is already in the sources.list
path: location of the source
Return True if the path already in.
'''
sources_list = self.list_from_sources_list()
error = 0
for elem in sources_list:
if elem[0] == path:
error=error+1
if error >= 1:
return True
else:
return False
def sources_check_sanity(self, path):
''' Do some check to be sure the source is ok
path: location of the source
return True if the source is not ok
'''
#Test If the source already in the sources.list
test = self.sources_list_check_double_path(path)
#Test if the source is not null
if path == '':
test = True
#Test if it's not a fantasic path
if not path.startswith("/") or not path.startswith("http://"):
test = True
#TODO Add more tests
#Desktop files
def read_desktop(self, file_path):
''' Read a desktop file and return a dictionnary with all fields
API still unstable
'''
#API of the desktop file (unstable, WIP etc ...)
# keys should be a string of the type
# value could be
# '' if there is nothing,
# a string when there is no settings
# a list when there is a setting : [value of the setting, group settings, key setting]
struct = {
'type': '', # Applet
'location':'', # Location of the desktop file
'name': '', # Name of the Type
'comment':'', # Comments
'version':'', # Version of the
'copyright':'', # Copyright
'author':'', # Author
'licence_code':'', # Licence for the code
'licence_icons':'', # Licence for the icons
'icon':'', # Icon for the type
'exec':'', # Execution path, for applet
'applet_type':'', # Type of teh applet (C, Vala or Python)
'applet_category':'', # Category for the applet
'singleton':'', # True or False, use only one instance.
}
desktop_entry = DesktopEntry(file_path)
struct['type'] = desktop_entry.get('X-AWN-Type')
struct['location'] = file_path
struct['name'] = desktop_entry.get('Name')
#TODO More to add
struct['icon'] = desktop_entry.get('Icon')
struct['exec'] = desktop_entry.get('X-AWN-AppletExec')
struct['applet_type'] = desktop_entry.get('X-AWN-AppletType')
struct['applet_category'] = desktop_entry.get('X-AWN-AppletCategory').rsplit(",")
return struct
def get_files_from_source(self, source, file_type, directories = defs.HOME_THEME_DIR):
''' Read all desktop file from a source
source is a list of 2 entries ('url','directory').
source is 1 line of the sources list.
'''
if source[1] == "local":
path = source[0]
else:
path= str(directories + "/" + source[1])
try:
list_files = os.listdir(path)
files = [path + "/" + elem for elem in list_files if os.path.splitext(elem)[1] ==file_type]
return files
except:
print(_("Error %s is missing on your system, please remove it from the sources.list") % path)
return None
def catalog_from_sources_list(self, file_type='.desktop'):
'''
Return a catalog (list of desktop files from the sources list)
'''
catalog=[]
sources_list = self.list_from_sources_list()
for elem in sources_list:
desktops = self.get_files_from_source(elem, file_type)
if desktops is not None:
[ catalog.append(i) for i in desktops ]
return catalog
def type_catalog_from_sources_list(self, type_catalog='Theme'):
'''
Return a catalog of themes or applets (list of desktop files from the sources list)
type_catalog is the type of catalog (Theme of Applets)
'''
extension = '.awn-theme' if type_catalog == 'Theme' else '.desktop'
catalog = self.catalog_from_sources_list(extension)
final_catalog = []
if type_catalog == 'Theme':
final_catalog = catalog
else:
for elem in catalog:
desktop = DesktopEntry(elem)
if desktop.get('X-AWN-Type') == type_catalog:
final_catalog.append(elem)
else:
if desktop.get('X-AWN-AppletType') and type_catalog =='Applet':
final_catalog.append(elem)
return final_catalog
def load_settings_from_theme(self, path):
''' Load settings from desktop file
'''
parser = ConfigParser()
parser.read(path)
for section in parser.sections():
if section.startswith('config'):
ids = section.split('/')
group, instance_id = None, None
if len(ids) > 2:
group = ids[1]
instance_id = ids[2]
else:
group = ids[1]
client = self.client
if instance_id is not None:
client = awn.config_get_default(int(instance_id))
for key, value in parser.items(section):
try:
if value.isdigit():
value = int(value)
elif len(value.split('.')) == 2:
value = float(value)
elif value.lower() in ['true', 'false']:
value = True if value.lower() == 'true' else False
elif value.startswith('#'):
client.set_string(group, key, value)
continue
client.set_value(group, key, value)
except:
print "Unable to set value %s for %s/%s" % (value, group, key)
def list_applets_categories(self):
''' List all categories of applets
'''
catalog = self.type_catalog_from_sources_list(type_catalog='Applet')
desktop_list = [self.read_desktop(elem) for elem in catalog]
categories_list = []
for applet in desktop_list:
for elem in applet['applet_category']:
if not elem in categories_list and elem is not "":
categories_list.append(elem)
categories_list.append("All")
return categories_list
def applets_by_categories(self, categories = ""):
''' Return applets uris of this categories
categories = list of Categories
'''
catalog = self.type_catalog_from_sources_list(type_catalog='Applet')
desktop_list = [self.read_desktop(elem) for elem in catalog]
if categories is "":
list_applets = catalog
else:
list_applets = [applet['location'] for applet in desktop_list if categories in applet['applet_category']]
return list_applets
#GUI functions
def make_row (self, path):
''' Make a row for a list of applets or launchers
path : path of the desktop file
'''
icon = None
text = ""
name = ""
try:
if not os.path.exists(path):
raise IOError("Desktop file does not exist!")
if os.path.splitext(path)[1] == '.desktop':
item = DesktopEntry (path)
name = item.getName()
text = "<b>%s</b>\n%s" % (name, item.getComment())
icon_name = item.getIcon()
icon = self.make_icon(icon_name)
else:
parser = ConfigParser()
parser.read(path)
name = parser.get('theme-info', 'Name')
text = "<b>%s</b> %s" % (name,
parser.get('theme-info', 'Version'))
if parser.has_option('theme-info', 'Author'):
text += "\n<span style='italic'>by</span> %s" % parser.get('theme-info', 'Author')
#icon = self.make_icon(parser.get('theme-info', 'Icon'))
icon = gdk.pixbuf_new_from_file(parser.get('theme-info', 'Icon'))
except:
pass
return icon, text, name
def make_icon (self, name, icon_size=32):
''' Extract an icon from a desktop file
'''
icon_final = None
theme = gtk.icon_theme_get_default ()
pixmaps_path = [os.path.join(p, "share", "pixmaps") for p in ("/usr", "/usr/local", defs.PREFIX)]
applets_path = [os.path.join(p, "share", "avant-window-navigator","applets") for p in ("/usr", "/usr/local", defs.PREFIX)]
list_icons = (
('theme icon', self.search_icon(
name, type_icon="theme", size=icon_size)
),
('stock_icon', self.search_icon(
name, type_icon="stock", size=icon_size)
),
('file_icon', self.search_icon(
name, size=icon_size)
),
('pixmap_png_icon', self.search_icon(
name, pixmaps_path, extension=".png", size=icon_size)
),
('pixmap_icon', self.search_icon(
name, pixmaps_path, size=icon_size)
),
('applets_png_icon', self.search_icon(
name, applets_path, extension=".png", size=icon_size)
),
('applets_svg_icon', self.search_icon(
name, applets_path, extension=".svg", size=icon_size)
)
)
for i in list_icons:
if i[1] is not None:
icon_final = i[1]
break
if icon_final is not None:
return icon_final
else:
return theme.load_icon('gtk-execute', icon_size, 0)
def search_icon (self, name, path="", extension="",
type_icon="pixmap", size=32):
''' Search a icon'''
theme = gtk.icon_theme_get_default ()
icon = None
if type_icon is "theme":
try:
icon = theme.load_icon (name, size, 0)
except:
icon = None
elif type_icon is "stock":
try:
image = gtk.image_new_from_stock(name, size)
icon = image.get_pixbuf()
except:
icon = None
elif type_icon is "pixmap":
for i in path:
if os.path.exists(os.path.join(i,name+extension)):
try:
icon = gdk.pixbuf_new_from_file_at_size(os.path.join(i,name+extension), size, size)
except:
icon = None
return icon
def add_uris_to_model(self, model, uris):
for uri in uris:
if os.path.isfile(uri):
icon, text, name = self.make_row (uri)
if len(text) > 2:
row = model.append ()
model.set_value (row, 0, icon)
model.set_value (row, 1, text)
model.set_value (row, 2, uri)
model.set_value (row, 3, name)
def make_applet_model(self, uris, treeview):
self.applet_model = model = AwnListStore(gdk.Pixbuf, str, str, str)
treeview.set_model (model)
def deactivate_applet(applet_model, dest, selection_data):
model, src = selection_data.tree_get_row_drag_data()
itr = model.get_iter(src)
model.remove(itr)
self.apply_applet_list_changes()
infobar = self.wTree.get_object("tm_infobar")
if self.check_for_task_manager():
infobar.get_parent().hide_all()
else:
infobar.get_parent().show_all()
self.applet_model.connect("foreign-drop", deactivate_applet)
ren = gtk.CellRendererPixbuf()
col = gtk.TreeViewColumn ("Pixbuf", ren, pixbuf=0)
col.set_expand (False)
treeview.append_column (col)
ren = gtk.CellRendererText()
ren.props.ellipsize = pango.ELLIPSIZE_END
col = gtk.TreeViewColumn ("Description", ren, markup=1)
col.set_expand (True)
treeview.append_column (col)
ren = gtk.CellRendererText()
col = gtk.TreeViewColumn ("Desktop", ren)
col.set_visible (False)
treeview.append_column (col)
ren = gtk.CellRendererText()
col = gtk.TreeViewColumn ("Name", ren)
col.set_visible (False)
treeview.append_column (col)
# Plus icon
#ren = gtk.CellRendererPixbuf()
#ren.props.icon_name = "gtk-add"
#ren.props.stock_size = gtk.ICON_SIZE_DND
#col = gtk.TreeViewColumn ("AddIcon", ren)
#col.set_expand (False)
#treeview.append_column (col)
self.add_uris_to_model(model, uris)
treeview.show()
return model
def make_launchers_model(self, uris, treeview):
model = AwnListStore(gdk.Pixbuf, str, str, str)
treeview.set_model (model)
def add_launcher(model, dest, selection):
data = urllib.unquote(selection.data)
data = data.replace("file://", "").replace("\r\n", "")
if data.endswith('.desktop'):
paths = self.client_taskman.get_list(GROUP_DEFAULT, defs.LAUNCHERS_LIST)
paths.append(data)
self.client_taskman.set_list(GROUP_DEFAULT, defs.LAUNCHERS_LIST, paths)
else:
print "This widget accepts only desktop files!"
model.connect('foreign-drop', add_launcher)
ren = gtk.CellRendererPixbuf()
col = gtk.TreeViewColumn ("Pixbuf", ren, pixbuf=0)
treeview.append_column (col)
ren = gtk.CellRendererText()
col = gtk.TreeViewColumn ("Description", ren, markup=1)
col.set_expand (True)
treeview.append_column (col)
ren = gtk.CellRendererText()
ren.props.visible = False
col = gtk.TreeViewColumn ("Desktop", ren)
treeview.append_column (col)
ren = gtk.CellRendererText()
ren.props.visible = False
col = gtk.TreeViewColumn ("Name", ren)
treeview.append_column (col)
self.add_uris_to_model(model, uris)
treeview.show()
return model
def make_model(self, uris, treeview):
model = gtk.ListStore(gdk.Pixbuf, str, str, str)
treeview.set_model (model)
ren = gtk.CellRendererPixbuf()
col = gtk.TreeViewColumn ("Pixbuf", ren, pixbuf=0)
treeview.append_column (col)
ren = gtk.CellRendererText()
col = gtk.TreeViewColumn ("Description", ren, markup=1)
col.set_expand (True)
treeview.append_column (col)
ren = gtk.CellRendererText()
ren.props.visible = False
col = gtk.TreeViewColumn ("Desktop", ren)
treeview.append_column (col)
ren = gtk.CellRendererText()
ren.props.visible = False
col = gtk.TreeViewColumn ("Name", ren)
treeview.append_column (col)
self.add_uris_to_model(model, uris)
treeview.show()
return model
def refresh_tree (self, uris, model):
model.clear()
self.add_uris_to_model(model, uris)
def create_dropdown(self, widget, entries, matrix_settings=False):
''' Create a dropdown.
widget : The widget where create the dropdown
entries : entries to add to the dropdown
matrix_settings : connect to settings (not implemented yet)
'''
model = gtk.ListStore(str)
[model.append([elem]) for elem in entries]
widget.set_model(model)
cell = gtk.CellRendererText()
widget.pack_start(cell)
widget.add_attribute(cell,'text',0)
def check_for_task_manager(self):
applets = self.client.get_list(defs.PANEL, defs.APPLET_LIST)
for applet in applets:
tokens = applet.split("::")
if tokens[0].find('taskmanager.desktop') > 0:
return True
return False
class awnPreferences(awnBzr):
def setup_font(self, group, key, font_btn):
"""sets up font chooser"""
self.load_font(group, key, font_btn)
font_btn.connect("font-set", self.font_changed, (group, key))
self.client.notify_add(group, key, self.reload_font, font_btn)
def load_font(self, group, key, font_btn):
font = self.client.get_string(group, key)
if font == None:
font = "Sans 10"
font_btn.set_font_name(font)
def reload_font(self, group, key, value, font_btn):
self.load_font(group, key, font_btn)
def font_changed(self, font_btn, groupkey):
group, key = groupkey
self.client.set_string(group, key, font_btn.get_font_name())
def load_effect(self, group, key, dropdown):
dropdown.set_active(self.client.get_int(group, key))
def reload_effect(self, group, key, value, dropdown):
self.load_effect(group, key, dropdown)
def setup_custom_effects(self, group, key):
self.effect_drop = []
for drop in ['open', 'close', 'hover', 'launch', 'attention']:
d = self.wTree.get_object('effect_'+drop)
self.effect_drop.append(d)
model = gtk.ListStore(str)
model.append([_("None")])
model.append([_("Simple")])
model.append([_("Classic")])
model.append([_("Fade")])
model.append([_("Spotlight")])
model.append([_("Zoom")])
model.append([_("Squish")])
model.append([_("3D Turn")])
model.append([_("3D Spotlight Turn")])
model.append([_("Glow")])
d.set_model(model)
cell = gtk.CellRendererText()
d.pack_start(cell)
d.add_attribute(cell,'text',0)
self.load_effect_custom(group,key)
self.client.notify_add(group, key, self.reload_effect_custom)
for drop in ['open', 'close', 'hover', 'launch', 'attention']:
d = self.wTree.get_object('effect_'+drop)
d.connect("changed", self.effect_custom_changed, (group, key))
def load_effect_custom(self, group, key):
effect_settings = self.client.get_int(group, key)
effect_dict = {'open': 0xF, 'close': 0xF0, 'hover': 0xF00,
'launch': 0xF000, 'attention': 0xF0000}
for drop in effect_dict.keys():
d = self.wTree.get_object('effect_'+drop)
current_effect = effect_settings & effect_dict[drop]
while current_effect > 15: current_effect >>= 4
if current_effect == 15:
d.set_active(0)
else:
d.set_active(current_effect+1)
def reload_effect_custom(self, group, key, value):
self.load_effect_custom(group, key)
def effect_custom_changed(self, dropdown, groupkey):
group, key = groupkey
if (dropdown.get_active() != self.effects_dd.get_active()):
self.effects_dd.set_active(10) #Custom
new_effects = self.get_custom_effects()
self.client.set_int(group, key, new_effects)
print "Setting effects to:", "0x%0.8X" % new_effects
def get_custom_effects(self):
effects = 0
dropdowns = ['open', 'close', 'hover', 'launch', 'attention']
dropdowns.reverse()
for drop in dropdowns:
d = self.wTree.get_object('effect_'+drop)
if(d.get_active() == 0):
effects = effects << 4 | 15
else:
effects = effects << 4 | int(d.get_active())-1
return effects
def setup_effects(self, group, key, dropdown):
self.effects_dd = dropdown
model = gtk.ListStore(str)
model.append([_("None")])
model.append([_("Simple")])
model.append([_("Classic")])
model.append([_("Fade")])
model.append([_("Spotlight")])
model.append([_("Zoom")])
model.append([_("Squish")])
model.append([_("3D Turn")])
model.append([_("3D Spotlight Turn")])
model.append([_("Glow")])
model.append([_("Custom")]) ##Always last
dropdown.set_model(model)
cell = gtk.CellRendererText()
dropdown.pack_start(cell)
dropdown.add_attribute(cell,'text',0)
self.load_effect(group,key,dropdown)
dropdown.connect("changed", self.effect_changed, (group, key))
self.client.notify_add(group, key, self.reload_effect, dropdown)
def load_effect(self, group, key, dropdown):
effect_settings = self.client.get_int(group, key)
hover_effect = effect_settings & 15 # not really hover
bundle = 0
for i in range(5):
bundle = bundle << 4 | hover_effect
if (bundle == effect_settings):
if (hover_effect == 15):
active = 0
else:
active = hover_effect+1
else:
active = 10 #Custom
self.btn_edit_custom_effects.show()
dropdown.set_active(int(active))
def reload_effect(self, group, key, value, dropdown):
self.load_effect(group, key, dropdown)
def effect_changed(self, dropdown, groupkey):
group, key = groupkey
new_effects = 0
effect = 0
if dropdown.get_active() != 10: # not Custom
if dropdown.get_active() == 0:
effect = 15
else:
effect = dropdown.get_active() - 1
for i in range(5):
new_effects = new_effects << 4 | effect
self.client.set_int(group, key, new_effects)
self.btn_edit_custom_effects.hide()
print "Setting effects to: ", "0x%0.8X" % new_effects
else:
self.btn_edit_custom_effects.show()
response = self.custom_effects_dialog.run()
self.custom_effects_dialog.hide()
def setup_autostart(self, check):
"""sets up checkboxes"""
self.load_autostart(check)
check.connect("toggled", self.autostart_changed)
def load_autostart(self, check):
autostart_file = self.get_autostart_file_path()
check.set_active(os.path.isfile(autostart_file))
def reload_autostart(self, group, key, value, check):
self.load_autostart(group, key, check)
def autostart_changed(self, check):
if check.get_active():
self.create_autostarter()
else:
self.delete_autostarter()
# The following code is adapted from screenlets-manager.py
def get_autostart_file_path(self):
if os.environ.has_key('DESKTOP_SESSION') and os.environ['DESKTOP_SESSION'].startswith('kde'):
autostart_dir = os.path.join(os.environ['HOME'], '.kde', 'Autostart')
else:
autostart_dir = os.path.join(os.environ['HOME'], '.config', 'autostart')
return os.path.join(autostart_dir, 'awn.desktop')
def create_autostarter(self):
'''Create an autostart entry for Awn.'''
def err_dialog():
err_msg = _('Automatic creation failed. Please manually create the directory:\n%s') % autostart_dir
msg = gtk.MessageDialog(parent, type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_OK, message_format=err_msg)
msg.show_all()
msg.run()
msg.destroy()
autostart_file = self.get_autostart_file_path()
autostart_dir = os.path.dirname(autostart_file)
if not os.path.isdir(autostart_dir):
# create autostart directory, if not existent
parent = self.wTree.get_object('awnManagerWindow')
dialog = gtk.Dialog(_('Confirm directory creation'), parent, gtk.DIALOG_MODAL, ((gtk.STOCK_NO, gtk.RESPONSE_NO, gtk.STOCK_YES, gtk.RESPONSE_YES)))
dialog.vbox.add(gtk.Label(_('There is no existing autostart directory for your user account yet.\nDo you want me to automatically create it for you?')))
dialog.show_all()
response = dialog.run()
dialog.destroy()
if response == gtk.RESPONSE_YES:
try:
os.mkdir(autostart_dir)
except Exception, e:
err_dialog()