main.c (4507B)
1 /* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail> 2 * See LICENSE file for license details. 3 */ 4 #define EXTERN 5 #include "dat.h" 6 #include <X11/Xproto.h> 7 #include <locale.h> 8 #include <stdio.h> 9 #include <string.h> 10 #include <stuff/clientutil.h> 11 #include <sys/signal.h> 12 #include "fns.h" 13 14 static const char version[] = "witray-"VERSION", "COPYRIGHT"\n"; 15 16 static int exitsignal; 17 static struct sigaction sa; 18 19 static void 20 usage(void) { 21 fprint(2, "usage: %s [-a <address>] [-NESW] [-HVn] [-p <padding>] [-s <iconsize>] [-t tags]\n" 22 " %s -v\n", argv0, argv0); 23 exit(1); 24 } 25 26 static int 27 errfmt(Fmt *f) { 28 return fmtstrcpy(f, ixp_errbuf()); 29 } 30 31 static void 32 cleanup_handler(int signal) { 33 sa.sa_handler = SIG_DFL; 34 sigaction(signal, &sa, nil); 35 36 selection_release(tray.selection); 37 srv.running = false; 38 39 switch(signal) { 40 case SIGINT: 41 case SIGTERM: 42 sa.sa_handler = cleanup_handler; 43 sigaction(SIGALRM, &sa, nil); 44 alarm(1); 45 default: 46 exitsignal = signal; 47 break; 48 case SIGALRM: 49 raise(SIGTERM); 50 } 51 } 52 53 static void 54 init_traps(void) { 55 56 sa.sa_flags = 0; 57 sa.sa_handler = cleanup_handler; 58 sigaction(SIGINT, &sa, nil); 59 sigaction(SIGTERM, &sa, nil); 60 sigaction(SIGQUIT, &sa, nil); 61 sigaction(SIGHUP, &sa, nil); 62 sigaction(SIGUSR1, &sa, nil); 63 sigaction(SIGUSR2, &sa, nil); 64 } 65 66 void 67 cleanup(Selection *s) { 68 USED(s); 69 70 while(tray.clients) 71 client_disown(tray.clients); 72 tray.selection = nil; 73 srv.running = false; 74 } 75 76 void 77 message(Selection *s, XClientMessageEvent *ev) { 78 Window *w; 79 Client *c; 80 81 USED(s); 82 83 Dprint("message(%A) 0x%lx\n", ev->message_type, ev->window); 84 Dprint("\t0x%lx, 0x%lx, 0x%ulx, 0x%ulx, 0x%ulx\n", 85 ev->data.l[0], ev->data.l[1], ev->data.l[2], ev->data.l[3], ev->data.l[4]); 86 87 w = findwin(ev->window); 88 if(w == nil) 89 return; 90 91 if(w == tray.selection->owner) { 92 if(ev->message_type == NET("SYSTEM_TRAY_OPCODE") && ev->format == 32) 93 if(ev->data.l[1] == TrayRequestDock) 94 client_manage(ev->data.l[2]); 95 return; 96 } 97 98 if((c = client_find(w))) { 99 if(ev->message_type == NET("SYSTEM_TRAY_OPCODE") && ev->format == 32) 100 client_opcode(w->aux, ev->data.l[1], ev->data.l[2], ev->data.l[3], ev->data.l[4]); 101 else 102 client_message(w->aux, ev->message_type, ev->format, (ClientMessageData*)&ev->data); 103 return; 104 } 105 } 106 107 ErrorCode ignored_xerrors[] = { 108 { 0, BadWindow }, 109 { X_GetAtomName, BadAtom }, 110 }; 111 112 int 113 main(int argc, char *argv[]) { 114 static char* address; 115 bool steal; 116 117 program_args = argv; 118 119 setlocale(LC_CTYPE, ""); 120 fmtinstall('r', errfmt); 121 fmtinstall('E', fmtevent); 122 123 steal = true; 124 tray.orientation = OHorizontal; 125 tray.tags = "/./"; 126 tray.padding = 1; 127 128 ARGBEGIN{ 129 case 'N': 130 tray.edge = (tray.edge & ~South) | North; 131 break; 132 case 'S': 133 tray.edge = (tray.edge & ~North) | South; 134 break; 135 case 'E': 136 tray.edge = (tray.edge & ~West) | East; 137 break; 138 case 'W': 139 tray.edge = (tray.edge & ~East) | West; 140 break; 141 case 'H': 142 tray.orientation = OHorizontal; 143 break; 144 case 'V': 145 tray.orientation = OVertical; 146 break; 147 case 'n': 148 steal = false; 149 break; 150 case 'p': 151 if(!getulong(EARGF(usage()), &tray.padding)) 152 usage(); 153 tray.padding = max(1, min(10, (int)tray.padding)); 154 break; 155 case 's': 156 if(!getulong(EARGF(usage()), &tray.iconsize)) 157 usage(); 158 tray.iconsize = max(1, (int)tray.iconsize); 159 break; 160 case 't': 161 tray.tags = EARGF(usage()); 162 break; 163 case 'a': 164 address = EARGF(usage()); 165 break; 166 case 'D': 167 debug++; 168 break; 169 case 'v': 170 lprint(1, "%s", version); 171 return 0; 172 default: 173 usage(); 174 }ARGEND; 175 176 if(argc) 177 usage(); 178 179 init_traps(); 180 initdisplay(); 181 182 srv.preselect = event_preselect; 183 ixp_listen(&srv, ConnectionNumber(display), nil, event_fdready, event_fdclosed); 184 185 event_updatextime(); 186 tray.selection = selection_manage(sxprint(Net("SYSTEM_TRAY_S%d"), scr.screen), 187 event_xtime, message, cleanup, steal); 188 if(tray.selection == nil) 189 fatal("Another system tray is already running."); 190 if(tray.selection->oldowner) 191 lprint(1, "%s: Replacing currently running system tray.\n", argv0); 192 193 xext_init(); 194 tray_init(); 195 196 client_init(address); 197 198 if(tray.edge == 0) 199 tray.edge = West | (!strcmp(readctl("/ctl", "bar on "), "top") ? North : South); 200 201 client_readconfig(&tray.normcolors, &tray.selcolors, &tray.font); 202 203 if(tray.iconsize == 0) /* Default to wmii's bar size. */ 204 tray.iconsize = labelh(tray.font) - 2 * tray.padding; 205 206 srv.running = true; 207 ixp_serverloop(&srv); 208 209 if(tray.selection) 210 selection_release(tray.selection); 211 212 XCloseDisplay(display); 213 214 if(exitsignal) 215 raise(exitsignal); 216 return 0; 217 } 218