diff --git a/LFSTray/LFSTray/src/callbacks.cpp b/LFSTray/LFSTray/src/callbacks.cpp new file mode 100644 index 00000000..fbb6de1c --- /dev/null +++ b/LFSTray/LFSTray/src/callbacks.cpp @@ -0,0 +1,91 @@ +/* + * + * ©K. D. Hedger. Tue 21 Jan 13:07:30 GMT 2025 keithdhedger@gmail.com + + * This file (callbacks.cpp) is part of LFSTray. + + * LFSTray 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 3 of the License, or + * (at your option) any later version. + + * LFSTray 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 LFSTray. If not, see . +*/ + +#include "globals.h" + +bool eventCB(LFSTK_applicationClass *p,XEvent *event) +{ + switch(event->type) + { + case ClientMessage: + //fprintf(stderr,">>>>>ClientMessage>>>\n"); + { + Window win; + unsigned long opcode=event->xclient.data.l[1]; + switch (opcode) + { + case SYSTEM_TRAY_REQUEST_DOCK: + { + win=event->xclient.data.l[2]; + fprintf(stderr,"SYSTEM_TRAY_REQUEST_DOCK\n"); + if(win) + { + fprintf(stderr,"request win=%p\n",win); + } + trayClass->firstrun=100; + bool retval=trayClass->embedClass->addIcon(win); + trayClass->embedClass->embedWindow(win); + trayClass->resetWindow(); + trayClass->firstrun=0; + } + break; + + case SYSTEM_TRAY_BEGIN_MESSAGE: + case SYSTEM_TRAY_CANCEL_MESSAGE: + fprintf(stderr,"N_MESSAGE\n"); + // we don't show baloons messages. + break; + + default: + //fprintf(stderr,"got wid=%p\n",event->xany.window); + if(opcode==trayClass->_NET_SYSTEM_TRAY_MESSAGE_DATA) + fprintf(stderr,"lfstray: message from dockapp: %s\n",event->xclient.data.b); + else + fprintf(stderr, "lfstray: SYSTEM_TRAY : unknown message type" "\n"); + break; + } + } + break; + case DestroyNotify: + if(trayClass->iconList.count(event->xdestroywindow.window)>0) + { + trayClass->firstrun=100; + trayClass->embedClass->removeIcon(event->xdestroywindow.window); + trayClass->resetWindow(); + trayClass->embedClass->refreshIcons(); + XDestroyWindow(trayClass->apc->display,trayClass->embedClass->currentIcon.parentWindow); + XFreePixmap(trayClass->apc->display,trayClass->embedClass->currentIcon.background); + trayClass->firstrun=0; + } + break; + + case ConfigureNotify: + if(trayClass->firstrun<5) + { + trayClass->embedClass->refreshIcons(); + trayClass->firstrun++; + } + break; + default: + break; + } + return(false); + +} \ No newline at end of file diff --git a/LFSTray/LFSTray/src/callbacks.h b/LFSTray/LFSTray/src/callbacks.h new file mode 100644 index 00000000..72bfbe01 --- /dev/null +++ b/LFSTray/LFSTray/src/callbacks.h @@ -0,0 +1,28 @@ +/* + * + * ©K. D. Hedger. Tue 21 Jan 13:07:42 GMT 2025 keithdhedger@gmail.com + + * This file (callbacks.h) is part of LFSTray. + + * LFSTray 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 3 of the License, or + * (at your option) any later version. + + * LFSTray 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 LFSTray. If not, see . +*/ + +#ifndef _CALLBACKS_ +#define _CALLBACKS_ + +extern LFSTray_trayClass *trayClass; + +bool eventCB(LFSTK_applicationClass *p,XEvent *event); + +#endif diff --git a/LFSTray/LFSTray/src/embedClass.cpp b/LFSTray/LFSTray/src/embedClass.cpp new file mode 100644 index 00000000..d5205b25 --- /dev/null +++ b/LFSTray/LFSTray/src/embedClass.cpp @@ -0,0 +1,219 @@ +/* + * + * ©K. D. Hedger. Tue 21 Jan 15:58:37 GMT 2025 keithdhedger@gmail.com + + * This file (embedClass.cpp) is part of LFSTray. + + * LFSTray 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 3 of the License, or + * (at your option) any later version. + + * LFSTray 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 LFSTray. If not, see . +*/ + +#include "globals.h" + +LFSTray_embedClass::LFSTray_embedClass(LFSTray_trayClass *trayclass) +{ + this->tray=trayclass; +} + +LFSTray_embedClass::~LFSTray_embedClass(void) +{ +} + +Pixmap LFSTray_embedClass::makePixmap(void) +{ + int x; + int y; + Window cr; + + Pixmap pm=this->tray->apc->globalLib->LFSTK_getWindowPixmap(this->tray->apc->display,this->tray->apc->rootWindow); + Pixmap back=XCreatePixmap(this->tray->apc->display,this->tray->apc->mainWindow->window,this->tray->iconSize,this->tray->iconSize,24); + GC gc=XCreateGC(this->tray->apc->display,back,0,NULL); + XTranslateCoordinates(this->tray->apc->display,this->tray->apc->mainWindow->window,this->tray->apc->rootWindow,0,0,&x,&y,&cr); + XCopyArea(this->tray->apc->display,pm,back,gc,x+this->nextIconX,y+this->nextIconY,this->tray->iconSize,this->tray->iconSize,0,0); + XFreeGC(this->tray->apc->display,gc); +//fprintf(stderr,"back=%p x+this->nextIconX=%i\n",back,x+this->nextIconX); +//XSync(this->tray->apc->display,False); + return(back); +} + +void LFSTray_embedClass::nextPosition(void) +{ + int xoffset=0; + int yoffset=0; + + if(this->tray->vertical==false) + { + xoffset=this->tray->iconSize; + yoffset=0; + } + else + { + xoffset=0; + yoffset=this->tray->iconSize; + } + + this->nextIconX+=xoffset; + this->nextIconY+=yoffset; +} + + +bool LFSTray_embedClass::addIcon(Window wid) +{ + std::string winname=trayClass->getWindowName(wid); + int pid=0; + Atom actual_type; + int actual_format; + unsigned long nitems; + unsigned long bytes_after; + unsigned char *prop=0; + XWindowAttributes attr; + + fprintf(stderr,"winname=%s\n",winname.c_str()); + //XSync(this->tray->apc->display,False); + xerror=false; + XErrorHandler old=XSetErrorHandler(windowErrorHandler); + + XSelectInput(this->tray->apc->display,wid,StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); + int ret=XGetWindowProperty(this->tray->apc->display,wid,trayClass->_NET_WM_PID,0,1024,False,AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop); + if(ret==Success && prop) + { + pid=prop[1] * 256; + pid += prop[0]; + } + +// if(XGetWindowAttributes(this->tray->apc->display,wid, &attr)==False) +// { +// XSelectInput(this->tray->apc->display,wid,NoEventMask); +// XSync(this->tray->apc->display,False); +// XSetErrorHandler(old); +// return(false); +// } + + //XSynchronize(this->tray->apc->display,true); + // Create the parent window that will embed the icon + if(this->tray->debugmsg) + fprintf(stderr,"lfstray: XGetWindowAttributes(server.display,win=%p,&attr)\n",wid); + if(XGetWindowAttributes(this->tray->apc->display,wid, &attr)==False) + { + fprintf(stderr,"no wid attr\n"); + XSelectInput(this->tray->apc->display,wid,NoEventMask); + XSync(this->tray->apc->display,False); + XSetErrorHandler(old); + return FALSE; + } + + unsigned long mask=0; + XSetWindowAttributes set_attr; + Visual *visual=this->tray->apc->visual; + + if(this->tray->debugmsg) + fprintf(stderr,"addIcon: %p (%s),pid %d,visual %p,colormap %lu,depth %d,width %d,height %d" "\n",wid,winname.c_str(),pid,(void*)attr.visual,attr.colormap,attr.depth,attr.width,attr.height); + visual=attr.visual; + set_attr.background_pixel=0; + set_attr.border_pixel=0; + set_attr.colormap=attr.colormap; + mask=CWColormap | CWBackPixel | CWBorderPixel; + + if(this->tray->debugmsg) + fprintf(stderr,"lfstray: XCreateWindow(...)\n"); + Window parent=XCreateWindow(this->tray->apc->display,this->tray->apc->mainWindow->window,-1000,-1000,this->tray->iconSize,this->tray->iconSize,0,attr.depth,InputOutput,visual,mask, &set_attr); + + this->tray->iconList[wid]={wid,parent,this->nextIconX,this->nextIconY,this->tray->iconSize,this->tray->iconSize,false,this->makePixmap()}; + + return(true); +} + +void LFSTray_embedClass::embedWindow(Window wid) +{ + sysIcons icondata; + XEvent e; + + icondata=this->tray->iconList.find(wid)->second; + if(icondata.embedded==false) + { + if(this->tray->debugmsg) + fprintf(stderr,"wid=%p par=%p x=%i y=%i w=%i h=%i embedded=%i\n",icondata.iconWindow,icondata.parentWindow,icondata.x,icondata.y,icondata.w,icondata.h,icondata.embedded); + + XWithdrawWindow(this->tray->apc->display,icondata.iconWindow,this->tray->apc->screen); + doingwhat="XReparentWindow "+std::to_string(__LINE__); + XReparentWindow(this->tray->apc->display,icondata.iconWindow,icondata.parentWindow,0,0); + + if(this->tray->debugmsg) + fprintf(stderr,"XMoveResizeWindow(this->tray->apc->display,wid=%p,0,0,this->tray->iconSize=%d,this->tray->iconSize=%d)\n",icondata.iconWindow,this->tray->iconSize,this->tray->iconSize); + doingwhat="XMoveResizeWindow "+std::to_string(__LINE__); + XMoveResizeWindow(this->tray->apc->display,icondata.iconWindow,0,0,this->tray->iconSize,this->tray->iconSize); + + // Embed into parent + e.xclient.type=ClientMessage; + e.xclient.serial=0; + e.xclient.send_event=True; + e.xclient.message_type=trayClass->_XEMBED; + e.xclient.window=icondata.iconWindow; + e.xclient.format=32; + e.xclient.data.l[0]=CurrentTime; + e.xclient.data.l[1]=XEMBED_EMBEDDED_NOTIFY; + e.xclient.data.l[2]=0; + e.xclient.data.l[3]=icondata.parentWindow; + e.xclient.data.l[4]=0; + if(this->tray->debugmsg) + fprintf(stderr,"lfstray: XSendEvent(server.display,traywin->win,False,NoEventMask,&e)\n"); + doingwhat="XSendEvent "+std::to_string(__LINE__); + XSendEvent(this->tray->apc->display,icondata.iconWindow,False,NoEventMask, &e); + + this->tray->iconList[wid].embedded=true; + DEBUG_showIcons(); + XMapWindow(this->tray->apc->display,icondata.parentWindow); + } +} + + +void LFSTray_embedClass::removeIcon(Window wid) +{ + if(this->tray->iconList.find(wid)!=this->tray->iconList.end()) + { + this->currentIcon=this->tray->iconList.find(wid)->second; + this->tray->iconList.erase(this->tray->iconList.find(wid)); + } +} + +void LFSTray_embedClass::refreshIcons(void) +{ + std::map::iterator it; + + this->nextIconX=0; + this->nextIconY=0; + Pixmap pm; + + if(trayClass->iconList.size()>0) + { + for (it=trayClass->iconList.begin();it!=trayClass->iconList.end();++it) + { + it->second.x=nextIconX; + it->second.y=nextIconY; + + XMoveWindow(this->tray->apc->display,it->second.parentWindow,nextIconX,nextIconY); + pm=this->makePixmap(); + XSetWindowBackgroundPixmap(this->tray->apc->display,it->second.parentWindow,pm); + XFreePixmap(this->tray->apc->display,it->second.background); + it->second.background=pm; + XWithdrawWindow(this->tray->apc->display,it->second.iconWindow,this->tray->apc->screen); + XMapWindow(this->tray->apc->display,it->second.iconWindow); + + it->second.x=nextIconX; + it->second.y=nextIconY; + this->nextPosition(); + } + } + else + this->tray->apc->mainWindow->LFSTK_resizeWindow(1,1,true); +} diff --git a/LFSTray/LFSTray/src/embedClass.h b/LFSTray/LFSTray/src/embedClass.h new file mode 100644 index 00000000..88fa86e0 --- /dev/null +++ b/LFSTray/LFSTray/src/embedClass.h @@ -0,0 +1,45 @@ +/* + * + * ©K. D. Hedger. Tue 21 Jan 15:58:25 GMT 2025 keithdhedger@gmail.com + + * This file (embedClass.h) is part of LFSTray. + + * LFSTray 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 3 of the License, or + * (at your option) any later version. + + * LFSTray 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 LFSTray. If not, see . +*/ + +#ifndef _EMBEDCLASS_ +#define _EMBEDCLASS_ + +#include "globals.h" + +class LFSTray_embedClass +{ + public: + LFSTray_embedClass(LFSTray_trayClass *trayclass); + ~LFSTray_embedClass(void); + + LFSTray_trayClass *tray=NULL; + int nextIconX=0; + int nextIconY=0; + sysIcons currentIcon;; + + void removeIcon(Window wid); + void refreshIcons(void); + void embedWindow(Window wid); + bool addIcon(Window wid); + void nextPosition(void); + Pixmap makePixmap(void); +}; + +#endif diff --git a/LFSTray/LFSTray/src/trayClass.cpp b/LFSTray/LFSTray/src/trayClass.cpp new file mode 100644 index 00000000..f60766bc --- /dev/null +++ b/LFSTray/LFSTray/src/trayClass.cpp @@ -0,0 +1,222 @@ +/****************************************************** +* +* ©keithhedger Tue 21 Jan 15:56:31 GMT 2025 +* kdhedger68713@gmail.com +* +* trayClass.cpp +* +******************************************************/ + +#include "globals.h" + +LFSTray_trayClass::LFSTray_trayClass(LFSTK_applicationClass *app) +{ + this->apc=app; + this->embedClass=new LFSTray_embedClass(this); +} + +LFSTray_trayClass::~LFSTray_trayClass() +{ + delete this->embedClass; +} + +void LFSTray_trayClass::setTrayAtoms(void) +{ + std::string aname; + + aname="_NET_SYSTEM_TRAY_S"+std::to_string(this->apc->screen); + fprintf(stderr,"aname=%s\n",aname.c_str()); + this->_NET_SYSTEM_TRAY_SCREEN=XInternAtom(this->apc->display,aname.c_str(),False); + + aname="MANAGER"; + fprintf(stderr,"aname=%s\n",aname.c_str()); + this->MANAGER=XInternAtom(this->apc->display,aname.c_str(),False); + + aname="_NET_SYSTEM_TRAY_OPCODE"; + fprintf(stderr,"aname=%s\n",aname.c_str()); + this->_NET_SYSTEM_TRAY_OPCODE=XInternAtom(this->apc->display,aname.c_str(),False); + + aname="_NET_SYSTEM_TRAY_MESSAGE_DATA"; + fprintf(stderr,"aname=%s\n",aname.c_str()); + this->_NET_SYSTEM_TRAY_MESSAGE_DATA=XInternAtom(this->apc->display,aname.c_str(),False); + + aname="_NET_WM_NAME"; + fprintf(stderr,"aname=%s\n",aname.c_str()); + this->_NET_WM_NAME=XInternAtom(this->apc->display,aname.c_str(),False); + + aname="UTF8_STRING"; + fprintf(stderr,"aname=%s\n",aname.c_str()); + this->UTF8_STRING=XInternAtom(this->apc->display,aname.c_str(),False); + + aname="_NET_WM_PID"; + fprintf(stderr,"aname=%s\n",aname.c_str()); + this->_NET_WM_PID=XInternAtom(this->apc->display,aname.c_str(),False); + + + aname="_XEMBED"; + fprintf(stderr,"aname=%s\n",aname.c_str()); + this->_XEMBED=XInternAtom(this->apc->display,aname.c_str(),False); +} + +void* LFSTray_trayClass::getProperty(Window w,Atom prop,Atom type,long unsigned int *nitems_return) +{ + void *prop_return=NULL; + Atom actual_type_return=0; + int actual_format_return=0; + unsigned long bytes_after_return=0; + int result=-1; + + result=XGetWindowProperty(this->apc->display,w,prop,0L,32,false,type, &actual_type_return, &actual_format_return,nitems_return, &bytes_after_return, (unsigned char**)&prop_return); + if(result!=Success||bytes_after_return>0) + { + XFree(prop_return); + prop_return=NULL; + return(NULL); + } + + return(prop_return); +} + +std::string LFSTray_trayClass::getWindowName(Window win) +{ + char *namex=NULL; + XTextProperty p; + long unsigned int nitems_return; + std::string name; + name=""; + + namex=(char*)this->getProperty(win,this->_NET_WM_NAME,this->UTF8_STRING, &nitems_return); + if(namex!=NULL) + { + name=namex; + free(namex); + } + else + { + if(XGetWMName(this->apc->display,win, &p)!=0) + { + char **v=NULL; + int n=0; + + XmbTextPropertyToTextList(this->apc->display, &p, &v, &n); + if(n>0) + name=v[0]; + + if(v!=NULL) + XFreeStringList(v); + } + } + + return(name); +} + +void LFSTray_trayClass::resetWindow(void) +{ + const monitorStruct *mons=this->apc->LFSTK_getMonitors(); + int w=1; + int h=1; + int x=-1000; + int y=-1000; + + if(this->iconList.size()==0) + { + this->apc->mainWindow->LFSTK_moveResizeWindow(-1000,-1000,1,1,true); + return; + } + + if(this->gravity==N || this->gravity==S) + this->vertical=false; + if(this->gravity==E || this->gravity==W) + this->vertical=true; + + if(this->vertical==false) + { + w=this->iconList.size()*this->iconSize; + h=this->iconSize; + } + else + { + w=this->iconSize; + h=this->iconList.size()*this->iconSize; + } + + switch(this->gravity) + { + case N: + x=(mons[this->onMonitor].x+(mons[this->onMonitor].w)/2)-((this->iconList.size()*this->iconSize)/2); + y=mons[this->onMonitor].y; + break; + case S: + x=(mons[this->onMonitor].x+(mons[this->onMonitor].w)/2)-((this->iconList.size()*this->iconSize)/2); + y=mons[this->onMonitor].y+mons[this->onMonitor].h-this->iconSize; + break; + case E: + x=mons[this->onMonitor].x+mons[this->onMonitor].w-this->iconSize; + y=(mons[this->onMonitor].y+(mons[this->onMonitor].h)/2)-((this->iconList.size()*this->iconSize)/2); + break; + case W: + x=mons[this->onMonitor].x; + y=(mons[this->onMonitor].y+(mons[this->onMonitor].h)/2)-((this->iconList.size()*this->iconSize)/2); + break; + case NW: + x=mons[this->onMonitor].x; + y=mons[this->onMonitor].y; + break; + case NE: + if(this->vertical==false) + { + x=mons[this->onMonitor].x+mons[this->onMonitor].w-this->iconList.size()*this->iconSize; + y=mons[this->onMonitor].y; + } + else + { + x=mons[this->onMonitor].x+mons[this->onMonitor].w-this->iconSize; + y=mons[this->onMonitor].y; + } + break; + case SW: + if(this->vertical==false) + { + x=mons[this->onMonitor].x; + y=mons[this->onMonitor].y+mons[this->onMonitor].h-this->iconSize; + } + else + { + x=mons[this->onMonitor].x; + y=mons[this->onMonitor].y+mons[this->onMonitor].h-this->iconList.size()*this->iconSize; + } + break; + case SE: + if(this->vertical==false) + { + x=mons[this->onMonitor].x+mons[this->onMonitor].w-this->iconList.size()*this->iconSize; + y=mons[this->onMonitor].y+mons[this->onMonitor].h-this->iconSize; + } + else + { + x=mons[this->onMonitor].x+mons[this->onMonitor].w-this->iconSize; + y=mons[this->onMonitor].y+mons[this->onMonitor].h-this->iconList.size()*this->iconSize; + } + break; + } + this->apc->mainWindow->LFSTK_moveResizeWindow(x,y,w,h,true); +} + +void LFSTray_trayClass::setStacking(int stackit) +{ + this->apc->mainWindow->LFSTK_setKeepAbove(false); + this->apc->mainWindow->LFSTK_setKeepBelow(false); + switch(stackit) + { + case ABOVEALL: + this->apc->mainWindow->LFSTK_setKeepAbove(true); + break; + case BELOWALL: + this->apc->mainWindow->LFSTK_setKeepBelow(true); + break; + case NORMAL: + this->apc->mainWindow->LFSTK_setKeepAbove(false); + this->apc->mainWindow->LFSTK_setKeepBelow(false); + break; + } +} diff --git a/LFSTray/LFSTray/src/trayClass.h b/LFSTray/LFSTray/src/trayClass.h new file mode 100644 index 00000000..f9669381 --- /dev/null +++ b/LFSTray/LFSTray/src/trayClass.h @@ -0,0 +1,66 @@ +/* + * + * ©K. D. Hedger. Tue 21 Jan 15:57:44 GMT 2025 keithdhedger@gmail.com + + * This file (trayClass.h) is part of LFSTray. + + * LFSTray 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 3 of the License, or + * (at your option) any later version. + + * LFSTray 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 LFSTray. If not, see . +*/ + +#ifndef _TRAYCLASS_ +#define _TRAYCLASS_ + +#include "globals.h" + +enum TrayPos{NW=1,NE,SE,SW,N,E,S,W}; +//enum Stack{TRAYABOVE=1,TRAYBELOW,TRAYNORMAL}; + +class LFSTray_trayClass +{ + public: + LFSTray_trayClass(LFSTK_applicationClass *app); + ~LFSTray_trayClass(void); + + LFSTK_applicationClass *apc; + LFSTray_embedClass *embedClass; + std::map iconList; + + Atom _NET_SYSTEM_TRAY_SCREEN; + Atom MANAGER; + Atom _NET_SYSTEM_TRAY_OPCODE; + Atom _NET_SYSTEM_TRAY_MESSAGE_DATA; + Atom _NET_WM_NAME; + Atom UTF8_STRING; + Atom _NET_WM_PID; + Atom _XEMBED; + + std::string doingwhat; + int iconSize=128; + bool vertical=false; + int onMonitor=0; + TrayPos gravity=SE; + int stacking=ABOVEALL; + + int firstrun=0; + bool isbelow=false; + int debugmsg=0; + + void setTrayAtoms(void); + void* getProperty(Window w,Atom prop,Atom type,long unsigned int *nitems_return); + std::string getWindowName(Window win); + void resetWindow(void); + void setStacking(int stackit); + +}; +#endif