mirror of
https://github.com/amiwm/amiwm.git
synced 2026-04-14 11:04:18 +00:00
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.
382 lines
9.2 KiB
C
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);
|
|
}
|
|
}
|