/*
* Copyright (C) 1999,2000,2001 Frank Hale
* frankhale@yahoo.com
* http://sapphire.sourceforge.net/
*
* Updated: 3 Nov 2001
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sapphire.hh"
Client::Client()
{
// One thing I cannot stand is fucking variables that are cryptic.
// I gotta lay off the dope when I code, shit!
shaped = false;
moving = false;
shaded = false;
maxsized = false;
name = "unknown";
// Defaults for this Clients x, y position and width and height.
x = 1;
y = 1;
width = 1;
height = 1;
oumx = 1;
oumy = 1;
oumwidth = 1;
oumheight = 1;
old_width = width;
old_height = height;
default_titlebar_height = wm->getIHeight() + DEFAULT_SPACE;
default_client_name_x = DEFAULT_SPACE + 20;
default_client_name_y = wm->getFontPosition(); //DEFAULT_SPACE + wm->getXFont()->ascent + 2;
default_button_width= 13;
default_button_height= 13;
client_position[40]=0;
text_width=0;
right_sidebar_width=10;
// These are set to there real defaults in the reparent function.
default_close_button_x = 0;
default_close_button_y = 0;
default_shade_button_x = 0;
default_shade_button_y = 0;
default_minimize_button_x = 0;
default_minimize_button_y = 0;
default_maximize_button_x = 0;
default_maximize_button_y = 0;
close_button_pressed=false;
shade_button_pressed=false;
minimize_button_pressed=false;
maximize_button_pressed=false;
// Mouse Button defaults
button1=button2=button3=false;
// Window Decorations
//
// The parent_window is the main parent. The titlebar is a child of the parent_window
// all other button windows are childs of the titlebar.
has_titlebar=true;
has_close_button=true;
has_minimize_button=true;
has_maximize_button=true;
has_shade_button=true;
frame_pix=None; // Pixmap used for the titlebar
button_pix=None;// Pixmap used for titlebar buttons
ignore_unmap=0;
close.window = maximize.window
= minimize.window
= shadeButton.window
= window
= parent
= transient
= title
= right_sidebar
= resize_win
= None;
}
Client::~Client()
{
}
Window Client::createTopLevelWindow(int x, int y,
unsigned int width,unsigned int height,unsigned int borderwidth)
{
XSetWindowAttributes attrib;
unsigned long create_mask = CWOverrideRedirect |
CWBackPixmap | CWBackPixel | CWBorderPixel | CWCursor |
CWEventMask;
attrib.background_pixmap = None;
attrib.background_pixel = wm->getBackgroundColor().pixel;
attrib.border_pixel = wm->getBorderColor().pixel;
attrib.override_redirect = true;
attrib.cursor = XCreateFontCursor(wm->getDisplay(), XC_left_ptr);
attrib.event_mask = StructureNotifyMask | SubstructureNotifyMask |
SubstructureRedirectMask | ExposureMask | ButtonMotionMask |
ButtonPressMask | ButtonReleaseMask | FocusChangeMask;
return (XCreateWindow(wm->getDisplay(), wm->getRootWindow(), x,y,width,height,borderwidth,
DefaultDepth(wm->getDisplay(), wm->getScreen()), InputOutput, DefaultVisual(wm->getDisplay(), wm->getScreen()),
create_mask, &attrib));
}
Window Client::createChildWindow(Window parent, int x, int y,
unsigned int width,unsigned int height,unsigned int borderwidth)
{
XSetWindowAttributes attrib;
unsigned long create_mask =
CWBackPixmap | CWBackPixel | CWBorderPixel | CWCursor |
CWEventMask;
attrib.background_pixmap = None;
attrib.background_pixel = wm->getBackgroundColor().pixel;
attrib.border_pixel = wm->getBorderColor().pixel;
attrib.cursor = XCreateFontCursor(wm->getDisplay(), XC_left_ptr);
attrib.event_mask = StructureNotifyMask | SubstructureNotifyMask |
SubstructureRedirectMask | ExposureMask | EnterWindowMask |
LeaveWindowMask | ButtonMotionMask | ButtonPressMask |
ButtonReleaseMask;
return (XCreateWindow(wm->getDisplay(), parent, x,y,width,height,borderwidth,
DefaultDepth(wm->getDisplay(), wm->getScreen()), InputOutput, DefaultVisual(wm->getDisplay(), wm->getScreen()),
create_mask, &attrib));
}
void Client::make_new_client(Window w)
{
long dummy;
XWMHints *hints;
XWindowAttributes attr;
// Populate the hints structure with the window hints (w) has.
hints = XGetWMHints(wm->getDisplay(), w);
// Create a new Client object.
Client *c = new Client();
// Insert the client into the window manager client list.
wm->insertClient(c);
// Assign the window (w) to c->window, c->window represents the application.
c->window = w;
c->ignore_unmap = 0;
XGetWindowAttributes(wm->getDisplay(), c->window, &attr);
c->x = attr.x;
c->y = attr.y;
c->width = attr.width;
c->height = attr.height;
c->cmap = attr.colormap;
c->size = XAllocSizeHints();
init_position(c);
XGetWMNormalHints(wm->getDisplay(), c->window, c->size, &dummy);
XSelectInput(wm->getDisplay(), c->window, ColormapChangeMask | PropertyChangeMask | EnterWindowMask );
getTransients(c);
if (XFetchName(wm->getDisplay(), c->window, &c->name)==0)
c->name=NULL;
if (isViewable(c)) c->ignore_unmap++;
change_gravity(c, 1);
// Determine if this client needs window decorations.
setButtonPositionDefaults(c);
determineWindowDecorations(c);
if (hints) XFree(hints);
// Do all the necessary reparenting for this client
reparent(c);
// If this client should be iconic on start then we won't map it.
isIconic(c);
XAddToSaveSet(wm->getDisplay(), c->window);
XSetWindowBorderWidth(wm->getDisplay(), c->window, 0);
}
void Client::init_position(Client *c)
{
/* Adapted from aewm 1.1.2 */
int xmax = wm->getXRes();
int ymax = wm->getYRes();
int mouse_x=0, mouse_y=0;
if (c->size->flags & (USSize))
{
c->width = c->size->width;
c->height = c->size->height;
} else {
/* we would check PSize here, if GTK didn't blow goats */
/* make sure it's big enough to click at */
if (c->width < 2 * theight(c)) c->width = 2 * theight(c);
if (c->height < theight(c)) c->height = theight(c);
}
if (c->size->flags & USPosition)
{
c->x = c->size->x;
c->y = c->size->y;
} else {
if (c->size->flags & PPosition)
{
c->x = c->size->x;
c->y = c->size->y;
}
if (c->x < 0) c->x = 0;
if (c->y < 0) c->y = 0;
if (c->x > xmax) c->x = xmax - 5;
if (c->y > ymax) c->y = ymax - 5;
}
if (c->x == 0 && c->y == 0)
{
get_mouse_position(&mouse_x, &mouse_y);
if (c->width < xmax)
c->x = (mouse_x / 2);
if (c->height + theight(c) < ymax)
c->y = (mouse_y / 2);
c->y += theight(c);
change_gravity(c, -1);
}
}
void Client::remove_client(Client *c)
{
XEvent foo;
XGrabServer(wm->getDisplay());
if(! XCheckTypedWindowEvent(wm->getDisplay(), c->window, DestroyNotify, &foo))
{
// Sets input focus back to the root window
XSetInputFocus(wm->getDisplay(), wm->getRootWindow(), RevertToPointerRoot, CurrentTime);
change_gravity(c, -1);
XReparentWindow(wm->getDisplay(), c->window, wm->getRootWindow(), c->x, c->y);
XRemoveFromSaveSet(wm->getDisplay(), c->window);
XDestroyWindow(wm->getDisplay(), c->close.window);
XDestroyWindow(wm->getDisplay(), c->maximize.window);
XDestroyWindow(wm->getDisplay(), c->minimize.window);
XDestroyWindow(wm->getDisplay(), c->shadeButton.window);
XDestroyWindow(wm->getDisplay(), c->right_sidebar);
XDestroyWindow(wm->getDisplay(), c->resize_win);
XDestroyWindow(wm->getDisplay(), c->title);
XDestroyWindow(wm->getDisplay(), c->parent);
if (c->name) XFree(c->name);
if (c->size) XFree(c->size);
wm->getImageControl()->removeImage(c->frame_pix);
wm->getImageControl()->removeImage(c->right_pix);
wm->getImageControl()->removeImage(c->button_pix);
wm->getImageControl()->removeImage(c->resize_pix);
wm->removeClient(c);
delete c;
}
XSync(wm->getDisplay(), false);
XUngrabServer(wm->getDisplay());
}
void Client::setButtonPositionDefaults(Client *c)
{
c->default_close_button_x = 4;
c->default_close_button_y = theight(c) / 2 - 7;
c->default_shade_button_x = c->width - 44;
c->default_shade_button_y = theight(c) / 2 - 7;
c->default_minimize_button_x = c->width - 27;
c->default_minimize_button_y = theight(c) / 2 - 7;
c->default_maximize_button_x = c->width - 10;
c->default_maximize_button_y = theight(c) / 2 - 7;
}
void Client::reparent(Client *c)
{
createParentWindow(c);
createTitlebarWindow(c);
createRightSidebarWindow(c);
createResizeWindow(c);
createCloseButtonWindow(c);
createMinimizeButtonWindow(c);
createMaximizeButtonWindow(c);
createShadeButtonWindow(c);
if (wm->getShape()) {
XShapeSelectInput(wm->getDisplay(), c->window, ShapeNotifyMask);
set_shape(c);
}
// If this window doesn't request that it shouldn't be reparented
// then we will go ahead an reparent it to c->parent which is the
// parent window which holds the client application window ( c->window ) aswell
// as the titlebar window and the button windows.
if (c->has_titlebar)
{
int x, y;
unsigned int width, height, border, depth;
Window win;
XGetGeometry(wm->getDisplay(), c->parent, &win, &x, &y, &width, &height, &border, &depth);
XReparentWindow(wm->getDisplay(), c->window, c->parent, 0, theight(c));
if(y <= theight(c))
{
XMoveWindow(wm->getDisplay(), c->parent, x, y);
c->y = theight(c);
}
else {
XMoveWindow(wm->getDisplay(), c->parent, x, y - theight(c));
c->y = y;
}
}
else
{
// If we don't need to reparent it with window decorations then we
// reparent it back to the root window and move it to where it wishes
// to be when mapped.
XReparentWindow(wm->getDisplay(), c->window, wm->getRootWindow(), 0, 0);
XMoveWindow(wm->getDisplay(), c->window, c->x, c->y);
}
createButtonImage(c);
createResizeImage(c);
send_config(c);
}
void Client::createParentWindow(Client *c)
{
c->parent = createTopLevelWindow
(
c->x,
c->y - theight(c),
c->width + right_sidebar_width,
c->height + theight(c),
DEFAULT_BORDER_SIZE
);
}
void Client::createTitlebarWindow(Client *c)
{
c->title = createChildWindow
(
c->parent,
0,
0,
c->width + right_sidebar_width,
theight(c),
0
);
}
void Client::createRightSidebarWindow(Client *c)
{
c->right_sidebar = createChildWindow
(
c->parent,
c->width,
theight(c),
right_sidebar_width,
c->height - 10,
1
);
}
void Client::createResizeWindow(Client *c)
{
c->resize_win = createChildWindow
(
c->parent,
c->width,
c->height + 10,
right_sidebar_width,
10,
1
);
}
void Client::createCloseButtonWindow(Client *c)
{
c->close.x = c->default_close_button_x;
c->close.y = c->default_close_button_y;
c->close.width = c->default_button_width;
c->close.height = c->default_button_height;
c->close.window = createChildWindow
(
c->title,
c->close.x,
c->close.y,
c->close.width,
c->close.height,
1
);
}
void Client::createMinimizeButtonWindow(Client *c)
{
c->minimize.x = c->default_minimize_button_x;
c->minimize.y = c->default_minimize_button_y;
c->minimize.width = c->default_button_width;
c->minimize.height = c->default_button_height;
c->minimize.window = createChildWindow
(
c->title,
c->minimize.x,
c->minimize.y,
c->minimize.width,
c->minimize.height,
1
);
}
void Client::createMaximizeButtonWindow(Client *c)
{
c->maximize.x = c->default_maximize_button_x;
c->maximize.y = c->default_maximize_button_y;
c->maximize.width = c->default_button_width;
c->maximize.height = c->default_button_height;
c->maximize.window = createChildWindow
(
c->title,
c->maximize.x,
c->maximize.y,
c->maximize.width,
c->maximize.height,
1
);
}
void Client::createShadeButtonWindow(Client *c)
{
c->shadeButton.x = c->default_shade_button_x;
c->shadeButton.y = c->default_shade_button_y;
c->shadeButton.width = c->default_button_height;
c->shadeButton.height = c->default_button_height;
c->shadeButton.window = createChildWindow
(
c->title,
c->shadeButton.x,
c->shadeButton.y,
c->shadeButton.width,
c->shadeButton.height,
1
);
}
int Client::theight(Client *c) const
{
//return ((c->transient ? 2*DEFAULT_SPACE : wm->iheight) + DEFAULT_SPACE);
// For now this function will pass a Client object. Even though we don't
// use it for much, I still might want to have transients have a different style
// than there top level parents later on.
//
// For instance I could turn off some of the titlebar buttons, or I could change the
// height of the client's titlebar and button width and height.
//
// This is the reason why I am passing the Client object to this function. I simply
// haven't made up my mind at this point.
return c->default_titlebar_height;
}
void Client::getTransients(Client *c)
{
Window trans;
XGetTransientForHint(wm->getDisplay(), c->window, &trans);
c->transient = trans;
}
void Client::determineWindowDecorations(Client *c)
{
// This code was ripped from somewhere but since Client.cc
// is coded so fucking badly it doesn't work for anything.
int format;
Atom atom_return;
unsigned long num, len;
if (XGetWindowProperty(wm->getDisplay(), c->window,
wm->getMotifWMHintsAtom(), 0,
PropMwmHintsElements, false,
wm->getMotifWMHintsAtom(), &atom_return,
&format, &num, &len,
(unsigned char **) &c->mwm_hint) == Success && c->mwm_hint)
if (num == PropMwmHintsElements) {
if (c->mwm_hint->flags & MwmHintsDecorations)
{
if (c->mwm_hint->decorations & MwmDecorAll)
{
c->has_titlebar=c->has_close_button=c->has_minimize_button=c->has_maximize_button=c->has_shade_button=true;
}
else {
c->has_titlebar=c->has_close_button=c->has_minimize_button=c->has_maximize_button=c->has_shade_button=false;
if (c->mwm_hint->decorations & MwmDecorTitle) c->has_titlebar = true;
c->has_minimize_button = true;
c->has_maximize_button = true;
c->has_shade_button=true;
c->has_close_button=true;
}
}
}}
Client *Client::find_client(Window w)
{
if (w && w != wm->getRootWindow())
{
if(wm->getClientCount())
{
LinkedListIterator<Client> it(wm->getClientListObject());
for(; it.current(); it++)
{
if (w == it.current()->parent ||
w == it.current()->title ||
w == it.current()->window ||
w == it.current()->close.window ||
w == it.current()->maximize.window ||
w == it.current()->minimize.window ||
w == it.current()->resize_win ||
w == it.current()->right_sidebar ||
w == it.current()->shadeButton.window )
{
return it.current();
}
}
}
}
return NULL;
}
int Client::isViewable(Client *c)
{
XWindowAttributes attr;
XGetWindowAttributes(wm->getDisplay(), c->window, &attr);
return attr.map_state;
}
void Client::createTitleImage(Client* c)
{
unsigned long style=0;
style = wm->getTheme()->getTitlebarStyle();
c->frame_pix = wm->getImageControl()->renderImage(
c->width+c->right_sidebar_width,
theight(c),
style,
wm->getTheme()->getClientColorFrom(),
wm->getTheme()->getClientColorTo());
XSetWindowBackgroundPixmap(wm->getDisplay(), c->title, c->frame_pix);
}
void Client::createRightSidebarImage(Client *c)
{
unsigned long style=0;
style = wm->getTheme()->getRightSidebarStyle();
c->right_pix = wm->getImageControl()->renderImage(
10,
c->height + theight(c) - 10,
style,
wm->getTheme()->getRightSidebarColorFrom(),
wm->getTheme()->getRightSidebarColorTo());
XSetWindowBackgroundPixmap(wm->getDisplay(), c->right_sidebar, c->right_pix);
}
void Client::createResizeImage(Client *c)
{
unsigned long style=0;
style = wm->getTheme()->getResizeStyle();
c->resize_pix = wm->getImageControl()->renderImage(
10,
10,
style,
wm->getTheme()->getResizeColorFrom(),
wm->getTheme()->getResizeColorTo());
XSetWindowBackgroundPixmap(wm->getDisplay(), c->resize_win, c->resize_pix);
}
void Client::createButtonImage(Client* c)
{
unsigned long style=0;
style = wm->getTheme()->getButtonStyle();
c->button_pix = wm->getImageControl()->renderImage(
c->default_button_width,
c->default_button_height,
style,
wm->getTheme()->getButtonColorFrom(),
wm->getTheme()->getButtonColorTo());
XSetWindowBackgroundPixmap(wm->getDisplay(), c->shadeButton.window, c->button_pix);
XSetWindowBackgroundPixmap(wm->getDisplay(), c->close.window, c->button_pix);
XSetWindowBackgroundPixmap(wm->getDisplay(), c->minimize.window, c->button_pix);
XSetWindowBackgroundPixmap(wm->getDisplay(), c->maximize.window, c->button_pix);
}
void Client::reconfigure(Client *c)
{
createTitleImage(c);
createRightSidebarImage(c);
redraw(c);
}
void Client::send_config(Client *c)
{
XConfigureEvent ce;
XEvent foo;
ce.type = ConfigureNotify;
ce.event = c->window;
ce.window = c->window;
ce.x = c->x;
ce.y = c->y;
ce.width = c->width;
ce.height = c->height;
ce.border_width = 0;
ce.above = None;
ce.override_redirect = 0;
if(! XCheckTypedWindowEvent(wm->getDisplay(), c->window, DestroyNotify, &foo))
{
if(! moving) reconfigure(c);
}
XSendEvent(wm->getDisplay(), c->window, false, StructureNotifyMask, (XEvent *)&ce);
}
void Client::move(Client *c)
{
if (c) {
moving=true;
drag(c);
XMoveWindow(wm->getDisplay(), c->parent, c->x, c->y -theight(c));
send_config(c);
moving=false;
}
}
void Client::drag(Client *c)
{
XEvent ev;
int x1=c->x;
int y1=c->y;
int old_cx = c->x;
int old_cy = c->y;
wm->grabPointer(wm->getRootWindow(), ButtonPressMask | ButtonReleaseMask | PointerMotionMask, wm->getMoveCursor());
XGrabServer(wm->getDisplay());
get_mouse_position(&x1, &y1);
draw_outline(c);
for (;;) {
XMaskEvent(wm->getDisplay(), ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &ev);
switch (ev.type) {
case MotionNotify:
draw_outline(c); /* clear */
c->x = old_cx + (ev.xmotion.x_root - x1);
c->y = old_cy + (ev.xmotion.y_root - y1);
draw_outline(c);
break;
case ButtonRelease:
draw_outline(c); /* clear */
XUngrabServer(wm->getDisplay());
wm->ungrabPointer();
return;
}
}
}
void Client::resize(Client *c)
{
if (c) {
sweep(c);
if (c->maxsized) {
c->maxsized = false;
}
XMoveResizeWindow(wm->getDisplay(), c->parent, c->x, c->y - theight(c), c->width+c->right_sidebar_width, c->height + theight(c));
XMoveResizeWindow(wm->getDisplay(), c->title, 0, 0, c->width+c->right_sidebar_width, theight(c));
XMoveResizeWindow(wm->getDisplay(), c->right_sidebar, c->width, theight(c), c->right_sidebar_width, c->height - 10);
XMoveResizeWindow(wm->getDisplay(), c->resize_win, c->width, c->height + 10, 10, 10);
XMoveWindow(wm->getDisplay(), c->maximize.window, c->width - 10, c->maximize.y);
XMoveWindow(wm->getDisplay(), c->minimize.window, c->width - 27, c->minimize.y);
XMoveWindow(wm->getDisplay(), c->shadeButton.window, c->width - 44, c->shadeButton.y);
XMoveResizeWindow(wm->getDisplay(), c->window, 0, theight(c), c->width, c->height);
send_config(c);
}
}
void Client::recalculate_sweep(Client *c, int x1, int y1, int x2, int y2)
{
int basex=0;
int basey=0;
c->width = abs(x1 - x2) - DEFAULT_BORDER_SIZE;
c->height = abs(y1 - y2) - DEFAULT_BORDER_SIZE;
if (c->size->flags & PResizeInc) {
basex = (c->size->flags & PBaseSize) ? c->size->base_width :
(c->size->flags & PMinSize) ? c->size->min_width : c->x;
basey = (c->size->flags & PBaseSize) ? c->size->base_height :
(c->size->flags & PMinSize) ? c->size->min_height : c->y;
c->width -= (c->width - basex) % c->size->width_inc;
c->height -= (c->height - basey) % c->size->height_inc;
}
if (c->size->flags & PMinSize) {
if (c->width < c->size->min_width) c->width = c->size->min_width;
if (c->height < c->size->min_height) c->height = c->size->min_height;
}
if (c->size->flags & PMaxSize) {
if (c->width > c->size->max_width) c->width = c->size->max_width;
if (c->height > c->size->max_height) c->height = c->size->max_height;
}
c->x = (x1 <= x2) ? x1 : x1 - c->width;
c->y = (y1 <= y2) ? y1 : y1 - c->height;
}
void Client::sweep(Client *c)
{
XEvent ev;
int old_cx = c->x;
int old_cy = c->y;
wm->grabPointer(wm->getRootWindow(), ButtonReleaseMask | PointerMotionMask, wm->getResizeCursor());
draw_outline(c);
for (;;) {
XMaskEvent(wm->getDisplay(), ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &ev);
switch (ev.type) {
case MotionNotify:
draw_outline(c);
recalculate_sweep(c, old_cx, old_cy, ev.xmotion.x_root , ev.xmotion.y_root);
draw_outline(c);
break;
case ButtonRelease:
draw_outline(c);
wm->ungrabPointer();
return;
}
}
}
void Client::draw_outline(Client *c)
{
if(c->shaded)
{
XDrawRectangle(wm->getDisplay(), wm->getRootWindow(), wm->getInvertGC(),
c->x, /* x */
c->y - theight(c) + DEFAULT_BORDER_SIZE/2, /* y */
c->width+10, /* width */
theight(c) + DEFAULT_BORDER_SIZE); /* height */
} else {
XDrawRectangle(wm->getDisplay(), wm->getRootWindow(), wm->getInvertGC(),
c->x + DEFAULT_BORDER_SIZE/2, /* x */
c->y - theight(c) + DEFAULT_BORDER_SIZE/2, /* y */
c->width + 10 + DEFAULT_BORDER_SIZE, /* width */
c->height + theight(c) + DEFAULT_BORDER_SIZE); /* height */
sprintf(c->client_position, "%dx%d+%d+%d",
c->width+c->right_sidebar_width,
c->height+theight(c),
c->x,
c->y);
c->text_width=XTextWidth(wm->getXFont(), c->client_position, strlen(c->client_position));
XDrawString(wm->getDisplay(),
wm->getRootWindow(),
wm->getInvertGC(),
c->x + c->width - XTextWidth(wm->getXFont(),
c->client_position,
strlen(c->client_position)),
c->y + c->height - DEFAULT_SPACE,
c->client_position, strlen(c->client_position));
}
}
void Client::maximumresize(Client *c)
{
// Check to see if this window can be resized more
// if its at its max size then lets leave it alone.
if (c && !(c->size->flags & PMaxSize) ) {
if (c->maxsized)
{
c->x = c->oumx;
c->y = c->oumy;
c->width = c->oumwidth;
c->height = c->oumheight;
c->maxsized = false;
} else {
c->oumx = c->x;
c->oumy = c->y;
c->oumwidth = c->width;
c->oumheight = c->height;
c->x = 1;
if (wm->getTheme()->getToolbarExtraStyle() & TOOLBAR_TOP)
{
c->y = 28 + theight(c);
c->width = wm->getXRes() - 14;
c->height = wm->getYRes() - theight(c) - 34;
c->maxsized = true;
} else {
c->y = 0 + theight(c);
c->width = wm->getXRes() - 14;
c->height = wm->getYRes() - 28 - theight(c);
c->maxsized = true;
}
}
XMoveResizeWindow(wm->getDisplay(), c->parent, c->x, c->y - theight(c), c->width + c->right_sidebar_width, c->height + theight(c));
XMoveResizeWindow(wm->getDisplay(), c->title, 0, 0, c->width+c->right_sidebar_width, theight(c));
XMoveResizeWindow(wm->getDisplay(), c->right_sidebar, c->width, theight(c), c->right_sidebar_width, c->height - 10);
XMoveResizeWindow(wm->getDisplay(), c->resize_win, c->width, c->height + 10, right_sidebar_width, 10);
XMoveWindow(wm->getDisplay(), c->maximize.window, c->width - 10, c->maximize.y);
XMoveWindow(wm->getDisplay(), c->minimize.window, c->width - 27, c->minimize.y);
XMoveWindow(wm->getDisplay(), c->shadeButton.window, c->width - 44, c->shadeButton.y);
XMoveResizeWindow(wm->getDisplay(), c->window, 0, theight(c), c->width, c->height);
send_config(c);
}
}
void Client::hide(Client *c)
{
c->ignore_unmap++;
if(c->has_titlebar)
{
XUnmapSubwindows(wm->getDisplay(), c->parent);
XUnmapWindow(wm->getDisplay(), c->parent);
} else {
XUnmapWindow(wm->getDisplay(), c->window);
}
set_wm_state(c, IconicState);
wm->getIconMenu()->addIcon(c->name, c);
}
void Client::unhide(Client *c)
{
mapClient(c);
}
// This repaints the titlebar and buttons on it, It also paints the window title.
void Client::redraw(Client *c)
{
if (c->has_titlebar)
{
XClearWindow(wm->getDisplay(), c->title);
XClearWindow(wm->getDisplay(), c->close.window);
XClearWindow(wm->getDisplay(), c->minimize.window);
XClearWindow(wm->getDisplay(), c->maximize.window);
XClearWindow(wm->getDisplay(), c->shadeButton.window);
XClearWindow(wm->getDisplay(), c->right_sidebar);
XClearWindow(wm->getDisplay(), c->resize_win);
// Close Button
XDrawLine(wm->getDisplay(), c->close.window, wm->getBorderGC(), 2,2,c->close.width - 3,c->close.height-3);
XDrawLine(wm->getDisplay(), c->close.window, wm->getBorderGC(), 2,c->close.height - 3,c->close.width-3,2);
// Maximize Button
XDrawRectangle(wm->getDisplay(), c->maximize.window,
wm->getBorderGC(), 2, 2, c->maximize.width - 5, c->maximize.height - 5);
XDrawLine(wm->getDisplay(), c->maximize.window,
wm->getBorderGC(), 2, 3, c->maximize.width - 3, 3);
// Minimize Button
XDrawRectangle(wm->getDisplay(), c->minimize.window,
wm->getBorderGC(), 2, c->minimize.height - 5, c->minimize.width - 5, 2);
draw_shade_button(c);
if (c->name)
{
XDrawString(wm->getDisplay(),
c->title,
wm->getStringGC(),
c->default_client_name_x,
c->default_client_name_y,
c->name,
strlen(c->name));
}
}
}
void Client::draw_shade_button(Client *c)
{
if (c->shaded)
{
// Draws a triangle pointing down which indicates that this
// window is shaded.
//
XDrawLine(wm->getDisplay(), c->shadeButton.window,wm->getBorderGC(),
2, 5, 11, 5);
XDrawLine(wm->getDisplay(), c->shadeButton.window,wm->getBorderGC(),
3, 6, 10, 6);
XDrawLine(wm->getDisplay(), c->shadeButton.window,wm->getBorderGC(),
4, 7, 9, 7);
XDrawLine(wm->getDisplay(), c->shadeButton.window,wm->getBorderGC(),
5, 8, 8, 8);
XDrawLine(wm->getDisplay(), c->shadeButton.window,wm->getBorderGC(),
6, 9, 7, 9);
} else {
// Draws a triangle pointing up which indicates that this
// window is not shaded.
//
XDrawLine(wm->getDisplay(), c->shadeButton.window,wm->getBorderGC(),
6, 5, 7, 5);
XDrawLine(wm->getDisplay(), c->shadeButton.window,wm->getBorderGC(),
5, 6, 8, 6);
XDrawLine(wm->getDisplay(), c->shadeButton.window,wm->getBorderGC(),
4, 7, 9, 7);
XDrawLine(wm->getDisplay(), c->shadeButton.window,wm->getBorderGC(),
3, 8, 10, 8);
XDrawLine(wm->getDisplay(), c->shadeButton.window,wm->getBorderGC(),
2, 9, 11, 9);
}
}
void Client::change_gravity(Client *c, int multiplier)
{
int dy = 0;
int gravity = (c->size->flags & PWinGravity) ?
c->size->win_gravity : NorthWestGravity;
switch (gravity) {
case NorthWestGravity:
case NorthEastGravity:
case NorthGravity: dy = theight(c); break;
case CenterGravity: dy = theight(c)/2; break;
}
c->y += multiplier * dy;
}
void Client::set_shape(Client *c)
{
int n, order;
XRectangle *rect;
rect = XShapeGetRectangles(wm->getDisplay(), c->window, ShapeBounding, &n, &order);
if (n > 1) XShapeCombineShape(wm->getDisplay(),
c->parent, ShapeBounding, 0, theight(c),
c->window, ShapeBounding, ShapeSet);
XFree(rect);
}
void Client::get_mouse_position(int *x, int *y)
{
Window dw1=None;
Window dw2=None;
int t1=0;
int t2=0;
unsigned int t3=0;
XQueryPointer(wm->getDisplay(), wm->getRootWindow(), &dw1, &dw2, x, y, &t1, &t2, &t3);
}
void Client::shade(Client *c)
{
if (c->shaded)
{
XResizeWindow(wm->getDisplay(), c->parent, c->width+10, c->height + theight(c));
c->shaded=false;
} else {
XResizeWindow(wm->getDisplay(), c->parent, c->width+10, theight(c));
c->shaded=true;
}
}
void Client::closeButtonPressed(Client *c)
{
XSetWindowBorderWidth(wm->getDisplay(), c->close.window, 2);
XEvent ev;
for (;;) {
XMaskEvent(wm->getDisplay(), ButtonReleaseMask | LeaveWindowMask, &ev);
switch (ev.type)
{
case LeaveNotify:
{
XSetWindowBorderWidth(wm->getDisplay(), c->close.window, 1);
return;
}
case ButtonRelease:
{
XSetWindowBorderWidth(wm->getDisplay(), c->close.window, 1);
send_wm_delete(c);
return;
}
}
}
}
void Client::shadeButtonPressed(Client *c)
{
XSetWindowBorderWidth(wm->getDisplay(), c->shadeButton.window, 2);
XEvent ev;
for (;;) {
XMaskEvent(wm->getDisplay(), ButtonReleaseMask | LeaveWindowMask, &ev);
switch (ev.type)
{
case LeaveNotify:
{
XSetWindowBorderWidth(wm->getDisplay(), c->shadeButton.window, 1);
return;
}
case ButtonRelease:
{
XSetWindowBorderWidth(wm->getDisplay(), c->shadeButton.window, 1);
XRaiseWindow(wm->getDisplay(), c->parent);
shade(c);
return;
}
}
}
}
void Client::minimizeButtonPressed(Client *c)
{
XSetWindowBorderWidth(wm->getDisplay(), c->minimize.window, 2);
XEvent ev;
for (;;) {
XMaskEvent(wm->getDisplay(), ButtonReleaseMask | LeaveWindowMask, &ev);
switch (ev.type)
{
case LeaveNotify:
{
XSetWindowBorderWidth(wm->getDisplay(), c->minimize.window, 1);
return;
}
case ButtonRelease:
{
XSetWindowBorderWidth(wm->getDisplay(), c->minimize.window, 1);
hide(c);
return;
}
}
}
}
void Client::maximizeButtonPressed(Client *c)
{
XSetWindowBorderWidth(wm->getDisplay(), c->maximize.window, 2);
XEvent ev;
for (;;) {
XMaskEvent(wm->getDisplay(), ButtonReleaseMask | LeaveWindowMask, &ev);
switch (ev.type)
{
case LeaveNotify:
{
XSetWindowBorderWidth(wm->getDisplay(), c->maximize.window, 1);
return;
}
case ButtonRelease:
{
XSetWindowBorderWidth(wm->getDisplay(), c->maximize.window, 1);
switch(ev.xbutton.button)
{
case 1:
{
if(c->shaded)
{
shade(c);
XRaiseWindow(wm->getDisplay(), c->parent);
// Make sure it doesn't keep resizing if its already max resized
if (! c->maxsized) maximumresize(c);
} else {
XRaiseWindow(wm->getDisplay(), c->parent);
maximumresize(c);
}
return;
}
}
}
}
}
}
void Client::send_wm_delete(Client *c)
{
if (c) send_xmessage(c->window, wm->getWMProtocolsAtom(), wm->getWMDeleteAtom(), CurrentTime);
}
int Client::send_xmessage(Window w, Atom a, long x, long y)
{
XEvent ev;
long mask;
memset(&ev, '\0', sizeof ev);
ev.type = ClientMessage;
ev.xclient.window = w;
ev.xclient.message_type = a;
ev.xclient.format = 32;
ev.xclient.data.l[0] = x;
ev.xclient.data.l[1] = y;
mask = (w == wm->getRootWindow()) ? SubstructureRedirectMask : 0L;
return XSendEvent(wm->getDisplay(), w, false, mask, &ev);
}
void Client::set_wm_state(Client *c, int state)
{
long data[2];
data[0] = (long) state;
data[1] = (long) None; /* icon window */
c->state = state;
XChangeProperty(wm->getDisplay(), c->window, wm->getWMStateAtom(), wm->getWMStateAtom(),
32, PropModeReplace, (unsigned char *)data, 2);
}
int Client::get_wm_state(Client *c)
{
Atom real_type;
int real_format, state;
unsigned long n, extra;
unsigned char *data;
if ((XGetWindowProperty(wm->getDisplay(), c->window, wm->getWMStateAtom(), 0L, 2L, false,
AnyPropertyType, &real_type, &real_format, &n,
&extra, &data) == Success) && n) {
state = *(int *)data;
XFree(data);
return state;
} else return WithdrawnState;
}
void Client::handle_enter_event(XCrossingEvent *e)
{
Client *c = find_client(e->window);
if(c) XSetInputFocus(wm->getDisplay(), c->window, RevertToPointerRoot, CurrentTime);
}
void Client::handle_button_press_event(XButtonEvent *e)
{
Client *c = find_client(e->window);
if (c)
{
switch (e->button)
{
case Button1:
{
if(c->close.window == e->window) closeButtonPressed(c);
else if (c->maximize.window == e->window) maximizeButtonPressed(c);
else if (c->minimize.window == e->window) minimizeButtonPressed(c);
else if (c->shadeButton.window == e->window) shadeButtonPressed(c);
else if (c->right_sidebar == e->window)
{
XRaiseWindow(wm->getDisplay(), c->parent);
redraw(c);
move(c);
}
else if (c->resize_win == e->window)
{
XRaiseWindow(wm->getDisplay(), c->parent);
resize(c);
}
else if (c->title == e->window)
{
XRaiseWindow(wm->getDisplay(), c->parent);
redraw(c);
move(c);
}
break;
}
case Button2:
{
if (c->title == e->window)
{
// Middle click also allows you to shade the window.
if(c->shaded)
{
XRaiseWindow(wm->getDisplay(), c->parent);
shade(c);
redraw(c);
} else {
XRaiseWindow(wm->getDisplay(), c->parent);
shade(c);
redraw(c);
}
}
break;
}
}
}
}
void Client::handle_configure_request(XConfigureRequestEvent *e)
{
Client *c = find_client(e->window);
XWindowChanges wc;
if (c)
{
change_gravity(c, -1);
if (e->value_mask & CWX) c->x = e->x;
if (e->value_mask & CWY) c->y = e->y;
if (e->value_mask & CWWidth) c->width = e->width;
if (e->value_mask & CWHeight) c->height = e->height;
change_gravity(c, 1);
if (c->width != wc.width && c->height != wc.height)
{
if (c->has_titlebar) XMoveResizeWindow(wm->getDisplay(), c->window, 0, theight(c), c->width, c->height);
if (c->has_titlebar) XMoveResizeWindow(wm->getDisplay(), c->parent, c->x, c->y - theight(c), c->width+c->right_sidebar_width, c->height + theight(c));
XMoveResizeWindow(wm->getDisplay(), c->title, 0, 0, c->width+c->right_sidebar_width, theight(c));
XMoveResizeWindow(wm->getDisplay(), c->right_sidebar, c->width, theight(c), c->right_sidebar_width, c->height - 10);
XMoveResizeWindow(wm->getDisplay(), c->resize_win, c->width, c->height + 10, right_sidebar_width, 10);
XMoveWindow(wm->getDisplay(), c->maximize.window, c->width - 10, c->maximize.y);
XMoveWindow(wm->getDisplay(), c->minimize.window, c->width - 27, c->minimize.y);
XMoveWindow(wm->getDisplay(), c->shadeButton.window, c->width - 44, c->shadeButton.y);
}
wc.x = c->x;
wc.y = c->y - theight(c);
wc.width = c->width + c->right_sidebar_width;
wc.height = c->height + theight(c);
wc.border_width = DEFAULT_BORDER_SIZE;
wc.sibling = e->above;
wc.stack_mode = e->detail;
XConfigureWindow(wm->getDisplay(), c->parent, e->value_mask, &wc);
// If a window has been shaded and we get a configure request
// we need to fix the shade button so it shows the correct state.
// Otherwise the client will be mapped but show that its been
// shaded. If you try and move it, it will draw a shaded outline.
if(c->shaded) shade(c);
send_config(c);
}
if(c && c->has_titlebar)
{
wc.x = 0;
wc.y = theight(c);
} else {
wc.x = e->x;
wc.y = e->y;
}
wc.width = e->width;
wc.height = e->height;
wc.sibling = e->above;
wc.stack_mode = e->detail;
XConfigureWindow(wm->getDisplay(), e->window, e->value_mask, &wc);
}
void Client::handle_map_request(XMapRequestEvent *e)
{
Client *c = find_client(e->window);
if (c) mapClient(c);
else make_new_client(e->window);
}
void Client::handle_unmap_event(XUnmapEvent *e)
{
Client *c = find_client(e->window);
if (c) {
if (c->ignore_unmap) c->ignore_unmap--;
else
{
if (get_wm_state(c) == IconicState)
XMapWindow(wm->getDisplay(), c->window);
else
{
set_wm_state(c, WithdrawnState);
remove_client(c);
}
}
}
}
void Client::handle_client_message(XClientMessageEvent *e)
{
Client *c = find_client(e->window);
if (c)
{
if(e->message_type == wm->getWMChangeStateAtom())
if(e->format == 32 && e->data.l[0] == IconicState) hide(c);
}
}
void Client::handle_colormap_change(XColormapEvent *e)
{
Client *c = find_client(e->window);
if (c && e->c_new)
{
c->cmap = e->colormap;
installColorMap(c->cmap);
}
}
void Client::handle_property_change(XPropertyEvent *e)
{
Client *c = find_client(e->window);
long dummy;
if (c)
{
switch (e->atom)
{
case XA_WM_NAME:
{
if (c->name) XFree(c->name);
XFetchName(wm->getDisplay(), c->window, &c->name);
XClearWindow(wm->getDisplay(), c->title);
redraw(c);
}
break;
case XA_WM_NORMAL_HINTS:
{
XGetWMNormalHints(wm->getDisplay(), c->window, c->size, &dummy);
}
break;
//case XA_WM_ICON_NAME:
//break;
case XA_WM_TRANSIENT_FOR:
getTransients(c);
break;
}
}
}
void Client::handle_expose_event(XExposeEvent *e)
{
Client *c = find_client(e->window);
if (c && e->count == 0) redraw(c);
}
void Client::handle_destroy_notify(XDestroyWindowEvent *e)
{
Client *c = find_client(e->window);
if(c) remove_client(c);
}
void Client::handle_shape_change(XShapeEvent *e)
{
Client *c = find_client(e->window);
if (c)
{
c->shaped=true;
set_shape(c);
}
}
void Client::installColorMap(Colormap cmap)
{
XInstallColormap(wm->getDisplay(), cmap);
}
void Client::isIconic(Client *c)
{
// Determine if this client is already in its iconic state upon creation
// if so then we won't map it, but just iconify it.
if (get_wm_state(c) == IconicState) hide(c);
else mapClient(c);
}
void Client::mapClient(Client *c)
{
if (c->has_titlebar)
{
if(c->has_shade_button) XMapWindow(wm->getDisplay(), c->shadeButton.window);
if(c->has_close_button) XMapWindow(wm->getDisplay(), c->close.window);
if(c->has_minimize_button) XMapWindow(wm->getDisplay(), c->minimize.window);
if(c->has_maximize_button) XMapWindow(wm->getDisplay(), c->maximize.window);
XMapWindow(wm->getDisplay(), c->right_sidebar);
XMapWindow(wm->getDisplay(), c->resize_win);
XMapWindow(wm->getDisplay(), c->title);
XMapWindow(wm->getDisplay(), c->window);
XMapRaised(wm->getDisplay(), c->parent);
}
else XMapWindow(wm->getDisplay(), c->window);
set_wm_state(c, NormalState);
}
void Client::themeChange(Client *c)
{
if (c->has_titlebar)
{
XFreePixmap(wm->getDisplay(), c->frame_pix);
XFreePixmap(wm->getDisplay(), c->right_pix);
XFreePixmap(wm->getDisplay(), c->button_pix);
XFreePixmap(wm->getDisplay(), c->resize_pix);
createTitleImage(c);
createRightSidebarImage(c);
createButtonImage(c);
createResizeImage(c);
redraw(c);
}
}
void Client::raise()
{
XRaiseWindow(wm->getDisplay(), parent);
redraw(this);
}
syntax highlighted by Code2HTML, v. 0.9.1