mirror of
https://github.com/edeproject/ede.git
synced 2023-08-10 21:13:03 +03:00
1363 lines
34 KiB
C++
1363 lines
34 KiB
C++
/*
|
|
* $Id$
|
|
*
|
|
* Evoke, head honcho of everything
|
|
* Part of Equinox Desktop Environment (EDE).
|
|
* Based on xcompmgr (c) 2003 Keith Packard.
|
|
* Copyright (c) 2007 EDE Authors.
|
|
*
|
|
* This program is licensed under terms of the
|
|
* GNU General Public License version 2 or newer.
|
|
* See COPYING for details.
|
|
*/
|
|
|
|
#include "Composite.h"
|
|
#include "ClassHack.h"
|
|
|
|
#include <edelib/Debug.h>
|
|
|
|
#include <FL/x.h>
|
|
#include <FL/Fl.h>
|
|
|
|
#include <string.h> // memcpy
|
|
#include <stdlib.h> // malloc, realloc
|
|
|
|
#include <X11/extensions/Xcomposite.h>
|
|
#include <X11/extensions/Xrender.h>
|
|
|
|
#define TRANSLUCENT 0xe0000000
|
|
#define OPAQUE 0xffffffff
|
|
|
|
#define REFRESH_TIMEOUT 0.05
|
|
|
|
#define WIN_MODE_SOLID 0
|
|
#define WIN_MODE_TRANS 1
|
|
#define WIN_MODE_ARGB 2
|
|
|
|
static int render_error;
|
|
static int damage_error;
|
|
static int xfixes_error;
|
|
static bool have_name_pixmap = false;
|
|
static int composite_opcode;
|
|
static int damage_event;
|
|
static bool another_is_running;
|
|
|
|
|
|
Atom _XA_NET_WM_WINDOW_OPACITY;
|
|
Atom _XA_NET_WM_WINDOW_TYPE;
|
|
Atom _XA_NET_WM_WINDOW_TYPE_DESKTOP;
|
|
Atom _XA_NET_WM_WINDOW_TYPE_DOCK;
|
|
Atom _XA_NET_WM_WINDOW_TYPE_TOOLBAR;
|
|
Atom _XA_NET_WM_WINDOW_TYPE_MENU;
|
|
Atom _XA_NET_WM_WINDOW_TYPE_UTILITY;
|
|
Atom _XA_NET_WM_WINDOW_TYPE_SPLASH;
|
|
Atom _XA_NET_WM_WINDOW_TYPE_DIALOG;
|
|
Atom _XA_NET_WM_WINDOW_TYPE_NORMAL;
|
|
|
|
static char* backgroundProps[] = {
|
|
"_XROOTPMAP_ID",
|
|
"_XSETROOT_ID",
|
|
0
|
|
};
|
|
|
|
//#define HAVE_NAME_WINDOW_PIXMAP 1
|
|
|
|
struct CWindow {
|
|
Window id;
|
|
#if HAVE_NAME_WINDOW_PIXMAP
|
|
Pixmap pixmap;
|
|
#endif
|
|
XWindowAttributes attr;
|
|
int mode;
|
|
int damaged;
|
|
Damage damage;
|
|
|
|
Picture picture;
|
|
Picture picture_alpha;
|
|
Picture picture_shadow;
|
|
|
|
XserverRegion border_size;
|
|
XserverRegion extents;
|
|
|
|
Picture shadow;
|
|
int shadow_dx;
|
|
int shadow_dy;
|
|
int shadow_w;
|
|
int shadow_h;
|
|
unsigned int opacity;
|
|
|
|
Atom window_type;
|
|
|
|
unsigned long damage_sequence; // sequence when damage was created
|
|
|
|
// for drawing translucent windows
|
|
XserverRegion border_clip;
|
|
};
|
|
|
|
XserverRegion allDamage;
|
|
bool fadeWindows = true;
|
|
bool clipChanged = false;
|
|
bool excludeDockShadows = true;
|
|
Picture rootBuffer = 0;
|
|
Picture rootPicture = 0;
|
|
Picture rootTile = 0;
|
|
Picture blackPicture = 0;
|
|
|
|
int shadowRadius = 12;
|
|
int shadowOffsetX = -15;
|
|
int shadowOffsetY = -15;
|
|
double shadowOpacity = .75;
|
|
|
|
bool hasNamePixmap = true;
|
|
|
|
#define DO_BETTER_REPAINT 1
|
|
|
|
void idle_cb(void* c) {
|
|
Composite* comp = (Composite*)c;
|
|
|
|
#ifdef DO_BETTER_REPAINT
|
|
if(allDamage != None) {
|
|
comp->paint_all(allDamage);
|
|
|
|
XFixesDestroyRegion(fl_display, allDamage);
|
|
allDamage = None;
|
|
clipChanged = false;
|
|
}
|
|
#else
|
|
comp->paint_all(allDamage);
|
|
|
|
if(allDamage != None) {
|
|
XFixesDestroyRegion(fl_display, allDamage);
|
|
allDamage = None;
|
|
clipChanged = false;
|
|
}
|
|
#endif
|
|
|
|
#ifndef USE_CHECK
|
|
Fl::repeat_timeout(REFRESH_TIMEOUT, idle_cb, c);
|
|
#endif
|
|
}
|
|
|
|
int xerror_handler(Display* display, XErrorEvent* xev) {
|
|
if(xev->request_code == composite_opcode && xev->minor_code == X_CompositeRedirectSubwindows) {
|
|
EWARNING(ESTRLOC ": Another composite manager is running\n");
|
|
another_is_running = true;
|
|
return 1;
|
|
}
|
|
|
|
char* name = NULL;
|
|
int o = xev->error_code - xfixes_error;
|
|
switch(o) {
|
|
case BadRegion:
|
|
name = "BadRegion";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
o = xev->error_code - damage_error;
|
|
switch(o) {
|
|
case BadDamage:
|
|
name = "BadDamage";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
o = xev->error_code - render_error;
|
|
switch(o) {
|
|
case BadPictFormat:
|
|
name = "BadPictFormat";
|
|
break;
|
|
case BadPicture:
|
|
name = "BadPicture";
|
|
break;
|
|
case BadPictOp:
|
|
name = "BadPictOp";
|
|
break;
|
|
case BadGlyphSet:
|
|
name = "BadGlyphSet";
|
|
break;
|
|
case BadGlyph:
|
|
name = "BadGlyph";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//EDEBUG(ESTRLOC ": (%s) : error %i request %i minor %i serial %i\n",
|
|
// (name ? name : "unknown"), xev->error_code, xev->request_code, xev->minor_code, xev->serial);
|
|
|
|
#if 0
|
|
char buff[128];
|
|
XGetErrorDatabaseText(fl_display, "XlibMessage", "XError", "", buff, 128);
|
|
EDEBUG("%s", buff);
|
|
|
|
XGetErrorText(fl_display, xev->error_code, buff, 128);
|
|
EDEBUG(" :%s\n", buff);
|
|
|
|
XGetErrorDatabaseText(fl_display, "XlibMessage", "MajorCode", "%d", buff, 128);
|
|
EDEBUG(" ");
|
|
EDEBUG(buff, xev->request_code);
|
|
EDEBUG("\n");
|
|
|
|
XGetErrorDatabaseText(fl_display, "XlibMessage", "MinorCode", "%d", buff, 128);
|
|
EDEBUG(" ");
|
|
EDEBUG(buff, xev->minor_code);
|
|
EDEBUG("\n");
|
|
|
|
XGetErrorDatabaseText(fl_display, "XlibMessage", "ResourceID", "%d", buff, 128);
|
|
EDEBUG(" ");
|
|
EDEBUG(buff, xev->resourceid);
|
|
EDEBUG("\n");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
void set_ignore(unsigned long sequence) {
|
|
// TODO
|
|
}
|
|
|
|
unsigned int get_opacity_property(CWindow* win, unsigned int dflt) {
|
|
Atom actual;
|
|
int format;
|
|
unsigned long n, left;
|
|
unsigned char* data = NULL;
|
|
|
|
int ret = XGetWindowProperty(fl_display, win->id, _XA_NET_WM_WINDOW_OPACITY, 0L, 1L, False,
|
|
XA_CARDINAL, &actual, &format, &n, &left, &data);
|
|
|
|
if(ret == Success && data != NULL) {
|
|
unsigned int p;
|
|
// TODO: replace memcpy call
|
|
memcpy(&p, data, sizeof(unsigned int));
|
|
XFree(data);
|
|
// EDEBUG(":) Opacity for %i = %i\n", win->id, p);
|
|
return p;
|
|
}
|
|
|
|
//EDEBUG("Opacity for %i = %i\n", win->id, dflt);
|
|
|
|
return dflt;
|
|
}
|
|
|
|
double get_opacity_percent(CWindow* win, double dflt) {
|
|
unsigned int opacity = get_opacity_property(win, (unsigned int)(OPAQUE * dflt));
|
|
return opacity * 1.0 / OPAQUE;
|
|
}
|
|
|
|
Atom get_window_type_property(Window win) {
|
|
Atom actual;
|
|
int format;
|
|
unsigned long n, left;
|
|
unsigned char* data = NULL;
|
|
|
|
int ret = XGetWindowProperty(fl_display, win, _XA_NET_WM_WINDOW_TYPE, 0L, 1L, False,
|
|
XA_ATOM, &actual, &format, &n, &left, &data);
|
|
|
|
if(ret == Success && data != NULL) {
|
|
Atom a;
|
|
// TODO: replace memcpy call
|
|
memcpy(&a, data, sizeof(Atom));
|
|
XFree(data);
|
|
return a;
|
|
}
|
|
|
|
return _XA_NET_WM_WINDOW_TYPE_NORMAL;
|
|
}
|
|
|
|
Atom determine_window_type(Window win) {
|
|
Atom type = get_window_type_property(win);
|
|
if(type != _XA_NET_WM_WINDOW_TYPE_NORMAL)
|
|
return type;
|
|
|
|
// scan children
|
|
Window root_return, parent_return;
|
|
Window* children = NULL;
|
|
unsigned int nchildren;
|
|
|
|
if(XQueryTree(fl_display, win, &root_return, &parent_return, &children, &nchildren) != 0) {
|
|
if(children)
|
|
XFree(children);
|
|
return _XA_NET_WM_WINDOW_TYPE_NORMAL;
|
|
}
|
|
|
|
for(unsigned int i = 0; i < nchildren; i++) {
|
|
type = determine_window_type(children[i]);
|
|
if(type != _XA_NET_WM_WINDOW_TYPE_NORMAL)
|
|
return type;
|
|
}
|
|
|
|
if(children)
|
|
XFree(children);
|
|
return _XA_NET_WM_WINDOW_TYPE_NORMAL;
|
|
}
|
|
|
|
void add_damage(XserverRegion damage) {
|
|
if(allDamage != None) {
|
|
XFixesUnionRegion(fl_display, allDamage, allDamage, damage);
|
|
XFixesDestroyRegion(fl_display, damage);
|
|
} else
|
|
allDamage = damage;
|
|
}
|
|
|
|
void determine_mode(CWindow* win) {
|
|
if(win->picture_alpha) {
|
|
XRenderFreePicture(fl_display, win->picture_alpha);
|
|
win->picture_alpha = None;
|
|
}
|
|
|
|
if(win->picture_shadow) {
|
|
XRenderFreePicture(fl_display, win->picture_shadow);
|
|
win->picture_shadow = None;
|
|
}
|
|
|
|
XRenderPictFormat* format;
|
|
if(get_attributes_class_hack(&win->attr) == InputOnly)
|
|
format = 0;
|
|
else
|
|
format = XRenderFindVisualFormat(fl_display, win->attr.visual);
|
|
|
|
if(format && format->type == PictTypeDirect && format->direct.alphaMask)
|
|
win->mode = WIN_MODE_ARGB;
|
|
else if(win->opacity != OPAQUE)
|
|
win->mode = WIN_MODE_TRANS;
|
|
else
|
|
win->mode = WIN_MODE_SOLID;
|
|
|
|
if(win->extents) {
|
|
XserverRegion damage = XFixesCreateRegion(fl_display, 0, 0);
|
|
XFixesCopyRegion(fl_display, damage, win->extents);
|
|
add_damage(damage);
|
|
}
|
|
}
|
|
|
|
// TODO: make this a member
|
|
XserverRegion set_border_size(CWindow* win) {
|
|
/*
|
|
* if window doesn't exist anymore, this will generate an error
|
|
* as well as not generate a region. Perhaps a better XFixes
|
|
* architecture would be to have a request that copies instead
|
|
* of creates, that way you'd just end up with an empty region
|
|
* instead of an invalid XID.
|
|
*/
|
|
set_ignore(NextRequest(fl_display));
|
|
XserverRegion border = XFixesCreateRegionFromWindow(fl_display, win->id, WindowRegionBounding);
|
|
|
|
// translate this
|
|
set_ignore(NextRequest(fl_display));
|
|
XFixesTranslateRegion(fl_display, border,
|
|
win->attr.x + win->attr.border_width,
|
|
win->attr.y + win->attr.border_width);
|
|
|
|
return border;
|
|
}
|
|
|
|
// TODO: make this a part of paint_root()
|
|
Picture root_tile(void) {
|
|
Atom actual_type;
|
|
int actual_format;
|
|
unsigned long nitems;
|
|
unsigned long bytes_after;
|
|
unsigned char* prop;
|
|
Pixmap pixmap = None;
|
|
Atom pixmap_atom = XInternAtom(fl_display, "PIXMAP", False);
|
|
Window root = RootWindow(fl_display, fl_screen);
|
|
bool fill;
|
|
|
|
for(int i = 0; backgroundProps[i]; i++) {
|
|
if(XGetWindowProperty(fl_display, root, XInternAtom(fl_display, backgroundProps[i], False),
|
|
0, 4, False, AnyPropertyType,
|
|
&actual_type, &actual_format, &nitems, &bytes_after, &prop) == Success &&
|
|
actual_type == pixmap_atom &&
|
|
actual_format == 32 &&
|
|
nitems == 1) {
|
|
memcpy(&pixmap, prop, 4);
|
|
XFree(prop);
|
|
fill = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!pixmap) {
|
|
pixmap = XCreatePixmap(fl_display, root, 1, 1, DefaultDepth(fl_display, fl_screen));
|
|
fill = true;
|
|
}
|
|
|
|
XRenderPictureAttributes pa;
|
|
pa.repeat = True;
|
|
|
|
Picture picture = XRenderCreatePicture(fl_display, pixmap,
|
|
XRenderFindVisualFormat(fl_display, DefaultVisual(fl_display, fl_screen)),
|
|
CPRepeat, &pa);
|
|
|
|
if(fill) {
|
|
XRenderColor c;
|
|
c.red = c.green = c.blue = 0x8080;
|
|
c.alpha = 0xffff;
|
|
XRenderFillRectangle(fl_display, PictOpSrc, picture, &c, 0, 0, 1, 1);
|
|
}
|
|
|
|
return picture;
|
|
}
|
|
|
|
Picture solid_picture(bool argb, double a, double r, double g, double b) {
|
|
Pixmap pixmap = XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), 1, 1, argb ? 32 : 8);
|
|
if(!pixmap)
|
|
return None;
|
|
|
|
XRenderPictureAttributes pa;
|
|
pa.repeat = True;
|
|
|
|
Picture picture = XRenderCreatePicture(fl_display, pixmap,
|
|
XRenderFindStandardFormat(fl_display, argb ? PictStandardARGB32 : PictStandardA8),
|
|
CPRepeat, &pa);
|
|
|
|
if(!picture) {
|
|
XFreePixmap(fl_display, pixmap);
|
|
return None;
|
|
}
|
|
|
|
XRenderColor color;
|
|
color.alpha = a * 0xffff;
|
|
color.red = r * 0xffff;
|
|
color.green = g * 0xffff;
|
|
color.blue = b * 0xffff;
|
|
|
|
XRenderFillRectangle(fl_display, PictOpSrc, picture, &color, 0, 0, 1, 1);
|
|
XFreePixmap(fl_display, pixmap);
|
|
return picture;
|
|
}
|
|
|
|
|
|
Composite::Composite() : manual_redirect(true) {
|
|
}
|
|
|
|
Composite::~Composite() {
|
|
EDEBUG("Composite::~Composite()\n");
|
|
#ifdef USE_CHECK
|
|
Fl::remove_check(idle_cb);
|
|
#else
|
|
Fl::remove_timeout(idle_cb);
|
|
#endif
|
|
|
|
// TODO: this part should call finish_destroy_window()
|
|
CWindowListIter it = window_list.begin(), it_end = window_list.end();
|
|
while(it != it_end) {
|
|
delete *it;
|
|
++it;
|
|
}
|
|
}
|
|
|
|
bool Composite::init(void) {
|
|
another_is_running = false;
|
|
|
|
// set error handler first
|
|
XSetErrorHandler(xerror_handler);
|
|
|
|
int render_event;
|
|
if(!XRenderQueryExtension(fl_display, &render_event, &render_error)) {
|
|
EWARNING(ESTRLOC ": No render extension\n");
|
|
return false;
|
|
}
|
|
|
|
// check Composite extension
|
|
int composite_event, composite_error;
|
|
if(!XQueryExtension(fl_display, COMPOSITE_NAME, &composite_opcode, &composite_event, &composite_error)) {
|
|
EWARNING(ESTRLOC ": No composite extension\n");
|
|
return false;
|
|
}
|
|
|
|
int composite_major, composite_minor;
|
|
XCompositeQueryVersion(fl_display, &composite_major, &composite_minor);
|
|
EDEBUG(ESTRLOC ": Setting up XComposite version %i.%i\n", composite_major, composite_minor);
|
|
|
|
if(composite_major > 0 || composite_minor >= 2)
|
|
have_name_pixmap = true;
|
|
|
|
// check XDamage extension
|
|
if(!XDamageQueryExtension(fl_display, &damage_event, &damage_error)) {
|
|
EWARNING(ESTRLOC ": No damage extension\n");
|
|
return false;
|
|
}
|
|
|
|
// check XFixes extension
|
|
int xfixes_event;
|
|
if(!XFixesQueryExtension(fl_display, &xfixes_event, &xfixes_error)) {
|
|
EWARNING(ESTRLOC ": No XFixes extension\n");
|
|
return false;
|
|
}
|
|
|
|
_XA_NET_WM_WINDOW_OPACITY = XInternAtom(fl_display, "_NET_WM_WINDOW_OPACITY", False);
|
|
_XA_NET_WM_WINDOW_TYPE = XInternAtom(fl_display, "_NET_WM_WINDOW_TYPE", False);
|
|
_XA_NET_WM_WINDOW_TYPE_DESKTOP = XInternAtom(fl_display, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
|
|
_XA_NET_WM_WINDOW_TYPE_DOCK = XInternAtom(fl_display, "_NET_WM_WINDOW_TYPE_DOCK", False);
|
|
_XA_NET_WM_WINDOW_TYPE_TOOLBAR = XInternAtom(fl_display, "_NET_WM_WINDOW_TYPE_TOOLBAR", False);
|
|
_XA_NET_WM_WINDOW_TYPE_MENU = XInternAtom(fl_display, "_NET_WM_WINDOW_TYPE_MENU", False);
|
|
_XA_NET_WM_WINDOW_TYPE_UTILITY = XInternAtom(fl_display, "_NET_WM_WINDOW_TYPE_UTILITY", False);
|
|
_XA_NET_WM_WINDOW_TYPE_SPLASH = XInternAtom(fl_display, "_NET_WM_WINDOW_TYPE_SPLASH", False);
|
|
_XA_NET_WM_WINDOW_TYPE_DIALOG = XInternAtom(fl_display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
|
|
_XA_NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(fl_display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
|
|
|
|
allDamage = None;
|
|
clipChanged = true;
|
|
|
|
XRenderPictureAttributes pa;
|
|
pa.subwindow_mode = IncludeInferiors;
|
|
rootPicture = XRenderCreatePicture(fl_display, RootWindow(fl_display, fl_screen),
|
|
XRenderFindVisualFormat(fl_display, DefaultVisual(fl_display, fl_screen)), CPSubwindowMode, &pa);
|
|
|
|
blackPicture = solid_picture(true, 1, 0, 0, 0);
|
|
|
|
// now redirect all windows to the Composite
|
|
XGrabServer(fl_display);
|
|
|
|
/*
|
|
* If another manager is running, XCompositeRedirectSubwindows() will report it in xerror_handler().
|
|
* This only works if another-manager/evoke are both set in CompositeRedirectManual mode
|
|
*/
|
|
if(!manual_redirect)
|
|
XCompositeRedirectSubwindows(fl_display, RootWindow(fl_display, fl_screen), CompositeRedirectAutomatic);
|
|
else {
|
|
XCompositeRedirectSubwindows(fl_display, RootWindow(fl_display, fl_screen), CompositeRedirectManual);
|
|
#if 0
|
|
// Commented, since already selected in main evoke code (evoke.cpp).
|
|
XSelectInput(fl_display, RootWindow(fl_display, fl_screen),
|
|
SubstructureNotifyMask | ExposureMask | StructureNotifyMask | PropertyChangeMask);
|
|
#endif
|
|
|
|
Window root_ret, parent_ret;
|
|
Window* children;
|
|
unsigned int nchildren;
|
|
|
|
XQueryTree(fl_display, RootWindow(fl_display, fl_screen), &root_ret, &parent_ret, &children, &nchildren);
|
|
for(unsigned int i = 0; i < nchildren; i++)
|
|
add_window(children[i], i ? children[i-1] : None);
|
|
|
|
XFree(children);
|
|
}
|
|
|
|
XUngrabServer(fl_display);
|
|
|
|
/*
|
|
* draw all windows now, but only if we manualy manage them
|
|
* since window_list will be empty
|
|
*/
|
|
if(manual_redirect) {
|
|
paint_all(None);
|
|
/*
|
|
* Using add_check() instead add_timeout() makes difference in redrawing
|
|
* since add_check() callback function will be called before FLTK flushes
|
|
* the display which makes it very suitable for smooth redrawing.
|
|
*
|
|
* On other hand, using add_timeout() will trigger timer each REFRESH_TIMEOUT
|
|
* no matter for pending events (especially XDamageNotifyEvent) and due that
|
|
* timeout we can miss some XDamage events, yielding little bit non-smooth redrawing.
|
|
*/
|
|
#ifdef USE_CHECK
|
|
Fl::add_check(idle_cb, this);
|
|
#else
|
|
Fl::add_timeout(REFRESH_TIMEOUT, idle_cb, this);
|
|
#endif
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Composite::add_window(Window id, Window previous) {
|
|
CWindow* new_win = new CWindow;
|
|
new_win->id = id;
|
|
|
|
set_ignore(NextRequest(fl_display));
|
|
|
|
if(!XGetWindowAttributes(fl_display, id, &new_win->attr)) {
|
|
delete new_win;
|
|
return;
|
|
}
|
|
|
|
new_win->damaged = 0;
|
|
#if HAVE_NAME_WINDOW_PIXMAP
|
|
new_win->pixmap = None;
|
|
#endif
|
|
new_win->picture = None;
|
|
|
|
if(get_attributes_class_hack(&(new_win->attr)) == InputOnly) {
|
|
new_win->damage_sequence = 0;
|
|
new_win->damage = None;
|
|
} else {
|
|
new_win->damage_sequence = NextRequest(fl_display);
|
|
new_win->damage = XDamageCreate(fl_display, new_win->id, XDamageReportNonEmpty);
|
|
}
|
|
|
|
new_win->picture_alpha = None;
|
|
new_win->picture_shadow = None;
|
|
new_win->border_size = None;
|
|
new_win->extents = None;
|
|
new_win->shadow = None;
|
|
new_win->shadow_dx = 0;
|
|
new_win->shadow_dy = 0;
|
|
new_win->shadow_w = 0;
|
|
new_win->shadow_h = 0;
|
|
new_win->opacity = get_opacity_property(new_win, OPAQUE);
|
|
new_win->border_clip = None;
|
|
|
|
new_win->window_type = determine_window_type(new_win->id);
|
|
determine_mode(new_win);
|
|
|
|
// put window at the top
|
|
window_list.push_front(new_win);
|
|
|
|
// map it if was mapped before
|
|
if(new_win->attr.map_state == IsViewable)
|
|
map_window(new_win->id, new_win->damage_sequence - 1, true);
|
|
}
|
|
|
|
void Composite::map_window(Window id, unsigned long sequence, bool fade) {
|
|
CWindow* win = find_window(id);
|
|
if(!win)
|
|
return;
|
|
|
|
win->attr.map_state = IsViewable;
|
|
|
|
// this needs to be here or we loose transparency messages
|
|
//XSelectInput(fl_display, win->id, PropertyChangeMask);
|
|
XSelectInput(fl_display, win->id, PropertyChangeMask | win->attr.your_event_mask | StructureNotifyMask);
|
|
win->damaged = 0;
|
|
|
|
/*
|
|
* XXX: a hack, not present in xcompmgr due main event
|
|
* loop changes
|
|
*/
|
|
//repair_window(win);
|
|
|
|
// TODO: fading support
|
|
}
|
|
|
|
void Composite::unmap_window(Window id, bool fade) {
|
|
CWindow* win = find_window(id);
|
|
if(!win)
|
|
return;
|
|
win->attr.map_state = IsUnmapped;
|
|
#if HAVE_NAME_WINDOW_PIXMAP
|
|
if(win->pixmap && fade && fadeWindows) {
|
|
// TODO: fading support
|
|
} else
|
|
#endif
|
|
finish_unmap_window(win);
|
|
}
|
|
|
|
void Composite::finish_unmap_window(CWindow* win) {
|
|
win->damaged = 0;
|
|
if(win->extents != None) {
|
|
add_damage(win->extents); // destroy region
|
|
win->extents = None;
|
|
}
|
|
|
|
#if HAVE_NAME_WINDOW_PIXMAP
|
|
if(win->pixmap) {
|
|
XFreePixmap(fl_display, win->pixmap);
|
|
win->pixmap = None;
|
|
}
|
|
#endif
|
|
|
|
if(win->picture) {
|
|
set_ignore(NextRequest(fl_display));
|
|
XRenderFreePicture(fl_display, win->picture);
|
|
win->picture = None;
|
|
}
|
|
|
|
// don't care about properties anymore
|
|
set_ignore(NextRequest(fl_display));
|
|
XSelectInput(fl_display, win->id, 0);
|
|
|
|
if(win->border_size) {
|
|
set_ignore(NextRequest(fl_display));
|
|
XFixesDestroyRegion(fl_display, win->border_size);
|
|
win->border_size = None;
|
|
}
|
|
|
|
if(win->shadow) {
|
|
XRenderFreePicture(fl_display, win->shadow);
|
|
win->shadow = None;
|
|
}
|
|
|
|
if(win->border_clip) {
|
|
XFixesDestroyRegion(fl_display, win->border_clip);
|
|
win->border_clip = None;
|
|
}
|
|
|
|
clipChanged = true;
|
|
}
|
|
|
|
void Composite::configure_window(const XConfigureEvent* ce) {
|
|
CWindow* win = find_window(ce->window);
|
|
if(!win) {
|
|
if(ce->window == RootWindow(fl_display, fl_screen)) {
|
|
if(rootBuffer) {
|
|
XRenderFreePicture(fl_display, rootBuffer);
|
|
rootBuffer = None;
|
|
}
|
|
|
|
// TODO: here should be updated
|
|
// root_width and root_height
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
XserverRegion damage = None;
|
|
|
|
damage = XFixesCreateRegion(fl_display, 0, 0);
|
|
if(win->extents != None)
|
|
XFixesCopyRegion(fl_display, damage, win->extents);
|
|
|
|
win->attr.x = ce->x;
|
|
win->attr.y = ce->y;
|
|
if(win->attr.width != ce->width || win->attr.height != ce->height) {
|
|
#if HAVE_NAME_WINDOW_PIXMAP
|
|
if(win->pixmap) {
|
|
XFreePixmap(fl_display, win->pixmap);
|
|
win->pixmap = None;
|
|
if(win->picture) {
|
|
XRenderFreePicture(fl_display, win->picture);
|
|
win->picture = None;
|
|
}
|
|
}
|
|
#endif
|
|
if(win->shadow) {
|
|
XRenderFreePicture(fl_display, win->shadow);
|
|
win->shadow = None;
|
|
}
|
|
}
|
|
|
|
win->attr.width = ce->width;
|
|
win->attr.height = ce->height;
|
|
win->attr.border_width = ce->border_width;
|
|
win->attr.override_redirect = ce->override_redirect;
|
|
|
|
#if 0
|
|
EDEBUG("--- before restack() ---\n");
|
|
CWindowListIter first = window_list.begin();
|
|
for(; first != window_list.end(); ++first)
|
|
EDEBUG("0x%x ", (*first)->id);
|
|
EDEBUG("\n");
|
|
|
|
EDEBUG("ME: 0x%x ABOVE: 0x%x\n", win->id, ce->above);
|
|
#endif
|
|
restack_window(win, ce->above);
|
|
|
|
#if 0
|
|
EDEBUG("--- after restack() ---\n");
|
|
first = window_list.begin();
|
|
for(; first != window_list.end(); ++first)
|
|
EDEBUG("0x%x ", (*first)->id);
|
|
EDEBUG("\n");
|
|
#endif
|
|
|
|
if(damage) {
|
|
XserverRegion extents = window_extents(win);
|
|
XFixesUnionRegion(fl_display, damage, damage, extents);
|
|
XFixesDestroyRegion(fl_display, extents);
|
|
add_damage(damage);
|
|
}
|
|
|
|
clipChanged = true;
|
|
}
|
|
|
|
void Composite::restack_window(CWindow* win, Window new_above) {
|
|
CWindowListIter it = window_list.begin(), it_end = window_list.end();
|
|
while(it != it_end) {
|
|
if(*it == win)
|
|
break;
|
|
++it;
|
|
}
|
|
|
|
Window old_above;
|
|
if(it == it_end) // not found
|
|
old_above = None;
|
|
else {
|
|
++it; // get the next one
|
|
|
|
// check again
|
|
if(it == it_end)
|
|
old_above = None;
|
|
else
|
|
old_above = (*it)->id;
|
|
}
|
|
|
|
if(old_above != new_above) {
|
|
--it; // return to our window
|
|
EASSERT(*it == win && "Wrong code");
|
|
window_list.erase(it);
|
|
/*
|
|
it = window_list.begin();
|
|
it_end = window_list.end();
|
|
|
|
// find our window and remove it from current position
|
|
while(it != it_end) {
|
|
if(*it == win) {
|
|
window_list.erase(it);
|
|
break;
|
|
}
|
|
++it;
|
|
}*/
|
|
|
|
it = window_list.begin();
|
|
|
|
// now found new_above and insert our window
|
|
while(it != it_end) {
|
|
if((*it)->id == new_above) {
|
|
break;
|
|
}
|
|
++it;
|
|
}
|
|
// now insert where iterator was stopped (if not found 'new_above') it will insert at the end
|
|
window_list.insert(it, win);
|
|
}
|
|
}
|
|
|
|
void Composite::property_notify(const XPropertyEvent* pe) {
|
|
for(int i = 0; backgroundProps[i]; i++) {
|
|
if(pe->atom == XInternAtom(fl_display, backgroundProps[i], False)) {
|
|
if(rootTile) {
|
|
XClearArea(fl_display, RootWindow(fl_display, fl_screen), 0, 0, 0, 0, True);
|
|
XRenderFreePicture(fl_display, rootTile);
|
|
rootTile = None;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// check if Trans property was changed
|
|
if(pe->atom == _XA_NET_WM_WINDOW_OPACITY) {
|
|
// reset mode and redraw window
|
|
CWindow* win = find_window(pe->window);
|
|
if(win) {
|
|
// TODO: fading support
|
|
win->opacity = get_opacity_property(win, OPAQUE);
|
|
determine_mode(win);
|
|
if(win->shadow) {
|
|
XRenderFreePicture(fl_display, win->shadow);
|
|
win->shadow = None;
|
|
win->extents = window_extents(win);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
static XRectangle* expose_rects = 0;
|
|
static int size_expose = 0;
|
|
static int n_expose = 0;
|
|
#endif
|
|
|
|
void Composite::expose_event(const XExposeEvent* ee) {
|
|
#if 0
|
|
if(ee->window != RootWindow(fl_display, fl_screen))
|
|
return;
|
|
|
|
int more = ee->count + 1;
|
|
|
|
if(n_expose == size_expose) {
|
|
if(expose_rects) {
|
|
expose_rects = (XRectangle*)realloc(expose_rects, (size_expose + more) * sizeof(XRectangle));
|
|
size_expose += more;
|
|
} else {
|
|
expose_rects = (XRectangle*)malloc(more * sizeof(XRectangle));
|
|
size_expose = more;
|
|
}
|
|
}
|
|
|
|
expose_rects[n_expose].x = ee->x;
|
|
expose_rects[n_expose].y = ee->y;
|
|
expose_rects[n_expose].width = ee->width;
|
|
expose_rects[n_expose].height = ee->height;
|
|
n_expose++;
|
|
|
|
if(ee->count == 0) {
|
|
// expose root
|
|
XserverRegion region = XFixesCreateRegion(fl_display, expose_rects, n_expose);
|
|
add_damage(region);
|
|
n_expose = 0;
|
|
}
|
|
#endif
|
|
|
|
XRectangle rect[1];
|
|
rect[0].x = ee->x;
|
|
rect[0].y = ee->y;
|
|
rect[0].width = ee->width;
|
|
rect[0].height = ee->height;
|
|
|
|
XserverRegion region = XFixesCreateRegion(fl_display, rect, 1);
|
|
add_damage(region);
|
|
}
|
|
|
|
void Composite::reparent_notify(const XReparentEvent* re) {
|
|
if(re->parent == RootWindow(fl_display, fl_screen))
|
|
add_window(re->window, 0);
|
|
else
|
|
destroy_window(re->window, false, true);
|
|
}
|
|
|
|
void Composite::circulate_window(const XCirculateEvent* ce) {
|
|
CWindow* win = find_window(ce->window);
|
|
if(!win)
|
|
return;
|
|
|
|
Window new_above;
|
|
if(ce->place == PlaceOnTop)
|
|
new_above = (*window_list.begin())->id;
|
|
else
|
|
new_above = None;
|
|
restack_window(win, new_above);
|
|
clipChanged = true;
|
|
}
|
|
|
|
CWindow* Composite::find_window(Window id) {
|
|
if(window_list.size() == 0)
|
|
return NULL;
|
|
|
|
CWindowListIter it = window_list.begin(), it_end = window_list.end();
|
|
|
|
while(it != it_end) {
|
|
if((*it)->id == id)
|
|
return *it;
|
|
++it;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
XserverRegion Composite::window_extents(CWindow* win) {
|
|
XRectangle r;
|
|
r.x = win->attr.x;
|
|
r.y = win->attr.y;
|
|
r.width = win->attr.width + win->attr.border_width * 2;
|
|
r.height = win->attr.height + win->attr.border_width * 2;
|
|
|
|
if(!(win->window_type == _XA_NET_WM_WINDOW_TYPE_DOCK && excludeDockShadows)) {
|
|
// TODO: check this in xcompmgr since server shadows are not used, only client one
|
|
if(win->mode != WIN_MODE_ARGB) {
|
|
win->shadow_dx = shadowOffsetX;
|
|
win->shadow_dx = shadowOffsetX;
|
|
|
|
// make shadow if not already made
|
|
if(!win->shadow) {
|
|
double opacity = shadowOpacity;
|
|
|
|
if(win->mode == WIN_MODE_TRANS)
|
|
opacity = opacity * ((double)win->opacity)/((double)OPAQUE);
|
|
/*
|
|
win->shadow = shadow_picture(opacity, win->picture_alpha,
|
|
win->attr.width + win->attr.border_width * 2,
|
|
win->attr.height + win->attr.border_width * 2,
|
|
&win->shadow_w, &win->shadow_h);
|
|
*/
|
|
}
|
|
}
|
|
|
|
XRectangle sr;
|
|
sr.x = win->attr.x + win->shadow_dx;
|
|
sr.y = win->attr.y + win->shadow_dy;
|
|
sr.width = win->shadow_w;
|
|
sr.height = win->shadow_h;
|
|
|
|
if(sr.x < r.x) {
|
|
r.width = (r.x + r.width) - sr.x;
|
|
r.x = sr.x;
|
|
}
|
|
|
|
if(sr.y < r.y) {
|
|
r.height = (r.y + r.height) - sr.y;
|
|
r.y = sr.y;
|
|
}
|
|
|
|
if(sr.x + sr.width > r.x + r.width)
|
|
r.width = sr.x + sr.width - r.x;
|
|
if(sr.y + sr.height > r.y + r.height)
|
|
r.height = sr.y + sr.height - r.y;
|
|
}
|
|
|
|
return XFixesCreateRegion(fl_display, &r, 1);
|
|
}
|
|
|
|
void Composite::paint_root(void) {
|
|
if(!rootTile)
|
|
rootTile = root_tile();
|
|
|
|
XRenderComposite(fl_display, PictOpSrc, rootTile, None, rootBuffer, 0, 0, 0, 0, 0, 0,
|
|
DisplayWidth(fl_display, fl_screen),
|
|
DisplayHeight(fl_display, fl_screen));
|
|
}
|
|
|
|
void Composite::paint_all(XserverRegion region) {
|
|
//EDEBUG(ESTRLOC ": PAINT %i windows\n", window_list.size());
|
|
|
|
// if region is None repaint all screen
|
|
if(!region) {
|
|
XRectangle r;
|
|
r.x = 0;
|
|
r.y = 0;
|
|
// TODO: DisplayWidth/DisplayHeight should be calculated in init()
|
|
r.width = DisplayWidth(fl_display, fl_screen);
|
|
r.height = DisplayHeight(fl_display, fl_screen);
|
|
|
|
region = XFixesCreateRegion(fl_display, &r, 1);
|
|
}
|
|
|
|
if(!rootBuffer) {
|
|
Pixmap root_pix = XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen),
|
|
DisplayWidth(fl_display, fl_screen),
|
|
DisplayHeight(fl_display, fl_screen),
|
|
DefaultDepth(fl_display, fl_screen));
|
|
|
|
rootBuffer = XRenderCreatePicture(fl_display, root_pix,
|
|
XRenderFindVisualFormat(fl_display, DefaultVisual(fl_display, fl_screen)), 0, 0);
|
|
|
|
XFreePixmap(fl_display, root_pix);
|
|
}
|
|
|
|
XFixesSetPictureClipRegion(fl_display, rootPicture, 0, 0, region);
|
|
|
|
// paint from top to bottom
|
|
CWindowListIter it = window_list.begin(), it_end = window_list.end();
|
|
for(; it != it_end; ++it) {
|
|
CWindow* win = *it;
|
|
|
|
// never painted, ignore it
|
|
if(!win->damaged)
|
|
continue;
|
|
|
|
// invisible, ignore it
|
|
if(win->attr.x + win->attr.width < 1 || win->attr.y + win->attr.height < 1
|
|
|| win->attr.x >= DisplayWidth(fl_display, fl_screen)
|
|
|| win->attr.y >= DisplayHeight(fl_display, fl_screen)) {
|
|
continue;
|
|
}
|
|
|
|
if(!win->picture) {
|
|
Drawable draw = win->id;
|
|
#ifdef HAVE_NAME_WINDOW_PIXMAP
|
|
if(hasNamePixmap && !win->pixmap)
|
|
win->pixmap = XCompositeNameWindowPixmap(fl_display, win->id);
|
|
if(win->pixmap)
|
|
draw = win->pixmap;
|
|
#endif
|
|
XRenderPictFormat* format = XRenderFindVisualFormat(fl_display, win->attr.visual);
|
|
|
|
XRenderPictureAttributes pa;
|
|
pa.subwindow_mode = IncludeInferiors;
|
|
win->picture = XRenderCreatePicture(fl_display, draw, format, CPSubwindowMode, &pa);
|
|
}
|
|
|
|
if(clipChanged) {
|
|
if(win->border_size) {
|
|
set_ignore(NextRequest(fl_display));
|
|
XFixesDestroyRegion(fl_display, win->border_size);
|
|
win->border_size = None;
|
|
}
|
|
|
|
if(win->extents) {
|
|
XFixesDestroyRegion(fl_display, win->extents);
|
|
win->extents = None;
|
|
}
|
|
|
|
if(win->border_clip) {
|
|
XFixesDestroyRegion(fl_display, win->border_clip);
|
|
win->border_clip = None;
|
|
}
|
|
}
|
|
|
|
if(!win->border_size)
|
|
win->border_size = set_border_size(win);
|
|
|
|
if(!win->extents)
|
|
win->extents = window_extents(win);
|
|
|
|
// EDEBUG("mode :%i\n", win->mode);
|
|
|
|
if(win->mode == WIN_MODE_SOLID) {
|
|
int x, y, wid, hei;
|
|
#if HAVE_NAME_WINDOW_PIXMAP
|
|
x = win->attr.x;
|
|
y = win->attr.y;
|
|
wid = win->attr.width + win->attr.border_width * 2;
|
|
hei = win->attr.height + win->attr.border_width * 2;
|
|
#else
|
|
x = win->attr.x + win->attr.border_width;
|
|
y = win->attr.y + win->attr.border_width;
|
|
wid = win->attr.width;
|
|
hei = win->attr.height;
|
|
#endif
|
|
XFixesSetPictureClipRegion(fl_display, rootBuffer, 0, 0, region);
|
|
set_ignore(NextRequest(fl_display));
|
|
XFixesSubtractRegion(fl_display, region, region, win->border_size);
|
|
set_ignore(NextRequest(fl_display));
|
|
|
|
// EDEBUG(ESTRLOC ": Composite on %i x:%i y:%i w:%i h:%i\n", win->id, x, y, wid, hei);
|
|
|
|
XRenderComposite(fl_display, PictOpSrc, win->picture, None, rootBuffer,
|
|
0, 0, 0, 0, x, y, wid, hei);
|
|
}
|
|
|
|
if(!win->border_clip) {
|
|
win->border_clip = XFixesCreateRegion(fl_display, 0, 0);
|
|
XFixesCopyRegion(fl_display, win->border_clip, region);
|
|
}
|
|
}
|
|
|
|
XFixesSetPictureClipRegion(fl_display, rootBuffer, 0, 0, region);
|
|
paint_root();
|
|
|
|
/*
|
|
* paint from bottom to top
|
|
* use counter since checking only iterator will not pick up first element
|
|
*/
|
|
it = window_list.end();
|
|
it_end = window_list.begin();
|
|
--it; // decrease iterator so it pointing to the last element
|
|
|
|
for(unsigned int i = 0; i < window_list.size(); i++) {
|
|
CWindow* win = *it;
|
|
|
|
XFixesSetPictureClipRegion(fl_display, rootBuffer, 0, 0, win->border_clip);
|
|
|
|
// TODO: server shadows
|
|
// go and directly try to draw client shadows
|
|
// don't draw them on desktop
|
|
#if 0
|
|
if(win->shadow && win->window_type != _XA_NET_WM_WINDOW_TYPE_DESKTOP) {
|
|
XRenderComposite(fl_display, PictOpOver, blackPicture, win->shadow, rootBuffer,
|
|
0, 0, 0, 0,
|
|
win->attr.x + win->shadow_dx,
|
|
win->attr.y + win->shadow_dy,
|
|
win->shadow_w, win->shadow_h);
|
|
}
|
|
#endif
|
|
|
|
if(win->opacity != OPAQUE && !win->picture_alpha)
|
|
win->picture_alpha = solid_picture(false, (double)win->opacity / OPAQUE, 0, 0, 0);
|
|
|
|
// TODO: check this, xcompmgr have the same code for WIN_MODE_TRANS and WIN_MODE_ARGB
|
|
if(win->mode == WIN_MODE_TRANS || win->mode == WIN_MODE_ARGB) {
|
|
int x, y, wid, hei;
|
|
#if HAVE_NAME_WINDOW_PIXMAP
|
|
x = win->attr.x;
|
|
y = win->attr.y;
|
|
wid = win->attr.width + win->attr.border_width * 2;
|
|
hei = win->attr.height + win->attr.border_width * 2;
|
|
#else
|
|
x = win->attr.x + win->attr.border_width;
|
|
y = win->attr.y + win->attr.border_width;
|
|
wid = win->attr.width;
|
|
hei = win->attr.height;
|
|
#endif
|
|
set_ignore(NextRequest(fl_display));
|
|
|
|
XRenderComposite(fl_display, PictOpOver, win->picture, win->picture_alpha, rootBuffer,
|
|
0, 0, 0, 0,
|
|
x, y, wid, hei);
|
|
|
|
#if 0
|
|
XRenderComposite(fl_display, PictOpOver, win->picture, win->picture_alpha, rootBuffer,
|
|
10, 0,
|
|
0, 0,
|
|
x+10, y, wid-10, 100);
|
|
|
|
// solid
|
|
XRenderComposite(fl_display, PictOpSrc, win->picture, None, rootBuffer,
|
|
10, 100,
|
|
0, 0,
|
|
x+10, y+100, wid-10, hei-100);
|
|
|
|
XRenderComposite(fl_display, PictOpSrc, win->picture, None, rootBuffer,
|
|
0, 0,
|
|
0, 0,
|
|
x, y, 10, hei);
|
|
#endif
|
|
|
|
}
|
|
|
|
// XXX: a lot of errors here ?
|
|
if(win->border_clip != None) {
|
|
XFixesDestroyRegion(fl_display, win->border_clip);
|
|
win->border_clip = None;
|
|
}
|
|
|
|
// this will assure we catch first element too
|
|
if(it != it_end)
|
|
--it;
|
|
}
|
|
|
|
XFixesDestroyRegion(fl_display, region);
|
|
|
|
if(rootBuffer != rootPicture) {
|
|
XFixesSetPictureClipRegion(fl_display, rootBuffer, 0, 0, None);
|
|
XRenderComposite(fl_display, PictOpSrc, rootBuffer, None, rootPicture,
|
|
0, 0, 0, 0, 0, 0,
|
|
DisplayWidth(fl_display, fl_screen),
|
|
DisplayHeight(fl_display, fl_screen));
|
|
}
|
|
}
|
|
|
|
void Composite::damage_window(XDamageNotifyEvent* de) {
|
|
CWindow* win = find_window(de->drawable);
|
|
if(!win)
|
|
return;
|
|
#if 0
|
|
// XXX: addon
|
|
while(XPending(fl_display)) {
|
|
XEvent ev;
|
|
if(XPeekEvent(fl_display, &ev) && ev.type == (damage_event + XDamageNotify) && ev.xany.window == win->id) {
|
|
XNextEvent(fl_display, &ev);
|
|
repair_window(win);
|
|
EDEBUG("XXXXXXXXXXXXX\n");
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
#endif
|
|
repair_window(win);
|
|
}
|
|
|
|
void Composite::repair_window(CWindow* win) {
|
|
XserverRegion parts;
|
|
|
|
if(!win->damaged) {
|
|
parts = window_extents(win);
|
|
set_ignore(NextRequest(fl_display));
|
|
XDamageSubtract(fl_display, win->damage, None, None);
|
|
} else {
|
|
parts = XFixesCreateRegion(fl_display, 0, 0);
|
|
set_ignore(NextRequest(fl_display));
|
|
XDamageSubtract(fl_display, win->damage, None, parts);
|
|
|
|
XFixesTranslateRegion(fl_display, parts,
|
|
win->attr.x + win->attr.border_width,
|
|
win->attr.y + win->attr.border_width);
|
|
|
|
// TODO: server shadows
|
|
}
|
|
|
|
if(parts == None)
|
|
EDEBUG("parts == None\n");
|
|
|
|
add_damage(parts);
|
|
win->damaged = 1;
|
|
}
|
|
|
|
void Composite::destroy_window(Window id, bool gone, bool fade) {
|
|
#if HAVE_NAME_WINDOW_PIXMAP
|
|
CWindow* win = find_window(id);
|
|
|
|
if(win && win->pixmap && fade && fadeWindows) {
|
|
// TODO: fading support
|
|
} else
|
|
#endif
|
|
finish_destroy_window(id, gone);
|
|
}
|
|
|
|
void Composite::finish_destroy_window(Window id, bool gone) {
|
|
CWindowListIter it = window_list.begin(), it_end = window_list.end();
|
|
|
|
while(it != it_end) {
|
|
if((*it)->id == id) {
|
|
CWindow* win = *it;
|
|
|
|
if(!gone)
|
|
finish_unmap_window(win);
|
|
if(win->picture) {
|
|
set_ignore(NextRequest(fl_display));
|
|
XRenderFreePicture(fl_display, win->picture);
|
|
win->picture = None;
|
|
}
|
|
|
|
if(win->picture_alpha) {
|
|
XRenderFreePicture(fl_display, win->picture_alpha);
|
|
win->picture_alpha = None;
|
|
}
|
|
|
|
if(win->picture_shadow) {
|
|
XRenderFreePicture(fl_display, win->picture_shadow);
|
|
win->picture_shadow = None;
|
|
}
|
|
|
|
if(win->damage != None) {
|
|
set_ignore(NextRequest(fl_display));
|
|
XDamageDestroy(fl_display, win->damage);
|
|
win->damage = None;
|
|
}
|
|
|
|
// TODO: fading support
|
|
window_list.erase(it);
|
|
delete win;
|
|
break;
|
|
}
|
|
|
|
++it;
|
|
}
|
|
}
|
|
|
|
void Composite::update_screen(void) {
|
|
if(allDamage != None) {
|
|
paint_all(allDamage);
|
|
allDamage = None;
|
|
clipChanged = false;
|
|
}
|
|
}
|
|
|
|
int Composite::handle_xevents(const XEvent* xev) {
|
|
if(another_is_running || !manual_redirect)
|
|
return 0;
|
|
|
|
switch(xev->type) {
|
|
case CreateNotify:
|
|
EDEBUG(ESTRLOC ": CreateNotify from composite\n");
|
|
add_window(xev->xcreatewindow.window, 0);
|
|
break;
|
|
case ConfigureNotify:
|
|
EDEBUG(ESTRLOC ": ConfigureNotify from composite\n");
|
|
configure_window(&xev->xconfigure);
|
|
break;
|
|
case DestroyNotify:
|
|
EDEBUG(ESTRLOC ": DestroyNotify from composite\n");
|
|
destroy_window(xev->xdestroywindow.window, true, true);
|
|
break;
|
|
case MapNotify:
|
|
EDEBUG(ESTRLOC ": MapNotify from composite\n");
|
|
map_window(xev->xmap.window, xev->xmap.serial, true);
|
|
break;
|
|
case UnmapNotify:
|
|
EDEBUG(ESTRLOC ": UnmapNotify from composite\n");
|
|
unmap_window(xev->xunmap.window, true);
|
|
break;
|
|
case ReparentNotify:
|
|
EDEBUG(ESTRLOC ": ReparentNotify from composite\n");
|
|
reparent_notify(&xev->xreparent);
|
|
break;
|
|
case CirculateNotify:
|
|
EDEBUG(ESTRLOC ": CirculateNotify from composite\n");
|
|
circulate_window(&xev->xcirculate);
|
|
break;
|
|
case Expose:
|
|
EDEBUG(ESTRLOC ": Expose from composite\n");
|
|
expose_event(&xev->xexpose);
|
|
break;
|
|
case PropertyNotify:
|
|
EDEBUG(ESTRLOC ": PropertyNotify from composite\n");
|
|
property_notify(&xev->xproperty);
|
|
break;
|
|
default:
|
|
if(xev->type == (damage_event + XDamageNotify)) {
|
|
//EDEBUG("---------> %i <---------\n", damage_event + XDamageNotify);
|
|
damage_window((XDamageNotifyEvent*)xev);
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 1;
|
|
}
|