/* Dockapp.cc
Copyright © 2003 David Reveman.
This file is part of Waimea.
Waimea 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, or (at your option) any later
version.
Waimea 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 Waimea; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#ifdef HAVE_CONFIG_H
# include "../config.h"
#endif // HAVE_CONFIG_H
extern "C" {
#include <X11/Xatom.h>
}
#include "Dockapp.hh"
DockappHandler::DockappHandler(WaScreen *scrn, char *_name) :
RootWindowObject(scrn, 0, DockHandlerType,
new WaStringMap(WindowIDName, _name), "frame") {
XSetWindowAttributes attrib_set;
hidden = true;
x = 0;
y = 0;
width = 0;
height = 0;
desktop_mask = (1L << 16) - 1;
inworkspace = false;
name = WA_STRDUP(_name);
int create_mask = CWOverrideRedirect | CWEventMask | CWColormap;
if (ws->screen_depth == 32) {
attrib_set.background_pixmap = None;
attrib_set.background_pixel = 0x00000000;
attrib_set.border_pixel = 0x00000000;
create_mask |= CWBackPixel | CWBorderPixel;
} else {
attrib_set.background_pixmap = ParentRelative;
}
create_mask |= CWBackPixmap;
attrib_set.background_pixmap = ParentRelative;
attrib_set.colormap = ws->colormap;
attrib_set.override_redirect = true;
attrib_set.event_mask = SubstructureRedirectMask | ButtonPressMask |
ButtonReleaseMask | EnterWindowMask | LeaveWindowMask;
id = XCreateWindow(ws->display, ws->id, 0, 0, 1, 1, 0, ws->screen_depth,
CopyFromParent, ws->visual, create_mask,
&attrib_set);
wm_strut = new WMstrut;
wm_strut->window = id;
wm_strut->left = 0;
wm_strut->right = 0;
wm_strut->top = 0;
wm_strut->bottom = 0;
ws->strut_list.push_back(wm_strut);
ws->waimea->window_table.insert(make_pair(id, this));
setStacking(ws->config.dock_stacking);
}
DockappHandler::~DockappHandler(void) {
ws->docks.remove(this);
LISTUNREF(dockapp_list);
ws->strut_list.remove(wm_strut);
delete wm_strut;
ws->waimea->window_table.erase(id);
delete [] name;
}
void DockappHandler::update(void) {
if (dockapp_list.empty()) {
unref();
return;
}
width = height = 0;
double _top_spacing, _bottom_spacing, _left_spacing, _right_spacing,
_grid_spacing;
unsigned int top_spacing, bottom_spacing, left_spacing, right_spacing,
grid_spacing;
calc_length(style->top_spacing, style->top_spacing_u,
ws->vdpi, ws->height, &_top_spacing);
calc_length(style->bottom_spacing, style->bottom_spacing_u,
ws->vdpi, ws->height, &_bottom_spacing);
calc_length(style->left_spacing, style->left_spacing_u,
ws->hdpi, ws->width, &_left_spacing);
calc_length(style->right_spacing, style->right_spacing_u,
ws->hdpi, ws->width, &_right_spacing);
calc_length(style->grid_spacing, style->grid_spacing_u,
ws->hdpi, ws->width, &_grid_spacing);
switch (style->orientation) {
case VerticalOrientationType:
calc_length(style->grid_spacing, style->grid_spacing_u,
ws->vdpi, ws->height, &_grid_spacing);
break;
case HorizontalOrientationType:
calc_length(style->grid_spacing, style->grid_spacing_u,
ws->hdpi, ws->width, &_grid_spacing);
break;
}
top_spacing = WA_ROUND_U(_top_spacing);
bottom_spacing = WA_ROUND_U(_bottom_spacing);
left_spacing = WA_ROUND_U(_left_spacing);
right_spacing = WA_ROUND_U(_right_spacing);
grid_spacing = WA_ROUND_U(_grid_spacing);
list<Dockapp *>::iterator it = dockapp_list.begin();
for (; it != dockapp_list.end(); ++it) {
switch (style->orientation) {
case VerticalOrientationType:
if ((*it)->width > width) width = (*it)->width;
break;
case HorizontalOrientationType:
if ((*it)->height > height) height = (*it)->height;
break;
}
}
switch (style->orientation) {
case VerticalOrientationType:
width += left_spacing + right_spacing;
height = top_spacing;
break;
case HorizontalOrientationType:
height += top_spacing + bottom_spacing;
width = left_spacing;
break;
}
it = dockapp_list.begin();
for (; it != dockapp_list.end(); ++it) {
int dock_x, dock_y;
switch (style->orientation) {
case VerticalOrientationType:
dock_y = height;
height += ((*it)->height + grid_spacing);
dock_x = width / 2 - (*it)->width / 2;
break;
case HorizontalOrientationType:
dock_x = width;
width += ((*it)->width + grid_spacing);
dock_y = height / 2 - (*it)->height / 2;
break;
}
(*it)->x = dock_x;
(*it)->y = dock_y;
XMoveWindow(ws->display, (*it)->id, dock_x, dock_y);
}
switch (style->orientation) {
case VerticalOrientationType:
height -= grid_spacing;
height += bottom_spacing;
break;
case HorizontalOrientationType:
width -= grid_spacing;
width += right_spacing;
break;
}
if ((! width) || (! height)) return;
double map_x, map_y;
style->calcPositionFromSize(ws->width, ws->height, width, height,
PXLenghtUnitType, PXLenghtUnitType,
ws->hdpi, ws->vdpi, &map_x, &map_y);
x = (int) map_x;
y = (int) map_y;
XMoveResizeWindow(ws->display, id, x, y, width, height);
wm_strut->left = wm_strut->right = wm_strut->top =
wm_strut->bottom = 0;
if (! inworkspace) {
if (style->orientation == HorizontalOrientationType) {
switch (style->gravity) {
case NorthWestGravity:
case NorthGravity:
case NorthEastGravity:
wm_strut->top = y + height;
break;
case SouthWestGravity:
case SouthGravity:
case SouthEastGravity:
wm_strut->bottom = ws->height - y;
break;
default:
break;
}
} else {
switch (style->gravity) {
case NorthWestGravity:
case SouthWestGravity:
case WestGravity:
wm_strut->left = x + width;
break;
case NorthEastGravity:
case SouthEastGravity:
case EastGravity:
wm_strut->right = ws->width - x;
break;
default:
break;
}
}
}
if (desktop_mask & (1L << ws->current_desktop->number)) {
mapRequest = true;
hidden = false;
pushRenderEvent();
ws->updateWorkarea();
}
}
void DockappHandler::styleUpdate(bool pos_change, bool size_change) {
if (pos_change || size_change)
update();
else
pushRenderEvent();
}
Dockapp::Dockapp(WaScreen *_ws, Window _id) :
AWindowObject(NULL, _id, DockAppType, NULL, "client") {
char *host, *wclass, *wclassname;
int status, n;
char **cl;
XTextProperty text_prop;
XSetWindowAttributes attrib_set;
XWindowAttributes attrib;
name = WA_STRDUP("");
wclass = WA_STRDUP("");
wclassname = WA_STRDUP("");
host = WA_STRDUP("");
dh = NULL;
client_id = _id;
deleted = false;
prio = 0;
prio_set = false;
status = 0;
ws = _ws;
XWMHints *wmhints = XGetWMHints(ws->display, _id);
if (wmhints) {
if ((wmhints->flags & IconWindowHint) &&
(wmhints->icon_window != None)) {
XUnmapWindow(ws->display, client_id);
icon_id = wmhints->icon_window;
id = icon_id;
} else {
icon_id = None;
id = client_id;
}
XFree(wmhints);
} else {
icon_id = None;
id = client_id;
}
attrib_set.event_mask = StructureNotifyMask |
FocusChangeMask | EnterWindowMask | LeaveWindowMask;
attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask |
ButtonMotionMask;
XChangeWindowAttributes(ws->display, id, CWEventMask | CWDontPropagate,
&attrib_set);
XSetWindowBorderWidth(ws->display, id, 0);
if (XGetWindowAttributes(ws->display, id, &attrib)) {
width = attrib.width;
height = attrib.height;
} else
width = height = 64;
status = XGetWMName(ws->display, client_id, &text_prop);
if (status) {
if (text_prop.encoding == XA_STRING)
name = wa_locale_to_utf8((char *) text_prop.value);
else {
#ifndef X_HAVE_UTF8_STRING
# define Xutf8TextPropertyToTextList XmbTextPropertyToTextList
#endif // !X_HAVE_UTF8_STRING
Xutf8TextPropertyToTextList(ws->display, &text_prop, &cl, &n);
if (cl) {
name = WA_STRDUP(cl[0]);
XFreeStringList(cl);
}
}
}
status = 0;
status = XGetWMClientMachine(ws->display, client_id, &text_prop);
if (status) {
if (text_prop.encoding == XA_STRING)
host = wa_locale_to_utf8((char *) text_prop.value);
else {
#ifndef X_HAVE_UTF8_STRING
# define Xutf8TextPropertyToTextList XmbTextPropertyToTextList
#endif // !X_HAVE_UTF8_STRING
Xutf8TextPropertyToTextList(ws->display, &text_prop, &cl, &n);
if (cl) {
host = WA_STRDUP(cl[0]);
XFreeStringList(cl);
}
}
}
XClassHint *classhint = XAllocClassHint();
status = 0;
status = XGetClassHint(ws->display, client_id, classhint);
if (status) {
if (classhint->res_class) {
wclass = wa_locale_to_utf8((char *) classhint->res_class);
XFree(classhint->res_class);
}
if (classhint->res_name) {
wclassname = wa_locale_to_utf8((char *) classhint->res_name);
XFree(classhint->res_name);
}
}
XFree(classhint);
char window_id_str[32];
snprintf(window_id_str, 32, "0x%lx", client_id);
WaStringMap *sm = new WaStringMap();
sm->add(WindowIDName, name);
sm->add(WindowIDClassName, wclassname);
sm->add(WindowIDClass, wclass);
sm->add(WindowIDHost, host);
sm->add(WindowIDWinID, window_id_str);
resetActionList(sm);
delete [] wclassname;
delete [] wclass;
delete [] host;
ws->waimea->window_table.insert(make_pair(id, this));
}
Dockapp::~Dockapp(void) {
ws->waimea->window_table.erase(id);
if (! deleted) {
if (validate_window_mapped(id)) {
XChangeSaveSet(ws->display, id, SetModeDelete);
XSelectInput(ws->display, id, NoEventMask);
if (icon_id) XUnmapWindow(ws->display, id);
XReparentWindow(ws->display, id, ws->id, 0, 0);
XMapWindow(ws->display, client_id);
}
}
if (name) delete [] name;
}
syntax highlighted by Code2HTML, v. 0.9.1