tasks.c

Go to the documentation of this file.
00001 /*
00002  * File Name: tasks.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 // system include files, between < >
00032 #include <glib.h>
00033 #include <hal/libhal.h>
00034 #include <stdio.h>
00035 #include <signal.h>
00036 #include <string.h>
00037 
00038 // ereader include files, between < >
00039 
00040 // local include files, between " "
00041 #include "log.h"
00042 #include "busy.h"
00043 #include "devicelist.h"
00044 #include "hal.h"
00045 #include "ipc.h"
00046 #include "process.h"
00047 #include "system.h"
00048 #include "tasks.h"
00049 #include "xwindow.h"
00050 
00051 
00052 //----------------------------------------------------------------------------
00053 // Type Declarations
00054 //----------------------------------------------------------------------------
00055 
00056 typedef struct
00057 {
00058     proc_t          *proc;
00059     Window          window;
00060     gchar           *application;
00061     gchar           *document;
00062     gchar           *label;
00063     gchar           *image;
00064 } task_t;
00065 
00066 typedef struct
00067 {
00068     task_t          *task;
00069     eripc_context_t *context;
00070     gchar           *message_id; 
00071 } request_t;
00072 
00073 
00074 //----------------------------------------------------------------------------
00075 // Constants
00076 //----------------------------------------------------------------------------
00077 
00078 // time to wait for application started
00079 static const gint TIMEOUT_CHILD_NEW         = 30;
00080 static const gint TIMEOUT_CHILD_CLOSE       = 5;
00081 static const gint TIMEOUT_CHECK_RESTART_UDS = 5;
00082 
00083 static const gint TIMER_CHECK_WINDOW_MS     = 500;
00084 static const guint MAX_TASKS                 = 4;
00085 
00086 
00087 //----------------------------------------------------------------------------
00088 // Static Variables
00089 //----------------------------------------------------------------------------
00090 
00091 #define FOLDER_XID -1
00092 
00093 static GSList           *g_tasklist = NULL;
00094 static gboolean         g_forced_close = FALSE;
00095 static gint             g_child_terminate_source = 0;
00096 static gint             g_check_child_window_source = 0;
00097 static gint             g_task_pending_source = 0;
00098 
00099 
00100 //============================================================================
00101 // Local Function Definitions
00102 //============================================================================
00103 
00104 static gboolean child_new               (const char *command,
00105                                          const char *working_dir,
00106                                          const char *application,
00107                                          const char *document,
00108                                          const char *label, 
00109                                          const char *image, 
00110                                          eripc_context_t *context,
00111                                          const char *message_id);
00112 
00113 static gboolean child_activate          (task_t *task);
00114 static gboolean child_close             (task_t *task);
00115 
00116 static gboolean child_window_open       (task_t *task, request_t *request);
00117 static gboolean child_window_close      (task_t *task, request_t *request);
00118 
00119 static void     on_window_open_callback (eripc_context_t *context,
00120                                          const eripc_event_info_t *info,
00121                                          request_t *request);
00122 
00123 static void     on_window_close_callback(eripc_context_t *context,
00124                                          const eripc_event_info_t *info,
00125                                          request_t *request);
00126 
00127 static gboolean on_check_child_window   (gpointer data);
00128 static gboolean on_child_new_timeout    (gpointer data);
00129 static gboolean on_child_term_timeout   (gpointer data);
00130 
00131 /*
00132 static gboolean on_check_restart_uds    (gpointer data);
00133 static gboolean is_uds_in_use           (void);
00134 */
00135 
00136 static task_t   *tasklist_add           (proc_t *proc,
00137                                          const char *application, 
00138                                          const char *document, 
00139                                          const char *label, 
00140                                          const char *image, 
00141                                          Window window);
00142 
00143 static gboolean tasklist_set_first      (task_t *task);
00144 static gboolean tasklist_remove_pid     (GPid pid);
00145 static gboolean tasklist_remove_window  (Window window);
00146 static task_t   *find_valid_task        (task_t *task);
00147 static void     free_task               (task_t *task);
00148 
00149 static task_t *get_task                 (const char *application, const char *document);
00150 static task_t *get_task_by_xid          (Window xid);
00151 
00152 static gboolean parse_commandline       (const gchar *command_line, 
00153                                          gchar **application, 
00154                                          gchar **document, 
00155                                          gchar **arguments);
00156 
00157 static request_t *new_request           (task_t *task,
00158                                          eripc_context_t *context, 
00159                                          const char *message_id);
00160 
00161 static void     free_request            (request_t *request);
00162 
00163 
00164 //============================================================================
00165 // Functions Implementation
00166 //============================================================================
00167 
00168 gboolean task_start(const char *command_line, 
00169                     const char *working_dir, 
00170                     const char *label, 
00171                     const char *image, 
00172                     eripc_context_t *context, 
00173                     const char *message_id)
00174 {
00175     LOGPRINTF("entry: `%s`", command_line);
00176     
00177     gboolean retval       = FALSE;
00178     gchar    *application = NULL;
00179     gchar    *document    = NULL;
00180 
00181     parse_commandline(command_line, &application, &document, NULL);
00182 
00183     LOGPRINTF("app [%s] wd [%s] doc [%s] label [%s] image [%s]", application, working_dir, document, label, image);
00184     
00185     task_t *task = get_task(application, document);
00186     if (task)
00187     {
00188         LOGPRINTF("task exists, reopen or activate");
00189         // task already exists, reopen or activate
00190         //
00191         if (task->proc && task->proc->ipc_service && task->proc->is_multidoc)
00192         {
00193             request_t *request = new_request(task, context, message_id);
00194             retval = child_window_open(task, request);
00195         }
00196         else
00197         {
00198             retval = child_activate(task);
00199             if (context && message_id)
00200             {
00201                 // return result to caller
00202                 ipc_send_reply_task_start(context, message_id, 0, NULL);
00203             }
00204         }
00205     }
00206     else
00207     {
00208         proc_t *proc = process_get_by_name(application);
00209         if (proc)
00210         {
00211             // process is running but no task yet, create new
00212             //
00213             if (proc->ipc_service && proc->is_multidoc)
00214             {
00215                 LOGPRINTF("task %s, %s not found, create it...", application, document);
00216                 task_t *task = tasklist_add(proc, application, document, label, image, 0);
00217                 request_t *request = new_request(task, context, message_id);
00218                 retval = child_window_open(task, request);
00219             }
00220             else
00221             {
00222                 if (proc->is_multidoc) {
00223                     LOGPRINTF("%s, %s is currently running but is not a task, ignored.", application, document);
00224                     // process running, singledoc and no task found for it
00225                     // this is either a window-less process or a system process
00226                     // in either case; we ignore this start command.
00227                 } else {
00228                     // TODO REFACTOR (common code)
00229                     // process not running, create new
00230                     LOGPRINTF("process %s running, but not for current doc, start new", application);
00231                     retval = child_new(command_line, working_dir, application, document, label, image, context, message_id);
00232                 }
00233             }
00234         }
00235         else
00236         {
00237             // process not running, create new
00238             //
00239             LOGPRINTF("process %s, not currently running start new", application);
00240             retval = child_new(command_line, working_dir, application, document, label, image, context, message_id);
00241         }
00242     }
00243 
00244     // free allocated memory
00245     g_free(application);
00246     g_free(document);
00247 
00248     LOGPRINTF("leave: retval %d", retval);
00249     
00250     return retval;
00251 }
00252 
00253 
00254 gboolean task_stop(const char *command_line,
00255                    eripc_context_t *context, 
00256                    const char *message_id)
00257 {
00258     LOGPRINTF("entry: `%s`", command_line);
00259 
00260     gboolean retval       = FALSE;
00261     gchar    *application = NULL;
00262     gchar    *document    = NULL;
00263     
00264     parse_commandline(command_line, &application, &document, NULL);
00265                      
00266     task_t *task = get_task(application, document);
00267     if (task)
00268     {
00269         if (task->proc && task->proc->ipc_service && task->proc->is_multidoc)
00270         {
00271             request_t *request = new_request(task, context, message_id);
00272             LOGPRINTF("found multidoc window, close child window");
00273             retval = child_window_close(task, request);
00274         }
00275         else
00276         {
00277             LOGPRINTF("found singledoc window, close child");
00278             retval = child_close(task);
00279             ipc_send_reply(context, message_id, retval);
00280         }
00281     }
00282 
00283     // free allocated memory
00284     g_free(application);
00285     g_free(document);
00286     
00287     LOGPRINTF("leave: retval %d", retval);
00288     
00289     return retval;
00290 }
00291 
00292 
00293 gboolean task_rename(int xid, const char *new_document, const char* new_label)
00294 {
00295     LOGPRINTF("[%d] %s '%s'", xid, new_document, new_label);
00296     task_t *task = get_task_by_xid(xid);
00297     if (task == NULL) {
00298         ERRORPRINTF("unknown task: xid=%d", xid);
00299         return FALSE;
00300     }
00301     g_free(task->document);
00302     task->document = g_strdup(new_document);
00303     g_free(task->label);
00304     task->label = g_strdup(new_label);
00305     ipc_menu_rename_task(xid, task->label);
00306     return TRUE;
00307 }
00308 
00309 
00310 void task_activate_by_xid(int xid)
00311 {
00312     LOGPRINTF("entry xid=%d", xid);
00313     if (xid == FOLDER_XID) 
00314     {
00315         process_activate_ctb();
00316         return; 
00317     }
00318     task_t *task = get_task_by_xid(xid);
00319     if (task)
00320     {
00321         LOGPRINTF("found task, activate window %d", (gint) task->window);
00322         child_activate(task);
00323     } 
00324     else 
00325     {
00326         WARNPRINTF("task not found, xid=%d", xid);
00327     }
00328 }
00329 
00330 
00331 gboolean task_activate(const char *command_line)
00332 {
00333     LOGPRINTF("entry: `%s`", command_line);
00334 
00335     gboolean retval       = FALSE;
00336     gchar    *application = NULL;
00337     gchar    *document    = NULL;
00338     
00339     parse_commandline(command_line, &application, &document, NULL);
00340                      
00341     task_t *task = get_task(application, document);
00342     if (task)
00343     {
00344         LOGPRINTF("found task, activate window %d", (gint) task->window);
00345         retval = child_activate(task);
00346     }
00347     else 
00348     {
00349         WARNPRINTF("task not found cmdline='%s'", command_line);
00350     }
00351 
00352     // free allocated memory
00353     g_free(application);
00354     g_free(document);
00355     
00356     LOGPRINTF("leave: retval %d", retval);
00357     
00358     return retval;
00359 }
00360 
00361 
00362 #if (TESTING_ON)
00363 void print_task_list()
00364 {
00365     GSList *task_ptr = g_tasklist;
00366     
00367     int i = 0;
00368     printf("%s() TASKS\n", __func__);
00369     while (task_ptr)
00370     {
00371         task_t *task = (task_t *) task_ptr->data;
00372         int pid = (task->proc) ? task->proc->pid : 0;
00373         printf("  [%d] proc_pid=%d  window=%d  app=%s  doc=%s\n", i, pid,
00374                 (guint)task->window, task->application, task->document);
00375 
00376         task_ptr = task_ptr->next;
00377         i++;
00378     }
00379 }
00380 #endif
00381 
00382 
00383 const gchar *task_service_by_window(Window xid)
00384 {
00385     LOGPRINTF("entry: %d", (gint) xid);
00386 
00387     task_t *task = get_task_by_xid(xid);
00388     if (task && task->proc && task->proc->ipc_service) 
00389     {
00390         return task->proc->ipc_service;
00391     }
00392     return NULL;
00393 }
00394 
00395 
00396 gboolean task_add(const char *application, 
00397                   const char *document, 
00398                   const char *label, 
00399                   const char *image, 
00400                   const char *ipc_service, 
00401                   gint        pid, 
00402                   Window      xid)
00403 {
00404     LOGPRINTF("entry");
00405     
00406     gboolean retval = FALSE;
00407     
00408     task_t *task = get_task(application, document);
00409     proc_t *proc = process_get_by_pid(pid);
00410     if (proc && !task)
00411     {
00412         LOGPRINTF("task %s, %s, not found, add it...", application, document);
00413         task = tasklist_add(proc, application, document, label, image, xid);
00414         if (task)
00415         {
00416             retval = TRUE;
00417         }
00418     }
00419 
00420     return retval;
00421 }
00422 
00423 
00424 gboolean task_cleanup_pid(GPid pid)
00425 {
00426     LOGPRINTF("entry: forced %d", g_forced_close);
00427 
00428     gboolean result = tasklist_remove_pid(pid);
00429 
00430     if (result && !g_forced_close)
00431     {
00432 #if MACHINE_IS_DR800SG || MACHINE_IS_DR800S || MACHINE_IS_DR800SW
00433         // automatically return to application that was on top in the stack
00434 #elif MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
00435         // return to folder in content browser
00436         process_activate_ctb();
00437 #endif
00438     }
00439     
00440     g_forced_close = FALSE;
00441     
00442     return result;
00443 }
00444 
00445 
00446 gboolean task_cleanup_window(Window xid)
00447 {
00448     LOGPRINTF("entry: xid %d, forced %d", (int) xid, g_forced_close);
00449  
00450     gboolean result = tasklist_remove_window(xid);
00451 
00452     if (result && !g_forced_close)
00453     {
00454 #if MACHINE_IS_DR800SG || MACHINE_IS_DR800S || MACHINE_IS_DR800SW
00455         // automatically return to application that was on top in the stack
00456 #elif MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
00457         // return to folder in content browser
00458         process_activate_ctb();
00459 #endif
00460     }
00461     
00462     g_forced_close = FALSE;
00463     
00464     return result;
00465 }
00466 
00467 
00468 gboolean task_startup_completed(proc_t *proc, Window window)
00469 {
00470     LOGPRINTF("entry");
00471     
00472     GSList *task_ptr = g_tasklist;
00473     while (task_ptr)
00474     {
00475         task_t *task = (task_t *) task_ptr->data;
00476 
00477         if (task->proc == proc)
00478         {
00479             if (window != 0)
00480             {
00481                 task->window = window;
00482                LOGPRINTF("assigned window %d to %s, %s", (gint) task->window, task->application, task->document);
00483             }
00484 
00485             // add to task manager
00486             ipc_menu_add_task((gint)task->window, task->label);
00487 
00488             return TRUE;
00489         }
00490         task_ptr = task_ptr->next;
00491     }
00492     return FALSE;
00493 }
00494 
00495 
00496 char* testing_task_get_list()
00497 {
00498 #if (TESTING_ON)
00499     char buffer[1000];
00500     char* cp = buffer;
00501     GSList *iter = g_tasklist;
00502     while (iter)
00503     {
00504         task_t* task = (task_t*) iter->data;
00505         strcpy(cp, task->application);
00506         cp += strlen(task->application);
00507         *cp++ = '|';
00508         strcpy(cp, task->document);
00509         cp += strlen(task->document);
00510         *cp++ = '\n';
00511 
00512         iter = g_slist_next(iter);
00513     }
00514     *cp = 0;
00515     char* result = g_strdup(buffer);
00516     return result;
00517 #endif
00518     return g_strdup("no debug");
00519 }
00520 
00521 
00522 //============================================================================
00523 // Local Function Implementation
00524 //============================================================================
00525 
00526 static gboolean child_new(const char *command,
00527                           const char *working_dir,
00528                           const char *application,
00529                           const char *document,
00530                           const char *label, 
00531                           const char *image, 
00532                           eripc_context_t *context,
00533                           const char *message_id)
00534 {
00535     LOGPRINTF("entry");
00536 
00537     gboolean retval = FALSE;
00538 
00539     if (   g_check_child_window_source == 0
00540         && g_task_pending_source       == 0 )
00541     {
00542      
00543         if (working_dir && working_dir[0]=='\0')
00544         {
00545             working_dir = NULL;
00546         }
00547         
00548         proc_t *proc = process_start(command, working_dir, NULL, NULL, PS_WAIT_STARTED);
00549         if (proc != NULL)
00550         {
00551             task_t    *task = tasklist_add(proc, application, document, label, image, 0);
00552             request_t *request = new_request(task, context, message_id);
00553 
00554             // show busy indication
00555             busy_add_foreground(0, BUSY_DIALOG_DELAYED, NULL);
00556 
00557             LOGPRINTF("pending task adding, wait for window id");
00558            
00559             // periodically check window list
00560             g_check_child_window_source = g_timeout_add(TIMER_CHECK_WINDOW_MS, on_check_child_window, request);            
00561             
00562             // set maximum time to wait for new window
00563             g_task_pending_source = g_timeout_add_seconds(TIMEOUT_CHILD_NEW, on_child_new_timeout, request);
00564             
00565             retval = TRUE;
00566         }
00567         else 
00568         {
00569             LOGPRINTF("error starting, return failure");
00570             // return FAILED immediately        
00571         }
00572     }
00573     else
00574     {
00575         ERRORPRINTF("still waiting for another task to be started, refusing task [%s]", label);
00576     }
00577     
00578     return retval;
00579 }
00580 
00581 
00582 static gboolean child_window_open(task_t     *task,
00583                                   request_t  *request)
00584 {
00585     LOGPRINTF("entry");
00586     
00587     gboolean retval = FALSE;
00588     
00589     if (task->proc && task->proc->ipc_service)
00590     {
00591         LOGPRINTF("pending task added, wait for on_window_open_callback");
00592         retval = ipc_send_open(task->proc->ipc_service, task->document, on_window_open_callback, request);
00593     }
00594 
00595     return retval;
00596 }
00597     
00598 
00599 static request_t *new_request(task_t *task,
00600                               eripc_context_t *context, 
00601                               const char *message_id)
00602 {
00603     LOGPRINTF("entry");
00604     
00605     request_t *request  = g_new0(request_t, 1);
00606     if (!request)
00607     {
00608         ERRORPRINTF("mem alloc failed");
00609         return FALSE;
00610     }
00611     request->task       = task;
00612     request->context    = context;
00613     request->message_id = g_strdup(message_id);
00614     
00615     return request;
00616 }
00617 
00618 
00619 static void free_request(request_t *request)
00620 {
00621     LOGPRINTF("entry");
00622     
00623     g_free(request->message_id);
00624     g_free(request);
00625     request = NULL;
00626 }
00627 
00628 
00629 static gboolean child_window_close(task_t    *task,
00630                                    request_t *request)
00631 {
00632     LOGPRINTF("entry");
00633     
00634     gboolean retval = FALSE;
00635 
00636     if (task->proc && task->proc->ipc_service)
00637     {
00638         LOGPRINTF("wait for on_window_close_callback");
00639         retval = ipc_send_close(task->proc->ipc_service, task->document, on_window_close_callback, request);
00640     }
00641     
00642     return retval;
00643 }
00644 
00645 
00646 static gboolean child_activate(task_t *task)
00647 {
00648     LOGPRINTF("entry");
00649     
00650     // set task to head of list
00651     tasklist_set_first(task);
00652     
00653     // activate X11 window 
00654     window_activate(task->window);
00655 
00656     return TRUE;
00657 }
00658 
00659 
00660 static gboolean child_close(task_t *task)
00661 {
00662     LOGPRINTF("entry");
00663     
00664     if (task->proc)
00665     {
00666         // terminate child
00667         kill(task->proc->pid, SIGTERM);
00668     }
00669     
00670     // set maximum time to wait for child termination
00671     g_child_terminate_source = g_timeout_add_seconds(TIMEOUT_CHILD_CLOSE, on_child_term_timeout, task);
00672     
00673     return TRUE;
00674 }
00675 
00676 
00677 static gboolean on_child_new_timeout(gpointer data)
00678 {
00679     LOGPRINTF("entry");
00680     
00681     request_t *request = data;
00682     
00683     g_return_val_if_fail(request != NULL, FALSE);
00684     
00685     if (g_check_child_window_source)
00686     {
00687         g_source_remove(g_check_child_window_source);
00688         g_check_child_window_source = 0;
00689     }
00690     
00691     if (g_task_pending_source)
00692     {
00693         g_source_remove(g_task_pending_source);
00694         g_task_pending_source = 0;
00695     }    
00696     
00697     task_t *task = find_valid_task(request->task);
00698     if (task != NULL)
00699     {
00700         tasklist_remove_pid(request->task->proc->pid);
00701     }   
00702     
00703     // return result to caller
00704     if (request->context && request->message_id)
00705     {
00706         ipc_send_reply_task_start(request->context, request->message_id, 2, NULL);
00707     }
00708     free_request(request);
00709     
00710     // remove busy indication
00711     busy_remove_foreground(0);
00712 
00713     // stop and destroy this timer
00714     return FALSE; 
00715 }
00716 
00717 
00718 static void check_num_tasks()
00719 {
00720     if (g_slist_length(g_tasklist) > MAX_TASKS)
00721     {
00722         LOGPRINTF("maximum number of tasks reached, remove oldest");
00723         
00724         // get last task in list
00725         GSList *list_last_task = g_slist_last(g_tasklist);
00726         task_t *last_task = list_last_task->data;
00727 
00728         g_forced_close = TRUE;
00729         
00730         // close last task
00731         if (last_task->proc && last_task->proc->ipc_service
00732                 && last_task->proc->is_multidoc)
00733         {
00734             request_t *request = new_request(last_task, NULL, NULL);
00735             child_window_close(last_task, request);
00736         }
00737         else
00738         {
00739             child_close(last_task);
00740         }            
00741     }
00742 }
00743 
00744 
00745 static gboolean on_check_child_window(gpointer data)
00746 {
00747     LOGPRINTF("entry");
00748     
00749     request_t *request = data;
00750 
00751     if (request != NULL)
00752     {
00753         task_t *task = find_valid_task(request->task);
00754         if (task != NULL)
00755         {
00756             LOGPRINTF("looking for %s", task->application);
00757 
00758             Window child_window = get_application_window(task->application);
00759             if (child_window == 0)
00760             {
00761                 //  do nothing (wait for next call)
00762                 return TRUE;
00763             }
00764             else
00765             {
00766                 check_num_tasks();
00767 
00768                 // add window id to task info
00769                 if (task->window == 0) {
00770                     task->window = child_window;
00771                 }
00772 
00773                 if (request->context && request->message_id)
00774                 {
00775                     // return success to caller
00776                     ipc_send_reply_task_start(request->context, request->message_id, 0, NULL);
00777                 }
00778                 free_request(request);
00779             }
00780         }
00781         else
00782         {
00783             WARNPRINTF("task not found");
00784 
00785             if (request->context && request->message_id)
00786             {
00787                 // return failed to caller
00788                 ipc_send_reply_task_start(request->context, request->message_id, 3, NULL);
00789             }
00790             free_request(request);
00791         }
00792     }
00793     else
00794     {
00795         WARNPRINTF("request not found");
00796     }
00797 
00798     // stop and destroy timer
00799     g_check_child_window_source = 0;
00800     
00801     // stop pending timeout
00802     if (g_task_pending_source)
00803     {
00804         g_source_remove(g_task_pending_source);
00805         g_task_pending_source = 0;
00806     }
00807 
00808     // remove busy indication
00809     busy_remove_foreground(0);
00810 
00811     return FALSE;
00812 }
00813 
00814 
00815 static void on_window_open_callback(eripc_context_t *context,
00816                                     const eripc_event_info_t *info,
00817                                     request_t *request)
00818 {
00819     LOGPRINTF("entry request [%p]", request);
00820     
00821     gboolean retval = FALSE;
00822     gchar *errmsg = NULL;
00823     const eripc_arg_t *arg_array = info->args;
00824     
00825     g_return_if_fail(request != NULL);
00826     
00827     if (info->event_type != ERIPC_EVENT_REPLY)
00828     {
00829         WARNPRINTF("invalid event: %d", info->event_type);
00830     }
00831     else if ((arg_array == NULL) || (arg_array[0].type != ERIPC_TYPE_INT))
00832     {
00833         WARNPRINTF("invalid arguments in reply, task not added");
00834     }
00835     else if (arg_array[0].value.i < 0)
00836     {
00837         LOGPRINTF("child returned failure, task not added");
00838         
00839         if (arg_array[1].type == ERIPC_TYPE_STRING)
00840         {
00841             LOGPRINTF("error message: %s", arg_array[1].value.s);
00842             errmsg = g_strdup(arg_array[1].value.s);
00843         }
00844         
00845         task_t *new_task = find_valid_task(request->task);
00846         if (new_task)
00847         {
00848             tasklist_remove_window(new_task->window);
00849         }
00850     }
00851     else    
00852     {
00853         task_t *old_task  = NULL;
00854         task_t *task_data = NULL;
00855         GSList *task      = g_tasklist;
00856         
00857         Window child_window = arg_array[0].value.i;
00858     
00859         // TODO
00860         // - add check if window exists in windowlist
00861         
00862         LOGPRINTF("task started in window: %d", (int) child_window);
00863 
00864         // check if window is already in tasklist
00865         //
00866         while ( (task != NULL) && (task->data != NULL) )
00867         {
00868             task_data = task->data;
00869 
00870             LOGPRINTF("check %s, %s; window %d", task_data->application, task_data->document, (int) task_data->window);
00871 
00872             if (task_data->window == child_window)
00873             {
00874                 // task with this window found
00875                 old_task = task_data;
00876                 break;
00877             }
00878             
00879             task = task->next;
00880         }
00881 
00882         task_t *new_task = find_valid_task(request->task);
00883         if (new_task && (child_window > 0))
00884         {
00885             LOGPRINTF("task %s, %s; window %d", new_task->application, new_task->document, (int) child_window);
00886             
00887             if (old_task == new_task)
00888             {
00889                 // task is already in task manager, activate it
00890                 child_activate(old_task);
00891             }
00892             else
00893             {
00894                 if (old_task)
00895                 {
00896                     // new task will replace old task
00897                     LOGPRINTF("remove old task %s, %s: window %d", old_task->application, old_task->document, (int) old_task->window);
00898                     tasklist_remove_window(old_task->window);
00899                 }
00900                 else
00901                 {
00902                     // task is new, check current number of tasks
00903                     check_num_tasks();
00904                 }
00905 
00906                 // add to task manager
00907                 ipc_menu_add_task(child_window, new_task->label);
00908 
00909                 // save new window
00910                 new_task->window = child_window;
00911 
00912                 if (old_task)
00913                 {
00914                     // activate existing window 
00915                     LOGPRINTF("reactivate existing window");
00916                     window_activate(child_window);
00917                 }
00918             }
00919         }
00920             
00921         // set success
00922         retval = TRUE;
00923     }
00924 
00925     if (request != NULL)
00926     {
00927         if (request->message_id != NULL)
00928         {
00929             // return result to caller
00930             if (retval == TRUE)
00931             {
00932                 LOGPRINTF("return result to caller [%d], message_id [%s]", 0, request->message_id);
00933                 ipc_send_reply_task_start(request->context, request->message_id, 0, NULL);
00934             }
00935             else
00936             {
00937                 LOGPRINTF("return result to caller [%d], message_id [%s]", 4, request->message_id);
00938                 ipc_send_reply_task_start(request->context, request->message_id, 4, errmsg);            
00939             }
00940         }
00941         free_request(request);
00942     }
00943     
00944     g_free(errmsg);
00945 }
00946 
00947 
00948 static void on_window_close_callback(eripc_context_t *context,
00949                                      const eripc_event_info_t *info,
00950                                      request_t *request)
00951 {
00952     LOGPRINTF("entry request [%p]", request);
00953     
00954     gboolean retval = FALSE;
00955     const eripc_arg_t *arg_array = info->args;
00956     
00957     if (request == NULL)
00958     {
00959         WARNPRINTF("request is null");
00960     }
00961     if (find_valid_task(request->task) == NULL)
00962     {
00963         WARNPRINTF("task not found [%p]", request->task);
00964     }
00965     else if (info->event_type != ERIPC_EVENT_REPLY)
00966     {
00967         WARNPRINTF("invalid event: %d", info->event_type);
00968     }
00969     else if ((arg_array == NULL) || (arg_array[0].type != ERIPC_TYPE_BOOL))
00970     {
00971         WARNPRINTF("invalid arguments in reply");
00972     }
00973     else if (arg_array[0].value.b == FALSE)
00974     {
00975         LOGPRINTF("child returned failure");
00976     }
00977     else
00978     {
00979         // TODO
00980         // - check if window is really closed
00981         
00982         // remove task with this window from list
00983         tasklist_remove_window(request->task->window);
00984         retval = TRUE;
00985     }
00986     
00987     if (request != NULL)
00988     {
00989         if (request->message_id != NULL)
00990         {
00991             // return result to caller
00992             LOGPRINTF("return result to caller [%d], message_id [%s]", retval, request->message_id);
00993             ipc_send_reply(request->context, request->message_id, retval);
00994         }
00995         free_request(request);
00996     }
00997 }
00998 
00999 
01000 
01001 static gboolean on_child_term_timeout(gpointer data)
01002 {
01003     LOGPRINTF("entry");
01004     
01005     task_t *task = data;
01006     
01007     if (task->proc && (task->proc->pid > 0))
01008     {
01009         // termination timed out, now do it the really hard way
01010         kill(task->proc->pid, SIGKILL);
01011     }
01012     
01013     // reset terminated handler
01014     g_child_terminate_source = 0;
01015     
01016     // stop and destroy timer
01017     return FALSE;
01018 }
01019 
01020 
01021 static task_t *tasklist_add(proc_t *proc, const char *application, const char *document,
01022                             const char *label, const char *image, Window window)
01023 {
01024     LOGPRINTF("entry");
01025    
01026     task_t *task = g_new0 (task_t, 1);
01027     if (!task)
01028     {
01029         ERRORPRINTF("mem alloc failed");
01030         return NULL;
01031     }
01032     
01033     task->proc        = proc;
01034     task->application = g_strdup(application);
01035     task->document    = g_strdup(document);
01036     task->label       = g_strdup(label);
01037     task->image       = g_strdup(image);
01038     task->window      = window;
01039     
01040     g_tasklist = g_slist_prepend(g_tasklist, task);
01041 
01042     LOGPRINTF("done. task %p [#tasks: %d]", task, g_slist_length(g_tasklist));
01043     
01044     return task;
01045 }
01046 
01047 
01048 static void free_task(task_t *task)
01049 {
01050     g_free(task->application);
01051     g_free(task->document);
01052     g_free(task->label);
01053     g_free(task->image);
01054     g_free(task);
01055     task = NULL;
01056 }
01057 
01058 
01059 static gboolean tasklist_set_first(task_t *task)
01060 {
01061     LOGPRINTF("entry");
01062    
01063     task_t *task_data = NULL;
01064     GSList *cur_task = g_tasklist;
01065     
01066     while ( (cur_task != NULL) && (cur_task->data != NULL) )
01067     {
01068         task_data = cur_task->data;
01069         if (task_data == task)
01070         {
01071             ipc_menu_set_first_task(task->window);
01072 
01073             g_tasklist = g_slist_delete_link(g_tasklist, cur_task);
01074             g_tasklist = g_slist_prepend(g_tasklist, task);
01075             LOGPRINTF("task set to first [#tasks: %d]", g_slist_length(g_tasklist));
01076             return TRUE;
01077         }
01078         
01079         cur_task = cur_task->next;
01080     }
01081     
01082     LOGPRINTF("no first task found [#tasks: %d]", g_slist_length(g_tasklist));
01083     return FALSE;
01084 }
01085 
01086 
01087 static gboolean tasklist_remove_pid(GPid pid)
01088 {
01089     LOGPRINTF("entry");
01090     
01091     GSList *task = g_tasklist;
01092     gint    npre = g_slist_length(g_tasklist);
01093     
01094     while ( (task != NULL) && (task->data != NULL) )
01095     {
01096         task_t *task_data = task->data;
01097 
01098         if (task_data->proc && (task_data->proc->pid == pid))
01099         {
01100             ipc_menu_remove_task(task_data->window);
01101             free_task(task_data);
01102     
01103             g_tasklist = g_slist_delete_link(g_tasklist, task);
01104             
01105             // start over iteration
01106             task = g_tasklist;
01107         }
01108         else
01109         {
01110             task = task->next;
01111         }
01112     }
01113     
01114     gint npost = g_slist_length(g_tasklist);
01115     
01116     if (npre != npost)
01117     {
01118         LOGPRINTF("removed %d tasks, %d remaining", npre-npost, npost);
01119         return TRUE;
01120     }
01121     else
01122     {
01123         LOGPRINTF("no tasks found for pid %d", pid);
01124         return FALSE;
01125     }
01126 }
01127 
01128 
01129 static gboolean tasklist_remove_window(Window window)
01130 {
01131     LOGPRINTF("entry: xid %d", (int) window);
01132     
01133     GSList *task = g_tasklist;
01134     gint    npre = g_slist_length(g_tasklist);
01135     gboolean is_uds_task = FALSE;
01136     
01137     while ( (task != NULL) && (task->data != NULL) )
01138     {
01139         task_t *task_data = task->data;
01140 
01141         if (task_data->window == window)
01142         {
01143             ipc_menu_remove_task(task_data->window);
01144              
01145             if (strcmp(task_data->application, "uds") == 0)
01146             {
01147                 is_uds_task = TRUE;
01148             }
01149             free_task(task_data);
01150             
01151             g_tasklist = g_slist_delete_link(g_tasklist, task);
01152             
01153             // start over iteration
01154             task = g_tasklist;
01155         }
01156         else
01157         {
01158             task = task->next;
01159         }
01160     }
01161     
01162     gint npost = g_slist_length(g_tasklist);
01163 /*    
01164     if (is_uds_task && !is_uds_in_use())
01165     {
01166         // start timer to check if any windows for UDS remain
01167         LOGPRINTF("no task found for UDS, start timer");
01168         g_timeout_add_seconds(TIMEOUT_CHECK_RESTART_UDS, on_check_restart_uds, NULL);
01169     }
01170 */
01171 
01172     if (npre != npost)
01173     {
01174         LOGPRINTF("removed %d tasks, %d remaining", npre-npost, npost);
01175         return TRUE;
01176     }
01177     else
01178     {
01179         LOGPRINTF("no tasks found for window %d", (int) window);
01180         return FALSE;
01181     }
01182 }
01183 
01184 
01185 static task_t *find_valid_task(task_t *task)
01186 {
01187     if (task == NULL) return NULL;
01188 
01189     task_t *task_data = NULL;
01190     GSList *cur_task = g_tasklist;
01191     
01192     while ( (cur_task != NULL) && (cur_task->data != NULL) )
01193     {
01194         task_data = cur_task->data;
01195         if (task_data == task)
01196         {
01197             return task_data;
01198         }
01199         cur_task = cur_task->next;
01200     }
01201     
01202     return NULL;
01203 }
01204 
01205 
01206 static task_t *get_task_by_xid(Window xid)
01207 {
01208     GSList *task_ptr = g_tasklist;
01209     
01210     while (task_ptr)
01211     {
01212         task_t *cur_task = (task_t *) task_ptr->data;
01213 
01214         if (cur_task->window == xid) return cur_task;
01215         task_ptr = task_ptr->next;
01216     }
01217     return NULL;
01218 }
01219 
01220 
01221 static task_t *get_task(const char *application, const char *document)
01222 {
01223     LOGPRINTF("entry");
01224     
01225     GSList *task_ptr = g_tasklist;
01226     gchar  *baseapp  = g_path_get_basename(application);
01227     
01228     while (task_ptr)
01229     {
01230         task_t *cur_task = (task_t *) task_ptr->data;
01231 
01232         if (baseapp && cur_task->application && (strcmp(cur_task->application, baseapp) == 0) && 
01233             ((document == NULL) || (cur_task->document && (strcmp(cur_task->document, document) == 0))))
01234         {
01235             g_free(baseapp);
01236             return cur_task;
01237         }
01238         task_ptr = task_ptr->next;
01239     }
01240     
01241     g_free(baseapp);
01242     return NULL;
01243 }
01244 
01245 
01246 gboolean parse_commandline(const gchar *command_line, gchar **application, gchar **document, gchar **arguments)
01247 {
01248     char   **argv_ptr   = NULL;
01249     GError *error       = NULL;
01250     gchar  *app         = NULL;
01251     gchar  *doc         = NULL;
01252     gchar  *arg         = NULL;
01253     gint   argc         = 0;
01254     
01255     LOGPRINTF("enter");
01256     
01257     g_shell_parse_argv(command_line, &argc, &argv_ptr, &error);
01258     if (error)
01259     {
01260         WARNPRINTF("Execution of '%s' failed with error: %s", command_line, error->message);
01261         g_error_free(error);
01262         return FALSE;
01263     }
01264     
01265     // split command line
01266     //
01267     app = g_path_get_basename(argv_ptr[0]);
01268     
01269     if (argc > 1)
01270     {
01271         doc  = g_strdup(argv_ptr[argc-1]);
01272         
01273         // join all arguments except application
01274         arg = g_strjoinv(" ", &argv_ptr[1]); 
01275     }
01276     
01277     // return arguments
01278     //
01279     if (application != NULL)
01280     {
01281         LOGPRINTF("app `%s`", app);
01282         *application = app;
01283     }
01284     else 
01285     {
01286         g_free(app);
01287     }
01288         
01289     if (document != NULL)
01290     {
01291         LOGPRINTF("doc `%s`", doc);
01292         *document = doc;
01293     }
01294     else 
01295     {
01296         g_free(doc);
01297     }
01298         
01299     if (arguments != NULL)
01300     {
01301         LOGPRINTF("arg `%s`", arg);
01302         *arguments = arg;
01303     }
01304     else 
01305     {
01306         g_free(arg);
01307     }
01308 
01309     g_strfreev(argv_ptr);
01310     
01311     return TRUE;
01312 }
Generated by  doxygen 1.6.2-20100208