Files
amiwm-neo/client.c
Adrian Chadd 26cecc8487 [amiwm] Use XAllocSizeHints() for the sizehints in struct Client
Although it likely doesn't matter /that/ much, the x11 xlib manual
does say to use it rather than expecting the struct to stay the same
size.

Yeah yeah it's 2022 and we really do build things from source,
ICCCM is likely not going to change that much nowdays, etc, etc.
2022-03-12 21:04:24 -08:00

382 lines
9.2 KiB
C

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "drawinfo.h"
#include "screen.h"
#include "icon.h"
#include "client.h"
#include "icc.h"
#include "prefs.h"
#ifdef AMIGAOS
#include <pragmas/xlib_pragmas.h>
extern struct Library *XLibBase;
#endif
extern Display *dpy;
extern XContext client_context, screen_context;
extern Client *activeclient;
extern Scrn *menuactive;
extern void setfocus(Window);
Client *clients=NULL;
void grav_map_frame_to_win(Client *c, int x0, int y0, int *x, int *y)
{
switch(c->gravity) {
case EastGravity:
case NorthEastGravity:
case SouthEastGravity:
*x=x0+c->framewidth-c->old_bw-c->old_bw; break;
case CenterGravity:
case NorthGravity:
case SouthGravity:
*x=x0+4-c->old_bw; break;
case WestGravity:
case NorthWestGravity:
case SouthWestGravity:
default:
*x=x0; break;
}
switch(c->gravity) {
case SouthGravity:
case SouthEastGravity:
case SouthWestGravity:
*y=y0+c->frameheight-c->old_bw-c->old_bw; break;
case CenterGravity:
case EastGravity:
case WestGravity:
*y=y0+c->scr->bh-c->old_bw; break;
case NorthGravity:
case NorthEastGravity:
case NorthWestGravity:
default:
*y=y0; break;
}
}
void grav_map_win_to_frame(Client *c, int x0, int y0, int *x, int *y)
{
switch(c->gravity) {
case EastGravity:
case NorthEastGravity:
case SouthEastGravity:
*x=x0-c->framewidth+c->old_bw+c->old_bw; break;
case CenterGravity:
case NorthGravity:
case SouthGravity:
*x=x0-4+c->old_bw; break;
case WestGravity:
case NorthWestGravity:
case SouthWestGravity:
default:
*x=x0; break;
}
switch(c->gravity) {
case SouthGravity:
case SouthEastGravity:
case SouthWestGravity:
*y=y0-c->frameheight+c->old_bw+c->old_bw; break;
case CenterGravity:
case EastGravity:
case WestGravity:
*y=y0-c->scr->bh+c->old_bw; break;
case NorthGravity:
case NorthEastGravity:
case NorthWestGravity:
default:
*y=y0; break;
}
}
void sendconfig(Client *c)
{
XConfigureEvent ce;
ce.type = ConfigureNotify;
ce.event = c->window;
ce.window = c->window;
/*
grav_map_frame_to_win(c, c->x, c->y, &ce.x, &ce.y);
*/
ce.x = c->x+4;
#ifndef ASSIMILATE_WINDOWS
ce.y = c->y+c->scr->bh+c->scr->y;
#else
ce.y = c->y+c->scr->bh;
#endif
ce.width = c->pwidth-c->framewidth;
ce.height = c->pheight-c->frameheight;
ce.border_width = c->old_bw;
ce.above = None;
ce.override_redirect = 0;
XSendEvent(dpy, c->window, False, StructureNotifyMask, (XEvent*)&ce);
XSync(dpy, False);
}
void scrsendconfig(Scrn *s)
{
Client *c;
for (c=clients; c; c = c->next)
if(c->scr == s)
sendconfig(c);
}
void checksizehints(Client *c)
{
long supplied;
XGetWMNormalHints(dpy, c->window, c->sizehints, &supplied);
if(!(c->sizehints->flags&PMinSize))
c->sizehints->min_width=c->sizehints->min_height=0;
if(!(c->sizehints->flags&PMaxSize)) {
c->sizehints->max_width=c->sizehints->max_height=1<<30;
}
if(!(c->sizehints->flags&PResizeInc))
c->sizehints->width_inc=c->sizehints->height_inc=1;
if(c->sizehints->flags&PBaseSize) {
c->sizehints->min_width=c->sizehints->base_width;
c->sizehints->min_height=c->sizehints->base_height;
}
if(c->sizehints->min_width<1) c->sizehints->min_width=1;
if(c->sizehints->min_height<1) c->sizehints->min_height=1;
c->sizehints->base_width=c->sizehints->min_width;
c->sizehints->base_height=c->sizehints->min_height;
if(c->sizehints->flags&PWinGravity) c->gravity=c->sizehints->win_gravity;
}
void setclientstate(Client *c, int state)
{
long data[2];
data[0] = (long) state;
data[1] = (long) None;
c->state = state;
XChangeProperty(dpy, c->window, wm_state, wm_state, 32,
PropModeReplace, (unsigned char *)data, 2);
}
void getstate(Client *c)
{
long *data=NULL;
if(_getprop(c->window, wm_state, wm_state, 2l, (char **)&data)>0) {
c->state=*data;
XFree((char *)data);
}
}
Client *createclient(Window w)
{
extern void checkstyle(Client *c);
XWindowAttributes attr;
Client *c;
int b = 0;
if(w==0) return 0;
if(!XFindContext(dpy, w, client_context, (XPointer*)&c)) return c;
XGetWindowAttributes(dpy, w, &attr);
c = (Client *)calloc(1, sizeof(Client));
c->sizehints = XAllocSizeHints();
c->scr = scr;
c->window = w;
c->parent = scr->root;
c->old_bw = attr.border_width;
c->next = clients;
c->state = WithdrawnState;
c->gravity = NorthWestGravity;
c->reparenting = 0;
XSelectInput(dpy, c->window, PropertyChangeMask);
#ifdef USE_FONTSETS
{
XTextProperty prop;
c->title = NULL;
if(XGetWMName(dpy, c->window, &prop) && prop.value) {
char **list;
int n;
if(XmbTextPropertyToTextList(dpy, &prop, &list, &n) >= Success) {
if(n > 0)
c->title = strdup(list[0]);
XFreeStringList(list);
}
XFree(prop.value);
}
}
#else
XGetWMName(dpy, c->window, &c->title);
#endif
c->style = NULL;
checkstyle(c);
checksizehints(c);
c->zoomx=0;
c->zoomy=scr->bh;
if ((c->sizehints->width_inc &&
c->sizehints->min_width+c->sizehints->width_inc<=c->sizehints->max_width)||
(c->sizehints->height_inc &&
c->sizehints->min_height+c->sizehints->height_inc<=c->sizehints->max_height))
b = prefs.sizeborder;
if(c->sizehints->width_inc) {
c->zoomw=scr->width-c->sizehints->base_width;
if (b & Psizeright)
c->zoomw-=22;
else
c->zoomw-=8;
c->zoomw-=c->zoomw%c->sizehints->width_inc;
c->zoomw+=c->sizehints->base_width;
if(c->zoomw>c->sizehints->max_width)
c->zoomw=c->sizehints->max_width;
if(c->zoomw<c->sizehints->min_width)
c->zoomw=c->sizehints->min_width;
} else
c->zoomw=attr.width;
if(c->sizehints->height_inc) {
c->zoomh=scr->height-c->sizehints->base_height-scr->bh-c->zoomy;
if (b & Psizebottom)
c->zoomh -= 10;
else
c->zoomh -= 2;
c->zoomh-=c->zoomh%c->sizehints->height_inc;
c->zoomh+=c->sizehints->base_height;
if(c->zoomh>c->sizehints->max_height)
c->zoomh=c->sizehints->max_height;
if(c->zoomh<c->sizehints->min_height)
c->zoomh=c->sizehints->min_height;
} else
c->zoomh=attr.height;
XSaveContext(dpy, w, client_context, (XPointer)c);
return clients = c;
}
void rmclient(Client *c)
{
Client *cc;
if (c == clients)
clients = c->next;
else
if((cc = clients))
for (; cc->next; cc = cc->next)
if (cc->next == c) {
cc->next = cc->next->next;
break;
}
if(c->active) {
if(!menuactive)
setfocus(None);
c->active=False;
activeclient = NULL;
XInstallColormap(dpy, scr->cmap);
} else if(prefs.focus==FOC_CLICKTOTYPE)
XUngrabButton(dpy, Button1, AnyModifier, c->parent);
#ifdef USE_FONTSETS
if(c->title)
free(c->title);
#else
if(c->title.value)
XFree(c->title.value);
#endif
if(c->parent != c->scr->root) {
XDestroyWindow(dpy, c->parent);
XDeleteContext(dpy, c->parent, client_context);
}
if(c->close)
XDeleteContext(dpy, c->close, client_context);
if(c->drag)
XDeleteContext(dpy, c->drag, client_context);
if(c->iconify)
XDeleteContext(dpy, c->iconify, client_context);
if(c->zoom)
XDeleteContext(dpy, c->zoom, client_context);
if(c->depth)
XDeleteContext(dpy, c->depth, client_context);
if(c->resize)
XDeleteContext(dpy, c->resize, client_context);
if(c->icon)
rmicon(c->icon);
if(c->window)
XDeleteContext(dpy, c->window, client_context);
if (c->sizehints)
XFree(c->sizehints);
free(c);
}
int screen_has_clients()
{
int n = 0;
Client *c = clients;
while(c) {
if(c->scr == scr)
n++;
c = c->next;
}
return n;
}
void flushclients()
{
unsigned int i, nwins;
Window dw1, dw2, *wins;
Client *c;
#ifdef ASSIMILATE_WINDOWS
Scrn *scr2;
#endif
if((scr = front)) do {
scr = scr->upfront;
XQueryTree(dpy, scr->back, &dw1, &dw2, &wins, &nwins);
for(i=0; i<nwins; i++)
if((!XFindContext(dpy, wins[i], client_context, (XPointer *)&c))&&wins[i]==c->parent) {
int x,y;
grav_map_frame_to_win(c, c->x, c->y, &x, &y);
XReparentWindow(dpy, c->window, scr->root, x, y);
XSetWindowBorderWidth(dpy, c->window, c->old_bw);
XRemoveFromSaveSet(dpy, c->window);
wins[i]=c->window;
rmclient(c);
}
#ifdef ASSIMILATE_WINDOWS
else if((!XFindContext(dpy, wins[i], screen_context, (XPointer *)&scr2)) && scr2==scr) {
XWindowAttributes attr;
XSetWindowAttributes xsa;
XGetWindowAttributes(dpy, wins[i], &attr);
XReparentWindow(dpy, wins[i], scr->root, attr.x, attr.y);
xsa.override_redirect = True;
XChangeWindowAttributes(dpy, wins[i], CWOverrideRedirect, &xsa);
XDeleteContext(dpy, wins[i], screen_context);
XRemoveFromSaveSet(dpy, wins[i]);
}
#endif
/*
if(nwins) {
for(i=0; i<(nwins>>1); i++) {
Window w=wins[i];
wins[i]=wins[nwins-1-i];
wins[nwins-1-i]=w;
}
XRestackWindows(dpy, wins, nwins);
}
*/
XFree((void *) wins);
} while(scr!=front);
while((c=clients)) {
if(c->parent != c->scr->root) {
int x,y;
grav_map_frame_to_win(c, c->x, c->y, &x, &y);
XReparentWindow(dpy, c->window, c->scr->root, x, y);
XSetWindowBorderWidth(dpy, c->window, c->old_bw);
XRemoveFromSaveSet(dpy, c->window);
}
rmclient(c);
}
}