Automated merge with ssh://hg@gajim.org/gajim
This commit is contained in:
commit
528a01ff9d
38 changed files with 19 additions and 2936 deletions
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
echo "[encoding: UTF-8]" > po/POTFILES.in \
|
echo "[encoding: UTF-8]" > po/POTFILES.in \
|
||||||
&& ls -1 data/gajim.desktop.in.in data/glade/*.glade \
|
&& ls -1 data/gajim.desktop.in.in data/glade/*.glade \
|
||||||
src/*py src/common/*py src/common/zeroconf/*.py src/osx/*.py >> \
|
src/*py src/common/*py src/common/zeroconf/*.py >> \
|
||||||
po/POTFILES.in || exit 1
|
po/POTFILES.in || exit 1
|
||||||
if test -z `which pkg-config 2>/dev/null`;then
|
if test -z `which pkg-config 2>/dev/null`;then
|
||||||
echo "***Error: pkg-config not found***"
|
echo "***Error: pkg-config not found***"
|
||||||
|
|
71
configure.ac
71
configure.ac
|
@ -59,72 +59,6 @@ AC_ARG_ENABLE(trayicon,
|
||||||
test "x$enable_trayicon" = "xyes" && have_trayicon=true || have_trayicon=false
|
test "x$enable_trayicon" = "xyes" && have_trayicon=true || have_trayicon=false
|
||||||
AM_CONDITIONAL(BUILD_TRAYICON, $have_trayicon)
|
AM_CONDITIONAL(BUILD_TRAYICON, $have_trayicon)
|
||||||
|
|
||||||
dnl ****
|
|
||||||
dnl Cocoa
|
|
||||||
dnl ****
|
|
||||||
AC_ARG_ENABLE([cocoa],
|
|
||||||
[ --disable-cocoa do not build cocoa integration [default auto]],
|
|
||||||
enable_cocoa=$enableval, enable_cocoa=yes)
|
|
||||||
|
|
||||||
if test "x$enable_cocoa" = "xyes";then
|
|
||||||
dnl There is no pkgconfig for cocoa; lets do a header check
|
|
||||||
temp_save_cflags="$CFLAGS"
|
|
||||||
CFLAGS="$CFLAGS -ObjC"
|
|
||||||
AC_CHECK_HEADER(Cocoa/Cocoa.h, [have_cocoa=true], [have_cocoa=false])
|
|
||||||
AC_CHECK_HEADER(AppKit/AppKit.h, [have_appkit=true], [have_appkit=false])
|
|
||||||
CFLAGS="$temp_save_cflags"
|
|
||||||
|
|
||||||
if test "x$have_cocoa" = "xtrue";then
|
|
||||||
COCOA_LIBS="$COCOA_LIBS -Xlinker -framework -Xlinker Cocoa"
|
|
||||||
fi
|
|
||||||
if test "x$have_appkit" = "xtrue";then
|
|
||||||
COCOA_LIBS="$COCOA_LIBS -Xlinker -framework -Xlinker AppKit"
|
|
||||||
fi
|
|
||||||
if test "x$COCOA_LIBS" != "x";then
|
|
||||||
AC_SUBST(COCOA_LIBS)
|
|
||||||
true
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
AM_CONDITIONAL(BUILD_COCOA, $have_cocoa)
|
|
||||||
|
|
||||||
dnl ****
|
|
||||||
dnl Carbon
|
|
||||||
dnl ****
|
|
||||||
AC_ARG_ENABLE([carbon],
|
|
||||||
[ --disable-carbon do not build with carbon [default auto]],
|
|
||||||
enable_carbon=$enableval, enable_carbon=yes)
|
|
||||||
|
|
||||||
if test "x$enable_carbon" = "xyes";then
|
|
||||||
dnl There is no pkgconfig for carbon; lets do a header check
|
|
||||||
AC_CHECK_HEADER(Carbon/Carbon.h, [have_carbon=true], [have_carbon=false])
|
|
||||||
AC_CHECK_HEADER(IOKit/IOKitLib.h, [have_iokit=true], [have_iokit=false])
|
|
||||||
|
|
||||||
if test "x$have_carbon" = "xtrue";then
|
|
||||||
CARBON_LIBS="$CARBON_LIBS -Xlinker -framework -Xlinker Carbon"
|
|
||||||
fi
|
|
||||||
if test "x$have_iokit" = "xtrue";then
|
|
||||||
CARBON_LIBS="$CARBON_LIBS -Xlinker -framework -Xlinker IOKit"
|
|
||||||
fi
|
|
||||||
if test "x$CARBON_LIBS" != "x";then
|
|
||||||
AC_SUBST(CARBON_LIBS)
|
|
||||||
have_idle_osx=true
|
|
||||||
dnl Disable custom trayicon
|
|
||||||
have_trayicon=gtk+
|
|
||||||
AM_CONDITIONAL(BUILD_TRAYICON, false)
|
|
||||||
dnl Hack to work around failure in gettext package detection on OS/X
|
|
||||||
if test "x$GMSGFMT" = "x";then
|
|
||||||
AC_SUBST(GMSGFMT, msgfmt)
|
|
||||||
AC_SUBST(MSGFMT, msgfmt)
|
|
||||||
AC_SUBST(XGETTEXT, xgettext)
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
have_carbon=false
|
|
||||||
have_idle_osx=false
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
AM_CONDITIONAL(BUILD_IDLE_OSX, $have_carbon)
|
|
||||||
AM_CONDITIONAL(BUILD_CARBON, $have_carbon)
|
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS="\${ACLOCAL_FLAGS}"
|
ACLOCAL_AMFLAGS="\${ACLOCAL_FLAGS}"
|
||||||
AC_SUBST(ACLOCAL_AMFLAGS)
|
AC_SUBST(ACLOCAL_AMFLAGS)
|
||||||
|
|
||||||
|
@ -151,9 +85,6 @@ AC_CONFIG_FILES([
|
||||||
data/gajim.desktop.in
|
data/gajim.desktop.in
|
||||||
data/defs.py
|
data/defs.py
|
||||||
src/Makefile
|
src/Makefile
|
||||||
src/osx/Makefile
|
|
||||||
src/osx/growl/Makefile
|
|
||||||
src/osx/syncmenu/Makefile
|
|
||||||
scripts/gajim
|
scripts/gajim
|
||||||
scripts/gajim-remote:scripts/gajim.in
|
scripts/gajim-remote:scripts/gajim.in
|
||||||
scripts/gajim-history-manager:scripts/gajim.in
|
scripts/gajim-history-manager:scripts/gajim.in
|
||||||
|
@ -164,6 +95,4 @@ echo "
|
||||||
*****************************
|
*****************************
|
||||||
Build features:
|
Build features:
|
||||||
trayicon ......... ${have_trayicon}
|
trayicon ......... ${have_trayicon}
|
||||||
idle module OSX .. ${have_idle_osx}
|
|
||||||
cocoa (OSX)....... ${have_cocoa}
|
|
||||||
*****************************"
|
*****************************"
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
SUBDIRS = osx
|
|
||||||
|
|
||||||
CLEANFILES = \
|
CLEANFILES = \
|
||||||
trayicon.c
|
trayicon.c
|
||||||
INCLUDES = \
|
INCLUDES = \
|
||||||
|
|
|
@ -59,16 +59,10 @@ class Config:
|
||||||
DEFAULT_ICONSET = 'dcraven'
|
DEFAULT_ICONSET = 'dcraven'
|
||||||
DEFAULT_MOOD_ICONSET = 'default'
|
DEFAULT_MOOD_ICONSET = 'default'
|
||||||
DEFAULT_ACTIVITY_ICONSET = 'default'
|
DEFAULT_ACTIVITY_ICONSET = 'default'
|
||||||
if sys.platform == 'darwin':
|
DEFAULT_OPENWITH = 'gnome-open'
|
||||||
DEFAULT_OPENWITH = 'open'
|
DEFAULT_BROWSER = 'firefox'
|
||||||
DEFAULT_BROWSER = 'open -a Safari'
|
DEFAULT_MAILAPP = 'mozilla-thunderbird -compose'
|
||||||
DEFAULT_MAILAPP = 'open -a Mail'
|
DEFAULT_FILE_MANAGER = 'xffm'
|
||||||
DEFAULT_FILE_MANAGER = 'open -a Finder'
|
|
||||||
else:
|
|
||||||
DEFAULT_OPENWITH = 'gnome-open'
|
|
||||||
DEFAULT_BROWSER = 'firefox'
|
|
||||||
DEFAULT_MAILAPP = 'mozilla-thunderbird -compose'
|
|
||||||
DEFAULT_FILE_MANAGER = 'xffm'
|
|
||||||
|
|
||||||
__options = {
|
__options = {
|
||||||
# name: [ type, default_value, help_string ]
|
# name: [ type, default_value, help_string ]
|
||||||
|
|
|
@ -32,12 +32,6 @@ from common import exceptions
|
||||||
_GAJIM_ERROR_IFACE = 'org.gajim.dbus.Error'
|
_GAJIM_ERROR_IFACE = 'org.gajim.dbus.Error'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if sys.platform == 'darwin':
|
|
||||||
try:
|
|
||||||
import osx.dbus
|
|
||||||
osx.dbus.load(True)
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
import dbus
|
import dbus
|
||||||
import dbus.glib
|
import dbus.glib
|
||||||
# test if dbus-x11 is installed
|
# test if dbus-x11 is installed
|
||||||
|
|
|
@ -367,11 +367,7 @@ def get_file_path_from_dnd_dropped_uri(uri):
|
||||||
if re.match('^file:///[a-zA-Z]:/', path): # windows
|
if re.match('^file:///[a-zA-Z]:/', path): # windows
|
||||||
path = path[8:] # 8 is len('file:///')
|
path = path[8:] # 8 is len('file:///')
|
||||||
elif path.startswith('file://'): # nautilus, rox
|
elif path.startswith('file://'): # nautilus, rox
|
||||||
if sys.platform == 'darwin':
|
path = path[7:] # 7 is len('file://')
|
||||||
# OS/X includes hostname in file:// URI
|
|
||||||
path = re.sub('file://[^/]*', '', path)
|
|
||||||
else:
|
|
||||||
path = path[7:] # 7 is len('file://')
|
|
||||||
elif path.startswith('file:'): # xffm
|
elif path.startswith('file:'): # xffm
|
||||||
path = path[5:] # 5 is len('file:')
|
path = path[5:] # 5 is len('file:')
|
||||||
return path
|
return path
|
||||||
|
@ -638,11 +634,6 @@ def compute_caps_hash(identities, features, dataforms=[], hash_method='sha-1'):
|
||||||
import gajim
|
import gajim
|
||||||
import pep
|
import pep
|
||||||
|
|
||||||
try:
|
|
||||||
from osx import nsapp
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def convert_bytes(string):
|
def convert_bytes(string):
|
||||||
suffix = ''
|
suffix = ''
|
||||||
|
@ -723,9 +714,6 @@ def launch_browser_mailer(kind, uri):
|
||||||
command = 'kfmclient exec'
|
command = 'kfmclient exec'
|
||||||
elif gajim.config.get('openwith') == 'exo-open':
|
elif gajim.config.get('openwith') == 'exo-open':
|
||||||
command = 'exo-open'
|
command = 'exo-open'
|
||||||
elif ((sys.platform == 'darwin') and\
|
|
||||||
(gajim.config.get('openwith') == 'open')):
|
|
||||||
command = 'open'
|
|
||||||
elif gajim.config.get('openwith') == 'custom':
|
elif gajim.config.get('openwith') == 'custom':
|
||||||
if kind == 'url':
|
if kind == 'url':
|
||||||
command = gajim.config.get('custombrowser')
|
command = gajim.config.get('custombrowser')
|
||||||
|
@ -753,9 +741,6 @@ def launch_file_manager(path_to_open):
|
||||||
command = 'kfmclient exec'
|
command = 'kfmclient exec'
|
||||||
elif gajim.config.get('openwith') == 'exo-open':
|
elif gajim.config.get('openwith') == 'exo-open':
|
||||||
command = 'exo-open'
|
command = 'exo-open'
|
||||||
elif ((sys.platform == 'darwin') and\
|
|
||||||
(gajim.config.get('openwith') == 'open')):
|
|
||||||
command = 'open'
|
|
||||||
elif gajim.config.get('openwith') == 'custom':
|
elif gajim.config.get('openwith') == 'custom':
|
||||||
command = gajim.config.get('custom_file_manager')
|
command = gajim.config.get('custom_file_manager')
|
||||||
if command == '': # if no app is configured
|
if command == '': # if no app is configured
|
||||||
|
@ -819,11 +804,6 @@ def play_sound_file(path_to_soundfile):
|
||||||
path_to_soundfile = check_soundfile_path(path_to_soundfile)
|
path_to_soundfile = check_soundfile_path(path_to_soundfile)
|
||||||
if path_to_soundfile is None:
|
if path_to_soundfile is None:
|
||||||
return
|
return
|
||||||
if sys.platform == 'darwin':
|
|
||||||
try:
|
|
||||||
nsapp.playFile(path_to_soundfile)
|
|
||||||
except NameError:
|
|
||||||
pass
|
|
||||||
elif os.name == 'nt':
|
elif os.name == 'nt':
|
||||||
try:
|
try:
|
||||||
winsound.PlaySound(path_to_soundfile,
|
winsound.PlaySound(path_to_soundfile,
|
||||||
|
|
|
@ -43,9 +43,6 @@ try:
|
||||||
|
|
||||||
lastInputInfo = LASTINPUTINFO()
|
lastInputInfo = LASTINPUTINFO()
|
||||||
lastInputInfo.cbSize = ctypes.sizeof(lastInputInfo)
|
lastInputInfo.cbSize = ctypes.sizeof(lastInputInfo)
|
||||||
|
|
||||||
elif sys.platform == 'darwin':
|
|
||||||
import osx.idle as idle
|
|
||||||
else: # unix
|
else: # unix
|
||||||
from common import idle
|
from common import idle
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
|
@ -437,15 +437,6 @@ class PreferencesWindow:
|
||||||
self.xml.get_widget('custom_apps_frame').hide()
|
self.xml.get_widget('custom_apps_frame').hide()
|
||||||
self.xml.get_widget('custom_apps_frame').set_no_show_all(True)
|
self.xml.get_widget('custom_apps_frame').set_no_show_all(True)
|
||||||
|
|
||||||
if sys.platform == 'darwin':
|
|
||||||
self.applications_combobox.remove_text(4)
|
|
||||||
self.applications_combobox.remove_text(3)
|
|
||||||
self.applications_combobox.remove_text(2)
|
|
||||||
self.applications_combobox.remove_text(1)
|
|
||||||
self.applications_combobox.append_text(
|
|
||||||
_('Always use OS/X default applications'))
|
|
||||||
self.applications_combobox.append_text(_('Custom'))
|
|
||||||
|
|
||||||
if gajim.config.get('autodetect_browser_mailer'):
|
if gajim.config.get('autodetect_browser_mailer'):
|
||||||
self.applications_combobox.set_active(0)
|
self.applications_combobox.set_active(0)
|
||||||
# else autodetect_browser_mailer is False.
|
# else autodetect_browser_mailer is False.
|
||||||
|
@ -456,14 +447,8 @@ class PreferencesWindow:
|
||||||
self.applications_combobox.set_active(2)
|
self.applications_combobox.set_active(2)
|
||||||
elif gajim.config.get('openwith') == 'exo-open':
|
elif gajim.config.get('openwith') == 'exo-open':
|
||||||
self.applications_combobox.set_active(3)
|
self.applications_combobox.set_active(3)
|
||||||
elif ((sys.platform == 'darwin') and\
|
|
||||||
(gajim.config.get('openwith') == 'open')):
|
|
||||||
self.applications_combobox.set_active(1)
|
|
||||||
elif gajim.config.get('openwith') == 'custom':
|
elif gajim.config.get('openwith') == 'custom':
|
||||||
if sys.platform == 'darwin':
|
self.applications_combobox.set_active(4)
|
||||||
self.applications_combobox.set_active(2)
|
|
||||||
else:
|
|
||||||
self.applications_combobox.set_active(4)
|
|
||||||
self.xml.get_widget('custom_apps_frame').show()
|
self.xml.get_widget('custom_apps_frame').show()
|
||||||
|
|
||||||
self.xml.get_widget('custom_browser_entry').set_text(
|
self.xml.get_widget('custom_browser_entry').set_text(
|
||||||
|
@ -962,30 +947,19 @@ class PreferencesWindow:
|
||||||
|
|
||||||
def on_applications_combobox_changed(self, widget):
|
def on_applications_combobox_changed(self, widget):
|
||||||
gajim.config.set('autodetect_browser_mailer', False)
|
gajim.config.set('autodetect_browser_mailer', False)
|
||||||
if sys.platform == 'darwin':
|
if widget.get_active() == 4:
|
||||||
|
self.xml.get_widget('custom_apps_frame').show()
|
||||||
|
gajim.config.set('openwith', 'custom')
|
||||||
|
else:
|
||||||
if widget.get_active() == 0:
|
if widget.get_active() == 0:
|
||||||
gajim.config.set('autodetect_browser_mailer', True)
|
gajim.config.set('autodetect_browser_mailer', True)
|
||||||
self.xml.get_widget('custom_apps_frame').hide()
|
|
||||||
elif widget.get_active() == 1:
|
elif widget.get_active() == 1:
|
||||||
self.xml.get_widget('custom_apps_frame').hide()
|
gajim.config.set('openwith', 'gnome-open')
|
||||||
gajim.config.set('openwith', 'open')
|
|
||||||
elif widget.get_active() == 2:
|
elif widget.get_active() == 2:
|
||||||
self.xml.get_widget('custom_apps_frame').show()
|
gajim.config.set('openwith', 'kfmclient exec')
|
||||||
gajim.config.set('openwith', 'custom')
|
elif widget.get_active() == 3:
|
||||||
else:
|
gajim.config.set('openwith', 'exo-open')
|
||||||
if widget.get_active() == 4:
|
self.xml.get_widget('custom_apps_frame').hide()
|
||||||
self.xml.get_widget('custom_apps_frame').show()
|
|
||||||
gajim.config.set('openwith', 'custom')
|
|
||||||
else:
|
|
||||||
if widget.get_active() == 0:
|
|
||||||
gajim.config.set('autodetect_browser_mailer', True)
|
|
||||||
elif widget.get_active() == 1:
|
|
||||||
gajim.config.set('openwith', 'gnome-open')
|
|
||||||
elif widget.get_active() == 2:
|
|
||||||
gajim.config.set('openwith', 'kfmclient exec')
|
|
||||||
elif widget.get_active() == 3:
|
|
||||||
gajim.config.set('openwith', 'exo-open')
|
|
||||||
self.xml.get_widget('custom_apps_frame').hide()
|
|
||||||
gajim.interface.save_config()
|
gajim.interface.save_config()
|
||||||
|
|
||||||
def on_custom_browser_entry_changed(self, widget):
|
def on_custom_browser_entry_changed(self, widget):
|
||||||
|
|
|
@ -224,12 +224,6 @@ class FeaturesWindow:
|
||||||
def notification_available(self):
|
def notification_available(self):
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
return False
|
return False
|
||||||
elif sys.platform == 'darwin':
|
|
||||||
try:
|
|
||||||
import osx.growler
|
|
||||||
except Exception:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
from common import dbus_support
|
from common import dbus_support
|
||||||
if self.dbus_available() and dbus_support.get_notifications_interface():
|
if self.dbus_available() and dbus_support.get_notifications_interface():
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -46,9 +46,6 @@ def send_error(error_message):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if sys.platform == 'darwin':
|
|
||||||
import osx.dbus
|
|
||||||
osx.dbus.load(False)
|
|
||||||
import dbus
|
import dbus
|
||||||
import dbus.service
|
import dbus.service
|
||||||
import dbus.glib
|
import dbus.glib
|
||||||
|
|
28
src/gajim.py
28
src/gajim.py
|
@ -54,13 +54,6 @@ if os.name == 'nt':
|
||||||
os.environ['PATH'] = ';'.join(new_list)
|
os.environ['PATH'] = ';'.join(new_list)
|
||||||
os.environ['GTK_BASEPATH'] = 'gtk'
|
os.environ['GTK_BASEPATH'] = 'gtk'
|
||||||
|
|
||||||
import sys
|
|
||||||
if sys.platform == 'darwin':
|
|
||||||
try:
|
|
||||||
import osx
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
# needed for docutils
|
# needed for docutils
|
||||||
sys.path.append('.')
|
sys.path.append('.')
|
||||||
|
@ -316,12 +309,6 @@ def pid_alive():
|
||||||
if get_p(pid) in ('python.exe', 'gajim.exe'):
|
if get_p(pid) in ('python.exe', 'gajim.exe'):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
elif sys.platform == 'darwin':
|
|
||||||
try:
|
|
||||||
from osx import checkPID
|
|
||||||
return checkPID(pid, 'Gajim.bin')
|
|
||||||
except ImportError:
|
|
||||||
return
|
|
||||||
try:
|
try:
|
||||||
if not os.path.exists('/proc'):
|
if not os.path.exists('/proc'):
|
||||||
return True # no /proc, assume Gajim is running
|
return True # no /proc, assume Gajim is running
|
||||||
|
@ -388,11 +375,6 @@ def on_exit():
|
||||||
os.remove(pid_filename)
|
os.remove(pid_filename)
|
||||||
# Shutdown GUI and save config
|
# Shutdown GUI and save config
|
||||||
gajim.interface.roster.prepare_quit()
|
gajim.interface.roster.prepare_quit()
|
||||||
if sys.platform == 'darwin':
|
|
||||||
try:
|
|
||||||
osx.shutdown()
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
import atexit
|
import atexit
|
||||||
atexit.register(on_exit)
|
atexit.register(on_exit)
|
||||||
|
@ -3418,7 +3400,7 @@ class Interface:
|
||||||
self.systray_enabled = False
|
self.systray_enabled = False
|
||||||
self.systray_capabilities = False
|
self.systray_capabilities = False
|
||||||
|
|
||||||
if (os.name == 'nt') or (sys.platform == 'darwin'):
|
if (os.name == 'nt'):
|
||||||
import statusicon
|
import statusicon
|
||||||
self.systray = statusicon.StatusIcon()
|
self.systray = statusicon.StatusIcon()
|
||||||
self.systray_capabilities = True
|
self.systray_capabilities = True
|
||||||
|
@ -3508,7 +3490,7 @@ if __name__ == '__main__':
|
||||||
log.info("Encodings: d:%s, fs:%s, p:%s", sys.getdefaultencoding(), \
|
log.info("Encodings: d:%s, fs:%s, p:%s", sys.getdefaultencoding(), \
|
||||||
sys.getfilesystemencoding(), locale.getpreferredencoding())
|
sys.getfilesystemencoding(), locale.getpreferredencoding())
|
||||||
|
|
||||||
if ((os.name != 'nt') and (sys.platform != 'darwin')):
|
if os.name != 'nt':
|
||||||
# Session Management support
|
# Session Management support
|
||||||
try:
|
try:
|
||||||
import gnome.ui
|
import gnome.ui
|
||||||
|
@ -3536,12 +3518,6 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
check_paths.check_and_possibly_create_paths()
|
check_paths.check_and_possibly_create_paths()
|
||||||
|
|
||||||
if sys.platform == 'darwin':
|
|
||||||
try:
|
|
||||||
osx.init()
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
Interface()
|
Interface()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -190,8 +190,6 @@ def autodetect_browser_mailer():
|
||||||
gajim.config.set('openwith', 'kfmclient exec')
|
gajim.config.set('openwith', 'kfmclient exec')
|
||||||
elif user_runs_xfce():
|
elif user_runs_xfce():
|
||||||
gajim.config.set('openwith', 'exo-open')
|
gajim.config.set('openwith', 'exo-open')
|
||||||
elif user_runs_osx():
|
|
||||||
gajim.config.set('openwith', 'open')
|
|
||||||
else:
|
else:
|
||||||
gajim.config.set('openwith', 'custom')
|
gajim.config.set('openwith', 'custom')
|
||||||
|
|
||||||
|
@ -207,9 +205,6 @@ def user_runs_xfce():
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def user_runs_osx():
|
|
||||||
return sys.platform == 'darwin'
|
|
||||||
|
|
||||||
def get_running_processes():
|
def get_running_processes():
|
||||||
'''returns running processes or None (if not /proc exists)'''
|
'''returns running processes or None (if not /proc exists)'''
|
||||||
if os.path.isdir('/proc'):
|
if os.path.isdir('/proc'):
|
||||||
|
|
|
@ -56,9 +56,7 @@ supported = False
|
||||||
|
|
||||||
from common import dbus_support
|
from common import dbus_support
|
||||||
|
|
||||||
if sys.platform == 'darwin':
|
if dbus_support.supported:
|
||||||
supported = True
|
|
||||||
elif dbus_support.supported:
|
|
||||||
import dbus
|
import dbus
|
||||||
import dbus.glib
|
import dbus.glib
|
||||||
|
|
||||||
|
|
|
@ -50,13 +50,6 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
USER_HAS_PYNOTIFY = False
|
USER_HAS_PYNOTIFY = False
|
||||||
|
|
||||||
USER_HAS_GROWL = True
|
|
||||||
try:
|
|
||||||
import osx.growler
|
|
||||||
osx.growler.init()
|
|
||||||
except Exception:
|
|
||||||
USER_HAS_GROWL = False
|
|
||||||
|
|
||||||
if gajim.HAVE_INDICATOR:
|
if gajim.HAVE_INDICATOR:
|
||||||
import indicate
|
import indicate
|
||||||
|
|
||||||
|
@ -358,13 +351,6 @@ def popup(event_type, jid, account, msg_type='', path_to_image=None,
|
||||||
indicator.connect('user-display', display, account, jid, msg_type)
|
indicator.connect('user-display', display, account, jid, msg_type)
|
||||||
indicator.show()
|
indicator.show()
|
||||||
|
|
||||||
# Try Growl first, as we might have D-Bus and notification daemon running
|
|
||||||
# on OS X for some reason.
|
|
||||||
if USER_HAS_GROWL:
|
|
||||||
osx.growler.notify(event_type, jid, account, msg_type, path_to_image,
|
|
||||||
title, text)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Try to show our popup via D-Bus and notification daemon
|
# Try to show our popup via D-Bus and notification daemon
|
||||||
if gajim.config.get('use_notif_daemon') and dbus_support.supported:
|
if gajim.config.get('use_notif_daemon') and dbus_support.supported:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
SUBDIRS = growl syncmenu
|
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I ../m4
|
|
||||||
|
|
||||||
OBJC = gcc
|
|
||||||
|
|
||||||
export MACOSX_DEPLOYMENT_TARGET=10.4
|
|
||||||
INCLUDES = \
|
|
||||||
$(PYTHON_INCLUDES)
|
|
||||||
|
|
||||||
if BUILD_IDLE_OSX
|
|
||||||
idlelib_LTLIBRARIES = idle.la
|
|
||||||
idlelibdir = $(pkglibdir)
|
|
||||||
|
|
||||||
idle_la_LIBADD = $(CARBON_LIBS)
|
|
||||||
|
|
||||||
idle_la_SOURCES = idle.c
|
|
||||||
|
|
||||||
idle_la_LDFLAGS = \
|
|
||||||
-module -avoid-version -Xcompiler -isysroot -Xcompiler /Developer/SDKs/MacOSX10.4u.sdk -Xcompiler -arch -Xcompiler ppc -Xcompiler -arch -Xcompiler i386
|
|
||||||
|
|
||||||
idle_la_CFLAGS = -Xcompiler -isysroot -Xcompiler /Developer/SDKs/MacOSX10.4u.sdk -Xcompiler -arch -Xcompiler ppc -Xcompiler -arch -Xcompiler i386 $(PYTHON_INCLUDES)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if BUILD_COCOA
|
|
||||||
nsapplib_LTLIBRARIES = nsapp.la
|
|
||||||
nsapplibdir = $(pkglibdir)
|
|
||||||
|
|
||||||
nsapp_la_LIBADD = $(COCOA_LIBS)
|
|
||||||
|
|
||||||
nsapp_la_SOURCES = nsapp.m
|
|
||||||
|
|
||||||
nsapp_la_LDFLAGS = \
|
|
||||||
-module -avoid-version -Xcompiler -isysroot -Xcompiler /Developer/SDKs/MacOSX10.4u.sdk -Xcompiler -arch -Xcompiler ppc -Xcompiler -arch -Xcompiler i386
|
|
||||||
|
|
||||||
nsapp_la_CFLAGS = -Xcompiler -isysroot -Xcompiler /Developer/SDKs/MacOSX10.4u.sdk -Xcompiler -arch -Xcompiler ppc -Xcompiler -arch -Xcompiler i386 $(PYTHON_INCLUDES)
|
|
||||||
|
|
||||||
AM_OBJCFLAGS = $(nsapp_la_CFLAGS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
DISTCLEANFILES =
|
|
||||||
|
|
||||||
EXTRA_DIST =
|
|
||||||
|
|
||||||
MAINTAINERCLEANFILES = Makefile.in
|
|
|
@ -1,45 +0,0 @@
|
||||||
import sys, commands
|
|
||||||
from network_manager_listener import device_now_active, device_no_longer_active
|
|
||||||
|
|
||||||
|
|
||||||
if sys.platform != 'darwin':
|
|
||||||
raise ImportError('System platform is not OS X')
|
|
||||||
|
|
||||||
net_device_active = True
|
|
||||||
|
|
||||||
###
|
|
||||||
### Utility functions
|
|
||||||
###
|
|
||||||
|
|
||||||
def checkPID(pid, procname):
|
|
||||||
out = commands.getstatusoutput("ps -wwp %d" % pid)
|
|
||||||
arr = out[1].split("\n")
|
|
||||||
if ((len(arr) == 2) and (arr[1].find(procname) >= 0)):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
import nsapp
|
|
||||||
|
|
||||||
def init():
|
|
||||||
nsapp.init()
|
|
||||||
nsapp.setNetworkCB(netDeviceChanged)
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def shutdown():
|
|
||||||
import dbus
|
|
||||||
dbus.shutdown()
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def netDeviceChanged():
|
|
||||||
global net_device_active
|
|
||||||
if net_device_active:
|
|
||||||
net_device_active = False
|
|
||||||
device_no_longer_active(None)
|
|
||||||
else:
|
|
||||||
net_device_active = True
|
|
||||||
device_now_active(None)
|
|
||||||
return
|
|
||||||
|
|
||||||
# vim: se ts=3:
|
|
133
src/osx/dbus.py
133
src/osx/dbus.py
|
@ -1,133 +0,0 @@
|
||||||
###
|
|
||||||
### Internal dbus management. This can go away once native gtk+ is in fink or
|
|
||||||
### macports and we can require their dbus.
|
|
||||||
###
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import os, sys, commands, signal
|
|
||||||
|
|
||||||
if sys.platform != "darwin":
|
|
||||||
raise ImportError("System platform is not OS/X")
|
|
||||||
|
|
||||||
import osx, osx.nsapp
|
|
||||||
from common.configpaths import gajimpaths
|
|
||||||
|
|
||||||
|
|
||||||
_GTK_BASE = "/Library/Frameworks/GTK+.framework/Versions/Current"
|
|
||||||
|
|
||||||
|
|
||||||
def readEnv():
|
|
||||||
gajimpaths.add_from_root(u'dbus.env', u'dbus.env')
|
|
||||||
try:
|
|
||||||
dbus_env = open(gajimpaths[u'dbus.env'], "r")
|
|
||||||
except Exception:
|
|
||||||
return False
|
|
||||||
try:
|
|
||||||
line1 = dbus_env.readline()
|
|
||||||
line2 = dbus_env.readline()
|
|
||||||
dbus_env.close()
|
|
||||||
except Exception:
|
|
||||||
print "Invalid dbus.env file"
|
|
||||||
return False
|
|
||||||
return parseEnv(line1, line2)
|
|
||||||
|
|
||||||
|
|
||||||
def parseEnv(line1, line2):
|
|
||||||
try:
|
|
||||||
if not line1 or not line2:
|
|
||||||
return False
|
|
||||||
if (not line1.startswith("DBUS_SESSION_BUS_ADDRESS=") or
|
|
||||||
not line2.startswith("DBUS_SESSION_BUS_PID=")):
|
|
||||||
return False
|
|
||||||
arr = line2.split("=")
|
|
||||||
pid = arr[1].strip().strip('"')
|
|
||||||
if not osx.checkPID(int(pid), "dbus-daemon"):
|
|
||||||
return False
|
|
||||||
line1 = line1.strip()
|
|
||||||
loc = line1.find("=")
|
|
||||||
address = line1[loc + 1:]
|
|
||||||
address = address.strip().strip('"')
|
|
||||||
return [address, pid]
|
|
||||||
except Exception, e:
|
|
||||||
print "Invalid dbus.env file", e
|
|
||||||
return False
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def setEnv(env):
|
|
||||||
os.environ['DBUS_SESSION_BUS_ADDRESS'] = env[0]
|
|
||||||
os.environ['DBUS_SESSION_BUS_PID'] = env[1]
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def writeEnv(env):
|
|
||||||
gajimpaths.add_from_root(u'dbus.env', u'dbus.env')
|
|
||||||
try:
|
|
||||||
dbus_env = open(gajimpaths[u'dbus.env'], "w+")
|
|
||||||
dbus_env.write("DBUS_SESSION_BUS_ADDRESS=\"" + env[0] + "\"\n")
|
|
||||||
dbus_env.write("DBUS_SESSION_BUS_PID=\"" + env[1] + "\"\n")
|
|
||||||
dbus_env.close()
|
|
||||||
except Exception, e:
|
|
||||||
print "Failed to write file: %s" % gajimpaths[u'dbus.env']
|
|
||||||
print str(e)
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def checkUUID():
|
|
||||||
if os.path.exists(_GTK_BASE + "/var/lib/dbus/machine-id"):
|
|
||||||
return
|
|
||||||
ret = commands.getstatusoutput(_GTK_BASE + "/bin/dbus-uuidgen --ensure")
|
|
||||||
if ret[0] != 0:
|
|
||||||
print "Failed to initialize dbus machine UUID:", ret[1]
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def load(start):
|
|
||||||
# Look for existing external session and just use it if it exists
|
|
||||||
if (('DBUS_SESSION_BUS_ADDRESS' in os.environ) and
|
|
||||||
('DBUS_SESSION_BUS_PID' in os.environ) and
|
|
||||||
osx.checkPID(int(os.environ['DBUS_SESSION_BUS_PID']), 'dbus-daemon')):
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Look for our own internal session
|
|
||||||
env = readEnv()
|
|
||||||
if env:
|
|
||||||
# We have a valid existing dbus session, yay
|
|
||||||
setEnv(env)
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Initialize the machine's UUID if not done yet
|
|
||||||
checkUUID()
|
|
||||||
|
|
||||||
if start:
|
|
||||||
# None found, start a new session
|
|
||||||
print "Starting new dbus session"
|
|
||||||
#cmd = os.path.join(osx.nsapp.getBundlePath(),
|
|
||||||
# "Contents/Resources/bin/dbus-launch --exit-with-session")
|
|
||||||
cmd = _GTK_BASE + "/bin/dbus-launch --exit-with-session"
|
|
||||||
ret = commands.getstatusoutput(cmd)
|
|
||||||
arr = ret[1].split("\n")
|
|
||||||
if len(arr) != 2:
|
|
||||||
print "Failed to start internal dbus session:"
|
|
||||||
print ret[1]
|
|
||||||
return
|
|
||||||
env = parseEnv(arr[0].strip(), arr[1].strip())
|
|
||||||
if not env:
|
|
||||||
print "Failed to start internal dbus session:"
|
|
||||||
print ret[1]
|
|
||||||
return
|
|
||||||
setEnv(env)
|
|
||||||
writeEnv(env)
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def shutdown():
|
|
||||||
env = readEnv()
|
|
||||||
if not env:
|
|
||||||
return
|
|
||||||
os.kill(int(env[1]), signal.SIGINT)
|
|
||||||
return
|
|
||||||
|
|
||||||
# vim: se ts=3:
|
|
|
@ -1,245 +0,0 @@
|
||||||
"""
|
|
||||||
A Python module that enables posting notifications to the Growl daemon.
|
|
||||||
See <http://growl.info/> for more information.
|
|
||||||
"""
|
|
||||||
__version__ = "0.7"
|
|
||||||
__author__ = "Mark Rowe <bdash@users.sourceforge.net>"
|
|
||||||
__copyright__ = "(C) 2003 Mark Rowe <bdash@users.sourceforge.net>. Released under the BSD license."
|
|
||||||
__contributors__ = ["Ingmar J Stein (Growl Team)",
|
|
||||||
"Rui Carmo (http://the.taoofmac.com)",
|
|
||||||
"Jeremy Rossi <jeremy@jeremyrossi.com>"
|
|
||||||
]
|
|
||||||
|
|
||||||
try:
|
|
||||||
import _growl
|
|
||||||
except Exception:
|
|
||||||
_growl = False
|
|
||||||
import struct
|
|
||||||
import md5
|
|
||||||
import socket
|
|
||||||
|
|
||||||
GROWL_UDP_PORT=9887
|
|
||||||
GROWL_PROTOCOL_VERSION=1
|
|
||||||
GROWL_TYPE_REGISTRATION=0
|
|
||||||
GROWL_TYPE_NOTIFICATION=1
|
|
||||||
|
|
||||||
GROWL_APP_NAME="ApplicationName"
|
|
||||||
GROWL_APP_ICON="ApplicationIcon"
|
|
||||||
GROWL_NOTIFICATIONS_DEFAULT="DefaultNotifications"
|
|
||||||
GROWL_NOTIFICATIONS_ALL="AllNotifications"
|
|
||||||
GROWL_NOTIFICATIONS_USER_SET="AllowedUserNotifications"
|
|
||||||
|
|
||||||
GROWL_NOTIFICATION_NAME="NotificationName"
|
|
||||||
GROWL_NOTIFICATION_TITLE="NotificationTitle"
|
|
||||||
GROWL_NOTIFICATION_DESCRIPTION="NotificationDescription"
|
|
||||||
GROWL_NOTIFICATION_ICON="NotificationIcon"
|
|
||||||
GROWL_NOTIFICATION_APP_ICON="NotificationAppIcon"
|
|
||||||
GROWL_NOTIFICATION_PRIORITY="NotificationPriority"
|
|
||||||
|
|
||||||
GROWL_NOTIFICATION_STICKY="NotificationSticky"
|
|
||||||
GROWL_NOTIFICATION_CLICK_CONTEXT="NotificationClickContext"
|
|
||||||
|
|
||||||
GROWL_APP_REGISTRATION="GrowlApplicationRegistrationNotification"
|
|
||||||
GROWL_APP_REGISTRATION_CONF="GrowlApplicationRegistrationConfirmationNotification"
|
|
||||||
GROWL_NOTIFICATION="GrowlNotification"
|
|
||||||
GROWL_SHUTDOWN="GrowlShutdown"
|
|
||||||
GROWL_PING="Honey, Mind Taking Out The Trash"
|
|
||||||
GROWL_PONG="What Do You Want From Me, Woman"
|
|
||||||
GROWL_IS_READY="Lend Me Some Sugar; I Am Your Neighbor!"
|
|
||||||
|
|
||||||
GROWL_NOTIFICATION_CLICKED="GrowlClicked!"
|
|
||||||
GROWL_NOTIFICATION_TIMED_OUT="GrowlTimedOut!"
|
|
||||||
GROWL_KEY_CLICKED_CONTEXT="ClickedContext"
|
|
||||||
|
|
||||||
|
|
||||||
growlPriority = {"Very Low":-2,"Moderate":-1,"Normal":0,"High":1,"Emergency":2}
|
|
||||||
|
|
||||||
class netgrowl:
|
|
||||||
"""Builds a Growl Network Registration packet.
|
|
||||||
Defaults to emulating the command-line growlnotify utility."""
|
|
||||||
|
|
||||||
__notAllowed__ = [GROWL_APP_ICON, GROWL_NOTIFICATION_ICON, GROWL_NOTIFICATION_APP_ICON]
|
|
||||||
|
|
||||||
def __init__(self, hostname, password ):
|
|
||||||
self.hostname = hostname
|
|
||||||
self.password = password
|
|
||||||
self.socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
|
|
||||||
|
|
||||||
def send(self, data):
|
|
||||||
self.socket.sendto(data, (self.hostname, GROWL_UDP_PORT))
|
|
||||||
|
|
||||||
def PostNotification(self, userInfo):
|
|
||||||
priority = userInfo.get(GROWL_NOTIFICATION_PRIORITY, 0)
|
|
||||||
if GROWL_NOTIFICATION_STICKY in userInfo:
|
|
||||||
sticky = userInfo[GROWL_NOTIFICATION_STICKY]
|
|
||||||
else:
|
|
||||||
priority = False
|
|
||||||
data = self.encodeNotify(userInfo[GROWL_APP_NAME],
|
|
||||||
userInfo[GROWL_NOTIFICATION_NAME],
|
|
||||||
userInfo[GROWL_NOTIFICATION_TITLE],
|
|
||||||
userInfo[GROWL_NOTIFICATION_DESCRIPTION],
|
|
||||||
priority,
|
|
||||||
sticky)
|
|
||||||
return self.send(data)
|
|
||||||
|
|
||||||
def PostRegistration(self, userInfo):
|
|
||||||
data = self.encodeRegistration(userInfo[GROWL_APP_NAME],
|
|
||||||
userInfo[GROWL_NOTIFICATIONS_ALL],
|
|
||||||
userInfo[GROWL_NOTIFICATIONS_DEFAULT])
|
|
||||||
return self.send(data)
|
|
||||||
|
|
||||||
def encodeRegistration(self, application, notifications, defaultNotifications):
|
|
||||||
data = struct.pack("!BBH",
|
|
||||||
GROWL_PROTOCOL_VERSION,
|
|
||||||
GROWL_TYPE_REGISTRATION,
|
|
||||||
len(application) )
|
|
||||||
data += struct.pack("BB",
|
|
||||||
len(notifications),
|
|
||||||
len(defaultNotifications) )
|
|
||||||
data += application
|
|
||||||
for i in notifications:
|
|
||||||
encoded = i.encode("utf-8")
|
|
||||||
data += struct.pack("!H", len(encoded))
|
|
||||||
data += encoded
|
|
||||||
for i in defaultNotifications:
|
|
||||||
data += struct.pack("B", i)
|
|
||||||
return self.encodePassword(data)
|
|
||||||
|
|
||||||
def encodeNotify(self, application, notification, title, description,
|
|
||||||
priority = 0, sticky = False):
|
|
||||||
|
|
||||||
application = application.encode("utf-8")
|
|
||||||
notification = notification.encode("utf-8")
|
|
||||||
title = title.encode("utf-8")
|
|
||||||
description = description.encode("utf-8")
|
|
||||||
flags = (priority & 0x07) * 2
|
|
||||||
if priority < 0:
|
|
||||||
flags |= 0x08
|
|
||||||
if sticky:
|
|
||||||
flags = flags | 0x0001
|
|
||||||
data = struct.pack("!BBHHHHH",
|
|
||||||
GROWL_PROTOCOL_VERSION,
|
|
||||||
GROWL_TYPE_NOTIFICATION,
|
|
||||||
flags,
|
|
||||||
len(notification),
|
|
||||||
len(title),
|
|
||||||
len(description),
|
|
||||||
len(application) )
|
|
||||||
data += notification
|
|
||||||
data += title
|
|
||||||
data += description
|
|
||||||
data += application
|
|
||||||
return self.encodePassword(data)
|
|
||||||
|
|
||||||
def encodePassword(self, data):
|
|
||||||
checksum = md5.new()
|
|
||||||
checksum.update(data)
|
|
||||||
if self.password:
|
|
||||||
checksum.update(self.password)
|
|
||||||
data += checksum.digest()
|
|
||||||
return data
|
|
||||||
|
|
||||||
class _ImageHook(type):
|
|
||||||
def __getattribute__(self, attr):
|
|
||||||
global Image
|
|
||||||
if Image is self:
|
|
||||||
from _growlImage import Image
|
|
||||||
|
|
||||||
return getattr(Image, attr)
|
|
||||||
|
|
||||||
class Image(object):
|
|
||||||
__metaclass__ = _ImageHook
|
|
||||||
|
|
||||||
class _RawImage(object):
|
|
||||||
def __init__(self, data): self.rawImageData = data
|
|
||||||
|
|
||||||
class GrowlNotifier(object):
|
|
||||||
"""
|
|
||||||
A class that abstracts the process of registering and posting
|
|
||||||
notifications to the Growl daemon.
|
|
||||||
|
|
||||||
You can either pass `applicationName', `notifications',
|
|
||||||
`defaultNotifications' and `applicationIcon' to the constructor
|
|
||||||
or you may define them as class-level variables in a sub-class.
|
|
||||||
|
|
||||||
`defaultNotifications' is optional, and defaults to the value of
|
|
||||||
`notifications'. `applicationIcon' is also optional but defaults
|
|
||||||
to a pointless icon so is better to be specified.
|
|
||||||
"""
|
|
||||||
|
|
||||||
applicationName = 'GrowlNotifier'
|
|
||||||
notifications = []
|
|
||||||
defaultNotifications = []
|
|
||||||
applicationIcon = None
|
|
||||||
_notifyMethod = _growl
|
|
||||||
_notify_cb = None
|
|
||||||
|
|
||||||
def __init__(self, applicationName=None, notifications=None, defaultNotifications=None, applicationIcon=None, hostname=None, password=None, notify_cb=None):
|
|
||||||
assert(applicationName is not None, 'an application name is required')
|
|
||||||
self.applicationName = applicationName
|
|
||||||
|
|
||||||
assert(notifications, 'a sequence of one or more notification names is required')
|
|
||||||
self.notifications = list(notifications)
|
|
||||||
if defaultNotifications is not None:
|
|
||||||
self.defaultNotifications = list(defaultNotifications)
|
|
||||||
else:
|
|
||||||
self.defaultNotifications = list(self.notifications)
|
|
||||||
|
|
||||||
if applicationIcon is not None:
|
|
||||||
self.applicationIcon = self._checkIcon(applicationIcon)
|
|
||||||
|
|
||||||
if hostname is not None and password is not None:
|
|
||||||
self._notifyMethod = netgrowl(hostname, password)
|
|
||||||
elif hostname is not None or password is not None:
|
|
||||||
raise KeyError, "Hostname and Password are both required for a network notification"
|
|
||||||
|
|
||||||
if notify_cb is not None:
|
|
||||||
self._notify_cb = notify_cb
|
|
||||||
else:
|
|
||||||
self._notify_cb = self.notifyCB
|
|
||||||
|
|
||||||
if hostname is None and password is None:
|
|
||||||
self._notifyMethod.Init(applicationName, self._notify_cb)
|
|
||||||
|
|
||||||
def _checkIcon(self, data):
|
|
||||||
if isinstance(data, str):
|
|
||||||
return _RawImage(data)
|
|
||||||
else:
|
|
||||||
return data
|
|
||||||
|
|
||||||
def register(self):
|
|
||||||
if self.applicationIcon is not None:
|
|
||||||
self.applicationIcon = self._checkIcon(self.applicationIcon)
|
|
||||||
|
|
||||||
regInfo = {GROWL_APP_NAME: self.applicationName,
|
|
||||||
GROWL_NOTIFICATIONS_ALL: self.notifications,
|
|
||||||
GROWL_NOTIFICATIONS_DEFAULT: self.defaultNotifications,
|
|
||||||
GROWL_APP_ICON:self.applicationIcon,
|
|
||||||
}
|
|
||||||
self._notifyMethod.PostRegistration(regInfo)
|
|
||||||
|
|
||||||
def notify(self, noteType, title, description, icon=None, sticky=False, priority=None, context=None):
|
|
||||||
assert noteType in self.notifications
|
|
||||||
notifyInfo = {GROWL_NOTIFICATION_NAME: noteType,
|
|
||||||
GROWL_APP_NAME: self.applicationName,
|
|
||||||
GROWL_NOTIFICATION_TITLE: title,
|
|
||||||
GROWL_NOTIFICATION_DESCRIPTION: description,
|
|
||||||
}
|
|
||||||
if sticky:
|
|
||||||
notifyInfo[GROWL_NOTIFICATION_STICKY] = 1
|
|
||||||
|
|
||||||
if priority is not None:
|
|
||||||
notifyInfo[GROWL_NOTIFICATION_PRIORITY] = priority
|
|
||||||
|
|
||||||
if icon:
|
|
||||||
notifyInfo[GROWL_NOTIFICATION_ICON] = self._checkIcon(icon)
|
|
||||||
|
|
||||||
if context:
|
|
||||||
notifyInfo[GROWL_NOTIFICATION_CLICK_CONTEXT] = context
|
|
||||||
|
|
||||||
self._notifyMethod.PostNotification(notifyInfo)
|
|
||||||
|
|
||||||
def notifyCB(self, userdata):
|
|
||||||
print "Got notify in pyland", userdata
|
|
||||||
|
|
||||||
# vim: se ts=3:
|
|
|
@ -1,41 +0,0 @@
|
||||||
OBJC = gcc
|
|
||||||
|
|
||||||
export MACOSX_DEPLOYMENT_TARGET=10.4
|
|
||||||
INCLUDES = \
|
|
||||||
$(PYTHON_INCLUDES)
|
|
||||||
|
|
||||||
if BUILD_CARBON
|
|
||||||
_growllib_LTLIBRARIES = _growl.la
|
|
||||||
_growllibdir = $(pkglibdir)
|
|
||||||
|
|
||||||
_growl_la_LIBADD = $(CARBON_LIBS)
|
|
||||||
|
|
||||||
_growl_la_SOURCES = _growl.c
|
|
||||||
|
|
||||||
_growl_la_LDFLAGS = \
|
|
||||||
-module -avoid-version -Xcompiler -isysroot -Xcompiler /Developer/SDKs/MacOSX10.4u.sdk -Xcompiler -arch -Xcompiler ppc -Xcompiler -arch -Xcompiler i386
|
|
||||||
|
|
||||||
_growl_la_CFLAGS = -Xcompiler -isysroot -Xcompiler /Developer/SDKs/MacOSX10.4u.sdk -Xcompiler -arch -Xcompiler ppc -Xcompiler -arch -Xcompiler i386 $(PYTHON_INCLUDES)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if BUILD_COCOA
|
|
||||||
_growlImagelib_LTLIBRARIES = _growlImage.la
|
|
||||||
_growlImagelibdir = $(pkglibdir)
|
|
||||||
|
|
||||||
_growlImage_la_LIBADD = $(COCOA_LIBS)
|
|
||||||
|
|
||||||
_growlImage_la_SOURCES = _growlImage.m
|
|
||||||
|
|
||||||
_growlImage_la_LDFLAGS = \
|
|
||||||
-module -avoid-version -Xcompiler -isysroot -Xcompiler /Developer/SDKs/MacOSX10.4u.sdk -Xcompiler -arch -Xcompiler ppc -Xcompiler -arch -Xcompiler i386
|
|
||||||
|
|
||||||
_growlImage_la_CFLAGS = -Xcompiler -isysroot -Xcompiler /Developer/SDKs/MacOSX10.4u.sdk -Xcompiler -arch -Xcompiler ppc -Xcompiler -arch -Xcompiler i386 $(PYTHON_INCLUDES)
|
|
||||||
|
|
||||||
AM_OBJCFLAGS = $(_growlImage_la_CFLAGS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
DISTCLEANFILES =
|
|
||||||
|
|
||||||
EXTRA_DIST =
|
|
||||||
|
|
||||||
MAINTAINERCLEANFILES = Makefile.in
|
|
|
@ -1,3 +0,0 @@
|
||||||
# No-op file that just helps python with the growl module directory.
|
|
||||||
|
|
||||||
# vim: se ts=3:
|
|
|
@ -1,239 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2004-2005 The Growl Project.
|
|
||||||
* Created by Jeremy Rossi <jeremy@jeremyrossi.com>
|
|
||||||
* Released under the BSD license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <Python.h>
|
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
|
||||||
|
|
||||||
#define str(cfstr) CFStringGetCStringPtr(cfstr, kCFStringEncodingMacRoman)
|
|
||||||
#define cfstr(str) CFStringCreateWithCString(kCFAllocatorDefault, str, kCFStringEncodingMacRoman)
|
|
||||||
|
|
||||||
static PyObject * _notify_cb = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
static PyObject * growl_PostDictionary(CFStringRef name, PyObject *self, PyObject *args) {
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
PyObject *inputDict;
|
|
||||||
PyObject *pKeys = NULL;
|
|
||||||
PyObject *pKey, *pValue;
|
|
||||||
|
|
||||||
CFMutableDictionaryRef note = CFDictionaryCreateMutable(kCFAllocatorDefault,
|
|
||||||
/*capacity*/ 0,
|
|
||||||
&kCFTypeDictionaryKeyCallBacks,
|
|
||||||
&kCFTypeDictionaryValueCallBacks);
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O!", &PyDict_Type, &inputDict))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
pKeys = PyDict_Keys(inputDict);
|
|
||||||
for (i = 0; i < PyList_Size(pKeys); ++i) {
|
|
||||||
CFStringRef convertedKey;
|
|
||||||
|
|
||||||
/* Converting the PyDict key to NSString and used for key in note */
|
|
||||||
pKey = PyList_GetItem(pKeys, i);
|
|
||||||
if (!pKey)
|
|
||||||
// Exception already set
|
|
||||||
goto error;
|
|
||||||
pValue = PyDict_GetItem(inputDict, pKey);
|
|
||||||
if (!pValue) {
|
|
||||||
// XXX Neeed a real Error message here.
|
|
||||||
PyErr_SetString(PyExc_TypeError," ");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (PyUnicode_Check(pKey)) {
|
|
||||||
convertedKey = CFStringCreateWithBytes(kCFAllocatorDefault,
|
|
||||||
(const UInt8 *)PyUnicode_AS_DATA(pKey),
|
|
||||||
PyUnicode_GET_DATA_SIZE(pKey),
|
|
||||||
kCFStringEncodingUnicode,
|
|
||||||
false);
|
|
||||||
} else if (PyString_Check(pKey)) {
|
|
||||||
convertedKey = CFStringCreateWithCString(kCFAllocatorDefault,
|
|
||||||
PyString_AsString(pKey),
|
|
||||||
kCFStringEncodingUTF8);
|
|
||||||
} else {
|
|
||||||
PyErr_SetString(PyExc_TypeError,"The Dict keys must be strings/unicode");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Converting the PyDict value to NSString or NSData based on class */
|
|
||||||
if (PyString_Check(pValue)) {
|
|
||||||
CFStringRef convertedValue = CFStringCreateWithCString(kCFAllocatorDefault,
|
|
||||||
PyString_AS_STRING(pValue),
|
|
||||||
kCFStringEncodingUTF8);
|
|
||||||
CFDictionarySetValue(note, convertedKey, convertedValue);
|
|
||||||
CFRelease(convertedValue);
|
|
||||||
} else if (PyUnicode_Check(pValue)) {
|
|
||||||
CFStringRef convertedValue = CFStringCreateWithBytes(kCFAllocatorDefault,
|
|
||||||
(const UInt8 *)PyUnicode_AS_DATA(pValue),
|
|
||||||
PyUnicode_GET_DATA_SIZE(pValue),
|
|
||||||
kCFStringEncodingUnicode,
|
|
||||||
false);
|
|
||||||
CFDictionarySetValue(note, convertedKey, convertedValue);
|
|
||||||
CFRelease(convertedValue);
|
|
||||||
} else if (PyInt_Check(pValue)) {
|
|
||||||
long v = PyInt_AS_LONG(pValue);
|
|
||||||
CFNumberRef convertedValue = CFNumberCreate(kCFAllocatorDefault,
|
|
||||||
kCFNumberLongType,
|
|
||||||
&v);
|
|
||||||
CFDictionarySetValue(note, convertedKey, convertedValue);
|
|
||||||
CFRelease(convertedValue);
|
|
||||||
} else if (pValue == Py_None) {
|
|
||||||
CFDataRef convertedValue = CFDataCreate(kCFAllocatorDefault, NULL, 0);
|
|
||||||
CFDictionarySetValue(note, convertedKey, convertedValue);
|
|
||||||
CFRelease(convertedValue);
|
|
||||||
} else if (PyList_Check(pValue)) {
|
|
||||||
int size = PyList_Size(pValue);
|
|
||||||
CFMutableArrayRef listHolder = CFArrayCreateMutable(kCFAllocatorDefault,
|
|
||||||
size,
|
|
||||||
&kCFTypeArrayCallBacks);
|
|
||||||
for (j = 0; j < size; ++j) {
|
|
||||||
PyObject *lValue = PyList_GetItem(pValue, j);
|
|
||||||
if (PyString_Check(lValue)) {
|
|
||||||
CFStringRef convertedValue = CFStringCreateWithCString(kCFAllocatorDefault,
|
|
||||||
PyString_AS_STRING(lValue),
|
|
||||||
kCFStringEncodingUTF8);
|
|
||||||
CFArrayAppendValue(listHolder, convertedValue);
|
|
||||||
CFRelease(convertedValue);
|
|
||||||
} else if (PyUnicode_Check(lValue)) {
|
|
||||||
CFStringRef convertedValue = CFStringCreateWithBytes(kCFAllocatorDefault,
|
|
||||||
(const UInt8 *)PyUnicode_AS_DATA(lValue),
|
|
||||||
PyUnicode_GET_DATA_SIZE(lValue),
|
|
||||||
kCFStringEncodingUnicode,
|
|
||||||
false);
|
|
||||||
CFArrayAppendValue(listHolder, convertedValue);
|
|
||||||
CFRelease(convertedValue);
|
|
||||||
} else {
|
|
||||||
CFRelease(convertedKey);
|
|
||||||
PyErr_SetString(PyExc_TypeError,"The lists must only contain strings");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CFDictionarySetValue(note, convertedKey, listHolder);
|
|
||||||
CFRelease(listHolder);
|
|
||||||
} else if (PyObject_HasAttrString(pValue, "rawImageData")) {
|
|
||||||
PyObject *lValue = PyObject_GetAttrString(pValue, "rawImageData");
|
|
||||||
if (!lValue) {
|
|
||||||
goto error;
|
|
||||||
} else if (PyString_Check(lValue)) {
|
|
||||||
CFDataRef convertedValue = CFDataCreate(kCFAllocatorDefault,
|
|
||||||
(const UInt8 *)PyString_AsString(lValue),
|
|
||||||
PyString_Size(lValue));
|
|
||||||
CFDictionarySetValue(note, convertedKey, convertedValue);
|
|
||||||
CFRelease(convertedValue);
|
|
||||||
} else {
|
|
||||||
CFRelease(convertedKey);
|
|
||||||
PyErr_SetString(PyExc_TypeError, "Icon with rawImageData attribute present must ensure it is a string.");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
CFRelease(convertedKey);
|
|
||||||
PyErr_SetString(PyExc_TypeError, "Value is not of Str/List");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
CFRelease(convertedKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
|
||||||
CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(),
|
|
||||||
/*name*/ name,
|
|
||||||
/*object*/ NULL,
|
|
||||||
/*userInfo*/ note,
|
|
||||||
/*deliverImmediately*/ false);
|
|
||||||
CFRelease(note);
|
|
||||||
Py_END_ALLOW_THREADS
|
|
||||||
|
|
||||||
Py_DECREF(pKeys);
|
|
||||||
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
return Py_None;
|
|
||||||
|
|
||||||
error:
|
|
||||||
CFRelease(note);
|
|
||||||
|
|
||||||
Py_XDECREF(pKeys);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void growl_NotifyCB(CFNotificationCenterRef center, void *observer,
|
|
||||||
CFStringRef name, const void *object,
|
|
||||||
CFDictionaryRef userInfo)
|
|
||||||
{
|
|
||||||
CFIndex size, len;
|
|
||||||
const void * keys[1];
|
|
||||||
const void * values[1];
|
|
||||||
CFArrayRef arr;
|
|
||||||
CFStringRef cfstr;
|
|
||||||
CFRange cfrange;
|
|
||||||
UInt8 *buff;
|
|
||||||
int i;
|
|
||||||
PyObject * pylist;
|
|
||||||
|
|
||||||
cfrange.location = 0;
|
|
||||||
CFDictionaryGetKeysAndValues(userInfo, keys, values);
|
|
||||||
arr = (CFArrayRef)values[0];
|
|
||||||
size = CFArrayGetCount(arr);
|
|
||||||
pylist = PyList_New(size);
|
|
||||||
for (i=0; i < size; ++i)
|
|
||||||
{
|
|
||||||
cfstr = (CFStringRef)CFArrayGetValueAtIndex(arr, i);
|
|
||||||
cfrange.length = CFStringGetLength(cfstr);
|
|
||||||
CFStringGetBytes(cfstr, cfrange, kCFStringEncodingUnicode, 0, false,
|
|
||||||
NULL, 0, &len);
|
|
||||||
buff = (UInt8*)malloc(len);
|
|
||||||
CFStringGetBytes(cfstr, cfrange, kCFStringEncodingUnicode, 0, false,
|
|
||||||
buff, len, &len);
|
|
||||||
PyList_SetItem(pylist, i,
|
|
||||||
PyUnicode_DecodeUTF16((char*)buff, len, NULL, NULL));
|
|
||||||
free(buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject_CallObject(_notify_cb, Py_BuildValue("(O)", pylist));
|
|
||||||
Py_DECREF(pylist);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject * growl_Init(PyObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
char* name = NULL;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "sO", &name, &_notify_cb))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
Py_INCREF(_notify_cb);
|
|
||||||
|
|
||||||
char* buff = (char*)malloc(strlen(name) + 14);
|
|
||||||
strcpy(buff, name);
|
|
||||||
strcat(buff, "GrowlClicked!");
|
|
||||||
CFStringRef cfbuff = cfstr(buff);
|
|
||||||
CFNotificationCenterAddObserver(
|
|
||||||
CFNotificationCenterGetDistributedCenter(), NULL, &growl_NotifyCB,
|
|
||||||
cfbuff, NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
|
|
||||||
free(buff);
|
|
||||||
CFRelease(cfbuff);
|
|
||||||
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
return Py_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject * growl_PostRegistration(PyObject *self, PyObject *args) {
|
|
||||||
return growl_PostDictionary(CFSTR("GrowlApplicationRegistrationNotification"), self, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject * growl_PostNotification(PyObject *self, PyObject *args) {
|
|
||||||
return growl_PostDictionary(CFSTR("GrowlNotification"), self, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyMethodDef GrowlMethods[] = {
|
|
||||||
{"Init", growl_Init, METH_VARARGS, "Initialize notifications with GrowlHelperApp"},
|
|
||||||
{"PostNotification", growl_PostNotification, METH_VARARGS, "Send a notification to GrowlHelperApp"},
|
|
||||||
{"PostRegistration", growl_PostRegistration, METH_VARARGS, "Send a registration to GrowlHelperApp"},
|
|
||||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
PyMODINIT_FUNC init_growl(void) {
|
|
||||||
Py_InitModule("_growl", GrowlMethods);
|
|
||||||
}
|
|
|
@ -1,274 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2004 Mark Rowe <bdash@users.sourceforge.net>
|
|
||||||
* Released under the BSD license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Python.h"
|
|
||||||
#import <Cocoa/Cocoa.h>
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
PyObject_HEAD
|
|
||||||
NSImage *theImage;
|
|
||||||
} ImageObject;
|
|
||||||
|
|
||||||
|
|
||||||
static PyTypeObject ImageObject_Type;
|
|
||||||
|
|
||||||
#define ImageObject_Check(v) ((v)->ob_type == &ImageObject_Type)
|
|
||||||
|
|
||||||
static ImageObject *
|
|
||||||
newImageObject(NSImage *img)
|
|
||||||
{
|
|
||||||
ImageObject *self;
|
|
||||||
if (! img)
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError, "Invalid image.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
self = PyObject_New(ImageObject, &ImageObject_Type);
|
|
||||||
if (! self)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
self->theImage = [img retain];
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ImageObject_dealloc(ImageObject *self)
|
|
||||||
{
|
|
||||||
PyObject_Del(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
ImageObject_getAttr(PyObject *self, PyObject *attr)
|
|
||||||
{
|
|
||||||
char *theAttr = PyString_AsString(attr);
|
|
||||||
NSAutoreleasePool *pool = nil;
|
|
||||||
|
|
||||||
if (strcmp(theAttr, "rawImageData") == 0)
|
|
||||||
{
|
|
||||||
pool = [[NSAutoreleasePool alloc] init];
|
|
||||||
NSData *imageData = [((ImageObject *) self)->theImage TIFFRepresentation];
|
|
||||||
PyObject *pyImageData = PyString_FromStringAndSize([imageData bytes], [imageData length]);
|
|
||||||
[pool release];
|
|
||||||
return pyImageData;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return PyObject_GenericGetAttr(self, attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
ImageObject_imageFromPath(PyTypeObject *cls, PyObject *args)
|
|
||||||
{
|
|
||||||
ImageObject *self;
|
|
||||||
char *fileName_ = NULL;
|
|
||||||
NSString *fileName = nil;
|
|
||||||
NSImage *theImage = nil;
|
|
||||||
NSAutoreleasePool *pool = nil;
|
|
||||||
|
|
||||||
if (! PyArg_ParseTuple(args, "et:imageFromPath",
|
|
||||||
Py_FileSystemDefaultEncoding, &fileName_))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
pool = [[NSAutoreleasePool alloc] init];
|
|
||||||
|
|
||||||
fileName = [NSString stringWithUTF8String:fileName_];
|
|
||||||
theImage = [[[NSImage alloc] initWithContentsOfFile:fileName] autorelease];
|
|
||||||
self = newImageObject(theImage);
|
|
||||||
|
|
||||||
[pool release];
|
|
||||||
return (PyObject *) self;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
ImageObject_imageWithData(PyTypeObject *cls, PyObject *args)
|
|
||||||
{
|
|
||||||
ImageObject *self;
|
|
||||||
char *imageData = NULL;
|
|
||||||
int imageDataSize = 0;
|
|
||||||
NSImage *theImage = nil;
|
|
||||||
NSAutoreleasePool *pool = nil;
|
|
||||||
|
|
||||||
if (! PyArg_ParseTuple(args, "s#:imageWithData",
|
|
||||||
&imageData, &imageDataSize))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
pool = [[NSAutoreleasePool alloc] init];
|
|
||||||
|
|
||||||
|
|
||||||
theImage = [[[NSImage alloc] initWithData:[NSData dataWithBytes:imageData
|
|
||||||
length:imageDataSize]] autorelease];
|
|
||||||
self = newImageObject(theImage);
|
|
||||||
|
|
||||||
[pool release];
|
|
||||||
return (PyObject *) self;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
ImageObject_imageWithIconForFile(PyTypeObject *cls, PyObject *args)
|
|
||||||
{
|
|
||||||
ImageObject *self;
|
|
||||||
char *fileName_ = NULL;
|
|
||||||
NSString *fileName = nil;
|
|
||||||
NSImage *theImage = nil;
|
|
||||||
NSAutoreleasePool *pool = nil;
|
|
||||||
|
|
||||||
if (! PyArg_ParseTuple(args, "et:imageWithIconForFile",
|
|
||||||
Py_FileSystemDefaultEncoding, &fileName_))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
pool = [[NSAutoreleasePool alloc] init];
|
|
||||||
|
|
||||||
fileName = [NSString stringWithUTF8String:fileName_];
|
|
||||||
theImage = [[NSWorkspace sharedWorkspace] iconForFile:fileName];
|
|
||||||
self = newImageObject(theImage);
|
|
||||||
|
|
||||||
[pool release];
|
|
||||||
return (PyObject *) self;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
ImageObject_imageWithIconForFileType(PyTypeObject *cls, PyObject *args)
|
|
||||||
{
|
|
||||||
ImageObject *self;
|
|
||||||
char *fileType = NULL;
|
|
||||||
NSImage *theImage = nil;
|
|
||||||
NSAutoreleasePool *pool = nil;
|
|
||||||
|
|
||||||
if (! PyArg_ParseTuple(args, "s:imageWithIconForFileType",
|
|
||||||
&fileType))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
pool = [[NSAutoreleasePool alloc] init];
|
|
||||||
|
|
||||||
theImage = [[NSWorkspace sharedWorkspace] iconForFileType:[NSString stringWithUTF8String:fileType]];
|
|
||||||
self = newImageObject(theImage);
|
|
||||||
|
|
||||||
[pool release];
|
|
||||||
return (PyObject *) self;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
ImageObject_imageWithIconForCurrentApplication(PyTypeObject *cls, PyObject *args)
|
|
||||||
{
|
|
||||||
ImageObject *self;
|
|
||||||
NSAutoreleasePool *pool = nil;
|
|
||||||
|
|
||||||
if (! PyArg_ParseTuple(args, ":imageWithIconForCurrentApplication"))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
pool = [[NSAutoreleasePool alloc] init];
|
|
||||||
|
|
||||||
self = newImageObject([NSApp applicationIconImage]);
|
|
||||||
|
|
||||||
[pool release];
|
|
||||||
return (PyObject *) self;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
ImageObject_imageWithIconForApplication(PyTypeObject *cls, PyObject *args)
|
|
||||||
{
|
|
||||||
ImageObject *self;
|
|
||||||
char *appName_ = NULL;
|
|
||||||
NSString *appName = nil;
|
|
||||||
NSString *appPath = nil;
|
|
||||||
NSImage *theImage = nil;
|
|
||||||
NSAutoreleasePool *pool = nil;
|
|
||||||
|
|
||||||
if (! PyArg_ParseTuple(args, "et:imageWithIconForApplication",
|
|
||||||
Py_FileSystemDefaultEncoding, &appName_))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
pool = [[NSAutoreleasePool alloc] init];
|
|
||||||
|
|
||||||
appName = [NSString stringWithUTF8String:appName_];
|
|
||||||
appPath = [[NSWorkspace sharedWorkspace] fullPathForApplication:appName];
|
|
||||||
if (! appPath)
|
|
||||||
{
|
|
||||||
PyErr_Format(PyExc_RuntimeError, "Application named '%s' not found", appName_);
|
|
||||||
self = NULL;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
theImage = [[NSWorkspace sharedWorkspace] iconForFile:appPath];
|
|
||||||
self = newImageObject(theImage);
|
|
||||||
|
|
||||||
done:
|
|
||||||
[pool release];
|
|
||||||
return (PyObject *) self;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static PyMethodDef ImageObject_methods[] = {
|
|
||||||
{"imageFromPath", (PyCFunction)ImageObject_imageFromPath, METH_VARARGS | METH_CLASS},
|
|
||||||
{"imageWithData", (PyCFunction)ImageObject_imageWithData, METH_VARARGS | METH_CLASS},
|
|
||||||
{"imageWithIconForFile", (PyCFunction)ImageObject_imageWithIconForFile, METH_VARARGS | METH_CLASS},
|
|
||||||
{"imageWithIconForFileType", (PyCFunction)ImageObject_imageWithIconForFileType, METH_VARARGS | METH_CLASS},
|
|
||||||
{"imageWithIconForCurrentApplication", (PyCFunction)ImageObject_imageWithIconForCurrentApplication, METH_VARARGS | METH_CLASS},
|
|
||||||
{"imageWithIconForApplication", (PyCFunction)ImageObject_imageWithIconForApplication, METH_VARARGS | METH_CLASS},
|
|
||||||
{NULL, NULL} /* sentinel */
|
|
||||||
};
|
|
||||||
|
|
||||||
static PyTypeObject ImageObject_Type = {
|
|
||||||
PyObject_HEAD_INIT(NULL)
|
|
||||||
0, /*ob_size*/
|
|
||||||
"_growlImage.Image", /*tp_name*/
|
|
||||||
sizeof(ImageObject), /*tp_basicsize*/
|
|
||||||
0, /*tp_itemsize*/
|
|
||||||
/* methods */
|
|
||||||
(destructor)ImageObject_dealloc, /*tp_dealloc*/
|
|
||||||
0, /*tp_print*/
|
|
||||||
0, /*tp_getattr*/
|
|
||||||
0, /*tp_setattr*/
|
|
||||||
0, /*tp_compare*/
|
|
||||||
0, /*tp_repr*/
|
|
||||||
0, /*tp_as_number*/
|
|
||||||
0, /*tp_as_sequence*/
|
|
||||||
0, /*tp_as_mapping*/
|
|
||||||
0, /*tp_hash*/
|
|
||||||
0, /*tp_call*/
|
|
||||||
0, /*tp_str*/
|
|
||||||
ImageObject_getAttr, /*tp_getattro*/
|
|
||||||
0, /*tp_setattro*/
|
|
||||||
0, /*tp_as_buffer*/
|
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_CLASS, /*tp_flags*/
|
|
||||||
0, /*tp_doc*/
|
|
||||||
0, /*tp_traverse*/
|
|
||||||
0, /*tp_clear*/
|
|
||||||
0, /*tp_richcompare*/
|
|
||||||
0, /*tp_weaklistoffset*/
|
|
||||||
0, /*tp_iter*/
|
|
||||||
0, /*tp_iternext*/
|
|
||||||
ImageObject_methods, /*tp_methods*/
|
|
||||||
0, /*tp_members*/
|
|
||||||
0, /*tp_getset*/
|
|
||||||
0, /*tp_base*/
|
|
||||||
0, /*tp_dict*/
|
|
||||||
0, /*tp_descr_get*/
|
|
||||||
0, /*tp_descr_set*/
|
|
||||||
0, /*tp_dictoffset*/
|
|
||||||
0, /*tp_init*/
|
|
||||||
PyType_GenericAlloc, /*tp_alloc*/
|
|
||||||
0, /*tp_new*/
|
|
||||||
0, /*tp_free*/
|
|
||||||
0, /*tp_is_gc*/
|
|
||||||
};
|
|
||||||
|
|
||||||
static PyMethodDef _growlImage_methods[] = {
|
|
||||||
{NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
PyMODINIT_FUNC
|
|
||||||
init_growlImage(void)
|
|
||||||
{
|
|
||||||
PyObject *m;
|
|
||||||
|
|
||||||
if (PyType_Ready(&ImageObject_Type) < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m = Py_InitModule("_growlImage", _growlImage_methods);
|
|
||||||
|
|
||||||
PyModule_AddObject(m, "Image", (PyObject *)&ImageObject_Type);
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
from distutils.core import setup, Extension
|
|
||||||
import sys
|
|
||||||
|
|
||||||
_growl = Extension('_growl',
|
|
||||||
extra_link_args = ["-framework","CoreFoundation"],
|
|
||||||
sources = ['libgrowl.c'])
|
|
||||||
_growlImage = Extension('_growlImage',
|
|
||||||
extra_link_args = ["-framework","Cocoa"],
|
|
||||||
sources = ['growlImage.m'])
|
|
||||||
|
|
||||||
if sys.platform.startswith("darwin"):
|
|
||||||
modules = [_growl, _growlImage]
|
|
||||||
else:
|
|
||||||
modules = []
|
|
||||||
|
|
||||||
setup(name="py-Growl",
|
|
||||||
version="0.0.7",
|
|
||||||
description="Python bindings for posting notifications to the Growl daemon",
|
|
||||||
author="Mark Rowe",
|
|
||||||
author_email="bdash@users.sourceforge.net",
|
|
||||||
url="http://growl.info",
|
|
||||||
py_modules=["Growl"],
|
|
||||||
ext_modules = modules )
|
|
||||||
|
|
||||||
|
|
||||||
# vim: se ts=3:
|
|
|
@ -1,64 +0,0 @@
|
||||||
import sys, os
|
|
||||||
from growl.Growl import GrowlNotifier
|
|
||||||
from common import gajim
|
|
||||||
|
|
||||||
|
|
||||||
if sys.platform != "darwin":
|
|
||||||
raise ImportError("System platform is not OS/X")
|
|
||||||
|
|
||||||
|
|
||||||
GENERIC_NOTIF = _('Generic')
|
|
||||||
notifications = [
|
|
||||||
_('Contact Signed In'), _('Contact Signed Out'), _('New Message'),
|
|
||||||
_('New Single Message'), _('New Private Message'), _('New E-mail'),
|
|
||||||
_('File Transfer Request'), _('File Transfer Error'),
|
|
||||||
_('File Transfer Completed'), _('File Transfer Stopped'),
|
|
||||||
_('Groupchat Invitation'), _('Contact Changed Status'),
|
|
||||||
_('Connection Failed'), GENERIC_NOTIF
|
|
||||||
]
|
|
||||||
|
|
||||||
growler = None
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def init():
|
|
||||||
global growler
|
|
||||||
icon = open(os.path.join(gajim.DATA_DIR, "pixmaps", "gajim.icns"), "r")
|
|
||||||
growler = GrowlNotifier(applicationName = "Gajim",
|
|
||||||
notifications = notifications,
|
|
||||||
applicationIcon = icon.read(),
|
|
||||||
notify_cb = notifyCB)
|
|
||||||
growler.register()
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def notify(event_type, jid, account, msg_type, path_to_image, title, text):
|
|
||||||
if not event_type in notifications:
|
|
||||||
event_type = GENERIC_NOTIF
|
|
||||||
if not text:
|
|
||||||
text = gajim.get_name_from_jid(account, jid) # default value of text
|
|
||||||
text = filterString(text)
|
|
||||||
if not title:
|
|
||||||
title = event_type
|
|
||||||
title = filterString(title)
|
|
||||||
if not path_to_image:
|
|
||||||
path_to_image = os.path.abspath(
|
|
||||||
os.path.join(gajim.DATA_DIR, 'pixmaps', 'events',
|
|
||||||
'chat_msg_recv.png')) # img to display
|
|
||||||
icon = open(path_to_image, "r")
|
|
||||||
context = [account, jid, msg_type]
|
|
||||||
growler.notify(event_type, title, text, icon.read(), False, None,
|
|
||||||
context)
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def notifyCB(data):
|
|
||||||
gajim.interface.handle_event(data[0], data[1], data[2])
|
|
||||||
|
|
||||||
|
|
||||||
def filterString(string):
|
|
||||||
string = string.replace(""", "'")
|
|
||||||
return string
|
|
||||||
|
|
||||||
|
|
||||||
# vim: se ts=3:
|
|
175
src/osx/idle.c
175
src/osx/idle.c
|
@ -1,175 +0,0 @@
|
||||||
/*****
|
|
||||||
This is a modified form of idler.c. The original copyright notice follows.
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*****************************************
|
|
||||||
* idler.c
|
|
||||||
*
|
|
||||||
* Uses IOKit to figure out the idle time of the system. The idle time
|
|
||||||
* is stored as a property of the IOHIDSystem class; the name is
|
|
||||||
* HIDIdleTime. Stored as a 64-bit int, measured in ns.
|
|
||||||
*
|
|
||||||
* The program itself just prints to stdout the time that the computer
|
|
||||||
has
|
|
||||||
* been idle in seconds.
|
|
||||||
*
|
|
||||||
* Compile with gcc -Wall -framework IOKit -framework Carbon idler.c -o
|
|
||||||
* idler
|
|
||||||
*
|
|
||||||
* Copyright (c) 2003, Stanford University
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
are
|
|
||||||
* met:
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice,
|
|
||||||
* this list of conditions and the following disclaimer in the
|
|
||||||
documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* Neither the name of Stanford University nor the names of its
|
|
||||||
contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS
|
|
||||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO,
|
|
||||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
||||||
PARTICULAR
|
|
||||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
||||||
OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
|
||||||
#include <CoreServices/CoreServices.h>
|
|
||||||
#include <IOKit/IOKitLib.h>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <Python.h>
|
|
||||||
|
|
||||||
/* 10^9 -- number of ns in a second */
|
|
||||||
#define NS_SECONDS 1000000000
|
|
||||||
|
|
||||||
|
|
||||||
static mach_port_t __idle_osx_master_port;
|
|
||||||
io_registry_entry_t __idle_osx_service;
|
|
||||||
|
|
||||||
|
|
||||||
static PyObject * idle_init(PyObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
io_iterator_t iter;
|
|
||||||
CFMutableDictionaryRef hid_match;
|
|
||||||
|
|
||||||
IOMasterPort(MACH_PORT_NULL, &__idle_osx_master_port);
|
|
||||||
|
|
||||||
/* Get IOHIDSystem */
|
|
||||||
hid_match = IOServiceMatching("IOHIDSystem");
|
|
||||||
IOServiceGetMatchingServices(__idle_osx_master_port, hid_match, &iter);
|
|
||||||
if (iter == 0) {
|
|
||||||
printf("Error accessing IOHIDSystem\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
__idle_osx_service = IOIteratorNext(iter);
|
|
||||||
if (__idle_osx_service == 0) {
|
|
||||||
printf("Iterator's empty!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
IOObjectRelease(iter);
|
|
||||||
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
return Py_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject * idle_getIdleSec(PyObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
CFMutableDictionaryRef properties = 0;
|
|
||||||
CFTypeRef obj = NULL;
|
|
||||||
uint64_t tHandle = 0;
|
|
||||||
|
|
||||||
if (IORegistryEntryCreateCFProperties(__idle_osx_service, &properties,
|
|
||||||
kCFAllocatorDefault, 0) ==
|
|
||||||
KERN_SUCCESS && properties != NULL)
|
|
||||||
{
|
|
||||||
obj = CFDictionaryGetValue(properties, CFSTR("HIDIdleTime"));
|
|
||||||
CFRetain(obj);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Couldn't grab properties of system\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj)
|
|
||||||
{
|
|
||||||
CFTypeID type = CFGetTypeID(obj);
|
|
||||||
|
|
||||||
if (type == CFDataGetTypeID())
|
|
||||||
{
|
|
||||||
CFDataGetBytes((CFDataRef) obj,
|
|
||||||
CFRangeMake(0, sizeof(tHandle)),
|
|
||||||
(UInt8*) &tHandle);
|
|
||||||
}
|
|
||||||
else if (type == CFNumberGetTypeID())
|
|
||||||
{
|
|
||||||
CFNumberGetValue((CFNumberRef)obj,
|
|
||||||
kCFNumberSInt64Type,
|
|
||||||
&tHandle);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("%d: unsupported type\n", (int)type);
|
|
||||||
}
|
|
||||||
|
|
||||||
CFRelease(obj);
|
|
||||||
|
|
||||||
// essentially divides by 10^9
|
|
||||||
tHandle >>= 30;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Can't find idle time\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
CFRelease((CFTypeRef)properties);
|
|
||||||
return Py_BuildValue("L", tHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject * idle_close(PyObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
/* Release our resources */
|
|
||||||
IOObjectRelease(__idle_osx_service);
|
|
||||||
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
return Py_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyMethodDef idleMethods[] =
|
|
||||||
{
|
|
||||||
{"init", idle_init, METH_VARARGS, "init idle"},
|
|
||||||
{"getIdleSec", idle_getIdleSec, METH_VARARGS, "Get idle time in seconds"},
|
|
||||||
{"close", idle_close, METH_VARARGS, "close idle"},
|
|
||||||
{NULL, NULL, 0, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
PyMODINIT_FUNC initidle(void)
|
|
||||||
{
|
|
||||||
(void) Py_InitModule("idle", idleMethods);
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
#import <Cocoa/Cocoa.h>
|
|
||||||
|
|
||||||
|
|
||||||
@interface NSApplication (Gajim)
|
|
||||||
|
|
||||||
- (void) initGajim;
|
|
||||||
- (void) initGUI;
|
|
||||||
- (BOOL) initNetNotify;
|
|
||||||
- (void) orderFrontStandardAboutPanel: (id)sender;
|
|
||||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
|
|
||||||
- (BOOL) application:(NSApplication *)theApplication
|
|
||||||
openFile:(NSString *)filename;
|
|
||||||
- (void) application:(NSApplication *)sender openFiles:(NSArray *)filenames;
|
|
||||||
- (BOOL) applicationOpenUntitledFile:(NSApplication *)theApplication;
|
|
||||||
- (BOOL) applicationShouldOpenUntitledFile:(NSApplication *)sender;
|
|
||||||
|
|
||||||
+ (void) netNotifyCB: (NSNotification*)notif;
|
|
||||||
|
|
||||||
@end
|
|
239
src/osx/nsapp.m
239
src/osx/nsapp.m
|
@ -1,239 +0,0 @@
|
||||||
#import "nsapp.h"
|
|
||||||
#include <notify.h>
|
|
||||||
|
|
||||||
#include <AppKit/NSSound.h>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <Python.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define GAJIM_POOL_ALLOC \
|
|
||||||
NSAutoreleasePool *gajim_pool = [[NSAutoreleasePool alloc] init];
|
|
||||||
#define GAJIM_POOL_FREE [gajim_pool release];
|
|
||||||
|
|
||||||
|
|
||||||
static PyObject *netChangedCB = NULL;
|
|
||||||
static NSFileHandle* netNotifyFH = nil;
|
|
||||||
static int netNotifyToken = -1;
|
|
||||||
|
|
||||||
|
|
||||||
@implementation NSApplication (Gajim)
|
|
||||||
|
|
||||||
- (void) initGUI
|
|
||||||
{
|
|
||||||
[NSBundle loadNibNamed:@"Gajim" owner:NSApp];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void) netNotifyCB: (NSNotification*) notif
|
|
||||||
{
|
|
||||||
NSLog(@"Network changed notification");
|
|
||||||
|
|
||||||
if (netChangedCB)
|
|
||||||
{
|
|
||||||
PyObject_CallObject(netChangedCB, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[notif object] readInBackgroundAndNotify];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL) initNetNotify
|
|
||||||
{
|
|
||||||
int fd = 0;
|
|
||||||
|
|
||||||
if (notify_register_file_descriptor(
|
|
||||||
"com.apple.system.config.network_change", &fd, 0,
|
|
||||||
&netNotifyToken) != NOTIFY_STATUS_OK)
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
netNotifyFH = [[NSFileHandle alloc] initWithFileDescriptor: fd];
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver: [self class]
|
|
||||||
selector: @selector(netNotifyCB:)
|
|
||||||
name: NSFileHandleReadCompletionNotification
|
|
||||||
object: netNotifyFH];
|
|
||||||
[netNotifyFH readInBackgroundAndNotify];
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) initGajim
|
|
||||||
{
|
|
||||||
GAJIM_POOL_ALLOC
|
|
||||||
|
|
||||||
[self initGUI];
|
|
||||||
[self initNetNotify];
|
|
||||||
|
|
||||||
[NSApp setDelegate:self];
|
|
||||||
[NSApp finishLaunching];
|
|
||||||
|
|
||||||
GAJIM_POOL_FREE
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) orderFrontStandardAboutPanel: (id)sender
|
|
||||||
{
|
|
||||||
PyRun_SimpleString("\n\
|
|
||||||
import gobject\n\
|
|
||||||
import dialogs\n\
|
|
||||||
def doAbout():\n\
|
|
||||||
dialogs.AboutDialog()\n\
|
|
||||||
return None\n\
|
|
||||||
gobject.idle_add(doAbout)\n\
|
|
||||||
");
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
PyRun_SimpleString("\n\
|
|
||||||
import gajim\n\
|
|
||||||
import gobject\n\
|
|
||||||
def doQuit():\n\
|
|
||||||
gajim.interface.roster.on_quit_menuitem_activate(None)\n\
|
|
||||||
return None\n\
|
|
||||||
gobject.idle_add(doQuit)\n\
|
|
||||||
");
|
|
||||||
*/
|
|
||||||
return NSTerminateNow;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL) application:(NSApplication *)theApplication
|
|
||||||
openFile:(NSString *)filename
|
|
||||||
{
|
|
||||||
NSLog(@"openFile");
|
|
||||||
NSLog(filename);
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
|
|
||||||
{
|
|
||||||
NSLog(@"openFiles");
|
|
||||||
|
|
||||||
NSEnumerator* iter = [filenames objectEnumerator];
|
|
||||||
NSString* str;
|
|
||||||
while ((str = [iter nextObject]))
|
|
||||||
{
|
|
||||||
NSLog(str);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)applicationOpenUntitledFile:(NSApplication *)theApplication
|
|
||||||
{
|
|
||||||
NSLog(@"openUntitledFile");
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender
|
|
||||||
{
|
|
||||||
NSLog(@"shouldOpenUntitledFile");
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
static PyObject * nsapp_init(PyObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
[NSApp initGajim];
|
|
||||||
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
return Py_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject * nsapp_setNetworkCB(PyObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
PyArg_UnpackTuple(args, "netcb", 1, 1, &netChangedCB);
|
|
||||||
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
return Py_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject * nsapp_requestUserAttention(PyObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
GAJIM_POOL_ALLOC
|
|
||||||
[NSApp requestUserAttention:NSInformationalRequest];
|
|
||||||
GAJIM_POOL_FREE
|
|
||||||
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
return Py_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject * nsapp_playFile(PyObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
GAJIM_POOL_ALLOC
|
|
||||||
|
|
||||||
const char* cstr = NULL;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s", &cstr))
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSSound* snd = [[NSSound alloc] initWithContentsOfFile:
|
|
||||||
[[NSString alloc] initWithUTF8String: cstr]
|
|
||||||
byReference: YES];
|
|
||||||
if (!snd)
|
|
||||||
{
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
return Py_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (![snd play])
|
|
||||||
{
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
return Py_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
GAJIM_POOL_FREE
|
|
||||||
|
|
||||||
return Py_BuildValue("b", 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject * nsapp_getBundlePath(PyObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
GAJIM_POOL_ALLOC
|
|
||||||
|
|
||||||
NSBundle* bundle = [NSBundle mainBundle];
|
|
||||||
if (!bundle)
|
|
||||||
{
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
return Py_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSString* nspath = [bundle bundlePath];
|
|
||||||
if (!nspath)
|
|
||||||
{
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
return Py_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* path = [nspath UTF8String];
|
|
||||||
PyObject* pypath = Py_BuildValue("s", path);
|
|
||||||
|
|
||||||
GAJIM_POOL_FREE
|
|
||||||
|
|
||||||
return pypath;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyMethodDef nsappMethods[] =
|
|
||||||
{
|
|
||||||
{"init", nsapp_init, METH_VARARGS, "init nsapp"},
|
|
||||||
{"setNetworkCB", nsapp_setNetworkCB, METH_VARARGS,
|
|
||||||
"Callback to call when the network state changes"},
|
|
||||||
{"getBundlePath", nsapp_getBundlePath, METH_VARARGS,
|
|
||||||
"Get the path to the bundle we were run from"},
|
|
||||||
{"playFile", nsapp_playFile, METH_VARARGS,
|
|
||||||
"Play a sound file"},
|
|
||||||
{"requestUserAttention", nsapp_requestUserAttention, METH_VARARGS,
|
|
||||||
"Sends a request for the users attention to the window manager"},
|
|
||||||
{NULL, NULL, 0, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
PyMODINIT_FUNC initnsapp(void)
|
|
||||||
{
|
|
||||||
(void) Py_InitModule("nsapp", nsappMethods);
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
### Adjust the sys.path so that the site-packages.zip is before the lib-dynload
|
|
||||||
### so that the osx/__init__.py in the .zip is read before looking for it in the
|
|
||||||
### lib-dynload/osx dir where the .so's are.
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
py = -1
|
|
||||||
lib_dyn = -1
|
|
||||||
site_zip = -1
|
|
||||||
for index in xrange(len(sys.path)):
|
|
||||||
if 'Contents/Resources' in sys.path[index]:
|
|
||||||
if sys.path[index].endswith('lib/python2.5'):
|
|
||||||
py = index
|
|
||||||
if sys.path[index].endswith('lib-dynload'):
|
|
||||||
lib_dyn = index
|
|
||||||
elif sys.path[index].endswith('site-packages.zip'):
|
|
||||||
site_zip = index
|
|
||||||
if ((lib_dyn > -1) and (site_zip > -1)):
|
|
||||||
tmp = sys.path[lib_dyn]
|
|
||||||
sys.path[lib_dyn] = sys.path[site_zip]
|
|
||||||
sys.path[site_zip] = tmp
|
|
||||||
if py > -1:
|
|
||||||
del sys.path[py]
|
|
||||||
|
|
||||||
# vim: se ts=3:
|
|
|
@ -1,22 +0,0 @@
|
||||||
from distutils.core import setup, Extension
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name = 'Gajim',
|
|
||||||
version = '0.11',
|
|
||||||
description = 'A full featured Jabber client',
|
|
||||||
author = 'Gajim Development Team',
|
|
||||||
url = 'http://www.gajim.org/',
|
|
||||||
download_url = 'http://www.gajim.org/downloads.php',
|
|
||||||
license = 'GPL',
|
|
||||||
|
|
||||||
ext_modules=[
|
|
||||||
Extension('idle', ['idle.c'],
|
|
||||||
extra_compile_args=['-Wall'],
|
|
||||||
extra_link_args=['-framework', 'IOKit', '-framework', 'Carbon']),
|
|
||||||
Extension('nsapp', ['nsapp.m'],
|
|
||||||
extra_compile_args=['-Wall'],
|
|
||||||
extra_link_args=['-framework', 'AppKit', '-framework', 'Cocoa']),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
# vim: se ts=3:
|
|
|
@ -1,21 +0,0 @@
|
||||||
GTKPATH="/Library/Frameworks/GTK+.framework/Versions/Current/bin"
|
|
||||||
|
|
||||||
export MACOSX_DEPLOYMENT_TARGET=10.4
|
|
||||||
INCLUDES = $(PYTHON_INCLUDES)
|
|
||||||
|
|
||||||
GTKLDFLAGS=`$(GTKPATH)/pkg-config --libs gtk+-2.0 pygobject-2.0`
|
|
||||||
GTKCFLAGS=`$(GTKPATH)/pkg-config --cflags gtk+-2.0 pygobject-2.0`
|
|
||||||
|
|
||||||
if BUILD_COCOA
|
|
||||||
syncmenulib_LTLIBRARIES = syncmenu.la
|
|
||||||
syncmenulibdir = $(pkglibdir)
|
|
||||||
syncmenu_la_SOURCES = sync-menu.c pysyncmenu.c
|
|
||||||
syncmenu_la_LDFLAGS = -module -avoid-version -Xcompiler -isysroot -Xcompiler /Developer/SDKs/MacOSX10.4u.sdk -Xcompiler -arch -Xcompiler ppc -Xcompiler -arch -Xcompiler i386 $(GTKLDFLAGS)
|
|
||||||
syncmenu_la_CFLAGS = -Xcompiler -isysroot -Xcompiler /Developer/SDKs/MacOSX10.4u.sdk -Xcompiler -arch -Xcompiler ppc -Xcompiler -arch -Xcompiler i386 $(GTKCFLAGS) -Wall -g $(INCLUDES)
|
|
||||||
endif
|
|
||||||
|
|
||||||
DISTCLEANFILES =
|
|
||||||
|
|
||||||
EXTRA_DIST =
|
|
||||||
|
|
||||||
MAINTAINERCLEANFILES = Makefile.in
|
|
|
@ -1,55 +0,0 @@
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <Python.h>
|
|
||||||
#include <pygobject.h>
|
|
||||||
#include "sync-menu.h"
|
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(pysync_menu_takeover_menu__doc__,
|
|
||||||
"Receives: a GtkMenuShell\n"
|
|
||||||
"Returns:\n");
|
|
||||||
|
|
||||||
static PyObject *pysync_menu_takeover_menu(PyObject *s, PyObject *args)
|
|
||||||
{
|
|
||||||
PyObject *obj = NULL;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O:GtkMenuShell", &obj))
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError, "Failed to process parameter1");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Py_INCREF(obj);
|
|
||||||
|
|
||||||
GtkMenuShell* menu = pyg_boxed_get(obj, GtkMenuShell);
|
|
||||||
if (!menu)
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError, "Failed to process parameter2");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
sync_menu_takeover_menu(menu);
|
|
||||||
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
return Py_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyMethodDef syncmenuModuleMethods[] =
|
|
||||||
{
|
|
||||||
{"takeover_menu", (PyCFunction)pysync_menu_takeover_menu,
|
|
||||||
METH_VARARGS, pysync_menu_takeover_menu__doc__},
|
|
||||||
{NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
PyDoc_STRVAR(modsyncmenu__doc__,
|
|
||||||
"GTK+ Integration for the Mac OS X Menubar.\n");
|
|
||||||
|
|
||||||
void initsyncmenu(void)
|
|
||||||
{
|
|
||||||
if (!Py_InitModule3("syncmenu", syncmenuModuleMethods, modsyncmenu__doc__))
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_ImportError,
|
|
||||||
"Py_InitModule3(\"syncmenu\") failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
import sys
|
|
||||||
from distutils.core import setup, Extension
|
|
||||||
import commands
|
|
||||||
|
|
||||||
|
|
||||||
retval, output = commands.getstatusoutput("pkg-config --cflags gtk+-2.0 pygtk-2.0")
|
|
||||||
if retval != 0:
|
|
||||||
print "Failed to find package details for gtk+-2.0"
|
|
||||||
print
|
|
||||||
print output
|
|
||||||
sys.exit(1)
|
|
||||||
cflags = output.strip().split()
|
|
||||||
retval, output = commands.getstatusoutput("pkg-config --libs gtk+-2.0 pygtk-2.0")
|
|
||||||
if retval != 0:
|
|
||||||
print "Failed to find package details for gtk+-2.0"
|
|
||||||
print
|
|
||||||
print output
|
|
||||||
sys.exit(1)
|
|
||||||
libs = output.strip().split()
|
|
||||||
|
|
||||||
|
|
||||||
setup(name='syncmenu', version='0.2',
|
|
||||||
author='James Newton', author_email='baron@codepunks.org',
|
|
||||||
ext_modules=[
|
|
||||||
Extension('syncmenu', ['pysyncmenu.c', 'sync-menu.c'],
|
|
||||||
extra_link_args=libs + ['-framework', 'Carbon'],
|
|
||||||
extra_compile_args=['-Wall'] + cflags)
|
|
||||||
])
|
|
||||||
|
|
||||||
# vim: se ts=3:
|
|
|
@ -1,728 +0,0 @@
|
||||||
/* GTK+ Integration for the Mac OS X Menubar.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2007 Pioneer Research Center USA, Inc.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the
|
|
||||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
* Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
#include <gdk/gdkkeysyms.h>
|
|
||||||
|
|
||||||
#include <Carbon/Carbon.h>
|
|
||||||
|
|
||||||
#include "sync-menu.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* TODO
|
|
||||||
*
|
|
||||||
* - Setup shortcuts, possibly transforming ctrl->cmd
|
|
||||||
* - Sync menus
|
|
||||||
* - Create on demand? (can this be done with gtk+? ie fill in menu items when the menu is opened)
|
|
||||||
* - Figure out what to do per app/window...
|
|
||||||
* - Toggle/radio items
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define GTK_QUARTZ_MENU_CREATOR 'GTKC'
|
|
||||||
#define GTK_QUARTZ_ITEM_WIDGET 'GWID'
|
|
||||||
|
|
||||||
|
|
||||||
static void sync_menu_shell (GtkMenuShell *menu_shell,
|
|
||||||
MenuRef carbon_menu,
|
|
||||||
gboolean toplevel);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* utility functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
static GtkWidget *
|
|
||||||
find_menu_label (GtkWidget *widget)
|
|
||||||
{
|
|
||||||
GtkWidget *label = NULL;
|
|
||||||
|
|
||||||
if (GTK_IS_LABEL (widget))
|
|
||||||
return widget;
|
|
||||||
|
|
||||||
if (GTK_IS_CONTAINER (widget))
|
|
||||||
{
|
|
||||||
GList *children;
|
|
||||||
GList *l;
|
|
||||||
|
|
||||||
children = gtk_container_get_children (GTK_CONTAINER (widget));
|
|
||||||
|
|
||||||
for (l = children; l; l = l->next)
|
|
||||||
{
|
|
||||||
label = find_menu_label (l->data);
|
|
||||||
if (label)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_list_free (children);
|
|
||||||
}
|
|
||||||
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const gchar *
|
|
||||||
get_menu_label_text (GtkWidget *menu_item,
|
|
||||||
GtkWidget **label)
|
|
||||||
{
|
|
||||||
*label = find_menu_label (menu_item);
|
|
||||||
if (!*label)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return gtk_label_get_text (GTK_LABEL (*label));
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
accel_find_func (GtkAccelKey *key,
|
|
||||||
GClosure *closure,
|
|
||||||
gpointer data)
|
|
||||||
{
|
|
||||||
return (GClosure *) data == closure;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CarbonMenu functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
MenuRef menu;
|
|
||||||
} CarbonMenu;
|
|
||||||
|
|
||||||
static GQuark carbon_menu_quark = 0;
|
|
||||||
|
|
||||||
static CarbonMenu *
|
|
||||||
carbon_menu_new (void)
|
|
||||||
{
|
|
||||||
return g_slice_new0 (CarbonMenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
carbon_menu_free (CarbonMenu *menu)
|
|
||||||
{
|
|
||||||
g_slice_free (CarbonMenu, menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
static CarbonMenu *
|
|
||||||
carbon_menu_get (GtkWidget *widget)
|
|
||||||
{
|
|
||||||
return g_object_get_qdata (G_OBJECT (widget), carbon_menu_quark);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
carbon_menu_connect (GtkWidget *menu,
|
|
||||||
MenuRef menuRef)
|
|
||||||
{
|
|
||||||
CarbonMenu *carbon_menu = carbon_menu_get (menu);
|
|
||||||
|
|
||||||
if (!carbon_menu)
|
|
||||||
{
|
|
||||||
carbon_menu = carbon_menu_new ();
|
|
||||||
|
|
||||||
g_object_set_qdata_full (G_OBJECT (menu), carbon_menu_quark,
|
|
||||||
carbon_menu,
|
|
||||||
(GDestroyNotify) carbon_menu_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
carbon_menu->menu = menuRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CarbonMenuItem functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
MenuRef menu;
|
|
||||||
MenuItemIndex index;
|
|
||||||
MenuRef submenu;
|
|
||||||
GClosure *accel_closure;
|
|
||||||
} CarbonMenuItem;
|
|
||||||
|
|
||||||
static GQuark carbon_menu_item_quark = 0;
|
|
||||||
|
|
||||||
static CarbonMenuItem *
|
|
||||||
carbon_menu_item_new (void)
|
|
||||||
{
|
|
||||||
return g_slice_new0 (CarbonMenuItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
carbon_menu_item_free (CarbonMenuItem *menu_item)
|
|
||||||
{
|
|
||||||
if (menu_item->accel_closure)
|
|
||||||
g_closure_unref (menu_item->accel_closure);
|
|
||||||
|
|
||||||
g_slice_free (CarbonMenuItem, menu_item);
|
|
||||||
}
|
|
||||||
|
|
||||||
static CarbonMenuItem *
|
|
||||||
carbon_menu_item_get (GtkWidget *widget)
|
|
||||||
{
|
|
||||||
return g_object_get_qdata (G_OBJECT (widget), carbon_menu_item_quark);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
carbon_menu_item_update_state (CarbonMenuItem *carbon_item,
|
|
||||||
GtkWidget *widget)
|
|
||||||
{
|
|
||||||
gboolean sensitive;
|
|
||||||
gboolean visible;
|
|
||||||
UInt32 set_attrs = 0;
|
|
||||||
UInt32 clear_attrs = 0;
|
|
||||||
|
|
||||||
g_object_get (widget,
|
|
||||||
"sensitive", &sensitive,
|
|
||||||
"visible", &visible,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (!sensitive)
|
|
||||||
set_attrs |= kMenuItemAttrDisabled;
|
|
||||||
else
|
|
||||||
clear_attrs |= kMenuItemAttrDisabled;
|
|
||||||
|
|
||||||
if (!visible)
|
|
||||||
set_attrs |= kMenuItemAttrHidden;
|
|
||||||
else
|
|
||||||
clear_attrs |= kMenuItemAttrHidden;
|
|
||||||
|
|
||||||
ChangeMenuItemAttributes (carbon_item->menu, carbon_item->index,
|
|
||||||
set_attrs, clear_attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
carbon_menu_item_update_active (CarbonMenuItem *carbon_item,
|
|
||||||
GtkWidget *widget)
|
|
||||||
{
|
|
||||||
gboolean active;
|
|
||||||
|
|
||||||
g_object_get (widget,
|
|
||||||
"active", &active,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
CheckMenuItem (carbon_item->menu, carbon_item->index,
|
|
||||||
active);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
carbon_menu_item_update_submenu (CarbonMenuItem *carbon_item,
|
|
||||||
GtkWidget *widget)
|
|
||||||
{
|
|
||||||
GtkWidget *submenu;
|
|
||||||
|
|
||||||
submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
|
|
||||||
|
|
||||||
if (submenu)
|
|
||||||
{
|
|
||||||
GtkWidget *label = NULL;
|
|
||||||
|
|
||||||
carbon_item->submenu = NULL;
|
|
||||||
GetMenuItemHierarchicalMenu(carbon_item->menu, carbon_item->index,
|
|
||||||
&carbon_item->submenu);
|
|
||||||
if (!carbon_item->submenu)
|
|
||||||
{
|
|
||||||
const gchar *label_text;
|
|
||||||
CFStringRef cfstr = NULL;
|
|
||||||
|
|
||||||
label_text = get_menu_label_text (widget, &label);
|
|
||||||
if (label_text)
|
|
||||||
cfstr = CFStringCreateWithCString (NULL, label_text,
|
|
||||||
kCFStringEncodingUTF8);
|
|
||||||
CreateNewMenu (0, 0, &carbon_item->submenu);
|
|
||||||
SetMenuTitleWithCFString (carbon_item->submenu, cfstr);
|
|
||||||
SetMenuItemHierarchicalMenu (carbon_item->menu, carbon_item->index,
|
|
||||||
carbon_item->submenu);
|
|
||||||
if (cfstr)
|
|
||||||
CFRelease (cfstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
sync_menu_shell (GTK_MENU_SHELL (submenu), carbon_item->submenu, FALSE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetMenuItemHierarchicalMenu (carbon_item->menu, carbon_item->index,
|
|
||||||
NULL);
|
|
||||||
carbon_item->submenu = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
carbon_menu_item_update_label (CarbonMenuItem *carbon_item,
|
|
||||||
GtkWidget *widget)
|
|
||||||
{
|
|
||||||
GtkWidget *label;
|
|
||||||
const gchar *label_text;
|
|
||||||
CFStringRef cfstr = NULL;
|
|
||||||
|
|
||||||
label_text = get_menu_label_text (widget, &label);
|
|
||||||
if (label_text)
|
|
||||||
cfstr = CFStringCreateWithCString (NULL, label_text,
|
|
||||||
kCFStringEncodingUTF8);
|
|
||||||
|
|
||||||
SetMenuItemTextWithCFString (carbon_item->menu, carbon_item->index,
|
|
||||||
cfstr);
|
|
||||||
|
|
||||||
if (cfstr)
|
|
||||||
CFRelease (cfstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
carbon_menu_item_update_accelerator (CarbonMenuItem *carbon_item,
|
|
||||||
GtkWidget *widget)
|
|
||||||
{
|
|
||||||
GtkWidget *label;
|
|
||||||
|
|
||||||
get_menu_label_text (widget, &label);
|
|
||||||
|
|
||||||
if (GTK_IS_ACCEL_LABEL (label) &&
|
|
||||||
GTK_ACCEL_LABEL (label)->accel_closure)
|
|
||||||
{
|
|
||||||
GtkAccelKey *key;
|
|
||||||
|
|
||||||
key = gtk_accel_group_find (GTK_ACCEL_LABEL (label)->accel_group,
|
|
||||||
accel_find_func,
|
|
||||||
GTK_ACCEL_LABEL (label)->accel_closure);
|
|
||||||
|
|
||||||
if (key &&
|
|
||||||
key->accel_key &&
|
|
||||||
key->accel_flags & GTK_ACCEL_VISIBLE)
|
|
||||||
{
|
|
||||||
GdkDisplay *display = gtk_widget_get_display (widget);
|
|
||||||
GdkKeymap *keymap = gdk_keymap_get_for_display (display);
|
|
||||||
GdkKeymapKey *keys;
|
|
||||||
gint n_keys;
|
|
||||||
|
|
||||||
if (gdk_keymap_get_entries_for_keyval (keymap, key->accel_key,
|
|
||||||
&keys, &n_keys))
|
|
||||||
{
|
|
||||||
UInt8 modifiers = 0;
|
|
||||||
|
|
||||||
SetMenuItemCommandKey (carbon_item->menu, carbon_item->index,
|
|
||||||
true, keys[0].keycode);
|
|
||||||
|
|
||||||
g_free (keys);
|
|
||||||
|
|
||||||
if (key->accel_mods)
|
|
||||||
{
|
|
||||||
if (key->accel_mods & GDK_SHIFT_MASK)
|
|
||||||
modifiers |= kMenuShiftModifier;
|
|
||||||
|
|
||||||
if (key->accel_mods & GDK_MOD1_MASK)
|
|
||||||
modifiers |= kMenuOptionModifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(key->accel_mods & GDK_CONTROL_MASK))
|
|
||||||
{
|
|
||||||
modifiers |= kMenuNoCommandModifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetMenuItemModifiers (carbon_item->menu, carbon_item->index,
|
|
||||||
modifiers);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* otherwise, clear the menu shortcut */
|
|
||||||
SetMenuItemModifiers (carbon_item->menu, carbon_item->index,
|
|
||||||
kMenuNoModifiers | kMenuNoCommandModifier);
|
|
||||||
ChangeMenuItemAttributes (carbon_item->menu, carbon_item->index,
|
|
||||||
0, kMenuItemAttrUseVirtualKey);
|
|
||||||
SetMenuItemCommandKey (carbon_item->menu, carbon_item->index,
|
|
||||||
false, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
carbon_menu_item_accel_changed (GtkAccelGroup *accel_group,
|
|
||||||
guint keyval,
|
|
||||||
GdkModifierType modifier,
|
|
||||||
GClosure *accel_closure,
|
|
||||||
GtkWidget *widget)
|
|
||||||
{
|
|
||||||
CarbonMenuItem *carbon_item = carbon_menu_item_get (widget);
|
|
||||||
GtkWidget *label;
|
|
||||||
|
|
||||||
get_menu_label_text (widget, &label);
|
|
||||||
|
|
||||||
if (GTK_IS_ACCEL_LABEL (label) &&
|
|
||||||
GTK_ACCEL_LABEL (label)->accel_closure == accel_closure)
|
|
||||||
carbon_menu_item_update_accelerator (carbon_item, widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
carbon_menu_item_update_accel_closure (CarbonMenuItem *carbon_item,
|
|
||||||
GtkWidget *widget)
|
|
||||||
{
|
|
||||||
GtkAccelGroup *group;
|
|
||||||
GtkWidget *label;
|
|
||||||
|
|
||||||
get_menu_label_text (widget, &label);
|
|
||||||
|
|
||||||
if (carbon_item->accel_closure)
|
|
||||||
{
|
|
||||||
group = gtk_accel_group_from_accel_closure (carbon_item->accel_closure);
|
|
||||||
if (group)
|
|
||||||
g_signal_handlers_disconnect_by_func (group,
|
|
||||||
carbon_menu_item_accel_changed,
|
|
||||||
widget);
|
|
||||||
|
|
||||||
g_closure_unref (carbon_item->accel_closure);
|
|
||||||
carbon_item->accel_closure = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GTK_IS_ACCEL_LABEL (label))
|
|
||||||
carbon_item->accel_closure = GTK_ACCEL_LABEL (label)->accel_closure;
|
|
||||||
|
|
||||||
if (carbon_item->accel_closure)
|
|
||||||
{
|
|
||||||
g_closure_ref (carbon_item->accel_closure);
|
|
||||||
|
|
||||||
group = gtk_accel_group_from_accel_closure (carbon_item->accel_closure);
|
|
||||||
|
|
||||||
g_signal_connect_object (group, "accel-changed",
|
|
||||||
G_CALLBACK (carbon_menu_item_accel_changed),
|
|
||||||
widget, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
carbon_menu_item_update_accelerator (carbon_item, widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
carbon_menu_item_notify (GObject *object,
|
|
||||||
GParamSpec *pspec,
|
|
||||||
CarbonMenuItem *carbon_item)
|
|
||||||
{
|
|
||||||
if (!strcmp (pspec->name, "sensitive") ||
|
|
||||||
!strcmp (pspec->name, "visible"))
|
|
||||||
{
|
|
||||||
carbon_menu_item_update_state (carbon_item, GTK_WIDGET (object));
|
|
||||||
}
|
|
||||||
else if (!strcmp (pspec->name, "active"))
|
|
||||||
{
|
|
||||||
carbon_menu_item_update_active (carbon_item, GTK_WIDGET (object));
|
|
||||||
}
|
|
||||||
else if (!strcmp (pspec->name, "submenu"))
|
|
||||||
{
|
|
||||||
carbon_menu_item_update_submenu (carbon_item, GTK_WIDGET (object));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
carbon_menu_item_notify_label (GObject *object,
|
|
||||||
GParamSpec *pspec,
|
|
||||||
gpointer data)
|
|
||||||
{
|
|
||||||
CarbonMenuItem *carbon_item = carbon_menu_item_get (GTK_WIDGET (object));
|
|
||||||
|
|
||||||
if (!strcmp (pspec->name, "label"))
|
|
||||||
{
|
|
||||||
carbon_menu_item_update_label (carbon_item,
|
|
||||||
GTK_WIDGET (object));
|
|
||||||
}
|
|
||||||
else if (!strcmp (pspec->name, "accel-closure"))
|
|
||||||
{
|
|
||||||
carbon_menu_item_update_accel_closure (carbon_item,
|
|
||||||
GTK_WIDGET (object));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static CarbonMenuItem *
|
|
||||||
carbon_menu_item_connect (GtkWidget *menu_item,
|
|
||||||
GtkWidget *label,
|
|
||||||
MenuRef menu,
|
|
||||||
MenuItemIndex index)
|
|
||||||
{
|
|
||||||
CarbonMenuItem *carbon_item = carbon_menu_item_get (menu_item);
|
|
||||||
|
|
||||||
if (!carbon_item)
|
|
||||||
{
|
|
||||||
carbon_item = carbon_menu_item_new ();
|
|
||||||
|
|
||||||
g_object_set_qdata_full (G_OBJECT (menu_item), carbon_menu_item_quark,
|
|
||||||
carbon_item,
|
|
||||||
(GDestroyNotify) carbon_menu_item_free);
|
|
||||||
|
|
||||||
g_signal_connect (menu_item, "notify",
|
|
||||||
G_CALLBACK (carbon_menu_item_notify),
|
|
||||||
carbon_item);
|
|
||||||
|
|
||||||
if (label)
|
|
||||||
g_signal_connect_swapped (label, "notify::label",
|
|
||||||
G_CALLBACK (carbon_menu_item_notify_label),
|
|
||||||
menu_item);
|
|
||||||
}
|
|
||||||
|
|
||||||
carbon_item->menu = menu;
|
|
||||||
carbon_item->index = index;
|
|
||||||
|
|
||||||
return carbon_item;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* carbon event handler
|
|
||||||
*/
|
|
||||||
|
|
||||||
gboolean menuitem_activate_wrapper(gpointer data)
|
|
||||||
{
|
|
||||||
gtk_menu_item_activate((GtkMenuItem*)data);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static OSStatus
|
|
||||||
menu_event_handler_func (EventHandlerCallRef event_handler_call_ref,
|
|
||||||
EventRef event_ref,
|
|
||||||
void *data)
|
|
||||||
{
|
|
||||||
UInt32 event_class = GetEventClass (event_ref);
|
|
||||||
UInt32 event_kind = GetEventKind (event_ref);
|
|
||||||
MenuRef menu_ref;
|
|
||||||
|
|
||||||
switch (event_class)
|
|
||||||
{
|
|
||||||
case kEventClassCommand:
|
|
||||||
/* This is called when activating (is that the right GTK+ term?)
|
|
||||||
* a menu item.
|
|
||||||
*/
|
|
||||||
if (event_kind == kEventCommandProcess)
|
|
||||||
{
|
|
||||||
HICommand command;
|
|
||||||
OSStatus err;
|
|
||||||
|
|
||||||
//g_print ("Menu: kEventClassCommand/kEventCommandProcess\n");
|
|
||||||
|
|
||||||
err = GetEventParameter (event_ref, kEventParamDirectObject,
|
|
||||||
typeHICommand, 0,
|
|
||||||
sizeof (command), 0, &command);
|
|
||||||
|
|
||||||
if (err == noErr)
|
|
||||||
{
|
|
||||||
GtkWidget *widget = NULL;
|
|
||||||
|
|
||||||
if (command.commandID == kHICommandQuit)
|
|
||||||
{
|
|
||||||
gtk_main_quit (); /* Just testing... */
|
|
||||||
return noErr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get any GtkWidget associated with the item. */
|
|
||||||
err = GetMenuItemProperty (command.menu.menuRef,
|
|
||||||
command.menu.menuItemIndex,
|
|
||||||
GTK_QUARTZ_MENU_CREATOR,
|
|
||||||
GTK_QUARTZ_ITEM_WIDGET,
|
|
||||||
sizeof (widget), 0, &widget);
|
|
||||||
if (err == noErr && widget)
|
|
||||||
{
|
|
||||||
g_idle_add(menuitem_activate_wrapper,
|
|
||||||
(gpointer)GTK_MENU_ITEM (widget));
|
|
||||||
return noErr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case kEventClassMenu:
|
|
||||||
GetEventParameter (event_ref,
|
|
||||||
kEventParamDirectObject,
|
|
||||||
typeMenuRef,
|
|
||||||
NULL,
|
|
||||||
sizeof (menu_ref),
|
|
||||||
NULL,
|
|
||||||
&menu_ref);
|
|
||||||
|
|
||||||
switch (event_kind)
|
|
||||||
{
|
|
||||||
case kEventMenuTargetItem:
|
|
||||||
/* This is called when an item is selected (what is the
|
|
||||||
* GTK+ term? prelight?)
|
|
||||||
*/
|
|
||||||
//g_print ("kEventClassMenu/kEventMenuTargetItem\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case kEventMenuOpening:
|
|
||||||
/* Is it possible to dynamically build the menu here? We
|
|
||||||
* can at least set visibility/sensitivity.
|
|
||||||
*/
|
|
||||||
//g_print ("kEventClassMenu/kEventMenuOpening\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case kEventMenuClosed:
|
|
||||||
//g_print ("kEventClassMenu/kEventMenuClosed\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CallNextEventHandler (event_handler_call_ref, event_ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
setup_menu_event_handler (void)
|
|
||||||
{
|
|
||||||
EventHandlerUPP menu_event_handler_upp;
|
|
||||||
EventHandlerRef menu_event_handler_ref;
|
|
||||||
const EventTypeSpec menu_events[] = {
|
|
||||||
{ kEventClassCommand, kEventCommandProcess },
|
|
||||||
{ kEventClassMenu, kEventMenuTargetItem },
|
|
||||||
{ kEventClassMenu, kEventMenuOpening },
|
|
||||||
{ kEventClassMenu, kEventMenuClosed }
|
|
||||||
};
|
|
||||||
|
|
||||||
/* FIXME: We might have to install one per window? */
|
|
||||||
|
|
||||||
menu_event_handler_upp = NewEventHandlerUPP (menu_event_handler_func);
|
|
||||||
InstallEventHandler (GetApplicationEventTarget (), menu_event_handler_upp,
|
|
||||||
GetEventTypeCount (menu_events), menu_events, 0,
|
|
||||||
&menu_event_handler_ref);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* FIXME: Remove the handler with: */
|
|
||||||
RemoveEventHandler(menu_event_handler_ref);
|
|
||||||
DisposeEventHandlerUPP(menu_event_handler_upp);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sync_menu_shell (GtkMenuShell *menu_shell,
|
|
||||||
MenuRef carbon_menu,
|
|
||||||
gboolean toplevel)
|
|
||||||
{
|
|
||||||
GList *children;
|
|
||||||
GList *l;
|
|
||||||
MenuItemIndex carbon_index = 1;
|
|
||||||
|
|
||||||
carbon_menu_connect (GTK_WIDGET (menu_shell), carbon_menu);
|
|
||||||
|
|
||||||
children = gtk_container_get_children (GTK_CONTAINER (menu_shell));
|
|
||||||
|
|
||||||
UInt16 carbon_item_count = CountMenuItems(carbon_menu);
|
|
||||||
|
|
||||||
for (l = children; l; l = l->next)
|
|
||||||
{
|
|
||||||
GtkWidget *menu_item = l->data;
|
|
||||||
CarbonMenuItem *carbon_item;
|
|
||||||
|
|
||||||
if (GTK_IS_TEAROFF_MENU_ITEM (menu_item))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (toplevel && g_object_get_data (G_OBJECT (menu_item),
|
|
||||||
"gtk-empty-menu-item"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
GtkWidget *label = NULL;
|
|
||||||
const gchar *label_text = NULL;
|
|
||||||
|
|
||||||
label_text = get_menu_label_text (menu_item, &label);
|
|
||||||
if (label_text && strcmp(label_text, "_SKIP_") == 0)
|
|
||||||
{
|
|
||||||
carbon_index++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (!label_text)
|
|
||||||
label_text = "";
|
|
||||||
|
|
||||||
MenuItemAttributes attributes = 0;
|
|
||||||
if (GTK_IS_SEPARATOR_MENU_ITEM (menu_item))
|
|
||||||
attributes |= kMenuItemAttrSeparator;
|
|
||||||
if (!GTK_WIDGET_IS_SENSITIVE (menu_item))
|
|
||||||
attributes |= kMenuItemAttrDisabled;
|
|
||||||
if (!GTK_WIDGET_VISIBLE (menu_item))
|
|
||||||
attributes |= kMenuItemAttrHidden;
|
|
||||||
|
|
||||||
CFStringRef cfstr = CFStringCreateWithCString (NULL, label_text,
|
|
||||||
kCFStringEncodingUTF8);
|
|
||||||
if (carbon_index > carbon_item_count)
|
|
||||||
AppendMenuItemTextWithCFString(carbon_menu, cfstr, attributes, 0,
|
|
||||||
NULL);
|
|
||||||
else if (!toplevel && (carbon_index > carbon_item_count))
|
|
||||||
InsertMenuItemTextWithCFString (carbon_menu, cfstr,
|
|
||||||
carbon_index, attributes, 0);
|
|
||||||
else
|
|
||||||
SetMenuItemTextWithCFString(carbon_menu, carbon_index, cfstr);
|
|
||||||
CFRelease (cfstr);
|
|
||||||
|
|
||||||
MenuItemAttributes c_attributes = kMenuItemAttrSectionHeader |
|
|
||||||
kMenuItemAttrAutoDisable;
|
|
||||||
if (!(attributes & kMenuItemAttrDisabled))
|
|
||||||
c_attributes |= kMenuItemAttrDisabled;
|
|
||||||
if (!(attributes & kMenuItemAttrSeparator))
|
|
||||||
c_attributes |= kMenuItemAttrSeparator;
|
|
||||||
if (!(attributes & kMenuItemAttrHidden))
|
|
||||||
c_attributes |= kMenuItemAttrHidden;
|
|
||||||
ChangeMenuItemAttributes(carbon_menu, carbon_index,
|
|
||||||
attributes, c_attributes);
|
|
||||||
SetMenuItemProperty (carbon_menu, carbon_index,
|
|
||||||
GTK_QUARTZ_MENU_CREATOR,
|
|
||||||
GTK_QUARTZ_ITEM_WIDGET,
|
|
||||||
sizeof (menu_item), &menu_item);
|
|
||||||
|
|
||||||
carbon_item = carbon_menu_item_connect (menu_item, label,
|
|
||||||
carbon_menu,
|
|
||||||
carbon_index);
|
|
||||||
|
|
||||||
if (GTK_IS_CHECK_MENU_ITEM (menu_item))
|
|
||||||
carbon_menu_item_update_active (carbon_item, menu_item);
|
|
||||||
|
|
||||||
carbon_menu_item_update_accel_closure (carbon_item, menu_item);
|
|
||||||
|
|
||||||
if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu_item)))
|
|
||||||
carbon_menu_item_update_submenu (carbon_item, menu_item);
|
|
||||||
|
|
||||||
carbon_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (carbon_index <= carbon_item_count)
|
|
||||||
{
|
|
||||||
DeleteMenuItem (carbon_menu, carbon_index);
|
|
||||||
carbon_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_list_free (children);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sync_menu_takeover_menu (GtkMenuShell *menu_shell)
|
|
||||||
{
|
|
||||||
static MenuRef carbon_menubar = NULL;
|
|
||||||
|
|
||||||
g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
|
|
||||||
|
|
||||||
if (carbon_menu_quark == 0)
|
|
||||||
carbon_menu_quark = g_quark_from_static_string ("CarbonMenu");
|
|
||||||
|
|
||||||
if (carbon_menu_item_quark == 0)
|
|
||||||
carbon_menu_item_quark = g_quark_from_static_string ("CarbonMenuItem");
|
|
||||||
|
|
||||||
if (!carbon_menubar)
|
|
||||||
{
|
|
||||||
carbon_menubar = AcquireRootMenu();
|
|
||||||
setup_menu_event_handler ();
|
|
||||||
}
|
|
||||||
|
|
||||||
sync_menu_shell (menu_shell, carbon_menubar, TRUE);
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
/* GTK+ Integration for the Mac OS X Menubar.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2007 Pioneer Research Center USA, Inc.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the
|
|
||||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
* Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
|
||||||
|
|
||||||
void sync_menu_takeover_menu (GtkMenuShell *menu_shell);
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
|
@ -1,107 +0,0 @@
|
||||||
#include <gtk/gtk.h>
|
|
||||||
|
|
||||||
#include "sync-menu.h"
|
|
||||||
|
|
||||||
GtkWidget *open_item;
|
|
||||||
GtkWidget *copy_item;
|
|
||||||
|
|
||||||
static void
|
|
||||||
menu_item_activate_cb (GtkWidget *item,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
gboolean visible;
|
|
||||||
gboolean sensitive;
|
|
||||||
|
|
||||||
g_print ("Item activated: %s\n", (gchar *) user_data);
|
|
||||||
|
|
||||||
g_object_get (G_OBJECT (copy_item),
|
|
||||||
"visible", &visible,
|
|
||||||
"sensitive", &sensitive,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (item == open_item) {
|
|
||||||
gtk_widget_set_sensitive (copy_item, !sensitive);
|
|
||||||
/*g_object_set (G_OBJECT (copy_item), "visible", !visible, NULL);*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static GtkWidget *
|
|
||||||
test_setup_menu (void)
|
|
||||||
{
|
|
||||||
GtkWidget *menubar;
|
|
||||||
GtkWidget *menu;
|
|
||||||
GtkWidget *item;
|
|
||||||
|
|
||||||
menubar = gtk_menu_bar_new ();
|
|
||||||
|
|
||||||
item = gtk_menu_item_new_with_label ("File");
|
|
||||||
gtk_menu_shell_append (GTK_MENU_SHELL (menubar), item);
|
|
||||||
menu = gtk_menu_new ();
|
|
||||||
gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
|
|
||||||
item = gtk_menu_item_new_with_label ("Open");
|
|
||||||
open_item = item;
|
|
||||||
g_signal_connect (item, "activate", G_CALLBACK (menu_item_activate_cb), "open");
|
|
||||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
||||||
item = gtk_menu_item_new_with_label ("Quit");
|
|
||||||
g_signal_connect (item, "activate", G_CALLBACK (menu_item_activate_cb), "quit");
|
|
||||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
||||||
|
|
||||||
item = gtk_menu_item_new_with_label ("Edit");
|
|
||||||
|
|
||||||
gtk_menu_shell_append (GTK_MENU_SHELL (menubar), item);
|
|
||||||
menu = gtk_menu_new ();
|
|
||||||
gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
|
|
||||||
item = gtk_menu_item_new_with_label ("Copy");
|
|
||||||
copy_item = item;
|
|
||||||
g_signal_connect (item, "activate", G_CALLBACK (menu_item_activate_cb), "copy");
|
|
||||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
||||||
item = gtk_menu_item_new_with_label ("Paste");
|
|
||||||
g_signal_connect (item, "activate", G_CALLBACK (menu_item_activate_cb), "paste");
|
|
||||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
||||||
|
|
||||||
item = gtk_menu_item_new_with_label ("Help");
|
|
||||||
gtk_menu_shell_append (GTK_MENU_SHELL (menubar), item);
|
|
||||||
menu = gtk_menu_new ();
|
|
||||||
gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
|
|
||||||
item = gtk_menu_item_new_with_label ("About");
|
|
||||||
g_signal_connect (item, "activate", G_CALLBACK (menu_item_activate_cb), "about");
|
|
||||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
||||||
|
|
||||||
return menubar;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main (int argc, char **argv)
|
|
||||||
{
|
|
||||||
GtkWidget *window;
|
|
||||||
GtkWidget *vbox;
|
|
||||||
GtkWidget *menubar;
|
|
||||||
|
|
||||||
gtk_init (&argc, &argv);
|
|
||||||
|
|
||||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
||||||
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
|
|
||||||
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
|
|
||||||
|
|
||||||
vbox = gtk_vbox_new (FALSE, 0);
|
|
||||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
|
||||||
|
|
||||||
menubar = test_setup_menu ();
|
|
||||||
gtk_box_pack_start (GTK_BOX (vbox),
|
|
||||||
menubar,
|
|
||||||
FALSE, TRUE, 0);
|
|
||||||
|
|
||||||
gtk_box_pack_start (GTK_BOX (vbox),
|
|
||||||
gtk_label_new ("Some window content here"),
|
|
||||||
TRUE, TRUE, 0);
|
|
||||||
|
|
||||||
gtk_widget_show_all (window);
|
|
||||||
|
|
||||||
gtk_widget_hide (menubar);
|
|
||||||
|
|
||||||
sync_menu_takeover_menu (GTK_MENU_SHELL (menubar));
|
|
||||||
|
|
||||||
gtk_main ();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
import gtk, syncmenu
|
|
||||||
|
|
||||||
|
|
||||||
open_item = None
|
|
||||||
copy_item = None
|
|
||||||
|
|
||||||
|
|
||||||
def menu_item_activate_cb(item, user_data):
|
|
||||||
print "Item activated: %s" % user_data
|
|
||||||
|
|
||||||
#g_object_get (G_OBJECT (copy_item),
|
|
||||||
# "visible", &visible,
|
|
||||||
# "sensitive", &sensitive,
|
|
||||||
# NULL)
|
|
||||||
|
|
||||||
#if (item == open_item) {
|
|
||||||
#gtk_widget_set_sensitive (copy_item, !sensitive)
|
|
||||||
#/*g_object_set (G_OBJECT (copy_item), "visible", !visible, NULL)*/
|
|
||||||
|
|
||||||
|
|
||||||
def test_setup_menu():
|
|
||||||
global open_item, copy_item
|
|
||||||
menubar = gtk.MenuBar()
|
|
||||||
|
|
||||||
item = gtk.MenuItem("File")
|
|
||||||
menubar.append(item)
|
|
||||||
menu = gtk.Menu()
|
|
||||||
item.set_submenu(menu)
|
|
||||||
item = gtk.MenuItem("Open")
|
|
||||||
open_item = item
|
|
||||||
item.connect("activate", menu_item_activate_cb, "open")
|
|
||||||
menu.append(item)
|
|
||||||
item = gtk.MenuItem("Quit")
|
|
||||||
item.connect("activate", menu_item_activate_cb, "quit")
|
|
||||||
menu.append(item)
|
|
||||||
|
|
||||||
item = gtk.MenuItem("Edit")
|
|
||||||
|
|
||||||
menubar.append(item)
|
|
||||||
menu = gtk.Menu()
|
|
||||||
item.set_submenu(menu)
|
|
||||||
item = gtk.MenuItem("Copy")
|
|
||||||
copy_item = item
|
|
||||||
item.connect("activate", menu_item_activate_cb, "copy")
|
|
||||||
menu.append(item)
|
|
||||||
item = gtk.MenuItem("Paste")
|
|
||||||
item.connect("activate", menu_item_activate_cb, "paste")
|
|
||||||
menu.append(item)
|
|
||||||
|
|
||||||
item = gtk.MenuItem("Help")
|
|
||||||
menubar.append(item)
|
|
||||||
menu = gtk.Menu()
|
|
||||||
item.set_submenu(menu)
|
|
||||||
item = gtk.MenuItem("About")
|
|
||||||
item.connect("activate", menu_item_activate_cb, "about")
|
|
||||||
menu.append(item)
|
|
||||||
|
|
||||||
return menubar
|
|
||||||
|
|
||||||
|
|
||||||
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
|
||||||
window.set_default_size(400, 300)
|
|
||||||
window.connect("destroy", gtk.main_quit, None)
|
|
||||||
|
|
||||||
vbox = gtk.VBox(False, 0)
|
|
||||||
window.add(vbox)
|
|
||||||
|
|
||||||
menubar = test_setup_menu()
|
|
||||||
vbox.pack_start(menubar, False, True, 0)
|
|
||||||
vbox.pack_start(gtk.Label("Some window content here"), True, True, 0)
|
|
||||||
|
|
||||||
window.show_all()
|
|
||||||
menubar.hide()
|
|
||||||
|
|
||||||
syncmenu.takeover_menu(menubar)
|
|
||||||
|
|
||||||
gtk.main()
|
|
||||||
|
|
||||||
# vim: se ts=3:
|
|
|
@ -68,11 +68,6 @@ if dbus_support.supported:
|
||||||
from common.xmpp.protocol import NS_COMMANDS, NS_FILE, NS_MUC
|
from common.xmpp.protocol import NS_COMMANDS, NS_FILE, NS_MUC
|
||||||
from common.pep import MOODS, ACTIVITIES
|
from common.pep import MOODS, ACTIVITIES
|
||||||
|
|
||||||
try:
|
|
||||||
from osx import syncmenu
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
#(icon, name, type, jid, account, editable, second pixbuf)
|
#(icon, name, type, jid, account, editable, second pixbuf)
|
||||||
(
|
(
|
||||||
C_IMG, # image to show state (online, new message etc)
|
C_IMG, # image to show state (online, new message etc)
|
||||||
|
@ -2086,10 +2081,6 @@ class RosterWindow:
|
||||||
self.chg_contact_status(contact, 'offline', '', account)
|
self.chg_contact_status(contact, 'offline', '', account)
|
||||||
self.actions_menu_needs_rebuild = True
|
self.actions_menu_needs_rebuild = True
|
||||||
self.update_status_combobox()
|
self.update_status_combobox()
|
||||||
# Force the rebuild now since the on_activates on the menu itself does
|
|
||||||
# not work with the os/x top level menubar
|
|
||||||
if sys.platform == 'darwin':
|
|
||||||
self.make_menu(force=True)
|
|
||||||
|
|
||||||
def get_status_message(self, show, on_response, show_pep=True,
|
def get_status_message(self, show, on_response, show_pep=True,
|
||||||
always_ask=False):
|
always_ask=False):
|
||||||
|
@ -4862,12 +4853,6 @@ class RosterWindow:
|
||||||
advanced_menuitem.set_submenu(advanced_sub_menu)
|
advanced_menuitem.set_submenu(advanced_sub_menu)
|
||||||
advanced_sub_menu.show_all()
|
advanced_sub_menu.show_all()
|
||||||
|
|
||||||
if sys.platform == 'darwin':
|
|
||||||
try:
|
|
||||||
syncmenu.takeover_menu(self.xml.get_widget('menubar'))
|
|
||||||
except NameError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
self.actions_menu_needs_rebuild = False
|
self.actions_menu_needs_rebuild = False
|
||||||
|
|
||||||
def build_account_menu(self, account):
|
def build_account_menu(self, account):
|
||||||
|
@ -6080,14 +6065,6 @@ class RosterWindow:
|
||||||
account, bookmark)
|
account, bookmark)
|
||||||
gc_sub_menu.append(item)
|
gc_sub_menu.append(item)
|
||||||
|
|
||||||
def set_actions_menu_needs_rebuild(self):
|
|
||||||
self.actions_menu_needs_rebuild = True
|
|
||||||
# Force the rebuild now since the on_activates on the menu itself does
|
|
||||||
# not work with the os/x top level menubar
|
|
||||||
if sys.platform == 'darwin':
|
|
||||||
self.make_menu(force=True)
|
|
||||||
return
|
|
||||||
|
|
||||||
def show_appropriate_context_menu(self, event, iters):
|
def show_appropriate_context_menu(self, event, iters):
|
||||||
# iters must be all of the same type
|
# iters must be all of the same type
|
||||||
model = self.modelfilter
|
model = self.modelfilter
|
||||||
|
@ -6128,54 +6105,6 @@ class RosterWindow:
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def setup_for_osx(self):
|
|
||||||
'''Massage the GTK menu so it will match up to the OS/X nib style menu
|
|
||||||
when passed to sync-menu and merged'''
|
|
||||||
pass
|
|
||||||
# This is broken
|
|
||||||
# main_menu = self.xml.get_widget('menubar')
|
|
||||||
# app_item = gtk.MenuItem('Gajim')
|
|
||||||
# main_menu.insert(app_item, 0)
|
|
||||||
# win_item = gtk.MenuItem('Window')
|
|
||||||
# main_menu.insert(win_item, 4)
|
|
||||||
# actions_menu = self.xml.get_widget('actions_menu_menu')
|
|
||||||
# quit_item = self.xml.get_widget('quit_menuitem')
|
|
||||||
# actions_menu.remove(quit_item)
|
|
||||||
# actions_menu.remove(self.xml.get_widget('separator1'))
|
|
||||||
# edit_menu = self.xml.get_widget('edit_menu_menu')
|
|
||||||
# #edit_menu.remove(self.xml.get_widget('preferences_menuitem'))
|
|
||||||
# edit_menu.remove(self.xml.get_widget('separator2'))
|
|
||||||
# help_menu = self.xml.get_widget('help_menu_menu')
|
|
||||||
# about_item = self.xml.get_widget('about_menuitem')
|
|
||||||
# help_menu.remove(about_item)
|
|
||||||
# # Build up App menu
|
|
||||||
# app_menu = gtk.Menu()
|
|
||||||
# app_item.set_submenu(app_menu)
|
|
||||||
# app_menu.append(about_item)
|
|
||||||
# app_menu.append(gtk.MenuItem('__SKIP__'))
|
|
||||||
# prefs_item = gtk.MenuItem('Preferences...')
|
|
||||||
# prefs_item.connect('activate', self.on_preferences_menuitem_activate)
|
|
||||||
# accels = gtk.AccelGroup()
|
|
||||||
# self.xml.get_widget('roster_window').add_accel_group(accels)
|
|
||||||
# prefs_item.add_accelerator('activate', accels, ord(','),
|
|
||||||
# gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
|
|
||||||
# app_menu.append(prefs_item)
|
|
||||||
# app_menu.append(gtk.MenuItem('__SKIP__'))
|
|
||||||
# app_menu.append(gtk.MenuItem('__SKIP__'))
|
|
||||||
# app_menu.append(gtk.MenuItem('__SKIP__'))
|
|
||||||
# app_menu.append(gtk.MenuItem('__SKIP__'))
|
|
||||||
# app_menu.append(gtk.MenuItem('__SKIP__'))
|
|
||||||
# app_menu.append(gtk.MenuItem('__SKIP__'))
|
|
||||||
# app_menu.append(gtk.MenuItem('__SKIP__'))
|
|
||||||
# app_menu.append(quit_item)
|
|
||||||
# app_menu.show_all()
|
|
||||||
# # Do the merge baby!
|
|
||||||
# syncmenu.takeover_menu(main_menu)
|
|
||||||
# self.make_menu(force=True)
|
|
||||||
# # Hide the GTK menubar itself and let the OS/X menubar do its thing
|
|
||||||
# #self.xml.get_widget('menubar').hide()
|
|
||||||
# return
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
###
|
###
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -6434,8 +6363,4 @@ class RosterWindow:
|
||||||
from common.zeroconf import connection_zeroconf
|
from common.zeroconf import connection_zeroconf
|
||||||
connection_zeroconf.ConnectionZeroconf(gajim.ZEROCONF_ACC_NAME)
|
connection_zeroconf.ConnectionZeroconf(gajim.ZEROCONF_ACC_NAME)
|
||||||
|
|
||||||
if sys.platform == 'darwin':
|
|
||||||
self.setup_for_osx()
|
|
||||||
|
|
||||||
|
|
||||||
# vim: se ts=3:
|
# vim: se ts=3:
|
||||||
|
|
|
@ -30,12 +30,6 @@ import systray
|
||||||
from common import gajim
|
from common import gajim
|
||||||
from common import helpers
|
from common import helpers
|
||||||
|
|
||||||
if sys.platform == 'darwin':
|
|
||||||
try:
|
|
||||||
import osx
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
class StatusIcon(systray.Systray):
|
class StatusIcon(systray.Systray):
|
||||||
'''Class for the notification area icon'''
|
'''Class for the notification area icon'''
|
||||||
#NOTE: gtk api does NOT allow:
|
#NOTE: gtk api does NOT allow:
|
||||||
|
@ -73,11 +67,6 @@ class StatusIcon(systray.Systray):
|
||||||
text = helpers.get_notification_icon_tooltip_text()
|
text = helpers.get_notification_icon_tooltip_text()
|
||||||
self.status_icon.set_tooltip(text)
|
self.status_icon.set_tooltip(text)
|
||||||
if gajim.events.get_nb_systray_events():
|
if gajim.events.get_nb_systray_events():
|
||||||
if sys.platform == 'darwin':
|
|
||||||
try:
|
|
||||||
osx.nsapp.requestUserAttention()
|
|
||||||
except NameError:
|
|
||||||
pass
|
|
||||||
state = 'event'
|
state = 'event'
|
||||||
self.status_icon.set_blinking(True)
|
self.status_icon.set_blinking(True)
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Add table
Reference in a new issue