40
static gboolean _cd_clean_one_old_processes (int *iPid, CDProcess *pProcess, double *fTime)
42
if (pProcess->fLastCheckTime < *fTime)
46
void cd_sysmonitor_clean_old_processes (CairoDockModuleInstance *myApplet, double fTime)
48
g_hash_table_foreach_remove (myData.pProcessTable, (GHRFunc) _cd_clean_one_old_processes, &fTime);
51
void cd_sysmonitor_clean_all_processes (CairoDockModuleInstance *myApplet)
53
g_hash_table_remove_all (myData.pProcessTable);
57
static inline void _cd_sysmonitor_insert_process_in_top_list (CairoDockModuleInstance *myApplet, CDProcess *pProcess)
42
static inline void _cd_sysmonitor_insert_process_in_top_list (CDTopSharedMemory *pSharedMemory, CDProcess *pProcess)
60
if (myData.bSortTopByRam)
45
if (pSharedMemory->bSortTopByRam)
62
47
if (pProcess->iMemAmount > 0)
64
i = myConfig.iNbDisplayedProcesses - 1;
65
while (i >= 0 && (myData.pTopList[i] == NULL || pProcess->iMemAmount > myData.pTopList[i]->iMemAmount))
49
i = pSharedMemory->iNbDisplayedProcesses - 1;
50
while (i >= 0 && (pSharedMemory->pTopList[i] == NULL || pProcess->iMemAmount > pSharedMemory->pTopList[i]->iMemAmount))
67
if (i != myConfig.iNbDisplayedProcesses - 1)
52
if (i != pSharedMemory->iNbDisplayedProcesses - 1)
70
for (j = myConfig.iNbDisplayedProcesses - 2; j >= i; j --)
71
myData.pTopList[j+1] = myData.pTopList[j];
72
myData.pTopList[i] = pProcess;
55
for (j = pSharedMemory->iNbDisplayedProcesses - 2; j >= i; j --)
56
pSharedMemory->pTopList[j+1] = pSharedMemory->pTopList[j];
57
pSharedMemory->pTopList[i] = pProcess;
120
if (myData.pProcessTable == NULL)
121
myData.pProcessTable = g_hash_table_new_full (g_int_hash, g_int_equal, NULL, (GDestroyNotify) cd_sysmonitor_free_process); // la cle est dans la valeur.
122
if (myData.pTopList == NULL)
123
myData.pTopList = g_new0 (CDProcess *, myConfig.iNbDisplayedProcesses);
105
if (pSharedMemory->pProcessTable == NULL)
106
pSharedMemory->pProcessTable = g_hash_table_new_full (g_int_hash, g_int_equal, NULL, (GDestroyNotify) _cd_sysmonitor_free_process); // a table of (pid*, process*), the pid* points directly into the process.
107
if (pSharedMemory->pTopList == NULL)
108
pSharedMemory->pTopList = g_new0 (CDProcess *, pSharedMemory->iNbDisplayedProcesses); // list of the processes to be displayed (points directly into the table).
125
memset (myData.pTopList, 0, myConfig.iNbDisplayedProcesses * sizeof (CDProcess *));
126
if (myData.iMemPageSize == 0)
127
myData.iMemPageSize = sysconf(_SC_PAGESIZE);
110
memset (pSharedMemory->pTopList, 0, pSharedMemory->iNbDisplayedProcesses * sizeof (CDProcess *));
111
if (pSharedMemory->iMemPageSize == 0)
112
pSharedMemory->iMemPageSize = sysconf(_SC_PAGESIZE);
129
114
const gchar *cPid;
131
116
CDProcess *pProcess;
133
unsigned long long iVmSize, iVmRSS, iTotalMemory; // Quantité de mémoire totale utilisée / (Virtual Memory Resident Stack Size) Taille de la pile en mémoire.
118
unsigned long long iVmSize, iVmRSS, iTotalMemory; // Quantite de memoire totale utilisee / (Virtual Memory Resident Stack Size) Taille de la pile en memoire.
135
120
while ((cPid = g_dir_read_name (dir)) != NULL)
200
185
iVmSize = atoll (tmp);
201
186
jump_to_next_value (tmp);
202
187
iVmRSS = atoll (tmp);
203
iTotalMemory = iVmRSS * myData.iMemPageSize;
188
iTotalMemory = iVmRSS * pSharedMemory->iMemPageSize;
205
190
//g_print ("%s : %d -> %d\n", pProcess->cName, pProcess->iCpuTime, iNewCpuTime);
206
191
if (pProcess->iCpuTime != 0 && fTimeElapsed != 0)
207
pProcess->fCpuPercent = (iNewCpuTime - pProcess->iCpuTime) / myConfig.fUserHZ / myData.iNbCPU / fTimeElapsed;
192
pProcess->fCpuPercent = (iNewCpuTime - pProcess->iCpuTime) / pSharedMemory->fUserHZ / pSharedMemory->iNbCPU / fTimeElapsed;
208
193
pProcess->iCpuTime = iNewCpuTime;
209
194
pProcess->iMemAmount = iTotalMemory;
211
_cd_sysmonitor_insert_process_in_top_list (myApplet, pProcess);
196
_cd_sysmonitor_insert_process_in_top_list (pSharedMemory, pProcess);
214
199
g_dir_close (dir);
202
static gboolean _clean_one_old_processes (int *iPid, CDProcess *pProcess, double *fTime)
204
if (pProcess->fLastCheckTime < *fTime)
218
static void _cd_sysmonitor_get_top_list (CairoDockModuleInstance *myApplet)
209
static void _cd_sysmonitor_get_top_list (CDTopSharedMemory *pSharedMemory)
220
// on recupere le delta T.
221
g_timer_stop (myData.pTopClock);
222
double fTimeElapsed = g_timer_elapsed (myData.pTopClock, NULL);
223
g_timer_start (myData.pTopClock);
211
// get the elapsed time since the last 'top'.
213
if (pSharedMemory->pTopClock == NULL)
215
pSharedMemory->pTopClock = g_timer_new ();
220
g_timer_stop (pSharedMemory->pTopClock);
221
fTimeElapsed = g_timer_elapsed (pSharedMemory->pTopClock, NULL);
222
g_timer_start (pSharedMemory->pTopClock);
225
// get the current time.
224
226
GTimeVal time_val;
225
227
g_get_current_time (&time_val); // on pourrait aussi utiliser un compteur statique a la fonction ...
226
228
double fTime = time_val.tv_sec + time_val.tv_usec * 1e-6;
227
// on recupere les donnees de tous les processus.
228
_cd_sysmonitor_get_process_data (myApplet, fTime, fTimeElapsed);
229
// on nettoie la table des vieux processus.
230
cd_sysmonitor_clean_old_processes (myApplet, fTime);
230
// get the data for all processes.
231
_cd_sysmonitor_get_process_data (pSharedMemory, fTime, fTimeElapsed);
233
// clean the table from old processes.
234
g_hash_table_foreach_remove (pSharedMemory->pProcessTable, (GHRFunc) _clean_one_old_processes, &fTime);
233
static gboolean _cd_sysmonitor_update_top_list (CairoDockModuleInstance *myApplet)
238
static gboolean _cd_sysmonitor_update_top_list (CDTopSharedMemory *pSharedMemory)
235
// On ecrit les processus dans l'ordre.
240
CairoDockModuleInstance *myApplet = pSharedMemory->pApplet;
243
// determine the max length of process names.
237
244
CDProcess *pProcess;
239
246
guint iNameLength = 0;
240
for (i = 0; i < myConfig.iNbDisplayedProcesses; i ++)
247
for (i = 0; i < pSharedMemory->iNbDisplayedProcesses; i ++)
242
pProcess = myData.pTopList[i];
249
pProcess = pSharedMemory->pTopList[i];
243
250
if (pProcess == NULL || pProcess->cName == NULL)
245
252
iNameLength = MAX (iNameLength, strlen (pProcess->cName));
248
gchar *cSpaces = g_new0 (gchar, iNameLength+1);
255
// write the processes in the form "name (pid) : 15.2% - 12.3Mb".
256
gchar *cSpaces = g_new0 (gchar, iNameLength+6+1); // name + pid(<1e6) + '\0'
249
257
memset (cSpaces, ' ', iNameLength);
251
259
GString *sTopInfo = g_string_new ("");
252
for (i = 0; i < myConfig.iNbDisplayedProcesses; i ++)
260
for (i = 0; i < pSharedMemory->iNbDisplayedProcesses; i ++)
254
pProcess = myData.pTopList[i];
262
pProcess = pSharedMemory->pTopList[i];
255
263
if (pProcess == NULL || pProcess->cName == NULL)
257
iOffset = iNameLength-strlen (pProcess->cName);
258
if (pProcess->iPid < 1e5)
265
// determine the number of spaces needed to have a correct alignment.
266
iNbSpaces = iNameLength - strlen (pProcess->cName);
267
if (pProcess->iPid < 1e5) // no PID is >= 1e6; if ever it was, there would just be a small offset of the cpu and ram values displayed.
260
269
if (pProcess->iPid < 1e4)
286
295
(pProcess->fCpuPercent > .1 ? "" : " "),
287
296
(double) pProcess->iMemAmount / (myConfig.bTopInPercent && myData.ramTotal ? 10.24 * myData.ramTotal : 1024 * 1024),
288
297
(myConfig.bTopInPercent && myData.ramTotal ? "%" : D_("Mb")));
289
cSpaces[iOffset] = ' ';
298
cSpaces[iNbSpaces] = ' ';
291
300
g_free (cSpaces);
292
if (i == 0) // liste vide.
302
// display the info on the dialog.
303
if (sTopInfo->len == 0) // empty list, let the default message ("loading").
294
305
g_string_free (sTopInfo, TRUE);
295
306
CD_APPLET_LEAVE (TRUE);
298
sTopInfo->str[sTopInfo->len-1] = '\0';
308
else // remove the trailing \n.
310
sTopInfo->str[sTopInfo->len-1] = '\0';
300
// on affiche ca sur le dialogue.
301
313
cairo_dock_render_dialog_with_new_data (myData.pTopDialog, (CairoDialogRendererDataPtr) sTopInfo->str);
302
314
g_string_free (sTopInfo, TRUE);
304
if (myData.iNbProcesses != g_hash_table_size (myData.pProcessTable))
316
// update the dialog title with the total number of processes if it has changed.
317
if (myData.iNbProcesses != g_hash_table_size (pSharedMemory->pProcessTable))
306
myData.iNbProcesses = g_hash_table_size (myData.pProcessTable);
307
gchar *cTitle = g_strdup_printf (" [ Top %d / %d ] :", myConfig.iNbDisplayedProcesses, myData.iNbProcesses);
319
myData.iNbProcesses = g_hash_table_size (pSharedMemory->pProcessTable);
320
gchar *cTitle = g_strdup_printf (" [ Top %d / %d ] :", pSharedMemory->iNbDisplayedProcesses, myData.iNbProcesses);
308
321
cairo_dock_set_dialog_message (myData.pTopDialog, cTitle);
325
// update the sort for the next step.
326
pSharedMemory->bSortTopByRam = myData.bSortTopByRam;
311
328
CD_APPLET_LEAVE (TRUE);
317
void cd_sysmonitor_stop_top_dialog (CairoDockModuleInstance *myApplet)
319
if (myData.pTopDialog == NULL)
321
// on arrete la mesure.
322
cairo_dock_stop_task (myData.pTopTask);
323
// on detruit le dialogue.
324
cairo_dock_dialog_unreference (myData.pTopDialog);
325
myData.pTopDialog = NULL;
326
cairo_surface_destroy (myData.pTopSurface);
327
myData.pTopSurface = NULL;
328
g_timer_destroy (myData.pTopClock);
329
myData.pTopClock = NULL;
330
// on libere la liste des processus.
331
cd_sysmonitor_clean_all_processes (myApplet);
334
static void _sort_one_process (int *iPid, CDProcess *pProcess, CairoDockModuleInstance *myApplet)
336
_cd_sysmonitor_insert_process_in_top_list (myApplet, pProcess);
332
static void _free_shared_memory (CDTopSharedMemory *pSharedMemory)
334
g_hash_table_destroy (pSharedMemory->pProcessTable);
335
g_free (pSharedMemory->pTopList);
336
g_timer_destroy (pSharedMemory->pTopClock);
337
g_free (pSharedMemory);
339
static void cd_sysmonitor_launch_top_task (CairoDockModuleInstance *myApplet)
341
g_return_if_fail (myData.pTopTask == NULL);
343
myData.iNbProcesses = 0;
344
if (myData.iNbCPU == 0)
345
cd_sysmonitor_get_cpu_info (myApplet, NULL);
347
CDTopSharedMemory *pSharedMemory = g_new0 (CDTopSharedMemory, 1);
348
pSharedMemory->iNbDisplayedProcesses = myConfig.iNbDisplayedProcesses;
349
pSharedMemory->fUserHZ = myConfig.fUserHZ;
350
pSharedMemory->iNbCPU = myData.iNbCPU;
351
pSharedMemory->pApplet = myApplet;
353
myData.pTopTask = cairo_dock_new_task_full (myConfig.iProcessCheckInterval,
354
(CairoDockGetDataAsyncFunc) _cd_sysmonitor_get_top_list,
355
(CairoDockUpdateSyncFunc) _cd_sysmonitor_update_top_list,
356
(GFreeFunc) _free_shared_memory,
358
cairo_dock_launch_task (myData.pTopTask);
361
static void _sort_one_process (int *iPid, CDProcess *pProcess, CDTopSharedMemory *pSharedMemory)
363
_cd_sysmonitor_insert_process_in_top_list (pSharedMemory, pProcess);
338
365
static void _on_change_order (int iClickedButton, GtkWidget *pInteractiveWidget, CairoDockModuleInstance *myApplet, CairoDialog *pDialog)
367
if (iClickedButton == 2 || iClickedButton == -2) // 'close' button or Escape, just return and let the dialog be destroyed.
340
371
gboolean bSortByRamNew = (iClickedButton == 1);
341
if (bSortByRamNew != myData.bSortTopByRam) // on peut lire myData.bSortTopByRam car le thread n'y accede qu'en lecture.
372
if (bSortByRamNew != myData.bSortTopByRam) // we'll sort the result immediately, so that the user doesn't have to wait until the next measure to see the result.
343
cairo_dock_stop_task (myData.pTopTask); // le thread se termine.
344
374
myData.bSortTopByRam = bSortByRamNew;
345
memset (myData.pTopList, 0, myConfig.iNbDisplayedProcesses * sizeof (CDProcess *)); // on re-trie tout suivant le nouvel ordre.
346
g_hash_table_foreach (myData.pProcessTable, (GHFunc) _sort_one_process, myApplet);
347
_cd_sysmonitor_update_top_list (myApplet); // on redessine.
348
cairo_dock_launch_task_delayed (myData.pTopTask, 1000. * myConfig.iProcessCheckInterval); // on relance en gardant un intervalle de temps constant, sinon relancer la mesure tout de suite risquerait de donner des resultats peu precis.
376
cairo_dock_stop_task (myData.pTopTask); // blocks until the thread terminates.
378
CDTopSharedMemory *pSharedMemory = myData.pTopTask->pSharedMemory; // this is ok only because we stopped the task beforehand.
379
pSharedMemory->bSortTopByRam = bSortByRamNew;
380
if (pSharedMemory->pTopList != NULL && pSharedMemory->iNbDisplayedProcesses != 0)
382
memset (pSharedMemory->pTopList, 0, pSharedMemory->iNbDisplayedProcesses * sizeof (CDProcess *)); // on re-trie tout suivant le nouvel ordre.
383
g_hash_table_foreach (pSharedMemory->pProcessTable, (GHFunc) _sort_one_process, pSharedMemory);
384
_cd_sysmonitor_update_top_list (pSharedMemory); // on redessine.
387
cairo_dock_launch_task_delayed (myData.pTopTask, 1000. * myConfig.iProcessCheckInterval); // restart the task with a delay equal to the interval, to keep the measure accurate.
350
cairo_dock_dialog_reference (pDialog);
389
cairo_dock_dialog_reference (pDialog); // keep the dialog alive.
391
static void _on_dialog_destroyed (CairoDockModuleInstance *myApplet)
393
// discard the 'top' task.
394
cairo_dock_discard_task (myData.pTopTask);
395
myData.pTopTask = NULL;
398
myData.pTopDialog = NULL;
352
400
void cd_sysmonitor_start_top_dialog (CairoDockModuleInstance *myApplet)
354
402
g_return_if_fail (myData.pTopDialog == NULL);
355
// on cree le dialogue.
403
// build an interactive widget that will be used to display the top list.
356
404
gchar *cTitle = g_strdup_printf (" [ Top %d ] :", myConfig.iNbDisplayedProcesses);
357
405
GtkWidget *pInteractiveWidget = gtk_vbox_new (FALSE, 0);
358
406
gtk_widget_set_size_request (pInteractiveWidget,
359
407
myConfig.pTopTextDescription->iSize * 15,
360
408
myConfig.pTopTextDescription->iSize * myConfig.iNbDisplayedProcesses); // approximatif au depart.
361
/*myData.pTopDialog = cairo_dock_show_dialog_full (cTitle,
365
MY_APPLET_SHARE_DATA_DIR"/"MY_APPLET_ICON_FILE,
370
411
CairoDialogAttribute attr;
371
412
memset (&attr, 0, sizeof (CairoDialogAttribute));
372
413
attr.cText = cTitle;
374
415
attr.pInteractiveWidget = pInteractiveWidget;
375
416
attr.pActionFunc = (CairoDockActionOnAnswerFunc) _on_change_order;
376
417
attr.pUserData = myApplet;
377
const gchar *cButtons[3] = {MY_APPLET_SHARE_DATA_DIR"/button-cpu.png", MY_APPLET_SHARE_DATA_DIR"/button-ram.png", NULL};
418
attr.pFreeDataFunc = (GFreeFunc) _on_dialog_destroyed;
419
const gchar *cButtons[] = {MY_APPLET_SHARE_DATA_DIR"/button-cpu.svg", MY_APPLET_SHARE_DATA_DIR"/button-ram.svg", "cancel", NULL};
378
420
attr.cButtonsImage = cButtons;
379
myData.pTopDialog = cairo_dock_build_dialog (&attr, myIcon, myContainer);
421
myData.pTopDialog = cairo_dock_build_dialog (&attr, myIcon, myContainer);
382
424
g_return_if_fail (myData.pTopDialog != NULL);
384
const gpointer pConfig[2] = {myConfig.pTopTextDescription, (const gpointer)"Loading ..."};
426
// set a dialog renderer of type 'text'.
427
const gpointer pConfig[2] = {myConfig.pTopTextDescription, (const gpointer)D_("Loading")};
385
428
cairo_dock_set_dialog_renderer_by_name (myData.pTopDialog, "Text", (CairoDialogRendererConfigPtr) pConfig);
387
// on lance la mesure.
388
myData.pTopClock = g_timer_new ();
389
myData.iNbProcesses = 0;
390
if (myData.pTopTask == NULL)
391
myData.pTopTask = cairo_dock_new_task (myConfig.iProcessCheckInterval,
392
(CairoDockGetDataAsyncFunc) _cd_sysmonitor_get_top_list,
393
(CairoDockUpdateSyncFunc) _cd_sysmonitor_update_top_list,
395
cairo_dock_launch_task (myData.pTopTask);
430
// launch the 'top' task.
431
cd_sysmonitor_launch_top_task (myApplet);