1 /****************************************************************
4 * Date: January 17, 2001
5 * Author: Edward H. Flora <ehflora@access1.net>
7 * This file is a part of the wmcalc application. As such, this
8 * file is licensed under the GNU General Public License, version 2.
9 * A copy of this license may be found in the file COPYING that should
10 * have been distributed with this file. If not, please refer to
11 * http://www.gnu.org/copyleft/gpl.html for details.
13 ****************************************************************
15 This file contains the main program code for the wmcalc
16 application. Wmcalc is a dockapp designed for the WindowMaker or
17 Afterstep window managers (although it should run well in most
18 others.) wmcalc is a four-function (and more) calculator that
19 has a small enough footprint that you may leave it open on your
20 desktop at all times, for convenient use.
25 01/17/01 Updated to use XLookupString
26 12/10/00 Revised includes, extracting X libs to wmcalc_x.h
27 11/09/00 Added "locked" memory capabilities
28 11/08/00 Added Code to Support Keyboard / focus
29 10/29/00 Implemented memory use, configuration files, and a
30 quickstart button for a larger calculator. Also
31 abstracted some of the macros, global vars, function
32 prototypes, etc out to independent header files, to
33 eliminate some dependency issues between source files.
34 02/10/00 Added keyboard event code, without success
35 12/21/99 Original product release, version 0.1
36 11/26/99 Original file creation
38 ****************************************************************/
41 #include <X11/XKBlib.h>
48 #include "wmcalc_err.h"
53 #include "backdrop.xpm" // background graphic
54 #include "calcbuttons.xpm" // graphic of buttons
55 #include "charmap.xpm" // pixmap of characters
58 /* Global Variables */
59 /* Ok, so I didn't get them all extracted. Should look into this
61 int N
= 1; /* Button number pressed to goto app # */
63 int Verbose
= 0; /* Debug flag */
64 int mmouse
= 1; /* flag to enable middle mouse (hold
66 int button_pressed
= -1; /* button to be drawn pressed */
67 char PlusMinusFlag
= '+'; /* flag for sign of number in display */
68 char OpFlag
= ' '; /* Operation requested */
69 int ExpFlag
= 0; /* Flag if in scientific notation */
70 int DecFlag
= 0; /* Flag if a decimal is in display */
71 int ImgFlag
= 0; /* Flag if a number is imaginary */
73 double RegisterA
= 0.0; /* Main working register, displayed */
74 double RegisterB
= 0.0; /* Second register to add to, etc */
75 char DispString
[DISPSIZE
+1]; /* Pointer to string of display */
76 ButtonArea button_region
[NUM_BUTTONS
]; /* Array of buttons */
78 char *app_name
= "wmcalc"; /* Name of app, for window management */
80 /****************************************************************
82 ****************************************************************
84 This is the main Program control function for wmcalc. It
85 contains all the X11 windows function calls, as well as other
90 01/17/01 Updated to use XLookupString to get KeySym
91 11/09/00 Added Events for focus and keyboard work.
92 11/01/00 File Header Added
93 21/09/01 Added global configfile by Gordon Fraser
94 ****************************************************************/
95 int main( int argc
, char **argv
) {
98 XTextProperty app_name_atom
;
102 char Geometry_str
[64] = "64x64+0+0";
103 char Display_str
[64] = "";
104 int KeywithMask
= NO_BUTTON
;
106 XComposeStatus compose
;
112 strcpy(configfile
, getenv("HOME")); // Added to wmbutton by Casey Harkin, 3/6/99
113 strcat(configfile
, CONFFILENAME
); // Fixed Bug - didn't look in home directory
114 // but startup directory
115 strcat(tempfile
, CONFTEMPFILE
); // Setup name for temp file
117 /* Clear the Calculator Display */
118 for(i
=0; i
<11; i
++) DispString
[i
] = ' ';
119 DispString
[11] = '\0';
121 /* Parse Command Line Arguments */
122 for ( i
=1; i
< argc
; i
++ ) {
123 if ( *argv
[i
] == '-' ) {
124 switch ( *(argv
[i
]+1) ) {
125 case 'v': // Turn on Verbose (debugging) Mode
128 case 'g': // Set Geometry Options
129 if ( ++i
>= argc
) show_usage();
130 sscanf(argv
[i
], "%s", Geometry_str
);
131 if ( Verbose
) printf("Geometry is: %s\n", Geometry_str
);
133 case 'd': // Set display
134 if ( ++i
>= argc
) show_usage();
135 sscanf(argv
[i
], "%s", Display_str
);
136 if ( Verbose
) printf("Display is: %s\n", Display_str
);
138 case 'h': // Show Help Message
141 case 'f': // use config file <filename>
142 if ( ++i
>= argc
) show_usage();
143 sscanf(argv
[i
], "%s", configfile
);
144 if ( Verbose
) printf("Using Config File: %s\n", configfile
);
146 default: // other, unknown, parameters
151 } /* End of loop to process command line options */
153 /* Open display on requested X server */
154 if ( (display
= XOpenDisplay(Display_str
)) == NULL
) {
155 error_handler(ERR_X_DISPLAY
, Display_str
);
158 screen
= DefaultScreen(display
);
159 rootwin
= RootWindow(display
,screen
);
160 depth
= DefaultDepth(display
, screen
);
162 bg_pixel
= WhitePixel(display
, screen
);
163 fg_pixel
= BlackPixel(display
, screen
);
165 xsizehints
.flags
= USSize
| USPosition
;
166 xsizehints
.width
= APP_WIDTH
;
167 xsizehints
.height
= APP_HEIGHT
;
169 /* Parse Geometry string and fill in sizehints fields */
170 XWMGeometry(display
, screen
,
181 if ( (win
= XCreateSimpleWindow(display
,
188 fg_pixel
, bg_pixel
) ) == 0 ) {
189 error_handler(ERR_X_CREATE_WINDOW
, NULL
);
192 if ( (iconwin
= XCreateSimpleWindow(display
,
199 fg_pixel
, bg_pixel
) ) == 0 ) {
200 error_handler(ERR_X_CREATE_WINDOW
, NULL
);
203 /* Set up shaped windows */
204 /*Gives the appicon a border so you can grab and move it. */
206 if ( ( pixmask
= XCreateBitmapFromData(display
,
210 mask_height
) ) == 0 ) {
211 error_handler(ERR_X_CREATE_BITMAP
, NULL
);
214 XShapeCombineMask(display
, win
, ShapeBounding
, 0, 0, pixmask
, ShapeSet
);
215 XShapeCombineMask(display
, iconwin
, ShapeBounding
, 0, 0, pixmask
, ShapeSet
);
217 /* Convert in pixmaps from .xpm includes. */
220 /* Interclient Communication stuff */
221 /* Appicons don't work with out this stuff */
222 xwmhints
= XAllocWMHints();
223 xwmhints
->flags
= WindowGroupHint
| IconWindowHint
| StateHint
;
224 xwmhints
->icon_window
= iconwin
;
225 xwmhints
->window_group
= win
;
226 xwmhints
->initial_state
= WithdrawnState
;
227 XSetWMHints( display
, win
, xwmhints
);
229 xclasshint
.res_name
= app_name
;
230 xclasshint
.res_class
= app_name
;
231 XSetClassHint( display
, win
, &xclasshint
);
233 XSetWMNormalHints( display
, win
, &xsizehints
);
235 /* Tell window manager what the title bar name is. We never see */
236 /* this anyways in the WithdrawnState */
237 if ( XStringListToTextProperty(&app_name
, 1, &app_name_atom
) == 0 ) {
238 error_handler(ERR_SETUP_WINDOW_NAME
, app_name
);
240 XSetWMName( display
, win
, &app_name_atom
);
242 /* Create Graphic Context */
243 if (( gc
= XCreateGC(display
, win
,(GCForeground
| GCBackground
), &xgcValues
))
245 error_handler(ERR_CREATE_GC
, NULL
);
248 /* XEvent Masks. We want both windows to process X events */
249 XSelectInput(display
, win
,
252 ButtonReleaseMask
| /* added ButtonReleaseMask *charkins*/
256 KeyPressMask
| /* Try this to get keyboard working */
257 StructureNotifyMask
|
259 XSelectInput(display
, iconwin
,
262 ButtonReleaseMask
| /* added ButtonReleaseMask *charkins*/
266 KeyPressMask
| /* Try this to get keyboard working */
267 StructureNotifyMask
|
270 /* Store the 'state' of the application for restarting */
271 XSetCommand( display
, win
, argv
, argc
);
273 /* Window won't ever show up until it is mapped.. then drawn after a */
274 /* ConfigureNotify */
275 XMapWindow( display
, win
);
277 /* Read Configuration File */
278 err_code
= read_config();
280 error_handler(err_code
, configfile
);
285 XNextEvent(display
, &report
);
286 switch (report
.type
) {
288 if (report
.xexpose
.count
!= 0) {
291 if ( Verbose
) printf("Event: Expose\n");
294 case ConfigureNotify
:
295 if ( Verbose
) printf("Event: ConfigureNotify\n");
300 if (Verbose
) printf("Event: Key state: 0x%x Key: 0x%x\n",
301 report
.xkey
.state
, report
.xkey
.keycode
);
303 // ksym = XLookupKeysym(&(report.xkey), report.xkey.state);
304 /* KeywithMask - this allows Left, middle, and right button functions
305 to be implemented via keyboard */
306 chcnt
= XLookupString(&(report
.xkey
), buffer
, bufsize
, &ksym
, &compose
);
307 if (Verbose
) printf("Keysym is: 0x%x\n", (int) ksym
);
308 KeywithMask
= whichKey(ksym
);
309 ExecFunc( KeywithMask
);
313 case ButtonPress
: /* draw button pressed, don't launch *charkins*/
314 switch (report
.xbutton
.button
) {
316 N
= whichButton(report
.xbutton
.x
, report
.xbutton
.y
);
317 if ( (N
>= 0) && (N
<= NUM_BUTTONS
) ) {
318 button_pressed
= N
+ LMASK
;
322 printf("Button 1:x=%d y=%d N=%d\n",
323 report
.xbutton
.x
, report
.xbutton
.y
, N
+LMASK
);
327 N
= whichButton(report
.xbutton
.x
, report
.xbutton
.y
);
328 if ( (N
>= 0) && (N
<= NUM_BUTTONS
) ) {
329 button_pressed
= N
+ MMASK
;
333 printf("Button 2:x=%d y=%d N=%d\n",
334 report
.xbutton
.x
, report
.xbutton
.y
, N
+MMASK
);
338 N
= whichButton(report
.xbutton
.x
, report
.xbutton
.y
);
339 if ( (N
>= 0) && (N
<= NUM_BUTTONS
) ) {
340 button_pressed
= N
+ RMASK
;
344 printf("Button 3:x=%d y=%d N=%d\n",
345 report
.xbutton
.x
, report
.xbutton
.y
, N
+RMASK
);
349 case ButtonRelease
: /* If still over button, it was a real button press */
350 switch (report
.xbutton
.button
) {
352 N
= whichButton(report
.xbutton
.x
, report
.xbutton
.y
);
353 if ( (N
>= 0) && (N
<= NUM_BUTTONS
) && (N
== button_pressed
- LMASK
))
358 printf("Button 1:x=%d y=%d N=%d\n",
359 report
.xbutton
.x
, report
.xbutton
.y
, N
+LMASK
);
363 N
= whichButton(report
.xbutton
.x
, report
.xbutton
.y
);
364 if ( (N
>= 0) && (N
<= NUM_BUTTONS
) && (N
== button_pressed
- MMASK
))
365 ExecFunc( N
+ MMASK
);
369 printf("Button 2:x=%d y=%d N=%d\n",
370 report
.xbutton
.x
, report
.xbutton
.y
, N
+MMASK
);
374 N
= whichButton(report
.xbutton
.x
, report
.xbutton
.y
);
375 if ( (N
>= 0) && (N
<= NUM_BUTTONS
) && (N
== button_pressed
- RMASK
))
376 ExecFunc( N
+ RMASK
);
380 printf("Button 3:x=%d y=%d N=%d\n",
381 report
.xbutton
.x
, report
.xbutton
.y
, N
+RMASK
);
386 if ( Verbose
) printf("Requested Program Quit.\n");
387 XFreeGC(display
, gc
);
388 XDestroyWindow(display
,win
);
389 XDestroyWindow(display
,iconwin
);
390 XCloseDisplay(display
);
395 XSetInputFocus(display
, PointerRoot
, RevertToParent
, CurrentTime
);
396 if (Verbose
) printf("Focus Change\n");
401 } /***** End of main program ***********************************/
403 /****************************************************************
405 ****************************************************************
407 This function maintains the appearance of the application
408 by copying the "visible" pixmap to the two windows (the withdrawn
409 main window, and the icon window which is the main windows's icon
414 11/1/00 Function Header updated
415 ****************************************************************/
418 XCopyArea(display
, template.pixmap
, visible
.pixmap
, gc
, 0, 0,
419 template.attributes
.width
, template.attributes
.height
, 0, 0 );
421 defineButtonRegions();
423 /* Copy button to icon */
424 XCopyArea(display
, buttons
.pixmap
, visible
.pixmap
, gc
,
425 1, 1, 53, 40, 6, 20);
428 XCopyArea(display
, visible
.pixmap
, win
, gc
, 0, 0,
429 visible
.attributes
.width
, visible
.attributes
.height
, 0, 0 );
430 flush_expose( iconwin
);
431 XCopyArea(display
, visible
.pixmap
, iconwin
, gc
, 0, 0,
432 visible
.attributes
.width
, visible
.attributes
.height
, 0, 0 );
433 // if ( Verbose ) printf("In Redraw()\n");
435 } /***** End of function redraw() ********************************/
437 /****************************************************************
438 * Function: whichButton
439 ****************************************************************
441 Return the button at the x,y coordinates. The button need not
442 be visible ( drawn ). Return -1 if no button match.
446 11/1/00 Function Header Updated
447 ****************************************************************/
448 int whichButton( int x
, int y
) {
451 for ( index
=0; index
< NUM_BUTTONS
; index
++ ) {
452 if ( (x
>= button_region
[index
].x
) && (x
<= button_region
[index
].i
) &&
453 (y
>= button_region
[index
].y
) && (y
<= button_region
[index
].j
) ) {
458 } /***** End of function whichButton() **************************/
460 /****************************************************************
462 ****************************************************************
464 This function decodes the keycode passed in and converts this to
465 a function number to execute. This is not simply the Button number,
466 but also contains the LMASK, MMASK, or RMASK to pass into ExecFunc to
467 handle expanded functions.
471 01/17/01 Updated to take a KeySym, rather than a KeyCode
472 11/09/00 Original Function creation
473 ****************************************************************/
474 int whichKey (KeySym keysym
) {
476 int func
= NO_BUTTON
;
478 if (Verbose
) printf("KeySym 0x%x received, decoding...\n", (int) keysym
);
604 if (Verbose
) printf("Unknown Keysym, ignoring.\n");
609 } /***** End of function whichKey() ****************************/
611 /****************************************************************
612 * Function: getPixmaps
613 ****************************************************************
615 Load XPM data into X Pixmaps.
617 * Pixmap 'template' contains the untouched window backdrop image.
618 * Pixmap 'visible' is the template pixmap with buttons drawn on it.
619 -- what is seen by the user.
620 * Pixmap 'buttons' holds the images for individual buttons that are
621 later copied onto Pixmap visible.
622 * Pixmap 'charmap' holds the character map for the characters in
627 11/1/00 Function Header Updated
628 ****************************************************************/
630 template.attributes
.valuemask
|= (XpmReturnPixels
| XpmReturnExtensions
);
631 visible
.attributes
.valuemask
|= (XpmReturnPixels
| XpmReturnExtensions
);
632 buttons
.attributes
.valuemask
|= (XpmReturnPixels
| XpmReturnExtensions
);
633 charmap
.attributes
.valuemask
|= (XpmReturnPixels
| XpmReturnExtensions
);
635 /* Template Pixmap. Never Drawn To. */
636 if ( XpmCreatePixmapFromData( display
, rootwin
, backdrop_xpm
,
637 &template.pixmap
, &template.mask
,
638 &template.attributes
) != XpmSuccess
) {
639 error_handler(ERR_CREATE_PIXMAP
, "template");
642 /* Visible Pixmap. Copied from template Pixmap and then drawn to. */
643 if ( XpmCreatePixmapFromData( display
, rootwin
, backdrop_xpm
,
644 &visible
.pixmap
, &visible
.mask
,
645 &visible
.attributes
) != XpmSuccess
) {
646 error_handler(ERR_CREATE_PIXMAP
, "visible");
650 if ( XpmCreatePixmapFromData( display
, rootwin
, calcbuttons_xpm
,
651 &buttons
.pixmap
, &buttons
.mask
,
652 &buttons
.attributes
) != XpmSuccess
) {
653 error_handler(ERR_CREATE_PIXMAP
, "buttons");
656 /* Character Map Pixmap. */
657 if ( XpmCreatePixmapFromData( display
, rootwin
, charmap_xpm
,
658 &charmap
.pixmap
, &charmap
.mask
,
659 &charmap
.attributes
) != XpmSuccess
) {
660 error_handler(ERR_CREATE_PIXMAP
, "charmap");
662 } /***** End of function getPixmaps() *****************************/
664 /****************************************************************
665 * Function: flush_expose
666 ****************************************************************
668 This function is a hold-over from previous programs (wmcp).
669 The use of this function is not well understood.
673 11/1/00 Function header updated.
674 ****************************************************************/
675 int flush_expose(Window w
) {
679 while (XCheckTypedWindowEvent(display
, w
, Expose
, &dummy
)) i
++;
681 } /***** End of function flush_expose() *************************/
683 /****************************************************************
684 * Function: defineButtonRegion
685 ****************************************************************
687 This function defines the start and end x and y coordinates for
688 the various buttons used in wmcalc.
690 There should be a better way to do this, as right now, changing
691 the pixmap calcbuttons.xpm may require the modification of these
696 11/1/00 Function header updated
697 ****************************************************************/
698 void defineButtonRegions(void) {
699 int ndx
= 0; /* button index */
701 button_region
[0].x
= 1; // Define display region button
702 button_region
[0].i
= 62;
703 button_region
[0].y
= 6;
704 button_region
[0].j
= 17;
706 for (ndx
= 1; ndx
<= 5; ndx
++) { // Define y coord's for top row
707 button_region
[ndx
].y
= 20;
708 button_region
[ndx
].j
= 29;
710 for (ndx
= 6; ndx
<= 10; ndx
++) { // Define y coord's for 2nd row
711 button_region
[ndx
].y
= 30;
712 button_region
[ndx
].j
= 39;
714 for (ndx
= 11; ndx
<= 15; ndx
++) { // Define y coord's for 3rd row
715 button_region
[ndx
].y
= 40;
716 button_region
[ndx
].j
= 49;
718 for (ndx
= 16; ndx
<= 20; ndx
++) { // Define y coord's for bottom row
719 button_region
[ndx
].y
= 50;
720 button_region
[ndx
].j
= 59;
722 for (ndx
= 1; ndx
<= 16; ndx
+=5) { // Define x coord's for Left column
723 button_region
[ndx
].x
= 5;
724 button_region
[ndx
].i
= 16;
726 for (ndx
= 2; ndx
<= 17; ndx
+=5) { // Define x coord's for 2nd Left column
727 button_region
[ndx
].x
= 17;
728 button_region
[ndx
].i
= 26;
730 for (ndx
= 3; ndx
<= 18; ndx
+=5) { // Define x coord's for middle column
731 button_region
[ndx
].x
= 27;
732 button_region
[ndx
].i
= 36;
734 for (ndx
= 4; ndx
<= 19; ndx
+=5) { // Define x coord's for 2nd right column
735 button_region
[ndx
].x
= 37;
736 button_region
[ndx
].i
= 46;
738 for (ndx
= 5; ndx
<= 20; ndx
+=5) { // Define x coord's for 2nd right column
739 button_region
[ndx
].x
= 47;
740 button_region
[ndx
].i
= 57;
742 } /***** End of function defineButtonRgions() *************************/
744 /****************************************************************
745 * Function: displaychar
746 ****************************************************************
748 This function displays individual characters to the "display".
749 This function should only be called from displaystr().
753 11/09/00 Added "Locked" character and capabilities
754 11/01/00 Function header updated
755 10/30/00 Updated to include the memory indicators as well.
756 ****************************************************************/
757 void displaychar(char ch
, int location
) {
761 dispchar
= getboundaries(ch
); /* Get the region of the charmap
762 containing the character to
766 locatx
= 2 + location
* 6;
768 /* If the character is a memory display character, use the memory
769 location display region. Valid Characters are:
770 '_' - No data in Memory Location
771 '=' - Value in Memory Location, Not Locked
772 '#' - Constant in Memory Location, Locked
774 if ((ch
== '=') || (ch
== '_') || ch
== '#') {
778 XCopyArea(display
, charmap
.pixmap
, win
, gc
,
779 dispchar
.x
, dispchar
.y
,
780 dispchar
.i
-dispchar
.x
, dispchar
.j
-dispchar
.y
,
782 XCopyArea(display
, charmap
.pixmap
, iconwin
, gc
,
783 dispchar
.x
, dispchar
.y
,
784 dispchar
.i
-dispchar
.x
, dispchar
.j
-dispchar
.y
,
787 } /***** End of Function displaychar() **************************/
789 /****************************************************************
790 * Function: displaystr
791 ****************************************************************
796 11/09/00 Added Capabilities for "Locked" memories
797 11/01/00 Function header updated
798 10/30/00 Added memory location indicators
799 ****************************************************************/
800 void displaystr(void) {
801 extern char DispString
[];
802 extern int MemLock
[];
803 extern double MemArray
[];
807 if (Verbose
) printf("Displaystr %s\n", DispString
);
809 /* Update the alphanumeric display */
810 for (i
= 0; i
< DISPSIZE
; i
++)
811 displaychar(DispString
[i
], i
);
813 /* Update the memory location indicators */
814 for (i
= 0; i
< NUM_MEM_CELLS
; i
++) {
815 if (MemArray
[i
] == 0.0)
816 displaychar('_', i
); /* Value NOT stored here */
817 else if (MemLock
[i
] == 0)
818 displaychar('=', i
); /* Value IS stored here */
820 displaychar('#', i
); /* Constant IS stored here */
824 } /***** End of function displaystr() ***************************/
826 /****************************************************************
827 * Function: show_usage
828 ****************************************************************
830 This function prints a brief usage message to stdout,
835 11/01/00 Function header updated
836 ****************************************************************/
837 void show_usage(void) {
840 printf(" %s: Ver %d Rel %d\n",app_name
, VER
, REL
);
842 printf("usage: %s [-g geometry] [-d display] [-f <filename>] [-v] [-h] \n",
845 printf("-g <geometry> Window Geometry - ie: 64x64+10+10\n");
846 printf("-d <display> Display - ie: 127.0.0.1:0.0\n");
847 printf("-f <filename> Name of Config file - ie: /home/user/.wmcalc\n");
848 printf("-v Verbose Mode. \n");
849 printf("-h Help. This message.\n");
852 } /***** End of function show_usage() ***************************/
854 /****************************************************************
855 * Function: error_handler
856 ****************************************************************
858 This function will handle all fatal error conditions that exist.
859 Error condition codes are kept in wmcalc_err.h
863 11/1/00 Function created
864 ****************************************************************/
865 void error_handler (int err_code
, char *err_string
) {
866 extern char tempfile
[];
868 if (err_code
== OKAY
) {
869 /* This case should never happen.
870 If it does, somebody screwed up (probably me),
871 but don't kill the program!! */
875 fprintf(stderr
, "Error Code %d: ", err_code
);
877 case ERR_FILE_NOT_FOUND
:
878 fprintf(stderr
, "Could not open file %s\n",configfile
);
880 case ERR_TMP_FILE_FAILED
:
881 fprintf(stderr
, "Could not open temporary file %s\n", tempfile
);
883 case ERR_X_CREATE_WINDOW
:
884 fprintf(stderr
, "Could not create simple window\n");
886 case ERR_X_CREATE_BITMAP
:
887 fprintf(stderr
, "Could not create bitmap from data\n");
889 case ERR_SETUP_WINDOW_NAME
:
890 fprintf(stderr
, "Could not setup window name %s\n", err_string
);
893 fprintf(stderr
, "XCreateGC\n");
896 fprintf(stderr
, "Could not open display on %s\n", err_string
);
898 case ERR_CREATE_PIXMAP
:
899 fprintf(stderr
, "Can't Create %s Pixmap\n", err_string
);
904 fprintf(stderr
, "Unknown Error\n");
909 } /***** End of Function error_handler **************************/