/* * Copyright (c) 1999, 2000 Motoyuki Kasahara. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pccard.h" #include "pccard_alias.h" #include "wmpccard.xpm" #include "wmpccard2.xpm" #include "digits.xpm" #include "defs.h" /* * Application name and version. */ #define APPLICATION_NAME "wmpccard" #ifndef APPLICATION_VERSION #define APPLICATION_VERSION "?.?" #endif /* * Resource class. */ #define RESOURCE_CLASS "WMPccard" /* * Window size. */ #define WINDOW_WIDTH 64 #define WINDOW_HEIGHT 64 /* * Colors. */ #define FOREGROUND_COLOR "cyan" #define BACKGROUND_COLOR "gray20" /* * Font. */ #define FONT_NAME "6x10" /* * Geometry and size information for the card name area. */ #define CARD_NAME_AREA_X1 5 #define CARD_NAME_AREA_Y1 5 #define CARD_NAME_AREA_WIDTH 54 #define CARD_NAME_AREA_HEIGHT 39 /* * Geometry and size information for the power button. */ #define POWER_BUTTON_X1 4 #define POWER_BUTTON_Y1 47 #define POWER_BUTTON_X2 28 #define POWER_BUTTON_Y2 59 #define POWER_BUTTON_WIDTH (POWER_BUTTON_X2 - POWER_BUTTON_X1 + 1) #define POWER_BUTTON_HEIGHT (POWER_BUTTON_Y2 - POWER_BUTTON_Y1 + 1) /* * Geometry and size information for the slot button. */ #define SLOT_BUTTON_X1 35 #define SLOT_BUTTON_Y1 47 #define SLOT_BUTTON_X2 46 #define SLOT_BUTTON_Y2 59 #define SLOT_BUTTON_WIDTH (SLOT_BUTTON_X2 - SLOT_BUTTON_X1 + 1) #define SLOT_BUTTON_HEIGHT (SLOT_BUTTON_Y2 - SLOT_BUTTON_Y1 + 1) /* * Geometry information for the slot number display. */ #define SLOT_NUMBER_X1 49 #define SLOT_NUMBER_Y1 48 /* * Size information for digit drawn on the slot number display. */ #define DIGIT_WIDTH 10 #define DIGIT_HEIGHT 11 #define MAX_SLOTS 3 /* * Maximum length of a string displayed in the card name area. */ #define MAX_CARD_NAME_LENGTH 127 /* * Display */ Display *display = NULL; /* * Window. */ Window icon_window; Window master_window; /* * Program name (argv[0]). */ char *program_name; /* * Display name. */ char *display_name = ""; /* * Font name. */ char *font_name = FONT_NAME; /* * Graphic context. */ GC gc; /* * Font information. */ XFontStruct *font; /* * Pixmaps for icon window. */ Pixmap icon_pixmap; /* * Pixmap and mask data for "wmpccard.xpm". */ Pixmap back_pixmap; Pixmap back_mask_pixmap; /* * pixmap and mask data for "wmpccard2.xpm". */ Pixmap back2_pixmap; Pixmap back2_mask_pixmap; /* * pixmap and mask data for "digits.xpm". */ Pixmap digits_pixmap; Pixmap digits_mask_pixmap; /* * Socket connected to X server. */ int display_socket; /* * Socket for communicating with pccardd. */ int pccard_socket; /* * The number of PCcard slots your note PC has. */ int number_of_slots; /* * The slot number that wmpccard currently displayes its information. */ int current_slot; /* * True if the slot button is pressed. */ int slot_button_pressed = 0; /* * PCcard alias file name. */ const char *alias_file_name = ALIAS_FILE_NAME; /* * Draw the card name. */ static void draw_card_name(void) { char card_name[MAX_CARD_NAME_LENGTH + 1]; size_t card_name_length; const char *manufacturer; const char *driver; const char *version; const char *alias; int card_status; int rows; int columns; int font_width; int font_height; int i; /* * Set card name to display. */ card_status = pccard_status(current_slot); switch (card_status) { case PCCARD_STATUS_FILLED: manufacturer = pccard_manufacturer(current_slot); driver = pccard_driver(current_slot); version = pccard_version(current_slot); alias = pccard_alias(current_slot); if (alias != NULL && *alias != '\0') { snprintf(card_name, MAX_CARD_NAME_LENGTH + 1, "%s:%s", driver, alias); } else { snprintf(card_name, MAX_CARD_NAME_LENGTH + 1, "%s:%s %s", driver, manufacturer, version); } break; case PCCARD_STATUS_INACTIVE: strcpy(card_name, "inactive"); break; case PCCARD_STATUS_EMPTY: strcpy(card_name, "empty"); break; case PCCARD_STATUS_FILLED2: case PCCARD_STATUS_INACTIVE2: XCopyArea(display, back2_pixmap, icon_pixmap, gc, CARD_NAME_AREA_X1, CARD_NAME_AREA_Y1, CARD_NAME_AREA_WIDTH, CARD_NAME_AREA_HEIGHT, CARD_NAME_AREA_X1, CARD_NAME_AREA_Y1); return; default: strcpy(card_name, "unknown status"); } card_name_length = strlen(card_name); /* * Calclate rows and columns. */ font_width = font->max_bounds.width; font_height = font->ascent + font->descent; columns = CARD_NAME_AREA_WIDTH / font_width; rows = CARD_NAME_AREA_HEIGHT / font_height; /* * Draw background. */ XCopyArea(display, back_pixmap, icon_pixmap, gc, CARD_NAME_AREA_X1, CARD_NAME_AREA_Y1, CARD_NAME_AREA_WIDTH, CARD_NAME_AREA_HEIGHT, CARD_NAME_AREA_X1, CARD_NAME_AREA_Y1); /* * Draw the card name string. */ for (i = 0; i < rows && columns * i < card_name_length; i++) { if (columns * i + columns < card_name_length) { XDrawString(display, icon_pixmap, gc, CARD_NAME_AREA_X1, CARD_NAME_AREA_Y1 + font_height * i + font->ascent, card_name + columns * i, columns); } else { XDrawString(display, icon_pixmap, gc, CARD_NAME_AREA_X1, CARD_NAME_AREA_Y1 + font_height * i + font->ascent, card_name + columns * i, card_name_length - columns * i); } } } /* * Draw the slot number (0, 1, 2 ...). */ static void draw_slot_number(void) { XCopyArea(display, digits_pixmap, icon_pixmap, gc, DIGIT_WIDTH * current_slot, 0, DIGIT_WIDTH, DIGIT_HEIGHT, SLOT_NUMBER_X1, SLOT_NUMBER_Y1); } /* * Draw the power button. */ static void draw_power_button(void) { int card_status; card_status = pccard_status(current_slot); switch (card_status) { case PCCARD_STATUS_FILLED: case PCCARD_STATUS_INACTIVE2: XCopyArea(display, back2_pixmap, icon_pixmap, gc, POWER_BUTTON_X1, POWER_BUTTON_Y1, POWER_BUTTON_WIDTH, POWER_BUTTON_HEIGHT, POWER_BUTTON_X1, POWER_BUTTON_Y1); break; default: XCopyArea(display, back_pixmap, icon_pixmap, gc, POWER_BUTTON_X1, POWER_BUTTON_Y1, POWER_BUTTON_WIDTH, POWER_BUTTON_HEIGHT, POWER_BUTTON_X1, POWER_BUTTON_Y1); } } /* * Draw the slot button. */ static void draw_slot_button(void) { if (slot_button_pressed) { XCopyArea(display, back2_pixmap, icon_pixmap, gc, SLOT_BUTTON_X1, SLOT_BUTTON_Y1, SLOT_BUTTON_WIDTH, SLOT_BUTTON_HEIGHT, SLOT_BUTTON_X1, SLOT_BUTTON_Y1); } else { XCopyArea(display, back_pixmap, icon_pixmap, gc, SLOT_BUTTON_X1, SLOT_BUTTON_Y1, SLOT_BUTTON_WIDTH, SLOT_BUTTON_HEIGHT, SLOT_BUTTON_X1, SLOT_BUTTON_Y1); } } /* * Update the window. */ static void update_window(void) { XCopyArea(display, icon_pixmap, icon_window, gc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0); } /* * Process a pccard event. (pccardd sends me an update notice.) */ static int event_pccardd(void) { int slot; /* * Get an unpdate notify. */ slot = pccard_update(); if (slot == -1) return 0; else if (slot == current_slot) { draw_power_button(); draw_card_name(); update_window(); } return 1; } /* * Process a destroy notify event. */ static int event_destroy_notify(void) { pccard_finalize_client(); XCloseDisplay(display); fflush(stderr); _exit(0); /* never reached */ return 1; } /* * Process an event that the button 1 is pressed on the power button. */ static int event_power_button_pressed(void) { int card_status; /* * Send a request to change status of the current slot. */ card_status = pccard_status(current_slot); if (card_status == PCCARD_STATUS_FILLED) { if (pccard_remove(current_slot) == -1) return 0; draw_power_button(); draw_card_name(); update_window(); } else if (card_status == PCCARD_STATUS_INACTIVE) { if (pccard_insert(current_slot) == -1) return 0; draw_power_button(); draw_card_name(); update_window(); } return 1; } /* * Process an event that the button 1 is pressed on the slot button. */ static int event_slot_button_pressed(void) { slot_button_pressed = 1; /* * Draw the pressed button. */ draw_slot_button(); /* * Update the current slot number. */ current_slot = (current_slot + 1) % number_of_slots; /* * Draw the slot number, power button and cardname. */ draw_slot_number(); draw_power_button(); draw_card_name(); update_window(); return 1; } /* * Process an event that the button 1 is released on the slot button. */ static int event_slot_button_released(void) { slot_button_pressed = 0; /* * Draw the unpressed button. */ draw_slot_button(); update_window(); return 1; } /* * Exit handler for exit(). */ static void atexit_handler(void) { pccard_finalize_client(); if (display != NULL) XCloseDisplay(display); fflush(stderr); } /* * Signal handler for SIGINT, SIGQUIT and SIGTERM. */ static void exit_signal_handler(int sig) { pccard_finalize_client(); if (display != NULL) XCloseDisplay(display); fflush(stderr); _exit(1); } /* * Signal handler for SIGHUP. */ static void restart_signal_handler(int sig) { pccard_synchronize(); draw_power_button(); draw_card_name(); update_window(); } /* * Main. */ int main(int argc, char *argv[]) { XClassHint class_hint; XWMHints wm_hints; XGCValues gc_values; unsigned long gc_mask; XColor foreground, background; struct sigaction sigact; sigset_t sigset; int option; /* * Set program name. */ program_name = strrchr(argv[0], '/'); if (program_name != NULL) program_name++; else program_name = argv[0]; /* * Parse command line arguments. */ for (;;) { option = getopt(argc, argv, "a:d:f:hs:tv"); if (option == EOF) break; switch(option) { case 'a': alias_file_name = (strcmp(optarg, "-") != 0) ? optarg : NULL; break; case 'd': display_name = optarg; break; case 'f': font_name = optarg; break; case 'h': printf("Usage: %s [-option...]\n", program_name); printf("Options:\n"); printf(" -a set alias file name\n"); printf(" (default: %s)\n", ALIAS_FILE_NAME); printf(" -d set display\n"); printf(" -f set font (default: %s)\n", FONT_NAME); printf(" -h show this help and exit\n"); printf(" -s set initial slot (default: 0)\n"); printf(" -t trace mode\n"); printf(" -v show version number and exit\n"); exit(0); case 's': current_slot = atoi(optarg); break; case 't': pccard_set_debug_flag(); break; case 'v': printf("%s version %s\n", APPLICATION_NAME, APPLICATION_VERSION); exit(0); default: fprintf(stderr, "type `%s -help' for more information\n", program_name); goto die; } } if (argc - optind > 0) { fprintf(stderr, "too many arguments\n"); fprintf(stderr, "type `%s -help' for more information\n", program_name); goto die; } /* * Register a function to be called on exit(). */ atexit(atexit_handler); /* * Block SIGHUP. */ sigemptyset(&sigset); sigaddset(&sigset, SIGHUP); sigprocmask(SIG_BLOCK, &sigset, NULL); /* * Set signal handler. */ sigact.sa_handler = restart_signal_handler; sigemptyset(&sigact.sa_mask); sigact.sa_flags = SA_NOCLDSTOP; sigaction(SIGHUP, &sigact, NULL); sigact.sa_handler = exit_signal_handler; sigemptyset(&sigact.sa_mask); sigact.sa_flags = SA_NOCLDSTOP; sigaction(SIGINT, &sigact, NULL); sigaction(SIGQUIT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); /* * Connect to pccardd. */ if (pccard_initialize_client(alias_file_name) == -1) goto die; number_of_slots = pccard_number_of_slots(); pccard_socket = pccard_socket_file(); if (number_of_slots == 0) { fprintf(stderr, "this system has no card slot\n"); goto die; } if (number_of_slots <= current_slot) { fprintf(stderr, "warning: this system doesn't have the slot %d\n", number_of_slots); fprintf(stderr, "warning: initial slot is set to 0\n"); current_slot = 0; } if (number_of_slots > MAX_SLOTS) number_of_slots = MAX_SLOTS; /* * Open a display. */ display = XOpenDisplay(display_name); if (display == NULL) { fprintf(stderr, "failed to open display %s\n", display_name); goto die; } display_socket = ConnectionNumber(display); /* * Create windows. */ icon_window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0, 0); master_window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0, 1, 1, 0, 0, 0); /* * Set font. */ font = XLoadQueryFont(display, font_name); if (font == NULL) { fprintf(stderr, "failed to load font: %s\n", font_name); goto die; } /* * Set foreground color. */ if (!XParseColor(display, DefaultColormap(display, DefaultScreen(display)), FOREGROUND_COLOR, &foreground)) { fprintf(stderr, "failed to parse color: %s\n", FOREGROUND_COLOR); goto die; } if (!XAllocColor(display, DefaultColormap(display, DefaultScreen(display)), &foreground)) { fprintf(stderr, "failed to allocate color: %s\n", FOREGROUND_COLOR); } /* * Set background color. */ if (!XParseColor(display, DefaultColormap(display, DefaultScreen(display)), BACKGROUND_COLOR, &background)) { fprintf(stderr, "failed to parse color: %s\n", BACKGROUND_COLOR); goto die; } if (!XAllocColor(display, DefaultColormap(display, DefaultScreen(display)), &background)) { fprintf(stderr, "failed to allocate color: %s\n", BACKGROUND_COLOR); } /* * Set GC. */ gc_mask = GCForeground | GCBackground | GCFont; gc_values.foreground = foreground.pixel; gc_values.background = background.pixel; gc_values.font = font->fid; gc = XCreateGC(display, DefaultRootWindow(display), gc_mask, &gc_values); /* * Set class hints. */ class_hint.res_class = RESOURCE_CLASS; class_hint.res_name = program_name; XSetClassHint(display, master_window, &class_hint); /* * Set select input. */ XSelectInput(display, master_window, ButtonPressMask | ButtonReleaseMask | StructureNotifyMask); XSelectInput(display, icon_window, ButtonPressMask | ButtonReleaseMask | StructureNotifyMask); /* * Set wm hints. */ wm_hints.flags = IconWindowHint | WindowGroupHint | StateHint; wm_hints.window_group = master_window; wm_hints.icon_window = icon_window; wm_hints.initial_state = WithdrawnState; XSetWMHints(display, master_window, &wm_hints); /* * Set command. */ XSetCommand(display, master_window, argv, argc); /* * Set pixmap. */ icon_pixmap = XCreatePixmap(display, icon_window, WINDOW_WIDTH, WINDOW_HEIGHT, DefaultDepth(display, DefaultScreen(display))); XpmCreatePixmapFromData(display, icon_window, wmpccard_xpm, &back_pixmap, &back_mask_pixmap, NULL); XpmCreatePixmapFromData(display, icon_window, wmpccard2_xpm, &back2_pixmap, &back2_mask_pixmap, NULL); XpmCreatePixmapFromData(display, icon_window, digits_xpm, &digits_pixmap, &digits_mask_pixmap, NULL); XShapeCombineMask(display, icon_window, ShapeBounding, 0, 0, back_mask_pixmap, ShapeSet); /* * Display the window. */ XCopyArea(display, back_pixmap, icon_pixmap, gc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0); draw_slot_number(); draw_power_button(); draw_card_name(); XSetWindowBackgroundPixmap(display, icon_window, icon_pixmap); XClearWindow(display, icon_window); XMapRaised(display, master_window); XFlush(display); /* * Main loop. */ for (;;) { XEvent event; fd_set fdset; int nfiles; /* * Unblock SIGHUP. */ sigemptyset(&sigset); sigaddset(&sigset, SIGHUP); sigprocmask(SIG_UNBLOCK, &sigset, NULL); /* * Wait an event. */ /* XSync(display, False); */ FD_ZERO(&fdset); FD_SET(display_socket, &fdset); FD_SET(pccard_socket, &fdset); nfiles = (display_socket < pccard_socket) ? pccard_socket + 1 : display_socket + 1; if (select(nfiles, &fdset, NULL, NULL, NULL) == -1) continue; /* * Block SIGHUP. */ sigemptyset(&sigset); sigaddset(&sigset, SIGHUP); sigprocmask(SIG_BLOCK, &sigset, NULL); /* * Process an event sent by pccardd. */ if (FD_ISSET(pccard_socket, &fdset)) { if (!event_pccardd()) goto die; } /* * Process an event sent by X server. */ while (XPending(display)) { XNextEvent(display, &event); if (event.type == DestroyNotify) { /* * Destroy Window. */ event_destroy_notify(); } else if (event.type == ButtonPress && event.xbutton.button == 1 && POWER_BUTTON_X1 <= event.xbutton.x && POWER_BUTTON_Y1 <= event.xbutton.y && event.xbutton.x <= POWER_BUTTON_X2 && event.xbutton.y <= POWER_BUTTON_Y2) { /* * Button 1 is pressed on the power button. */ if (!event_power_button_pressed()) goto die; } else if (event.type == ButtonPress && event.xbutton.button == 1 && SLOT_BUTTON_X1 <= event.xbutton.x && SLOT_BUTTON_Y1 <= event.xbutton.y && event.xbutton.x <= SLOT_BUTTON_X2 && event.xbutton.y <= SLOT_BUTTON_Y2) { /* * Button 1 is pressed on the slot button. */ if (!event_slot_button_pressed()) goto die; } else if (event.type == ButtonRelease && event.xbutton.button == 1 && slot_button_pressed) { /* * Button 1 is released when the slot button is pressed. */ if (!event_slot_button_released()) goto die; } } } /* * Error occurs. */ die: pccard_finalize_client(); if (display != NULL) XCloseDisplay(display); fflush(stderr); _exit(1); }