mirror of
https://github.com/amiwm/amiwm.git
synced 2026-03-24 01:24:15 +00:00
reparenting the client's window creates a few issues: • We get bogus UnmapNotify and MapNotify events that are ultimately generated by amiwm itself. • We do not get button events from the window, since its frame (c->parent) that we have called XGrabButtons(3) onto, is not its parent anymore. To fix this, do not reparent the client window, but its frame window. And keep the client window always inside the frame.
474 lines
12 KiB
C
474 lines
12 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 open_fscrn(Client *c)
|
|
{
|
|
c->fsscr = scr = openscreen(NULL, scr->root);
|
|
c->reparenting = 1;
|
|
XReparentWindow(dpy, c->parent, c->fsscr->back, 0, 0);
|
|
XRaiseWindow(dpy, c->window);
|
|
XMoveResizeWindow(dpy, c->parent, 0, 0, c->fsscr->width, c->fsscr->height);
|
|
XMoveResizeWindow(dpy, c->window, 0, 0, c->fsscr->width, c->fsscr->height);
|
|
for (Client *dialog = clients; dialog != NULL; dialog = dialog->next)
|
|
if (dialog->leader == c)
|
|
reparent_client(c->fsscr, dialog);
|
|
XResizeWindow(dpy, c->window, scr->width, scr->height);
|
|
realizescreens();
|
|
scr = c->fsscr;
|
|
#ifdef USE_FONTSETS
|
|
XStoreName(dpy, scr->back, c->title);
|
|
#else
|
|
XSetWMName(dpy, scr->back, &c->title);
|
|
#endif
|
|
screentoback();
|
|
}
|
|
|
|
void close_fscrn(Client *c, int state)
|
|
{
|
|
if (c->fsscr == NULL)
|
|
return;
|
|
XReparentWindow(dpy, c->parent, c->scr, c->x, c->y);
|
|
XMoveResizeWindow(dpy, c->parent, c->x, c->y, c->pwidth, c->pheight);
|
|
XMoveResizeWindow(dpy, c->window, 4, c->scr->bh, c->pwidth-c->framewidth, c->pheight-c->frameheight);
|
|
XResizeWindow(dpy, c->window, c->pwidth-c->framewidth, c->pheight-c->frameheight);
|
|
XLowerWindow(dpy, c->window);
|
|
scr = c->fsscr;
|
|
closescreen();
|
|
c->fsscr = NULL;
|
|
scr = c->scr;
|
|
if (state != IconicState)
|
|
XMapWindow(dpy, c->parent);
|
|
for (Client *dialog = clients; dialog != NULL; dialog = dialog->next)
|
|
if (dialog->leader == c)
|
|
reparent_client(c->scr, dialog);
|
|
}
|
|
|
|
void setclientstate(Client *c, int state)
|
|
{
|
|
long data[2];
|
|
|
|
data[0] = (long) state;
|
|
data[1] = (long) None;
|
|
|
|
if (c->fullscreen) {
|
|
if (state != NormalState && c->state == NormalState) {
|
|
close_fscrn(c, state);
|
|
} else if (state == NormalState && c->state != NormalState) {
|
|
open_fscrn(c);
|
|
}
|
|
}
|
|
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->fsscr = NULL;
|
|
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;
|
|
c->fullscreen = 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 ((scr = c->fsscr))
|
|
closescreen();
|
|
scr = c->scr;
|
|
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);
|
|
for (Client *dialog = clients; dialog != NULL; dialog = dialog->next)
|
|
if (dialog->leader == c)
|
|
dialog->leader = NULL;
|
|
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 = get_front_scr())) 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!= get_front_scr());
|
|
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);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Reparent the given client to the given screen.
|
|
*
|
|
* This moves the given client to the given screen.
|
|
*/
|
|
void
|
|
reparent_client(Scrn *s, Client *client)
|
|
{
|
|
client->scr = s;
|
|
if(client->parent != client->scr->root)
|
|
XReparentWindow(dpy, client->parent, s->back, client->x, client->y);
|
|
if (s->deftitle != NULL)
|
|
setstringprop(client->window, amiwm_screen, s->deftitle);
|
|
sendconfig(client);
|
|
}
|
|
|
|
|
|
void fullscreen(Client *c, int fs)
|
|
{
|
|
if (fs == c->fullscreen)
|
|
return;
|
|
if (c->state != NormalState) {
|
|
c->fullscreen = fs;
|
|
setwmstate(c);
|
|
return;
|
|
}
|
|
|
|
if (fs) {
|
|
open_fscrn(c);
|
|
c->fullscreen = 1;
|
|
} else {
|
|
close_fscrn(c, c->state);
|
|
c->fullscreen = 0;
|
|
setclientstate(c, NormalState);
|
|
}
|
|
setwmstate(c);
|
|
}
|