/*********************************************************************** * Code is based on wmppp, wmload, wmtime, wmcp, and asbutton * Author: Edward H. Flora * Ver 0 Rel 6.1 Jan 23, 2005 * * Contributors: * Christian 'Greek0' Aichinger * Did some code cleanup and fixed several memory leaks. * Ralf Horstmann * Added ability to load pixmaps at startup, * without having to re-compile * Michael Cohrs * Added Tool Tips, and updated graphics * Bruno Essmann ) * Creator of wmpager * Casey Harkins * Bug fix reading config file path - 3/6/99 * Added button-presses, and other - denoted by *charkins* * Ben Cohen * original author of wmcp (et al.) * Thomas Nemeth * contributor to wmcp * Michael Henderson * Application ideas, suggestions * Ryan ?? * Modified wmbutton to asbutton. * Note: asbutton is a seperate program, not associated * with wmbutton (just as wmbutton is not associated * with wmcp) * Jon Bruno * Web Page Development * The contributors listed above are not necessarily involved with the * development of wmbutton. I'm listing them here partially as thanks for * helping out, catching bugs in the code, etc. ***********************************************************************/ #include #include #include #include #include #include #include "wmbutton.h" #include "backdrop.xpm" /* background graphic */ #include "buttons.xpm" /* graphic of 9 buttons */ #include "mask.xbm" /* Border Graphic */ /*************** Function Prototypes ***********************************/ void redraw(void); void getPixmaps(void); int whichButton(int x, int y); // determine which button has been pressed void SetWmHints(); void SetClassHints(); /*********************************************************************** * Globals.. OK.. there's too many globals. * Feel free and fix it, if you'd like. ***********************************************************************/ Display *display; int screen; Window rootwin, win, iconwin; GC gc; int depth; Pixel bg_pixel, fg_pixel; struct Config_t Config; typedef struct _XpmIcon { Pixmap pixmap; Pixmap mask; XpmAttributes attributes; } XpmIcon; typedef struct _button_region { int x,y; int i,j; } ButtonArea; ButtonArea button_region[9]; XpmIcon template, visible, buttons; int border = 0; int button_pressed = -1; /* button to be drawn pressed *charkins*/ char *app_name = "wmbutton"; /*********************************************************************** * Main ***********************************************************************/ int main( int argc, char ** argv ) { XEvent report; XGCValues xgcValues; XTextProperty app_name_atom; XSizeHints xsizehints; Pixmap pixmask; int dummy = 0; int N = 1; /* Button number pressed to goto app # */ /* Added for Tool Tip Support */ long nTooltipShowDelay = TOOLTIP_SHOW_DELAY; long nTooltipReshowDelay = TOOLTIP_RESHOW_DELAY; long nTooltipTimer = -1; long nTooltipHideTimer = -1; long nNow; int nTooltipButton = 0, nTooltipX = 0, nTooltipY = 0; /* Parse Command Line Arguments */ parseargs(argc, argv); /* Open Display */ if ( (display = XOpenDisplay(Config.Display_str)) == NULL ) err_mess(FAILDISP, Config.Display_str); screen = DefaultScreen(display); rootwin = RootWindow(display,screen); depth = DefaultDepth(display, screen); bg_pixel = WhitePixel(display, screen ); fg_pixel = BlackPixel(display, screen ); xsizehints.flags = USSize | USPosition; xsizehints.width = 64; xsizehints.height = 64; /* Parse Geometry string and fill in sizehints fields */ XWMGeometry(display, screen, Config.Geometry_str, NULL, border, &xsizehints, &xsizehints.x, &xsizehints.y, &xsizehints.width, &xsizehints.height, &dummy); if ( (win = XCreateSimpleWindow(display, rootwin, xsizehints.x, xsizehints.y, xsizehints.width, xsizehints.height, border, fg_pixel, bg_pixel) ) == 0 ) err_mess(FAILSWIN, NULL); if ( (iconwin = XCreateSimpleWindow(display, win, xsizehints.x, xsizehints.y, xsizehints.width, xsizehints.height, border, fg_pixel, bg_pixel) ) == 0 ) err_mess(FAILICON, NULL); /* Set up shaped windows */ /*Gives the appicon a border so you can grab and move it. */ if ( ( pixmask = XCreateBitmapFromData(display, win, mask_bits, mask_width, mask_height) ) == 0 ) err_mess(FAILXPM,NULL); XShapeCombineMask(display, win, ShapeBounding, 0, 0, pixmask, ShapeSet ); XShapeCombineMask(display, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet); /* Convert in pixmaps from .xpm includes. */ getPixmaps(); /* Interclient Communication stuff */ /* Appicons don't work with out this stuff */ SetWmHints(); SetClassHints(); XSetWMNormalHints( display, win, &xsizehints ); /* Tell window manager what the title bar name is. We never see */ /* this anyways in the WithdrawnState */ if ( XStringListToTextProperty(&app_name, 1, &app_name_atom) == 0 ) err_mess(FAILWNAM,app_name); XSetWMName( display, win, &app_name_atom ); /* Create Graphic Context */ if (( gc = XCreateGC(display, win,(GCForeground | GCBackground), &xgcValues)) == NULL ) err_mess(FAILGC,NULL); /* XEvent Masks. We want both window to process X events */ XSelectInput(display, win, ExposureMask | ButtonPressMask | ButtonReleaseMask | /* added ButtonReleaseMask *charkins*/ PointerMotionMask | StructureNotifyMask | LeaveWindowMask ); XSelectInput(display, iconwin, ExposureMask | ButtonPressMask | ButtonReleaseMask | /* added ButtonReleaseMask *charkins*/ PointerMotionMask | StructureNotifyMask | LeaveWindowMask ); /* Store the 'state' of the application for restarting */ XSetCommand( display, win, argv, argc ); /* Window won't ever show up until it is mapped.. then drawn after a */ /* ConfigureNotify */ XMapWindow( display, win ); /* Initialize Tooltip Support */ initTime(); initTooltip(!Config.bTooltipDisable, Config.szTooltipFont, Config.bTooltipSwapColors); /* X Event Loop */ while (1) { while (XPending(display) || nTooltipTimer == -1) { XNextEvent(display, &report ); switch (report.type) { case Expose: if (report.xexpose.count != 0) { break; } if ( Config.Verbose ) fprintf(stdout,"Event: Expose\n"); redraw(); break; case ConfigureNotify: if ( Config.Verbose ) fprintf(stdout,"Event: ConfigureNotify\n"); redraw(); break; case MotionNotify: if (hasTooltipSupport()) { if (!hasTooltip()) { nTooltipTimer= currentTimeMillis(); nTooltipX= report.xbutton.x; nTooltipY= report.xbutton.y; nTooltipButton= whichButton(report.xbutton.x, report.xbutton.y); } else { int nButton = whichButton(report.xbutton.x, report.xbutton.y); if (nButton != nTooltipButton) { hideTooltip(); nTooltipTimer= -1; nTooltipX = report.xbutton.x; nTooltipY = report.xbutton.y; nTooltipButton = nButton; showTooltip(nTooltipButton, nTooltipX, nTooltipY); } } } break; case LeaveNotify: if ( Config.Verbose ) fprintf(stdout,"Event: LeaveNotify\n"); if (hasTooltip()) { hideTooltip(); nTooltipHideTimer= currentTimeMillis(); } nTooltipTimer= -1; break; case ButtonPress: /* draw button pressed, don't launch *charkins*/ if (hasTooltip()) { hideTooltip(); nTooltipHideTimer= currentTimeMillis(); } switch (report.xbutton.button) { case Button1: N = whichButton(report.xbutton.x, report.xbutton.y ); if ( (N >= 0) && (N <= NUMB_OF_APPS) ) { button_pressed = N + LMASK; redraw(); } if ( Config.Verbose ) fprintf(stdout,"Button 1:x=%d y=%d N=%d\n", report.xbutton.x, report.xbutton.y, N+LMASK); break; case Button2: if (Config.mmouse) { N = whichButton(report.xbutton.x, report.xbutton.y ); if ( (N >= 0) && (N <= NUMB_OF_APPS) ) { button_pressed = N + MMASK; redraw(); } if ( Config.Verbose ) fprintf(stdout,"Button 2:x=%d y=%d N=%d\n", report.xbutton.x, report.xbutton.y, N+MMASK); } break; case Button3: N = whichButton(report.xbutton.x, report.xbutton.y ); if ( (N >= 0) && (N <= NUMB_OF_APPS) ) { button_pressed = N + RMASK; redraw(); } if ( Config.Verbose ) fprintf(stdout,"Button 3:x=%d y=%d N=%d\n", report.xbutton.x, report.xbutton.y, N+RMASK); break; } break; case ButtonRelease: /* launch app here if still over button *charkins*/ switch (report.xbutton.button) { case Button1: N = whichButton(report.xbutton.x, report.xbutton.y ); if ( (N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed)) RunAppN( N + LMASK); button_pressed=-1; redraw(); if ( Config.Verbose ) fprintf(stdout,"Button 1:x=%d y=%d N=%d\n", report.xbutton.x, report.xbutton.y, N+LMASK); break; case Button2: if (Config.mmouse) { N = whichButton(report.xbutton.x, report.xbutton.y ); if ( (N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed)) RunAppN( N + MMASK); button_pressed=-1; redraw(); if ( Config.Verbose ) fprintf(stdout,"Button 2:x=%d y=%d N=%d\n", report.xbutton.x, report.xbutton.y, N+MMASK); } break; case Button3: N = whichButton(report.xbutton.x, report.xbutton.y ); if ( (N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed)) RunAppN( N + RMASK); button_pressed=-1; redraw(); if ( Config.Verbose ) fprintf(stdout,"Button 3:x=%d y=%d N=%d\n", report.xbutton.x, report.xbutton.y, N+RMASK); break; } break; case DestroyNotify: if ( Config.Verbose ) fprintf(stdout, "Bye\n"); destroyTooltip(); XFreeGC(display, gc); XDestroyWindow(display,win); XDestroyWindow(display,iconwin); XCloseDisplay(display); exit(0); break; } } usleep(50000); nNow = currentTimeMillis(); if ( nTooltipTimer != -1 && ( (nNow > nTooltipTimer + nTooltipShowDelay) || (nNow < nTooltipHideTimer + nTooltipReshowDelay) ) ) { showTooltip(nTooltipButton, nTooltipX, nTooltipY); nTooltipTimer = -1; } } return (0); }/***********************************************************************/ /*********************************************************************** * redraw * * Map the button region coordinates. * * Draw the appropriate number of buttons on the 'visible' Pixmap * using data from the 'buttons' pixmap. * * Then, copy the 'visible' pixmap to the two windows ( the withdrawn * main window and the icon window which is the main window's icon image.) ***********************************************************************/ void redraw() { int n; int i,j; int dest_x, dest_y; int space; int offset; int bsize = 18; if ( Config.Verbose ) fprintf(stdout,"In Redraw()\n"); space = 0; offset = 5; XCopyArea(display, template.pixmap, visible.pixmap, gc, 0, 0, template.attributes.width, template.attributes.height, 0, 0 ); for ( j=0; j < 3; j++ ) { for ( i=0; i < 3; i++ ) { n = i + j * 3; dest_x = i*(bsize + space) + offset + space; dest_y = j*(bsize + space) + offset + space; /* Define button mouse coords */ button_region[n].x = dest_x; button_region[n].y = dest_y; button_region[n].i = dest_x + bsize - 1; button_region[n].j = dest_y + bsize - 1; /* Copy button images for valid apps */ if ( (n + 1) <= NUMB_OF_APPS ) { XCopyArea(display, buttons.pixmap, visible.pixmap, gc, i * bsize, j * bsize, bsize, bsize, dest_x, dest_y); } } } if ( button_pressed>0 ) { /* draw pressed button *charkins*/ if(button_pressed>RMASK) button_pressed-=RMASK; else if(button_pressed>MMASK) button_pressed-=MMASK; else if(button_pressed>LMASK) button_pressed-=LMASK; i = (button_pressed-1) % 3; /* get col of button */ j = (button_pressed-1) / 3; /* get row of button */ dest_x = i * (bsize + space) + offset + space; dest_y = j * (bsize + space) + offset + space; XSetForeground(display, gc, bg_pixel); XDrawLine(display, visible.pixmap, gc, dest_x+1, dest_y+bsize-1, dest_x+bsize-1, dest_y+bsize-1); XDrawLine(display, visible.pixmap, gc, dest_x+bsize-1, dest_y+bsize-1, dest_x+bsize-1, dest_y+1); XSetForeground(display, gc, fg_pixel); XDrawLine(display, visible.pixmap, gc, dest_x, dest_y, dest_x+bsize-2, dest_y); XDrawLine(display, visible.pixmap, gc, dest_x, dest_y, dest_x, dest_y+bsize-2); } /*charkins*/ flush_expose( win ); XCopyArea(display, visible.pixmap, win, gc, 0, 0, visible.attributes.width, visible.attributes.height, 0, 0 ); flush_expose( iconwin ); XCopyArea(display, visible.pixmap, iconwin, gc, 0, 0, visible.attributes.width, visible.attributes.height, 0, 0 ); }/***********************************************************************/ /*********************************************************************** * whichButton * * Return the button that at the x,y coordinates. The button need not * be visible ( drawn ). Return -1 if no button match. ***********************************************************************/ int whichButton( int x, int y ) { int index; for ( index=0; index < NUMB_OF_APPS; index++ ) { if ( x >= button_region[index].x && x <= button_region[index].i && y >= button_region[index].y && y <= button_region[index].j ) { return( index + 1); } } return(-1); }/***********************************************************************/ /*********************************************************************** * getPixmaps * * Load XPM data into X Pixmaps. * * Pixmap template contains the untouched window backdrop image. * Pixmap visible is the template pixmap with buttons drawn on it. * -- what is seen by the user. * Pixmap buttons holds the images for individual buttons that are * later copied onto Pixmap visible. ***********************************************************************/ void getPixmaps() { int loaded = 0; template.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions); visible.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions); buttons.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions); if (Config.Verbose) fprintf(stdout, "In getPixmaps\n"); /* Template Pixmap. Never Drawn To. */ if ( XpmCreatePixmapFromData( display, rootwin, backdrop_xpm, &template.pixmap, &template.mask, &template.attributes) != XpmSuccess ) err_mess(FAILTMPL, NULL); /* Visible Pixmap. Copied from template Pixmap and then drawn to. */ if ( XpmCreatePixmapFromData( display, rootwin, backdrop_xpm, &visible.pixmap, &visible.mask, &visible.attributes) != XpmSuccess ) err_mess(FAILVIS, NULL); /* Button Pixmap. */ if ( access( Config.buttonfile, R_OK ) == 0 ) { /* load buttons from file */ if ( XpmReadFileToPixmap( display, rootwin, Config.buttonfile, &buttons.pixmap, &buttons.mask, &buttons.attributes) != XpmSuccess ) { err_mess(FAILBUT, NULL); } else { loaded = 1; } } if (! loaded) { /* Use Builtin Button Pixmap. */ if (Config.Verbose) fprintf(stdout, "Using builtin buttons pixmap\n"); if ( XpmCreatePixmapFromData( display, rootwin, buttons_xpm, &buttons.pixmap, &buttons.mask, &buttons.attributes) != XpmSuccess ) err_mess(FAILBUT, NULL); } if (Config.Verbose) fprintf(stdout, "Leaving getPixmaps\n"); }/*********************************************************************/ void SetWmHints() { XWMHints *xwmhints; xwmhints = XAllocWMHints(); xwmhints->flags = WindowGroupHint | IconWindowHint | StateHint; xwmhints->icon_window = iconwin; xwmhints->window_group = win; xwmhints->initial_state = WithdrawnState; XSetWMHints( display, win, xwmhints ); XFree(xwmhints); xwmhints = NULL; } void SetClassHints() { XClassHint xclasshint; xclasshint.res_name = "wmbutton"; xclasshint.res_class = "Wmbutton"; XSetClassHint( display, win, &xclasshint ); }