/* * accessary.cc * * Copyright (C) 1995, 1996, 1997, 1997, 1998, 1999, 2000, 2001, 2002 Kenichi Kourai * Copyright (C) 1999, 2000, 2001, 2002 Luiz Blanes * * 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 * (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 blwm; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include "main.h" #include "accessory.h" #include "util.h" #include "callback.h" #include "timer.h" Accessory::Accessory(char* filename, char* pos, char* mode) : m_filename(filename), m_pos(pos) { if (strcmp(mode, "Background") == 0) m_mode = ACC_BACK; else if (strcmp(mode, "OnTop") == 0) m_mode = ACC_ONTOP; else if (strcmp(mode, "Application") == 0) m_mode = ACC_APP; else { BlwmError("invalid accessory mode: %s", mode); m_mode = ACC_BACK; } m_pid = 0; } Accessory::~Accessory() { if (m_pid) kill(m_pid, SIGTERM); } void Accessory::CreateAccessory() { // make a child process process accessories in order to separate from blwm // heavy task to create image if ((m_pid = fork()) != 0) return; // signal initialization (all ignore) signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGSEGV, SIG_DFL); signal(SIGBUS, SIG_DFL); signal(SIGFPE, SIG_DFL); signal(SIGHUP, SIG_DFL); // error handler initialization XSetErrorHandler((XErrorHandler)NULL); XSetIOErrorHandler((XIOErrorHandler)NULL); // X initialization display = XOpenDisplay(displayName); screen = DefaultScreen(display); root = RootWindow(display, screen); // timer initialization timer = new Timer(); m_img = CreateImageFromFile(m_filename, timer); if (m_img == NULL) exit(1); XSetWindowAttributes attributes; unsigned long valueMask; int gravity; Point pt = CalcPosition(m_pos, &gravity); Dim szImg = m_img->GetSize(); if (m_mode == ACC_APP) attributes.override_redirect = False; else attributes.override_redirect = True; valueMask = CWOverrideRedirect; m_win = XCreateWindow(display, root, pt.x, pt.y, szImg.width, szImg.height, 0, CopyFromParent, InputOutput, CopyFromParent, valueMask, &attributes); if (m_mode == ACC_APP) { XSizeHints hints; hints.flags = USPosition | PWinGravity; hints.win_gravity = gravity; XSetWMNormalHints(display, m_win, &hints); char name[256]; sprintf(name, "Accessory: %s", m_filename); XStoreName(display, m_win, name); } if (m_mode != ACC_APP) { m_shapeMask = XCreatePixmap(display, m_win, szImg.width, szImg.height, 1); m_gcShape = XCreateGC(display, m_shapeMask, 0, 0); } SetBgImage(); m_img->SetDisplayCallback(new Callback(this, &Accessory::SetBgImage)); MapAccessory(); EventLoop(); XDestroyWindow(display, m_win); BlImage::Destroy(m_img); if (m_mode != ACC_APP) { XFreePixmap(display, m_shapeMask); XFreeGC(display, m_gcShape); } XCloseDisplay(display); exit(0); } void Accessory::CreateShapedWindow() { Dim szImg = m_img->GetSize(); // make the whole transparent (pixel value 0 is transparent). XSetForeground(display, m_gcShape, 0); XFillRectangle(display, m_shapeMask, m_gcShape, 0, 0, szImg.width, szImg.height); // make opaque XSetForeground(display, m_gcShape, 1); XSetBackground(display, m_gcShape, 0); if (m_img->GetMask()) XCopyPlane(display, m_img->GetMask(), m_shapeMask, m_gcShape, 0, 0, szImg.width, szImg.height, 0, 0, 1); else XFillRectangle(display, m_shapeMask, m_gcShape, 0, 0, szImg.width, szImg.height); XShapeCombineMask(display, m_win, ShapeBounding, 0, 0, m_shapeMask, ShapeSet); } Point Accessory::CalcPosition(char* pos, int* gravity) { Dim szImg = m_img->GetSize(); Dim szRoot(DisplayWidth(display, screen), DisplayHeight(display, screen)); Point pt; if (strcmp(pos, "Center") == 0) { pt.x = (szRoot.width - szImg.width) / 2; pt.y = (szRoot.height - szImg.height) / 2; *gravity = CenterGravity; } else if (strcmp(pos, "Bottom") == 0) { pt.x = (szRoot.width - szImg.width) / 2; pt.y = szRoot.height - szImg.height; *gravity = SouthGravity; } else if (strcmp(pos, "Top") == 0) { pt.x = (szRoot.width - szImg.width) / 2; pt.y = 0; *gravity = NorthGravity; } else if (strcmp(pos, "Left") == 0) { pt.x = 0; pt.y = (szRoot.height - szImg.height) / 2; *gravity = WestGravity; } else if (strcmp(pos, "Right") == 0) { pt.x = szRoot.width - szImg.width; pt.y = (szRoot.height - szImg.height) / 2; *gravity = EastGravity; } else if (strcmp(pos, "TopLeft") == 0) { pt.x = 0; pt.y = 0; *gravity = NorthWestGravity; } else if (strcmp(pos, "TopRight") == 0) { pt.x = szRoot.width - szImg.width; pt.y = 0; *gravity = NorthEastGravity; } else if (strcmp(pos, "BottomLeft") == 0) { pt.x = 0; pt.y = szRoot.height - szImg.height; *gravity = SouthWestGravity; } else if (strcmp(pos, "BottomRight") == 0) { pt.x = szRoot.width - szImg.width; pt.y = szRoot.height - szImg.height; *gravity = SouthEastGravity; } else { unsigned int width, height; int bitmask; bitmask = XParseGeometry(pos, &pt.x, &pt.y, &width, &height); if ((bitmask & (XValue|YValue)) == (XValue|YValue)) { if (bitmask & XNegative) pt.x = szRoot.width + pt.x - szImg.width; if (bitmask & YNegative) pt.y = szRoot.height + pt.y - szImg.height; if ((bitmask & (XNegative | YNegative)) == 0) *gravity = NorthWestGravity; else if ((bitmask & (XNegative | YNegative)) == XNegative) *gravity = NorthEastGravity; else if ((bitmask & (XNegative | YNegative)) == YNegative) *gravity = SouthWestGravity; else if ((bitmask & (XNegative | YNegative)) == (XNegative | YNegative)) *gravity = SouthEastGravity; } else { pt.x = 0; pt.y = 0; *gravity = CenterGravity; } } return pt; } void Accessory::SetBgImage() { XSetWindowBackgroundPixmap(display, m_win, m_img->GetPixmap()); if (m_mode != ACC_APP) CreateShapedWindow(); XClearWindow(display, m_win); } void Accessory::MapAccessory() { XMapWindow(display, m_win); if (m_mode == ACC_BACK) XLowerWindow(display, m_win); else if (m_mode == ACC_ONTOP) XRaiseWindow(display, m_win); } void Accessory::EventLoop() { XEvent ev; int fd = ConnectionNumber(display); fd_set fds; struct timeval tm, *tmp; XSynchronize(display, True); while (1) { FD_ZERO(&fds); FD_SET(fd, &fds); while (XPending(display) != 0) { XNextEvent(display, &ev); timer->CheckTimeout(&tm); } if (timer->CheckTimeout(&tm)) tmp = &tm; else tmp = NULL; XFlush(display); #if defined(__hpux) && !defined(_XPG4_EXTENDED) if (select(fd + 1, (int *)&fds, 0, 0, tmp) == 0) { // timeout #else if (select(fd + 1, &fds, 0, 0, tmp) == 0) { // timeout #endif timer->CheckTimeout(&tm); } } }