/*
* 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 <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <X11/Xatom.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/extensions/shape.h>
#include <X11/xpm.h>
#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 <file> set alias file name\n");
printf(" (default: %s)\n", ALIAS_FILE_NAME);
printf(" -d <display> set display\n");
printf(" -f <font> set font (default: %s)\n", FONT_NAME);
printf(" -h show this help and exit\n");
printf(" -s <number> 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);
}
syntax highlighted by Code2HTML, v. 0.9.1