/*
* property.cc
*
* Copyright (C) 1995-2001 Kenichi Kourai
*
* 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, or (at your option)
* 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 qvwm; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include "main.h"
#include "misc.h"
#include "qvwm.h"
#include "hash.h"
#include "tbutton.h"
#include "qvwmrc.h"
#include "util.h"
#include "desktop.h"
#include "gnome.h"
#include "image.h"
#include "dialog.h"
#include "switcher.h"
#include "session.h"
#include "tooltip.h"
Hash<AppAttr>* Qvwm::appHashTable;
#if 0
static Pixmap FixIconPixmap(Pixmap origPix, unsigned int width,
unsigned int height, int size, unsigned int depth,
unsigned long fore, unsigned long back);
#endif
static QvImage* GetDefLogo(int size);
/*
* SetProperty --
* Set window property.
*/
void Qvwm::SetProperty(Atom atom)
{
switch (atom) {
case XA_WM_NAME:
name = GetNameFromHint();
toolTip->SetString(name);
CalcShortName();
DrawTitle(False);
break;
case XA_WM_ICON_NAME:
ASSERT(tButton);
tButton->ChangeName();
tButton->DrawButton();
break;
case XA_WM_HINTS:
if (!CheckFlags(LARGE_IMG)) {
QvImage::Destroy(imgLarge);
imgLarge = GetFixedIcon(32);
}
if (!CheckFlags(SMALL_IMG)) {
QvImage::Destroy(imgSmall);
imgSmall = GetFixedIcon(16);
ASSERT(tButton);
tButton->SetImage(imgSmall->Duplicate());
tButton->DrawButton();
}
break;
case XA_WM_NORMAL_HINTS:
GetWindowSizeHints();
break;
default:
if (atom == _XA_WM_PROTOCOLS)
FetchWMProtocols();
else if (atom == _XA_WM_COLORMAP_WINDOWS) {
FetchWMColormapWindows();
InstallWindowColormaps();
}
}
}
/*
* GetWindowClassHints --
*
*/
void Qvwm::GetWindowClassHints()
{
AppAttr* attrs;
int argc;
char** argv;
char* cmdName;
// Get an application name
name = GetNameFromHint();
if (XGetClassHint(display, wOrig, &classHints) == 0) {
classHints.res_name = NULL;
classHints.res_class = NULL;
}
if (XGetCommand(display, wOrig, &argv, &argc) == 0 ||
argv == NULL || argv[0] == NULL)
cmdName = NULL;
else {
// get only a basename
cmdName = strrchr(argv[0], '/');
if (cmdName)
cmdName++;
else
cmdName = argv[0];
}
/*
* Set flags and pixmaps according to resource name, resource class and
* application name.
*/
if ((attrs = appHashTable->GetHashItem(name)) ||
(attrs = appHashTable->GetHashItem(classHints.res_name)) ||
(attrs = appHashTable->GetHashItem(classHints.res_class)) ||
(attrs = appHashTable->GetHashItem(cmdName))) {
// give higher priority to window decorations specified by a
// configuration file than MWM hints (i.e. prefer unset bits)
flags = ~(~flags | ~attrs->flags) & DECOR_MASK;
flags |= attrs->flags & ~DECOR_MASK;
if (!CheckFlags(BORDER))
SetFlags(THIN_BORDER);
/*
* If LARGE_IMG is specified and large pixmap hasn't been created,
* create it.
*/
if (CheckFlags(LARGE_IMG)) {
if (attrs->large_img == NULL) {
attrs->large_img = CreateImageFromFile(attrs->large_file,
TaskSwitcher::swTimer);
if (attrs->large_img)
imgLarge = attrs->large_img->Duplicate();
else
ResetFlags(LARGE_IMG);
}
else
imgLarge = attrs->large_img->Duplicate();
}
/*
* If SMALL_IMG is specified and large pixmap hasn't been created,
* create it.
*/
if (CheckFlags(SMALL_IMG)) {
if (attrs->small_img == NULL) {
attrs->small_img = CreateImageFromFile(attrs->small_file, timer);
if (attrs->small_img)
imgSmall = attrs->small_img->Duplicate();
else
ResetFlags(SMALL_IMG);
}
else
imgSmall = attrs->small_img->Duplicate();
}
if (CheckFlags(GEOMETRY))
geom = &attrs->geom;
if (CheckFlags(ONTOP)) {
desktop.GetOnTopList().InsertTail(this);
Gnome::ChangeLayer(this, WIN_LAYER_ONTOP);
}
}
// free returned argv when XGetCommand succeeded
if (cmdName)
XFreeStringList(argv);
}
/*
* GetWindowSizeHints --
* Get window size hints.
*/
void Qvwm::GetWindowSizeHints()
{
long supplied;
if (!XGetWMNormalHints(display, wOrig, &hints, &supplied))
hints.flags = 0;
if (hints.flags & PResizeInc) {
if (hints.width_inc == 0)
hints.width_inc = 1;
if (hints.height_inc == 0)
hints.height_inc = 1;
}
else {
hints.width_inc = 1;
hints.height_inc = 1;
}
if (!(hints.flags & PBaseSize)) {
if (hints.flags & PMinSize) {
hints.base_width = hints.min_width;
hints.base_height = hints.min_height;
}
else {
hints.base_width = 0;
hints.base_height = 0;
}
}
if (!(hints.flags & PMinSize)) {
hints.min_width = hints.base_width;
hints.min_height = hints.base_height;
}
if (!(hints.flags & PMaxSize)) {
hints.max_width = MAX_WINDOW_WIDTH;
hints.max_height = MAX_WINDOW_HEIGHT;
}
if (!(hints.flags & PWinGravity)) {
hints.win_gravity = NorthWestGravity;
hints.flags |= PWinGravity;
}
}
/*
* GetGravityOffset --
* Get the offset needed in the gravity.
*/
Point& Qvwm::GetGravityOffset()
{
int gr;
if (CheckFlags(GEOMETRY) && !CheckFlags(FIXED_POS))
return geom->gravity;
if (hints.flags & PWinGravity)
gr = hints.win_gravity;
else
gr = NorthWestGravity;
if (gr < ForgetGravity || gr > StaticGravity)
return GravityOffset[NorthWestGravity];
else
return GravityOffset[gr];
}
/*
* FetchWMProtocols --
*/
void Qvwm::FetchWMProtocols()
{
Atom *protocols, *ap;
int i, n;
Atom atype;
int aformat;
unsigned long bytes_remain, nitems;
if (XGetWMProtocols(display, wOrig, &protocols, &n)) {
ap = protocols;
for (i = 0; i < n; i++) {
if (*ap == (Atom)_XA_WM_DELETE_WINDOW)
SetFlags(WM_DELETE_WINDOW);
if (*ap == (Atom)_XA_WM_TAKE_FOCUS)
SetFlags(WM_TAKE_FOCUS);
ap++;
}
if (protocols)
XFree(protocols);
}
else {
if ((XGetWindowProperty(display, wOrig, _XA_WM_PROTOCOLS, 0L, 10L, False,
_XA_WM_PROTOCOLS, &atype, &aformat, &nitems,
&bytes_remain, (unsigned char **)&protocols))
== Success) {
ap = protocols;
for (i = 0; i < (int)nitems; i++) {
if (*ap == (Atom)_XA_WM_DELETE_WINDOW)
SetFlags(WM_DELETE_WINDOW);
if (*ap == (Atom)_XA_WM_TAKE_FOCUS)
SetFlags(WM_TAKE_FOCUS);
ap++;
}
if (protocols)
XFree(protocols);
}
}
}
void Qvwm::GetTransientForHint()
{
Window tWin;
if (XGetTransientForHint(display, wOrig, &tWin)) {
if (XFindContext(display, tWin, context, (caddr_t*)&qvMain) == XCSUCCESS) {
qvMain->trList.InsertTail(this);
if (qvMain->CheckFlags(ONTOP) && !CheckFlags(ONTOP)) {
SetFlags(ONTOP);
desktop.GetOnTopList().InsertTail(this);
Gnome::ChangeLayer(this, WIN_LAYER_ONTOP);
}
}
else
qvMain = NULL;
SetFlags(TRANSIENT);
ResetFlags(CTRL_MENU | BORDER_EDGE | BUTTON1 | BUTTON2 | BUTTON3);
}
else {
qvMain = NULL; // meaning this window itself is a main window
ResetFlags(TRANSIENT);
}
}
/*
* GetFixedIcon --
* Get icon whose size becomes 16 or 32.
*/
QvImage* Qvwm::GetFixedIcon(int size)
{
QvImage* img;
// FixIconPixmap() is unstable.
#if 0
Window junkRoot;
Rect rect;
unsigned int junkBW, pixDepth;
QvImage* img;
if (wmHints == NULL || !(wmHints->flags & IconPixmapHint) ||
wmHints->icon_pixmap == None)
img = GetDefLogo(size);
else {
if (XGetGeometry(display, wmHints->icon_pixmap, &junkRoot,
&rect.x, &rect.y,
(unsigned int *)&rect.width, (unsigned int *)&rect.height,
&junkBW, &pixDepth) == 0) {
img = GetDefLogo(size);
XFree(wmHints);
return img;
}
if (rect.width == 0 || rect.height == 0) {
img = GetDefLogo(size);
XFree(wmHints);
return img;
}
pix = FixIconPixmap(wmHints->icon_pixmap, rect.width, rect.height, size,
depth, IconForeColor.pixel, IconBackColor.pixel);
if (pix == None) {
img = GetDefLogo(size);
XFree(wmHints);
return;
}
if ((wmHints->flags & IconMaskHint) && wmHints->icon_mask != None) {
mask = FixIconPixmap(wmHints->icon_mask, rect.width, rect.height, size,
1, 1, 0);
gcv.clip_mask = mask;
gc = XCreateGC(display, root, GCClipMask, &gcv);
}
else
gc = XCreateGC(display, root, 0, 0);
img = new QvImage(pix, gc, Dim(size, size));
}
#else
img = GetDefLogo(size);
#endif // 0
return img;
}
/*
* GetDefLogo --
* Get default logo pixmap.
*/
static QvImage* GetDefLogo(int size)
{
QvImage* img;
if (size == 16)
img = imgLogo->Duplicate();
else if (size == 32)
img = imgLargeLogo->Duplicate();
else
img = NULL;
return img;
}
#if 0
/*
* FixIconPixmap --
* Adjust icon pixmap size.
*/
static Pixmap FixIconPixmap(Pixmap origPix, unsigned int width,
unsigned int height, int size, unsigned int depth,
unsigned long fore, unsigned long back)
{
XImage *srcImage, *destImage;
char* data = new char[(size + 7) / 8 * size * depth];
Point pt;
unsigned long pixel;
Pixmap pix;
GC gc;
srcImage = XGetImage(display, origPix, 0, 0, width, height, AllPlanes,
XYPixmap);
destImage = XCreateImage(display, DefaultVisual(display, screen), depth,
XYPixmap, 0, data, size, size, 8, 0);
for (int x = 0; x < size; x++) {
pt.x = (int)((double)width / size * x);
for (int y = 0; y < size; y++) {
pt.y = (int)((double)height / size * y);
pixel = XGetPixel(srcImage, pt.x, pt.y);
XPutPixel(destImage, x, y, pixel ? fore : back);
}
}
pix = XCreatePixmap(display, root, size, size, depth);
gc = XCreateGC(display, pix, 0, 0);
XPutImage(display, pix, gc, destImage, 0, 0, 0, 0, size, size);
XFreeGC(display, gc);
XDestroyImage(srcImage);
XFree(destImage);
delete [] data;
return pix;
}
#endif // 0
void Qvwm::SetStateProperty(int state)
{
unsigned long data[2];
ASSERT(tButton);
data[0] = (unsigned long)state;
data[1] = (unsigned long)tButton->GetFrameWin();
XChangeProperty(display, wOrig, _XA_WM_STATE, _XA_WM_STATE, 32,
PropModeReplace, (unsigned char *)data, 2);
}
#ifdef USE_XSMP
void Qvwm::GetSMClientId()
{
Atom atype;
int aformat;
unsigned long nitems, bytes_remain;
if (smClientId) {
XFree(smClientId);
smClientId = NULL;
}
// WM_CLIENT_LEADER
// type: WINDOW
// format: 8
// -- the window ID of the client leader window
unsigned char* prop = NULL;
if (XGetWindowProperty(display, wOrig,
_XA_WM_CLIENT_LEADER, 0, 1, False,
XA_WINDOW, &atype, &aformat,
&nitems, &bytes_remain, &prop) != Success) {
return;
}
Window leader = None;
if (atype == XA_WINDOW && aformat == 32 &&
nitems == 1 && bytes_remain == 0) {
leader = ((Window *)prop)[0];
}
if (prop)
XFree(prop);
if (leader == None)
return;
// SM_CLIENT_ID
// type: STRING
// format: 8
// XPCS, ISO 8859-1
// -- the client leader window must have this prop.
XTextProperty text_prop;
if (XGetTextProperty(display, leader, &text_prop, _XA_SM_CLIENT_ID)) {
if (text_prop.encoding == XA_STRING &&
text_prop.format == 8 && text_prop.nitems != 0) {
smClientId = text_prop.value;
}
}
}
void Qvwm::GetWMRole()
{
Atom atype;
int aformat;
unsigned long nitems, bytes_remain;
// WM_WINDOW_ROLE
// type: STRING
// format: 8
// XPCS, ISO 8859-1
// -- a string that uniquely identifies that window amaong
// all windows that have the same client leader window.
unsigned char* wm_role = NULL;
if (XGetWindowProperty(display, wOrig,
_XA_WM_WINDOW_ROLE, 0, 256, False,
XA_STRING, &atype, &aformat,
&nitems, &bytes_remain, &wm_role) != Success) {
wm_role = NULL;
}
if(wmRole)
XFree(wmRole);
if (wm_role)
wmRole = wm_role;
else
wmRole = NULL;
}
#endif // USE_XSMP
syntax highlighted by Code2HTML, v. 0.9.1