// bbmail.cpp for bbmail - an tool for display the mail in X11. // // Copyright (c) 1998-2005 by John Kennis, jkennis@chello.nl // // 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 this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // // (See the included file COPYING / GPL-2.0) // #include "bbmail.h" #include "config.h" #include extern "C" { #include #include #include #include #include } #include "EWMH.hh" #define SEPERATOR "/" Checkmail::Checkmail(ToolWindow *toolwindow): m_pBbtool(toolwindow) { timer = new bt::Timer(m_pBbtool, this) ; timer->setTimeout(m_pBbtool->getResource()->report.check_delay * 1000); timer->recurring(true); timer->start(); broken = false; last_totalmail = 0; last_newmail = 0; new_mailbox = 0; newmail = 0; spoolfile = new LocalSpoolfile[m_pBbtool->getResource()->report.number_of_spoolfiles]; number_of_checks = m_pBbtool->getResource()->report.force_check_delay; } Checkmail::~Checkmail() { delete [] spoolfile; delete timer; } void Checkmail::reconfigure() { delete [] spoolfile; spoolfile = new LocalSpoolfile[ m_pBbtool->getResource()->report.number_of_spoolfiles]; number_of_checks = m_pBbtool->getResource()->report.force_check_delay; timer->fireTimeout(); } bool Checkmail::CheckMaildir(int spoolno) { struct stat file_status, maildir_status; if (m_pBbtool->getResource()->spoolfile[spoolno].filename.empty()) { fprintf(stderr,"No qmail maildir specified\n"); return(false); } if (stat(m_pBbtool->getResource()->spoolfile[spoolno].filename.c_str(), &file_status)!=0) { fprintf(stderr,"Could not read status spool file %s\n", m_pBbtool->getResource()->spoolfile[spoolno].filename.c_str()); return(false); } // check maildir new/ if (stat(m_pBbtool->getResource()->spoolfile[spoolno].new_maildir.c_str(), &maildir_status) != 0) { fprintf(stderr,"Could not read status new maildir: %s\n", m_pBbtool->getResource()->spoolfile[spoolno].new_maildir.c_str()); return(false); } if (maildir_status.st_mtime > file_status.st_mtime) { file_status.st_mtime = maildir_status.st_mtime; } if (stat(m_pBbtool->getResource()->spoolfile[spoolno].cur_maildir.c_str(), &maildir_status) != 0) { fprintf(stderr,"Could not read status current maildir: %s\n", m_pBbtool->getResource()->spoolfile[spoolno].cur_maildir.c_str()); return(false); } if (maildir_status.st_mtime > file_status.st_mtime) { file_status.st_mtime = maildir_status.st_mtime; } if (file_status.st_mtime != spoolfile[spoolno].last_mtime) { spoolfile[spoolno].last_mtime = file_status.st_mtime; spoolfile[spoolno].newmail=0; DIR *dir; if ((dir = opendir( m_pBbtool->getResource()->spoolfile[spoolno].new_maildir.c_str()) ) == NULL) { fprintf(stderr,"Could not open maildir %s\n", m_pBbtool->getResource()->spoolfile[spoolno].new_maildir.c_str()); return false; } while (readdir (dir)) { spoolfile[spoolno].newmail++; } /* -2 for . and .. */ spoolfile[spoolno].newmail -= 2; closedir(dir); if ((dir = opendir( m_pBbtool->getResource()->spoolfile[spoolno].cur_maildir.c_str()) ) == NULL) { fprintf(stderr,"Could not open maildir %s\n", m_pBbtool->getResource()->spoolfile[spoolno].new_maildir.c_str()); return false; } spoolfile[spoolno].totalmail=spoolfile[spoolno].newmail; while (readdir (dir)) { spoolfile[spoolno].totalmail++; } /* -2 for . and .. */ spoolfile[spoolno].totalmail-=2; closedir(dir); } return(true); } bool Checkmail::CheckOther(int spoolno,bool force) { struct stat file_status; FILE *fp; int num[2]={-1,-1}; int number_of_values; if ((m_pBbtool->getResource()->spoolfile[spoolno].proc.empty())& (m_pBbtool->getResource()->spoolfile[spoolno].proc.empty())) { fprintf(stderr,"Nothing to do, no proc defined\n"); return(false); } if (!m_pBbtool->getResource()->spoolfile[spoolno].filename.empty()) { if (stat(m_pBbtool->getResource()->spoolfile[spoolno].filename.c_str(), &file_status)!=0) { fprintf(stderr,"Could not read status spool file %s\n", m_pBbtool->getResource()->spoolfile[spoolno].filename.c_str()); return(false); } } if ((file_status.st_mtime != spoolfile[spoolno].last_mtime)&& (m_pBbtool->getResource()->spoolfile[spoolno].filename.empty())|| (force && m_pBbtool->getResource()->spoolfile[spoolno].force_check)) { if (m_pBbtool->getResource()->spoolfile[spoolno].second_ignore) { number_of_values = 1; } else { number_of_values = 2; } spoolfile[spoolno].last_mtime = file_status.st_mtime; int old_newmail = spoolfile[spoolno].newmail; spoolfile[spoolno].newmail = 0; spoolfile[spoolno].totalmail = 0; if (!m_pBbtool->getResource()->spoolfile[spoolno].proc.empty()) { if ((fp = (FILE*)popen( m_pBbtool->getResource()->spoolfile[spoolno].proc.c_str(), "r")) == NULL) { fprintf(stderr,"Could not run command %s\n", m_pBbtool->getResource()->spoolfile[spoolno].proc.c_str()); return(false); } else { while (!(feof(fp))) { if (ReadPipe(fp,num,number_of_values) != 0) { if (num[0] > old_newmail) { new_mailbox = spoolno; } #ifdef DEBUG fprintf(stderr,"first int: %i, second int %i\n",num[0],num[1]); #endif spoolfile[spoolno].newmail += num[0]; spoolfile[spoolno].totalmail += num[1]; } else { if ((num[0] == -1) & (num[1] == -1)) { pclose(fp); return(false); } } } pclose(fp); } } if (!m_pBbtool->getResource()->spoolfile[spoolno].reversedProc.empty()) { if ((fp=(FILE*)popen( m_pBbtool->getResource()->spoolfile[spoolno].reversedProc.c_str(), "r")) == NULL) { fprintf(stderr,"Could not run command %s\n", m_pBbtool->getResource()->spoolfile[spoolno].reversedProc.c_str()); return(false); } else { while (!(feof(fp))) { if (ReadPipe(fp,num,number_of_values)!=0) { if (num[1]>old_newmail) new_mailbox = spoolno; spoolfile[spoolno].newmail+=num[1]; spoolfile[spoolno].totalmail+=num[0]; } } pclose(fp); } } if (!m_pBbtool->getResource()->spoolfile[spoolno].first_is_new) spoolfile[spoolno].newmail=spoolfile[spoolno].totalmail- spoolfile[spoolno].newmail; if (!m_pBbtool->getResource()->spoolfile[spoolno].second_is_total) spoolfile[spoolno].totalmail=spoolfile[spoolno].newmail+ spoolfile[spoolno].totalmail; } return(true); } void Checkmail::forceCheck() { timer->fireTimeout(); } bool Checkmail::getChar(const char *string,int *index) { bool special = false; if (string[*index] == '\\') { (*index)++; } else { if ((string[*index] == '[')|(string[*index] == ']')) special = true; } return(special); } bool Checkmail::checkStatusFlag(char *status_flag,int spoolno) { int i, x, len; bool passed; len = m_pBbtool->getResource()->spoolfile[spoolno].statusflag.length(); for (i = 0, x = 0; i < len; i++, x++) { if (getChar(m_pBbtool->getResource()->spoolfile[spoolno].statusflag.c_str(), &i)) { if ((m_pBbtool->getResource()->spoolfile[spoolno].statusflag[i]=='[')) { passed=false; while ((m_pBbtool->getResource()->spoolfile[spoolno].statusflag[i]!=']') & (igetResource()->spoolfile[spoolno].statusflag.c_str(), &i)) if (m_pBbtool->getResource()->spoolfile[spoolno].statusflag[i]== status_flag[x]) { passed=true; } } if (!passed) return false; } else { fprintf(stderr,"unexpected token in statusFlag\n"); } } else if (m_pBbtool->getResource()->spoolfile[spoolno].statusflag[i]!=status_flag[x]) return(false); } return(true); } bool Checkmail::CheckMbox(int spoolno) { int readmail = 0; int mailcount = 0; FILE *spool_id; bool read_status = true; char mailbuf[128]; struct stat file_status; struct utimbuf ut; if (m_pBbtool->getResource()->spoolfile[spoolno].filename.empty()) { fprintf(stderr,"No mbox mailfile specified\n"); return(false); } if (!(spool_id = fopen(m_pBbtool->getResource()->spoolfile[spoolno].filename.c_str(), "r"))) { fprintf(stderr,"Could not open mail spool file %s\n", m_pBbtool->getResource()->spoolfile[spoolno].filename.c_str()); return(false); } fstat(fileno(spool_id), &file_status); if(file_status.st_mtime != spoolfile[spoolno].last_mtime || file_status.st_size != spoolfile[spoolno].last_size) { spoolfile[spoolno].last_mtime = file_status.st_mtime; spoolfile[spoolno].last_size = file_status.st_size; while(fgets(mailbuf, 127, spool_id)) { if(!strncmp(mailbuf, "From ", 5)) { mailcount++; read_status=False; } else if (checkStatusFlag(mailbuf,spoolno)) { if(!read_status) { readmail++; read_status=True; } } else if (!strncmp(mailbuf,"Subject",7)) { if (!strncmp(&mailbuf[9], "DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA",49)!=0) { mailcount--; read_status=True; } } } if ((mailcount - readmail) > spoolfile[spoolno].newmail) new_mailbox = spoolno; spoolfile[spoolno].newmail = mailcount - readmail; spoolfile[spoolno].totalmail = mailcount; #ifdef DEBUG fprintf(stderr,"mailcount=%d, readmail=%d, spoolno=%d\n",mailcount, readmail,spoolno); #endif } fclose(spool_id); ut.actime = file_status.st_atime; ut.modtime = file_status.st_mtime; utime(m_pBbtool->getResource()->spoolfile[spoolno].filename.c_str(), &ut); return(true); } void Checkmail::timeout(bt::Timer *timer) { int totalmail=0; bool change_raise=False; bool force=False; int i,old_total,old_new; bool redraw=False; newmail=0; broken=False; if (m_pBbtool->getResource()->report.force_check) { if (m_pBbtool->getResource()->report.force_check_delay==number_of_checks) { force=True; number_of_checks=0; } else { number_of_checks++; #ifdef DEBUG fprintf(stderr,"number_of_checks %i\n",number_of_checks); #endif } } for (i = 0; i < (int)m_pBbtool->getResource()->report.number_of_spoolfiles; i++) { old_new=spoolfile[i].newmail; old_total=spoolfile[i].totalmail; if (m_pBbtool->getResource()->spoolfile[i].type==SpoolList::other) { if (!(CheckOther(i,force))) { broken=True; } else { newmail+=spoolfile[i].newmail; totalmail+=spoolfile[i].totalmail; if ((spoolfile[i].newmail!=old_new)|(spoolfile[i].totalmail!=old_total)) { m_pBbtool->mbMenu()->UpdateNumbers(spoolfile[i].newmail, spoolfile[i].totalmail,i); } } } else if (m_pBbtool->getResource()->spoolfile[i].type==SpoolList::mbox) { if (!(CheckMbox(i))) broken=True; else { totalmail+=spoolfile[i].totalmail; newmail+=spoolfile[i].newmail; if ((spoolfile[i].newmail != old_new) | (spoolfile[i].totalmail != old_total)) m_pBbtool->mbMenu()->UpdateNumbers(spoolfile[i].newmail, spoolfile[i].totalmail,i); } } else if (m_pBbtool->getResource()->spoolfile[i].type == SpoolList::maildir) { if (!(CheckMaildir(i))) broken=True; else { totalmail+=spoolfile[i].totalmail; newmail+=spoolfile[i].newmail; if ((spoolfile[i].newmail!=old_new)|(spoolfile[i].totalmail!=old_total)) m_pBbtool->mbMenu()->UpdateNumbers(spoolfile[i].newmail, spoolfile[i].totalmail,i); } } } if (newmail>last_newmail) change_raise = True; else { /* are there ny not empty mailboxes left */ for (i = 0; i < (int)m_pBbtool->getResource()->report.number_of_spoolfiles; i++) { if (spoolfile[i].newmail!=0) { new_mailbox=i; // change_raise = True; } } } if ((newmail!=last_newmail)|(totalmail!=last_totalmail)|(broken) ) { redraw=True; } last_newmail=newmail; last_totalmail=totalmail; if (redraw) m_pBbtool->redraw(change_raise); } int Checkmail::ReadPipe(FILE *fp,int num[2],int number_of_values) { int i=0; bool found=False; bool newline=False; int x=0; char ch[6]={0,0,0,0,0,0}; while (!(feof(fp))&(x!=number_of_values)&(ch[i]!='\n')&(!newline)) { fread(&ch[i],1,1,fp); while ((ch[i]>='0' && ch[i] <='9' && ch[1]!='\n')&(!feof(fp))) { i++; if (i==7) return(0); fread(&ch[i],1,1,fp); found=True; } if (ch[i]=='\n') newline=True; if (found) { ch[i]='\0'; num[x]=atoi(ch); i=0; x++; found=False; } } /* skip to next line */ while (!(feof(fp))&(ch[0]!='\n')&(!newline)) fread(&ch[0],1,1,fp); return(x); } ToolWindow::ToolWindow(Configuration cml_options): bt::Application(cml_options.appName(), cml_options.displayName().c_str(), false), current_screen_info(display().screenInfo(DefaultScreen(XDisplay()))), _config(cml_options) { checkmail = NULL; mbmenu = NULL; current_screen = DefaultScreen(XDisplay()); wm_delete_window = XInternAtom (XDisplay(), "WM_DELETE_WINDOW",False); /* initialize xrm database */ XrmInitialize(); resource = new Resource(this, _config.rcFilename()); frame_window = new FrameWindow(this); label_window = new LabelWindow(this); envelope_window = new EnvelopeWindow(this); if (resource->validMailbox()) { checkmail = new Checkmail(this); makeWindow(false); redraw(False); checkmail->forceCheck(); } else { throw -1; } } ToolWindow::~ToolWindow() { delete envelope_window; delete label_window; delete mbmenu; delete resource; delete checkmail; delete frame_window; } void ToolWindow::reconfigure(void) { delete resource; resource = new Resource(this, _config.rcFilename()); mbmenu->reconfigure(); checkmail->reconfigure(); makeWindow(true); // if (resource->show.label) XClearWindow(XDisplay(), label_window->window()); // XClearWindow(XDisplay(), envelope_window->window()); // XClearWindow(XDisplay(), frame_window->window()); redraw(False); } void ToolWindow::makeWindow(bool reconfigure) { frame_window->setHeight(textHeight(getCurrentScreen(), resource->frame.font) + 4 * resource->frame.bevelWidth); if (resource->show.envelope) { envelope_window->setHeight(frame_window->height() - 2 * resource->frame.bevelWidth - 2 * resource->envelope.bevelHeight); envelope_window->setWidth((envelope_window->height() * 3) / 2); if (!(fmod((double)envelope_window->width(), 2.0) > 0.0)) envelope_window->setWidth(envelope_window->width() + 1); } else envelope_window->setWidth(0); if (resource->show.label) { label_window->calcSize(); label_window->setHeight(frame_window->height() - 2 * resource->frame.bevelWidth); } frame_window->setWidth(label_window->width() + envelope_window->width() + resource->frame.bevelWidth * 3 + resource->envelope.bevelWidth * 2); if (resource->position.mask & XNegative) resource->position.x = getCurrentScreenInfo()->width() + resource->position.x - frame_window->width(); if (resource->position.mask & YNegative) resource->position.y = getCurrentScreenInfo()->height() + resource->position.y - frame_window->height(); if (!config().isWithdrawn()) { frame_window->setX(resource->position.x); frame_window->setY(resource->position.y); } if (!reconfigure) { frame_window->createWindow(); } else { frame_window->reconfigure(); } if (resource->show.label) { label_window->setX(2 * resource->frame.bevelWidth + envelope_window->width() + 2 * resource->envelope.bevelWidth); label_window->setY(resource->frame.bevelWidth); if (!reconfigure) label_window->createWindow(); else label_window->reconfigure(); } if (resource->show.envelope) { envelope_window->setX(resource->frame.bevelWidth + resource->envelope.bevelWidth); envelope_window->setY(resource->frame.bevelWidth + resource->envelope.bevelWidth); if (!reconfigure) envelope_window->createWindow(); else envelope_window->reconfigure(); } if (!reconfigure) { mbmenu = new MailboxMenu(this); XClearWindow(XDisplay(), frame_window->window()); XMapSubwindows(XDisplay(), frame_window->window()); mapped=true; if (!config().isDecorated() && !config().isWithdrawn()) { XMoveResizeWindow(XDisplay(),frame_window->window(),frame_window->x(), frame_window->y(), frame_window->width(), frame_window->height()); } } } void ToolWindow::redraw(bool change_raise) { if (checkmail->getNewmail()==0) { if (resource->show.onlyAtNewMail&mapped) { XUnmapSubwindows(XDisplay(), frame_window->window()); XUnmapWindow(XDisplay(), frame_window->window()); mapped=false; } else if (resource->show.envelope) { envelope_window->redraw(); } } else { if ((resource->show.onlyAtNewMail) & (!(mapped))) { XMapSubwindows(XDisplay(), frame_window->window()); XMapWindow(XDisplay(),frame_window->window()); mapped=true; } if (change_raise) { if (resource->spoolfile[checkmail->getNewMailbox()].bell) XBell(XDisplay(),100); if (!resource->spoolfile[checkmail->getNewMailbox()].newmailProc.empty()); system(resource->spoolfile[checkmail->getNewMailbox()].newmailProc.c_str()); if ((resource->report.auto_raise)&(!(raised))) { XRaiseWindow(XDisplay(), frame_window->window()); raised = true; } } if (resource->show.envelope) { envelope_window->redraw(); } } if (resource->show.label) { label_window->redraw(); } } FrameWindow::FrameWindow(ToolWindow *toolwindow) : bt::EventHandler() , m_pBbtool(toolwindow), fwindow(0), fx(0), fy(0), m_pixmap(0), fposition(NULL), m_screen(toolwindow->getCurrentScreen()), display(toolwindow->XDisplay()) { } FrameWindow::~FrameWindow(void) { if (m_pixmap) bt::PixmapCache::release(m_pixmap); if (fposition) delete fposition; if (fwindow) XDestroyWindow(display, fwindow); } void FrameWindow::createWindow(void) { XSetWindowAttributes attrib; XWMHints wmhints; unsigned long create_mask = CWBackPixmap | CWCursor | CWEventMask | CWOverrideRedirect; attrib.background_pixmap = ParentRelative; m_pixmap = bt::PixmapCache::find(m_screen, m_pBbtool->getResource()->frame.texture, fwidth, fheight); if (m_pBbtool->config().isWithdrawn()) { wmhints.initial_state = WithdrawnState; } else { wmhints.initial_state = NormalState; } attrib.cursor = XCreateFontCursor(display, XC_left_ptr); attrib.event_mask = ButtonPressMask | ButtonReleaseMask | ExposureMask | FocusChangeMask | KeyPressMask | StructureNotifyMask; attrib.override_redirect = False; bt::EWMH ewmh(m_pBbtool->display()); bool wm_window_type_dock = false; if (!m_pBbtool->config().isDecorated() && !m_pBbtool->config().isWithdrawn()) { bt::EWMH::AtomList supported_atoms; if (ewmh.readSupported(m_pBbtool->getCurrentScreenInfo()->rootWindow(), supported_atoms)) { bt::EWMH::AtomList::iterator it = supported_atoms.begin(); for (; it != supported_atoms.end(); ++it) { if ( (*it) == ewmh.wmWindowTypeDock()) { wm_window_type_dock = true; } } } else { attrib.override_redirect = True; } } fwindow = XCreateWindow(display, m_pBbtool->getCurrentScreenInfo()->rootWindow(), fx, fy, fwidth, fheight, 0, m_pBbtool->getCurrentScreenInfo()->depth(), InputOutput, m_pBbtool->getCurrentScreenInfo()->visual(), create_mask, &attrib); wmhints.flags = IconWindowHint | StateHint; wmhints.icon_window = fwindow; XTextProperty windowname; XClassHint classhints; char *name = PACKAGE; XSizeHints sizehints; classhints.res_name = PACKAGE; classhints.res_class = "m_pBbtools"; sizehints.x = m_pBbtool->getResource()->position.x; sizehints.y = m_pBbtool->getResource()->position.y; sizehints.max_width = sizehints.min_width = fwidth; sizehints.max_height = sizehints.min_height = fheight; sizehints.flags = USPosition | PMinSize | PMaxSize; XStringListToTextProperty(&name, 1, &windowname); XSetWMProperties(display, fwindow, &windowname, NULL, m_pBbtool->config().argv(), m_pBbtool->config().argc(), &sizehints, &wmhints, &classhints); XFree(windowname.value); Atom wmproto[2]; wmproto[0] = m_pBbtool->wmDeleteWindowAtom(); XSetWMProtocols(display, fwindow, wmproto, 1); bt::EWMH::AtomList window_type_atom; window_type_atom.push_back(ewmh.wmWindowTypeDock()); if (!m_pBbtool->config().isDecorated() && !m_pBbtool->config().isWithdrawn()) { if (wm_window_type_dock) { XChangeProperty(display, fwindow, ewmh.wmWindowType(), XA_ATOM, 32, PropModeReplace, reinterpret_cast(&(window_type_atom[0])), window_type_atom.size()); } else { //attrib.override_redirect set fprintf(stderr, "Cannot dock\n"); } } bt::EWMH::AtomList state_atom; state_atom.push_back(ewmh.wmStateSticky()); state_atom.push_back(ewmh.wmStateSkipTaskbar()); state_atom.push_back(ewmh.wmStateSkipPager()); ewmh.setWMState(fwindow, state_atom); //XSetWindowBackgroundPixmap(display, fwindow, m_pixmap); redraw(); m_pBbtool->insertEventHandler(fwindow, this); } void FrameWindow::redraw(void) { bt::Rect u(0, 0, fwidth, fheight); bt::drawTexture(m_screen, m_pBbtool->getResource()->frame.texture, fwindow, u, u, m_pixmap); } void FrameWindow::reconfigure(void) { bt::PixmapCache::release(m_pixmap); m_pixmap = bt::PixmapCache::find(m_screen, m_pBbtool->getResource()->frame.texture, fwidth, fheight); if (!m_pBbtool->config().isWithdrawn()) { XMoveResizeWindow(display, fwindow, fx, fy, fwidth, fheight); } else { XResizeWindow(display, fwindow, fwidth, fheight); } redraw(); } void FrameWindow::clientMessageEvent(const XClientMessageEvent *xclient_event) { if ((unsigned)xclient_event->data.l[0] == m_pBbtool->wmDeleteWindowAtom()) m_pBbtool->shutdown(); } void FrameWindow::exposeEvent(const XExposeEvent *) { redraw(); } void FrameWindow::buttonPressEvent(const XButtonEvent *xbutton_event) { if (xbutton_event->button == LEFT_BUTTON) { if (!m_pBbtool->isRaised()) { XRaiseWindow(display, fwindow); m_pBbtool->setRaised(true); } } else if (xbutton_event->button == MIDDLE_BUTTON) { if (m_pBbtool->isRaised()) { XLowerWindow(display, fwindow); m_pBbtool->setRaised(false); } } } LabelWindow::LabelWindow(ToolWindow *toolwindow) : bt::EventHandler() , m_pBbtool(toolwindow), m_pDisplay(toolwindow->XDisplay()), m_window(0), m_pixmap(0), m_x(0), m_y(0), m_widthNewMail(0), m_widthTotalMail(0), m_widthSeperator(0), m_screen(toolwindow->getCurrentScreen()) { } LabelWindow::~LabelWindow(void) { if (m_pixmap) bt::PixmapCache::release(m_pixmap); if (m_window) XDestroyWindow(m_pDisplay, m_window); delete m_pPen; } void LabelWindow::createWindow(void) { XSetWindowAttributes attrib; unsigned long create_mask = CWBackPixmap | CWEventMask; int i; m_maxValue = 1; for (i = 0; i < m_pBbtool->getResource()->report.number_of_digits; i++) m_maxValue *= 10; m_maxValue -= 1; attrib.background_pixmap = ParentRelative; attrib.cursor = XCreateFontCursor(m_pDisplay, XC_left_ptr); attrib.event_mask = ButtonPressMask | ButtonReleaseMask | ExposureMask | FocusChangeMask | KeyPressMask | StructureNotifyMask; if (!m_pBbtool->getResource()->label.transparent) m_pixmap = bt::PixmapCache::find(m_screen, m_pBbtool->getResource()->label.texture, m_width, m_height); m_window = XCreateWindow(m_pDisplay, m_pBbtool->frameWindow()->window(), m_x, m_y, m_width, m_height, 0, m_pBbtool->getCurrentScreenInfo()->depth(), InputOutput, m_pBbtool->getCurrentScreenInfo()->visual(), create_mask, &attrib); m_pPen = new bt::Pen(m_screen, m_pBbtool->getResource()->label.newmail_textColor); // lpen->setFont(m_pBbtool->getResource()->label.font); redraw(); m_pBbtool->insertEventHandler(m_window, this); XClearWindow(m_pDisplay, m_pBbtool->frameWindow()->window()); XMapWindow(m_pDisplay, m_pBbtool->frameWindow()->window()); XMapSubwindows(m_pDisplay, m_pBbtool->frameWindow()->window()); } void LabelWindow::reconfigure(void) { if (!m_pBbtool->getResource()->label.transparent) { bt::PixmapCache::release(m_pixmap); m_pixmap = bt::PixmapCache::find(m_screen, m_pBbtool->getResource()->label.texture, m_width, m_height); } XMoveResizeWindow(m_pDisplay, m_window, m_x, m_y, m_width, m_height); delete m_pPen; m_pPen = new bt::Pen(m_screen, m_pBbtool->getResource()->label.newmail_textColor); redraw(); } void LabelWindow::calcSize() { bt::ustring str; char *t; t = new char [m_pBbtool->getResource()->report.number_of_digits + m_pBbtool->getResource()->report.number_of_digits + 1 + 1]; if (m_pBbtool->getResource()->show.newmail_counter && m_pBbtool->getResource()->show.newmail_counter) { sprintf(t, "%0*d/%0*d", m_pBbtool->getResource()->report.number_of_digits, 0, m_pBbtool->getResource()->report.number_of_digits, 0); str = bt::toUnicode(t); unsigned int text_width = bt::textRect(m_pBbtool->getCurrentScreen(), m_pBbtool->getResource()->label.font, str).width(); m_width = text_width + 3 * m_pBbtool->getResource()->frame.bevelWidth; sprintf(t, "%0*d", m_pBbtool->getResource()->report.number_of_digits, 0); str = bt::toUnicode(t); m_widthNewMail = bt::textRect(m_pBbtool->getCurrentScreen(), m_pBbtool->getResource()->label.font, str).width(); sprintf(t, "%0*d", m_pBbtool->getResource()->report.number_of_digits, 0); str = bt::toUnicode(t); m_widthTotalMail = bt::textRect(m_pBbtool->getCurrentScreen(), m_pBbtool->getResource()->label.font, str).width(); m_widthSeperator = text_width - m_widthNewMail - m_widthTotalMail; } else if (m_pBbtool->getResource()->show.newmail_counter) // split these up now, so we can use different number_of_digits later { sprintf(t, "%0*d", m_pBbtool->getResource()->report.number_of_digits, 0); str = bt::toUnicode(t); m_width = bt::textRect(m_pBbtool->getCurrentScreen(), m_pBbtool->getResource()->label.font, str).width() + 2 * m_pBbtool->getResource()->frame.bevelWidth; } else if (m_pBbtool->getResource()->show.totalmail_counter) { sprintf(t, "%0*d", m_pBbtool->getResource()->report.number_of_digits, 0); str = bt::toUnicode(t); m_width = bt::textRect(m_pBbtool->getCurrentScreen(), m_pBbtool->getResource()->label.font, str).width() + 2 * m_pBbtool->getResource()->frame.bevelWidth; } delete [] t; } void LabelWindow::redraw(void) { // redraw windows if (m_pixmap == ParentRelative || m_pBbtool->getResource()->label.transparent) // we can remove the transparent option in the future { bt::Rect u(0, 0, width(), height()); bt::Rect t(-x(), -y(), m_pBbtool->frameWindow()->width(), m_pBbtool->frameWindow()->height()); bt::drawTexture(m_screen, m_pBbtool->getResource()->frame.texture, m_window, t, u, m_pBbtool->frameWindow()->pixmap()); } else { bt::Rect u(0, 0, width(), height()); bt::drawTexture(m_screen, m_pBbtool->getResource()->label.texture, m_window, u, u, m_pixmap); } // redraw text char t[6]; bt::ustring txt; // if (m_pBbtool->getResource()->show.label) // XClearWindow(m_pDisplay, m_window); if (m_pBbtool->getResource()->show.newmail_counter) { if (m_pBbtool->checkMail()->getNewmail() == 0) XSetForeground(m_pDisplay, m_pPen->gc(), m_pBbtool->getResource()->label.newmail_boring_textColor.pixel(m_screen)); else XSetForeground(m_pDisplay, m_pPen->gc(), m_pBbtool->getResource()->label.newmail_textColor.pixel(m_screen)); if (m_pBbtool->checkMail()->getNewmail() < m_maxValue) { sprintf(t, "%0*d",m_pBbtool->getResource()->report.number_of_digits, m_pBbtool->checkMail()->getNewmail()); txt = bt::toUnicode(t); bt::Rect text_rect = bt::textRect(m_screen, m_pBbtool->getResource()->label.font, txt); text_rect.setX(m_pBbtool->getResource()->frame.bevelWidth); text_rect.setY(text_rect.y() + m_pBbtool->getResource()->frame.bevelWidth); text_rect.setWidth(m_widthNewMail); drawText(m_pBbtool->getResource()->label.font, *m_pPen, m_window, text_rect, bt::AlignCenter, txt); } else { sprintf(t, ">"); txt = bt::toUnicode(t); bt::Rect text_rect = bt::textRect(m_screen, m_pBbtool->getResource()->label.font, txt); text_rect.setX(m_pBbtool->getResource()->frame.bevelWidth); text_rect.setY(text_rect.y() + m_pBbtool->getResource()->frame.bevelWidth); text_rect.setWidth(m_widthNewMail); drawText(m_pBbtool->getResource()->label.font, *m_pPen, m_window, text_rect, bt::AlignCenter, txt); } } if (m_pBbtool->getResource()->show.totalmail_counter) { if (m_pBbtool->getResource()->show.newmail_counter) { if ((m_pBbtool->checkMail()->getLastTotalmail() == 0) | (m_pBbtool->checkMail()->getNewmail() == 0)) XSetForeground(m_pDisplay, m_pPen->gc(), m_pBbtool->getResource()->label.seperator_boring_textColor.pixel(m_screen)); else XSetForeground(m_pDisplay, m_pPen->gc(), m_pBbtool->getResource()->label.seperator_textColor.pixel(m_screen)); sprintf(t, SEPERATOR); txt = bt::toUnicode(t); bt::Rect text_rect = bt::textRect(m_screen, m_pBbtool->getResource()->label.font, txt); text_rect.setX(m_widthNewMail + m_pBbtool->getResource()->frame.bevelWidth); text_rect.setY(text_rect.y() + m_pBbtool->getResource()->frame.bevelWidth); text_rect.setWidth(m_widthSeperator); drawText(m_pBbtool->getResource()->label.font, *m_pPen, m_window, text_rect, bt::AlignCenter, txt); } if (m_pBbtool->checkMail()->getLastTotalmail() > m_maxValue) { sprintf(t, ">"); txt = bt::toUnicode(t); bt::Rect text_rect = bt::textRect(m_screen, m_pBbtool->getResource()->label.font, txt); text_rect.setX(m_widthNewMail + m_widthSeperator + m_pBbtool->getResource()->frame.bevelWidth); text_rect.setY(text_rect.y() + m_pBbtool->getResource()->frame.bevelWidth); text_rect.setWidth(m_widthTotalMail); drawText(m_pBbtool->getResource()->label.font, *m_pPen, m_window, text_rect, bt::AlignCenter, txt); } else { if (m_pBbtool->checkMail()->getLastTotalmail() == 0) { XSetForeground(m_pDisplay, m_pPen->gc(), m_pBbtool->getResource()->label.totalmail_boring_textColor.pixel(m_screen)); } else { XSetForeground(m_pDisplay, m_pPen->gc(), m_pBbtool->getResource()->label.totalmail_textColor.pixel(m_screen)); } sprintf(t, "%0*d", m_pBbtool->getResource()->report.number_of_digits, m_pBbtool->checkMail()->getLastTotalmail()); txt = bt::toUnicode(t); bt::Rect text_rect = bt::textRect(m_screen, m_pBbtool->getResource()->label.font, txt); text_rect.setX( m_widthNewMail + m_widthSeperator + m_pBbtool->getResource()->frame.bevelWidth); text_rect.setY(text_rect.y() + m_pBbtool->getResource()->frame.bevelWidth); text_rect.setWidth(m_widthTotalMail); drawText(m_pBbtool->getResource()->label.font, *m_pPen, m_window, text_rect, bt::AlignCenter, txt); } } } void LabelWindow::buttonPressEvent(const XButtonEvent *xbutton_event) { if (xbutton_event->button == LEFT_BUTTON) { if (!m_pBbtool->isRaised()) { XRaiseWindow(m_pDisplay, m_pBbtool->frameWindow()->window()); m_pBbtool->setRaised(true); } } else if (xbutton_event->button == MIDDLE_BUTTON) { if (m_pBbtool->isRaised()) { XLowerWindow(m_pDisplay, m_pBbtool->frameWindow()->window()); m_pBbtool->setRaised(false); } } } void LabelWindow::exposeEvent(const XExposeEvent *) { redraw(); } EnvelopeWindow::EnvelopeWindow(ToolWindow *toolwindow) : bt::EventHandler() , display(toolwindow->XDisplay()), m_pBbtool(toolwindow), m_screen(toolwindow->getCurrentScreen()), m_window(0), ex(0), ey(0), pixmap(0), pixmap_pressed(0), envelope_pushed(false) { } EnvelopeWindow::~EnvelopeWindow(void) { if (pixmap) bt::PixmapCache::release(pixmap); if (pixmap_pressed) bt::PixmapCache::release(pixmap_pressed); int i; for (i = 0; i < num_of_pixmaps; i++) { bt::PixmapCache::release(pixmap_new[i]); bt::PixmapCache::release(pixmap_new_pressed[i]); } delete [] pixmap_new; delete [] pixmap_new_pressed; delete epen; if (m_window) XDestroyWindow(display, m_window); } void EnvelopeWindow::createWindow(void) { XSetWindowAttributes attrib; unsigned long create_mask = CWBackPixmap | CWCursor | CWEventMask; attrib.background_pixmap = ParentRelative; attrib.cursor = XCreateFontCursor(display, XC_left_ptr); attrib.event_mask = ButtonPressMask | ButtonReleaseMask | ExposureMask | FocusChangeMask | KeyPressMask | StructureNotifyMask; pixmap = bt::PixmapCache::find(m_screen, m_pBbtool->getResource()->envelope.texture, ewidth, eheight); pixmap_pressed = bt::PixmapCache::find(m_screen, m_pBbtool->getResource()->envelope.texture_pressed, ewidth, eheight); num_of_pixmaps = m_pBbtool->getResource()->report.number_of_spoolfiles; pixmap_new = new Pixmap [num_of_pixmaps]; pixmap_new_pressed = new Pixmap [num_of_pixmaps]; int i; for (i = 0; i < num_of_pixmaps; i++) { pixmap_new[i] = bt::PixmapCache::find(m_screen, m_pBbtool->getResource()->spoolfile[i].newmail_texture, ewidth, eheight); pixmap_new_pressed[i] = bt::PixmapCache::find(m_screen, m_pBbtool->getResource()->spoolfile[i].newmail_pressed_texture, ewidth, eheight); } m_window = XCreateWindow(display, m_pBbtool->frameWindow()->window(), ex, ey, ewidth, eheight, 0, m_pBbtool->getCurrentScreenInfo()->depth(), InputOutput, m_pBbtool->getCurrentScreenInfo()->visual(), create_mask, &attrib); epen = new bt::Pen(m_screen, m_pBbtool->getResource()->envelope.textColor); //epen->setFont(m_pBbtool->getResource()->frame.font); calcPoints(); m_pBbtool->insertEventHandler(m_window, this); } void EnvelopeWindow::reconfigure(void) { bt::PixmapCache::release(pixmap); bt::PixmapCache::release(pixmap_pressed); int i; for (i = 0; i < num_of_pixmaps; i++) { bt::PixmapCache::release(pixmap_new[i]); bt::PixmapCache::release(pixmap_new_pressed[i]); } delete [] pixmap_new; delete [] pixmap_new_pressed; pixmap = bt::PixmapCache::find(m_screen, m_pBbtool->getResource()->envelope.texture, ewidth, eheight); pixmap_pressed = bt::PixmapCache::find(m_screen, m_pBbtool->getResource()->envelope.texture_pressed, ewidth, eheight); num_of_pixmaps = m_pBbtool->getResource()->report.number_of_spoolfiles; pixmap_new = new Pixmap [num_of_pixmaps]; pixmap_new_pressed = new Pixmap [num_of_pixmaps]; for (i = 0; i < num_of_pixmaps; i++) { pixmap_new[i] = bt::PixmapCache::find(m_screen, m_pBbtool->getResource()->spoolfile[i].newmail_texture, ewidth, eheight); pixmap_new_pressed[i] = bt::PixmapCache::find(m_screen, m_pBbtool->getResource()->spoolfile[i].newmail_pressed_texture, ewidth, eheight); } delete epen; epen = new bt::Pen(m_screen, m_pBbtool->getResource()->envelope.textColor); calcPoints(); XMoveResizeWindow(display, m_window, ex, ey, ewidth, eheight); redraw(); } void EnvelopeWindow::release(void) { if (envelope_pushed) { envelope_pushed = false; m_pBbtool->redraw(false); } } void EnvelopeWindow::buttonPressEvent(const XButtonEvent *xbutton_event) { if (xbutton_event->button == LEFT_BUTTON) { if (!m_pBbtool->isRaised()) { XRaiseWindow(display, m_pBbtool->frameWindow()->window()); m_pBbtool->setRaised(true); } envelope_pushed = true; m_pBbtool->redraw(false); } else if (xbutton_event->button == MIDDLE_BUTTON) { if (m_pBbtool->isRaised()) { XLowerWindow(display, m_pBbtool->frameWindow()->window()); m_pBbtool->setRaised(false); } } else if (xbutton_event->button == RIGHT_BUTTON) { if (!envelope_pushed) { envelope_pushed = true; m_pBbtool->redraw(false); if (!m_pBbtool->mbMenu()->isVisible()) { m_pBbtool->mbMenu()->popup(m_pBbtool->frameWindow()->x(), m_pBbtool->frameWindow()->y(), m_pBbtool->config().isWithdrawn()); } } } } void EnvelopeWindow::buttonReleaseEvent(const XButtonEvent *xbutton_event) { if (xbutton_event->button == LEFT_BUTTON) { envelope_pushed = false; m_pBbtool->redraw(false); if (xbutton_event->x > 0 && xbutton_event->x < (int)ewidth && xbutton_event->y > 0 && xbutton_event->y < (int)eheight ) { if (m_pBbtool->checkMail()->getNewmail() != 0) { if (!m_pBbtool->getResource()->spoolfile[m_pBbtool->checkMail()->getNewMailbox()].runCommand.empty()) { system(m_pBbtool->getResource()->spoolfile[m_pBbtool->checkMail()->getNewMailbox()].runCommand.c_str()); } else { if (!m_pBbtool->getResource()->report.runCommand.empty()) { system(m_pBbtool->getResource()->report.runCommand.c_str()); } } } else { if (!m_pBbtool->getResource()->report.runCommand.empty()) { system(m_pBbtool->getResource()->report.runCommand.c_str()); } } } } } void EnvelopeWindow::exposeEvent(const XExposeEvent *) { redraw(); } void EnvelopeWindow::calcPoints(void) { points[0].x = 2; points[0].y = 2; points[1].x = ewidth / 2; points[1].y = (eheight * 2) / 3; points[2].x = ewidth - 3; points[2].y = 2; points[3].x = 2; points[3].y = eheight - 3; points[4].x = ewidth / 3; points[4].y = eheight / 2 - 1; points[5].x = ewidth - 3; points[5].y = eheight - 3; points[6].x = (ewidth * 2) / 3; points[6].y = eheight / 2; points[7].x = ewidth / 3; points[7].y = 2; points[8].x = (ewidth * 2) / 3 - 1; points[8].y = eheight / 2; points[9].x = (ewidth * 2) / 3 - 1; points[9].y = 2; points[10].x = ewidth / 3; points[10].y = eheight / 2; } void EnvelopeWindow::redraw(void) { if (m_pBbtool->checkMail()->getNewmail() == 0) { if (envelope_pushed) { // XSetWindowBackgroundPixmap(display, m_window, pixmap_pressed); if (pixmap_pressed == ParentRelative) { bt::Rect u(0, 0, width(), height()); bt::Rect t(-x(), -y(), m_pBbtool->frameWindow()->width(), m_pBbtool->frameWindow()->height()); bt::drawTexture(m_screen, m_pBbtool->getResource()->frame.texture, m_window, t, u, m_pBbtool->frameWindow()->pixmap()); } else { bt::Rect u(0, 0, width(), height()); bt::drawTexture(m_screen, m_pBbtool->getResource()->envelope.texture_pressed, m_window, u, u, pixmap_pressed); } } else { // XSetWindowBackgroundPixmap(display, m_window, pixmap); if (pixmap == ParentRelative) { bt::Rect u(0, 0, width(), height()); bt::Rect t(-x(), -y(), m_pBbtool->frameWindow()->width(), m_pBbtool->frameWindow()->height()); bt::drawTexture(m_screen, m_pBbtool->getResource()->frame.texture, m_window, t, u, m_pBbtool->frameWindow()->pixmap()); } else { bt::Rect u(0, 0, width(), height()); bt::drawTexture(m_screen, m_pBbtool->getResource()->envelope.texture, m_window, u, u, pixmap); } } XSetForeground(display, epen->gc(), m_pBbtool->getResource()->envelope.textColor.pixel(m_screen)); XClearWindow(display, m_window); XDrawLines(display, m_window, epen->gc(), points, 3, CoordModeOrigin); XDrawLine(display, m_window, epen->gc(), points[3].x, points[3].y, points[4].x, points[4].y); XDrawLine(display, m_window, epen->gc(), points[5].x, points[5].y, points[6].x, points[6].y); if (m_pBbtool->checkMail()->getBroken()) { XSetForeground(display, epen->gc(), m_pBbtool->getResource()->envelope.error_textColor.pixel(m_screen)); XSetLineAttributes(display, epen->gc() , 2, LineSolid, CapButt, JoinMiter); XDrawLine(display, m_window, epen->gc(), points[7].x, points[7].y, points[8].x, points[8].y); XDrawLine(display, m_window, epen->gc(), points[9].x, points[9].y, points[10].x, points[10].y); XSetLineAttributes(display, epen->gc(), 0, LineSolid,CapButt,JoinMiter); } } else { if (envelope_pushed) { if (pixmap_pressed == ParentRelative) { bt::Rect u(0, 0, width(), height()); bt::Rect t(-x(), -y(), m_pBbtool->frameWindow()->width(), m_pBbtool->frameWindow()->height()); bt::drawTexture(m_screen, m_pBbtool->getResource()->frame.texture, m_window, t, u, m_pBbtool->frameWindow()->pixmap()); } else { bt::Rect u(0, 0, width(), height()); bt::drawTexture(m_screen, m_pBbtool->getResource()->spoolfile[m_pBbtool->checkMail()->getNewMailbox()].newmail_pressed_texture, m_window, u, u, pixmap_new_pressed[m_pBbtool->checkMail()->getNewMailbox()]); } // XSetWindowBackgroundPixmap(display, m_window, // pixmap_new_pressed[m_pBbtool->checkMail()->getNewMailbox()]); } else { if (pixmap_pressed == ParentRelative) { bt::Rect u(0, 0, width(), height()); bt::Rect t(-x(), -y(), m_pBbtool->frameWindow()->width(), m_pBbtool->frameWindow()->height()); bt::drawTexture(m_screen, m_pBbtool->getResource()->frame.texture, m_window, t, u, m_pBbtool->frameWindow()->pixmap()); } else { bt::Rect u(0, 0, width(), height()); bt::drawTexture(m_screen, m_pBbtool->getResource()->spoolfile[m_pBbtool->checkMail()->getNewMailbox()].newmail_texture, m_window, u, u, pixmap_new[m_pBbtool->checkMail()->getNewMailbox()]); } // XSetWindowBackgroundPixmap(display, m_window, // pixmap_new[m_pBbtool->checkMail()->getNewMailbox()]); } XSetForeground(display, epen->gc(), m_pBbtool->getResource()->spoolfile[m_pBbtool->checkMail()->getNewMailbox()]. newmail_textColor.pixel(m_screen)); XClearWindow(display, m_window); XDrawLines(display, m_window, epen->gc(), points, 3, CoordModeOrigin); XDrawLine(display, m_window, epen->gc(), points[3].x, points[3].y, points[4].x, points[4].y); XDrawLine(display, m_window, epen->gc(), points[5].x, points[5].y, points[6].x, points[6].y); if (m_pBbtool->checkMail()->getBroken()) { XSetForeground(display, epen->gc(), m_pBbtool->getResource()->spoolfile[m_pBbtool->checkMail()->getNewMailbox()]. newmail_error_textColor.pixel(m_screen)); XSetLineAttributes(display, epen->gc(), 2, LineSolid,CapButt,JoinMiter); XDrawLine(display, m_window, epen->gc(), points[7].x, points[7].y, points[8].x, points[8].y); XDrawLine(display, m_window, epen->gc(), points[9].x, points[9].y, points[10].x, points[10].y); XSetLineAttributes(display, epen->gc(), 0, LineSolid, CapButt, JoinMiter); } } } void FrameWindow::configureNotifyEvent(const XConfigureEvent *xconfigure_event) { if (xconfigure_event->send_event) { if (m_pBbtool->config().isWithdrawn()) { m_pBbtool->reconfigure(); } int parent_x,parent_y; Window parent_root; unsigned int parent_width; unsigned int parent_height; unsigned int parent_border_width; unsigned int parent_depth; if (m_pBbtool->config().isWithdrawn()) { XGetGeometry(display, xconfigure_event->above, &parent_root, &parent_x, &parent_y, &parent_width, &parent_height, &parent_border_width, &parent_depth); fx = xconfigure_event->x + parent_x; fy = xconfigure_event->y + parent_y; } else { fx = xconfigure_event->x; fy = xconfigure_event->y; if (m_pBbtool->config().isDecorated()) { char position[13]; sprintf(position,"+%i+%i", fx, fy); m_pBbtool->config().setGeometry(position); } } if (m_pBbtool->mbMenu()->isVisible()) m_pBbtool->mbMenu()->show(); } }