[Tkabber-dev] r166 - in trunk/plugins: . urgent

tkabber-svn at jabber.ru tkabber-svn at jabber.ru
Wed Jan 21 04:31:39 MSK 2009


Author: kostix
Date: 2009-01-21 04:31:38 +0300 (Wed, 21 Jan 2009)
New Revision: 166

Added:
   trunk/plugins/urgent/
   trunk/plugins/urgent/urgent.c
   trunk/plugins/urgent/urgent.tcl
Log:
Added preliminary implementation of the "urgent" plugin
which controls the X Window "urgency" hint on Tkabber
chat windows.
See http://www.jabber.ru/bugzilla/show_bug.cgi?id=389


Added: trunk/plugins/urgent/urgent.c
===================================================================
--- trunk/plugins/urgent/urgent.c	                        (rev 0)
+++ trunk/plugins/urgent/urgent.c	2009-01-21 01:31:38 UTC (rev 166)
@@ -0,0 +1,103 @@
+/*
+ * $Id$
+ *
+ * Compile with
+ *     gcc -L/usr/X11R6/lib -lX11 urgent.c -o urgent
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+typedef long (*FLAGMANIP) (long);
+
+static long set_urgency(long flags)
+{
+	return flags | XUrgencyHint;
+}
+
+static long clear_urgency(long flags)
+{
+	return flags & ~XUrgencyHint;
+}
+
+static long toggle_urgency(long flags)
+{
+	if ((flags & XUrgencyHint) == 0) {
+		return set_urgency(flags);
+	} else {
+		return clear_urgency(flags);
+	}
+}
+
+static int apply(Display *dpy, Window id, FLAGMANIP f)
+{
+	XWMHints *hints = XGetWMHints(dpy, id);
+
+	if (hints == NULL)
+		return 0;
+
+	hints->flags = f(hints->flags);
+
+	return (XSetWMHints(dpy, id, hints) != 0);
+}
+
+int main(int argc, char *argv[])
+{
+	const char helpstr[] = "Usage: urgent {-set|-clear|-toggle} XWINID\n";
+	Display *dpy;
+	Window id;
+	FLAGMANIP action;
+
+	if (argc == 2 && strcmp(argv[1], "-help") == 0) {
+		printf("Sets, clears or toggles the \"urgency\" flag "
+			"for a specified X window using its WM_HINTS property\n");
+		printf(helpstr);
+		return EXIT_SUCCESS;
+	}
+
+	if (argc != 3) {
+		fprintf(stderr, "Wrong number of agruments\n");
+		fprintf(stderr, helpstr);
+		return EXIT_FAILURE;
+	}
+
+	if (strcmp(argv[1], "-set") == 0) {
+		action = set_urgency;
+	} else if (strcmp(argv[1], "-clear") == 0) {
+		action = clear_urgency;
+	} else if (strcmp(argv[1], "-toggle") == 0) {
+		action = toggle_urgency;
+	} else {
+		fprintf(stderr, "Invalid action \"%s\", "
+			"must be one of -set, -clear or -toggle\n", argv[1]);
+		return EXIT_FAILURE;
+	}
+
+	errno = 0;
+	id = strtol(argv[2], NULL, 16);
+	if (errno != 0) {
+		fprintf(stderr, "Invalid X window id \"%s\", "
+			"must be a hexadecimal integer\n", argv[2]);
+		return EXIT_FAILURE;
+	}
+
+	dpy = XOpenDisplay(NULL);
+
+	if (dpy == NULL) {
+		fprintf(stderr, "Unable to open display.");
+		return EXIT_FAILURE;
+	}
+
+	apply(dpy, id, action);
+
+	XFlush(dpy);
+
+	XCloseDisplay(dpy);
+
+	return EXIT_SUCCESS;
+}
+


Property changes on: trunk/plugins/urgent/urgent.c
___________________________________________________________________
Added: svn:keywords
   + Id
Added: svn:eol-style
   + native

Added: trunk/plugins/urgent/urgent.tcl
===================================================================
--- trunk/plugins/urgent/urgent.tcl	                        (rev 0)
+++ trunk/plugins/urgent/urgent.tcl	2009-01-21 01:31:38 UTC (rev 166)
@@ -0,0 +1,144 @@
+# $Id$
+
+namespace eval urgent {
+    custom::defgroup Urgent [::msgcat::mc "Urgency hinting."] -group Plugins
+
+    custom::defvar options(enabled) 1 \
+	[::msgcat::mc "Set the urgency hint on Tkabber's chat\
+	    window when a new message is received."] \
+	-type boolean \
+	-group Urgent
+
+    custom::defvar options(handle_personal_messages) 1 \
+	[::msgcat::mc "React on messages addressed to us."] \
+	-type boolean \
+	-group Urgent
+
+    custom::defvar options(handle_normal_messages) 0 \
+	[::msgcat::mc "React on messages in MUC rooms\
+	    which are not addressed to us."] \
+	-type boolean \
+	-group Urgent
+
+    custom::defvar options(handle_server_messages) 0 \
+	[::msgcat::mc "React on messages generated by the server"] \
+	-type boolean \
+	-group Urgent
+}
+
+proc urgent::chat_message_notify {chatid from type body extras} {
+    variable options
+
+    if {!$options(enabled)} return
+
+    set delayed [::xmpp::delay::exists $extras]
+    if {$delayed} return
+
+    switch -- $type {
+	groupchat {
+	    if {[string equal [chat::get_jid $chatid] $from]} {
+		if {$options(handle_server_messages)} {
+		    notify $chatid
+		}
+	    } else {
+		set mynick [chat::get_nick [chat::get_xlib $chatid] \
+					   [chat::our_jid $chatid] $type]
+		if {[check_message $mynick $body]} {
+		    if {$options(handle_personal_messages)} {
+			notify $chatid
+		    }
+		} else {
+		    if {$options(handle_normal_messages)} {
+			notify $chatid
+		    }
+		}
+	    }
+	}
+	chat {
+	    foreach xelem $extras {
+		::xmpp::xml::split $xelem tag xmlns attrs cdata subels
+		# Don't play sound if this 'empty' tag is present. It indicates
+		# messages history in chat window.
+		if {[string equal $tag ""] && \
+				    [string equal $xmlns tkabber:x:nolog]} {
+		    return
+		}
+	    }
+
+	    if {$from == "" && $options(handle_server_messages)} {
+		notify $chatid
+	    } elseif {$options(handle_personal_messages)} {
+		notify $chatid
+	    }
+	}
+    }
+}
+
+proc urgent::notify {chatid} {
+    variable options
+    variable xwinids
+
+    exec $options(program) -set $xwinids($chatid)
+}
+
+proc urgent::xwinid {win} {
+    # Parent window id: 0x2e0001e "Tkabber"
+    set data [exec xwininfo -children -id [winfo id $win]]
+    if {[regexp {Parent window id: (\S+)} $data -> id]} {
+	return $id
+    } else {
+	return ""
+    }	
+}
+
+proc urgent::root_winid {xwinid _chatid} {
+    return $xwinid
+}
+
+proc urgent::chat_winid {chatid} {
+    xwinid [winfo id [chat::winid $chatid]]
+}
+
+proc urgent::record_xwinid {chatid _type} {
+    variable xwinids
+    set xwinids($chatid) [winid $chatid]
+}
+
+proc urgent::clear_urgency_hint {winid} {
+    variable options
+    variable xwinids
+
+    set chatid [chat::winid_to_chatid $winid]
+    
+    exec $options(program) -clear $xwinids($chatid)
+}
+
+namespace eval urgent {
+    variable options
+
+    if {![info exists options(program)]} {
+	set options(program) [file join \
+	    [file dirname [info script]] urgent]
+    }
+    if {![file executable $options(program)]} {
+	puts stderr [::msgcat::mc "Urgency hint setting program \"%s\"\
+	    is not available or not executed by the current user.\
+	    The \"urgent\" plugin is disabled. Consult its README file."
+	    $options(program)]
+	set options(enabled) 0
+    }
+
+    if {$::ifacetk::options(use_tabbar)} {
+	interp alias {} [namespace current]::winid \
+	    {} [namespace current]::root_winid [xwinid .]
+    } else {
+	interp alias {} [namespace current]::winid \
+	    {} [namespace current]::chat_winid
+    }
+
+    hook::add open_chat_post_hook [namespace current]::record_xwinid 40
+    hook::add draw_message_hook [namespace current]::chat_message_notify 19
+    hook::add got_focus_hook [namespace current]::clear_urgency_hint
+}
+
+# vim:ts=8:sw=4:sts=4:noet


Property changes on: trunk/plugins/urgent/urgent.tcl
___________________________________________________________________
Added: svn:keywords
   + Id
Added: svn:eol-style
   + native



More information about the Tkabber-dev mailing list