root/trunk/src/gtkgui_helpers.py

Revision 10556, 30.9 kB (checked in by asterix, 6 weeks ago)

remove useless print

  • Property svn:eol-style set to LF
Line 
1# -*- coding:utf-8 -*-
2## src/gtkgui_helpers.py
3##
4## Copyright (C) 2003-2008 Yann Leboulanger <asterix AT lagaule.org>
5## Copyright (C) 2005-2006 Dimitur Kirov <dkirov AT gmail.com>
6## Copyright (C) 2005-2007 Nikos Kouremenos <kourem AT gmail.com>
7## Copyright (C) 2006 Travis Shirk <travis AT pobox.com>
8## Copyright (C) 2006-2007 Junglecow J <junglecow AT gmail.com>
9## Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
10## Copyright (C) 2007 James Newton <redshodan AT gmail.com>
11##                    Julien Pivotto <roidelapluie AT gmail.com>
12## Copyright (C) 2007-2008 Stephan Erb <steve-e AT h3c.de>
13## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
14##
15## This file is part of Gajim.
16##
17## Gajim is free software; you can redistribute it and/or modify
18## it under the terms of the GNU General Public License as published
19## by the Free Software Foundation; version 3 only.
20##
21## Gajim is distributed in the hope that it will be useful,
22## but WITHOUT ANY WARRANTY; without even the implied warranty of
23## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24## GNU General Public License for more details.
25##
26## You should have received a copy of the GNU General Public License
27## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
28##
29
30import xml.sax.saxutils
31import gtk
32import gtk.glade
33import gobject
34import pango
35import os
36import sys
37
38import vcard
39import dialogs
40
41import logging
42log = logging.getLogger('gajim.gtkgui_helpers')
43
44
45HAS_PYWIN32 = True
46if os.name == 'nt':
47        try:
48                import win32file
49                import win32con
50                import pywintypes
51        except ImportError:
52                HAS_PYWIN32 = False
53
54from common import i18n
55from common import gajim
56from common import helpers
57
58gtk.glade.bindtextdomain(i18n.APP, i18n.DIR) 
59gtk.glade.textdomain(i18n.APP)
60
61screen_w = gtk.gdk.screen_width()
62screen_h = gtk.gdk.screen_height()
63
64GLADE_DIR = os.path.join('..', 'data', 'glade')
65def get_glade(file_name, root = None):
66        file_path = os.path.join(GLADE_DIR, file_name)
67        return gtk.glade.XML(file_path, root=root, domain=i18n.APP)
68
69def get_completion_liststore(entry):
70        ''' create a completion model for entry widget
71        completion list consists of (Pixbuf, Text) rows'''
72        completion = gtk.EntryCompletion()
73        liststore = gtk.ListStore(gtk.gdk.Pixbuf, str)
74       
75        render_pixbuf = gtk.CellRendererPixbuf()
76        completion.pack_start(render_pixbuf, expand = False)
77        completion.add_attribute(render_pixbuf, 'pixbuf', 0)
78       
79        render_text = gtk.CellRendererText()
80        completion.pack_start(render_text, expand = True)
81        completion.add_attribute(render_text, 'text', 1)
82        completion.set_property('text_column', 1)
83        completion.set_model(liststore)
84        entry.set_completion(completion)
85        return liststore
86       
87       
88def popup_emoticons_under_button(menu, button, parent_win):
89        ''' pops emoticons menu under button, which is in parent_win'''
90        window_x1, window_y1 = parent_win.get_origin()
91        def position_menu_under_button(menu):
92                # inline function, which will not keep refs, when used as CB
93                button_x, button_y = button.allocation.x, button.allocation.y
94               
95                # now convert them to X11-relative
96                window_x, window_y = window_x1, window_y1
97                x = window_x + button_x
98                y = window_y + button_y
99
100                menu_width, menu_height = menu.size_request()
101
102                ## should we pop down or up?
103                if (y + button.allocation.height + menu_height
104                        < gtk.gdk.screen_height()):
105                        # now move the menu below the button
106                        y += button.allocation.height
107                else:
108                        # now move the menu above the button
109                        y -= menu_height
110
111                # push_in is True so all the menuitems are always inside screen
112                push_in = True
113                return (x, y, push_in)
114
115        menu.popup(None, None, position_menu_under_button, 1, 0)
116       
117def get_theme_font_for_option(theme, option):
118        '''return string description of the font, stored in
119        theme preferences'''
120        font_name = gajim.config.get_per('themes', theme, option)
121        font_desc = pango.FontDescription()
122        font_prop_str =  gajim.config.get_per('themes', theme, option + 'attrs')
123        if font_prop_str:
124                if font_prop_str.find('B') != -1:
125                        font_desc.set_weight(pango.WEIGHT_BOLD)
126                if font_prop_str.find('I') != -1:
127                        font_desc.set_style(pango.STYLE_ITALIC)
128        fd = pango.FontDescription(font_name)
129        fd.merge(font_desc, True)
130        return fd.to_string()
131       
132def get_default_font():
133        '''Get the desktop setting for application font
134        first check for GNOME, then Xfce and last KDE
135        it returns None on failure or else a string 'Font Size' '''
136       
137        try:
138                import gconf
139                # in try because daemon may not be there
140                client = gconf.client_get_default()
141
142                return client.get_string('/desktop/gnome/interface/font_name'
143                        ).decode('utf-8')
144        except Exception:
145                pass
146
147        # try to get xfce default font
148        # Xfce 4.2 adopts freedesktop.org's Base Directory Specification
149        # see http://www.xfce.org/~benny/xfce/file-locations.html
150        # and http://freedesktop.org/Standards/basedir-spec
151        xdg_config_home = os.environ.get('XDG_CONFIG_HOME', '')
152        if xdg_config_home == '':
153                xdg_config_home = os.path.expanduser('~/.config') # default     
154        xfce_config_file = os.path.join(xdg_config_home, 'xfce4/mcs_settings/gtk.xml')
155       
156        kde_config_file = os.path.expanduser('~/.kde/share/config/kdeglobals')
157       
158        if os.path.exists(xfce_config_file):
159                try:
160                        for line in open(xfce_config_file):
161                                if line.find('name="Gtk/FontName"') != -1:
162                                        start = line.find('value="') + 7
163                                        return line[start:line.find('"', start)].decode('utf-8')
164                except Exception:
165                        #we talk about file
166                        print >> sys.stderr, _('Error: cannot open %s for reading') % xfce_config_file
167       
168        elif os.path.exists(kde_config_file):
169                try:
170                        for line in open(kde_config_file):
171                                if line.find('font=') == 0: # font=Verdana,9,other_numbers
172                                        start = 5 # 5 is len('font=')
173                                        line = line[start:]
174                                        values = line.split(',')
175                                        font_name = values[0]
176                                        font_size = values[1]
177                                        font_string = '%s %s' % (font_name, font_size) # Verdana 9
178                                        return font_string.decode('utf-8')
179                except Exception:
180                        #we talk about file
181                        print >> sys.stderr, _('Error: cannot open %s for reading') % kde_config_file
182       
183        return None
184       
185def autodetect_browser_mailer():
186        # recognize the environment and set appropriate browser/mailer
187        if user_runs_gnome():
188                gajim.config.set('openwith', 'gnome-open')
189        elif user_runs_kde():
190                gajim.config.set('openwith', 'kfmclient exec')
191        elif user_runs_xfce():
192                gajim.config.set('openwith', 'exo-open')
193        elif user_runs_osx():
194                gajim.config.set('openwith', 'open')
195        else:
196                gajim.config.set('openwith', 'custom')
197
198def user_runs_gnome():
199        return 'gnome-session' in get_running_processes()
200
201def user_runs_kde():
202        return 'startkde' in get_running_processes()
203
204def user_runs_xfce():
205        procs = get_running_processes()
206        if 'startxfce4' in procs or 'xfce4-session' in procs:
207                return True
208        return False
209
210def user_runs_osx():
211        return sys.platform == 'darwin'
212
213def get_running_processes():
214        '''returns running processes or None (if not /proc exists)'''
215        if os.path.isdir('/proc'):
216                # under Linux: checking if 'gnome-session' or
217                # 'startkde' programs were run before gajim, by
218                # checking /proc (if it exists)
219                #
220                # if something is unclear, read `man proc`;
221                # if /proc exists, directories that have only numbers
222                # in their names contain data about processes.
223                # /proc/[xxx]/exe is a symlink to executable started
224                # as process number [xxx].
225                # filter out everything that we are not interested in:
226                files = os.listdir('/proc')
227
228                # files that doesn't have only digits in names...
229                files = filter(str.isdigit, files)
230
231                # files that aren't directories...
232                files = filter(lambda f:os.path.isdir('/proc/' + f), files)
233
234                # processes owned by somebody not running gajim...
235                # (we check if we have access to that file)
236                files = filter(lambda f:os.access('/proc/' + f +'/exe', os.F_OK), files)
237
238                # be sure that /proc/[number]/exe is really a symlink
239                # to avoid TBs in incorrectly configured systems
240                files = filter(lambda f:os.path.islink('/proc/' + f + '/exe'), files)
241
242                # list of processes
243                processes = [os.path.basename(os.readlink('/proc/' + f +'/exe')) for f in files]
244               
245                return processes
246        return []
247
248def move_window(window, x, y):
249        '''moves the window but also checks if out of screen'''
250        if x < 0:
251                x = 0
252        if y < 0:
253                y = 0
254        w, h = window.get_size()
255        if x + w > screen_w:
256                x = screen_w - w
257        if y + h > screen_h:
258                y = screen_h - h
259        window.move(x, y)
260
261def resize_window(window, w, h):
262        '''resizes window but also checks if huge window or negative values'''
263        if not w or not h:
264                return
265        if w > screen_w:
266                w = screen_w
267        if h > screen_h:
268                h = screen_h
269        window.resize(abs(w), abs(h))
270
271class HashDigest:
272        def __init__(self, algo, digest):
273                self.algo = self.cleanID(algo)
274                self.digest = self.cleanID(digest)
275
276        def cleanID(self, id_):
277                id_ = id_.strip().lower()
278                for strip in (' :.-_'): id_ = id_.replace(strip, '')
279                return id_
280
281        def __eq__(self, other):
282                sa, sd = self.algo, self.digest
283                if isinstance(other, self.__class__):
284                        oa, od = other.algo, other.digest
285                elif isinstance(other, basestring):
286                        sa, oa, od = None, None, self.cleanID(other)
287                elif isinstance(other, tuple) and len(other) == 2:
288                        oa, od = self.cleanID(other[0]), self.cleanID(other[1])
289                else:
290                        return False
291
292                return sa == oa and sd == od
293
294        def __ne__(self, other):
295                return not self == other
296
297        def __hash__(self):
298                return self.algo ^ self.digest
299
300        def __str__(self):
301                prettydigest = ''
302                for i in xrange(0, len(self.digest), 2):
303                        prettydigest += self.digest[i:i + 2] + ':'
304                return prettydigest[:-1]
305
306        def __repr__(self):
307                return "%s(%s, %s)" % (self.__class__, repr(self.algo), repr(str(self)))
308
309class ServersXMLHandler(xml.sax.ContentHandler):
310        def __init__(self):
311                xml.sax.ContentHandler.__init__(self)
312                self.servers = []
313
314        def startElement(self, name, attributes):
315                if name == 'item':
316                        # we will get the port next time so we just set it 0 here
317                        sitem = [None, 0, {}]
318                        sitem[2]['digest'] = {}
319                        sitem[2]['hidden'] = False
320                        for attribute in attributes.getNames():
321                                if attribute == 'jid':
322                                        jid = attributes.getValue(attribute)
323                                        sitem[0] = jid
324                                elif attribute == 'hidden':
325                                        hidden = attributes.getValue(attribute)
326                                        if hidden.lower() in ('1', 'y', 'yes', 't', 'true', 'on'):
327                                                sitem[2]['hidden'] = True
328                        self.servers.append(sitem)
329                elif name == 'active':
330                        for attribute in attributes.getNames():
331                                if attribute == 'port':
332                                        port = attributes.getValue(attribute)
333                                        # we received the jid last time, so we now assign the port
334                                        # number to the last jid in the list
335                                        self.servers[-1][1] = port
336                elif name == 'digest':
337                        algo, digest = None, None
338                        for attribute in attributes.getNames():
339                                if attribute == 'algo':
340                                        algo = attributes.getValue(attribute)
341                                elif attribute == 'value':
342                                        digest = attributes.getValue(attribute)
343                        hd = HashDigest(algo, digest)
344                        self.servers[-1][2]['digest'][hd.algo] = hd
345
346        def endElement(self, name):
347                pass
348
349def parse_server_xml(path_to_file):
350        try:
351                handler = ServersXMLHandler()
352                xml.sax.parse(path_to_file, handler)
353                return handler.servers
354        # handle exception if unable to open file
355        except IOError, message:
356                print >> sys.stderr, _('Error reading file:'), message
357        # handle exception parsing file
358        except xml.sax.SAXParseException, message:
359                print >> sys.stderr, _('Error parsing file:'), message
360
361def set_unset_urgency_hint(window, unread_messages_no):
362        '''sets/unsets urgency hint in window argument
363        depending if we have unread messages or not'''
364        if gajim.config.get('use_urgency_hint'):
365                if unread_messages_no > 0:
366                        window.props.urgency_hint = True
367                else:
368                        window.props.urgency_hint = False
369
370def get_abspath_for_script(scriptname, want_type = False):
371        '''checks if we are svn or normal user and returns abspath to asked script
372        if want_type is True we return 'svn' or 'install' '''
373        if os.path.isdir('.svn'): # we are svn user
374                type = 'svn'
375                cwd = os.getcwd() # it's always ending with src
376
377                if scriptname == 'gajim-remote':
378                        path_to_script = cwd + '/gajim-remote.py'
379               
380                elif scriptname == 'gajim':
381                        script = '#!/bin/sh\n' # the script we may create
382                        script += 'cd %s' % cwd
383                        path_to_script = cwd + '/../scripts/gajim_sm_script'
384                               
385                        try:
386                                if os.path.exists(path_to_script):
387                                        os.remove(path_to_script)
388
389                                f = open(path_to_script, 'w')
390                                script += '\nexec python -OOt gajim.py $0 $@\n'
391                                f.write(script)
392                                f.close()
393                                os.chmod(path_to_script, 0700)
394                        except OSError: # do not traceback (could be a permission problem)
395                                #we talk about a file here
396                                s = _('Could not write to %s. Session Management support will not work') % path_to_script
397                                print >> sys.stderr, s
398
399        else: # normal user (not svn user)
400                type = 'install'
401                # always make it like '/usr/local/bin/gajim'
402                path_to_script = helpers.is_in_path(scriptname, True)
403               
404       
405        if want_type:
406                return path_to_script, type
407        else:
408                return path_to_script
409
410def get_pixbuf_from_data(file_data, want_type = False):
411        '''Gets image data and returns gtk.gdk.Pixbuf
412        if want_type is True it also returns 'jpeg', 'png' etc'''
413        pixbufloader = gtk.gdk.PixbufLoader()
414        try:
415                pixbufloader.write(file_data)
416                pixbufloader.close()
417                pixbuf = pixbufloader.get_pixbuf()
418        except gobject.GError: # 'unknown image format'
419                pixbufloader.close()
420                pixbuf = None
421                if want_type:
422                        return None, None
423                else:
424                        return None
425
426        if want_type:
427                typ = pixbufloader.get_format()['name']
428                return pixbuf, typ
429        else:
430                return pixbuf
431
432def get_invisible_cursor():
433        pixmap = gtk.gdk.Pixmap(None, 1, 1, 1)
434        color = gtk.gdk.Color()
435        cursor = gtk.gdk.Cursor(pixmap, pixmap, color, color, 0, 0)
436        return cursor
437
438def get_current_desktop(window):
439        '''returns the current virtual desktop for given window
440        NOTE: window is GDK window'''
441        prop = window.property_get('_NET_CURRENT_DESKTOP')
442        if prop is None: # it means it's normal window (not root window)
443                # so we look for it's current virtual desktop in another property
444                prop = window.property_get('_NET_WM_DESKTOP')
445
446        if prop is not None:
447                # f.e. prop is ('CARDINAL', 32, [0]) we want 0 or 1.. from [0]
448                current_virtual_desktop_no = prop[2][0]
449                return current_virtual_desktop_no
450
451def possibly_move_window_in_current_desktop(window):
452        '''moves GTK window to current virtual desktop if it is not in the
453        current virtual desktop
454        window is GTK window'''
455        if os.name == 'nt':
456                return False
457
458        root_window = gtk.gdk.screen_get_default().get_root_window()
459        # current user's vd
460        current_virtual_desktop_no = get_current_desktop(root_window)
461       
462        # vd roster window is in
463        window_virtual_desktop = get_current_desktop(window.window)
464
465        # if one of those is None, something went wrong and we cannot know
466        # VD info, just hide it (default action) and not show it afterwards
467        if None not in (window_virtual_desktop, current_virtual_desktop_no):
468                if current_virtual_desktop_no != window_virtual_desktop:
469                        # we are in another VD that the window was
470                        # so show it in current VD
471                        window.present()
472                        return True
473        return False
474
475def file_is_locked(path_to_file):
476        '''returns True if file is locked (WINDOWS ONLY)'''
477        if os.name != 'nt': # just in case
478                return
479       
480        if not HAS_PYWIN32:
481                return
482       
483        secur_att = pywintypes.SECURITY_ATTRIBUTES()
484        secur_att.Initialize()
485       
486        try:
487                # try make a handle for READING the file
488                hfile = win32file.CreateFile(
489                        path_to_file,                                   # path to file
490                        win32con.GENERIC_READ,                  # open for reading
491                        0,                                                              # do not share with other proc
492                        secur_att,
493                        win32con.OPEN_EXISTING,                 # existing file only
494                        win32con.FILE_ATTRIBUTE_NORMAL, # normal file
495                        0                                                               # no attr. template
496                )
497        except pywintypes.error, e:
498                return True
499        else: # in case all went ok, close file handle (go to hell WinAPI)
500                hfile.Close()
501                return False
502
503def _get_fade_color(treeview, selected, focused):
504        '''get a gdk color that is between foreground and background in 0.3
505        0.7 respectively colors of the cell for the given treeview'''
506        style = treeview.style
507        if selected:
508                if focused: # is the window focused?
509                        state = gtk.STATE_SELECTED
510                else: # is it not? NOTE: many gtk themes change bg on this
511                        state = gtk.STATE_ACTIVE
512        else:
513                state = gtk.STATE_NORMAL
514        bg = style.base[state]
515        fg = style.text[state]
516
517        p = 0.3 # background
518        q = 0.7 # foreground # p + q should do 1.0
519        return gtk.gdk.Color(int(bg.red*p + fg.red*q),
520                                        int(bg.green*p + fg.green*q),
521                                        int(bg.blue*p + fg.blue*q))
522
523def get_scaled_pixbuf(pixbuf, kind):
524        '''returns scaled pixbuf, keeping ratio etc or None
525        kind is either "chat", "roster", "notification", "tooltip", "vcard"'''
526       
527        # resize to a width / height for the avatar not to have distortion
528        # (keep aspect ratio)
529        width = gajim.config.get(kind + '_avatar_width')
530        height = gajim.config.get(kind + '_avatar_height')
531        if width < 1 or height < 1:
532                return None
533
534        # Pixbuf size
535        pix_width = pixbuf.get_width()
536        pix_height = pixbuf.get_height()
537        # don't make avatars bigger than they are
538        if pix_width < width and pix_height < height:
539                return pixbuf # we don't want to make avatar bigger
540
541        ratio = float(pix_width) / float(pix_height)
542        if ratio > 1:
543                w = width
544                h = int(w / ratio)
545        else:
546                h = height
547                w = int(h * ratio)
548        scaled_buf = pixbuf.scale_simple(w, h, gtk.gdk.INTERP_HYPER)
549        return scaled_buf
550
551def get_avatar_pixbuf_from_cache(fjid, is_fake_jid = False, use_local = True):
552        '''checks if jid has cached avatar and if that avatar is valid image
553        (can be shown)
554        returns None if there is no image in vcard
555        returns 'ask' if cached vcard should not be used (user changed his vcard,
556        so we have new sha) or if we don't have the vcard'''
557
558        jid, nick = gajim.get_room_and_nick_from_fjid(fjid)
559        if gajim.config.get('hide_avatar_of_transport') and\
560                gajim.jid_is_transport(jid):
561                # don't show avatar for the transport itself
562                return None
563
564        puny_jid = helpers.sanitize_filename(jid)
565        if is_fake_jid:
566                puny_nick = helpers.sanitize_filename(nick)
567                path = os.path.join(gajim.VCARD_PATH, puny_jid, puny_nick)
568                local_avatar_basepath = os.path.join(gajim.AVATAR_PATH, puny_jid,
569                        puny_nick) + '_local'
570        else:
571                path = os.path.join(gajim.VCARD_PATH, puny_jid)
572                local_avatar_basepath = os.path.join(gajim.AVATAR_PATH, puny_jid) + \
573                        '_local'
574        if use_local:
575                for extension in ('.png', '.jpeg'):
576                        local_avatar_path = local_avatar_basepath + extension
577                        if os.path.isfile(local_avatar_path):
578                                avatar_file = open(local_avatar_path, 'rb')
579                                avatar_data = avatar_file.read()
580                                avatar_file.close()
581                                return get_pixbuf_from_data(avatar_data)
582
583        if not os.path.isfile(path):
584                return 'ask'
585
586        vcard_dict = gajim.connections.values()[0].get_cached_vcard(fjid,
587                is_fake_jid)
588        if not vcard_dict: # This can happen if cached vcard is too old
589                return 'ask'
590        if 'PHOTO' not in vcard_dict:
591                return None
592        pixbuf = vcard.get_avatar_pixbuf_encoded_mime(vcard_dict['PHOTO'])[0]
593        return pixbuf
594
595def make_gtk_month_python_month(month):
596        '''gtk start counting months from 0, so January is 0
597        but python's time start from 1, so align to python
598        month MUST be integer'''
599        return month + 1
600
601def make_python_month_gtk_month(month):
602        return month - 1
603
604def make_color_string(color):
605        '''create #aabbcc color string from gtk color'''
606        col = '#'
607        for i in ('red', 'green', 'blue'):
608                h = hex(getattr(color, i) / (16*16)).split('x')[1]
609                if len(h) == 1:
610                        h = '0' + h
611                col += h
612        return col
613
614def make_pixbuf_grayscale(pixbuf):
615        pixbuf2 = pixbuf.copy()
616        pixbuf.saturate_and_pixelate(pixbuf2, 0.0, False)
617        return pixbuf2
618
619def get_path_to_generic_or_avatar(generic, jid = None, suffix = None):
620        '''Chooses between avatar image and default image.
621        Returns full path to the avatar image if it exists,
622        otherwise returns full path to the image.
623        generic must be with extension and suffix without'''
624        if jid:
625                # we want an avatar
626                puny_jid = helpers.sanitize_filename(jid)
627                path_to_file = os.path.join(gajim.AVATAR_PATH, puny_jid) + suffix
628                path_to_local_file = path_to_file + '_local'
629                for extension in ('.png', '.jpeg'):
630                        path_to_local_file_full = path_to_local_file + extension
631                        if os.path.exists(path_to_local_file_full):
632                                return path_to_local_file_full
633                for extension in ('.png', '.jpeg'):
634                        path_to_file_full = path_to_file + extension
635                        if os.path.exists(path_to_file_full):
636                                return path_to_file_full
637        return os.path.abspath(generic)
638
639def decode_filechooser_file_paths(file_paths):
640        '''decode as UTF-8 under Windows and
641        ask sys.getfilesystemencoding() in POSIX
642        file_paths MUST be LIST'''
643        file_paths_list = list()
644       
645        if os.name == 'nt': # decode as UTF-8 under Windows
646                for file_path in file_paths:
647                        file_path = file_path.decode('utf8')
648                        file_paths_list.append(file_path)
649        else:
650                for file_path in file_paths:
651                        try:
652                                file_path = file_path.decode(sys.getfilesystemencoding())
653                        except Exception:
654                                try:
655                                        file_path = file_path.decode('utf-8')
656                                except Exception:
657                                        pass
658                        file_paths_list.append(file_path)
659       
660        return file_paths_list
661
662def possibly_set_gajim_as_xmpp_handler():
663        '''registers (by default only the first time) xmmp: to Gajim.'''
664        path_to_dot_kde = os.path.expanduser('~/.kde')
665        if os.path.exists(path_to_dot_kde):
666                path_to_kde_file = os.path.join(path_to_dot_kde, 
667                        'share/services/xmpp.protocol')
668        else:
669                path_to_kde_file = None
670
671        def set_gajim_as_xmpp_handler(is_checked=None):
672                if is_checked is not None:
673                        # come from confirmation dialog
674                        gajim.config.set('check_if_gajim_is_default', is_checked)
675                path_to_gajim_script, typ = get_abspath_for_script('gajim-remote', True