Terminal: added SUPPORT to the plugin, for mojo to display the keyStates
[webos-internals:applications.git] / termplugin / termplugin.cpp
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is mozilla.org code.
16  *
17  * The Initial Developer of the Original Code is
18  * Netscape Communications Corporation.
19  * Portions created by the Initial Developer are Copyright (C) 1998
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *   Josh Aas <josh@mozilla.com>
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either the GNU General Public License Version 2 or later (the "GPL"), or
27  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the MPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the MPL, the GPL or the LGPL.
36  *
37  * ***** END LICENSE BLOCK ***** */
38
39 #include <sys/time.h>
40
41 #include "termplugin.h"
42 #include "nppalmdefs.h"
43 #include "pixelbuffer.hpp"
44 #include "charbuffer.hpp"
45 #include "spawn.h"
46 #include "keyman.hpp"
47 #include "screen.hpp"
48
49 #include <stdlib.h>
50 #include <string.h>
51 #include <stdio.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <fcntl.h>
55 #include <unistd.h>
56 #include <pthread.h>
57 #include <algorithm>
58 #include "common.h"
59 #include "api.h"
60 using namespace std;
61
62 #define PLUGIN_NAME        "Term Plug-in"
63 #define PLUGIN_DESCRIPTION PLUGIN_NAME " (Mozilla SDK)"
64 #define PLUGIN_VERSION     "1.0.0.0"
65 #define PLUGIN_MIMEDESCRIPTION "application/x-webosinternals-termplugin:trm:Term plugin"
66
67 NPNetscapeFuncs NPNFuncs;
68
69 typedef struct
70 {
71         const char *key;
72         int id;
73         int minArgs;
74         const char *argsDesc;
75 }SUPPORTED_OBJECTS;
76
77
78 double CurrentTime()
79 {
80         struct timeval tv;
81         gettimeofday(&tv, 0);
82         return tv.tv_sec + tv.tv_usec/1000000.0;
83 }
84
85 #ifdef DEBUG_OUTPUT
86 static void logTimeStamp(FILE *out, int line)
87 {
88         struct tm *t;
89         time_t now;
90
91         if(!out)
92                 return;
93         time(&now);
94         t = localtime(&now);
95
96         my_fprintf(out, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d  %d      term: ",
97                         t->tm_year + 1900,
98                         t->tm_mon + 1,
99                         t->tm_mday,
100                         t->tm_hour,
101                         t->tm_min,
102                         t->tm_sec, line);
103 }
104 #endif
105 #define debugLogLine(x)                                                         debugLog(__LINE__, x)
106 #if 0
107 static void debugLogArgv(int line, int argc, char **argn, char **argv, const char *msg)
108 {
109         int j;
110         const char *prefix = "args =";
111 #if !defined(__STDERR_NO_GOOD__)
112         FILE *out = stderr;
113 #else
114         FILE *out = fopen("/tmp/termPluginOutput.log", "a");
115         if(!out)
116                 return;
117 #endif
118         logTimeStamp(out, line);
119         my_fprintf(out, "%s(", msg);
120         for(j = 0; argc > 0; argc--, argv++, argn++, j++, prefix = ",")
121                 my_fprintf(out, "%s %d:%s[%s]", prefix, j, *argn, *argv);
122         my_fprintf(out, ")\n");
123 #if defined(__STDERR_NO_GOOD__)
124         if(out != stderr)
125                 fclose(out);
126 #endif
127 }
128 #endif
129
130
131 #include <stdarg.h>
132 static void debugLog(int line, const char *format, ...)
133 {
134 #ifdef DEBUG_OUTPUT
135 #if !defined(__STDERR_NO_GOOD__)
136         FILE *out = stderr;
137 #else
138         FILE *out = fopen("/tmp/termPluginOutput.log", "a");
139         if(!out)
140                 return;
141 #endif
142         logTimeStamp(out, line);
143         va_list(arglist);
144         va_start(arglist, format);
145         vfprintf(out, format, arglist);
146         my_fprintf(out, "\n");
147 #if defined(__STDERR_NO_GOOD__)
148         if(out != stderr)
149                 fclose(out);
150 #endif
151 #endif
152 }
153 #if 0
154 void debugLogVariant(int line, NPVariant *var, bool ok, const char *msg)
155 {
156         if(ok)
157         {
158                 if(NPVARIANT_IS_INT32(*var))
159                         debugLog(line, "%s = %d val:%d", msg, ok, NPVARIANT_TO_INT32(*var));
160                 else if(NPVARIANT_IS_DOUBLE(*var))
161                         debugLog(line, "%s = %d val:%f", msg, ok, NPVARIANT_TO_DOUBLE(*var));
162                 else if(NPVARIANT_IS_BOOLEAN(*var))
163                         debugLog(line, "%s = %d val:%s", msg, ok, NPVARIANT_TO_BOOLEAN(*var) ? "true" : "false");
164                 else if(NPVARIANT_IS_STRING(*var))
165                         debugLog(line, "%s = %d val:[%s]", msg, ok, NPVARIANT_TO_STRING(*var).UTF8Characters);
166                 else if(NPVARIANT_IS_OBJECT(*var))
167                         debugLog(line, "%s = %d val:%p", msg, ok, NPVARIANT_TO_OBJECT(*var));
168                 else
169                         debugLog(line, "%s = %d type:%d", msg, ok, var->type);
170         }
171         else
172                 debugLog(line, "%s = %d", msg, ok);
173 }
174 #endif
175
176 struct MyObject : NPObject, KeyManager::Client {
177         NPP instance;
178         KeyManager key_manager;
179         int event_x;
180         int event_y;
181         int terminalHeight;
182         Screen screen;
183         SpawnData *spawn_data;
184         pthread_t select_thread;
185         bool select_thread_started;
186         pthread_mutex_t draw_mutex;
187         pthread_cond_t drawn_cond;
188         NPObject *scroller;
189         NPObject *keyStatesParentObj;
190
191         MyObject(NPP i);
192         ~MyObject();
193
194         void checkSpawn();
195
196         void sendChars(const char *buf,int len)
197         {
198 #ifdef DEBUG_OUTPUT
199                 {
200                         my_fprintf(stderr,"Sending");
201                         int i = 0;
202                         for (;i<len;++i) {
203                                 my_fprintf(stderr," %d",buf[i]);
204                         }
205                         my_fprintf(stderr,"\n");
206                 }
207 #endif
208                 Spawn_Send(spawn_data,buf,len);
209         }
210
211         static CommandHandlers term_handlers;
212
213         static int _termVoidOp(void *obj,TermOp_t op)
214         {
215                 ((MyObject *)obj)->_termVoid(op);
216                 return 1;
217         }
218
219         static int _termIntOp(void *obj,TermOp_t op,int arg1)
220         {
221                 ((MyObject *)obj)->_termInt(op,arg1);
222                 return 1;
223         }
224
225         static int _termIntIntOp(void *obj,TermOp_t op,int arg1,int arg2)
226         {
227                 ((MyObject *)obj)->_termIntInt(op,arg1,arg2);
228                 return 1;
229         }
230
231         static int _termStringOp(void *,TermOp_t op,const char *arg)
232         {
233                 my_fprintf(stderr,"term: string op\n");
234                 return 1;
235         }
236
237         static void _termTextOp(void *obj_ptr,const char *buf,int n)
238         {
239                 MyObject *myobj = (MyObject *)obj_ptr;
240                 myobj->_termText(buf,n);
241                 my_fprintf(stderr, "myobj->scroller:%p\n", myobj->scroller);
242                 if(myobj->scroller)
243                         scrollBottom(myobj->instance, myobj->scroller);
244         }
245
246         static void _termUnexpected(void *,int c)
247         {
248                 my_fprintf(stderr,"term: unexpected:%d\n", c);
249         }
250
251         void _termVoid(TermOp_t op);
252         void _termInt(TermOp_t op,int arg1);
253         void _termIntInt(TermOp_t op,int arg1,int arg2);
254         void _termText(const char *buf,int n);
255         void startSelectThread();
256         void stopSelectThread();
257         static void *selectThread(void *);
258         void runSelect();
259         static void masterReady(void *obj_ptr);
260         void start(char *user);
261 };
262
263 MyObject::MyObject(NPP i)
264 : instance(i),
265   key_manager(this),
266   event_x(0),
267   event_y(0),
268   spawn_data(0),
269   select_thread_started(false),
270   scroller(0),
271   keyStatesParentObj(0)
272 {
273         term_handlers.void_proc = MyObject::_termVoidOp;
274         term_handlers.int_proc = MyObject::_termIntOp;
275         term_handlers.int_int_proc = MyObject::_termIntIntOp;
276         term_handlers.string_proc = MyObject::_termStringOp;
277         term_handlers.text_proc = MyObject::_termTextOp;
278         term_handlers.unexpected_proc = MyObject::_termUnexpected;
279 }
280
281 MyObject::~MyObject()
282 {
283         if (select_thread_started) {
284                 stopSelectThread();
285         }
286         Spawn_Kill(spawn_data,"HUP");
287         Spawn_CheckChildExit(spawn_data,1);
288         Spawn_Delete(spawn_data);
289         spawn_data = 0;
290         if(scroller)
291                 NPNFuncs.releaseobject(scroller);
292         if(keyStatesParentObj)
293                 NPNFuncs.releaseobject(keyStatesParentObj);
294 }
295
296 void MyObject::start(char *user)
297 {
298         spawn_data = Spawn_Open(&term_handlers,this);
299         if (spawn_data) {
300                 const char *argv[] = {"/bin/login","-f",user, 0};
301                 Spawn_Exec(spawn_data,(char **)argv);
302                 startSelectThread();
303         }
304         free(user);
305 }
306
307 void MyObject::masterReady(void *obj_ptr)
308 {
309         my_fprintf(stderr,"term: masterReady: forcing redraw\n");
310         NPN_ForceRedraw(((MyObject *)obj_ptr)->instance);
311 }
312
313 void MyObject::runSelect()
314 {
315         my_fprintf(stderr,"In select thread.\n");
316         for (;;) {
317                 Spawn_WaitMaster(spawn_data);
318 #if 0
319                 my_fprintf(stderr,"term: calling masterReady\n");
320                 my_fprintf(stderr,"term: func=%p\n",NPNFuncs.pluginthreadasynccall);
321                 my_fprintf(stderr,"term: instance=%p\n",instance);
322                 NPNFuncs.pluginthreadasynccall(instance,MyObject::masterReady,this);
323 #else
324                 pthread_mutex_lock(&draw_mutex);
325                 fprintf(stderr,"Forcing redraw\n");
326                 NPN_ForceRedraw(instance);
327                 fprintf(stderr,"Waiting for redraw\n");
328                 pthread_cond_wait(&drawn_cond,&draw_mutex);
329                 fprintf(stderr,"Done redraw\n");
330                 pthread_mutex_unlock(&draw_mutex);
331 #endif
332         }
333 }
334
335 void *MyObject::selectThread(void *obj_ptr)
336 {
337         ((MyObject *)obj_ptr)->runSelect();
338         return 0;
339 }
340
341 void MyObject::startSelectThread()
342 {
343         pthread_mutex_init(&draw_mutex,NULL);
344         pthread_cond_init(&drawn_cond,NULL);
345         int rc = pthread_create(&select_thread,NULL,MyObject::selectThread,this);
346
347         if (rc!=0) {
348                 my_fprintf(stderr,"Failed to create select thread.\n");
349         }
350         else {
351                 my_fprintf(stderr,"Created select thread\n");
352                 select_thread_started = true;
353         }
354 }
355
356
357 void MyObject::stopSelectThread()
358 {
359         pthread_cancel(select_thread);
360         void *thread_return = 0;
361         pthread_join(select_thread,&thread_return);
362         my_fprintf(stderr,"Select thread terminated\n");
363         select_thread_started = false;
364 }
365
366
367 void MyObject::_termText(const char *buf,int n)
368 {
369         Screen::CharBuf &char_buf = screen.charBuf();
370
371 #ifdef DEBUG_OUTPUT
372         {
373                 my_fprintf(stderr,"_termText: '");
374                 int i = 0;
375                 for (;i!=n;++i) {
376                         my_fprintf(stderr,"%c",buf[i]);
377                 }
378                 my_fprintf(stderr,"'\n");
379         }
380 #endif
381         int i = 0;
382         for (;i!=n;++i) {
383                 char_buf.put(buf[i]);
384                 char_buf.advanceCursor();
385                 //my_fprintf(stderr,"cursor at %d,%d\n",char_buf.cursor().row(),char_buf.cursor().col());
386         }
387 }
388
389
390 void MyObject::_termVoid(TermOp_t op)
391 {
392         Screen::CharBuf &char_buf = screen.charBuf();
393
394         my_fprintf(stderr,"_termVoid: %s\n",TermState_OpName(op));
395         switch (op) {
396         case TERM_HOME_CURSOR:
397                 char_buf.homeCursor();
398                 break;
399         case TERM_CLEAR_BELOW:
400                 char_buf.clearToRight();
401                 char_buf.clearBelow();
402                 break;
403         case TERM_CLEAR_ABOVE:
404                 break;
405         case TERM_CLEAR_TO_RIGHT:
406                 char_buf.clearToRight();
407                 break;
408         case TERM_CLEAR_TO_LEFT:
409                 break;
410         case TERM_CLEAR_SCREEN:
411                 break;
412         case TERM_CLEAR_LINE:
413                 break;
414         case TERM_NORM_ATTR:
415                 char_buf.resetAttr();
416                 break;
417         case TERM_RESET:
418                 char_buf.reset();
419                 break;
420         case TERM_SAVE_CURSOR:
421                 break;
422         case TERM_RESTORE_CURSOR:
423                 break;
424         case TERM_BELL:
425                 break;
426         case TERM_BACKSPACE:
427                 char_buf.backSpaceCursor();
428                 break;
429         case TERM_TAB:
430                 break;
431         case TERM_CLEAR_TABS:
432                 break;
433         case TERM_CARRIAGE_RETURN:
434                 char_buf.carriageReturn();
435                 break;
436         case TERM_MOVE_UP:
437                 break;
438         case TERM_MOVE_DOWN:
439                 char_buf.moveCursorDown();
440                 break;
441         case TERM_EOF:
442                 break;
443         case TERM_BUFFER_EMPTY:
444                 break;
445         case TERM_REQ_ATTR:
446                 break;
447         case TERM_PRIMARY_FONT:
448                 break;
449         case TERM_ALTERNATE_FONT1:
450                 break;
451         case TERM_ALTERNATE_FONT2:
452                 break;
453         default:
454                 assert(0);
455         }
456 }
457
458
459 void MyObject::_termInt(TermOp_t op,int arg1)
460 {
461         Screen::CharBuf &char_buf = screen.charBuf();
462
463         my_fprintf(stderr,"_termInt: %s %d\n",TermState_OpName(op),arg1);
464         switch (op) {
465         case TERM_CURSOR_UP:
466                 char_buf.moveCursorUp(arg1);
467                 break;
468         case TERM_CURSOR_DOWN:
469                 char_buf.moveCursorDown(arg1);
470                 break;
471         case TERM_CURSOR_RIGHT:
472                 char_buf.moveCursorRight(arg1);
473                 break;
474         case TERM_CURSOR_LEFT:
475                 char_buf.moveCursorLeft(arg1);
476                 break;
477         case TERM_INSERT_LINE:
478                 break;
479         case TERM_DELETE_LINE:
480                 break;
481         case TERM_INSERT_CHAR:
482                 break;
483         case TERM_ERASE_CHAR:
484                 break;
485         case TERM_DELETE_CHAR:
486                 break;
487         case TERM_FGCOLOR_ATTR:
488                 char_buf.setFgColor(arg1);
489                 break;
490         case TERM_BGCOLOR_ATTR:
491                 char_buf.setBgColor(arg1);
492                 break;
493         case TERM_BOLD_ATTR:
494                 char_buf.setFlag(eBold, arg1);
495                 break;
496         case TERM_DIM_ATTR:
497                 char_buf.setFlag(eDim, arg1);
498                 break;
499         case TERM_ITALIC_ATTR:
500                 char_buf.setFlag(eItalics, arg1);
501                 break;
502         case TERM_UNDERLINE_ATTR:
503                 char_buf.setFlag(eUnderline, arg1);
504                 break;
505         case TERM_BLINK_ATTR:
506                 char_buf.setFlag(eBlink, arg1);
507                 break;
508         case TERM_INVERSE_ATTR:
509                 char_buf.setFlag(eInverse, arg1);
510                 break;
511         case TERM_APP_CURSOR_KEYS:
512                 key_manager.setAppCursorKeys(arg1);
513                 break;
514         default:
515                 break;
516         }
517 }
518
519
520 void MyObject::_termIntInt(TermOp_t op,int arg1,int arg2)
521 {
522         Screen::CharBuf &char_buf = screen.charBuf();
523
524         my_fprintf(stderr,"_termIntInt: %s %d %d\n",TermState_OpName(op),arg1,arg2);
525
526         switch (op) {
527         case TERM_SET_CURSOR:
528                 char_buf.setCursor(arg1,arg2);
529                 break;
530         case TERM_SET_SCROLL_REGION:
531                 char_buf.setScrollRegion(arg1,arg2);
532                 break;
533         default:
534                 break;
535         }
536 }
537
538
539 CommandHandlers MyObject::term_handlers;
540
541 void MyObject::checkSpawn()
542 {
543         if (spawn_data) {
544                 if (!Spawn_ReadMaster(spawn_data)) {
545                         spawn_data = 0;
546                 }
547         }
548 }
549
550 struct InstanceData {
551         //  NPP npp;
552         //  NPWindow window;
553         MyObject *object;
554         InstanceData() : object(0)
555         {
556         }
557 };
558
559 void logmsgv(const char* desc, NPPVariable variable)
560 {
561         my_fprintf(stderr, "term: %s - %s (#%i)\n", desc, varname(variable), variable);
562 }
563
564 static void
565 fillPluginFunctionTable(NPPluginFuncs* pFuncs)
566 {
567         pFuncs->version = 11;
568         pFuncs->size = sizeof(*pFuncs);
569         pFuncs->newp = NPP_New;
570         pFuncs->destroy = NPP_Destroy;
571         pFuncs->setwindow = NPP_SetWindow;
572         pFuncs->newstream = NPP_NewStream;
573         pFuncs->destroystream = NPP_DestroyStream;
574         pFuncs->asfile = NPP_StreamAsFile;
575         pFuncs->writeready = NPP_WriteReady;
576         pFuncs->write = NPP_Write;
577         pFuncs->print = NPP_Print;
578         pFuncs->event = NPP_HandleEvent;
579         pFuncs->urlnotify = NPP_URLNotify;
580         pFuncs->getvalue = NPP_GetValue;
581         pFuncs->setvalue = NPP_SetValue;
582 }
583
584 NP_EXPORT(NPError)
585 NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs)
586 {
587         my_fprintf(stderr,"term: NP_Initialize\n");
588         my_fprintf(stderr,"term: bFuncs->size=%d\n",bFuncs->size);
589         my_fprintf(stderr,"term: sizeof(NPNetscapeFuncs)=%d\n",sizeof(NPNetscapeFuncs));
590
591         NPNFuncs = *bFuncs;
592
593         fillPluginFunctionTable(pFuncs);
594
595         return NPERR_NO_ERROR;
596 }
597
598 NP_EXPORT(char*)
599 NP_GetPluginVersion()
600 {
601         my_fprintf(stderr, "term: NP_GetPluginVersion\n");
602         return (char *)PLUGIN_VERSION;
603 }
604
605 NP_EXPORT(char*)
606 NP_GetMIMEDescription()
607 {
608         my_fprintf(stderr,"term: NP_GetMIMEDescription\n");
609         return (char *)PLUGIN_MIMEDESCRIPTION;
610 }
611
612 NPObject *NPN_CreateObject(NPP npp, NPClass *aClass)
613 {
614         return NPNFuncs.createobject(npp, aClass);
615 }
616
617 void NPN_ForceRedraw(NPP npp)
618 {
619         return NPNFuncs.forceredraw(npp);
620 }
621
622 bool NPN_IdentifierIsString(NPIdentifier identifier)
623 {
624         return NPNFuncs.identifierisstring(identifier);
625 }
626
627 NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier)
628 {
629         return NPNFuncs.utf8fromidentifier(identifier);
630 }
631
632 static NPObject *Object_Allocate(NPP npp,NPClass *aClass)
633 {
634         return new MyObject(npp);
635 }
636
637 static void Object_Deallocate(NPObject *npobj)
638 {
639         my_fprintf(stderr,"term: In Object_Deallocate\n");
640         delete (MyObject *)npobj;
641 }
642
643 static bool
644 Object_Construct(
645                 NPObject *npobj,
646                 const NPVariant *args,
647                 uint32_t argCount,
648                 NPVariant *result
649 )
650 {
651         my_fprintf(stderr,"In Object_Construct\n");
652         return false;
653 }
654
655 static const SUPPORTED_OBJECTS *ContainsName(const char *callerName, const SUPPORTED_OBJECTS *list, NPIdentifier name)
656 {
657         my_fprintf(stderr,"%22s: ", callerName);
658         bool is_string = NPN_IdentifierIsString(name);
659         if (!is_string) {
660                 fprintf(stderr,"-- Identifier is not a string.\n");
661                 return NULL;
662         }
663         const char *name_str = NPN_UTF8FromIdentifier(name);
664         my_fprintf(stderr, " Identifier: %s",name_str);
665         for (const SUPPORTED_OBJECTS *me = list; me->key; me++)
666         {
667                 if(strcmp(name_str, me->key))
668                         continue;
669                 if(me->minArgs >= 0)
670                         my_fprintf(stderr, "(%s)\n", me->argsDesc);
671                 else
672                         my_fprintf(stderr, "\n");
673                 return me;
674         }
675         my_fprintf(stderr, " -- NOT found\n");
676         return NULL;
677 }
678
679
680 #ifdef DEBUG_OUTPUT
681 static void PrintValue(const NPVariant *arg)
682 {
683         if (NPVARIANT_IS_VOID(*arg)) {
684                 my_fprintf(stderr,"void");
685         }
686         else if (NPVARIANT_IS_NULL(*arg)) {
687                 my_fprintf(stderr,"null");
688         }
689         else if (NPVARIANT_IS_BOOLEAN(*arg)) {
690                 if (NPVARIANT_TO_BOOLEAN(*arg)) {
691                         my_fprintf(stderr,"true");
692                 }
693                 else {
694                         my_fprintf(stderr,"false");
695                 }
696         }
697         else if (NPVARIANT_IS_INT32(*arg)) {
698                 my_fprintf(stderr,"%d",NPVARIANT_TO_INT32(*arg));
699         }
700         else if (NPVARIANT_IS_DOUBLE(*arg)) {
701                 my_fprintf(stderr,"%g",NPVARIANT_TO_DOUBLE(*arg));
702         }
703         else if (NPVARIANT_IS_STRING(*arg)) {
704                 NPString value = NPVARIANT_TO_STRING(*arg);
705                 const NPUTF8 *chars = value.UTF8Characters;
706                 uint32_t len = value.UTF8Length;
707                 my_fprintf(stderr,"\"");
708                 {
709                         uint32_t i = 0;
710                         for (;i!=len;++i) {
711                                 my_fprintf(stderr,"%c",chars[i]);
712                         }
713                 }
714                 my_fprintf(stderr,"\"");
715         }
716         else if (NPVARIANT_IS_OBJECT(*arg)) {
717                 my_fprintf(stderr,"object");
718         }
719         else {
720                 my_fprintf(stderr,"unknown");
721         }
722 }
723 #endif
724
725
726 static void PrintArgs(const NPVariant *args,int argCount)
727 {
728 #ifdef DEBUG_OUTPUT
729         my_fprintf(stderr,"(");
730         int argnum = 0;
731         for (;argnum!=argCount;++argnum) {
732                 if (argnum!=0) {
733                         my_fprintf(stderr,",");
734                 }
735                 PrintValue(&args[argnum]);
736         }
737         my_fprintf(stderr,")");
738 #endif
739 }
740
741 static char* StringValue(const NPVariant *arg)
742 {
743         if (NPVARIANT_IS_STRING(*arg)) {
744                 NPString value = NPVARIANT_TO_STRING(*arg);
745                 const NPUTF8 *chars = value.UTF8Characters;
746                 uint32_t len = value.UTF8Length;
747                 char* shell = (char*)calloc(len,sizeof(char*));
748                 {
749                         uint32_t i = 0;
750                         for (;i!=len;++i) {
751                                 shell[i]= chars[i];
752                         }
753                 }
754                 return shell;
755         }
756         return NULL;
757 }
758
759
760 int IntValue(const NPVariant *value)
761 {
762         if (NPVARIANT_IS_INT32(*value)) {
763                 int32_t value_int32 = NPVARIANT_TO_INT32(*value);
764                 return value_int32;
765         }
766         else if (NPVARIANT_IS_DOUBLE(*value)) {
767                 double value_double = NPVARIANT_TO_DOUBLE(*value);
768                 return (int)value_double;
769         }
770         else if (NPVARIANT_IS_BOOLEAN(*value)) {
771                 bool value_bool = NPVARIANT_TO_BOOLEAN(*value);
772                 return (int)value_bool;
773         }
774         else if (NPVARIANT_IS_STRING(*value)) {
775                 const NPString &value_str = NPVARIANT_TO_STRING(*value);
776                 const char *value_chars = value_str.UTF8Characters;
777                 my_fprintf(stderr,"String is %s\n",value_chars);
778                 return (int)value_chars[0];
779         }
780         else {
781                 my_fprintf(stderr,"Expecting int, but got type %d\n",value->type);
782                 return 0;
783         }
784 }
785
786 #if 0
787 static bool BoolValue(const NPVariant *value)
788 {
789         if (NPVARIANT_IS_BOOLEAN(*value)) {
790                 bool value_bool = NPVARIANT_TO_BOOLEAN(*value);
791                 return value_bool;
792         }
793         else {
794                 return IntValue(value)!=0;
795         }
796 }
797 #endif
798
799 typedef enum
800 {
801         eMethod_sendEnter,
802         eMethod_setTerminalHeight,
803         eMethod_setFont,
804         eMethod_setColors,
805         eMethod_sendTap,
806         eMethod_initialize,
807         eMethod_start,
808         eMethod_redraw,
809         /*
810   eMethod_sendMouseDown,
811   eMethod_sendMouseUp,
812   eMethod_sendKeyUp,
813   eMethod_sendKeyPress,
814   eMethod_sendGestureStart,
815   eMethod_sendGestureEnd,
816   eMethod_sendGestureChange,
817   eMethod_test,
818          */
819 }eMethods;
820 const static SUPPORTED_OBJECTS supported_methods[] =
821 {
822                 { "sendEnter",               eMethod_sendEnter,                0,  "" },
823                 { "setTerminalHeight",       eMethod_setTerminalHeight,        1,  "height" },
824                 { "setFont",                 eMethod_setFont,                  2,  "width, height" },
825                 { "setColors",               eMethod_setColors,                2,  "fgColor, bgColor" },
826                 { "sendTap",                 eMethod_sendTap,                  2,  "x, y" },
827                 { "initialize",              eMethod_initialize,               0,  "" },                //      looks like it wont start w/o this method!!!
828                 { "start",                               eMethod_start,                            1,  "user" },
829                 { "redraw",                          eMethod_redraw,                   0,  "" },
830                 /*
831     { "sendMouseDown",           eMethod_sendMouseDown,            0,  "" },
832     { "sendMouseUp",             eMethod_sendMouseUp,              0,  "" },
833     { "sendKeyUp",               eMethod_sendKeyUp,                0,  "" },
834     { "sendKeyPress",            eMethod_sendKeyPress,             0,  "" },
835     { "sendGestureStart",        eMethod_sendGestureStart,         0,  "" },
836     { "sendGestureEnd",          eMethod_sendGestureEnd,           0,  "" },
837     { "sendGestureChange",       eMethod_sendGestureChange,        0,  "" },
838     { "test",                    eMethod_test,                     0,  "" },
839                  */
840                 { 0, 0, 0, 0 }
841 };
842
843 static bool Object_HasMethod(NPObject *npobj,NPIdentifier name)
844 {
845         return ContainsName("Object_HasMethod", supported_methods, name);
846 }
847
848 static bool
849 Object_Invoke(
850                 NPObject *npobj,
851                 NPIdentifier name,
852                 const NPVariant *args,
853                 uint32_t argCount,
854                 NPVariant *result
855 )
856 {
857         const SUPPORTED_OBJECTS *method = ContainsName("Object_Invoke", supported_methods, name);
858         if (!method)
859                 return false;
860         my_fprintf(stderr,"  Object_Invoke: %s", method->key);
861         PrintArgs(args,argCount);
862         my_fprintf(stderr,"\n");
863         if((int)argCount < method->minArgs)
864         {
865                 debugLog(__LINE__, "   wrong number of args for %s(%s), [requires:%d, found:%d]", method->key, method->argsDesc, method->minArgs, argCount);
866                 return false;
867         }
868         MyObject *myobj_ptr = (MyObject *)npobj;
869         assert(myobj_ptr);
870         MyObject &myobj = *myobj_ptr;
871         switch(method->id)
872         {
873         case eMethod_sendTap:
874                 myobj.event_x = IntValue(&args[0]);
875                 myobj.event_y = IntValue(&args[1]);
876                 NPN_ForceRedraw(myobj.instance);
877                 return true;
878         case eMethod_setFont:
879         {
880                 int width = IntValue(&args[0]);
881                 int height = IntValue(&args[1]);
882                 myobj.screen.setFont(width,height);
883                 FontInfo &font = myobj.screen.font();
884                 INT32_TO_NPVARIANT(font.char_height(), (*result));      // tell caller the height of the font
885                 my_fprintf(stderr,"  %s(%dx%d) result:%dx%d, returning:%d\n",method->key, width, height, font.char_width(), font.char_height(), font.char_height());
886                 return true;
887         }
888         case eMethod_setColors:
889         {
890                 int fgColor = IntValue(&args[0]);
891                 int bgColor = IntValue(&args[1]);
892                 myobj.screen.charBuf().setDefaultColors(fgColor, bgColor);
893                 //my_fprintf(stderr,"  %s(%d, %d)\n",method->key, fgColor, bgColor);
894                 return true;
895         }
896         case eMethod_setTerminalHeight:
897         {
898                 int terminalHeight = IntValue(&args[0]);
899                 //my_fprintf(stderr,"  setTerminalHeight(%d)\n",terminalHeight);
900                 myobj.screen.setVisibleHeightPixels(terminalHeight);
901                 return true;
902         }
903         case eMethod_start:
904         {
905                 myobj.start(StringValue(&args[0]));
906                 return true;
907         }
908         case eMethod_redraw:
909         {
910                 NPN_ForceRedraw(myobj.instance);
911                 return true;
912         }
913         case eMethod_sendEnter:
914                 myobj.key_manager.keyPressed(13,false,false,false,false);
915                 return true;
916         }
917
918         return false;
919 }
920
921 typedef enum
922 {
923         eProperty_event_x,
924         eProperty_event_y,
925         eProperty_scroller,
926         eProperty_keyStatesParentObj,
927         eProperty_test_property,
928 }eProperties;
929 const static SUPPORTED_OBJECTS supported_properties[] =
930 {
931                 { "event_x",                 eProperty_event_x,                -1,  "" },
932                 { "event_y",                 eProperty_event_y,                -1,  "" },
933                 { "scroller",                eProperty_scroller,               -1,  "" },
934                 { "keyStatesParentObj",      eProperty_keyStatesParentObj,     -1,  "" },
935                 { "test_property",           eProperty_test_property,          -1,  "" },
936                 { 0, 0, 0, 0 }
937 };
938 static bool Object_HasProperty(NPObject *npobj, NPIdentifier name)
939 {
940         return ContainsName("Object_HasProperty", supported_properties, name) ? true : false;
941 }
942
943 static bool
944 Object_SetProperty(
945                 NPObject *npobj,
946                 NPIdentifier name,
947                 const NPVariant *value
948 )
949 {
950         const SUPPORTED_OBJECTS *property = ContainsName("Object_SetProperty", supported_properties, name);
951         if (property)
952         {
953                 MyObject *myobj = (MyObject *)npobj;
954                 switch(property->id)
955                 {
956                 case eProperty_event_x:
957                         myobj->event_x = IntValue(value);
958                         my_fprintf(stderr,"  event_x set to %d\n",myobj->event_x);
959                         break;
960                 case eProperty_event_y:
961                         myobj->event_y = IntValue(value);
962                         my_fprintf(stderr,"  event_y set to %d\n",myobj->event_y);
963                         break;
964                 case eProperty_keyStatesParentObj:
965                         if(NPVARIANT_IS_OBJECT(*value))
966                                 {
967                                 myobj->keyStatesParentObj = NPVARIANT_TO_OBJECT(*value);
968                                 my_fprintf(stderr, "setting keyStatesParentObj:%p\n", myobj->keyStatesParentObj);
969                                 myobj->keyStatesParentObj = NPNFuncs.retainobject(myobj->keyStatesParentObj);
970                                 my_fprintf(stderr, "saving keyStatesParentObj:%p\n", myobj->keyStatesParentObj);
971                                 }
972                         else
973                                 my_fprintf(stderr, "scroller type:%d\n", value->type);
974                         break;
975                 case eProperty_scroller:
976                         if(NPVARIANT_IS_OBJECT(*value))
977                                 {
978                                 myobj->scroller = NPVARIANT_TO_OBJECT(*value);
979                                 my_fprintf(stderr, "setting scroller:%p\n", myobj->scroller);
980                                 myobj->scroller = NPNFuncs.retainobject(myobj->scroller);
981                                 my_fprintf(stderr, "saving scroller:%p\n", myobj->scroller);
982                                 }
983                         else
984                                 my_fprintf(stderr, "scroller type:%d\n", value->type);
985                         break;
986                 case eProperty_test_property:
987                 {
988                         int command = IntValue(value);
989                         my_fprintf(stderr,"  command=%d\n",command);
990                         if (command==2) {
991                                 NPN_ForceRedraw(myobj->instance);
992                         }
993                         break;
994                 }
995                 default:
996                         my_fprintf(stderr,"Invalid property\n");
997                         break;
998                 }
999         }
1000         return false;
1001 }
1002
1003 static NPObject *GetScriptableObject(NPP instance)
1004 {
1005         my_fprintf(stderr,"GetScriptableObject: instance=%p\n",instance);
1006         InstanceData *data = (InstanceData *)instance->pdata;
1007         if (!data->object) {
1008                 static NPClass object_class;
1009                 object_class.structVersion = NP_CLASS_STRUCT_VERSION;
1010                 object_class.allocate = Object_Allocate;
1011                 object_class.deallocate = Object_Deallocate;
1012                 object_class.invalidate = 0;
1013                 object_class.hasMethod = Object_HasMethod;
1014                 object_class.invoke = Object_Invoke;
1015                 object_class.invokeDefault = 0;
1016                 object_class.hasProperty = Object_HasProperty;
1017                 object_class.getProperty = 0;
1018                 object_class.setProperty = Object_SetProperty;
1019                 object_class.removeProperty = 0;
1020                 object_class.enumerate = 0;
1021                 object_class.construct = Object_Construct;
1022
1023                 data->object =
1024                         (MyObject *)NPN_CreateObject(
1025                                         instance,
1026                                         &object_class
1027                         );
1028         }
1029
1030         return data->object;
1031 }
1032
1033 NP_EXPORT(NPError)
1034 NP_GetValue(NPP instance, NPPVariable aVariable, void* aValue) {
1035
1036         switch (aVariable) {
1037         case NPPVpluginNameString:
1038                 *((const char**)aValue) = PLUGIN_NAME;
1039                 break;
1040         case NPPVpluginDescriptionString:
1041                 *((const char**)aValue) = PLUGIN_DESCRIPTION;
1042                 break;
1043         default:
1044                 return NPERR_INVALID_PARAM;
1045                 break;
1046         }
1047         return NPERR_NO_ERROR;
1048 }
1049
1050 NP_EXPORT(NPError)
1051 NP_Shutdown()
1052 {
1053         my_fprintf(stderr,"term: NP_Shutdown\n");
1054         return NPERR_NO_ERROR;
1055 }
1056
1057 NPError
1058 NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved) {
1059         instance->pdata = new InstanceData;
1060         my_fprintf(stderr,"term: NP_New\n");
1061         return NPERR_NO_ERROR;
1062 }
1063
1064 NPError
1065 NPP_Destroy(NPP instance, NPSavedData** save) {
1066         my_fprintf(stderr,"term: NPP_Destroy\n");
1067         InstanceData* instanceData = (InstanceData*)(instance->pdata);
1068         if (instanceData) {
1069                 delete instanceData;
1070         }
1071         return NPERR_NO_ERROR;
1072 }
1073
1074
1075 NPError
1076 NPP_SetWindow(NPP instance, NPWindow* window) {
1077         if (!window) {
1078                 // Destroying window
1079                 debugLog(__LINE__, "NPP_SetWindow(window:%p)", window);
1080                 return NPERR_NO_ERROR;
1081         }
1082         if (!window->window) {
1083                 debugLog(__LINE__, "NPP_SetWindow(window->window:%p)", window->window);
1084                 return NPERR_NO_ERROR;
1085         }
1086 #if 0
1087         debugLog(__LINE__, "NPP_SetWindow(x:%d, y:%d, width:%d, height:%d, type:%d)", window->x, window->y, window->width, window->height, window->type);
1088 #endif
1089
1090         InstanceData *data = (InstanceData *)instance->pdata;
1091         MyObject *myobj_ptr = data->object;
1092         if (!myobj_ptr) {
1093                 return NPERR_NO_ERROR;
1094         }
1095         Screen &screen = myobj_ptr->screen;
1096         if (!screen.setSizePixels(window->width, window->height)) {
1097                 return NPERR_NO_ERROR;
1098         }
1099         my_fprintf(stderr,"term: visibile size changed.\n");
1100         CharBuffer &char_buf = screen.charBuf();
1101         if (myobj_ptr->spawn_data) {
1102                 Spawn_Stty(
1103                         myobj_ptr->spawn_data,
1104                         char_buf.visibleHeight(),
1105                         char_buf.visibleWidth()
1106                 );
1107         }
1108         return NPERR_NO_ERROR;
1109 }
1110
1111
1112 NPError
1113 NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype) {
1114         my_fprintf(stderr,"term: NPP_NewStream\n");
1115         return NPERR_GENERIC_ERROR;
1116 }
1117
1118
1119 NPError
1120 NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason) {
1121         my_fprintf(stderr,"term: NPP_DestroyStream\n");
1122         return NPERR_GENERIC_ERROR;
1123 }
1124
1125 int32_t
1126 NPP_WriteReady(NPP instance, NPStream* stream) {
1127         my_fprintf(stderr,"term: NPP_WriteReady\n");
1128         return 0;
1129 }
1130
1131 int32_t
1132 NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer) {
1133         my_fprintf(stderr,"term: NPP_Write\n");
1134         return 0;
1135 }
1136
1137 void
1138 NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) {
1139         my_fprintf(stderr,"term: NPP_StreamAsFile\n");
1140 }
1141
1142 void
1143 NPP_Print(NPP instance, NPPrint* platformPrint) {
1144         my_fprintf(stderr,"term: NPP_Print\n");
1145 }
1146
1147
1148 void HandlePenMoveEvent(NpPalmPenEvent *penEvent,NPP instance)
1149 {
1150         my_fprintf(stderr,"HandlePenMoveEvent: x=%d, y=%d\n",penEvent->xCoord,penEvent->yCoord);
1151 }
1152
1153
1154 void HandleKeyEvent(NpPalmKeyEvent *keyEvent,NPP instance)
1155 {
1156         int key_code = keyEvent->rawkeyCode;
1157         int modifiers = keyEvent->rawModifier;
1158
1159         my_fprintf(
1160                         stderr,
1161                         "term: keyEvent key=%d, modifiers=%d\n",
1162                         key_code,
1163                         modifiers
1164         );
1165 #if 1
1166         InstanceData *data = (InstanceData *)instance->pdata;
1167         MyObject *myobj_ptr = data->object;
1168         if (!myobj_ptr) {
1169                 return;
1170         }
1171         MyObject &myobj = *myobj_ptr;
1172
1173         bool shift_pressed = (modifiers & 128)!=0;
1174         bool ctrl_pressed = (modifiers & 64)!=0;
1175         bool alt_pressed = false;
1176         bool meta_pressed = (modifiers & 32)!=0;
1177
1178         bool key_state_changed = myobj.key_manager.keyPressed(
1179                         key_code,shift_pressed,alt_pressed,ctrl_pressed,meta_pressed
1180         );
1181         //my_fprintf(stderr,"  keyEvent changed:%s\n", key_state_changed ? "true" : "false");
1182         if(key_state_changed)
1183                 {
1184         #ifdef USE_MOJO_FOR_KEYSTATE
1185                 //this.termplugin.keyStatesParentObj = this;
1186                 //this.keyStatesChanged(gesture, red, sym, shift)
1187                 if(myobj.keyStatesParentObj)
1188                         {
1189                         NPVariant args[4], result;
1190                         int argCount = 0;
1191                         INT32_TO_NPVARIANT(myobj.key_manager.getGestureHoldSstate(), args[argCount++]);
1192                         INT32_TO_NPVARIANT(myobj.key_manager.getRedState(), args[argCount++]);
1193                         INT32_TO_NPVARIANT(myobj.key_manager.getSymState(), args[argCount++]);
1194                         INT32_TO_NPVARIANT(myobj.key_manager.getShiftState(), args[argCount++]);
1195                         invokeObj(myobj.instance, myobj.keyStatesParentObj, "keyStatesChanged", args, argCount, &result);
1196                         }
1197         #else
1198                 NPN_ForceRedraw(myobj.instance);
1199         #endif
1200                 }
1201 #endif
1202 }
1203
1204 #ifndef USE_MOJO_FOR_KEYSTATE
1205 int write_key_state(PixelBuffer &pbuf, int x, PixelBuffer::Pixel foreground, PixelBuffer::Pixel background, const char *desc, int state)
1206 {
1207         if(state)
1208         {
1209                 if(state < 2 && *desc == '*')
1210                         desc++;         //      skip the '*', just show key-desc
1211                 x = pbuf.writeStrAbsoluteXY(x, 0, desc, foreground, background);
1212         }
1213         return x;
1214 }
1215 #endif
1216
1217 void HandleDrawEvent(NpPalmDrawEvent *drawEvent,NPP instance)
1218 {
1219         my_fprintf(stderr,"term: drawEvent sl: %i sr: %i st: %i sb: %i dl: %i dr: %i dt: %i db: %i drb:%i\n",
1220                         drawEvent->srcLeft,
1221                         drawEvent->srcRight,
1222                         drawEvent->srcTop,
1223                         drawEvent->srcBottom,
1224                         drawEvent->dstLeft,
1225                         drawEvent->dstRight,
1226                         drawEvent->dstTop,
1227                         drawEvent->dstBottom,
1228                         drawEvent->dstRowBytes
1229         );
1230         double start_time = CurrentTime();
1231         // PGContextIface *iface = (PGContextIface *) drawEvent->graphicsContext ;
1232         // iface->clearRect(5,5,20,20);
1233         unsigned int *screenBuffer = (unsigned int*) drawEvent->dstBuffer;
1234         // Draw a blue card - w00t
1235         // for(int i = 0 ;i < 320*480 ; i++) screenBuffer[i] = 0xaabbccdd ;
1236         InstanceData *data = (InstanceData *)instance->pdata;
1237         MyObject *myobj_ptr = data->object;
1238         if (!myobj_ptr) {
1239                 return;
1240         }
1241         MyObject &myobj = *myobj_ptr;
1242         pthread_mutex_lock(&myobj.draw_mutex);
1243         myobj.checkSpawn();
1244
1245         int dst_width = drawEvent->dstRight-drawEvent->dstLeft;
1246         int dst_height = drawEvent->dstBottom-drawEvent->dstTop;
1247
1248 #if 0
1249         const int screenWidth   = drawEvent->dstRowBytes / 4;
1250         int left        = max(0, drawEvent->dstLeft);
1251         int right       = min(screenWidth, drawEvent->dstRight);
1252         int top         = max(0, drawEvent->srcTop);
1253         int bottom      = drawEvent->srcBottom;
1254         debugLog(__LINE__, "HandleDrawEvent(sl:%i sr:%i st:%i sb:%i dl:%i dr:%i dt:%i db:%i drb:%i [top:%d left:%d bottom:%d right:%d screenWidth:%d] buf:%p myobj:%p)",
1255                         drawEvent->srcLeft,
1256                         drawEvent->srcRight,
1257                         drawEvent->srcTop,
1258                         drawEvent->srcBottom,
1259                         drawEvent->dstLeft,
1260                         drawEvent->dstRight,
1261                         drawEvent->dstTop,
1262                         drawEvent->dstBottom,
1263                         drawEvent->dstRowBytes,
1264                         top,
1265                         left,
1266                         bottom,
1267                         right,
1268                         screenWidth,
1269                         screenBuffer,
1270                         &myobj);
1271 #endif
1272
1273         FontInfo &font = myobj.screen.font();
1274         //debugLog(__LINE__, "font:%p", font);
1275         PixelBuffer pbuf(font, screenBuffer,dst_width,dst_height,drawEvent->dstRowBytes,drawEvent->srcTop);
1276         //debugLog(__LINE__, "pbuf:%p", &pbuf);
1277         //my_fprintf(stderr," ... Drawing before clear ... time: %g\n",CurrentTime()-start_time);
1278         //pbuf.clear(PixelBuffer::pixel(0,0,0));
1279         //my_fprintf(stderr," ... Drawing after clear ... time: %g\n",CurrentTime()-start_time);
1280
1281         {
1282                 Screen::CharBuf &char_buf = myobj.screen.charBuf();
1283                 //const int width = char_buf.width();
1284                 const int height = char_buf.height();
1285 #if 0
1286                 const int char_height = font.char_height();
1287                 const int char_width = font.char_width();
1288                 const int topRow = font.getLine(top);
1289                 int row = topRow, y = top - (topRow * line_height);
1290                 for (;row < height && y < bottom;++row, y += line_height) {
1291                         int col = 0, x;
1292                         for (x = left; col < width && x < right;++col, x += char_width) {
1293                                 pbuf.writeCharXY(x,y,char_buf.cell(row,col));
1294                         }
1295                 }
1296 #else
1297                 int begin_row = max(pbuf.topRow(),0);
1298                 int end_row = min(pbuf.bottomRow(),height);
1299                 {
1300                         int row = begin_row;
1301                         for (;row < end_row;++row) {
1302                                 assert(row<char_buf.height());
1303                                 pbuf.writeRow(row, char_buf);
1304                                 /*
1305                         int col = 0;
1306                         for (;col<width;++col) {
1307                                 pbuf.writeChar(row,col,char_buf.cell(row,col));
1308                         }
1309                                  */
1310                         }
1311                 }
1312                 //my_fprintf(stderr," ... Drawing cusror ... time: %g\n",CurrentTime()-start_time);
1313
1314                 assert(char_buf.currentRow()<char_buf.height());
1315                 pbuf.invertChar(char_buf.currentRow(),char_buf.currentCol());
1316 #endif
1317 #ifndef USE_MOJO_FOR_KEYSTATE
1318                 //my_fprintf(stderr," ... Drawing Keystate ... time: %g\n",CurrentTime()-start_time);
1319                 const int char_width = font.char_width();
1320                 int x = char_width;
1321                 PixelBuffer::Pixel foreground = colorRed;
1322                 PixelBuffer::Pixel background = colorYellow;
1323                 x = write_key_state(pbuf, x, foreground, background, "*Gesture ", myobj.key_manager.getGestureHoldSstate());
1324                 x = write_key_state(pbuf, x, foreground, background, "*Orange ", myobj.key_manager.getRedState());
1325                 x = write_key_state(pbuf, x, foreground, background, "*Sym ", myobj.key_manager.getSymState());
1326                 x = write_key_state(pbuf, x, foreground, background, "*Shift ", myobj.key_manager.getShiftState());
1327                 if(x != char_width)
1328                 {
1329                         pbuf.writeCharAbsoluteXY(0, 0, ' ', foreground, background);
1330                         //int y = font.char_height(), pixelsPerLine = (drawEvent->dstRowBytes / 4);
1331                         //unsigned int *o = screenBuffer + (y * pixelsPerLine);
1332                         //for(x = 0; x < pixelsPerLine; x++, o++)
1333                         //      *o = colorBlue;
1334                 }
1335 #endif
1336 #if 0
1337                 int cursor_y = cursor.row() * char_height;
1338                 int cursor_x = cursor.col() * char_width;
1339                 int add_y = (top % line_height);
1340                 debugLog(__LINE__, "cursor.row():%d, cursor_y:%d, top:%d, drawEvent->dstTop:%d, topRow:%d, line_height:%d, add_y:%d (%d)", cursor.row(), cursor_y, top, drawEvent->dstTop, topRow, line_height, add_y, cursor_y + add_y);
1341                 pbuf.invertCharXY(cursor_x, cursor_y + add_y - (add_y ? line_height : 0));
1342 #endif
1343         }
1344
1345         pthread_cond_signal(&myobj.drawn_cond);
1346         fprintf(stderr,"Done drawing\n");
1347         pthread_mutex_unlock(&myobj.draw_mutex);
1348         double end_time = CurrentTime();
1349         fprintf(stderr,"Drawing time: %g\n",end_time-start_time);
1350 }
1351
1352
1353 int16_t
1354 NPP_HandleEvent(NPP instance, void* aEvent) {
1355         NpPalmEventType *palmEvent = (NpPalmEventType *) aEvent;
1356         switch (palmEvent->eventType) {
1357         case npPalmPenDownEvent:
1358                 my_fprintf(stderr, "term: NPP_HandleEvent: npPalmPenDownEvent(x:%d, y:%d, mod:%d)\n", palmEvent->data.penEvent.xCoord, palmEvent->data.penEvent.yCoord, palmEvent->data.penEvent.modifiers);
1359                 break;
1360         case npPalmPenUpEvent:
1361                 my_fprintf(stderr, "term: NPP_HandleEvent: npPalmPenUpEvent(x:%d, y:%d, mod:%d)\n", palmEvent->data.penEvent.xCoord, palmEvent->data.penEvent.yCoord, palmEvent->data.penEvent.modifiers);
1362                 break;
1363         case npPalmPenMoveEvent:
1364                 my_fprintf(stderr, "term: NPP_HandleEvent: npPalmPenMoveEvent(x:%d, y:%d, mod:%d)\n", palmEvent->data.penEvent.xCoord, palmEvent->data.penEvent.yCoord, palmEvent->data.penEvent.modifiers);
1365                 HandlePenMoveEvent(&palmEvent->data.penEvent,instance);
1366                 break;
1367         case npPalmKeyDownEvent:
1368                 my_fprintf(stderr, "term: NPP_HandleEvent: npPalmKeyDownEvent(chr:%d, mod:%d, rawKey:%d, rawMod:%d)\n", palmEvent->data.keyEvent.chr, palmEvent->data.keyEvent.modifiers, palmEvent->data.keyEvent.rawkeyCode, palmEvent->data.keyEvent.rawModifier);
1369                 HandleKeyEvent(&palmEvent->data.keyEvent,instance);
1370                 break;
1371         case npPalmKeyUpEvent:
1372                 my_fprintf(stderr, "term: NPP_HandleEvent: npPalmKeyUpEvent(chr:%d, mod:%d, rawKey:%d, rawMod:%d)\n", palmEvent->data.keyEvent.chr, palmEvent->data.keyEvent.modifiers, palmEvent->data.keyEvent.rawkeyCode, palmEvent->data.keyEvent.rawModifier);
1373                 break;
1374         case npPalmKeyRepeatEvent:
1375                 my_fprintf(stderr, "term: NPP_HandleEvent: npPalmKeyRepeatEvent(chr:%d, mod:%d, rawKey:%d, rawMod:%d)\n", palmEvent->data.keyEvent.chr, palmEvent->data.keyEvent.modifiers, palmEvent->data.keyEvent.rawkeyCode, palmEvent->data.keyEvent.rawModifier);
1376                 break;
1377         case npPalmKeyPressEvent:
1378                 my_fprintf(stderr, "term: NPP_HandleEvent: npPalmKeyPressEvent(chr:%d, mod:%d, rawKey:%d, rawMod:%d)\n", palmEvent->data.keyEvent.chr, palmEvent->data.keyEvent.modifiers, palmEvent->data.keyEvent.rawkeyCode, palmEvent->data.keyEvent.rawModifier);
1379                 break;
1380         case npPalmDrawEvent:
1381                 HandleDrawEvent(&palmEvent->data.drawEvent,instance);
1382                 break;
1383         default:
1384                 my_fprintf(stderr, "term: NPP_HandleEvent: unknown\n");
1385                 break;
1386         }
1387         return 1;
1388 }
1389
1390 void
1391 NPP_URLNotify(NPP instance, const char* URL, NPReason reason, void* notifyData) {
1392         my_fprintf(stderr, "term: NPP_URLNotify\n");
1393 }
1394
1395 const char * varname(NPPVariable variable)
1396 {
1397         switch (variable) {
1398         case NPPVpluginNameString:
1399                 return "NPPVpluginNameString";
1400                 break;
1401         case NPPVpluginDescriptionString:
1402                 return "NPPVpluginDescriptionString";
1403                 break;
1404         case NPNVnetscapeWindow:
1405                 return "NPNVnetscapeWindow";
1406                 break;
1407         case NPPVpluginScriptableIID:
1408                 return "NPPVpluginScriptableIID";
1409                 break;
1410         case NPPVjavascriptPushCallerBool:
1411                 return "NPPVjavascriptPushCallerBool";
1412                 break;
1413         case NPPVpluginKeepLibraryInMemory:
1414                 return "NPPVpluginKeepLibraryInMemory";
1415                 break;
1416         case NPPVpluginScriptableNPObject:
1417                 return "NPPVpluginScriptableNPObject";
1418                 break;
1419         case NPPVpluginNeedsXEmbed:
1420                 return "NPPVpluginNeedsXEmbed";
1421                 break;
1422         case npPalmEventLoopValue:
1423                 return "npPalmEventLoopValue";
1424                 break;
1425         case npPalmCachePluginValue:
1426                 return "npPalmCachePluginValue";
1427                 break;
1428         case npPalmApplicationIdentifier:
1429                 return "npPalmApplicationIdentifier";
1430                 break;
1431         default:
1432                 return "unknown";
1433                 break;
1434         }
1435 }
1436
1437 NPError
1438 NPP_GetValue(NPP instance, NPPVariable variable, void *value) {
1439         logmsgv("NPP_GetValue",variable);
1440         switch (variable) {
1441         case NPPVpluginScriptableNPObject:
1442                 *(NPObject **)value = GetScriptableObject(instance);
1443                 break;
1444         default:
1445                 return NPERR_GENERIC_ERROR;
1446         }
1447         return NPERR_NO_ERROR;
1448 }
1449
1450 NPError
1451 NPP_SetValue(NPP instance, NPNVariable variable, void *value) {
1452         my_fprintf(stderr, "term: NPP_SetValue");
1453         // logmsgv("NPP_SetValue",variable);
1454         return NPERR_GENERIC_ERROR;
1455 }