Author: piumarta Date: 2012-07-30 15:05:14 -0700 (Mon, 30 Jul 2012) New Revision: 2573
Added: trunk/platforms/unix/plugins/ScratchPlugin/ trunk/platforms/unix/plugins/ScratchPlugin/unixScratchOps.c trunk/platforms/unix/plugins/ScratchPlugin/unixSeriaPort2Ops.c trunk/platforms/unix/plugins/UnicodePlugin/ trunk/platforms/unix/plugins/UnicodePlugin/README.UnicodePlugin trunk/platforms/unix/plugins/UnicodePlugin/UnicodeOps-linux.c trunk/platforms/unix/plugins/UnicodePlugin/config.cmake trunk/platforms/unix/plugins/WeDoPlugin/ trunk/platforms/unix/plugins/WeDoPlugin/WeDoLinux.c trunk/platforms/unix/plugins/WeDoPlugin/config.cmake Log: add Scratch, Unicode and WeDo plugins
Added: trunk/platforms/unix/plugins/ScratchPlugin/unixScratchOps.c =================================================================== --- trunk/platforms/unix/plugins/ScratchPlugin/unixScratchOps.c (rev 0) +++ trunk/platforms/unix/plugins/ScratchPlugin/unixScratchOps.c 2012-07-30 22:05:14 UTC (rev 2573) @@ -0,0 +1,98 @@ +/* unixScratchOps.c -- Scratch operations for unix based OSes. + * + * + * Copyright (C) 2011 Massachusetts Institute of Technology + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "ScratchPlugin.h" +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +void OpenURL(char *url) { + // Open a browser on the given URL. +#ifdef I_REALLY_DONT_CARE_HOW_UNSAFE_THIS_IS + char cmd[1000] = "xdg-open "; + strcat( cmd, url); + system(cmd); +#else + // Implement a secure way here. + // IMHO it would be best to call a script that the user or + // package maintainer can customize. But in any case, + // DO NOT call system() with an unchecked URL. --bf +#endif +} + +void SetScratchWindowTitle(char *title) { + // Set the text in the window title bar. Not yet implemented. +} + +void GetFolderPathForID(int folderID, char *path, int maxPath) { + // Get the full path for a special folder: + // 1 - user's home folder + // 2 - user's desktop folder + // 3 - user's document folder + // 4 - user's photos or pictures folder (does Linux have a convention for this?) + // 5 - user's music folder (does Linux have a convention for this?) + // path is filled in with a zero-terminated string of max length maxPath + + char *s = NULL; + + path[0] = 0; // a zero-length path indicates failure + + // get the user's HOME directory + s = getenv("HOME"); + if ((s == NULL) || (strlen(s) == 0)) return; + + strncat(path, s, maxPath); // home folder + + if (folderID == 1) return; + if (folderID == 2) strncat(path, "/Desktop", maxPath); + if (folderID == 4) strncat(path, "/Pictures", maxPath); + if (folderID == 5) strncat(path, "/Music", maxPath); + + if (folderID == 3) { + s = getenv("SUGAR_ACTIVITY_ROOT"); + if (s != NULL) { + // On XO, return the writeable activity "data" directory + strncat(path, s, maxPath); + strncat(path, "/data", maxPath); + } else { + strncat(path, "/Documents", maxPath); + } + } +} + +int WinShortToLongPath(char *shortPath, char* longPath, int maxPath) { + return -1; // fail on non-Windows platforms +} + +int IsFileOrFolderHidden(char *fullPath) { + // Always return false on Linux + return 0; +} + +void SetUnicodePasteBuffer(short int *utf16, int count) { + // Store the given Unicode UTF16 string in the paste buffer. + // No longer needed; use clipboard methods in UnicodePlugin. +}
Property changes on: trunk/platforms/unix/plugins/ScratchPlugin/unixScratchOps.c ___________________________________________________________________ Added: svn:executable + *
Added: trunk/platforms/unix/plugins/ScratchPlugin/unixSeriaPort2Ops.c =================================================================== --- trunk/platforms/unix/plugins/ScratchPlugin/unixSeriaPort2Ops.c (rev 0) +++ trunk/platforms/unix/plugins/ScratchPlugin/unixSeriaPort2Ops.c 2012-07-30 22:05:14 UTC (rev 2573) @@ -0,0 +1,356 @@ +/* unixSerialPort2Ops.c -- Scratch operations for unix based OSes. Support + * for SerialPort2 primitives under Unix, including OSX and Linux. + * + * + * Copyright (C) 2011 Massachusetts Institute of Technology + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "ScratchPlugin.h" + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <termios.h> +#include <unistd.h> + +// support for systems with a single hardware flow control bit +// on such systems setting hardware handshaking for input sets it for output as well +#ifndef CRTS_IFLOW +# define CRTS_IFLOW CRTSCTS +#endif +#ifndef CCTS_OFLOW +# define CCTS_OFLOW CRTSCTS +#endif + + +// globals +#define PORT_COUNT 32 +static int gFileDescr[PORT_COUNT] = { // file descriptors for open serial ports + -1, -1, -1, -1, -1, -1, -1, -1, // the portNum kept by Squeak is an index + -1, -1, -1, -1, -1, -1, -1, -1, // into this array. -1 marks unused entries. + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1}; +static struct termios gOrigTermios[PORT_COUNT]; // original termios settings for open ports + +#define PRIM_FAILED -1 + +// helper function declarations +int FileDescrForEntry(int portNum); +int OpenPortNamed(const char *bsdPath, int baudRate, int entryIndex); +int isPrefix(char *prefix, char *s); +int isSerialPortDev(char *s); + +int SerialPortCount(void) { + DIR *dirPtr; + struct dirent *entryPtr; + int cnt = 0; + + if ((dirPtr = opendir("/dev")) == NULL) return 0; + + while ((entryPtr = readdir(dirPtr)) != NULL) { + if (isSerialPortDev(entryPtr->d_name)) cnt++; + } + + closedir(dirPtr); + return cnt; +} + +// Find the name of the given port number. Fill in bsdPath if successful. +// Otherwise, make bsdPath be the empty string. +void SerialPortName(int portIndex, char *bsdPath, int maxPathSize) { + DIR *dirPtr; + struct dirent *entryPtr; + int cnt = 0; + + *bsdPath = '\0'; // result is the empty string if port not found + + if (portIndex < 1) return; + if ((dirPtr = opendir("/dev")) == NULL) return; + + while ((entryPtr = readdir(dirPtr)) != NULL) { + if (isSerialPortDev(entryPtr->d_name)) cnt++; + if (cnt == portIndex) { + strncat(bsdPath, "/dev/", maxPathSize); + strncat(bsdPath, entryPtr->d_name, maxPathSize); + closedir(dirPtr); + return; + } + } + + closedir(dirPtr); +} + +int SerialPortOpenPortNamed(char *portName, int baudRate) { + int entryIndex; + + // scan for first free entry + for (entryIndex = 0; entryIndex < PORT_COUNT; entryIndex++) { + if (gFileDescr[entryIndex] == -1) break; + } + if (entryIndex >= PORT_COUNT) return PRIM_FAILED; // no free entry + + if (!OpenPortNamed(portName, baudRate, entryIndex)) return PRIM_FAILED; + return entryIndex; +} + +void SerialPortClose(int portNum) { + int fDescr; + + if ((fDescr = FileDescrForEntry(portNum)) < 0) return; // already closed + + // restore the serial port settings to their original state + tcsetattr(fDescr, TCSANOW, &gOrigTermios[portNum]); + close(fDescr); + gFileDescr[portNum] = -1; +} + +int SerialPortIsOpen(int portNum) { + return FileDescrForEntry(portNum) != -1; +} + +int SerialPortRead(int portNum, char *bufPtr, int bufSize) { + int fDescr, count = 0; + + if ((fDescr = FileDescrForEntry(portNum)) < 0) return 0; + + count = read(fDescr, bufPtr, bufSize); + if (count < 0) return 0; // read error + return count; +} + +int SerialPortWrite(int portNum, char *bufPtr, int bufSize) { + int fDescr, count = 0; + + if ((fDescr = FileDescrForEntry(portNum)) < 0) return 0; + + count = write(fDescr, bufPtr, bufSize); + if (count < 0) return 0; // write error + return count; +} + +// Port options for SetOption/GetOption: +// 1. baud rate +// 2. data bits +// 3. stop bits +// 4. parity type +// 5. input flow control type +// 6. output flow control type +// 20-25: handshake line bits (DTR, RTS, CTS, DSR, CD, RD) + +int SerialPortSetOption(int portNum, int optionNum, int newValue) { + int fDescr, handshake; + struct termios options; + + if ((fDescr = FileDescrForEntry(portNum)) < 0) return PRIM_FAILED; + if (tcgetattr(fDescr, &options) == -1) return PRIM_FAILED; + + switch (optionNum) { + case 1: // baud rate + if (cfsetspeed(&options, newValue) == -1) return PRIM_FAILED; + break; + case 2: // # of data bits + switch(newValue) { + case 5: + options.c_cflag = (options.c_cflag & ~CSIZE) | CS5; + break; + case 6: + options.c_cflag = (options.c_cflag & ~CSIZE) | CS6; + break; + case 7: + options.c_cflag = (options.c_cflag & ~CSIZE) | CS7; + break; + case 8: + options.c_cflag = (options.c_cflag & ~CSIZE) | CS8; + break; + } + break; + case 3: // 1 or 2 stop bits + if (newValue > 1) options.c_cflag |= CSTOPB; // two stop bits + else options.c_cflag &= ~CSTOPB; // one stop bit + break; + case 4: // parity + options.c_cflag &= ~(PARENB | PARODD); // no parity + if (newValue == 1) options.c_cflag |= (PARENB | PARODD); // odd parity + if (newValue == 2) options.c_cflag |= PARENB; // even parity + break; + case 5: // input flow control + options.c_iflag &= ~IXOFF; // disable xoff input flow control + options.c_cflag &= ~CRTS_IFLOW; // disable RTS (hardware) input flow control + if (newValue == 1) options.c_iflag |= IXOFF; // enable xoff input flow control + if (newValue == 2) { + options.c_cflag |= CRTS_IFLOW; // enable RTS (hardware) input flow control + if (CRTS_IFLOW == CCTS_OFLOW) { // on systems with a single hardware flow control bit: + options.c_iflag &= ~(IXON | IXOFF); // disable xon/xoff flow control + } + } + break; + case 6: // output flow control + options.c_iflag &= ~IXON; // disable xon output flow control + options.c_cflag &= ~CCTS_OFLOW; // disable CTS (hardware) output flow control + if (newValue == 1) options.c_iflag |= IXON; // enable xon output flow control + if (newValue == 2) { + options.c_cflag |= CCTS_OFLOW; // enable CTS (hardware) output flow control + if (CRTS_IFLOW == CCTS_OFLOW) { // on systems with a single hardware flow control bit: + options.c_iflag &= ~(IXON | IXOFF); // disable xon/xoff flow control + } + } + break; + + case 20: // set DTR line state + if (ioctl(fDescr, TIOCMGET, &handshake) == -1) return PRIM_FAILED; + handshake = newValue ? (handshake | TIOCM_DTR) : (handshake & ~TIOCM_DTR); + if (ioctl(fDescr, TIOCMSET, &handshake) == -1) return PRIM_FAILED; + break; + case 21: // set RTS line state + if (ioctl(fDescr, TIOCMGET, &handshake) == -1) return PRIM_FAILED; + handshake = newValue ? (handshake | TIOCM_RTS) : (handshake & ~TIOCM_RTS); + if (ioctl(fDescr, TIOCMSET, &handshake) == -1) return PRIM_FAILED; + break; + } + if (tcsetattr(fDescr, TCSANOW, &options) == -1) return PRIM_FAILED; + return 0; +} + +int SerialPortGetOption(int portNum, int optionNum) { + int fDescr, handshake = -1; + struct termios options; + + if ((fDescr = FileDescrForEntry(portNum)) < 0) return PRIM_FAILED; + if (tcgetattr(fDescr, &options) == -1) return PRIM_FAILED; + if (ioctl(fDescr, TIOCMGET, &handshake) == -1) return PRIM_FAILED; + + switch (optionNum) { + case 1: return (int) cfgetispeed(&options); + case 2: + if ((options.c_cflag & CSIZE) == CS5) return 5; + if ((options.c_cflag & CSIZE) == CS6) return 6; + if ((options.c_cflag & CSIZE) == CS7) return 7; + if ((options.c_cflag & CSIZE) == CS8) return 8; + return PRIM_FAILED; + case 3: return (options.c_cflag & CSTOPB) ? 2 : 1; + case 4: + if (!(options.c_cflag & PARENB)) return 0; + return (options.c_cflag & PARODD) ? 1 : 2; + case 5: + if (options.c_iflag & IXOFF) return 1; + if (options.c_cflag & CRTS_IFLOW) return 2; + return 0; + case 6: + if (options.c_iflag & IXON) return 1; + if (options.c_cflag & CCTS_OFLOW) return 2; + return 0; + + case 20: return (handshake & TIOCM_DTR) > 0; + case 21: return (handshake & TIOCM_RTS) > 0; + case 22: return (handshake & TIOCM_CTS) > 0; + case 23: return (handshake & TIOCM_DSR) > 0; + case 24: return (handshake & TIOCM_CD) > 0; + case 25: return (handshake & TIOCM_RI) > 0; + } + return PRIM_FAILED; +} + +// ***** helper functions ***** + +// Return the file descriptor for the given entry or -1 if either the +// given port number (index) is out of range or the port is not open. +int FileDescrForEntry(int portNum) { + if ((portNum < 0) || (portNum >= PORT_COUNT)) return PRIM_FAILED; + return gFileDescr[portNum]; +} + +// Given the path to a serial device, open the device and configure it for +// using given entryIndex. Answer 1 if the operation succeeds, 0 if it fails. +int OpenPortNamed(const char *bsdPath, int baudRate, int entryIndex) { + int fDescr = -1; + struct termios options; + + // open the serial port read/write with no controlling terminal; don't block + fDescr = open(bsdPath, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (fDescr == -1) { + printf("Error opening serial port %s - %s(%d).\n", bsdPath, strerror(errno), errno); + goto error; + } + + // request exclusive access to the port + if (ioctl(fDescr, TIOCEXCL) == -1) { + printf("Error setting TIOCEXCL on %s - %s(%d).\n", bsdPath, strerror(errno), errno); + goto error; + } + + // save port settings so we can restore them later + if (tcgetattr(fDescr, &gOrigTermios[entryIndex]) == -1) { + printf("Error getting attributes %s - %s(%d).\n", bsdPath, strerror(errno), errno); + goto error; + } + + // port settings are made by modifying a copy of the termios struct + // and then calling tcsetattr() to make those changes take effect. + options = gOrigTermios[entryIndex]; + + // set the baud rate + if (cfsetspeed(&options, baudRate) == -1) { + printf("Error setting speed %d %s - %s(%d).\n", baudRate, bsdPath, strerror(errno), errno); + goto error; + } + + // set raw input (non-canonical) mode, with writes not blocking. + cfmakeraw(&options); + options.c_cc[VMIN] = 0; + options.c_cc[VTIME] = 0; + + // install the new port settings + if (tcsetattr(fDescr, TCSANOW, &options) == -1) { + printf("Error setting attributes %s - %s(%d).\n", bsdPath, strerror(errno), errno); + goto error; + } + gFileDescr[entryIndex] = fDescr; + return 1; // success! + +error: + if (fDescr != -1) close(fDescr); + return 0; +} + +int isSerialPortDev(char *s) { + return isPrefix("ttyusb", s); +} + +int isPrefix(char *prefix, char *s) { + int prefixC, c; + while (1) { + prefixC = *prefix++; + c = *s++; + if (prefixC == 0) return 1; // match! + if (c == 0) return 0; // s is shorter than prefix + if (c != prefixC) { + if (('a' <= c) && (c <= 'z')) c -= 32; + if (('a' <= prefixC) && (prefixC <= 'z')) prefixC -= 32; + if (c != prefixC) return 0; // non-match + } + } +}
Property changes on: trunk/platforms/unix/plugins/ScratchPlugin/unixSeriaPort2Ops.c ___________________________________________________________________ Added: svn:executable + *
Added: trunk/platforms/unix/plugins/UnicodePlugin/README.UnicodePlugin =================================================================== --- trunk/platforms/unix/plugins/UnicodePlugin/README.UnicodePlugin (rev 0) +++ trunk/platforms/unix/plugins/UnicodePlugin/README.UnicodePlugin 2012-07-30 22:05:14 UTC (rev 2573) @@ -0,0 +1 @@ +In order to build the Unicode plugin on Linux, you'll need a collection of Pango, Cairo, and glib header and library files. These can often be found in the GTK+ development package in the package repository for your version of Linux.
Property changes on: trunk/platforms/unix/plugins/UnicodePlugin/README.UnicodePlugin ___________________________________________________________________ Added: svn:executable + *
Added: trunk/platforms/unix/plugins/UnicodePlugin/UnicodeOps-linux.c =================================================================== --- trunk/platforms/unix/plugins/UnicodePlugin/UnicodeOps-linux.c (rev 0) +++ trunk/platforms/unix/plugins/UnicodePlugin/UnicodeOps-linux.c 2012-07-30 22:05:14 UTC (rev 2573) @@ -0,0 +1,280 @@ +/* UnicodeOps-linux.c + * + * + * Copyright (C) 2011 Massachusetts Institute of Technology + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + + +#include <pango/pangocairo.h> +#include <glib/gprintf.h> +#include <string.h> + +/* entry points */ + +int unicodeClipboardGet(unsigned short *utf16, int utf16Length); +void unicodeClipboardPut(unsigned short *utf16, int utf16Length); +int unicodeClipboardSize(void); +void unicodeDrawString(char *utf8, int utf8Length, int *wPtr, int *hPtr, unsigned int *bitmapPtr); +int unicodeGetFontList(char *str, int strLength); +int unicodeGetXRanges(char *utf8, int utf8Length, int *resultPtr, int resultLength); +void unicodeMeasureString(char *utf8, int utf8Length, int *wPtr, int *hPtr); +void unicodeSetColors(int fgRed, int fgGreen, int fgBlue, int bgRed, int bgGreen, int bgBlue, int mapBGToTransparent); +void unicodeSetFont(char *fontName, int fontSize, int boldFlag, int italicFlag, int antiAliasFlag); + +/* globals */ + +PangoLayout *cachedLayout = NULL; // used for measuring +PangoFontDescription *fontDescr = NULL; +cairo_font_options_t* fontOptions = NULL; + +int g_bgRed = 255, g_bgGreen = 255, g_bgBlue = 255; +int g_fgRed = 0, g_fgGreen = 0, g_fgBlue = 0; +int g_bgRGB = 0; // Squeak format +int g_bgTransparent = 0; + +/* helper procedures */ + +void computeLayout(PangoLayout *layout, char *utf8, int utf8Length, int *wPtr, int *hPtr, int *xOffsetPtr, int *yOffsetPtr, int *layoutDetailsPtr) { + PangoRectangle inkRect, logicalRect; + int left, top, right, bottom, baseline; + PangoLayoutIter *iter; + + if (fontDescr == NULL) unicodeSetFont("Verdana", 18, 0, 0, 1); + pango_cairo_context_set_font_options(pango_layout_get_context(layout), fontOptions); + pango_layout_set_font_description(layout, fontDescr); + pango_layout_set_text(layout, utf8, utf8Length); + pango_layout_get_pixel_extents(layout, &inkRect, &logicalRect); + + left = (inkRect.x < logicalRect.x) ? inkRect.x : logicalRect.x; + top = (inkRect.y < logicalRect.y) ? inkRect.y : logicalRect.y; + right = inkRect.x + inkRect.width; + if ((logicalRect.x + logicalRect.width) > right) right = logicalRect.x + logicalRect.width; + bottom = inkRect.y + inkRect.height; + if ((logicalRect.y + logicalRect.height) > bottom) bottom = logicalRect.y + logicalRect.height; + + iter = pango_layout_get_iter(layout); + baseline = PANGO_PIXELS(pango_layout_iter_get_baseline(iter)); + pango_layout_iter_free(iter); + + if (left < 0) { + inkRect.x = inkRect.x - left; + logicalRect.x = logicalRect.x - left; + } + if (top < 0) { + inkRect.y = inkRect.y - top; + logicalRect.y = logicalRect.y - top; + baseline = baseline - top; + } + + if (layoutDetailsPtr != NULL) { + layoutDetailsPtr[0] = inkRect.x; + layoutDetailsPtr[1] = inkRect.y; + layoutDetailsPtr[2] = inkRect.width; + layoutDetailsPtr[3] = inkRect.height; + + layoutDetailsPtr[4] = logicalRect.x; + layoutDetailsPtr[5] = logicalRect.y; + layoutDetailsPtr[6] = logicalRect.width; + layoutDetailsPtr[7] = logicalRect.height; + + layoutDetailsPtr[8] = baseline; + } + + *wPtr = right - left; + *hPtr = bottom - top; + *xOffsetPtr = left < 0 ? -left : 0; + *yOffsetPtr = top < 0 ? -top : 0; +} + +int unicodeLength(char *utf8, int utf8Length) { + int count, i, ch; + + count = i = 0; + while (i < utf8Length) { + count++; + ch = utf8[i]; + if ((ch & 0xE0) == 0xC0) i += 2; + else if ((ch & 0xF0) == 0xE0) i += 3; + else if ((ch & 0xF8) == 0xF0) i += 4; + else i += 1; + } + return count; +} + +/* entry points */ + +// Clipboard operations are not yet implemented +int unicodeClipboardGet(unsigned short *utf16, int utf16Length) { return 0; } +void unicodeClipboardPut(unsigned short *utf16, int utf16Length) { } +int unicodeClipboardSize(void) { return 0; } + +int unicodeGetFontList(char *str, int strLength) { + PangoFontMap *fontMap; + PangoFontFamily **fontFomilies; + int count, i; + + str[0] = '\0'; + + if (cachedLayout == NULL) { + cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1); + cairo_t *cr = cairo_create(surface); + cachedLayout = pango_cairo_create_layout(cr); + } + + fontMap = pango_context_get_font_map(pango_layout_get_context(cachedLayout)); + pango_font_map_list_families(fontMap, &fontFomilies, &count); + + for (i = 0; i < count; i++) { + strncat(str, pango_font_family_get_name(fontFomilies[i]), strLength); + strncat(str, "\n", strLength); + } + g_free(fontFomilies); + return strlen(str); +} + +void unicodeDrawString(char *utf8, int utf8Length, int *wPtr, int *hPtr, unsigned int *bitmapPtr) { + int w = *wPtr; + int h = *hPtr; + int pixelCount = w * h; + int offsetX, offsetY; + unsigned int *pixelPtr, *lastPtr; + + cairo_surface_t *surface = cairo_image_surface_create_for_data((unsigned char *) bitmapPtr, CAIRO_FORMAT_RGB24, w, h, (4 * w)); + cairo_t *cr = cairo_create(surface); + PangoLayout *layout = pango_cairo_create_layout(cr); + + computeLayout(layout, utf8, utf8Length, wPtr, hPtr, &offsetX, &offsetY, NULL); + + // fill with background color if not transparent + if (g_bgRGB != 0) { + cairo_set_source_rgb(cr, g_bgRed / 255.0, g_bgGreen / 255.0, g_bgBlue / 255.0); + cairo_paint(cr); + } + + cairo_translate(cr, offsetX, offsetY); + cairo_set_source_rgb(cr, g_fgRed / 255.0, g_fgGreen / 255.0, g_fgBlue / 255.0); + pango_cairo_show_layout(cr, layout); + + // map bg color pixels to transparent if so desired + if (g_bgTransparent) { + pixelPtr = bitmapPtr; + lastPtr = pixelPtr + pixelCount; + while (pixelPtr < lastPtr) { + if (*pixelPtr == g_bgRGB) *pixelPtr = 0; + pixelPtr++; + } + } + + g_object_unref(layout); + cairo_destroy(cr); + cairo_surface_destroy(surface); +} + +int unicodeGetXRanges(char *utf8, int utf8Length, int *resultPtr, int resultLength) { + int w, h, offsetX, offsetY; + int count, ch, i, j; + PangoRectangle rect; + + count = unicodeLength(utf8, utf8Length); + if (resultLength < (2 * count)) return -1; + + if (cachedLayout == NULL) { + cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1); + cairo_t *cr = cairo_create(surface); + cachedLayout = pango_cairo_create_layout(cr); + } + + computeLayout(cachedLayout, utf8, utf8Length, &w, &h, &offsetX, &offsetY, NULL); + + i = j = 0; + while ((i < utf8Length) && (j < (resultLength - 1))) { + pango_layout_index_to_pos(cachedLayout, i, &rect); + ch = utf8[i]; + if ((ch & 0xE0) == 0xC0) i += 2; + else if ((ch & 0xF0) == 0xE0) i += 3; + else if ((ch & 0xF8) == 0xF0) i += 4; + else i += 1; + resultPtr[j] = PANGO_PIXELS(rect.x); + resultPtr[j + 1] = PANGO_PIXELS(rect.x + rect.width); + j += 2; + } + + return count; +} + +void unicodeMeasureString(char *utf8, int utf8Length, int *wPtr, int *hPtr) { + int offsetX, offsetY; + + if (cachedLayout == NULL) { + cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1); + cairo_t *cr = cairo_create(surface); + cachedLayout = pango_cairo_create_layout(cr); + } + + computeLayout(cachedLayout, utf8, utf8Length, wPtr, hPtr, &offsetX, &offsetY, NULL); +} + +void unicodeSetColors(int fgRed, int fgGreen, int fgBlue, int bgRed, int bgGreen, int bgBlue, int mapBGToTransparent) { + g_fgRed = fgRed & 255; + g_fgGreen = fgGreen & 255; + g_fgBlue = fgBlue & 255; + g_bgRed = bgRed & 255; + g_bgGreen = bgGreen & 255; + g_bgBlue = bgBlue & 255; + g_bgRGB = (g_bgRed << 16) | (g_bgGreen << 8) | g_bgBlue; // Squeak pixel format + g_bgTransparent = mapBGToTransparent; +} + +void unicodeSetFont(char *fontName, int fontSize, int boldFlag, int italicFlag, int antiAliasFlag) { + char description[200]; + g_sprintf(description, "%s, %s %s %dpx", + fontName, + (boldFlag ? "bold" : ""), + (italicFlag ? "italic" : ""), + fontSize); + + if (fontDescr != NULL) pango_font_description_free(fontDescr); + fontDescr = pango_font_description_from_string(description); + + if (fontOptions == NULL) { + fontOptions = cairo_font_options_create(); + // Note: On Mac OS, the default hint style and metrics looked the best. Also, using + // the default allows the user to control the look via the OS settings. + /* + styles: + CAIRO_HINT_STYLE_DEFAULT Use the default hint style for for font backend and target device + CAIRO_HINT_STYLE_NONE Do not hint outlines + CAIRO_HINT_STYLE_SLIGHT Hint outlines slightly to improve contrast while retaining good fidelity to the original shapes. + CAIRO_HINT_STYLE_MEDIUM Hint outlines with medium strength giving a compromise between fidelity to the original shapes and contrast + CAIRO_HINT_STYLE_FULL Hint outlines to maximize contrast + metrics: + CAIRO_HINT_METRICS_DEFAULT Hint metrics in the default manner for the font backend and target device + CAIRO_HINT_METRICS_OFF Do not hint font metrics + CAIRO_HINT_METRICS_ON Hint font metrics + */ + cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_DEFAULT); + cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_DEFAULT); + } + + cairo_font_options_set_antialias(fontOptions, antiAliasFlag ? CAIRO_ANTIALIAS_GRAY : CAIRO_ANTIALIAS_NONE); +}
Property changes on: trunk/platforms/unix/plugins/UnicodePlugin/UnicodeOps-linux.c ___________________________________________________________________ Added: svn:executable + *
Added: trunk/platforms/unix/plugins/UnicodePlugin/config.cmake =================================================================== --- trunk/platforms/unix/plugins/UnicodePlugin/config.cmake (rev 0) +++ trunk/platforms/unix/plugins/UnicodePlugin/config.cmake 2012-07-30 22:05:14 UTC (rev 2573) @@ -0,0 +1,3 @@ +PLUGIN_REQUIRE_PACKAGE (PANGOCAIRO pangocairo) +PLUGIN_REQUIRE_PACKAGE (GLIB glib-2.0) +
Added: trunk/platforms/unix/plugins/WeDoPlugin/WeDoLinux.c =================================================================== --- trunk/platforms/unix/plugins/WeDoPlugin/WeDoLinux.c (rev 0) +++ trunk/platforms/unix/plugins/WeDoPlugin/WeDoLinux.c 2012-07-30 22:05:14 UTC (rev 2573) @@ -0,0 +1,220 @@ +/* WeDoLinux.c -- Linux plugin for Lego WeDo + * + * Author: Derek O'Connell doc@doconnel.f9.co.uk + * + * Copyright (C) 2010 by MIT + * All rights reserved. + * + * This file is part of Unix Squeak. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Last edited: 2010-06-20 16:23:00 by Derek O'Connell + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <linux/hiddev.h> + + +#define true 1 +#define false 0 + +#define NTEMPLATES 2 +#define MAXSTRLEN 64 + +static char hiddevFileTemplates[NTEMPLATES][MAXSTRLEN] = { + "/dev/usb/hiddev0", + "/dev/hiddev0" +}; + +static char hiddevFileName[MAXSTRLEN]; + +static int fdWeDo = 0; + + +/* ================================================= */ +/* ============== FUNCTION PROTOTYPES ============== */ +/* ================================================= */ + + +/* LIBRARY CONSTRUCTOR/DESCTRUCTOR */ +void __attribute__ ((constructor)) libConWeDo(void); +void __attribute__ ((destructor)) libDesWeDo(void); + +/* SQUEAK INTERFACE */ +int WeDoOpenPort(void); +int WeDoClosePort(void); +int WeDoRead(char *bufPtr, int bufSize); +int WeDoWrite(char *bufPtr, int bufSize); + + +/* ================================================= */ +/* ========== LIB CONSTRUCTOR/DESTRUCTOR =========== */ +/* ================================================= */ + + +void __attribute__ ((constructor)) +libConWeDo(void) { + /* NOTHING TO DO (YET) */ +} + + +void __attribute__ ((destructor)) +libDesWeDo(void) { + WeDoClosePort(); +} + + +/* ================================================= */ +/* =================== UTILITY ===================== */ +/* ================================================= */ + + +void +delay(int mS) { + int microsecs; + struct timeval tv; + + microsecs=mS * 1000; + tv.tv_sec = microsecs/1000000; + tv.tv_usec = microsecs%1000000; + + select(0, NULL, NULL, NULL, &tv); +} + + +/* ================================================= */ +/* ================== WEDO UTILS =================== */ +/* ================================================= */ + + +int +scanForWeDo(char *fileTemplate) { /* eg, "/dev/usb/hiddev0" */ + int f, i; + struct hiddev_devinfo dinfo; + + f = 0; + for (i=0; i<10; i++) { + strcpy(hiddevFileName, fileTemplate); + hiddevFileName[strlen(hiddevFileName)-1] = '0' + i; + if (-1 != (f = open(hiddevFileName, O_RDWR))) + if (-1 != ioctl(f, HIDIOCGDEVINFO, &dinfo)) + if ((dinfo.vendor == 0x0694) & (dinfo.product == 0x0003)) + return f; + } + return 0; +} + + +int +isWeDoAvailable() { + struct stat st; + + if (!fdWeDo) return false; + + /* Required, catches device being unplugged... */ + if (-1 == stat(hiddevFileName, &st)) { + WeDoClosePort(); + return false; + } + + return true; +} + + +/* ================================================= */ +/* ================= SCRATCH I/F =================== */ +/* ================================================= */ + + +int +WeDoOpenPort(void) { + int i; + + if (fdWeDo) return true; + + fdWeDo = 0; + for (i=0; i<NTEMPLATES; i++) + if (fdWeDo = scanForWeDo(hiddevFileTemplates[i])) + break; + + if (!fdWeDo) return false; + + delay(100); + return true; +} + + +int +WeDoClosePort(void) { + if (!fdWeDo) return true; + close(fdWeDo); + fdWeDo = 0; + return true; +} + + +int +WeDoRead(char *bufPtr, int bufSize) { + int i; + struct hiddev_usage_ref uref; + + if (!isWeDoAvailable()) return 8; + + for (i = 0; i < 8; i++) { + uref.report_type = HID_REPORT_TYPE_INPUT; + uref.report_id = HID_REPORT_ID_FIRST; + uref.field_index = 0; + uref.usage_index = i; + uref.value = 0; + if (isWeDoAvailable()) + if (ioctl(fdWeDo, HIDIOCGUCODE, &uref) < 0) continue; + if (isWeDoAvailable()) + if (ioctl(fdWeDo, HIDIOCGUSAGE, &uref) < 0) continue; + *(bufPtr + i) = uref.value; + } + return 8; +} + + +int +WeDoWrite(char *bufPtr, int bufSize) { + int i; + + if (!isWeDoAvailable()) return 8; + + for (i = 0; i < 8; i++) + if (isWeDoAvailable()) + ioctl(fdWeDo, HIDIOCSUSAGE, (int []){HID_REPORT_TYPE_OUTPUT, 0, 0, i, 0, *(bufPtr + i)}); + if (isWeDoAvailable()) + ioctl(fdWeDo, HIDIOCSREPORT,(int []){HID_REPORT_TYPE_OUTPUT, 0, 1}); + if (isWeDoAvailable()) + ioctl(fdWeDo, HIDIOCSREPORT,(int []){HID_REPORT_TYPE_OUTPUT, 0, 1}); + + return 8; +} +
Added: trunk/platforms/unix/plugins/WeDoPlugin/config.cmake =================================================================== --- trunk/platforms/unix/plugins/WeDoPlugin/config.cmake (rev 0) +++ trunk/platforms/unix/plugins/WeDoPlugin/config.cmake 2012-07-30 22:05:14 UTC (rev 2573) @@ -0,0 +1,3 @@ +PLUGIN_REQUIRE_INCLUDE(HIDDEV linux/hiddev.h /usr/include) + +
vm-dev@lists.squeakfoundation.org