1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
|
/*
File : flash.cpp
Description : Contains all functions for the Tk extension of flash windows
This is an extension for Tk only for windows, it will make the window
flash in the taskbar until it gets focus.
MAN :
NAME :
winflash - Flashes the window taskbar and caption of a toplevel widget
SYNOPSYS :
winflash window_name
DESCRIPTION :
This command will make the taskbar of a toplevel window and it's caption flash under linux,
the window_name argument must be the tk pathname of a toplevel widget (.window for example)
Author : Youness El Alaoui (KaKaRoTo - kakaroto@users.sourceforge.net)
Sander Hoentjen (Tjikkun)
*/
// Include the header file
#include "flash.h"
/*
Function : Tk_FlashWindow
Description : This is the function that does the whole job, it will flash the window as
given in it's argument
Arguments : ClienData clientdata : who knows what's that used for :P
anways, it's set to NULL and it's not used
Tcl_Interp *interp : This is the interpreter that called this function
it will be used to get some info about the window used
int objc : This is the number of arguments given to the function
Tcl_Obj *CONST objv[] : This is the array that contains all arguments given to
the function
Return value : TCL_OK in case everything is ok, or TCL_ERROR in case there is an error
Comments : http://standards.freedesktop.org/wm-spec/1.4/ar01s05.html#id2527339
*/
int Tk_FlashWindow (ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]) {
// We verify the arguments, we must have one arg, not more
if( objc != 2) {
Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"linflash window_name\"" , (char *) NULL);
return TCL_ERROR;
}
return flash_window(interp, objv[1], 1);
}
int Tk_UnFlashWindow (ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]) {
// We verify the arguments, we must have one arg, not more
if( objc != 2) {
Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"linunflash window_name\"" , (char *) NULL);
return TCL_ERROR;
}
return flash_window(interp, objv[1], 0);
}
int flash_window (Tcl_Interp *interp, Tcl_Obj *CONST objv1, int flash) {
// We declare our variables, we need one for every intermediate token we get,
// so we can verify if one of the function calls returned NULL
char * win = NULL;
Tk_Window tkwin;
Window window;
Display * xdisplay;
Window root, parent, *children;
unsigned int n;
unsigned int demandsSuccess = 0;
// Get the first argument string (object name) and check it
win = Tcl_GetStringFromObj(objv1, NULL);
// We check if the pathname is valid, this means it must beguin with a "."
// the strncmp(win, ".", 1) is used to compare the first char of the pathname
if (strncmp(win,".",1)) {
Tcl_AppendResult (interp, "Bad window path name : ",
Tcl_GetStringFromObj(objv1, NULL) , (char *) NULL);
return TCL_ERROR;
}
// Here we ge the long pathname (tk window name), from the short pathname, using the MainWindow from the interpreter
tkwin = Tk_NameToWindow(interp, win, Tk_MainWindow(interp));
// Error check
if ( tkwin == NULL) return TCL_ERROR;
// We then get the windowId (the X token) of the window, from it's long pathname
window = Tk_WindowId(tkwin);
// Error check
if ( window == NULL ) {
Tcl_AppendResult (interp, "error while processing WindowId : Window probably not viewable", (char *) NULL);
return TCL_ERROR;
}
xdisplay = Tk_Display(tkwin);
/* We get the window id of the root toplevel window */
XQueryTree(xdisplay, window, &root, &parent, &children, &n);
XFree(children);
//Since under *nix Tk wraps all windows in another one to put a menu bar, we must use the parent window ID which is the top one
demandsSuccess = demands_attention(xdisplay, root, parent, flash);
// If we disable flash, we make sure the UrencyHint is really disabled
// If either the WM doesn't support DEMANDS_ATTENTION or setting it failed, we use the Urgency flag
if (!demandsSuccess || !flash) {
setUrgencyHint(xdisplay, parent, flash);
}
//We return error to make the title change for really shitty/special WMs that don't support DEMANDS_ATTENTION
//We can't get a reliable way to determine if Urgency failed so even if it was success we ensure that application will use a fallback
return (demandsSuccess?TCL_OK:TCL_ERROR);
}
int demands_attention(Display *display, Window root, Window window, int flash) {
static Atom demandsAttention, wmState, wmSupported;
Atom type_return;
Atom *curr_atom = NULL;
int format_return;
unsigned long nitems_return;
unsigned long bytes_after_return;
unsigned char *prop_return = NULL;
int hasFlag = 0;
XEvent e;
memset(&e, 0, sizeof(e));
// We need Atom-s created only once, they don't change during runtime
demandsAttention = XInternAtom(display, "_NET_WM_STATE_DEMANDS_ATTENTION", True);
wmState = XInternAtom(display, "_NET_WM_STATE", True);
wmSupported = XInternAtom(display, "_NET_SUPPORTED", True);
if( XGetWindowProperty( display, root, wmSupported, 0, 4096, False, XA_ATOM,
&type_return, &format_return,
&nitems_return, &bytes_after_return,
&prop_return ) == Success && nitems_return ) {
for( curr_atom = (Atom *)prop_return; nitems_return > 0; nitems_return--, curr_atom++) {
if ( *curr_atom == demandsAttention) {
hasFlag = 1;
break;
}
}
XFree( prop_return );
}
e.xclient.type = ClientMessage;
e.xclient.message_type = wmState;
e.xclient.window = window;
e.xclient.display = display;
e.xclient.format = 32;
e.xclient.data.l[0] = flash;
e.xclient.data.l[1] = demandsAttention;
e.xclient.data.l[2] = 0l;
e.xclient.data.l[3] = 0l;
e.xclient.data.l[4] = 0l;
/* If the WM doesn't support the DEMANDS_ATTENTION, then we still send the event because some
* WMs (like xfce) support it but they tell us they don't. And we return TCL_ERROR just to make sure
* in case it *really* didn't support it, that the calling application does the fallback action.
*/
hasFlag = XSendEvent(display, root, False, (SubstructureRedirectMask | SubstructureNotifyMask), &e) && hasFlag;
return hasFlag;
}
int setUrgencyHint(Display *display, Window window, int flash) {
XWMHints *hints;
hints = XGetWMHints(display, window);
if (hints != NULL) {
if (flash)
hints->flags |= XUrgencyHint;
else
hints->flags &= ~XUrgencyHint;
XSetWMHints(display, window, hints);
XFree(hints);
return 1;
}
return 0;
}
/*
Function : Flash_Init
Description : The Init function that will be called when the extension is loaded to your tk shell
Arguments : Tcl_Interp *interp : This is the interpreter from which the load was made and to
which we'll add the new command
Return value : TCL_OK in case everything is ok, or TCL_ERROR in case there is an error (Tk version < 8.3)
Comments : hummmm... not much, it's simple :)
*/
int Flash_Init (Tcl_Interp *interp ) {
//Check TK version is 8.0 or higher
if (Tk_InitStubs(interp, "8.3", 0) == NULL) {
return TCL_ERROR;
}
// Create the new commands
Tcl_CreateObjCommand(interp, "linflash", Tk_FlashWindow,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "linunflash", Tk_UnFlashWindow,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
// end
return TCL_OK;
}
|