source: zero-center/trunk/fuentes/install-files/usr/share/zero-center/zero-center.py @ 7159

Last change on this file since 7159 was 7159, checked in by hectorgh, 3 years ago

adding resizing functionality

  • Property svn:executable set to *
File size: 34.0 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*
3 
4
5import os
6import multiprocessing
7import time
8import random
9import xmlrpclib
10import cairo
11import grp
12import sys
13import subprocess
14import json
15
16try:
17        import gi
18        gi.require_version('Gtk', '3.0')
19        gi.require_version('PangoCairo', '1.0')
20        from gi.repository import Gtk, Gdk, GObject, GLib, PangoCairo, Pango
21       
22except Exception as e:
23        print e
24        #zero-server-wizard initialization forces me to do this
25
26import signal
27signal.signal(signal.SIGINT, signal.SIG_DFL)
28
29import gettext
30gettext.textdomain('zero-center')
31_ = gettext.gettext
32
33
34BAR_HEIGHT=90
35CONF_X=5
36
37if os.path.exists("/home/lliurex/banners/"):
38        BANNER_PATH="/home/lliurex/banners/"
39else:
40        BANNER_PATH="/usr/share/banners/lliurex-neu/"
41       
42
43class CategoriesParser:
44       
45        CATEGORIES_PATH="/usr/share/zero-center/categories/"
46       
47        def __init__(self):
48               
49                self.parse_categories()
50               
51        #def init
52       
53        def parse_categories(self,path=None):
54               
55                self.categories=[]
56               
57                if path==None:
58                        path=self.CATEGORIES_PATH
59                       
60                for item in os.listdir(path):
61                        file_path=path+item
62                       
63                        f=open(file_path)
64                        lines=f.readlines()
65                        f.close()
66                       
67                        cat={}
68                       
69                        for line in lines:
70                                key,value=line.split("=")
71                                cat[key]=value.strip("\n")
72                                if key=="level":
73                                        cat[key]=int(cat[key])
74                       
75                        self.categories.append(cat)
76                       
77                tmp=[]
78               
79                while len(self.categories)>0:
80                        selected_index=0
81                        index=0
82                        level=0
83                        for item in self.categories:
84                                if item["level"]>level:
85                                        level=item["level"]
86                                        selected_index=index
87                                       
88                               
89                                index+=1
90                       
91                        tmp.append(self.categories[selected_index])
92                        self.categories.pop(selected_index)
93                       
94                self.categories=tmp
95               
96        #def parse_categories
97               
98               
99#class CategoriesParser
100
101
102class AppParser:
103       
104        BASE_DIR="/usr/share/zero-center/"
105        APP_PATH=BASE_DIR+"applications/"
106        ZMD_PATH=BASE_DIR+"zmds/"
107       
108       
109        def __init__(self):
110               
111                self.categories=["ID","Name","Comment","Icon","Category","Icon","ScriptPath","Groups","Service","Locks"]
112                self.apps={}
113                self.app_list=[]
114                self.configured=[]
115                #print("[ZeroCenter] Parsing apps...")
116                self.parse_all()
117               
118        #def init
119
120       
121        def add_app(self,app):
122               
123                try:
124                        if app["Category"].lower() not in self.apps:
125                                self.apps[app["Category"].lower()]=[]
126                       
127                        self.apps[app["Category"].lower()].append(app)
128                        self.app_list.append(app["ID"])
129                except:
130                        pass
131                       
132        #def add_app
133       
134        def parse_all(self,dir=None):
135               
136                if dir==None:
137                        dir=self.APP_PATH
138       
139                for item in os.listdir(dir):
140                        file_path=self.APP_PATH+item
141                        app=self.parse_file(file_path)
142                        self.add_app(app)
143                       
144        #def parse_all
145
146       
147        def parse_file(self,file_path):
148               
149                f=open(file_path)
150                lines=f.readlines()
151                f.close()
152                id=file_path.split("/")[-1].split(".")[0]
153                app={}
154                for item in lines:
155                        try:
156                                key,value=item.split("=")
157                                app[key]=value.strip("\n")
158                        except:
159                                pass
160               
161                app["ID"]=id
162                app["configured"]=-1
163                app["custom_msg"]=""
164               
165                app["bar_height"]=BAR_HEIGHT
166                app["conf_alpha"]=1.0
167
168               
169                app["expanding"]=False
170                app["restoring"]=False
171
172                return app
173               
174        #def parse_file
175
176       
177#class AppParser
178
179
180class ZeroCenter:
181       
182        def __init__(self):
183               
184                self.client=xmlrpclib.ServerProxy("https://localhost:9779")
185                self.create_user_env()
186                self.categories_parser=CategoriesParser()
187                self.app_parser=AppParser()
188                self.configured_apps=[]
189                self.get_states()
190               
191                self.mprocess=multiprocessing.Process()
192                self.commands=["set-configured","set-non-configured","set-failed","set-custom-text","add-zero-center-notification","remove-zero-center-notification","help","add-pulsating-color","remove-pulsating-color","non-animated","animated"]
193                self.drawing_mode=True
194                self.msg_text=""
195                self.msg_x=0
196                self.scrolling=False
197               
198                try:
199                        self.msg_text=self.client.get_zc_messages("","ZCenterVariables",self.lang)
200                        if self.msg_text=="":
201                                txt=self.client.lliurex_version("","LliurexVersion")
202                                if type(txt)==type([]):
203                                        self.msg_text=str(txt[1])
204                                else:
205                                        f=open("/etc/lsb-release")
206                                        lines=f.readlines()
207                                        f.close()
208                                        for line in lines:
209                                                if "DISTRIB_DESCRIPTION" in line:
210                                                        self.msg_text=line.split("=")[1]
211                        #Load slave_blacklist
212                        self.blacklist=self.client.get_variable("","VariablesManager","SLAVE_BLACKLIST")
213
214                except:
215                        self.msg_text=""
216               
217                #self.msg_text="hi, i'm a long enough text so that it won't show in just one line. I wonder how many lines I can get inside the box. In my restless dreams I see that town, Silent Hill. I don't know what to type, but I have to keep typing"
218                #57
219               
220        #def init
221
222       
223        def get_states(self):
224               
225                try:
226                        var=self.client.get_all_states("","ZCenterVariables")
227                except:
228                        local_path="/var/lib/n4d/variables-dir/ZEROCENTER"
229                        if os.path.exists(local_path):
230                                f=open(local_path)
231                                var=json.load(f)["ZEROCENTER"]["value"]
232                                f.close()
233                        else:
234                                var={}
235                               
236                try:
237                        for cat in self.app_parser.apps:
238                       
239                                for app in self.app_parser.apps[cat]:
240                                        app["configured"]=0
241                                       
242                                        if app["ID"] in var:
243                                                for key in ["state","pulsating","time","custom_text"]:
244                                                        if key in var[app["ID"]]:
245                                                                app[key]=var[app["ID"]][key]
246               
247                                                       
248                                        if "state" in app:
249                                                app["configured"]=app["state"]
250                               
251                                        if app["configured"]==1:
252                                                self.configured_apps.append(app["ID"])
253                               
254                               
255                except Exception as e:
256                        print e
257                        pass
258                       
259        #def get_states
260
261       
262        def get_translation(self,text):
263               
264                for category in self.categories_parser.categories:
265                       
266                        if text.lower()==category["name"].lower():
267                                for lang in self.language:
268                                        try:
269                                                return category["name["+lang+"]"]
270                                        except Exception as e:
271                                                pass
272                                return category["name"]
273               
274                return text
275               
276        #def get_translation
277
278       
279        def get_name(self,app):
280               
281                for lang in self.language:
282                        try:
283                                return app["Name["+lang+"]"]
284                        except:
285                                pass
286                               
287                return app["Name"]
288               
289        #def get_name
290
291       
292        def get_comment(self,app):
293               
294                for lang in self.language:
295                        try:
296                                return app["Comment["+lang+"]"]
297                        except:
298                                pass
299                               
300                return app["Comment"]
301               
302        #def get_name
303
304       
305        def create_user_env(self):
306               
307                try:
308                        self.lang=os.environ["LANGUAGE"].replace(".UTF-8","").split(":")[0]
309                        self.language=os.environ["LANGUAGE"].replace(".UTF-8","").split(":")
310                        if "es_ES" in self.language and "es" not in self.language:
311                                self.language.insert(self.language.index("es_ES")+1,"es")
312                        self.lang=self.lang.split("_")[0]
313                       
314                        if "ca_ES@valencia" in self.language:
315                                self.language.insert(self.language.index("ca_ES@valencia"),"qcv")
316                except:
317                        try:
318                                self.lang=os.environ["LANG"].replace(".UTF-8","")
319                                self.language=[]
320                                self.language.append(self.lang)
321                                self.lang=self.lang.split("_")[0]
322                               
323                        except:
324                                self.lang="en"
325
326                       
327                groups={}
328               
329                for item in grp.getgrall():
330                        if len(item.gr_mem)>0:
331                                if item.gr_name not in groups:
332                                        groups[item.gr_name]=item.gr_mem
333                                else:
334                                        groups[item.gr_name]=list(groups[item.gr_name]+item.gr_mem)
335                       
336               
337                self.user_groups=[]
338                try:
339                        for item in groups:
340                                if os.environ["USER"] in groups[item]:
341                                        self.user_groups.append(item)
342                                       
343                        self.user_groups.append("*")
344                except:
345                        pass
346               
347        #def create_user_area
348
349       
350        def start_gui(self):
351               
352               
353                self.icon_theme=Gtk.IconTheme()
354                self.icon_theme.set_custom_theme("lliurex-neu")
355               
356                builder=Gtk.Builder()
357                if os.path.exists("/srv/svn/pandora/zero-center2/install-files/usr/share/zero-center/rsrc/zero-center.glade"):
358                        builder.add_from_file("/srv/svn/pandora/zero-center2/install-files/usr/share/zero-center/rsrc/zero-center.glade")
359                else:
360                        builder.add_from_file("/usr/share/zero-center/rsrc/zero-center.glade")
361                self.window=builder.get_object("window1")
362                self.window.connect("delete_event",self.close_window)
363                self.window.set_name("BLACK")
364                self.buttons_vbox=builder.get_object("buttons_vbox")
365                self.content_hbox=builder.get_object("main_box")
366                self.content_hbox.override_background_color(Gtk.StateType.NORMAL, Gdk.RGBA(0.2,0.2,0.2,1))
367                self.window_box=builder.get_object("window_box")
368                self.viewport=builder.get_object("viewport1")
369                self.viewport.set_name("ORANGE")
370                self.category_combobox=builder.get_object("category_combobox")
371                self.msg_label=builder.get_object("llx_label")
372                self.msg_label.connect("draw",self.drawing_label_event)
373                self.msg_label.set_tooltip_text(self.msg_text)
374               
375                self.hidden_button=builder.get_object("button1")
376                self.hidden_button.grab_focus()
377               
378                self.search_entry=builder.get_object("entry")
379                self.search_entry.connect("changed",self.entry_changed)
380               
381                self.progress_bar=builder.get_object("progressbar")
382                self.progress_label=builder.get_object("progress_label")
383                self.progress_label.set_name("WHITE")
384               
385                self.add_categories_to_window("All")
386                self.set_css_info()
387               
388                self.window.show()
389                GObject.threads_init()
390                Gtk.main()
391               
392        #def start_gui
393       
394       
395        def entry_changed(self,widget):
396                self.add_categories_to_window("",False)
397       
398        def scroll_me(self,img):
399               
400                if self.msg_x > (self.scroll_width)*-1:
401                        self.msg_x-=1
402                else:
403                        self.msg_x=401
404                img.queue_draw()
405                return self.scrolling
406               
407        #def scroll_me
408
409
410        def set_msg_label_text(self,txt):
411       
412                self.msg_text=txt
413                self.msg_label.queue_draw()
414               
415        #def set_msg_label_text()
416
417       
418        def drawing_label_event(self,widget,ctx):
419               
420                lg1 = cairo.LinearGradient(0.0,18.0, 400.0, 18.0)
421                lg1.add_color_stop_rgba(0, 0.38, 0.38, 0.38, 1)
422                lg1.add_color_stop_rgba(0.1, 0.2, 0.2, 0.2, 1)
423                lg1.add_color_stop_rgba(0.9, 0.2, 0.2, 0.2, 1)
424                lg1.add_color_stop_rgba(1, 0.38, 0.38, 0.38, 1)
425                ctx.rectangle(0, 0, 400, 18)
426                ctx.set_source(lg1)
427                ctx.fill()
428
429                tmp_text=self.msg_text
430
431                if len(tmp_text)>66:
432                        if self.drawing_mode:
433                                if not self.scrolling:
434                                        self.scrolling=True
435                                        self.msg_x=200
436                                        GLib.timeout_add(12,self.scroll_me,widget)
437                        else:
438                                tmp_text=tmp_text[:63]
439                                tmp_text="      " + tmp_text+u" …"
440                else:
441                        self.scrolling=False
442                        spaces=90-len(tmp_text)
443                        space="".join([" "]*(spaces/2))
444                        tmp_text=space+tmp_text+space
445                       
446               
447               
448                tmp_text=tmp_text.replace("[","<b>[")
449                tmp_text=tmp_text.replace("]","] </b>")
450               
451                x=self.msg_x
452                pctx = PangoCairo.create_layout(ctx)
453                desc = Pango.font_description_from_string ("Ubuntu 9")
454                pctx.set_font_description(desc)
455                ctx.set_source_rgb(0.9,0.9,0.9)
456                pctx.set_markup(tmp_text)
457                self.scroll_width=pctx.get_pixel_size()[0]
458                ctx.move_to(x,0)
459                PangoCairo.show_layout(ctx, pctx)
460               
461        #def set_msg_label
462       
463       
464        def set_css_info(self):
465               
466                css = """
467               
468                #BLACK {
469                        background-image: -gtk-gradient (linear,        left top, left bottom, from (#1a1a1a),  to (#616161));
470                       
471                }
472
473                #ORANGE {
474                        background-image: -gtk-gradient (linear,        left top, left bottom, from (#575757),  to (#373737));
475                       
476                }
477               
478                #BLACKEXPANDER {
479                        background-image: -gtk-gradient (linear,        left top, left bottom, from (#1a1a1a),  to (#1a1a1a));
480                        color: white;
481                        box-shadow: 50px 50px;
482                       
483                }
484               
485                #WHITE {
486                        color: white;
487                        text-shadow: 0px 1px black;
488                }               
489               
490                #WHITE-15 {
491                        color: white;
492                        font-size: 15px;
493                        text-shadow: 1px 2px black;
494                }
495
496               
497                #BLACKBUTTON{
498                        background-image: -gtk-gradient (linear,        left top, left bottom, from (#2a2a2a),  to (#616161));
499                        color: #e0e0e0;
500                        border-color: #000;
501                        border-style: none;
502                        border-radius: 10px;
503                       
504                }
505               
506               
507               
508                #APPBUTTON{
509
510                        padding: 0px 0px;
511                        border:none;
512                        background-image: none;
513                        box-shadow: none;
514                        background-color: transparent;
515                        box-shadow: 0px 2px 5px rgba(0,0,0,0.8);
516
517                }
518
519                #APPBUTTON:hover{
520
521                       
522                        border-width: 0;
523                        border-radius: 0px;
524                        border-color: transparent;
525                        border: none;   
526                        box-shadow: 0px 1px 8px rgba(0,0,0,1);
527                }
528               
529                GtkSeparator {
530                        color: rgba(255,255,255,0.8);
531                }
532               
533                #PEPITO {
534                        border: none;
535                }
536               
537                """
538               
539                self.style_provider=Gtk.CssProvider()
540                self.style_provider.load_from_data(css)
541               
542                Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(),self.style_provider,Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
543               
544        #def set_css_info       
545       
546       
547        def get_banner_image(self,app):
548
549                package_rsrc_path=BANNER_PATH
550                img_path=package_rsrc_path+"package.png"
551               
552                for item in os.listdir(package_rsrc_path):
553                        f,ext=item.split(".")
554                        if app["Icon"] == f:
555                                img_path=package_rsrc_path+item
556               
557               
558                img=cairo.ImageSurface.create_from_png(img_path)
559                ctx=cairo.Context(img)
560
561                if not self.check_app_dependences(app):
562                        ctx.set_source_rgba(0.5,0.5,0.5,0.7)
563                        ctx.rectangle(0,0,235,110)
564                        ctx.fill()
565               
566
567                ctx.set_source_rgba(0,0,0,0.8)
568                ctx.rectangle(0,90,235,110)
569                ctx.fill()
570
571
572                show_status=True
573                if "Depends" in app:
574
575                        if not self.check_app_dependences(app):
576                               
577                                lg1 = cairo.LinearGradient(0.0,110.0, 200.0, 110.0)
578                                lg1.add_color_stop_rgba(0, 0.7, 0, 0, 1)
579                                lg1.add_color_stop_rgba(1, 1, 0.2, 0.2, 0)
580                                ctx.rectangle(0, 0, 200, 20)
581                                ctx.set_source(lg1)
582                                ctx.fill()
583                                                                                       
584                                ctx.select_font_face("Ubuntu")
585                                ctx.set_font_size(15)
586                                ctx.move_to(5,15)
587                                ctx.set_source_rgba(1,1,1,app["conf_alpha"])
588                                                                                       
589                                ctx.show_text(_("Unmet dependences"))
590                                ctx.stroke()
591                               
592                                show_status=False
593
594
595                if "Service" in app and show_status:
596
597                        if app["Service"].lower()=="true":
598
599                                if app["configured"]==1:
600
601                                        lg1 = cairo.LinearGradient(0.0,110.0, 200.0, 110.0)
602                                                               
603                                        lg1.add_color_stop_rgba(0, 0, 0.2, 0, 1)
604                                        lg1.add_color_stop_rgba(1, 0, 1, 0, 0)
605                                        ctx.rectangle(0, 0, 200, 20)
606                                        ctx.set_source(lg1)
607                                        ctx.fill()
608                                                       
609                                        ctx.select_font_face("Ubuntu")
610                                        ctx.set_font_size(15)
611                                        ctx.move_to(5,15)
612                                        ctx.set_source_rgb(1,1,1)
613                                                       
614                                        ctx.show_text(_("Configured"))
615                                        ctx.stroke()
616
617
618                                elif app["configured"]==0:
619
620                                        lg1 = cairo.LinearGradient(0.0,110.0, 200.0, 110.0)
621                                                               
622                                        lg1.add_color_stop_rgba(0, 0.7, 0, 0, 1)
623                                        lg1.add_color_stop_rgba(1, 1, 0.2, 0.2, 0)
624                                        ctx.rectangle(0, 0, 200, 20)
625                                        ctx.set_source(lg1)
626                                        ctx.fill()
627                                                       
628                                        ctx.select_font_face("Ubuntu")
629                                        ctx.set_font_size(15)
630                                        ctx.move_to(5,15)
631                                        ctx.set_source_rgb(1,1,1)
632                                                       
633                                        ctx.show_text(_("Not configured"))
634                                        ctx.stroke()
635                                       
636                                else:
637                                        lg1 = cairo.LinearGradient(0.0,110.0, 200.0, 110.0)
638                                        lg1.add_color_stop_rgba(0, 1, 0, 0, 1)
639                                        lg1.add_color_stop_rgba(1, 1, 0.2, 0.2, 0)
640                                        ctx.rectangle(0, 0, 200, 20)
641                                        ctx.set_source(lg1)
642                                        ctx.fill()
643                                                               
644                                        ctx.select_font_face("Ubuntu")
645                                        ctx.set_font_size(15)
646                                        ctx.move_to(5,15)
647                                        ctx.set_source_rgba(1,1,1,app["conf_alpha"])
648                                                               
649                                        ctx.show_text(_("Failed"))
650                                        ctx.stroke()
651
652                ctx.select_font_face("Ubuntu")
653                ctx.set_font_size(15)
654                ctx.move_to(5,105)
655                ctx.set_source_rgb(1,1,1)
656                txt=""
657                fix=True
658               
659                text=self.get_name(app)
660               
661               
662                for char in range(30):
663                        try:
664                                txt+=text[char]
665                        except:
666                                fix=False
667                                break
668                                                       
669                if fix:
670                        txt+="…"
671               
672                ctx.show_text(txt)
673                ctx.stroke()
674
675                #img.write_to_png(self.user_rsrc_path+item)
676                image=Gtk.Image()
677                #image.set_from_file(self.user_rsrc_path+item)
678                image.set_from_pixbuf(Gdk.pixbuf_get_from_surface(img,0,0,235,110))
679                image.set_name("BIMAGE")
680                return image
681               
682        #def get_image
683
684       
685        def drawing_banner_event(self,widget,ctx,app):
686               
687                package_rsrc_path=BANNER_PATH
688                img_path=package_rsrc_path+"package.png"
689                for item in os.listdir(package_rsrc_path):
690                        f,ext=item.split(".")
691                        if app["Icon"] == f:
692                                img_path=package_rsrc_path+item
693               
694       
695                img=cairo.ImageSurface.create_from_png(img_path)
696                ctx.set_source_surface(img,0,0)
697               
698                if not self.check_app_dependences(app):
699                        ctx.paint_with_alpha(0.2)
700                        ctx.set_source_rgba(0.5,0.5,0.5,0.7)
701                        ctx.rectangle(0,0,235,110)
702                        ctx.fill()
703                else:
704                        ctx.paint()
705
706
707                if "pulsating" in app and app["pulsating"]:
708                       
709                        '''
710                        if app["pulsating"]:
711                                ctx.set_source_rgba(1,1,1,app["pulsating_alpha"])
712                                ctx.rectangle(0,0,235,110)
713                                ctx.fill()             
714                        '''
715                       
716                        app.setdefault("pulsating_alpha",0.0)
717       
718                        lg1 = cairo.LinearGradient(0.0,10.0, 235.0, 10.0)
719                        lg1.add_color_stop_rgba(0, 0, 0.0, 0.8, 0.7)
720                        lg1.add_color_stop_rgba(app["pulsating_alpha"], 0.1, 0.7, 0.9, 1)
721                        lg1.add_color_stop_rgba(1, 0, 0, 0.8, 0.5)
722                        ctx.rectangle(0,app["bar_height"],235,20)
723                        ctx.set_source(lg1)
724                        ctx.fill()
725                        ctx.set_source_rgba(0,0,0,0.8)
726                        ctx.rectangle(0,app["bar_height"]+20,235,110)
727                        ctx.fill()                     
728                       
729                else:
730                       
731                        ctx.set_source_rgba(0,0,0,0.7)
732                        ctx.rectangle(0,app["bar_height"],235,110)
733                        ctx.fill()
734               
735                show_status=True
736                if "Depends" in app:
737
738                        if not self.check_app_dependences(app):
739                               
740                                lg1 = cairo.LinearGradient(0.0,110.0, 200.0, 110.0)
741                                lg1.add_color_stop_rgba(0, 0.7, 0, 0, 1)
742                                lg1.add_color_stop_rgba(1, 1, 0.2, 0.2, 0)
743                                ctx.rectangle(0, 0, 200, 20)
744                                ctx.set_source(lg1)
745                                ctx.fill()
746                                                                                       
747                                ctx.select_font_face("Ubuntu")
748                                ctx.set_font_size(15)
749                               
750                                ctx.move_to(6,16)
751                                ctx.set_source_rgba(0,0,0,app["conf_alpha"])
752                                ctx.show_text(_("Unmet dependences"))
753                                ctx.stroke()
754                               
755                               
756                                ctx.move_to(5,15)
757                                ctx.set_source_rgba(1,1,1,app["conf_alpha"])
758                                ctx.show_text(_("Unmet dependences"))
759                                ctx.stroke()
760                               
761                                show_status=False
762
763                if "Service" in app and show_status:
764                       
765                        if app["Service"].lower()=="true":
766
767                                if app["configured"]==1:
768
769                                        lg1 = cairo.LinearGradient(0.0,110.0, 200.0, 110.0)
770                                        lg1.add_color_stop_rgba(0, 0, 0.2, 0, 1)
771                                        lg1.add_color_stop_rgba(1, 0, 1, 0, 0)
772                                        ctx.rectangle(0, 0, 200, 20)
773                                        ctx.set_source(lg1)
774                                        ctx.fill()
775                                                       
776                                        ctx.select_font_face("Ubuntu")
777                                        ctx.set_font_size(15)
778                                       
779                                        ctx.set_source_rgba(0,0,0,app["conf_alpha"])
780                                        ctx.move_to(6,16)               
781                                        ctx.show_text(_("Configured"))
782                                        ctx.stroke()
783                                       
784                                       
785                                        ctx.set_source_rgba(1,1,1,app["conf_alpha"])
786                                        ctx.move_to(5,15)               
787                                        ctx.show_text(_("Configured"))
788                                        ctx.stroke()
789                                                       
790                                elif app["configured"]==-1:
791
792                                        lg1 = cairo.LinearGradient(0.0,110.0, 200.0, 110.0)
793                                        lg1.add_color_stop_rgba(0, 0.7, 0, 0, 1)
794                                        lg1.add_color_stop_rgba(1, 1, 0.2, 0.2, 0)
795                                        ctx.rectangle(0, 0, 200, 20)
796                                        ctx.set_source(lg1)
797                                        ctx.fill()
798                                                       
799                                        ctx.select_font_face("Ubuntu")
800                                        ctx.set_font_size(15)
801                                       
802                                        ctx.set_source_rgba(0,0,0,app["conf_alpha"])
803                                        ctx.move_to(6,16)               
804                                        ctx.show_text(_("Failed"))
805                                        ctx.stroke()
806                                       
807                                       
808                                        ctx.move_to(5,15)
809                                        ctx.set_source_rgba(1,1,1,app["conf_alpha"])
810                                        ctx.show_text(_("Failed"))
811                                        ctx.stroke()
812                                       
813                                else:
814                                       
815                                        lg1 = cairo.LinearGradient(0.0,110.0, 200.0, 110.0)
816                                        lg1.add_color_stop_rgba(0, 0.8, 0, 0, 1)
817                                        lg1.add_color_stop_rgba(1, 1, 0.2, 0.2, 0)
818                                        ctx.rectangle(0, 0, 200, 20)
819                                        ctx.set_source(lg1)
820                                        ctx.fill()
821
822                                        ctx.select_font_face("Ubuntu")
823                                        ctx.set_font_size(15)
824                                       
825                                        ctx.set_source_rgba(0,0,0,app["conf_alpha"])
826                                        ctx.move_to(6,16)               
827                                        ctx.show_text(_("Not configured"))
828                                        ctx.stroke()                                   
829                                       
830                                        ctx.move_to(5,15)
831                                        ctx.set_source_rgba(1,1,1,app["conf_alpha"])
832                                        ctx.show_text(_("Not configured"))
833                                        ctx.stroke()                                   
834
835
836                txt=""
837                fix=True
838                for char in range(30):
839                        try:
840                                txt+=self.get_name(app)[char]
841                        except:
842                                fix=False
843                                break
844                                                       
845                if fix:
846                        txt+="…"
847
848
849                ctx.select_font_face("Ubuntu")
850                ctx.set_font_size(15)
851               
852                ctx.move_to(6,app["bar_height"]+16)
853                ctx.set_source_rgb(0,0,0)
854                ctx.show_text(txt)
855                ctx.stroke()           
856               
857                ctx.move_to(5,app["bar_height"]+15)
858                ctx.set_source_rgb(0.9,0.9,0.9)
859                ctx.show_text(txt)
860                ctx.stroke()           
861
862               
863               
864               
865                y=app["bar_height"]+30
866                pctx = PangoCairo.create_layout(ctx)
867                desc = Pango.font_description_from_string ("Ubuntu 8")
868                pctx.set_font_description(desc)
869                pctx.set_alignment(Pango.Alignment.LEFT)
870                pctx.set_justify(True)
871                pctx.set_width(225000)
872                pctx.set_height(10)
873                ctx.set_source_rgb(1,1,0.8)
874                pctx.set_text(self.get_comment(app),-1)
875               
876
877                ctx.move_to(6,y)
878                PangoCairo.show_layout (ctx, pctx)
879               
880                if "custom_text" in app:
881                       
882                        ctx.set_source_rgb(0.5,0.5,1)
883                        pctx.set_text(app["custom_text"],-1)
884                        ctx.move_to(6,y+60)
885                        PangoCairo.show_layout (ctx, pctx)
886                       
887               
888        #def drawing_event
889       
890
891        def mouse_over(self,widget,event,app,img):
892               
893                if not app["expanding"]:
894                        app["restoring"]=False
895                        app["expanding"]=True
896                        GLib.timeout_add(10,self.expand_black_area,app,img)
897               
898        #def mouse_over
899
900       
901        def mouse_left(self,widget,event,app,img):
902               
903                if not app["restoring"]:
904                        app["expanding"]=False
905                        app["restoring"]=True
906                        GLib.timeout_add(10,self.restore_black_area,app,img)
907               
908        #def mouse_left
909
910       
911        def expand_black_area(self,app,img):
912               
913                while app["bar_height"]>0 and app["expanding"]:
914                        app["bar_height"]-=2
915                        if app["conf_alpha"]>0.0:
916                                app["conf_alpha"]-=0.025
917                        img.queue_draw()
918                        return True
919                       
920                if not app["expanding"]:
921                        return False
922                       
923                app["expanding"]=False
924                app["conf_alpha"]=0.0
925                img.queue_draw()
926                return False
927               
928        #def expand_black_area
929       
930       
931        def restore_black_area(self,app,img):
932               
933                while app["bar_height"]<BAR_HEIGHT and app["restoring"]:
934                        app["bar_height"]+=2
935                        if app["conf_alpha"]<1.0:
936                                app["conf_alpha"]+=0.025
937                        img.queue_draw()
938                        return True
939                       
940                if not app["restoring"]:
941                        return False
942                       
943                app["restoring"]=False
944                app["conf_alpha"]=1.0
945                img.queue_draw()
946                return False
947               
948        #def restore_black_area
949       
950       
951        def check_app_groups(self,app,verbose=True):
952               
953                if verbose:
954                        sys.stdout.write(" * Checking " + app["ID"] + " ... ")
955                groups=[]
956                if "Groups" not in app:
957                        if verbose:
958                                print("OK")
959                        return True
960               
961                try:
962                       
963                        if os.environ["USER"]=="root":
964                                if verbose:
965                                        print("OK")
966                                return True
967                       
968                        groups=app["Groups"].strip("\n").split(";")
969                        for group in groups:
970                                if group in self.user_groups:
971                                        if verbose:
972                                                print("OK")             
973                                        return True
974                       
975                except Exception as e:
976                        print e
977                        pass
978                       
979                if verbose:
980                        print "NOT ALLOWED"
981                        print "\t[!] App groups: ",sorted(groups)
982                return False
983               
984        #def check_app_groups
985
986       
987        def add_pulsating(self,app,image):
988               
989                GLib.timeout_add(70,self.pulsate_color,app,image)
990               
991        #def add_pulsating
992
993
994        def pulsate_color(self,app,image):
995               
996                app["pulsating_alpha"]+=app["pulsating_increment"]
997               
998                if app["pulsating_alpha"] >= 1.0 :
999                       
1000                        app["pulsating_increment"]=-0.02
1001                       
1002                if app["pulsating_alpha"] <= 0.0 :
1003                       
1004                        app["pulsating_increment"]=0.02
1005                       
1006                image.queue_draw()
1007                return app["pulsating"]
1008               
1009        #def pulsate_color
1010               
1011               
1012        def check_app_dependences(self,app):
1013               
1014                if "Depends" in app:
1015                        depends=app["Depends"].split(";")
1016                        for dep in depends:
1017                               
1018                                if dep not in self.configured_apps:
1019                                        return False
1020                               
1021                return True
1022               
1023        #def check_app_dependences
1024
1025       
1026        def add_categories_to_window(self,category,verbose=True):
1027               
1028                for child in self.content_hbox.get_children():
1029                        self.content_hbox.remove(child)
1030               
1031                for category in self.categories_parser.categories:
1032                       
1033                        icon=category["icon"]
1034                        category=category["name"].lower()
1035                       
1036                        once=True
1037                        hbox=Gtk.FlowBox()
1038                        hbox.set_margin_left(5)
1039                        hbox.set_margin_right(5)
1040                        hbox.set_homogeneous(True)
1041                        hbox.set_column_spacing(5)
1042                        hbox.set_row_spacing(10)
1043                        count=0
1044                        if category in self.app_parser.apps:
1045                                for app in sorted(self.app_parser.apps[category]):
1046                                       
1047                                        if self.check_app_groups(app,verbose):
1048
1049                                                search_txt=self.search_entry.get_text().lower().strip()
1050
1051                                                if search_txt not in app["ID"] and search_txt not in self.get_translation(app["Category"]).lower() and search_txt not in self.get_name(app).lower() and len(search_txt)>2:
1052                                                        continue
1053                                                button=Gtk.Button()
1054                                                button.set_name("APPBUTTON")
1055                                                button.set_size_request(235,110)
1056                                                #button.set_margin_top(10)
1057                                                button.set_halign(Gtk.Align.START)
1058                                                button.set_valign(Gtk.Align.START)
1059                                               
1060                                               
1061                                                if not self.drawing_mode:
1062                                                        image=self.get_banner_image(app)
1063                                                else:
1064                                                        image=Gtk.DrawingArea()
1065                                                       
1066                                                        image.show()
1067                                                        image.connect("draw",self.drawing_banner_event,app)
1068                                                       
1069                                                        if "pulsating" in app:
1070                                                                if app["pulsating"]:
1071                                                                        app["pulsating_alpha"]=0.0
1072                                                                        app["pulsating_increment"]=0.02
1073                                                                        self.add_pulsating(app,image)
1074                                                       
1075                                                       
1076                                                        button.add_events(Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK)
1077                                                        button.connect("motion-notify-event",self.mouse_over,app,image)
1078                                                        button.connect("leave_notify_event",self.mouse_left,app,image)
1079                                                       
1080                                                        #button.set_size_request(245,120)
1081                                               
1082                                                button.add(image)
1083                                                if "Name["+self.lang+"]" in app:
1084                                                        button.set_tooltip_text(app["Name["+self.lang+"]"])
1085                                                else:
1086                                                        button.set_tooltip_text(app["Name"])
1087                                                button.connect("clicked",self.app_clicked,app)
1088                                                app["gtk_button"]=button
1089                                               
1090                                                child=Gtk.FlowBoxChild()
1091                                                child.set_border_width(0)
1092                                               
1093                                                child.add(button)
1094                                               
1095                                                hbox.add(child)
1096                                                count+=1
1097                                               
1098                        if count!=0:
1099                                hbox.show_all()
1100                                if once:
1101                                        self.add_label(self.get_translation(category),icon)
1102                                        once=False
1103                                hbox.set_margin_left(20)
1104                                self.content_hbox.pack_start(hbox,True,True,5)
1105               
1106                if len(self.content_hbox.get_children()) > 0:
1107                        self.content_hbox.get_children()[-1].set_margin_bottom(10)
1108               
1109        #def add_categories_to_window
1110       
1111       
1112       
1113       
1114        def add_label(self,label_name,icon_name=None):
1115               
1116                if icon_name==None:
1117                        icon_name="system"
1118                       
1119                tmpbox=Gtk.HBox()
1120                img=Gtk.Image()
1121                img.set_from_icon_name(icon_name,Gtk.IconSize.MENU)
1122                label=Gtk.Label(label_name)
1123                label.set_name("WHITE-15")
1124                expander=Gtk.HSeparator()
1125                expander.set_margin_right(15)
1126                tmpbox.set_margin_left(10)
1127                tmpbox.set_margin_top(5)
1128                tmpbox.pack_start(img,False,False,0)
1129                tmpbox.pack_start(label,False,False,10)
1130                tmpbox.pack_start(expander,True,True,5)
1131                tmpbox.show_all()
1132                self.content_hbox.pack_start(tmpbox,False,False,5)             
1133               
1134        #def add_label
1135       
1136       
1137        def app_clicked(self,widget,app):
1138       
1139                if  self.client.get_variable("","VariablesManager","MASTER_SERVER_IP"):
1140                        if app["ID"] in self.blacklist:
1141                                result = self.open_dialog("Warning",_("We are in a center model and therefore should install this service on the master \n server to be accessible from any computer in the center, whether to continue \n with the installation on this computer the service is only available on computers \n that are in the internal network of this server."),True)
1142                                if result == Gtk.ResponseType.CANCEL:
1143                                        return -1
1144
1145                if app["ID"] in self.configured_apps:
1146                        ret=self.open_dialog("Warning",_("<b>%s</b> is already configured. Do you want to execute it again?")%self.get_name(app),True)
1147                        if ret==Gtk.ResponseType.CANCEL:
1148                                return -1
1149               
1150                if self.check_app_dependences(app):
1151               
1152                        cmd=""
1153                               
1154                        if "Using" in app:
1155                                cmd+=app["Using"].strip(" ").strip("\n") +" "
1156                                       
1157                        cmd+=self.app_parser.ZMD_PATH + app["ScriptPath"]
1158                       
1159                        gt=False
1160                        if "Gnome-terminal" in app:
1161                                if app["Gnome-terminal"].lower()=="true":
1162                                        cmd='gnome-terminal --command="'+cmd+'"'
1163                                        gt=True
1164                                       
1165                        if not gt:
1166                                if "gnome-terminal" in app:
1167                                        if app["gnome-terminal"].lower()=="true":
1168                                                cmd='gnome-terminal --command="'+cmd+'"'
1169                               
1170                               
1171                       
1172                        blocked=False
1173                        print(' * Executing "' + cmd + '" ...')
1174                        if "Modal" in app:
1175                                if app["Modal"].lower()=="true" and not self.mprocess.is_alive():
1176                                        GLib.timeout_add(250,self.pulse_progress)
1177                                        self.progress_bar.show()
1178                                       
1179                                        try:
1180                                                txt="Executing %s"%app["Name["+self.lang+"]"]
1181                                        except:
1182                                                txt="Executing %s"%app["Name"]
1183                                        self.progress_label.set_text(txt)
1184                                        self.progress_label.show()
1185                                        self.mprocess_app_name=app["Name"]
1186                                        blocked=True
1187                                else:
1188                                        self.open_dialog("Warning","<b>%s</b> is being executed. Please wait until it finishes."%self.mprocess_app_name )
1189                                        return -1
1190               
1191                        self.execute(cmd,blocked,app,widget)
1192                       
1193                else:
1194                       
1195                        self.open_dialog("Warning","<b>%s</b> dependences have not been configured."%self.get_name(app) +"\n[ %s ]"%app["Depends"])
1196               
1197        #def app_clicked
1198       
1199       
1200        def check_output(self,process,app,button):
1201               
1202                if not process.is_alive():
1203                       
1204                        print "[ZeroCenter] %s has ended"%app["ID"]
1205                       
1206                        if "Service" in app:
1207                                if app["Service"].lower()=="true":
1208                                       
1209                                        try:
1210                                                self.get_states()
1211                       
1212                                                for cat in self.app_parser.apps:
1213                                                        for item in self.app_parser.apps[cat]:
1214                                                                item["gtk_button"].get_child().queue_draw()
1215                                               
1216                                                darea=button.get_child()
1217                                                darea.queue_draw()
1218                                               
1219                                        except Exception as e:
1220                                                pass
1221                                       
1222                return process.is_alive()
1223               
1224        #def check_output
1225       
1226       
1227        def pulse_progress(self):
1228               
1229                self.progress_bar.pulse()
1230                if not self.mprocess.is_alive():
1231                        self.progress_bar.hide()
1232                        self.progress_label.hide()
1233                return self.mprocess.is_alive()
1234
1235        #def pulse_progress
1236
1237       
1238        def execute(self,cmd,blocked=False,app=None,widget=None):
1239               
1240                if not blocked:
1241                        p=multiprocessing.Process(target=self._execute,args=(cmd,))
1242                        #p.daemon=True
1243                        GLib.timeout_add(1000,self.check_output,p,app,widget)
1244                        p.start()
1245                       
1246                if blocked:
1247                       
1248                        if not self.mprocess.is_alive():
1249                                self.mprocess=multiprocessing.Process(target=self._execute,args=(cmd,))
1250                                #self.mprocess.daemon=True
1251                                self.mprocess.start()
1252                                GLib.timeout_add(1000,self.check_output,self.mprocess,app,widget)
1253                        else:
1254                                self.open_dialog("Warning",_("<b>%s</b> is being executed. Please wait until it finishes.")%self.mprocess_app_name )
1255               
1256        #def execute
1257
1258
1259        def _execute(self,cmd):
1260               
1261               
1262                subprocess.call(cmd,shell=True,preexec_fn=lambda: signal.signal(signal.SIGPIPE,signal.SIG_DFL))
1263               
1264                #os.system(cmd)
1265               
1266        #def _execute
1267
1268       
1269        def close_window(self,widget,data):
1270               
1271                if self.mprocess.is_alive():
1272                        ret=self.open_dialog("Warning",_("<b>%s</b> is being executed. Are you sure you want to exit?")%self.mprocess_app_name ,True)
1273               
1274                        if ret==Gtk.ResponseType.CANCEL:
1275                                return -1
1276                               
1277                        self.mprocess.terminate()
1278                        self.mprocess=multiprocessing.Process()
1279               
1280                Gtk.main_quit()
1281                print("")
1282               
1283        #def close_window
1284
1285               
1286        def open_dialog(self,title,text,show_cancel=False):
1287
1288                label = Gtk.Label()
1289                label.set_markup(text)
1290                if show_cancel:
1291                        dialog = Gtk.Dialog(title, None, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT, (Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT,Gtk.STOCK_CANCEL,Gtk.ResponseType.CANCEL))
1292                else:
1293                        dialog = Gtk.Dialog(title, None, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT, (Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT))
1294                hbox = Gtk.HBox()
1295                img=Gtk.Image.new_from_icon_name("emblem-important",Gtk.IconSize.DIALOG)
1296                hbox.pack_start(img,True,True,5)
1297                hbox.pack_start(label,True,True,10)
1298                hbox.show_all()
1299                dialog.vbox.pack_start(hbox,True,True,10)
1300                dialog.set_border_width(6)
1301                response = dialog.run()
1302                dialog.destroy()
1303                return response
1304               
1305        #def open_dialog
1306
1307       
1308        def get_state(self,app):
1309
1310                try:
1311                        configured=self.client.get_state("","ZCenterVariables",app["ID"])
1312                        return configured
1313                except:
1314                        return 0
1315               
1316        #def get_state
1317
1318       
1319        def set_configured(self,app,key):
1320               
1321                if app in self.app_parser.app_list:
1322                       
1323                        try:
1324                                self.client.set_configured(key,"ZCenterVariables",app)
1325                        except Exception as e:
1326                                print e
1327                               
1328                else:
1329                        print("[!] %s is not installed"%app)
1330               
1331                sys.exit(0)
1332                               
1333        #def set_configured
1334
1335       
1336        def set_non_configured(self,app,key):
1337               
1338                if app in self.app_parser.app_list:
1339                       
1340                        try:
1341                                self.client.set_non_configured(key,"ZCenterVariables",app)
1342                        except:
1343                                pass
1344                               
1345                else:
1346                        print("\t[!] %s is not installed"%app)
1347               
1348                sys.exit(0)
1349               
1350        #def set_non_configured
1351       
1352        def set_failed(self,app,key):
1353               
1354                if app in self.app_parser.app_list:
1355                       
1356                        try:
1357                                self.client.set_failed(key,"ZCenterVariables",app)
1358                        except:
1359                                pass
1360                               
1361                else:
1362                        print("\t[!] %s is not installed"%app)
1363               
1364                sys.exit(0)
1365               
1366        #def set_non_configured
1367
1368       
1369        def set_custom_text(self,app,text,key):
1370               
1371                if app in self.app_parser.app_list:
1372                       
1373                        try:
1374                                self.client.set_custom_text(key,"ZCenterVariables",app,text)
1375                        except:
1376                                pass
1377                               
1378                else:
1379                        print("\t[!] %s is not installed"%app)
1380               
1381                sys.exit(0)
1382               
1383        #def set_custom_text
1384
1385       
1386        def add_pulsating_color(self,key,app):
1387               
1388                try:
1389                        self.client.add_pulsating_color(key,"ZCenterVariables",app)
1390                except:
1391                        pass
1392                       
1393                sys.exit(0)
1394               
1395        #def add_pulsating_color
1396
1397       
1398        def remove_pulsating_color(self,key,app):
1399               
1400                try:
1401                        self.client.remove_pulsating_color(key,"ZCenterVariables",app)
1402                except:
1403                        pass
1404               
1405                sys.exit(0)
1406               
1407        #def add_pulsating_color
1408
1409       
1410        def add_zc_notification(self,key,app,text,text_es="",text_qcv=""):
1411               
1412                try:
1413                        self.client.set_zc_message(key,"ZCenterVariables",app,text,text_es,text_qcv)
1414                except Exception as e:
1415                        print e
1416                       
1417                sys.exit(0)
1418               
1419        #def add_zc_notification
1420
1421       
1422        def remove_zc_notification(self,key,app):
1423               
1424                try:
1425                        self.client.remove_zc_message(key,"ZCenterVariables",app)
1426                except Exception as e:
1427                        print e
1428                       
1429                sys.exit(0)
1430               
1431        #def remove_zc_notification
1432
1433
1434        def usage(self):
1435               
1436                print("USAGE:")
1437                print("\tzero-center [ OPTION [ APP ] ]")
1438                print("Options:")
1439                print("\tset-configured APP") 
1440                print("\tset-non-configured APP") 
1441                print("\tset-custom-text APP TEXT") 
1442                print("\tadd-zero-center-notification APP TEXT_EN [TEXT_ES TEXT_QCV]") 
1443                print("\tremove-zero-center-notification APP") 
1444                print("\tadd-pulsating-color APP") 
1445                print("\tremove-pulsating-color APP") 
1446                print("\tnon-animated")
1447                print("\tanimated")
1448                print("\thelp")
1449                print("")
1450                sys.exit(0)
1451               
1452        #def usage
1453       
1454
1455def check_root():
1456        try:
1457                f=open("/etc/n4d/key","r")
1458                key=f.readline().strip("\n")
1459                f.close()
1460                return key
1461        except:
1462                print("[!] You need root privileges to execute this option [!]")
1463                sys.exit(1)
1464
1465if __name__=="__main__":
1466       
1467
1468        zc=ZeroCenter()
1469        zc.drawing_mode=True
1470
1471        if len(sys.argv)>=2:
1472               
1473                if sys.argv[1] not in zc.commands:
1474                        zc.usage()
1475                        sys.exit(1)
1476                       
1477                if sys.argv[1] == "help":
1478                        zc.usage()
1479                       
1480                if sys.argv[1] == "set-configured":
1481                        key=check_root()
1482                        zc.set_configured(sys.argv[2],key)
1483                       
1484                if sys.argv[1] == "set-non-configured":
1485                        key=check_root()
1486                        zc.set_non_configured(sys.argv[2],key)
1487                       
1488                if sys.argv[1] == "set-failed":
1489                        key=check_root()
1490                        zc.set_failed(sys.argv[2],key)
1491                       
1492                if sys.argv[1] == "set-custom-text":
1493                        key=check_root()
1494                        zc.set_custom_text(sys.argv[2],sys.argv[3],key)
1495                       
1496                if sys.argv[1] == "add-zero-center-notification":
1497                        key=check_root()
1498                       
1499                        try:
1500                                app=sys.argv[2]
1501                        except:
1502                                zc.usage()
1503                        try:
1504                                text=sys.argv[3]
1505                        except:
1506                                zc.usage()
1507                        try:
1508                                text_es=sys.argv[4]
1509                        except Exception as e:
1510                                print e
1511                                text_es=""
1512                        try:
1513                                text_qcv=sys.argv[5]
1514                        except Exception as e:
1515                                print e
1516                                text_qcv=""
1517                       
1518                        zc.add_zc_notification(key,app,text,text_es,text_qcv)
1519                       
1520                if sys.argv[1] == "remove-zero-center-notification":
1521                       
1522                        key=check_root()
1523                       
1524                        try:
1525                                app=sys.argv[2]
1526                        except:
1527                                zc.usage()
1528                               
1529                        zc.remove_zc_notification(key,app)
1530                       
1531                if sys.argv[1] == "add-pulsating-color":
1532                        key=check_root()
1533                        try:
1534                                app=sys.argv[2]
1535                        except:
1536                                zc.usage()
1537                               
1538                        zc.add_pulsating_color(key,app)
1539                               
1540                if sys.argv[1] == "remove-pulsating-color":
1541                        key=check_root()
1542                       
1543                        try:
1544                                app=sys.argv[2]
1545                        except:
1546                                zc.usage()
1547                               
1548                        zc.remove_pulsating_color(key,app)
1549                       
1550
1551                if sys.argv[1]=="animated":
1552                        zc.drawing_mode=True
1553                       
1554                if sys.argv[1]=="non-animated":
1555                        zc.drawing_mode=False
1556               
1557       
1558       
1559        zc.start_gui()
1560
Note: See TracBrowser for help on using the repository browser.