Xinqi Bao's Git
   2  * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com> 
   3  * See LICENSE file for license details. 
  12 #include <sys/types.h> 
  15 #include <X11/cursorfont.h> 
  16 #include <X11/Xatom.h> 
  17 #include <X11/Xproto.h> 
  24 Atom wm_atom
[WMLast
], net_atom
[NetLast
]; 
  25 Cursor cursor
[CurLast
]; 
  29 char statustext
[1024], tag
[256]; 
  30 int screen
, sx
, sy
, sw
, sh
, bx
, by
, bw
, bh
; 
  33 Client 
*clients 
= NULL
; 
  36 static Bool other_wm_running
; 
  37 static const char version
[] = "gridwm - " VERSION 
", (C)opyright MMVI Anselm R. Garbe\n"; 
  38 static int (*x_error_handler
) (Display 
*, XErrorEvent 
*); 
  40 static const char *status
[] = { 
  41         "sh", "-c", "echo -n `date '+%Y-%m-%d %H:%M'`"  
  42         " `uptime | sed 's/.*://; s/,//g'`" 
  43         " `acpi | awk '{print $4}' | sed 's/,//'`", 0 
  49         fputs("usage: gridwm [-v]\n", stderr
); 
  61         if(XQueryTree(dpy
, root
, &d1
, &d2
, &wins
, &num
)) { 
  62                 for(i 
= 0; i 
< num
; i
++) { 
  63                         if(!XGetWindowAttributes(dpy
, wins
[i
], &wa
)) 
  65                         if(wa
.override_redirect 
|| XGetTransientForHint(dpy
, wins
[i
], &d1
)) 
  67                         if(wa
.map_state 
== IsViewable
) 
  76 win_property(Window w
, Atom a
, Atom t
, long l
, unsigned char **prop
) 
  80         unsigned long res
, extra
; 
  83         status 
= XGetWindowProperty(dpy
, w
, a
, 0L, l
, False
, t
, &real
, &format
, 
  86         if(status 
!= Success 
|| *prop 
== 0) { 
  98         unsigned char *protocols
; 
 103         res 
= win_property(w
, wm_atom
[WMProtocols
], XA_ATOM
, 20L, &protocols
); 
 107         for(i 
= 0; i 
< res
; i
++) { 
 108                 if(protocols
[i
] == wm_atom
[WMDelete
]) 
 109                         protos 
|= WM_PROTOCOL_DELWIN
; 
 111         free((char *) protocols
); 
 116 send_message(Window w
, Atom a
, long value
) 
 120         e
.type 
= ClientMessage
; 
 121         e
.xclient
.window 
= w
; 
 122         e
.xclient
.message_type 
= a
; 
 123         e
.xclient
.format 
= 32; 
 124         e
.xclient
.data
.l
[0] = value
; 
 125         e
.xclient
.data
.l
[1] = CurrentTime
; 
 126         XSendEvent(dpy
, w
, False
, NoEventMask
, &e
); 
 131  * There's no way to check accesses to destroyed windows, thus 
 132  * those cases are ignored (especially on UnmapNotify's). 
 133  * Other types of errors call Xlib's default error handler, which 
 137 error_handler(Display 
*dpy
, XErrorEvent 
*error
) 
 139         if(error
->error_code 
== BadWindow
 
 140                         || (error
->request_code 
== X_SetInputFocus
 
 141                                 && error
->error_code 
== BadMatch
) 
 142                         || (error
->request_code 
== X_PolyText8
 
 143                                 && error
->error_code 
== BadDrawable
) 
 144                         || (error
->request_code 
== X_PolyFillRectangle
 
 145                                 && error
->error_code 
== BadDrawable
) 
 146                         || (error
->request_code 
== X_PolySegment
 
 147                                 && error
->error_code 
== BadDrawable
) 
 148                         || (error
->request_code 
== X_ConfigureWindow
 
 149                                 && error
->error_code 
== BadMatch
) 
 150                         || (error
->request_code 
== X_GrabKey
 
 151                                 && error
->error_code 
== BadAccess
)) 
 153         fprintf(stderr
, "gridwm: fatal error: request code=%d, error code=%d\n", 
 154                         error
->request_code
, error
->error_code
); 
 155         return x_error_handler(dpy
, error
); /* may call exit() */ 
 159  * Startup Error handler to check if another window manager 
 160  * is already running. 
 163 startup_error_handler(Display 
*dpy
, XErrorEvent 
*error
) 
 165         other_wm_running 
= True
; 
 174         XSetInputFocus(dpy
, PointerRoot
, RevertToPointerRoot
, CurrentTime
); 
 190 main(int argc
, char *argv
[]) 
 193         XSetWindowAttributes wa
; 
 198         struct timeval t
, timeout 
= { 
 200                 .tv_sec 
= STATUSDELAY
, 
 203         /* command line args */ 
 204         for(i 
= 1; (i 
< argc
) && (argv
[i
][0] == '-'); i
++) { 
 205                 switch (argv
[i
][1]) { 
 207                         fprintf(stdout
, "%s", version
); 
 216         dpy 
= XOpenDisplay(0); 
 218                 error("gridwm: cannot connect X server\n"); 
 220         screen 
= DefaultScreen(dpy
); 
 221         root 
= RootWindow(dpy
, screen
); 
 223         /* check if another WM is already running */ 
 224         other_wm_running 
= False
; 
 225         XSetErrorHandler(startup_error_handler
); 
 226         /* this causes an error if some other WM is running */ 
 227         XSelectInput(dpy
, root
, SubstructureRedirectMask
); 
 231                 error("gridwm: another window manager is already running\n"); 
 234         sw 
= DisplayWidth(dpy
, screen
); 
 235         sh 
= DisplayHeight(dpy
, screen
); 
 236         sel_screen 
= XQueryPointer(dpy
, root
, &w
, &w
, &i
, &i
, &i
, &i
, &mask
); 
 239         x_error_handler 
= XSetErrorHandler(error_handler
); 
 242         wm_atom
[WMProtocols
] = XInternAtom(dpy
, "WM_PROTOCOLS", False
); 
 243         wm_atom
[WMDelete
] = XInternAtom(dpy
, "WM_DELETE_WINDOW", False
); 
 244         net_atom
[NetSupported
] = XInternAtom(dpy
, "_NET_SUPPORTED", False
); 
 245         net_atom
[NetWMName
] = XInternAtom(dpy
, "_NET_WM_NAME", False
); 
 247         XChangeProperty(dpy
, root
, net_atom
[NetSupported
], XA_ATOM
, 32, 
 248                         PropModeReplace
, (unsigned char *) net_atom
, NetLast
); 
 252         cursor
[CurNormal
] = XCreateFontCursor(dpy
, XC_left_ptr
); 
 253         cursor
[CurResize
] = XCreateFontCursor(dpy
, XC_sizing
); 
 254         cursor
[CurMove
] = XCreateFontCursor(dpy
, XC_fleur
); 
 259         loadcolors(dpy
, screen
, &brush
, BGCOLOR
, FGCOLOR
, BORDERCOLOR
); 
 260         loadfont(dpy
, &brush
.font
, FONT
); 
 262         wa
.override_redirect 
= 1; 
 263         wa
.background_pixmap 
= ParentRelative
; 
 264         wa
.event_mask 
= ExposureMask
; 
 268         bh 
= texth(&brush
.font
); 
 269         barwin 
= XCreateWindow(dpy
, root
, bx
, by
, bw
, bh
, 0, DefaultDepth(dpy
, screen
), 
 270                         CopyFromParent
, DefaultVisual(dpy
, screen
), 
 271                         CWOverrideRedirect 
| CWBackPixmap 
| CWEventMask
, &wa
); 
 272         XDefineCursor(dpy
, barwin
, cursor
[CurNormal
]); 
 273         XMapRaised(dpy
, barwin
); 
 275         brush
.drawable 
= XCreatePixmap(dpy
, root
, sw
, bh
, DefaultDepth(dpy
, screen
)); 
 276         brush
.gc 
= XCreateGC(dpy
, root
, 0, 0); 
 278         pipe_spawn(statustext
, sizeof(statustext
), dpy
, (char **)status
); 
 281         wa
.event_mask 
= SubstructureRedirectMask 
| EnterWindowMask \
 
 283         wa
.cursor 
= cursor
[CurNormal
]; 
 284         XChangeWindowAttributes(dpy
, root
, CWEventMask 
| CWCursor
, &wa
); 
 289                 if(XPending(dpy
) > 0) { 
 290                         XNextEvent(dpy
, &ev
); 
 292                                 (handler
[ev
.type
]) (&ev
); /* call handler */ 
 296                 FD_SET(ConnectionNumber(dpy
), &fds
); 
 298                 if(select(ConnectionNumber(dpy
) + 1, &fds
, NULL
, NULL
, &t
) > 0) 
 300                 else if(errno 
!= EINTR
) { 
 301                         pipe_spawn(statustext
, sizeof(statustext
), dpy
, (char **)status
);