sysd/src/display.c

Go to the documentation of this file.
00001 /*
00002  * File Name: display.c
00003  */
00004 
00005 /*
00006  * This file is part of sysd.
00007  *
00008  * sysd is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * sysd is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 /**
00023  * Copyright (C) 2008 iRex Technologies B.V.
00024  * All rights reserved.
00025  */
00026 
00027 //----------------------------------------------------------------------------
00028 // Include Files
00029 //----------------------------------------------------------------------------
00030 
00031 #include "config.h"
00032 
00033 // system include files, between < >
00034 #include <glib.h>
00035 #include <gtk/gtk.h>
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <fcntl.h>
00039 #include <sys/ioctl.h>
00040 #include <sys/time.h>
00041 #include <arpa/inet.h>
00042 #include <string.h>
00043 #include <pthread.h>
00044 
00045 // ereader include files, between < >
00046 #include <liberipc/eripc.h>
00047 #include <liberipc/eripc_support.h>
00048 #include <liberutils/display_utils.h>
00049 
00050 // local include files, between " "
00051 #include "log.h"
00052 #include "delta.h"
00053 #include "system.h"
00054 #include "tasks.h"
00055 #include "xwindow.h"
00056 #include "ipc.h"
00057 
00058 #define UNUSED(x) (void)(x)
00059 
00060 
00061 //----------------------------------------------------------------------------
00062 // Type Declarations
00063 //----------------------------------------------------------------------------
00064 
00065 // TCP port for incoming GTK messages
00066 #define DMPORT          50555
00067 #define LOCALHOST       0x7f000001L // "127.0.0.1"
00068 
00069 #define DM_MAXCHARONLINE 1024
00070 #define DM_CMD_NAME       128
00071 #define DM_ARGLENGTH      256
00072 #define DM_N_ARG           16
00073 
00074 // TCP port for incoming WM messages
00075 #define WMPORT          50556
00076 #define WM_NAME            64
00077 
00078 #define WAVEFORM_QUICK          6 // WAVEFORM_1BPP_IMAGE
00079 #define WAVEFORM_PARTIAL        9 // WAVEFORM_2BPP_IMAGE
00080 #define WAVEFORM_FULL           1 // WAVEFORM_4BPP_IMAGE
00081 
00082 // Times [ms] needed for the waveform playback during which delta is unavailable 
00083 #define DELTA_TIME_FULL         900*1000 
00084 // NOTE: not actual delay but this makes the soft keyboard act better
00085 #define DELTA_TIME_QUICK        50*1000                 
00086 
00087 typedef enum
00088 {
00089     DM_INFO,      // automically by GTK
00090     DM_FORCE,     // forced by application
00091     DM_UNDEFINED
00092 } DMCommandCode;
00093 
00094 typedef struct
00095 {
00096     int  pid;
00097     int  x, y;
00098     int  w, h;
00099     int  shouldIgnore;
00100     int  isWindow;
00101     int  windowType;
00102     char widgetType[64];
00103     int  isFocus;
00104 } DMCommandInfo;
00105 
00106 typedef struct
00107 {
00108     int  pid;
00109     int  takeControl;
00110     int  hint;
00111 } DMCommandForce;
00112 
00113 typedef struct
00114 {
00115     DMCommandCode cmd;
00116     DMCommandInfo info;
00117     DMCommandForce force;
00118 } DMCommand;
00119 
00120 typedef struct
00121 {
00122     char    name[DM_CMD_NAME]; // Command Name
00123     int     cc;             // Command Code
00124     char    arg[DM_N_ARG][DM_ARGLENGTH];
00125     int     nArg;
00126 } erDmCmd_t;
00127 
00128 typedef struct
00129 {
00130     char    name[WM_NAME];
00131     int     window;
00132     int     type;
00133     long    flags;
00134     int     pid;
00135 } WMInfo;
00136 
00137 
00138 typedef struct display_update_info DisplayUpdateInfo;
00139 typedef struct wave_info WaveInfo;
00140 typedef struct busy_info BusyInfo;
00141 
00142 // Client Struct State flags, taken from structs.h of Matchbox WM 1.2
00143 #define CLIENT_IS_SPLASH_WIN      (1<<0)
00144 #define CLIENT_FULLSCREEN_FLAG    (1<<1)
00145 #define CLIENT_TITLE_HIDDEN_FLAG  (1<<2)
00146 #define CLIENT_SHRUNK_FOR_TB_FLAG (1<<3)
00147 #define CLIENT_HELP_BUTTON_FLAG   (1<<4)
00148 #define CLIENT_ACCEPT_BUTTON_FLAG (1<<5)
00149 #define CLIENT_DOCK_NORTH         (1<<6)
00150 #define CLIENT_DOCK_SOUTH         (1<<7)
00151 #define CLIENT_DOCK_EAST          (1<<8)
00152 #define CLIENT_DOCK_WEST          (1<<9)
00153 #define CLIENT_WANTS_MASK_FLAG    (1<<10)
00154 #define CLIENT_IS_MODAL_FLAG      (1<<11)
00155 #define CLIENT_BORDERS_ONLY_FLAG  (1<<12)
00156 #define CLIENT_IS_MESSAGE_DIALOG  (1<<14)
00157 #define CLIENT_IS_DESKTOP_FLAG    (1<<15)
00158 #define CLIENT_NEW_FOR_DESKTOP    (1<<16)
00159 #define CLIENT_DOCK_TITLEBAR      (1<<17)
00160 #define CLIENT_CUSTOM_BUTTON_FLAG (1<<18)
00161 #define CLIENT_IS_MOVING          (1<<19)
00162 #define CLIENT_DOCK_TITLEBAR_SHOW_ON_DESKTOP (1<<20)
00163 #define CLIENT_NO_FOCUS_ON_MAP    (1<<21)
00164 #define CLIENT_IS_MINIMIZED       (1<<23)
00165 #define CLIENT_TOOLBARS_MOVED_FOR_FULLSCREEN (1<<24)
00166 #define CLIENT_IS_TRANSIENT_FOR_ROOT (1<<25)
00167 #define CLIENT_HAS_URGENCY_FLAG   (1<<26)
00168 #define CLIENT_HAS_ABOVE_STATE    (1<<27)
00169 #define CLIENT_IS_MENU_DIALOG     (1<<30)
00170 #define CLIENT_DELAY_MAPPING      (1<<31)
00171 
00172 // Client window types, taken from structs.h of Matchbox WM 1.2
00173 typedef enum 
00174 { 
00175   MBCLIENT_TYPE_DIALOG    = (1<<1),
00176   MBCLIENT_TYPE_TOOLBAR   = (1<<2),
00177   MBCLIENT_TYPE_PANEL     = (1<<3),
00178   MBCLIENT_TYPE_TASK_MENU = (1<<4),
00179   MBCLIENT_TYPE_APP       = (1<<5),
00180   MBCLIENT_TYPE_DESKTOP   = (1<<6),
00181   MBCLIENT_TYPE_OVERRIDE  = (1<<7),
00182   MBCLIENT_TYPE_ANY       = (1<<8)
00183 } MBClientTypeEnum;
00184 
00185 
00186 //----------------------------------------------------------------------------
00187 // Constants
00188 //----------------------------------------------------------------------------
00189 
00190 #define N_FILENAME              1024
00191 #define BUFFERSIZE              1024
00192 #define BUSY_ANIMATION_SPEED    50
00193 
00194 #if MACHINE_IS_DR800SG || MACHINE_IS_DR800S || MACHINE_IS_DR800SW
00195 #define UPDATE_TIMEOUT_FORCED              50
00196 #define UPDATE_TIMEOUT_NORMAL_PORTRAIT    300 /* can be quicker but increases double updates */
00197 #define UPDATE_TIMEOUT_NORMAL_LANDSCAPE   600
00198 #define UPDATE_TIMEOUT_KEY                 24
00199 #define UPDATE_TIMEOUT_CURSOR              60 /* can be quicker but makes successive updates slower */
00200 #define UPDATE_TIMEOUT_TYPE                60 /* can be quicker but makes successive updates slower */
00201 #define UPDATE_TIMEOUT_SCRIBBLE           150 /* can be quicker but makes successive updates slower */
00202 #define UPDATE_AREA_CONTENT               744*806
00203 #define UPDATE_AREA_FULL                  768*1024
00204 #elif MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
00205 #define UPDATE_TIMEOUT_FORCED              80
00206 #define UPDATE_TIMEOUT_NORMAL_PORTRAIT    450 /* can be quicker but increases double updates */
00207 #define UPDATE_TIMEOUT_NORMAL_LANDSCAPE   900
00208 #define UPDATE_TIMEOUT_KEY                 40
00209 #define UPDATE_TIMEOUT_CURSOR             100 /* can be quicker but makes successive updates slower */
00210 #define UPDATE_TIMEOUT_TYPE               100 /* can be quicker but makes successive updates slower */
00211 #define UPDATE_TIMEOUT_SCRIBBLE           250 /* can be quicker but makes successive updates slower */
00212 #define UPDATE_AREA_CONTENT               1000*1010
00213 #define UPDATE_AREA_FULL                  1024*1280
00214 #else
00215 #error Unhandled machine type
00216 #endif
00217 
00218 
00219 //----------------------------------------------------------------------------
00220 // Static Variables
00221 //----------------------------------------------------------------------------
00222 
00223 static int       fbDev                  = 0;
00224 static int       useSpecialWaveform     = 0;
00225 static DMCommand DisplayCommand;
00226 static WMInfo    WindowInfo;
00227 static uint64_t  deltaAvailableAgain    = 0;
00228 static GSList    *g_ignorelist          = NULL;
00229 
00230 static int      g_ctb_window            = 0;
00231 static int      g_prev_window           = 0;
00232 static gboolean g_display_locked        = FALSE;
00233 static gboolean g_vcom_is_set           = FALSE;
00234 
00235 static pthread_t dm_thread;
00236 static struct timeval g_timeout;
00237 
00238 
00239 //============================================================================
00240 // Local Function Definitions
00241 //============================================================================
00242 
00243 static gboolean handle_gtk_socket   (GIOChannel* source, GIOCondition condition, gpointer data);
00244 static gint parse_message           (char *szCommand, erDmCmd_t *pCmd);
00245 static gint parse_command           (erDmCmd_t *pCmd, DMCommand *command);
00246 static void get_arguments           (char *pChar, erDmCmd_t * pCmd, int nReqArgs);
00247 static void on_message_timeout      (void);
00248 static void* gtk_messages           (void *arg);
00249 static void display_update          (gint waveform);
00250 static void schedule_update         (gint delay, const char *rule);
00251 
00252 static gint delta_vcom_set          (gfloat vcom);
00253 static int  delta_uploadwave        (char *filename, glong offset);
00254 static gint delta_erase             (gint color);
00255 static gint delta_update_display    (DisplayUpdateInfo *displayUpdateInfo);
00256 static gint delta_busy              (gint xpos, gint ypos, gint speed);
00257 static void delta_init              (void);
00258 
00259 static gboolean ignore_pid          (gint pid);
00260 static void ignore_pid_add          (gint pid);
00261 static void ignore_pid_remove       (gint pid);
00262 
00263 static gboolean locked_display      (void) { return g_display_locked; }
00264 static void lock_display            (void) { g_display_locked = TRUE; }
00265 static void unlock_display          (void) { g_display_locked = FALSE; }
00266 
00267 
00268 //============================================================================
00269 // Functions Implementation
00270 //============================================================================
00271 
00272 static void parse_wm_messages(char* buffer)
00273 {
00274     // handle single message
00275     gchar **args = g_strsplit_set(buffer, ",", 4);
00276 
00277     gint window = atoi(args[0]);
00278     gint type   = atoi(args[1]);
00279     glong flags  = atol(args[2]);
00280     gchar *endp   = strchr(args[3], ' ');
00281     if (endp) {
00282         *endp = '\0';
00283     }
00284     gchar *name   = args[3];
00285 
00286     proc_t *proc = process_get_by_name(name);
00287 
00288     if ( ((type & MBCLIENT_TYPE_DIALOG) == MBCLIENT_TYPE_DIALOG) &&
00289          ((flags & CLIENT_IS_MENU_DIALOG) != CLIENT_IS_MENU_DIALOG) )
00290     {
00291         DMPPRINTF("ignored dialog, window [%d] name [%s] pid [%d]", WindowInfo.window, name, proc ? proc->pid : -1);
00292     }
00293     else
00294     {
00295         if ( (g_prev_window != window) &&
00296              ((flags & CLIENT_IS_MENU_DIALOG) != CLIENT_IS_MENU_DIALOG) )
00297         {
00298             LOGPRINTF("changed window and not menu, deactivate previous: %d", g_prev_window);
00299 
00300             // new window set as foreground, send deactivated to window
00301             if (g_prev_window > 0)
00302             {
00303                 const gchar *service = task_service_by_window(g_prev_window);
00304                 if (service)
00305                 {
00306                     ipc_send_window_deactivated(service,  g_prev_window);
00307                 }
00308                 else if (g_ctb_window != 0 && g_prev_window == g_ctb_window)
00309                 {
00310                     ipc_send_window_deactivated("com.irexnet.ctb", g_ctb_window);
00311                 }
00312             }
00313 
00314             if (window > 0)
00315             {
00316                 // send activatedWindow to window's application
00317                 const gchar *service = task_service_by_window(window);
00318                 if (service)
00319                 {
00320                     ipc_send_window_activated(service, window);
00321                 }
00322                 else if (g_ctb_window != 0 && window == g_ctb_window)
00323                 {
00324                     ipc_send_window_activated("com.irexnet.ctb", g_ctb_window);
00325                 }
00326             }
00327             g_prev_window = window;
00328         }
00329 
00330         // set current window info
00331         strncpy(WindowInfo.name, name, WM_NAME);
00332         WindowInfo.name[WM_NAME-1] = '\0';
00333         WindowInfo.window = window;
00334         WindowInfo.type   = type;
00335         WindowInfo.flags  = flags;
00336         WindowInfo.pid    = proc ? proc->pid : -1;
00337 
00338         DMPPRINTF("set window info [%d] type [%d] flags [%ld] name [%s] pid [%d]",
00339                   WindowInfo.window, WindowInfo.type, WindowInfo.flags, WindowInfo.name,
00340                   WindowInfo.pid);
00341     }
00342 
00343     // force next update to be full screen
00344     useSpecialWaveform = WAVEFORM_FULL;
00345 
00346     g_strfreev(args);
00347 }
00348 
00349 
00350 gboolean handle_wm_socket(GIOChannel* source, GIOCondition condition, gpointer data)
00351 {
00352     UNUSED(data);
00353     
00354     if (condition != G_IO_IN) {
00355         WARNPRINTF("%s() UNKNOWN CONDITION (%d)", __func__, condition);
00356         return FALSE;
00357     }
00358 
00359     gchar* buffer = NULL;
00360     gsize bytes_read = 0;
00361     gsize last_byte = 0;
00362     GError *error = NULL;
00363     g_io_channel_read_line(source, &buffer, &bytes_read, &last_byte, &error);
00364     buffer[last_byte] = 0;
00365     if (error) {
00366         WARNPRINTF("WM socket read failed: %s", error->message);
00367         g_error_free(error);
00368     } else {
00369         parse_wm_messages(buffer);
00370     }
00371     g_free(buffer);
00372     return TRUE;    // keep listening
00373 }
00374 
00375 
00376 void display_set_services()
00377 {
00378     LOGPRINTF("entry");
00379     
00380     if (pthread_create(&dm_thread, NULL, gtk_messages, NULL) != 0)
00381     {
00382         ERRORPRINTF("Could not create thread");
00383         return;
00384     }
00385 
00386     // add GIOChannel for WM socket
00387     //
00388     int sockfd = socket(PF_INET, SOCK_DGRAM, 0);
00389     if (sockfd == -1) {
00390         perror("Error invoking socket");
00391         return;
00392     }
00393     bzero(&WindowInfo, sizeof(WMInfo));
00394     struct sockaddr_in server_addr;
00395     bzero(&server_addr, sizeof(struct sockaddr_in));
00396     server_addr.sin_family = AF_INET;
00397     server_addr.sin_port = htons(WMPORT);
00398     server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
00399     memset(server_addr.sin_zero, 0, sizeof(server_addr.sin_zero));
00400 
00401     int error = bind(sockfd, &server_addr, sizeof(server_addr));
00402     if (error) {
00403         perror("Error invoking bind");
00404         return;
00405     }
00406     GIOChannel* channel = g_io_channel_unix_new(sockfd);
00407     g_io_channel_set_encoding(channel, NULL, NULL);
00408     g_io_add_watch(channel, G_IO_IN|G_IO_PRI|G_IO_ERR, handle_wm_socket, NULL);
00409 }
00410 
00411 
00412 void display_blank(void)
00413 {
00414     LOGPRINTF("entry");
00415 
00416     // cancel scheduled dislay update 
00417     if (g_timeout.tv_sec > 0 || g_timeout.tv_usec > 0) 
00418     { 
00419         bzero(&DisplayCommand, sizeof(DMCommand));
00420         g_timeout.tv_sec = -1;
00421         g_timeout.tv_usec = -1;
00422     }
00423 
00424     // clear display
00425     delta_erase(15);   
00426 }
00427 
00428 
00429 void display_busy_animation(gint xpos, gint ypos)
00430 {
00431     LOGPRINTF("entry: x %d, y %d", xpos, ypos);
00432     delta_busy(xpos, ypos, BUSY_ANIMATION_SPEED);
00433 }
00434 
00435 
00436 gchar *display_get_active_window(void)
00437 {
00438     LOGPRINTF("entry");
00439     return WindowInfo.name;
00440 }
00441 
00442 
00443 void display_cleanup_pid(gint pid)
00444 {
00445     LOGPRINTF("entry");
00446     ignore_pid_remove(pid);    
00447 }
00448 
00449 
00450 void display_set_vcom(gfloat vcom)
00451 {
00452     LOGPRINTF("entry [%f]", vcom);
00453     delta_vcom_set(vcom);
00454 }
00455 
00456 
00457 void display_set_waveforms(void)
00458 {
00459     LOGPRINTF("entry");
00460     delta_uploadwave("/var/tmp/waves", 0);
00461 }
00462 
00463 
00464 void display_init(void)
00465 {
00466     LOGPRINTF("entry");
00467     delta_init();
00468 }
00469 
00470 
00471 //============================================================================
00472 // Local Function Implementation
00473 //============================================================================
00474 
00475 static uint64_t getCurrentTime() 
00476 {
00477     struct timespec now;
00478 
00479     clock_gettime(CLOCK_MONOTONIC, &now);
00480     u_int64_t now64 = now.tv_sec;
00481     now64 *= 1000000;
00482     now64 += (now.tv_nsec/1000);
00483     return now64;
00484 }
00485 
00486 
00487 static gboolean ignore_pid(gint pid)
00488 {
00489     // just test if ANY pid ignored
00490     return (g_slist_length(g_ignorelist) > 0);
00491 }
00492 
00493 
00494 static void ignore_pid_add(gint pid)
00495 {
00496     LOGPRINTF("entry [%d]", pid);
00497 
00498     GSList *found = g_slist_find(g_ignorelist, (gconstpointer) pid);
00499     if (found == NULL) 
00500     {
00501         LOGPRINTF("added [%d]", pid);
00502         g_ignorelist = g_slist_prepend(g_ignorelist, (gpointer) pid);
00503     }
00504 }
00505 
00506 
00507 static void ignore_pid_remove(gint pid)
00508 {
00509     LOGPRINTF("entry [%d]", pid);
00510     g_ignorelist = g_slist_remove(g_ignorelist, (gpointer) pid);
00511 }
00512 
00513 
00514 static void promote_waveform(gint waveform)
00515 {
00516     if (useSpecialWaveform == waveform)
00517         return;
00518     
00519     switch (waveform)
00520     {
00521     case WAVEFORM_QUICK: 
00522         if (useSpecialWaveform == 0)
00523         {
00524             useSpecialWaveform = waveform;
00525         }
00526         break;
00527                 
00528     case WAVEFORM_PARTIAL: 
00529         if ((useSpecialWaveform == 0) || (useSpecialWaveform  == WAVEFORM_QUICK))
00530         {
00531             useSpecialWaveform = waveform;
00532         }
00533         break;
00534                 
00535     case WAVEFORM_FULL: 
00536     default: 
00537         useSpecialWaveform = waveform;
00538         break;
00539     }
00540 }
00541 
00542 
00543 static void parse_gtk_message(char* buffer)
00544 {    
00545 //    LOGPRINTF("entry");
00546 
00547 #if DMLOGGING_ON
00548     static GTimeVal   oldtime = {0};
00549 #endif    
00550     erDmCmd_t  cmd;
00551     DMCommand  command;
00552     bzero(&command, sizeof(command));
00553 
00554     if ((parse_message(buffer, &cmd)==0) && (parse_command(&cmd, &command) == 0))
00555     {
00556 #if DMLOGGING_ON
00557         GTimeVal curtime;
00558         g_get_current_time(&curtime);
00559         
00560         guint timediff = ((curtime.tv_sec - oldtime.tv_sec) * 1000) + 
00561             ((curtime.tv_usec / 1000 ) - (oldtime.tv_usec / 1000));
00562 #endif
00563 
00564         if (command.cmd == DM_FORCE)
00565         {
00566             DMCommandForce force = command.force;
00567             
00568             DMPPRINTF("%ld:%3ld [%4d] checking msg: %d, %d, %d", 
00569                 curtime.tv_sec, curtime.tv_usec / 1000, timediff, 
00570                 force.pid, force.takeControl, force.hint); 
00571 
00572             if (force.takeControl > 0)
00573             {
00574                 DMPPRINTF(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
00575                 ignore_pid_add(force.pid);
00576                 if (!locked_display() && (g_timeout.tv_sec > 0 || g_timeout.tv_usec > 0))
00577                 {
00578                     // cancel pending update
00579                     DMPPRINTF("cancel pending update");
00580                     bzero(&DisplayCommand, sizeof(DMCommand));
00581                     g_timeout.tv_sec = -1;
00582                     g_timeout.tv_usec = -1;
00583                 }
00584             }
00585             else
00586             {
00587                 DMPPRINTF("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
00588                 ignore_pid_remove(force.pid);
00589             }
00590             
00591             if (force.hint != DM_HINT_NONE)
00592             {
00593                 gint update_delay = UPDATE_TIMEOUT_FORCED;
00594                 switch (force.hint)
00595                 {
00596                     case DM_HINT_LOCK:
00597                         lock_display();
00598                         break;
00599                     case DM_HINT_UNLOCK:
00600                         unlock_display();
00601                         break;
00602                     case DM_HINT_FULL:
00603                     case DM_HINT_SPLASH:
00604                         useSpecialWaveform = WAVEFORM_FULL;
00605                         break;
00606                     case DM_HINT_CURSOR:
00607                         useSpecialWaveform = WAVEFORM_QUICK;
00608                         break;
00609                     case DM_HINT_PARTIAL:
00610                         useSpecialWaveform = WAVEFORM_PARTIAL;
00611                         break;
00612                     case DM_HINT_KEY:
00613                         update_delay = 20;
00614                         useSpecialWaveform = WAVEFORM_QUICK;
00615                         break;
00616                     default:
00617                         WARNPRINTF("unsupported display manager hint [%d]", force.hint);
00618                         useSpecialWaveform = WAVEFORM_FULL;
00619                         break;
00620                 }
00621 
00622                 if (sys_get_orientation() != ORIENTATION_PORTRAIT)
00623                 {
00624                     // account for slower updates when display is rotated
00625                     switch (force.hint)
00626                     {
00627                         case DM_HINT_FULL:
00628                             update_delay = UPDATE_TIMEOUT_NORMAL_LANDSCAPE;
00629                             break;
00630                         case DM_HINT_SPLASH:
00631                             // splash screens are shown in portrait mode
00632                             update_delay = UPDATE_TIMEOUT_NORMAL_PORTRAIT; 
00633                             break;
00634                         case DM_HINT_PARTIAL:
00635                             update_delay = UPDATE_TIMEOUT_NORMAL_LANDSCAPE;
00636                             break;
00637                         case DM_HINT_CURSOR:
00638                         case DM_HINT_KEY:
00639                             update_delay = 150;
00640                             break;
00641                         case DM_HINT_LOCK:
00642                         case DM_HINT_UNLOCK:
00643                             break;
00644                         default:
00645                             WARNPRINTF("unsupported display manager hint [%d]", force.hint);
00646                             break;
00647                     }
00648                 }
00649 
00650                 if ( (!locked_display() && !(force.hint == DM_HINT_UNLOCK)) || (force.hint == DM_HINT_SPLASH)  )
00651                 {
00652                     schedule_update(update_delay, "forced by application");
00653                 }
00654             }
00655         }
00656         else if (command.cmd == DM_INFO) 
00657         {
00658             DMCommandInfo  info  = command.info;
00659             const gchar   *rule        = NULL;
00660             gboolean      save         = FALSE;
00661             gboolean      trigger      = FALSE;
00662             gboolean      skip         = FALSE;
00663             guint         area_pending = DisplayCommand.info.w * DisplayCommand.info.h;
00664             gboolean      is_portait   = (sys_get_orientation() == ORIENTATION_PORTRAIT) ? TRUE : FALSE;
00665             gboolean      is_pending   = (area_pending > 0) ? TRUE : FALSE;
00666             guint      delay        = is_portait ? UPDATE_TIMEOUT_NORMAL_PORTRAIT : UPDATE_TIMEOUT_NORMAL_LANDSCAPE;
00667             guint         area         = info.w * info.h;
00668             
00669             if ((info.pid != -1) && ignore_pid(info.pid) && 
00670                 (strcmp(info.widgetType,"erGtkBusyDialog") != 0) && (strcmp(info.widgetType,"GtkMessageDialog") != 0))
00671             {
00672                 // skip updates when busy or loading dialog is shown
00673                 skip = TRUE;
00674             }
00675 
00676             DMPPRINTF("%ld:%3ld [%4d] %s pid [%d] %4dx%4d flags: i[%d] w[%d] t[%d] f[%d] %s",
00677                 curtime.tv_sec, curtime.tv_usec / 1000, timediff, skip ? "SKIPPED" : "checking", 
00678                 info.pid, info.w, info.h, info.shouldIgnore,
00679                 info.isWindow, info.windowType, info.isFocus,
00680                 info.widgetType);
00681             
00682             //
00683             // SPECIAL RULES - pre
00684             //
00685            
00686             if (!is_pending && info.h == 32 &&
00687                 strcmp(info.widgetType, "GtkEventBox") == 0)
00688             {
00689                 rule = "statusbar";
00690                 promote_waveform(WAVEFORM_PARTIAL);
00691                 save  = TRUE;
00692             }
00693 
00694             if (!is_pending && strcmp(info.widgetType,"GtkEntry")==0)
00695             {
00696                 rule = "keyboard entry";
00697                 promote_waveform( WAVEFORM_QUICK);
00698                 delay = UPDATE_TIMEOUT_TYPE;
00699                 save  = TRUE;
00700             }
00701             
00702             //
00703             // GENERAL RULES
00704             //
00705 
00706             if (!info.shouldIgnore ||
00707                 (strcmp(info.widgetType,"HtmlView")         == 0) || /* for libgtkhtml */
00708                 (strcmp(info.widgetType,"GtkDrawingArea")   == 0) ||
00709                 (strcmp(info.widgetType,"GtkCalendar")      == 0) ||
00710                 (strcmp(info.widgetType,"GtkTreeView")      == 0) ||
00711                 (strcmp(info.widgetType,"GtkIconView")      == 0) ||
00712                 (strcmp(info.widgetType,"erGtkIconView")    == 0) ||
00713                 (strcmp(info.widgetType,"erGtkListView")    == 0) ||
00714                 (strcmp(info.widgetType,"erGtkNetworkList") == 0) ||
00715                 (strcmp(info.widgetType,"WebKitWebView")    == 0) ||
00716                 (strcmp(info.widgetType,"GtkMenu")          == 0) ||
00717                 (strcmp(info.widgetType,"GtkProgressBar")   == 0) )
00718             {
00719                 if (!is_pending &&
00720                     info.isFocus && 
00721                     (area<UPDATE_AREA_CONTENT) &&
00722                     ((strcmp(info.widgetType, "erGtkIconView") == 0) ||
00723                      (strcmp(info.widgetType, "erGtkNetworkList") == 0) ||
00724                      (strcmp(info.widgetType, "erGtkListView") == 0)) ) 
00725                 {
00726                     rule = "cursor";
00727                     promote_waveform(WAVEFORM_QUICK);
00728                     delay = is_portait ? UPDATE_TIMEOUT_CURSOR : 3*UPDATE_TIMEOUT_CURSOR;
00729                     save  = TRUE;
00730                 }
00731                 else if (strcmp(WindowInfo.name, "erbrowser") == 0)
00732                 {
00733                     if ( !((strcmp(info.widgetType, "GtkWindow") == 0) && is_pending)
00734                         && ((area * 3) < UPDATE_AREA_FULL) )
00735                     {
00736                         rule = "paint, partial (browser)";
00737                         promote_waveform(WAVEFORM_PARTIAL);
00738                     }
00739                     else
00740                     {
00741                         rule = "paint, full (browser)";
00742                         promote_waveform(WAVEFORM_FULL);
00743                         delay = 1000;
00744                     }
00745                     save = TRUE;
00746                 }
00747                 else if (area > area_pending)
00748                 {
00749                     if ((area * 3) < UPDATE_AREA_FULL)
00750                     {
00751                         promote_waveform(WAVEFORM_PARTIAL);
00752                         rule = "paint, partial";
00753                     }
00754                     else
00755                     {
00756                         promote_waveform(WAVEFORM_FULL);
00757                         rule = "paint, full";
00758                         
00759                         if (is_portait && strcmp(info.widgetType,"GtkDrawingArea") == 0)
00760                         {
00761                             rule = "paint, full (UDS)";
00762                             delay /= 2;
00763                         }
00764                     }
00765                     save = TRUE;
00766                 }
00767                 else if (is_pending)
00768                 {
00769                     if (is_portait && strcmp(info.widgetType,"erGtkIconView")  == 0)
00770                     {
00771                         delay /= 2;
00772                     }
00773                     rule    = "delay";
00774                     trigger = TRUE;
00775                 }
00776             }
00777             
00778             //
00779             // SPECIAL RULES - post - override general rules
00780             //
00781            
00782             if (!is_pending && info.h == 29 && 
00783                 ((strcmp(info.widgetType,"GtkMessageDialog")==0) ||
00784                  (strcmp(info.widgetType,"GtkDialog")==0)))
00785             {
00786                 rule = "button cursor";
00787                 useSpecialWaveform = WAVEFORM_QUICK;
00788                 delay = is_portait ? UPDATE_TIMEOUT_CURSOR : 2*UPDATE_TIMEOUT_CURSOR;
00789                 save  = TRUE;
00790             }
00791             
00792             if (!is_pending && strcmp(info.widgetType,"erscribble")==0)
00793             {
00794                 rule = "scribble";
00795                 useSpecialWaveform = WAVEFORM_PARTIAL;
00796                 delay = UPDATE_TIMEOUT_SCRIBBLE;
00797                 save  = TRUE;
00798             }
00799             
00800             // NOTE: check is_pending
00801             if (is_pending && 
00802                 (useSpecialWaveform != WAVEFORM_FULL) &&
00803                 ( (strcmp(info.widgetType, "WebKitWebView")==0) ||
00804                   (strcmp(info.widgetType, "GtkEntry")==0) ) )
00805             {
00806                 rule = "entry speedup";
00807                 save = FALSE;
00808                 delay /= 2;
00809                 trigger = FALSE;
00810             }
00811             
00812             //
00813             // Save command and (re)set timeout
00814             //
00815             
00816             if (save)
00817             {
00818                 DMPPRINTF("%ld:%3ld save area %d (rule: %s)", curtime.tv_sec, curtime.tv_usec / 1000, area, rule);
00819                 
00820                 memcpy(&DisplayCommand, &command, sizeof(DMCommand));
00821                 trigger = TRUE;
00822             }
00823                 
00824             if (trigger && !skip)
00825             {
00826                 schedule_update(delay, rule);
00827             }
00828         }
00829 #if DMLOGGING_ON
00830         memcpy(&oldtime, &curtime, sizeof(GTimeVal));
00831 #endif                
00832     }
00833 }
00834 
00835 
00836 static void schedule_update(gint mdelay, const char *rule)
00837 {
00838     gulong udelay;
00839     
00840     // check if sending screen updates too fast
00841     uint64_t now = getCurrentTime();
00842 #if DMLOGGING_ON
00843     guint prev_delay = mdelay;
00844 #endif                
00845     // adjust delay to after delta is available again
00846     // except when time was set back as deltaAvailableAgain can't be trusted then
00847     if (((deltaAvailableAgain != 0) && ((now + mdelay*1000) < deltaAvailableAgain))
00848         && ((deltaAvailableAgain - DELTA_TIME_FULL) < now))
00849     {
00850         udelay = (deltaAvailableAgain - now);
00851     }
00852     else
00853     {
00854         udelay = mdelay * 1000;
00855     }
00856 
00857     // set new timeout
00858     g_timeout.tv_sec  = udelay / G_USEC_PER_SEC;
00859     g_timeout.tv_usec = udelay % G_USEC_PER_SEC;
00860     
00861     DMPPRINTF("set delay %ld.%03d [was 0.%03d] (rule: %s)", g_timeout.tv_sec, g_timeout.tv_usec/1000, prev_delay, rule);
00862 }
00863 
00864 
00865 static void display_update(gint waveform)
00866 {
00867     DisplayUpdateInfo displayUpdateInfo;
00868     
00869     displayUpdateInfo.color = 0;
00870     displayUpdateInfo.waveform = waveform;
00871     
00872 #if DMLOGGING_ON 
00873     GTimeVal curtime;
00874     g_get_current_time(&curtime);
00875     
00876     DMPPRINTF("\n\n%ld:%3ld update waveform %d\n",
00877            curtime.tv_sec, curtime.tv_usec / 1000, 
00878            displayUpdateInfo.waveform);
00879 #endif
00880 
00881     // init VCOM for delta driver
00882     if (!g_vcom_is_set)
00883     {
00884         display_set_vcom(sys_get_display_vcom());
00885         g_vcom_is_set = TRUE;
00886     }
00887 
00888     // perform display update
00889     delta_update_display(&displayUpdateInfo);
00890     
00891     // reset idle timer
00892     sys_reset_idle_time();
00893 }
00894 
00895 
00896 static void on_message_timeout(void)
00897 {
00898     gint waveform = WAVEFORM_FULL;
00899     
00900     if (useSpecialWaveform != 0)
00901     {
00902         waveform = useSpecialWaveform;
00903     }
00904 
00905     // set time when delta is available again
00906     deltaAvailableAgain = getCurrentTime();
00907     if ((waveform == WAVEFORM_FULL) || (waveform == WAVEFORM_PARTIAL)) 
00908     {
00909         deltaAvailableAgain += DELTA_TIME_FULL;
00910     } 
00911     else if (waveform == WAVEFORM_QUICK) 
00912     {
00913         deltaAvailableAgain += DELTA_TIME_QUICK;
00914     }
00915     
00916     // reset display command
00917     bzero(&DisplayCommand, sizeof(DMCommand));
00918     useSpecialWaveform = 0;
00919     
00920     // perform display update
00921     display_update(waveform);
00922 
00923     g_timeout.tv_sec = -1;
00924     g_timeout.tv_usec = -1;
00925 }
00926 
00927 
00928 static int delta_uploadwave(char *filename, glong offset)
00929 {
00930     LOGPRINTF("entry");
00931 
00932     int ret = 0;
00933     FILE *file = NULL;
00934     WaveInfo info;
00935     
00936     // open the wave file
00937     file = fopen(filename, "rb");
00938     if (file == NULL)
00939     {
00940         ERRORPRINTF("Error opening file %s", filename);
00941         return -1;
00942     }
00943     
00944     if (offset > 0)
00945     {
00946         if (fseek(file, offset, SEEK_SET) != 0)
00947         {
00948             ERRORPRINTF("Error seeking file in %s [%d]", filename, errno);
00949             return -1;
00950         }
00951     }
00952     
00953     info.wave = malloc(WAVEFORM_SIZE);
00954     if (info.wave == NULL)
00955     {
00956         ERRORPRINTF("Not enough memory\n");
00957         return -1;
00958     }
00959     
00960     info.size = fread(info.wave, 1, WAVEFORM_SIZE, file);
00961 
00962     // close the image
00963     fclose(file);
00964 
00965     ret = ioctl(fbDev, FBIO_DELTA_UPLOADWAVES, &info);
00966     if (ret != 0)
00967     {
00968         ERRORPRINTF("Error sending FBIO_DELTA_UPLOADWAVES: %x", ret);
00969     }
00970     
00971     free(info.wave);
00972 
00973     return ret;
00974 }
00975 
00976 
00977 static void delta_init()
00978 {
00979     LOGPRINTF("entry");
00980     
00981     gint ret = 0;
00982     
00983     if ((ret = ioctl(fbDev, FBIO_DELTA_INIT, NULL)))
00984     {
00985         ERRORPRINTF("Error sending FBIO_DELTA_INIT: %x\n", ret);
00986     }
00987 }
00988 
00989 
00990 static gint delta_vcom_set(gfloat vcom)
00991 {
00992     LOGPRINTF("entry");
00993 
00994     glong vcom_int = 0;
00995     gint ret = 0;
00996     
00997     if(vcom < -5) 
00998     {
00999         vcom = -5;
01000     }
01001     else if(vcom > 5) 
01002     {
01003         vcom = 5;
01004     }
01005     
01006     vcom_int = (signed long)(1000 * vcom);
01007     
01008     if ((ret=ioctl(fbDev, FBIO_DETA_VCOM_SET, &vcom_int)))
01009     { 
01010         ERRORPRINTF("Error sending FBIO_DETA_VCOM_SET: %x",ret); 
01011     }
01012     
01013     return ret;    
01014 }
01015 
01016 
01017 static gint delta_erase(gint color)
01018 {
01019     LOGPRINTF("entry");
01020 
01021     DisplayUpdateInfo updateinfo;
01022     
01023     updateinfo.waveform = 0; // full
01024     updateinfo.color = color;
01025     
01026     color = ((color & 0xf) << 4) + color;
01027     
01028     int ret =  ioctl(fbDev, FBIO_DELTA_ERASE, &updateinfo);
01029     if (ret != 0)
01030     { 
01031         ERRORPRINTF("Error sending FBIO_DELTA_ERASE: %x",ret); 
01032     }
01033     return ret;
01034 }
01035 
01036 
01037 static gint delta_busy(gint xpos, gint ypos, gint speed)
01038 {
01039     LOGPRINTF("entry");
01040     
01041     BusyInfo info;
01042 
01043     info.x     = (unsigned short) xpos;
01044     info.y     = (unsigned short) ypos;
01045     info.delay = (unsigned short) speed;
01046 
01047     int ret = ioctl(fbDev, FBIO_DELTA_BUSY, &info);
01048     if (ret != 0)
01049     { 
01050         ERRORPRINTF("Error sending FBIO_DELTA_BUSY: %x",ret);
01051     }
01052     return ret;
01053 }
01054 
01055 
01056 static gint delta_update_display(DisplayUpdateInfo *displayUpdateInfo) 
01057 {
01058 //    LOGPRINTF("entry");
01059 
01060     int ret = ioctl(fbDev, FBIO_DELTA_UPDATE_DISPLAY, displayUpdateInfo);
01061     if (ret != 0)
01062     {
01063         ERRORPRINTF("Error sending FBIO_DELTA_UPDATE_DISPLAY: %x", ret);
01064     }
01065     return ret;
01066 }
01067 
01068 
01069 static gint parse_message(char *szCommand, erDmCmd_t * pCmd)
01070 {
01071     int     i;
01072     char   *pChar;
01073     char    szToken[DM_MAXCHARONLINE];
01074 
01075     pCmd->cc = (int) DM_UNDEFINED;
01076     for (i = 0; i < DM_N_ARG; i++)
01077     {
01078         strcpy(pCmd->arg[i], "");
01079     }
01080 
01081     // parse command, form of a command is: !n1,n2,n3...
01082     if (szCommand[0] != '!')
01083     {
01084         ERRORPRINTF("Command should start with \'!\'. (%s)", szCommand);
01085         return -1;
01086     }
01087 
01088     // move beyond initial '!'
01089     pChar = szCommand + 1;
01090     i = 0;
01091     while (*pChar != '\0')
01092     {
01093         szToken[i] = '\0';
01094         if (*pChar == ',')
01095         {
01096             pChar++;
01097             break;
01098         }
01099         szToken[i] = *pChar++;
01100         i++;
01101         szToken[i] = '\0';
01102     }
01103 
01104     // we have found the command token, figure out what the command is
01105     if (!strcmp(szToken, "I"))
01106     {
01107         strcpy(pCmd->name, szToken);
01108         pCmd->cc = DM_INFO;
01109         pCmd->nArg = 10;
01110     }
01111     else if (!strcmp(szToken, "F"))
01112     {
01113         strcpy(pCmd->name, szToken);
01114         pCmd->cc = DM_FORCE;
01115         pCmd->nArg = 3;
01116     }
01117     else
01118     {
01119         return -1;
01120     }
01121 
01122     if (pCmd->nArg > 0)
01123     {
01124         get_arguments(pChar, pCmd, pCmd->nArg);
01125     }
01126     return 0;
01127 }
01128 
01129 
01130 static gint parse_command(erDmCmd_t *pCmd, DMCommand *command)
01131 {
01132     switch (pCmd->cc)
01133     {
01134     case DM_INFO:
01135         command->cmd                = DM_INFO;
01136         command->info.pid           = atoi(pCmd->arg[0]);
01137         command->info.x             = atoi(pCmd->arg[1]);
01138         command->info.y             = atoi(pCmd->arg[2]);
01139         command->info.w             = atoi(pCmd->arg[3]);
01140         command->info.h             = atoi(pCmd->arg[4]);
01141         command->info.shouldIgnore  = atoi(pCmd->arg[5]);
01142         command->info.isWindow      = atoi(pCmd->arg[6]);
01143         command->info.windowType    = atoi(pCmd->arg[7]);
01144         strcpy(command->info.widgetType,pCmd->arg[8]);   
01145         command->info.isFocus       = atoi(pCmd->arg[9]);
01146         break;
01147 
01148     case DM_FORCE:
01149         command->cmd                = DM_FORCE;
01150         command->force.pid          = atoi(pCmd->arg[0]);
01151         command->force.takeControl  = atoi(pCmd->arg[1]);
01152         command->force.hint         = atoi(pCmd->arg[2]);
01153         break;
01154 
01155     default:
01156         ERRORPRINTF("Undefined command");
01157         return -1;
01158         break;
01159     }
01160     return 0;
01161 }
01162 
01163 
01164 static void get_arguments(char *pChar, erDmCmd_t * pCmd, int nReqArgs)
01165 {
01166     int     nArg;
01167     int     i;
01168     char    szToken[DM_MAXCHARONLINE];
01169 
01170     for (nArg = 0; nArg < nReqArgs; nArg++)
01171     {
01172         i = 0;
01173         while (*pChar != '\0')
01174         {
01175             szToken[i] = '\0';
01176             if (*pChar == ',')
01177             {
01178                 pChar++;
01179                 break;
01180             }
01181             szToken[i] = *pChar++;
01182             i++;
01183             szToken[i] = '\0';
01184         }
01185         strcpy(pCmd->arg[nArg], szToken);
01186     }
01187 }
01188 
01189 
01190 void display_set_ctb_window(gint wid)
01191 {
01192     g_ctb_window = wid;
01193 }
01194 
01195 
01196 static void *gtk_messages(void *arg)
01197 {
01198     int        sockfd = -1;
01199     int        error = 0;
01200     struct     sockaddr_in server_addr;
01201     DMCommand  command;
01202     erDmCmd_t  cmd;
01203     gchar      buffer[BUFFERSIZE];
01204     gsize      n;
01205     
01206     // open framebuffer device
01207     fbDev = open("/dev/fb0", O_RDWR);
01208     if (fbDev == -1)
01209     {
01210         ERRORPRINTF("Cannot open framebufferdevice. # mknod /dev/fb0 c 29 0");
01211         return NULL;
01212     }
01213 
01214     // create and bind socket
01215     //
01216     sockfd = socket(PF_INET, SOCK_DGRAM, 0);
01217     bzero(&server_addr, sizeof(struct sockaddr_in));
01218     server_addr.sin_family = AF_INET;
01219     server_addr.sin_port = htons(DMPORT);
01220     server_addr.sin_addr.s_addr = htonl(LOCALHOST);
01221     memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero));
01222     
01223     bzero(&DisplayCommand, sizeof(DMCommand));
01224     
01225     error = bind(sockfd, &server_addr, sizeof(server_addr));
01226     if (error)
01227     {
01228         perror("Error invoking bind");
01229         return NULL;
01230     }
01231     
01232     int retval;
01233     fd_set rfds;
01234     
01235     // process incoming messages
01236     //
01237     for (;;)
01238     {
01239         FD_ZERO(&rfds);
01240         FD_SET(sockfd, &rfds);
01241         
01242         if (g_timeout.tv_sec > 0 || g_timeout.tv_usec > 0) 
01243         {
01244 //            WARNPRINTF("wait for data or timeout");
01245             retval = select(sockfd+1, &rfds, NULL, NULL, &g_timeout);
01246         }
01247         else
01248         {
01249 //            WARNPRINTF("wait for data indefinately");
01250             retval = select(sockfd+1, &rfds, NULL, NULL, NULL);
01251         }
01252         
01253         if (retval == -1 && errno == EINTR)
01254         {
01255             continue;        
01256         }
01257         if (retval < 0)
01258         {
01259             ERRORPRINTF("error in select");
01260             return arg;
01261         }
01262         if (retval > 0)
01263         {
01264             if (FD_ISSET(sockfd, &rfds))
01265             {
01266 //                WARNPRINTF("data available");
01267                 recv(sockfd, buffer, BUFFERSIZE, MSG_PEEK);
01268                 gint state  = sys_get_power_state();
01269                 if ((state == STATE_POWER_IDLE) || (state == STATE_POWER_STANDBY))
01270                 {
01271                     // device is not ready, check again after a little while
01272                     g_usleep(10*1000);
01273                     continue;
01274                 }
01275                 
01276                 n = recv(sockfd, buffer, BUFFERSIZE, 0);
01277                 buffer[n] = '\0';
01278                 parse_gtk_message(buffer);
01279             }
01280             else
01281             {
01282                 WARNPRINTF("huh? data for other channel");
01283             }
01284         }
01285         else
01286         {
01287             if (g_timeout.tv_sec >= 0 || g_timeout.tv_usec >= 0) 
01288             {
01289 //                WARNPRINTF("timeout, update");
01290                 on_message_timeout();
01291             }
01292             else
01293             {
01294 //                WARNPRINTF("timeout was reset");
01295             }
01296         }
01297     }
01298     return arg;
01299 }
Generated by  doxygen 1.6.2-20100208