~ubuntu-branches/ubuntu/utopic/parcellite/utopic

« back to all changes in this revision

Viewing changes to .pc/menu_popup_on_start.patch/src/main.c

  • Committer: Package Import Robot
  • Author(s): Andrew Starr-Bochicchio
  • Date: 2014-06-08 15:20:01 UTC
  • Revision ID: package-import@ubuntu.com-20140608152001-ogzb8yt9s11xozbj
Tags: 1.1.7-2
Backport upstream commit to stop menu from popping
up on start up under Unity (LP: #1298580).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2007-2008 by Xyhthyx <xyhthyx@gmail.com>
 
2
 *
 
3
 * This file is part of Parcellite.
 
4
 *
 
5
 * Parcellite is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 3 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * Parcellite is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
17
 
 
18
NOTES:
 
19
We keep track of a delete list while the history menu is up. We add/remove items from that 
 
20
list until we get a selection done event, then we delete those items from the real history
 
21
 
 
22
From http://standards.freedesktop.org/clipboards-spec/clipboards-latest.txt
 
23
 
 
24
Application authors should follow the following guidelines to get
 
25
correct behavior:
 
26
 
 
27
 - selecting but with no explicit copy should only set PRIMARY,
 
28
   never CLIPBOARD
 
29
 
 
30
 - middle mouse button should paste PRIMARY, never CLIPBOARD
 
31
 
 
32
 - explicit cut/copy commands (i.e. menu items, toolbar buttons)
 
33
   should always set CLIPBOARD to the currently-selected data (i.e.
 
34
   conceptually copy PRIMARY to CLIPBOARD)
 
35
 
 
36
 - explicit cut/copy commands should always set both CLIPBOARD and
 
37
   PRIMARY, even when copying doesn't involve a selection (e.g. a
 
38
   "copy url" -option which explicitly copies an url without the
 
39
   url being selected first)
 
40
 
 
41
 - explicit paste commands should paste CLIPBOARD, not PRIMARY
 
42
 
 
43
 - a selection becoming unselected should never unset PRIMARY
 
44
 
 
45
 - possibly contradicting the ICCCM, clients don't need to support
 
46
   SECONDARY, though if anyone can figure out what it's good
 
47
   for they should feel free to use it for that
 
48
 
 
49
 - cut buffers are evil; they only support ASCII, they don't 
 
50
   work with many clients, and they require data to be 
 
51
   copied to the X server. Therefore clients should avoid 
 
52
   using cut buffers and use only selections.
 
53
   
 
54
We can monitor ownership change with:
 
55
// This callback is invoked when the clipboard owner changes.
 
56
void handle_owner_change(GtkClipboard *clipboard, GdkEvent *event,  gpointer data){     }
 
57
}
 
58
g_signal_connect(clipboard, "owner-change",  G_CALLBACK(handle_owner_change), NULL);
 
59
 */
 
60
 
 
61
#ifdef HAVE_CONFIG_H
 
62
#include <config.h>
 
63
#endif
 
64
 
 
65
#include "parcellite.h"
 
66
 
 
67
/**ACT are actions, and MODE is the mode of the action  */
 
68
/** #define ACT_STOP  0
 
69
#define ACT_RUN   1 */
 
70
 
 
71
/** defines the mode of the above actions. These are bit-wise */
 
72
#define CMODE_PRI 1
 
73
#define CMODE_CLI 2
 
74
#define CMODE_ALL 3 /**needs to be or of the above  */
 
75
 
 
76
#define FIFCMD_STOP_PRI "stop_pri"
 
77
#define FIFCMD_STOP_CLI "stop_cli"
 
78
#define FIFCMD_STOP_ALL "stop_all"
 
79
#define FIFCMD_RUN_PRI "run_pri"
 
80
#define FIFCMD_RUN_CLI "run_cli"
 
81
#define FIFCMD_RUN_ALL "run_all"
 
82
 
 
83
GtkWidget *hmenu;
 
84
/* Uncomment the next line to print a debug trace. */
 
85
/*#define DEBUG     */
 
86
 
 
87
#ifdef DEBUG
 
88
#  define TRACE(x) x
 
89
#else
 
90
#  define TRACE(x) do {} while (FALSE);
 
91
#endif
 
92
/**see parcellite.h for define  */
 
93
#ifdef DEBUG_UPDATE
 
94
static int debug_update=0; /**disable/enable DTRACE  */
 
95
#  define DTRACE(x) if (debug_update) x
 
96
#else
 
97
#  define DTRACE(x) do {} while (FALSE);
 
98
#endif
 
99
 
 
100
static GtkClipboard* primary;
 
101
static GtkClipboard* clipboard;
 
102
struct p_fifo *fifo;
 
103
#ifdef HAVE_APPINDICATOR
 
104
static AppIndicator *indicator=NULL;
 
105
static GtkWidget *indicator_menu = NULL;
 
106
#endif
 
107
static GtkStatusIcon *status_icon; 
 
108
static GMutex *clip_lock=NULL;
 
109
GMutex *hist_lock=NULL;
 
110
static gboolean actions_lock = FALSE;
 
111
static int show_icon=0;
 
112
static int have_appindicator=0; /**if set, we have a running indicator-appmenu  */
 
113
static gchar *appindicator_process="indicator-messages-service"; /**process name  */
 
114
 
 
115
static int cmd_mode=CMODE_ALL; /**both clipboards  */
 
116
/** static int cmd_state=ACT_RUN; running  */
 
117
/**defines for moving between clipboard histories  */
 
118
#define HIST_MOVE_TO_CANCEL     0
 
119
#define HIST_MOVE_TO_OK         1
 
120
/**clipboard handling modes  */
 
121
#define H_MODE_INIT  0  /**clear out clipboards  */
 
122
#define H_MODE_NEW  1   /**new text, process it  */
 
123
#define H_MODE_LIST 2   /**from list, just put it on the clip  */
 
124
#define H_MODE_CHECK 3 /**see if there is new/lost contents.   */
 
125
#define H_MODE_LAST  4 /**just return the last updated value.  */
 
126
#define H_MODE_IGNORE 5 /**just put it on the clipboard, do not process 
 
127
                       and do not add to hist list  */
 
128
 
 
129
#define EDIT_MODE_USE_RIGHT_CLICK 1 /**used in edit dialog creation to determine behaviour. 
 
130
                                    If this is set, it will edit the entry, and replace it in the history.  */
 
131
#define EDIT_MODE_RC_EDIT_SET 2 /**used to   */                                    
 
132
 
 
133
/**protos in this file  */
 
134
void create_app_indicator(void);
 
135
 
 
136
/**Turns up in 2.16  */
 
137
int p_strcmp (const char *str1, const char *str2)
 
138
{
 
139
#if (GTK_MAJOR_VERSION > 2 || ( GTK_MAJOR_VERSION == 2 && GTK_MAJOR_VERSION >= 16))
 
140
  return g_strcmp0(str1,str2);
 
141
#else
 
142
  if(NULL ==str1 && NULL == str2)
 
143
    return 0;
 
144
  if(NULL ==str1 && str2)
 
145
    return -1;
 
146
  if(NULL ==str2 && str1)
 
147
    return 1;
 
148
  return strcmp(str1,str2);
 
149
#endif
 
150
}
 
151
 
 
152
/***************************************************************************/
 
153
/** Process the text based on our preferences.
 
154
\n\b Arguments:
 
155
\n\b Returns: processed text, or NULL if it is invalid.
 
156
****************************************************************************/
 
157
gchar *process_new_item(GtkClipboard *clip,gchar *ntext)
 
158
{
 
159
        glong len;
 
160
        gchar *rtn=NULL;
 
161
        if(NULL == ntext)
 
162
                return NULL;
 
163
        
 
164
        
 
165
/**we now check our options...  */              
 
166
        /*printf("opt\n"); fflush(NULL); */
 
167
        if (get_pref_int32("hyperlinks_only")){
 
168
                 if(is_hyperlink(ntext))
 
169
                                goto process;
 
170
        }       else {
 
171
                /*printf("wo\n"); fflush(NULL); */
 
172
                if(get_pref_int32("ignore_whiteonly")){
 
173
                        gchar *s;
 
174
                        for (s=ntext; NULL !=s && *s; ++s){
 
175
                                if(!isspace(*s)){
 
176
                /*                      printf("Saw 0x%x\n",*s); */
 
177
                                        goto process;
 
178
                                        break;
 
179
                                }
 
180
                        }
 
181
                }else
 
182
                        goto process;
 
183
        }
 
184
        /**set the clipboard to the last entry - effectively deleting this entry */
 
185
        goto done;
 
186
        
 
187
 process:  /**now process the text.  */
 
188
        /*printf("proc\n"); fflush(NULL); */
 
189
  len=strlen(ntext);/*g_utf8_strlen(ntext,-1); */
 
190
  len= validate_utf8_text(ntext, len);
 
191
        if(len){
 
192
                rtn=ntext;
 
193
                gint i;
 
194
                if(get_pref_int32("trim_newline")){
 
195
                        gchar *c;
 
196
                        for (c=ntext;*c;){
 
197
                                if(iscntrl(*c))
 
198
                                        *c=' ';
 
199
                                c=g_utf8_next_char(c);
 
200
                        }       
 
201
                }
 
202
                        
 
203
                if( get_pref_int32("trim_wspace_begend") )
 
204
                        ntext=g_strstrip(ntext);
 
205
        }       
 
206
done:
 
207
        return rtn;     
 
208
}
 
209
 
 
210
 
 
211
/***************************************************************************/
 
212
/** .
 
213
\n\b Arguments:
 
214
\n\b Returns:   text that was updated or NULL if not.
 
215
****************************************************************************/
 
216
gchar *_update_clipboard (GtkClipboard *clip, gchar *n, gchar **old, int set)
 
217
{
 
218
        
 
219
        /*return NULL; */
 
220
        if(NULL != n)   {
 
221
#ifdef DEBUG_UPDATE
 
222
                if(clip==primary)
 
223
                        g_printf("set PRI to %s\n",n);
 
224
                else
 
225
                        g_printf("set CLI to %s\n",n);
 
226
#endif
 
227
                if( set)
 
228
                        gtk_clipboard_set_text(clip, n, -1);
 
229
                if(NULL != old ){
 
230
                        if( NULL != *old)
 
231
                        g_free(*old);
 
232
                        *old=g_strdup(n);
 
233
                        return *old;
 
234
                }       
 
235
        }else if( NULL != old){
 
236
                if(NULL != *old)
 
237
                  g_free(*old);
 
238
                *old=NULL;
 
239
        }
 
240
                
 
241
        return NULL;
 
242
}
 
243
 
 
244
/***************************************************************************/
 
245
/** This checks to see if ANY content exists (i.e. like images).
 
246
\n\b Arguments:
 
247
\n\b Returns:
 
248
****************************************************************************/
 
249
gboolean content_exists(GtkClipboard *clip)
 
250
{
 
251
        gint count;
 
252
        GdkAtom *targets;
 
253
        gboolean contents = gtk_clipboard_wait_for_targets(clip, &targets, &count);
 
254
        g_free(targets);
 
255
        return contents;
 
256
}
 
257
 
 
258
/***************************************************************************/
 
259
/** 
 
260
\n\b Arguments:
 
261
\n\b Returns:    clipboard contents, to be freed with g_free, or NULL if empty.
 
262
****************************************************************************/
 
263
gchar *is_clipboard_empty(GtkClipboard *clip)
 
264
{
 
265
  /** int count;
 
266
  GdkAtom *targets;
 
267
        if(clipboard == clip) g_printf("-%s-",gtk_clipboard_wait_for_text(clip));
 
268
  gboolean contents = gtk_clipboard_wait_for_targets(clip, &targets, &count);
 
269
        if(clipboard == clip) g_printf("-%s-2nd-",gtk_clipboard_wait_for_text(clip));
 
270
  g_free(targets);
 
271
        if(TRUE == contents || count >0)
 
272
                return 0;*/
 
273
#if 1
 
274
         if(TRUE == gtk_clipboard_wait_is_text_available(clip))
 
275
        return(gtk_clipboard_wait_for_text(clip));
 
276
#else   
 
277
        /**attempt to fix  bug 87, Error converting selection from UTF8_STRING  
 
278
        Go http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
 
279
        line 2.3.4 will reproduce this using FireFox.   */
 
280
        if(TRUE == gtk_clipboard_wait_is_text_available(clip)){
 
281
                gchar *x=gtk_clipboard_wait_for_text(clip);
 
282
                if(FALSE == g_utf8_validate(x,-1,NULL))
 
283
                        gtk_clipboard_set_text(clip,"_BAD_UTF8_",-1);
 
284
                /** ulong l1, l2;
 
285
                l1=strlen*/
 
286
                /**if NULL == x, we have a problem with whatever is in the clipboard.  */
 
287
                /*if(NULL ==x) */
 
288
                        
 
289
                return(x);
 
290
        }
 
291
#endif          
 
292
        return NULL;
 
293
}
 
294
 
 
295
/***************************************************************************/
 
296
/** Update one clipboard at a time.
 
297
\n\b Arguments:
 
298
\n\b Returns:
 
299
****************************************************************************/
 
300
gchar *update_clipboard(GtkClipboard *clip,gchar *intext,  gint mode)
 
301
{
 
302
        /**current/last item in clipboard  */
 
303
        static gchar *ptext=NULL;
 
304
        static gchar *ctext=NULL;
 
305
        static gchar *last=NULL; /**last text change, for either clipboard  */
 
306
        gchar **existing, *changed=NULL;
 
307
        gchar *processed;
 
308
        GdkModifierType button_state;
 
309
/*      gchar *clipname; */
 
310
        int set=1;
 
311
        if( H_MODE_LAST == mode)
 
312
                return last;
 
313
        if(clip==primary){
 
314
/*              clipname="PRI "; */
 
315
                existing=&ptext;
 
316
        }       else{
 
317
/*              clipname="CLI "; */
 
318
                existing=&ctext;
 
319
        }
 
320
        
 
321
        /** if(H_MODE_CHECK!=mode )      */
 
322
   /*g_printf("HC%d-%c: in %s,ex %s\n",mode,clip==primary?'p':'c',intext,*existing); */
 
323
        if( H_MODE_INIT == mode){
 
324
                if(NULL != *existing)
 
325
                        g_free(*existing);
 
326
                *existing=NULL;
 
327
                if(NULL != intext)
 
328
                        _update_clipboard(clip,intext,NULL,1);
 
329
/*              gtk_clipboard_set_text(clip, intext, -1); */
 
330
                return NULL;
 
331
        }
 
332
        /**check that our clipboards are valid and user wants to use them  */
 
333
        if((clip != primary && clip != clipboard) ||
 
334
                (clip == primary && !get_pref_int32("use_primary")) ||
 
335
                (clip == clipboard && !get_pref_int32("use_copy")))
 
336
                        return NULL;
 
337
        
 
338
        if( H_MODE_CHECK==mode &&clip == primary){/*fix auto-deselect of text in applications like DevHelp and LyX*/
 
339
        gdk_window_get_pointer(NULL, NULL, NULL, &button_state);
 
340
                if ( button_state & (GDK_BUTTON1_MASK|GDK_SHIFT_MASK) ) /**button down, done.  */
 
341
                        goto done;
 
342
        }
 
343
        if(0 && NULL != intext){ /**we run this in process_new_item  */
 
344
                validate_utf8_text(intext,strlen(intext));
 
345
        }       
 
346
        /*g_printf("BS=0x%02X ",button_state); */
 
347
        if( H_MODE_IGNORE == mode){     /**ignore processing and just put it on the clip.  */
 
348
                DTRACE(g_fprintf(stderr,"%sJustSet '%s'\n",clip==clipboard?"CLI":"PRI",intext)); 
 
349
                _update_clipboard(clip,intext,NULL,1);
 
350
                /*gtk_clipboard_set_text(clip, intext, -1); */
 
351
                return intext;
 
352
        }
 
353
        if(H_MODE_LIST == mode && 0 != p_strcmp(intext,*existing)){ /**just set clipboard contents. Already in list  */
 
354
                DTRACE(g_fprintf(stderr,"%sInList '%s' ex '%s'\n",clip==clipboard?"CLI":"PRI",intext,*existing)); 
 
355
                last=_update_clipboard(clip,intext,existing,1);
 
356
                if( NULL != last){/**maintain persistence, if set  */
 
357
                        append_item(last,get_pref_int32("current_on_top")?HIST_DEL|HIST_CHECKDUP|HIST_KEEP_FLAGS:0);
 
358
                }
 
359
                goto done;
 
360
        }
 
361
        /**check for lost contents and restore if lost */
 
362
        changed=is_clipboard_empty(clip);
 
363
        if(NULL != changed){
 
364
                if(0 == validate_utf8_text(changed,strlen(changed)))
 
365
                        goto done;
 
366
        }
 
367
        
 
368
        if(NULL != *existing && NULL == changed && 1 == get_pref_int32("restore_empty")) {
 
369
                DTRACE(g_fprintf(stderr,"%sclp empty, ",clip==clipboard?"CLI":"PRI"));
 
370
                /* Only recover lost contents if there isn't any other type of content in the clipboard */
 
371
                if (!content_exists(clip)) {
 
372
                        DTRACE(g_fprintf(stderr,"set to '%s'\n",*existing));  
 
373
                        _update_clipboard(clip, *existing,NULL,1);
 
374
        /*gtk_clipboard_set_text(clip, *existing, -1); */
 
375
                        last=*existing;
 
376
                }       else
 
377
                        DTRACE(g_fprintf(stderr,"Left Null\n"));  
 
378
                return *existing;
 
379
  }
 
380
        if(NULL == changed)
 
381
                return NULL;                                                                                                                                    
 
382
        /**check for changed clipboard content - in all modes */
 
383
        /*changed=gtk_clipboard_wait_for_text(clip); */
 
384
        if(0 == p_strcmp(*existing, changed) ){
 
385
                g_free(changed);                    /**no change, do nothing  */
 
386
                changed=NULL;
 
387
        }       else {
 
388
                DTRACE(g_fprintf(stderr,"%sclp changed: ex '%s' is '%s' - ",clip==clipboard?"CLI":"PRI",*existing,changed)); 
 
389
                if(NULL != (processed=process_new_item(clip,changed)) ){ 
 
390
                        /**only check processed/changed. No need to update this clip, since the text is already there.  */
 
391
                         if(0 == p_strcmp(processed,changed)) set=0;
 
392
                        else set=1; 
 
393
                        DTRACE(g_fprintf(stderr,"set=%d. p='%s'\n",set,processed));
 
394
                        /*set=1; */ /** Always set the text.*/
 
395
                        last=_update_clipboard(clip,processed,existing,set);
 
396
                }else {/**restore clipboard - new item is binary/garbage/empty */
 
397
                        gchar *d;
 
398
                        
 
399
                        if(NULL ==*existing && NULL != history_list){
 
400
                                struct history_item *c;
 
401
                                c=(struct history_item *)(history_list->data);  
 
402
                                d=c->text;
 
403
                        }else 
 
404
                                d=*existing;
 
405
                        if(NULL != d){
 
406
                                DTRACE(g_fprintf(stderr,"\n%srestore clp '%s', ex='%s'\n",clip==clipboard?"CLI":"PRI",d,*existing)); 
 
407
                                last=_update_clipboard(clip,d,existing,1);
 
408
                        }
 
409
                                
 
410
                }
 
411
                if(NULL != last)
 
412
                        append_item(last,get_pref_int32("current_on_top")?HIST_DEL|HIST_CHECKDUP|HIST_KEEP_FLAGS:0);
 
413
                g_free(changed);
 
414
                changed=NULL;
 
415
        }
 
416
        if( H_MODE_CHECK==mode ){
 
417
                goto done;
 
418
        }
 
419
/**FIXME: Do we use the changed clip item or the one passed to us?  
 
420
        hmmm Use the changed one.
 
421
        
 
422
        */              
 
423
        
 
424
        if(H_MODE_NEW==mode){
 
425
                if(NULL != (processed=process_new_item(clip,intext)) ){
 
426
/*                      g_printf("%sNEW '%s'\n",clipname,processed); */
 
427
                        if(0 == p_strcmp(processed,*existing))set=0;
 
428
                        else set=1;
 
429
                        last=_update_clipboard(clip,processed,existing,set);
 
430
                        if(NULL != last)
 
431
                                append_item(last,get_pref_int32("current_on_top")?HIST_DEL|HIST_CHECKDUP|HIST_KEEP_FLAGS:0);
 
432
                }else 
 
433
                        return NULL;    
 
434
        }
 
435
                
 
436
done:
 
437
        return *existing;
 
438
}
 
439
 
 
440
/***************************************************************************/
 
441
/** Convience function to update both clipboards at the same time
 
442
\n\b Arguments:
 
443
\n\b Returns:
 
444
****************************************************************************/
 
445
void update_clipboards(gchar *intext, gint mode)
 
446
{
 
447
        /*g_printf("upclips\n"); */
 
448
        update_clipboard(primary, intext, mode);
 
449
        update_clipboard(clipboard, intext, mode);
 
450
}
 
451
 
 
452
/***************************************************************************/
 
453
/** Run a command. For now, just start and stop
 
454
\n\b Arguments:
 
455
\n\b Returns:
 
456
****************************************************************************/
 
457
void do_command(gchar *buf, gint len)
 
458
{
 
459
  g_printf("Got '%s' cmd\n",buf);
 
460
        if(!p_strcmp(buf,FIFCMD_RUN_ALL)) {
 
461
                cmd_mode|=CMODE_ALL;
 
462
                return;
 
463
        }       
 
464
        if(!p_strcmp(buf,FIFCMD_RUN_CLI)) {
 
465
                cmd_mode|=CMODE_CLI;
 
466
                return;
 
467
        }       
 
468
        if(!p_strcmp(buf,FIFCMD_RUN_PRI)) {
 
469
                cmd_mode|=CMODE_PRI;
 
470
                return;
 
471
        }       
 
472
        if(!p_strcmp(buf,FIFCMD_STOP_ALL)) {
 
473
                cmd_mode&=~(CMODE_ALL);
 
474
                return;
 
475
        }
 
476
                if(!p_strcmp(buf,FIFCMD_STOP_CLI)) {
 
477
                cmd_mode&=~(CMODE_CLI);
 
478
                return;
 
479
        }
 
480
                if(!p_strcmp(buf,FIFCMD_STOP_PRI)) {
 
481
                cmd_mode&=~(CMODE_PRI);
 
482
                return;
 
483
        }
 
484
        
 
485
}
 
486
 
 
487
/***************************************************************************/
 
488
/** Checks the clipboards and fifos for changes.
 
489
\n\b Arguments:
 
490
\n\b Returns:
 
491
****************************************************************************/
 
492
void check_clipboards(gint mode)
 
493
{
 
494
        gchar *ptext, *ctext, *last;
 
495
        int n=0;
 
496
        
 
497
        /*g_printf("check_clipboards\n"); */
 
498
        /*g_mutex_lock(clip_lock); */
 
499
        if(fifo->clen){/**we have a command to execute  */
 
500
                        /*fifo->which should be ID_CMD: */
 
501
                if(fifo->dbg) g_printf("Running CMD '%s'\n",fifo->cbuf);
 
502
                do_command(fifo->cbuf, fifo->clen);
 
503
                if(fifo->dbg) g_printf("mode is 0x%X\n",cmd_mode);
 
504
                fifo->clen=0;
 
505
                return;
 
506
        }       
 
507
        if(!(CMODE_ALL & cmd_mode))
 
508
                return;
 
509
        if(fifo->rlen >0){
 
510
                switch(fifo->which){
 
511
                        case ID_PRIMARY:
 
512
                                fifo->rlen=validate_utf8_text(fifo->buf, fifo->rlen);
 
513
                                if(fifo->dbg) g_printf("Setting PRI '%s'\n",fifo->buf);
 
514
                                update_clipboard(primary, fifo->buf, H_MODE_NEW);
 
515
                                fifo->rlen=0;
 
516
                                n=1;
 
517
                                break;
 
518
                        case ID_CLIPBOARD:
 
519
                                fifo->rlen=validate_utf8_text(fifo->buf, fifo->rlen);
 
520
                                if(fifo->dbg) g_printf("Setting CLI '%s'\n",fifo->buf);
 
521
                                update_clipboard(clipboard, fifo->buf, H_MODE_NEW);
 
522
                                n=2;
 
523
                                fifo->rlen=0;
 
524
                                break;
 
525
                        
 
526
                        default:
 
527
                                fifo->rlen=validate_utf8_text(fifo->buf, fifo->rlen);
 
528
                                g_printf("CLIP not set, discarding '%s'\n",fifo->buf);
 
529
                                fifo->rlen=0;
 
530
                                break;
 
531
                }
 
532
        }
 
533
        ptext=update_clipboard(primary, NULL, H_MODE_CHECK);
 
534
        ctext=update_clipboard(clipboard, NULL, H_MODE_CHECK);
 
535
        
 
536
        /*g_printf("pt=%s,ct=%s\n",ptext,ctext); */
 
537
  /* Synchronization */
 
538
  if (get_pref_int32("synchronize"))  {
 
539
  
 
540
                if(NULL==ptext && NULL ==ctext)
 
541
                        goto done;
 
542
                        last=update_clipboard(NULL, NULL, H_MODE_LAST);
 
543
                if( NULL != last && 0 != p_strcmp(ptext,ctext)){
 
544
                        /**last is a copy, of things that may be deallocated  */
 
545
                        last=strdup(last);
 
546
                        /*g_printf("Update clipb '%s' '%s' to '%s'\n",ptext,ctext,last);  */
 
547
                        update_clipboards(last, H_MODE_LIST);
 
548
                        g_free(last);
 
549
                }
 
550
                  
 
551
        }       
 
552
done:   
 
553
        return;
 
554
        /*g_mutex_unlock(clip_lock);     */
 
555
}
 
556
#ifdef HAVE_APPINDICATOR
 
557
/***************************************************************************/
 
558
/** Check for appindicator.
 
559
\n\b Arguments:
 
560
\n\b Returns:
 
561
****************************************************************************/
 
562
gboolean check_for_appindictor( gpointer data)
 
563
 
564
        int mode=PROC_MODE_STRSTR;
 
565
        if(NULL != appindicator_process && !have_appindicator ){
 
566
                /*g_printf("Looking for '%s'\n",appindicator_process); */
 
567
                if(get_pref_int32("multi_user"))
 
568
                        mode|=PROC_MODE_USER_QUALIFY;
 
569
                if(proc_find(appindicator_process,mode,NULL) >0){
 
570
                        have_appindicator=1;
 
571
                        if(NULL == indicator && show_icon)
 
572
                                create_app_indicator(); 
 
573
                        return FALSE;
 
574
                }
 
575
        }
 
576
        return TRUE;
 
577
}
 
578
#endif
 
579
/***************************************************************************/
 
580
/** Called every CHECK_INTERVAL seconds to check for new items 
 
581
\n\b Arguments:
 
582
\n\b Returns:
 
583
****************************************************************************/
 
584
gboolean check_clipboards_tic(gpointer data)
 
585
{
 
586
        /** gchar *txt=gtk_clipboard_wait_for_text(clipboard);
 
587
        g_printf("%s\n",txt);*/
 
588
        check_clipboards(H_MODE_CHECK);
 
589
#ifdef HAVE_APPINDICATOR
 
590
        if(have_appindicator){
 
591
                if(NULL == indicator && show_icon)
 
592
                        create_app_indicator(); 
 
593
        }
 
594
        
 
595
#endif
 
596
        return TRUE;
 
597
}
 
598
 
 
599
/* Thread function called for each action performed */
 
600
static void *execute_action(void *command)
 
601
{
 
602
  /* Execute action */
 
603
  actions_lock = TRUE;
 
604
  if (!have_appindicator && show_icon) {
 
605
  gtk_status_icon_set_from_stock((GtkStatusIcon*)status_icon, GTK_STOCK_EXECUTE);
 
606
  gtk_status_icon_set_tooltip((GtkStatusIcon*)status_icon, _("Executing action..."));
 
607
  }
 
608
  if(system((gchar*)command))
 
609
        g_fprintf(stderr,"sytem command '%s' failed\n",(gchar *)command);
 
610
  if (!have_appindicator &&show_icon) {
 
611
        gtk_status_icon_set_from_icon_name((GtkStatusIcon*)status_icon, PARCELLITE_ICON);
 
612
  gtk_status_icon_set_tooltip((GtkStatusIcon*)status_icon, _("Clipboard Manager"));
 
613
  }
 
614
  actions_lock = FALSE;
 
615
  g_free((gchar*)command);
 
616
  /* Exit this thread */
 
617
  pthread_exit(NULL);
 
618
}
 
619
 
 
620
/* Called when execution action exits */
 
621
static void action_exit(GPid pid, gint status, gpointer data)
 
622
{
 
623
  g_spawn_close_pid(pid);
 
624
  if (!have_appindicator && show_icon) {
 
625
                gtk_status_icon_set_from_icon_name((GtkStatusIcon*)status_icon, PARCELLITE_ICON);
 
626
    gtk_status_icon_set_tooltip((GtkStatusIcon*)status_icon, _("Clipboard Manager"));
 
627
  }
 
628
  actions_lock = FALSE;
 
629
}
 
630
 
 
631
/* Called when an action is selected from actions menu */
 
632
static void action_selected(GtkButton *button, gpointer user_data)
 
633
{
 
634
  /* Change icon and enable lock */
 
635
  actions_lock = TRUE;
 
636
  if (!have_appindicator && show_icon) {
 
637
    gtk_status_icon_set_from_stock((GtkStatusIcon*)status_icon, GTK_STOCK_EXECUTE);
 
638
    gtk_status_icon_set_tooltip((GtkStatusIcon*)status_icon, _("Executing action..."));
 
639
  }
 
640
  /* Insert clipboard into command (user_data), and prepare it for execution */
 
641
  gchar* clipboard_text = gtk_clipboard_wait_for_text(clipboard);
 
642
        g_fprintf(stderr,"Got cmd '%s', text '%s'->",(gchar *)user_data,clipboard_text);fflush(NULL);  
 
643
        gchar* command=g_strdup_printf((gchar *)user_data,clipboard_text);
 
644
        g_fprintf(stderr," '%s'\n",command);fflush(NULL);  
 
645
  g_free(clipboard_text);
 
646
  g_free(user_data);
 
647
  gchar* shell_command = g_shell_quote(command);
 
648
  g_free(command);
 
649
  gchar* cmd = g_strconcat("/bin/sh -c ", shell_command, NULL);
 
650
  g_free(shell_command);
 
651
  
 
652
  /* Execute action */
 
653
  GPid pid;
 
654
  gchar **argv;
 
655
  g_shell_parse_argv(cmd, NULL, &argv, NULL);
 
656
        g_fprintf(stderr,"cmd '%s' argv '%s' '%s' '%s'\n",cmd,argv[1],argv[2],argv[3]);  
 
657
  g_free(cmd);
 
658
  g_spawn_async(NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, NULL);
 
659
  g_child_watch_add(pid, (GChildWatchFunc)action_exit, NULL);
 
660
  g_strfreev(argv);
 
661
}
 
662
 
 
663
/* Called when Edit Actions is selected from actions menu */
 
664
static void edit_actions_selected(GtkButton *button, gpointer user_data)
 
665
{
 
666
  /* This helps prevent multiple instances */
 
667
  if (!gtk_grab_get_current())
 
668
    /* Show the preferences dialog on the actions tab */
 
669
    show_preferences(ACTIONS_TAB);
 
670
}
 
671
 
 
672
/***************************************************************************/
 
673
/**  Called when Edit is selected from history menu 
 
674
\n\b Arguments:
 
675
\n\b Returns:
 
676
****************************************************************************/
 
677
static void edit_selected(GtkMenuItem *menu_item, gpointer user_data)
 
678
{
 
679
        struct history_info *h=(struct history_info*)user_data;
 
680
        GList* element=NULL;
 
681
        struct history_item *c=NULL;
 
682
        if(NULL ==h)
 
683
                return;
 
684
        /*g_fprintf(stderr,"edit_selected call\n");  */
 
685
  /* This helps prevent multiple instances */
 
686
  if (!gtk_grab_get_current() ||h->wi.tmp1&EDIT_MODE_RC_EDIT_SET)  {
 
687
          gchar* current_clipboard_text=NULL;
 
688
                /*g_fprintf(stderr,"current..."); */
 
689
    /* Create clipboard buffer and set its text */
 
690
    GtkTextBuffer* clipboard_buffer = gtk_text_buffer_new(NULL);
 
691
                if(h->wi.index != -1){/**use index as pointer to text  */
 
692
                        element = g_list_nth(history_list, h->wi.index);
 
693
                        if(NULL == element){
 
694
                                g_fprintf(stderr,"edit_selected: element is NULL\n");
 
695
                                return;
 
696
                        }
 
697
                        c=(struct history_item *)(element->data);
 
698
                        if(NULL == c){
 
699
                                g_fprintf(stderr,"edit_selected: element->data is NULL\n");
 
700
                                return;
 
701
                        }
 
702
                        current_clipboard_text=p_strdup(c->text);
 
703
                        /*g_fprintf(stderr,"%s ",c->text);  */
 
704
                        
 
705
                }       else{
 
706
                        h->wi.tmp1=0;
 
707
                        if( NULL != h->element_text){/**this case should never happen  */
 
708
                                g_fprintf(stderr,"Oops. shouldn't be here\n");
 
709
                                current_clipboard_text=p_strdup(h->element_text);
 
710
                                
 
711
                        }else{
 
712
                                g_fprintf(stderr,"List Empty. Grab clipboard.\n");
 
713
                                current_clipboard_text = gtk_clipboard_wait_for_text(clipboard);
 
714
                        }       
 
715
                }
 
716
                
 
717
    
 
718
    if (current_clipboard_text != NULL)   {
 
719
                /*g_fprintf(stderr,"Got '%s'\n",current_clipboard_text); */
 
720
                        TRACE(g_fprintf(stderr,"Got '%s'\n",current_clipboard_text));
 
721
      gtk_text_buffer_set_text(clipboard_buffer, current_clipboard_text, -1);
 
722
    }    else    {
 
723
                        g_fprintf(stderr,"NULL text to edit. Nothing to do.\n");
 
724
                        return;
 
725
                }
 
726
    /*g_fprintf(stderr,"cr dialog\n");   */
 
727
    
 
728
    /* Create the dialog */
 
729
    GtkWidget* dialog = gtk_dialog_new_with_buttons(_("Editing Clipboard"), NULL,
 
730
                                                   (GTK_DIALOG_MODAL   +    GTK_DIALOG_NO_SEPARATOR),
 
731
                                                    GTK_STOCK_CANCEL,       GTK_RESPONSE_REJECT,
 
732
                                                    GTK_STOCK_OK,           GTK_RESPONSE_ACCEPT, NULL);
 
733
    
 
734
    gtk_window_set_default_size((GtkWindow*)dialog, 450, 300);
 
735
    gtk_window_set_icon((GtkWindow*)dialog, gtk_widget_render_icon(dialog, GTK_STOCK_EDIT, -1, NULL));
 
736
    
 
737
    /* Build the scrolled window with the text view */
 
738
    GtkWidget* scrolled_window = gtk_scrolled_window_new((GtkAdjustment*) gtk_adjustment_new(0, 0, 0, 0, 0, 0),
 
739
                                                         (GtkAdjustment*) gtk_adjustment_new(0, 0, 0, 0, 0, 0));
 
740
    
 
741
    gtk_scrolled_window_set_policy((GtkScrolledWindow*)scrolled_window,
 
742
                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 
743
    
 
744
    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), scrolled_window, TRUE, TRUE, 2);
 
745
    GtkWidget* text_view = gtk_text_view_new_with_buffer(clipboard_buffer);
 
746
    gtk_text_view_set_left_margin((GtkTextView*)text_view, 2);
 
747
    gtk_text_view_set_right_margin((GtkTextView*)text_view, 2);
 
748
    gtk_container_add((GtkContainer*)scrolled_window, text_view);
 
749
    
 
750
    /* Run the dialog */
 
751
    gtk_widget_show_all(dialog);
 
752
                
 
753
    if (gtk_dialog_run((GtkDialog*)dialog) == GTK_RESPONSE_ACCEPT) {
 
754
                        GtkTextIter start, end;
 
755
                        guint32 slen;
 
756
                        gchar *ntext=NULL;
 
757
      gtk_text_buffer_get_start_iter(clipboard_buffer, &start);
 
758
      gtk_text_buffer_get_end_iter(clipboard_buffer, &end);
 
759
      gchar* new_clipboard_text = gtk_text_buffer_get_text(clipboard_buffer, &start, &end, TRUE);
 
760
                        slen=strlen(new_clipboard_text);
 
761
                        if(0 == slen ){ /**just delete history entry, and set next in order to clipboard  */
 
762
                                if(NULL == element){/**just clear clipboard? or FIXME: is there a way to determine the element?  */
 
763
                                        /*gtk_clipboard_set_text(clipboard,"",0); */
 
764
                                        gtk_clipboard_clear(clipboard);
 
765
                                        goto finish;
 
766
                                }
 
767
                                /*g_fprintf(stderr,"Freeing %p\n",element->data); */
 
768
                                g_free(element->data);
 
769
                                if(element == history_list && NULL != element->next ){ /**set clipboard(s) to next entry  */
 
770
                                        c=(struct history_item *)(element->next->data); 
 
771
                                        if(NULL != c)
 
772
                                                ntext=c->text;
 
773
                                }
 
774
                                        
 
775
              history_list = g_list_delete_link(history_list, element);
 
776
                                if(NULL != ntext)/**set clipboards to next entry FIXME: Need logic here as to which clip(s) to update.  */
 
777
                update_clipboards(ntext, H_MODE_LIST);
 
778
                        }else {/**Text is not blank  */
 
779
                                /*g_fprintf(stderr,"Try to add '%s'\n",new_clipboard_text); */
 
780
                                gint16 type;
 
781
                                if( NULL != c)
 
782
                                        type=c->type;
 
783
                                else 
 
784
                                        type=0;
 
785
                                /**save changes to the history - deallocate current entry, and add new entry \Uffffffff�*/
 
786
                                /**FIXME: Need to filter this through existing & valid text? */
 
787
                                struct history_item *n=new_clip_item(type,slen, new_clipboard_text);
 
788
                                
 
789
                                if(NULL != c)
 
790
                                        n->flags=c->flags;
 
791
                                if(NULL != element && NULL != element->data){
 
792
                                        g_free(element->data);
 
793
                                        history_list=g_list_delete_link(history_list, element);
 
794
                                        history_list=g_list_prepend(history_list,c);
 
795
                                }else
 
796
                                
 
797
                                /**Does this cause crash since we are in the middle of a history window? 
 
798
                                Need to kill history menu too? 
 
799
                                What about setting up an indicator that on next tic, if history is not active, we update?
 
800
                                */
 
801
                           update_clipboards(n->text, H_MODE_NEW);
 
802
                        }
 
803
finish:                 
 
804
                        if(NULL != new_clipboard_text)
 
805
                                g_free(new_clipboard_text);     
 
806
    }
 
807
    gtk_widget_destroy(dialog);
 
808
    g_free(current_clipboard_text);
 
809
  }
 
810
        else TRACE(g_fprintf(stderr,"gtk_grab_get_current returned !0\n")); 
 
811
 
 
812
}
 
813
 
 
814
/***************************************************************************/
 
815
/** Only enabled when persistent history is enabled.
 
816
\n\b Arguments:
 
817
\n\b Returns:
 
818
****************************************************************************/
 
819
gboolean history_item_right_click_on_edit(GtkWidget *menuitem, gpointer data)
 
820
{
 
821
        struct history_info *h=(struct history_info*)data;
 
822
        h->wi.tmp1|=EDIT_MODE_USE_RIGHT_CLICK;
 
823
        edit_selected((GtkMenuItem *)menuitem, data);
 
824
}
 
825
 
 
826
/***************************************************************************/
 
827
/** Paste all. Grab all of the history and paste it to the clipboard.
 
828
\n\b Arguments:
 
829
\n\b Returns:
 
830
****************************************************************************/
 
831
gboolean history_item_right_click_on_copy_all(GtkWidget *menuitem, gpointer data)
 
832
{
 
833
        GList *element;
 
834
        gchar*str=NULL;
 
835
        gchar*last=NULL;
 
836
        gchar*delim= g_strcompress(get_pref_string("persistent_delim"));
 
837
        int which;
 
838
        struct history_info *h=(struct history_info*)data;
 
839
        /**if persistent and this history is persistent, only get persistent.  
 
840
        FIXME: this will only work with separarate set.
 
841
        */
 
842
        which=(get_pref_int32("persistent_history") && h->histno == HIST_DISPLAY_PERSISTENT);
 
843
        for (element = history_list; element != NULL; element = element->next) {
 
844
                struct history_item *c=(struct history_item *)(element->data);
 
845
                if(which && !(c->flags&CLIP_TYPE_PERSISTENT))
 
846
                        continue;
 
847
                if(NULL ==str)
 
848
                        str=c->text;
 
849
                else {
 
850
                        if(NULL == delim)
 
851
                                str=g_strconcat(str,c->text,NULL);
 
852
                        else
 
853
                                str=g_strconcat(str,delim,c->text,NULL);
 
854
                        if(NULL != last)
 
855
                                g_free(last);
 
856
                        last=str;
 
857
                }
 
858
        }       
 
859
        if(NULL != last){
 
860
                update_clipboards(str,H_MODE_IGNORE);
 
861
                g_free(last);
 
862
        }
 
863
                
 
864
        return TRUE;
 
865
}
 
866
/***************************************************************************/
 
867
/** .
 
868
\n\b Arguments:
 
869
\n\b Returns:
 
870
****************************************************************************/
 
871
gboolean  handle_history_item_right_click (int i, gpointer data)
 
872
{
 
873
  /* we passed the view as userdata when we connected the signal */
 
874
        struct history_info *h=(struct history_info*)data;
 
875
        struct history_item *c=NULL;
 
876
        if(NULL !=h ){
 
877
                GList* element = g_list_nth(history_list, h->wi.index);
 
878
                if(NULL !=element){
 
879
                        c=(struct history_item *)(element->data);
 
880
                        /*g_printf("%s ",c->text); */
 
881
                }
 
882
        }
 
883
        switch(i){
 
884
                case HIST_MOVE_TO_CANCEL:
 
885
/*                      g_print("canceled\n"); */
 
886
                        break;
 
887
                case HIST_MOVE_TO_OK:
 
888
/*                      g_printf("Move to"); */
 
889
                        handle_marking(h,h->wi.item,h->wi.index,OPERATE_PERSIST);
 
890
                        break;
 
891
        }
 
892
        /*gtk_widget_grab_focus(h->menu); */
 
893
        return TRUE;
 
894
}
 
895
/**callback wrappers for the above function  */
 
896
gboolean  history_item_right_click_on_move (GtkWidget *menuitem, gpointer data)
 
897
{
 
898
        return handle_history_item_right_click(HIST_MOVE_TO_OK,data);
 
899
}
 
900
gboolean history_item_right_click_on_cancel (GtkWidget *menuitem, gpointer data)
 
901
{
 
902
        return handle_history_item_right_click(HIST_MOVE_TO_CANCEL,data);
 
903
}
 
904
/***************************************************************************/
 
905
/** .
 
906
\n\b Arguments:
 
907
\n\b Returns:
 
908
if (event->type == GDK_BUTTON_PRESS  &&  event->button == 3)
 
909
        view_popup_menu(treeview, event, userdata);
 
910
        h->wi.index contains the element of the item clicked on.
 
911
****************************************************************************/
 
912
void  history_item_right_click (struct history_info *h, GdkEventKey *e, gint index)
 
913
{
 
914
  GtkWidget *menu, *menuitem;
 
915
  
 
916
        struct history_item *c=NULL;
 
917
        if(NULL !=h ){
 
918
                GList* element = g_list_nth(history_list, h->wi.index);
 
919
                if(NULL !=element){
 
920
                        c=(struct history_item *)(element->data);
 
921
                        /*g_printf("%s ",c->text); */
 
922
                }
 
923
        } else{
 
924
                g_fprintf(stderr,"h-i-r-c: h is NULL");
 
925
                return;
 
926
        }
 
927
        
 
928
        if(get_pref_int32("persistent_history")) {
 
929
                menu = gtk_menu_new();
 
930
                menuitem = gtk_menu_item_new_with_label("Copy All to Clip");
 
931
          g_signal_connect(menuitem, "activate", (GCallback) history_item_right_click_on_copy_all, (gpointer)h);
 
932
          gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
 
933
                /*g_printf("CreatehistR\n"); */
 
934
                if(NULL != c){
 
935
                        if(c->flags & CLIP_TYPE_PERSISTENT)
 
936
                                menuitem = gtk_menu_item_new_with_label("Move To Normal");
 
937
                        else
 
938
                                menuitem = gtk_menu_item_new_with_label("Move To Persistent");
 
939
                }       else
 
940
            menuitem = gtk_menu_item_new_with_label("Move To?");
 
941
        
 
942
          g_signal_connect(menuitem, "activate",(GCallback) history_item_right_click_on_move, (gpointer)h);
 
943
          gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
 
944
                
 
945
                menuitem = gtk_menu_item_new_with_label("Edit");
 
946
          g_signal_connect(menuitem, "activate", (GCallback) history_item_right_click_on_edit, (gpointer)h);
 
947
          gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);        
 
948
                
 
949
                menuitem = gtk_menu_item_new_with_label("Cancel");
 
950
          g_signal_connect(menuitem, "activate", (GCallback) history_item_right_click_on_cancel, (gpointer)h);
 
951
          gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);        
 
952
        
 
953
          gtk_widget_show_all(menu);
 
954
        
 
955
          /* Note: event can be NULL here when called from view_onPopupMenu;
 
956
           *  gdk_event_get_time() accepts a NULL argument */
 
957
           gtk_menu_popup(GTK_MENU(menu), h->menu, NULL, NULL, NULL,
 
958
                                                                                0,
 
959
                         /*(e != NULL) ? ((GdkEventButton *)e)->button : 0, */
 
960
                         gdk_event_get_time((GdkEvent*)e));
 
961
                /*gtk_widget_grab_focus(menu);  */      
 
962
        }else if(get_pref_int32("rc_edit") ){ /**just edit the selected text  */
 
963
                h->wi.tmp1|=EDIT_MODE_USE_RIGHT_CLICK|EDIT_MODE_RC_EDIT_SET;
 
964
                edit_selected((GtkMenuItem *)NULL,(gpointer)h);
 
965
                
 
966
        }
 
967
        
 
968
}
 
969
 
 
970
/* Called when Clear is selected from history menu */
 
971
static void clear_selected(GtkMenuItem *menu_item, gpointer user_data)
 
972
{
 
973
        int clear=1;
 
974
  /* Check for confirm clear option */
 
975
  if (get_pref_int32("confirm_clear"))  {
 
976
    GtkWidget* confirm_dialog = gtk_message_dialog_new(NULL,
 
977
                                                       GTK_DIALOG_MODAL,
 
978
                                                       GTK_MESSAGE_OTHER,
 
979
                                                       GTK_BUTTONS_OK_CANCEL,
 
980
                                                       _("Clear the history?"));
 
981
    
 
982
    if (gtk_dialog_run((GtkDialog*)confirm_dialog) != GTK_RESPONSE_OK)    {
 
983
                        clear=0;
 
984
                }
 
985
                gtk_widget_destroy(confirm_dialog);
 
986
        }       
 
987
        if(clear){
 
988
                struct history_info *h=(struct history_info *)user_data;
 
989
                /* Clear history and free history-related variables */
 
990
                remove_deleted_items(h); /**fix bug 92, Shift/ctrl right-click followed by clear segfaults/double free.  */     
 
991
                clear_history();
 
992
                /*g_printf("Clear hist done, h=%p, h->delete_list=%p\n",h, h->delete_list); */
 
993
                update_clipboard(primary, "", H_MODE_INIT);
 
994
    update_clipboard(clipboard, "", H_MODE_INIT);
 
995
        }
 
996
      
 
997
}
 
998
 
 
999
/* Called when About is selected from right-click menu */
 
1000
static void show_about_dialog(GtkMenuItem *menu_item, gpointer user_data)
 
1001
{
 
1002
  /* This helps prevent multiple instances */
 
1003
  if (!gtk_grab_get_current())
 
1004
  {
 
1005
    const gchar* authors[] = {_("Gilberto \"Xyhthyx\" Miralla <xyhthyx@gmail.com>\nDoug Springer <gpib@rickyrockrat.net>"), NULL};
 
1006
    const gchar* license =
 
1007
      "This program is free software; you can redistribute it and/or modify\n"
 
1008
      "it under the terms of the GNU General Public License as published by\n"
 
1009
      "the Free Software Foundation; either version 3 of the License, or\n"
 
1010
      "(at your option) any later version.\n\n"
 
1011
      "This program is distributed in the hope that it will be useful,\n"
 
1012
      "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
 
1013
      "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
 
1014
      "GNU General Public License for more details.\n\n"
 
1015
      "You should have received a copy of the GNU General Public License\n"
 
1016
      "along with this program.  If not, see <http://www.gnu.org/licenses/>.";
 
1017
    
 
1018
    /* Create the about dialog */
 
1019
    GtkWidget* about_dialog = gtk_about_dialog_new();
 
1020
    gtk_window_set_icon((GtkWindow*)about_dialog,
 
1021
                        gtk_widget_render_icon(about_dialog, GTK_STOCK_ABOUT, -1, NULL));
 
1022
    
 
1023
    gtk_about_dialog_set_name((GtkAboutDialog*)about_dialog, "Parcellite");
 
1024
    #ifdef HAVE_CONFIG_H        /**VER=555; sed "s#\(.*\)svn.*\".*#\1svn$VER\"#" config.h  */
 
1025
    gtk_about_dialog_set_version((GtkAboutDialog*)about_dialog, VERSION);
 
1026
    #endif
 
1027
    gtk_about_dialog_set_comments((GtkAboutDialog*)about_dialog,
 
1028
                                _("Lightweight GTK+ clipboard manager."));
 
1029
    
 
1030
    gtk_about_dialog_set_website((GtkAboutDialog*)about_dialog,
 
1031
                                 "http://parcellite.sourceforge.net");
 
1032
    
 
1033
    gtk_about_dialog_set_copyright((GtkAboutDialog*)about_dialog, _("Copyright (C) 2007, 2008 Gilberto \"Xyhthyx\" Miralla\nCopyright (C) 2010-2013 Doug Springer"));
 
1034
    gtk_about_dialog_set_authors((GtkAboutDialog*)about_dialog, authors);
 
1035
    gtk_about_dialog_set_translator_credits ((GtkAboutDialog*)about_dialog,
 
1036
                                             "Miloš Koutný <milos.koutny@gmail.com>\n"
 
1037
                                             "Kim Jensen <reklamepost@energimail.dk>\n"
 
1038
                                             "Eckhard M. Jäger <bart@neeneenee.de>\n"
 
1039
                                             "Michael Stempin <mstempin@web.de>\n"
 
1040
                                             "Benjamin Danon <benjamin@sphax3d.org>\n" 
 
1041
                                             "Németh Tamás <ntomasz@vipmail.hu>\n"
 
1042
                                             "Davide Truffa <davide@catoblepa.org>\n"
 
1043
                                             "Jiro Kawada <jiro.kawada@gmail.com>\n"
 
1044
                                             "Øyvind Sæther <oyvinds@everdot.org>\n"
 
1045
                                             "pankamyk <pankamyk@o2.pl>\n"
 
1046
                                             "Tomasz Rusek <tomek.rusek@gmail.com>\n"
 
1047
                                             "Phantom X <megaphantomx@bol.com.br>\n"
 
1048
                                             "Ovidiu D. Niţan <ov1d1u@sblug.ro>\n"
 
1049
                                             "Alexander Kazancev <kazancas@mandriva.ru>\n"
 
1050
                                             "Daniel Nylander <po@danielnylander.se>\n"
 
1051
                                             "Hedef Türkçe <iletisim@hedefturkce.com>\n"
 
1052
                                             "Lyman Li <lymanrb@gmail.com>\n"
 
1053
                                             "Gilberto \"Xyhthyx\" Miralla <xyhthyx@gmail.com>");
 
1054
    
 
1055
    gtk_about_dialog_set_license((GtkAboutDialog*)about_dialog, license);
 
1056
          gtk_about_dialog_set_logo_icon_name((GtkAboutDialog*)about_dialog, PARCELLITE_ICON);
 
1057
    /* Run the about dialog */
 
1058
    gtk_dialog_run((GtkDialog*)about_dialog);
 
1059
    gtk_widget_destroy(about_dialog);
 
1060
  }
 
1061
}
 
1062
 
 
1063
/* Called when Preferences is selected from right-click menu */
 
1064
static void preferences_selected(GtkMenuItem *menu_item, gpointer user_data)
 
1065
{
 
1066
  /* This helps prevent multiple instances */
 
1067
  if (!gtk_grab_get_current()){
 
1068
                 /* Show the preferences dialog */
 
1069
    show_preferences(0);
 
1070
        }
 
1071
 
 
1072
}
 
1073
 
 
1074
/* Called when Quit is selected from right-click menu */
 
1075
static void quit_selected(GtkMenuItem *menu_item, gpointer user_data)
 
1076
{
 
1077
  /* Prevent quit with dialogs open */
 
1078
  if (!gtk_grab_get_current())
 
1079
    /* Quit the program */
 
1080
    gtk_main_quit();
 
1081
}
 
1082
 
 
1083
/* Called when status icon is control-clicked */
 
1084
static gboolean show_actions_menu(gpointer data)
 
1085
{
 
1086
  /* Declare some variables */
 
1087
  GtkWidget *menu,       *menu_item,
 
1088
            *menu_image, *item_label;
 
1089
  
 
1090
  /* Create menu */
 
1091
  menu = gtk_menu_new();
 
1092
  g_signal_connect((GObject*)menu,"selection-done", (GCallback)gtk_widget_destroy, NULL);
 
1093
  /* Actions using: */
 
1094
  menu_item = gtk_image_menu_item_new_with_label("Actions using:");
 
1095
  menu_image = gtk_image_new_from_stock(GTK_STOCK_EXECUTE, GTK_ICON_SIZE_MENU);
 
1096
  gtk_image_menu_item_set_image((GtkImageMenuItem*)menu_item, menu_image);
 
1097
  g_signal_connect((GObject*)menu_item, "select", (GCallback)gtk_menu_item_deselect, NULL);
 
1098
  gtk_menu_shell_append((GtkMenuShell*)menu, menu_item);
 
1099
  /* Clipboard contents */
 
1100
  gchar* text = gtk_clipboard_wait_for_text(clipboard);
 
1101
  if (text != NULL)
 
1102
  {
 
1103
    menu_item = gtk_menu_item_new_with_label("None");
 
1104
    /* Modify menu item label properties */
 
1105
    item_label = gtk_bin_get_child((GtkBin*)menu_item);
 
1106
    gtk_label_set_single_line_mode((GtkLabel*)item_label, TRUE);
 
1107
    gtk_label_set_ellipsize((GtkLabel*)item_label, get_pref_int32("ellipsize"));
 
1108
    gtk_label_set_width_chars((GtkLabel*)item_label, 30);
 
1109
    /* Making bold... */
 
1110
    gchar* bold_text = g_markup_printf_escaped("<b>%s</b>", text);
 
1111
    gtk_label_set_markup((GtkLabel*)item_label, bold_text);
 
1112
    g_free(bold_text);
 
1113
    /* Append menu item */
 
1114
    g_signal_connect((GObject*)menu_item, "select", (GCallback)gtk_menu_item_deselect, NULL);
 
1115
    gtk_menu_shell_append((GtkMenuShell*)menu, menu_item);
 
1116
          g_free(text);
 
1117
  }
 
1118
  else
 
1119
  {
 
1120
    /* Create menu item for empty clipboard contents */
 
1121
    menu_item = gtk_menu_item_new_with_label("None");
 
1122
    /* Modify menu item label properties */
 
1123
    item_label = gtk_bin_get_child((GtkBin*)menu_item);
 
1124
    gtk_label_set_markup((GtkLabel*)item_label, _("<b>None</b>"));
 
1125
    /* Append menu item */
 
1126
    g_signal_connect((GObject*)menu_item, "select", (GCallback)gtk_menu_item_deselect, NULL);
 
1127
    
 
1128
    gtk_menu_shell_append((GtkMenuShell*)menu, menu_item);
 
1129
  }
 
1130
  /* -------------------- */
 
1131
  gtk_menu_shell_append((GtkMenuShell*)menu, gtk_separator_menu_item_new());
 
1132
  /* Actions */
 
1133
  gchar* path = g_build_filename(g_get_user_data_dir(), ACTIONS_FILE, NULL);
 
1134
        printf("got path '%s'\n",path); fflush(NULL);
 
1135
  FILE* actions_file = fopen(path, "rb");
 
1136
  g_free(path);
 
1137
  /* Check that it opened and begin read */
 
1138
  if (actions_file)
 
1139
  {
 
1140
    gint size;
 
1141
    if(0==fread(&size, 4, 1, actions_file))
 
1142
        g_print("1:got 0 items from fread\n");
 
1143
    /* Check if actions file is empty */
 
1144
    if (!size)
 
1145
    {
 
1146
      /* File contained no actions so adding empty */
 
1147
      menu_item = gtk_menu_item_new_with_label(_("Empty"));
 
1148
      gtk_widget_set_sensitive(menu_item, FALSE);
 
1149
      gtk_menu_shell_append((GtkMenuShell*)menu, menu_item);
 
1150
    }
 
1151
    /* Continue reading items until size is 0 */
 
1152
    while (size)
 
1153
    {
 
1154
      /* Read name */
 
1155
      gchar* name = (gchar*)g_malloc(size + 1);
 
1156
      if( 0 ==fread(name, size, 1, actions_file))
 
1157
        g_print("2:got 0 items from fread\n");
 
1158
      name[size] = '\0';
 
1159
      menu_item = gtk_menu_item_new_with_label(name);
 
1160
      
 
1161
      if(0 ==fread(&size, 4, 1, actions_file))
 
1162
        g_print("3:got 0 items from fread\n");
 
1163
      /* Read command */
 
1164
      gchar* command = (gchar*)g_malloc(size + 1);
 
1165
      if(0 ==fread(command, size, 1, actions_file))
 
1166
        g_print("4:got 0 items from fread\n");
 
1167
      command[size] = '\0';
 
1168
                  g_print("name='%s' cmd='%s'\n",name,command);
 
1169
      if(0 ==fread(&size, 4, 1, actions_file))
 
1170
        g_print("5:got 0 items from fread\n");
 
1171
      /* Append the action */
 
1172
      gtk_menu_shell_append((GtkMenuShell*)menu, menu_item);
 
1173
      g_signal_connect((GObject*)menu_item,        "activate",
 
1174
                       (GCallback)action_selected, (gpointer)command);      
 
1175
                  g_free(name);
 
1176
    }
 
1177
    fclose(actions_file);
 
1178
  }
 
1179
  else
 
1180
  {
 
1181
    /* File did not open so adding empty */
 
1182
    menu_item = gtk_menu_item_new_with_label(_("Empty"));
 
1183
    gtk_widget_set_sensitive(menu_item, FALSE);
 
1184
    gtk_menu_shell_append((GtkMenuShell*)menu, menu_item);
 
1185
  }
 
1186
  /* -------------------- */
 
1187
  gtk_menu_shell_append((GtkMenuShell*)menu, gtk_separator_menu_item_new());
 
1188
  /* Edit actions */
 
1189
  menu_item = gtk_image_menu_item_new_with_mnemonic(_("_Edit actions"));
 
1190
  menu_image = gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU);
 
1191
  gtk_image_menu_item_set_image((GtkImageMenuItem*)menu_item, menu_image);
 
1192
  g_signal_connect((GObject*)menu_item, "activate", (GCallback)edit_actions_selected, NULL);
 
1193
  gtk_menu_shell_append((GtkMenuShell*)menu, menu_item);
 
1194
  /* Popup the menu... */
 
1195
  gtk_widget_show_all(menu);
 
1196
  gtk_menu_popup((GtkMenu*)menu, NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time());
 
1197
  /* Return false so the g_timeout_add() function is called only once */
 
1198
  return FALSE;
 
1199
}
 
1200
 
 
1201
/***************************************************************************/
 
1202
/** Called just before destroying history menu.
 
1203
\n\b Arguments:
 
1204
\n\b Returns:
 
1205
****************************************************************************/
 
1206
static gboolean selection_done(GtkMenuShell *menushell, gpointer user_data) 
 
1207
{
 
1208
        struct history_info *h=(struct history_info *)user_data;
 
1209
        if(NULL != h && NULL != h->delete_list){/**have a list of items to delete.  */
 
1210
                remove_deleted_items(h);
 
1211
                goto done;
 
1212
        }       
 
1213
        /*g_print("selection_active=%d\n",selection_active); */
 
1214
        /*g_print("Got selection_done\n"); */
 
1215
        if(h->change_flag && get_pref_int32("save_history")){
 
1216
                save_history();
 
1217
                h->change_flag=0;
 
1218
        }
 
1219
                  
 
1220
done:
 
1221
        /*gtk_widget_destroy((GtkWidget *)menushell); - fixes annoying GTK_IS_WIDGET/GTK_IS_WINDOW
 
1222
          warnings from GTK when history dialog is destroyed. */
 
1223
        return FALSE;
 
1224
}
 
1225
 
 
1226
/***************************************************************************/
 
1227
/** Set the background color of the widget.
 
1228
\n\b Arguments:
 
1229
\n\b Returns:
 
1230
****************************************************************************/
 
1231
void set_widget_bg(gchar *color, GtkWidget *w)
 
1232
{
 
1233
  GdkColor c, *cp;
 
1234
  GtkRcStyle *st;
 
1235
  /** c.red = 65535;
 
1236
  c.green = 0;
 
1237
  c.blue = 0;*/
 
1238
  /*g_print("set_widget_bg\n"); */
 
1239
  if(NULL != color){
 
1240
    gdk_color_parse (color, &c); 
 
1241
    cp=&c;
 
1242
  }else
 
1243
    cp=NULL;
 
1244
    
 
1245
  gtk_widget_modify_bg(w, GTK_STATE_NORMAL, cp);
 
1246
  return;
 
1247
#if 0 /**none of this works  */  
 
1248
  gtk_widget_modify_bg(w, GTK_STATE_ACTIVE, cp);
 
1249
 
 
1250
  /*gdk_color_parse (color, &c); */
 
1251
  st=gtk_widget_get_modifier_style(w);
 
1252
  /*st=gtk_rc_style_new (); */
 
1253
  st->bg[GTK_STATE_NORMAL] = st->bg[GTK_STATE_ACTIVE] = c;
 
1254
  gtk_widget_modify_style (w, st);
 
1255
  gtk_widget_show(w);
 
1256
  /*gtk_widget_modify_bg (w, GTK_STATE_NORMAL, &c); */
 
1257
#endif
 
1258
}
 
1259
 
 
1260
/**postition the history dialog  - should only be called if get_pref_int32("history_pos") is set */
 
1261
void postition_history(GtkMenu *menu,gint *x,gint *y,gboolean *push_in, gpointer user_data)
 
1262
{
 
1263
        GdkScreen *s;
 
1264
        gint sx,sy;
 
1265
        s=gdk_screen_get_default();
 
1266
        sx= gdk_screen_get_width(s);
 
1267
        sy= gdk_screen_get_height(s);
 
1268
        if(NULL !=push_in)
 
1269
                *push_in=FALSE;
 
1270
        if(1 == GPOINTER_TO_INT(user_data)){
 
1271
                if(NULL !=x) *x=sx;
 
1272
                if(NULL !=y) *y=sy;     
 
1273
        }else{
 
1274
                if(get_pref_int32("history_pos")){
 
1275
                        int xx,yy;
 
1276
                        if(get_pref_int32("history_x") > get_pref_int32("item_length") )
 
1277
                                xx=get_pref_int32("history_x")-get_pref_int32("item_length");
 
1278
                        else
 
1279
                                xx=1;
 
1280
                        if(get_pref_int32("history_y") > get_pref_int32("history_limit") )
 
1281
                                yy=get_pref_int32("history_y")-get_pref_int32("history_limit");
 
1282
                        else
 
1283
                                yy=1;
 
1284
                        if(NULL !=x) *x=xx;
 
1285
                        if(NULL !=y) *y=yy;     
 
1286
                        TRACE(g_fprintf(stderr,"x=%d, y=%d\n",xx,yy));
 
1287
                }
 
1288
                
 
1289
        }
 
1290
        
 
1291
}
 
1292
 
 
1293
/***************************************************************************/
 
1294
/** This handles events for the history menu, which is the parent of each
 
1295
item.
 
1296
\n\b Arguments: user is the struct history_info created in history menu.
 
1297
\n\b Returns: FALSE if key was not handled, TRUE if it was.
 
1298
You get two key presses if you return FALSE.
 
1299
****************************************************************************/
 
1300
static gboolean key_release_cb (GtkWidget *w,GdkEventKey *e, gpointer user)
 
1301
{
 
1302
        static gchar *kstr=NULL;
 
1303
        static gint idx;
 
1304
  /*static GdkEvent *last_event=NULL; */
 
1305
        gint first, current,off;
 
1306
        static GtkWidget *item=NULL;
 
1307
        GList *children;
 
1308
  struct history_info *h;
 
1309
 
 
1310
  h=(struct history_info *)user;
 
1311
        
 
1312
        if(0&& NULL != e ){
 
1313
                if(GDK_MOTION_NOTIFY==e->type)
 
1314
                        return FALSE;
 
1315
    printf("krc (%x) S%x T%x C%x,SE%x, G%x, W%p, wdg%p",
 
1316
                e->keyval,e->state,e->type,
 
1317
                e->hardware_keycode,e->send_event,e->group,e->window,w);
 
1318
                if(GDK_DRAG_ENTER == e->type || GDK_DRAG_LEAVE==e->type){
 
1319
                        printf(" Drag %s\n",GDK_DRAG_ENTER == e->type?"ENTER":"LEAVE");
 
1320
                }
 
1321
                if(GDK_BUTTON_RELEASE==e->type || GDK_BUTTON_PRESS==e->type  ){
 
1322
                        GdkEventButton *b=(GdkEventButton *)e;
 
1323
                        printf(" button %d State 0x%x\n",b->button, b->state);
 
1324
                        if(GDK_BUTTON_RELEASE==e->type && 3 == b->button){
 
1325
                                /*toggle-size-request", */
 
1326
                                /*allow item_selected to get called  */
 
1327
                                /*return FALSE;   */
 
1328
                        }
 
1329
                        /*return TRUE; */
 
1330
                }
 
1331
                printf("\n");
 
1332
                fflush(NULL);
 
1333
  }
 
1334
        
 
1335
        /**serves as init for keysearch  */
 
1336
        if(NULL ==w && NULL==e && NULL == user){
 
1337
                if(NULL != kstr)
 
1338
                        g_free(kstr);
 
1339
                kstr=g_strnfill(KBUF_SIZE+8,0);
 
1340
                idx=0;
 
1341
                return FALSE;
 
1342
        }else if(NULL == kstr){
 
1343
                g_print("kstr null. Not init\n");
 
1344
                return FALSE;
 
1345
        }
 
1346
  if(NULL == e){
 
1347
    g_print("No Event!\n");
 
1348
    return FALSE;
 
1349
  }
 
1350
                
 
1351
  if(0 == get_pref_int32("type_search"))/**searching is turned off  */
 
1352
    return FALSE;
 
1353
        /**ignore left-clicks  */
 
1354
        if(GDK_BUTTON_RELEASE==e->type && 3 == ((GdkEventButton *)e)->button)
 
1355
                return FALSE;
 
1356
                
 
1357
  if(GDK_KEY_PRESS == e->type && ' ' == e->keyval) /**ignore space presses  */
 
1358
    return TRUE;
 
1359
        if(GDK_KEY_PRESS == e->type)
 
1360
                return FALSE;
 
1361
    /**pass all other non-release events on  */
 
1362
  if(GDK_KEY_RELEASE != e->type && GDK_BUTTON_RELEASE != e->type) 
 
1363
    return FALSE;
 
1364
  /** if(GDK_SELECTION_NOTIFY == e->type){
 
1365
    g_print("last %x\n",last_event->type);
 
1366
    last_event=(GdkEvent *)e;
 
1367
    return TRUE;
 
1368
  }
 
1369
  last_event=(GdkEvent *)e;*/
 
1370
        /** if(user)
 
1371
        if(e->state & (GDK_SHIFT_MASK|GDK_LOCK_MASK) != e->state){
 
1372
                g_print("rfs to use mods\n");
 
1373
                TRACE(g_fprintf(stderr,"state is %X. Refusing to use mods\n",e->state));
 
1374
                return TRUE;
 
1375
        } have to use for _ and others*/
 
1376
        /**ignore Ctrl-Alt  */
 
1377
        if((GDK_CONTROL_MASK|GDK_MOD1_MASK)==(e->state & (GDK_CONTROL_MASK|GDK_MOD1_MASK)))
 
1378
                return FALSE;
 
1379
        if( e->state & GDK_MOD1_MASK){/**alt key pressed  */
 
1380
                if(e->keyval == 'e'){
 
1381
                        TRACE(g_fprintf(stderr,"Alt-E\n"));
 
1382
                        gtk_grab_remove(w);
 
1383
                  edit_selected((GtkMenuItem *)h, (gpointer)h);
 
1384
                        return TRUE;
 
1385
                }
 
1386
                        
 
1387
                else if(e->keyval == 'c'){
 
1388
                        TRACE(g_fprintf(stderr,"Alt-C\n"));
 
1389
                        clear_selected(NULL, (gpointer)h); 
 
1390
                        return TRUE;
 
1391
                }       else{
 
1392
                        TRACE(g_fprintf(stderr,"Ignoring Alt-%c (0x%02x) state 0x%x",e->keyval,e->keyval,e->state));
 
1393
                }
 
1394
                return FALSE;
 
1395
        }       /**end alt key pressed  */
 
1396
        if(e->state & GDK_CONTROL_MASK) /**ignore control keys  */
 
1397
                return FALSE;
 
1398
        if(e->state &GDK_SHIFT_MASK   && get_pref_int32("case_search")) /**ignore shift   */
 
1399
                return FALSE;
 
1400
        if( GDK_EXPOSE== e->type || GDK_BUTTON_RELEASE==e->type)        /**fix bug 3560995, item 1/2, red clipboard.  */
 
1401
                return FALSE;
 
1402
        if(e->keyval == 0xff08){/**backspace  */
 
1403
//              g_printf("0x%x bs %d ",e->type,idx);
 
1404
                if(idx)
 
1405
                        --idx;
 
1406
    else if( NULL != h->clip_item){
 
1407
      gtk_menu_shell_select_item((GtkMenuShell *)h->menu,(GtkWidget *)h->clip_item);
 
1408
    }
 
1409
    set_widget_bg(NULL,h->menu);
 
1410
                kstr[idx]=0;
 
1411
        //      g_printf(" %d\n",idx);
 
1412
                return TRUE;
 
1413
        }       /**end backspace  */
 
1414
        if( e->keyval == 0xffe1 || e->keyval == 0xffe2){
 
1415
                /*fprintf(stderr,"Ignoring key '%c' 0x%02x\n",e->keyval,e->keyval); */
 
1416
                TRACE(g_fprintf(stderr,"Ignoring key '%c' 0x%02x\n",e->keyval,e->keyval));      
 
1417
                return FALSE;
 
1418
        }
 
1419
  if(e->keyval >= 0xff50 && e->keyval <= 0xff57) /**arrow keys, home,end,pgup,pgdwn  */
 
1420
        return FALSE;
 
1421
        
 
1422
        if(idx>=KBUF_SIZE){
 
1423
                TRACE(g_fprintf(stderr,"keys full\n"));
 
1424
                return TRUE;
 
1425
        }
 
1426
        kstr[idx++]=e->keyval;
 
1427
        kstr[idx]=0;
 
1428
        for ( off=0; off<50;++off){ /** this loop does a char search based on offset  */
 
1429
                children=gtk_container_get_children((GtkContainer *)h->menu);
 
1430
                item=NULL;
 
1431
                current=first=0; /**first is edit,   */
 
1432
                while(NULL != children->next){
 
1433
                        gchar *l;
 
1434
                        gint slen;
 
1435
                        GtkWidget *child=gtk_bin_get_child((GtkBin*)children->data);
 
1436
                        if(GTK_IS_LABEL(child)){
 
1437
                                l=(gchar *)gtk_label_get_text((GtkLabel *)child);
 
1438
                                slen=strlen(l);
 
1439
                                if(slen>off){
 
1440
                                        gint c;
 
1441
                                        if(get_pref_int32("case_search"))
 
1442
                                                c=strncmp(kstr,&l[off],idx);
 
1443
                                        else
 
1444
                                                c=g_ascii_strncasecmp(kstr,&l[off],idx);
 
1445
                                        if(!c){
 
1446
                                                if(0 ==current){
 
1447
                                                        first=1;
 
1448
                                                }       else{
 
1449
                                                        first=0;
 
1450
                                                }
 
1451
                                                
 
1452
                                                if(!first ){
 
1453
                                                        TRACE(g_fprintf(stderr,"Got cmp'%s'='%s'\n",kstr,l));
 
1454
                                                        item=(GtkWidget *)children->data;
 
1455
                                                        goto foundit;
 
1456
                                                }
 
1457
                                                
 
1458
                                        }               
 
1459
                                }
 
1460
                        }
 
1461
                        children=children->next;
 
1462
                        ++current;
 
1463
                }       
 
1464
  }
 
1465
  /**didn't find it. Set our title and return */
 
1466
  set_widget_bg("red",h->menu);
 
1467
  return TRUE;
 
1468
foundit:
 
1469
  set_widget_bg(NULL,h->menu);
 
1470
        /**user->children...
 
1471
        GList *children;  
 
1472
        gpointer data,next,prev
 
1473
        data should be a GtkMenuItem list, whose children are labels...
 
1474
        */       
 
1475
        /*str=(gchar *)gtk_label_get_text((GtkLabel *)gtk_bin_get_child((GtkBin*)children->data)); */
 
1476
        TRACE(g_fprintf(stderr,"Got '%c' 0x%02x, state 0x%02X",e->keyval,e->keyval,e->state));
 
1477
        if(NULL !=item){
 
1478
                if(first){TRACE(g_fprintf(stderr,"First:"));}
 
1479
                /*if(last)TRACE(g_fprintf(stderr,"Last:")); */
 
1480
                TRACE(g_fprintf(stderr,"At Item '%s'",gtk_label_get_text((GtkLabel *)gtk_bin_get_child((GtkBin*)item))));
 
1481
                gtk_menu_shell_select_item((GtkMenuShell *)h->menu,(GtkWidget *)item);
 
1482
        }
 
1483
                
 
1484
        TRACE(g_fprintf(stderr,"\n"));
 
1485
        return TRUE;
 
1486
}       
 
1487
 
 
1488
/***************************************************************************/
 
1489
/** Set clipboard from history list.
 
1490
\n\b Arguments:
 
1491
\n\b Returns:
 
1492
****************************************************************************/
 
1493
void set_clipboard_text(struct history_info *h, GList *element)
 
1494
{
 
1495
        int auto_whatever=0;
 
1496
        gchar *action=NULL;
 
1497
        gchar *txt=NULL;
 
1498
        gchar *cmd=NULL;
 
1499
        /*g_mutex_lock(clip_lock); */
 
1500
        if(NULL == find_h_item(h->delete_list,NULL,element)){   /**not in our delete list  */
 
1501
                /**make a copy of txt, because it gets freed and re-allocated.  */
 
1502
                txt=p_strdup(((struct history_item *)(element->data))->text);
 
1503
                DTRACE(g_fprintf(stderr,"set_clip_text %s\n",txt));  
 
1504
                if(get_pref_int32("use_copy") )
 
1505
                        update_clipboard(clipboard, txt, H_MODE_LIST);
 
1506
                if(get_pref_int32("use_primary"))
 
1507
                update_clipboard(primary, txt, H_MODE_LIST);    
 
1508
                
 
1509
                auto_whatever=1;
 
1510
        }
 
1511
  g_signal_emit_by_name ((gpointer)h->menu,"selection-done");
 
1512
        if(0 == auto_whatever)
 
1513
                return;
 
1514
        /*g_printf("set_clip_text done\n");  */
 
1515
        /*g_mutex_unlock(clip_lock); */
 
1516
        
 
1517
        if (get_pref_int32("automatic_paste")) { /** mousedown 2 */
 
1518
                if(get_pref_int32("auto_mouse"))
 
1519
                        action=g_strdup("mousedown 2 && xdotool mouseup 2'");
 
1520
                else if(get_pref_int32("auto_key"))
 
1521
                        action=g_strdup("key ctrl+v'");
 
1522
        }
 
1523
        
 
1524
        if( get_pref_int32("key_input")) 
 
1525
                action=g_strconcat("type \"",txt,"\"'",NULL);
 
1526
                
 
1527
        if(NULL == action)
 
1528
                        goto done;
 
1529
        /**from clipit 1.4.1 */
 
1530
  cmd = g_strconcat("/bin/sh -c 'xdotool ", action, NULL);
 
1531
        g_fprintf(stderr,"xdotool:'%s'\ntext:'%s'\n",cmd,txt);
 
1532
  GPid pid;
 
1533
  gchar **argv;
 
1534
  g_shell_parse_argv(cmd, NULL, &argv, NULL);
 
1535
  g_free(cmd);
 
1536
  g_spawn_async(NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, NULL);
 
1537
  g_child_watch_add(pid, (GChildWatchFunc)action_exit, NULL);
 
1538
  g_strfreev(argv);
 
1539
  /**end from clipit 1.4.1 */
 
1540
done:
 
1541
        if(NULL != txt)
 
1542
                g_free(txt);
 
1543
        if(NULL != action)
 
1544
                g_free(action);
 
1545
}
 
1546
 
 
1547
 
 
1548
/***************************************************************************/
 
1549
/** This handles the events for each item in the history menu.
 
1550
\n\b Arguments:  user is element number
 
1551
\n\b Returns:
 
1552
****************************************************************************/
 
1553
static gboolean my_item_event (GtkWidget *w,GdkEventKey *e, gpointer user)
 
1554
{
 
1555
        static struct history_info *h=NULL;
 
1556
        GtkWidget *menu=NULL;
 
1557
        
 
1558
        if(NULL==w && NULL==e){
 
1559
                h=(struct history_info *)user;
 
1560
          /*g_print("my_item_event: Set menu to %p\n",h); */
 
1561
                return FALSE;
 
1562
        }
 
1563
        if(NULL == h)
 
1564
                return FALSE;   
 
1565
        menu=h->menu;
 
1566
        /**check for enter  */
 
1567
        if(GDK_MOTION_NOTIFY == e->type)
 
1568
                return FALSE;
 
1569
        /*printf("my_item_event: T 0x%x S 0x%x ",e->type,e->state); */
 
1570
        if(NULL !=h && GDK_ENTER_NOTIFY ==e->type ){/**add to delete   */
 
1571
                GdkEventCrossing *enter=(GdkEventCrossing *)e;
 
1572
                /*printf("state 0x%x\n",enter->state); */
 
1573
                /**use shift and right-click  */
 
1574
                if(GDK_SHIFT_MASK&enter->state && GDK_BUTTON3_MASK&enter->state)
 
1575
                        handle_marking(h,w,GPOINTER_TO_INT(user),OPERATE_DELETE);
 
1576
        }
 
1577
        if(GDK_KEY_PRESS == e->type){
 
1578
                GdkEventKey *k= (GdkEventKey *)e;
 
1579
                printf("key press %d (0x%x)\n",e->keyval,e->keyval); 
 
1580
                fflush(NULL);
 
1581
        }
 
1582
        if(GDK_BUTTON_RELEASE==e->type){
 
1583
                GdkEventButton *b=(GdkEventButton *)e;
 
1584
                GList* element = g_list_nth(history_list, GPOINTER_TO_INT(user));
 
1585
                /*printf("type %x State 0x%x val %x %p '%s'\n",e->type, b->state,b->button,w,(gchar *)((struct history_item *(element->data))->text));  */
 
1586
                if(3 == b->button){ /**right-click  */
 
1587
                        gboolean rtn;
 
1588
                        if(GDK_CONTROL_MASK&b->state){
 
1589
                                handle_marking(h,w,GPOINTER_TO_INT(user),OPERATE_DELETE);
 
1590
                        }else{
 
1591
                                 if((GDK_CONTROL_MASK|GDK_SHIFT_MASK)&b->state)
 
1592
                                        return FALSE;
 
1593
                                /*g_print("Calling popup\n");  */
 
1594
              h->wi.event=e;
 
1595
              h->wi.item=w;
 
1596
                                h->wi.index=GPOINTER_TO_INT(user);
 
1597
                                /*g_fprintf(stderr,"Calling hist_itemRclk\n"); */
 
1598
                    history_item_right_click(h,e,GPOINTER_TO_INT(user));
 
1599
                                
 
1600
                        }
 
1601
                        return TRUE;
 
1602
                }else if( 1 == b->button){
 
1603
                  /* Get the text from the right element and set as clipboard */
 
1604
                        set_clipboard_text(h,element);
 
1605
                }       
 
1606
                fflush(NULL);
 
1607
        }
 
1608
        
 
1609
        return FALSE;
 
1610
}
 
1611
 
 
1612
/***************************************************************************/
 
1613
/** Attempt to handle enter key behaviour.
 
1614
\n\b Arguments:
 
1615
\n\b Returns:
 
1616
****************************************************************************/
 
1617
static void item_selected(GtkMenuItem *menu_item, gpointer user_data)
 
1618
{
 
1619
        static struct history_info *h=NULL;
 
1620
        if(NULL ==menu_item){
 
1621
                h=(struct history_info *)user_data;
 
1622
                return;
 
1623
        }
 
1624
                
 
1625
                
 
1626
        GdkEventKey *k=(GdkEventKey *)gtk_get_current_event();
 
1627
        GList* element = g_list_nth(history_list, GPOINTER_TO_INT(user_data));
 
1628
        /*g_print ("item_selected '%s' type %x val %x\n",(gchar *)((struct history_item *(element->data))->text),k->type, k->keyval);  */
 
1629
        if(0xFF0d == k->keyval && GDK_KEY_PRESS == k->type){
 
1630
                set_clipboard_text(h,element);
 
1631
        }
 
1632
}       
 
1633
 
 
1634
/***************************************************************************/
 
1635
/** Write the elements to the menu.
 
1636
\n\b Arguments:
 
1637
\n\b Returns:
 
1638
****************************************************************************/
 
1639
void write_history_menu_items(GList *list, GtkWidget *menu)
 
1640
{
 
1641
        GList *element;
 
1642
        if(NULL == list)
 
1643
                return;
 
1644
        for (element = list; element != NULL; element = element->next) 
 
1645
                        gtk_menu_shell_append((GtkMenuShell*)menu,element->data);       
 
1646
}
 
1647
 
 
1648
/***************************************************************************/
 
1649
/** Replace non-printing characters with ??.
 
1650
0x09->E28692 - \2192
 
1651
0x0a->E2818B - \204b
 
1652
space-E290A3 - \u2423 
 
1653
\n\b Arguments:
 
1654
\n\b Returns:
 
1655
****************************************************************************/
 
1656
GString* convert_string(GString* s)
 
1657
{
 
1658
        gchar arrow[4]={0xe2,0x86,0x92,0x00};/**0xe28692 (UTF-8 right-arrow) \\  */
 
1659
        gchar pharagraph[4]={0xe2,0x81,0x8b,0x00}; /**utf-8 pharagraph symbol \2192 */
 
1660
        gchar square_u[4]={0xe2,0x90,0xA3,0};    /**square-u \\2423  */
 
1661
        gchar *p, *r;
 
1662
        gint idx;
 
1663
        
 
1664
        for (p=s->str; p!= NULL; p=g_utf8_find_next_char(p,s->str+s->len)){
 
1665
                switch(*p){
 
1666
                        case 0x09:r=arrow; break;
 
1667
                        case 0x0a:r=pharagraph; break;
 
1668
                        case 0x20:r=square_u; break;
 
1669
                  default:r=NULL; break; 
 
1670
                }
 
1671
                if(NULL !=r ) {/**replace. */
 
1672
                        gint32 pos=(p-s->str)+1;
 
1673
                        *p=r[0];
 
1674
                        s=g_string_insert(s,pos,&r[1]);
 
1675
                        p=s->str+pos+2;
 
1676
                }
 
1677
        }
 
1678
        return s;
 
1679
}
 
1680
/***************************************************************************/
 
1681
/**  Called when status icon is left-clicked or action key hit.
 
1682
\n\b Arguments:
 
1683
\n\b Returns:
 
1684
****************************************************************************/
 
1685
 
 
1686
static gboolean show_history_menu(gpointer data)
 
1687
{
 
1688
  /* Declare some variables */
 
1689
  GtkWidget *menu,       *menu_item,
 
1690
            *menu_image, *item_label;
 
1691
  static struct history_info h;
 
1692
        gint nok,pok;
 
1693
        h.histno=GPOINTER_TO_INT(data);/**persistent or normal history  */
 
1694
        h.change_flag=0;
 
1695
        h.element_text=NULL;
 
1696
        h.wi.index=-1;
 
1697
  /**init our keystroke function  */
 
1698
        key_release_cb(NULL,NULL,NULL);
 
1699
        GList *element, *persistent=NULL;
 
1700
        GList *lhist=NULL;
 
1701
        int single_line=get_pref_int32("single_line");
 
1702
        
 
1703
  /* Create the menu */
 
1704
  menu = gtk_menu_new();
 
1705
        
 
1706
  h.menu=hmenu=menu;
 
1707
  h.clip_item=NULL;
 
1708
        h.delete_list=NULL;
 
1709
        h.persist_list=NULL;
 
1710
        h.wi.tmp1=0; /** used to tell edit what we are to edit  */
 
1711
        /*g_print("histmen %p\n",menu); */
 
1712
        my_item_event(NULL,NULL,(gpointer)&h); /**init our function  */
 
1713
        item_selected(NULL,(gpointer)&h);       /**ditto  */
 
1714
        gtk_menu_shell_set_take_focus((GtkMenuShell *)menu,TRUE); /**grab keyboard focus  */
 
1715
        /*g_signal_connect((GObject*)menu, "selection-done", (GCallback)selection_done, gtk_menu_get_attach_widget (menu));  */
 
1716
        g_signal_connect((GObject*)menu, "cancel", (GCallback)selection_done, &h); 
 
1717
        g_signal_connect((GObject*)menu, "selection-done", (GCallback)selection_done, &h); 
 
1718
  /*g_signal_connect((GObject*)menu, "selection-done", (GCallback)gtk_widget_destroy, NULL); */
 
1719
        /**Trap key events  */
 
1720
/*      g_signal_connect((GObject*)menu, "key-release-event", (GCallback)key_release_cb, (gpointer)&h); */
 
1721
  g_signal_connect((GObject*)menu, "event", (GCallback)key_release_cb, (gpointer)&h);
 
1722
        /**trap mnemonic events  */
 
1723
        /*g_signal_connect((GObject*)menu, "mnemonic-activate", (GCallback)key_release_cb, (gpointer)menu);  */
 
1724
 
 
1725
  /* -------------------- */
 
1726
  /*gtk_menu_shell_append((GtkMenuShell*)menu, gtk_separator_menu_item_new()); */
 
1727
  /* Items */
 
1728
  if ((history_list != NULL) && (history_list->data != NULL)) {
 
1729
    /* Declare some variables */
 
1730
                gint32 item_length= get_pref_int32("item_length");
 
1731
                gint32 ellipsize = get_pref_int32("ellipsize");
 
1732
                gint32 persistent_history=get_pref_int32("persistent_history");
 
1733
                gint32 nonprint_disp=get_pref_int32("nonprint_disp");
 
1734
    gint element_number = 0;
 
1735
    gchar* primary_temp = gtk_clipboard_wait_for_text(primary);
 
1736
    gchar* clipboard_temp = gtk_clipboard_wait_for_text(clipboard);
 
1737
    /* Reverse history if enabled */
 
1738
    if (0 && get_pref_int32("reverse_history")) {
 
1739
      /*history_list = g_list_reverse(history_list); */
 
1740
      element_number = g_list_length(history_list) - 1;
 
1741
    }
 
1742
    /* Go through each element and adding each */
 
1743
    for (element = history_list; element != NULL; element = element->next) {
 
1744
                        struct history_item *c=(struct history_item *)(element->data);
 
1745
                        gchar* hist_text=c->text;
 
1746
                        if(!(HIST_DISPLAY_PERSISTENT&h.histno) && (c->flags & CLIP_TYPE_PERSISTENT))
 
1747
                                goto next_loop;
 
1748
                        else if( !(HIST_DISPLAY_NORMAL&h.histno) && !(c->flags & CLIP_TYPE_PERSISTENT))
 
1749
                                goto next_loop;
 
1750
      GString* string = g_string_new(hist_text);
 
1751
                        if(nonprint_disp)
 
1752
                                string=convert_string(string);
 
1753
                  glong len=g_utf8_strlen(string->str, string->len);
 
1754
      /* Ellipsize text */
 
1755
      if (len > item_length) {
 
1756
        switch (ellipsize) {
 
1757
          case PANGO_ELLIPSIZE_START:
 
1758
                string = g_string_erase(string, 0, g_utf8_offset_to_pointer(string->str, len - item_length) - string->str);
 
1759
            /*string = g_string_erase(string, 0, string->len-(get_pref_int32("item_length"))); */
 
1760
            string = g_string_prepend(string, "...");
 
1761
            break;
 
1762
          case PANGO_ELLIPSIZE_MIDDLE:
 
1763
                {
 
1764
                                                gchar* p1 = g_utf8_offset_to_pointer(string->str, item_length / 2);
 
1765
            gchar* p2 = g_utf8_offset_to_pointer(string->str, len - item_length / 2);
 
1766
            string = g_string_erase(string, p1 - string->str, p2 - p1);
 
1767
            string = g_string_insert(string, p1 - string->str, "...");
 
1768
            /** string = g_string_erase(string, (get_pref_int32("item_length")/2), string->len-(get_pref_int32("item_length")));
 
1769
            string = g_string_insert(string, (string->len/2), "...");*/ 
 
1770
                                                }
 
1771
            break;
 
1772
          case PANGO_ELLIPSIZE_END:
 
1773
                string = g_string_truncate(string, g_utf8_offset_to_pointer(string->str, item_length) - string->str);
 
1774
            /*string = g_string_truncate(string, get_pref_int32("item_length")); */
 
1775
            string = g_string_append(string, "...");
 
1776
            break;
 
1777
        }
 
1778
      }
 
1779
                  /* Remove control characters */
 
1780
      gsize i = 0;
 
1781
      while (i < string->len)
 
1782
      {  /**fix 100% CPU utilization for odd data. - bug 2976890   */
 
1783
                                gsize nline=0;
 
1784
                                while(string->str[i+nline] == '\n' && nline+i<string->len)
 
1785
                                        nline++;
 
1786
                                if(nline){
 
1787
                                        g_string_erase(string, i, nline);
 
1788
                                        /* RMME printf("e %ld",nline);fflush(NULL); */
 
1789
                                }
 
1790
                                else
 
1791
          i++;
 
1792
 
 
1793
      }
 
1794
                        
 
1795
      /* Make new item with ellipsized text */
 
1796
      menu_item = gtk_menu_item_new_with_label(string->str);
 
1797
                
 
1798
                g_signal_connect((GObject*)menu_item,      "event",
 
1799
                       (GCallback)my_item_event, GINT_TO_POINTER(element_number));
 
1800
                  g_signal_connect((GObject*)menu_item,      "activate",
 
1801
                       (GCallback)item_selected, GINT_TO_POINTER(element_number));
 
1802
                
 
1803
      
 
1804
      /* Modify menu item label properties */
 
1805
      item_label = gtk_bin_get_child((GtkBin*)menu_item);
 
1806
                        if(single_line){
 
1807
                                /*gtk_label_set_line_wrap  */
 
1808
                                gtk_label_set_single_line_mode((GtkLabel*)item_label, TRUE);
 
1809
                        }       else{
 
1810
                                gtk_label_set_single_line_mode((GtkLabel*)item_label, FALSE);
 
1811
                        }
 
1812
      
 
1813
      /* Check if item is also clipboard text and make bold */
 
1814
      if ((clipboard_temp) && (p_strcmp(hist_text, clipboard_temp) == 0))
 
1815
      {
 
1816
        gchar* bold_text = g_markup_printf_escaped("<b>%s</b>", string->str);
 
1817
                          if( NULL == bold_text) g_fprintf(stderr,"NulBMKUp:'%s'\n",string->str);
 
1818
        gtk_label_set_markup((GtkLabel*)item_label, bold_text);
 
1819
        g_free(bold_text);
 
1820
        h.clip_item=menu_item;
 
1821
                                h.element_text=hist_text;
 
1822
                          h.wi.index=element_number;
 
1823
      }
 
1824
      else if ((primary_temp) && (p_strcmp(hist_text, primary_temp) == 0))
 
1825
      {
 
1826
        gchar* italic_text = g_markup_printf_escaped("<i>%s</i>", string->str);
 
1827
                          if( NULL == italic_text) g_fprintf(stderr,"NulIMKUp:'%s'\n",string->str);
 
1828
        gtk_label_set_markup((GtkLabel*)item_label, italic_text);
 
1829
        g_free(italic_text);
 
1830
        h.clip_item=menu_item;
 
1831
                          h.element_text=hist_text;
 
1832
                          h.wi.index=element_number;
 
1833
      }
 
1834
                        if(persistent_history && c->flags &CLIP_TYPE_PERSISTENT){
 
1835
                                persistent = g_list_prepend(persistent, menu_item);
 
1836
                                /*g_printf("persistent %s\n",c->text); */
 
1837
                        }       else{
 
1838
                                /* Append item */
 
1839
                                lhist = g_list_prepend(lhist, menu_item);
 
1840
              
 
1841
                        }
 
1842
                                
 
1843
      
 
1844
      /* Prepare for next item */
 
1845
      g_string_free(string, TRUE);
 
1846
next_loop:
 
1847
      /** if (get_pref_int32("reverse_history"))
 
1848
        element_number--;
 
1849
      else*/
 
1850
        element_number++;
 
1851
    }   /**end of for loop for each history item  */
 
1852
    /* Cleanup */
 
1853
    g_free(primary_temp);
 
1854
    g_free(clipboard_temp);
 
1855
    /* Return history to normal if reversed */
 
1856
    /** if (get_pref_int32("reverse_history"))
 
1857
      history_list = g_list_reverse(history_list);*/
 
1858
  }
 
1859
  else
 
1860
  {
 
1861
    /* Nothing in history so adding empty */
 
1862
    menu_item = gtk_menu_item_new_with_label(_("Empty"));
 
1863
    gtk_widget_set_sensitive(menu_item, FALSE);
 
1864
    gtk_menu_shell_append((GtkMenuShell*)menu, menu_item);
 
1865
  }
 
1866
        if (!get_pref_int32("reverse_history")) {
 
1867
                lhist = g_list_reverse(lhist);
 
1868
                persistent = g_list_reverse(persistent);
 
1869
        }       
 
1870
/**now actually add them from the list  */      
 
1871
        if(get_pref_int32("persistent_history")){
 
1872
                if(get_pref_int32("persistent_on_top")){
 
1873
                        write_history_menu_items(persistent,menu);
 
1874
                        gtk_menu_shell_append((GtkMenuShell*)menu, gtk_separator_menu_item_new()); 
 
1875
                        write_history_menu_items(lhist,menu);
 
1876
                }       else{
 
1877
                        write_history_menu_items(lhist,menu);
 
1878
                        gtk_menu_shell_append((GtkMenuShell*)menu, gtk_separator_menu_item_new()); 
 
1879
                        write_history_menu_items(persistent,menu);
 
1880
                }
 
1881
        }else { /**normal old operation, forget about persistence.  */
 
1882
                write_history_menu_items(lhist,menu);
 
1883
        }
 
1884
        
 
1885
  /* -------------------- */
 
1886
  gtk_menu_shell_append((GtkMenuShell*)menu, gtk_separator_menu_item_new());
 
1887
        
 
1888
        if(get_pref_int32("type_search")){
 
1889
    /* Edit clipboard */
 
1890
                h.title_item = gtk_image_menu_item_new_with_label( _("Use Alt-E to edit, Alt-C to clear") );
 
1891
    menu_image = gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU);
 
1892
    gtk_image_menu_item_set_image((GtkImageMenuItem*)h.title_item, menu_image);
 
1893
    gtk_menu_shell_append((GtkMenuShell*)menu, h.title_item);    
 
1894
  }else{
 
1895
    menu_item = gtk_image_menu_item_new_with_mnemonic(_("_Edit Clipboard"));
 
1896
    menu_image = gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU);
 
1897
    gtk_image_menu_item_set_image((GtkImageMenuItem*)menu_item, menu_image);
 
1898
                g_signal_connect((GObject*)menu_item, "activate", (GCallback)edit_selected, (gpointer)&h); 
 
1899
    gtk_menu_shell_append((GtkMenuShell*)menu, menu_item);
 
1900
                menu_item = gtk_image_menu_item_new_with_mnemonic(_("_Clear"));
 
1901
                /* Clear */
 
1902
          menu_image = gtk_image_new_from_stock(GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU);
 
1903
          gtk_image_menu_item_set_image((GtkImageMenuItem*)menu_item, menu_image);
 
1904
                g_signal_connect((GObject*)menu_item, "activate", (GCallback)clear_selected, (gpointer)&h);
 
1905
          gtk_menu_shell_append((GtkMenuShell*)menu, menu_item);
 
1906
  }
 
1907
        g_list_free(lhist);
 
1908
        g_list_free(persistent);
 
1909
  /* Popup the menu... */
 
1910
  gtk_widget_show_all(menu);
 
1911
  gtk_menu_popup((GtkMenu*)menu, NULL, NULL, get_pref_int32("history_pos")?postition_history:NULL, NULL, 1, gtk_get_current_event_time());
 
1912
        /**set last entry at first -fixes bug 2974614 */
 
1913
        if(get_pref_int32("reverse_history") && NULL != h.clip_item)
 
1914
                gtk_menu_shell_select_item((GtkMenuShell*)menu,h.clip_item);
 
1915
        else    
 
1916
                gtk_menu_shell_select_first((GtkMenuShell*)menu, TRUE);
 
1917
  /* Return FALSE so the g_timeout_add() function is called only once */
 
1918
  return FALSE;
 
1919
}
 
1920
 
 
1921
 
 
1922
/***************************************************************************/
 
1923
/** .
 
1924
\n\b Arguments:
 
1925
\n\b Returns:
 
1926
****************************************************************************/
 
1927
void _show_history_menu (GtkMenuItem *m, gpointer data)
 
1928
{
 
1929
        g_timeout_add(POPUP_DELAY, show_history_menu, GINT_TO_POINTER(figure_histories()));
 
1930
}
 
1931
/***************************************************************************/
 
1932
/** .
 
1933
\n\b Arguments:
 
1934
\n\b Returns:
 
1935
****************************************************************************/
 
1936
GtkWidget *create_parcellite_menu(guint button, guint activate_time)
 
1937
{
 
1938
  /* Declare some variables */
 
1939
  GtkWidget *menu, *menu_item;
 
1940
  
 
1941
  /* Create the menu */
 
1942
  menu = gtk_menu_new();
 
1943
  /*g_signal_connect((GObject*)menu, "selection-done", (GCallback)gtk_widget_destroy, NULL); */
 
1944
  /* About */
 
1945
  menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT, NULL);
 
1946
  g_signal_connect((GObject*)menu_item, "activate", (GCallback)show_about_dialog, NULL);
 
1947
  gtk_menu_shell_append((GtkMenuShell*)menu, menu_item);
 
1948
        
 
1949
        /* Save History */
 
1950
  menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_SAVE_AS, NULL);
 
1951
  g_signal_connect((GObject*)menu_item, "activate", (GCallback)history_save_as, NULL);
 
1952
        gtk_widget_set_tooltip_text(menu_item, _("Save History as a text file. Prepends xHIST_0000 to each entry. x is either P(persistent) or N (normal)"));
 
1953
  gtk_menu_shell_append((GtkMenuShell*)menu, menu_item);
 
1954
  /* Preferences */
 
1955
  menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_PREFERENCES, NULL);
 
1956
  g_signal_connect((GObject*)menu_item, "activate", (GCallback)preferences_selected, NULL);
 
1957
  gtk_menu_shell_append((GtkMenuShell*)menu, menu_item);
 
1958
        if(have_appindicator){
 
1959
                        /* History */
 
1960
                GtkWidget *img=gtk_image_new_from_icon_name(PARCELLITE_ICON,GTK_ICON_SIZE_MENU); 
 
1961
          menu_item = gtk_image_menu_item_new_with_mnemonic(_("_History"));
 
1962
                gtk_image_menu_item_set_image((GtkImageMenuItem *)menu_item,img);
 
1963
          g_signal_connect((GObject*)menu_item, "activate", (GCallback)_show_history_menu, NULL);
 
1964
          gtk_menu_shell_append((GtkMenuShell*)menu, menu_item);
 
1965
        }
 
1966
        
 
1967
  /* -------------------- */
 
1968
  gtk_menu_shell_append((GtkMenuShell*)menu, gtk_separator_menu_item_new());
 
1969
  /* Quit */
 
1970
  menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
 
1971
  g_signal_connect((GObject*)menu_item, "activate", (GCallback)quit_selected, NULL);
 
1972
  gtk_menu_shell_append((GtkMenuShell*)menu, menu_item);
 
1973
  /* Popup the menu... */
 
1974
  gtk_widget_show_all(menu);
 
1975
  gtk_menu_popup((GtkMenu*)menu, NULL, NULL, NULL, NULL, button, activate_time);        
 
1976
        return menu;
 
1977
}
 
1978
 
 
1979
/* Called when status icon is right-clicked */
 
1980
static void  show_parcellite_menu(GtkStatusIcon *status_icon, guint button, guint activate_time,  gpointer data)
 
1981
{
 
1982
        create_parcellite_menu(button, activate_time);
 
1983
}
 
1984
 
 
1985
/***************************************************************************/
 
1986
/** .
 
1987
\n\b Arguments:
 
1988
\n\b Returns:
 
1989
****************************************************************************/
 
1990
gboolean show_parcellite_menu_wrapper(gpointer data)
 
1991
{
 
1992
        create_parcellite_menu(0, gtk_get_current_event_time());
 
1993
}
 
1994
 
 
1995
/***************************************************************************/
 
1996
/** .
 
1997
\n\b Arguments:
 
1998
\n\b Returns:
 
1999
****************************************************************************/
 
2000
gint figure_histories(void)
 
2001
{
 
2002
        gint i;
 
2003
        if(get_pref_int32("persistent_history")){ 
 
2004
                if(get_pref_int32("persistent_separate"))
 
2005
                        i=HIST_DISPLAY_NORMAL;
 
2006
                else
 
2007
                        i=HIST_DISPLAY_PERSISTENT|HIST_DISPLAY_NORMAL;
 
2008
        }else 
 
2009
                i=HIST_DISPLAY_NORMAL;
 
2010
        /*g_printf("Using history 0x%X\n",i); */
 
2011
        return i;
 
2012
}
 
2013
#ifdef HAVE_APPINDICATOR
 
2014
/***************************************************************************/
 
2015
/** .
 
2016
\n\b Arguments:
 
2017
\n\b Returns:
 
2018
****************************************************************************/
 
2019
void create_app_indicator(void)
 
2020
{
 
2021
        /* Create the menu */
 
2022
        indicator_menu = create_parcellite_menu(0,gtk_get_current_event_time());
 
2023
        /* check if we need to create the indicator or just refresh the menu */
 
2024
        if(NULL == indicator) {
 
2025
                indicator = app_indicator_new("parcellite", "parcellite", APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
 
2026
                app_indicator_set_status (indicator, APP_INDICATOR_STATUS_ACTIVE);
 
2027
                
 
2028
                app_indicator_set_attention_icon (indicator,"parcellite");
 
2029
        }
 
2030
        app_indicator_set_menu (indicator, GTK_MENU (indicator_menu));
 
2031
}
 
2032
#endif
 
2033
        
 
2034
/* Called when status icon is left-clicked */
 
2035
static void status_icon_clicked(GtkStatusIcon *status_icon, gpointer user_data)
 
2036
{
 
2037
  /* Check what type of click was recieved */
 
2038
  GdkModifierType state;
 
2039
  gtk_get_current_event_state(&state);
 
2040
  /* Control click */
 
2041
  if (state == GDK_MOD2_MASK+GDK_CONTROL_MASK || state == GDK_CONTROL_MASK)
 
2042
  {
 
2043
                g_fprintf(stderr,"Got Ctrl-click\n");
 
2044
    if (actions_lock == FALSE)
 
2045
    {
 
2046
      g_timeout_add(POPUP_DELAY, show_actions_menu, NULL);
 
2047
    }
 
2048
  }
 
2049
  /* Normal click */
 
2050
  else
 
2051
  {
 
2052
    g_timeout_add(POPUP_DELAY, show_history_menu, GINT_TO_POINTER(figure_histories()));
 
2053
  }
 
2054
}
 
2055
 
 
2056
/* Called when history global hotkey is pressed */
 
2057
void history_hotkey(char *keystring, gpointer user_data)
 
2058
{
 
2059
  g_timeout_add(POPUP_DELAY, show_history_menu, GINT_TO_POINTER(figure_histories()));
 
2060
}
 
2061
/* Called when persistent history global hotkey is pressed */
 
2062
void phistory_hotkey(char *keystring, gpointer user_data)
 
2063
{
 
2064
        if(get_pref_int32("persistent_history") && get_pref_int32("persistent_separate"))
 
2065
    g_timeout_add(POPUP_DELAY, show_history_menu, GINT_TO_POINTER(HIST_DISPLAY_PERSISTENT));
 
2066
}
 
2067
 
 
2068
/* Called when actions global hotkey is pressed */
 
2069
void actions_hotkey(char *keystring, gpointer user_data)
 
2070
{
 
2071
  g_timeout_add(POPUP_DELAY, show_actions_menu, NULL);
 
2072
}
 
2073
 
 
2074
/* Called when actions global hotkey is pressed */
 
2075
void menu_hotkey(char *keystring, gpointer user_data)
 
2076
{
 
2077
#ifdef HAVE_APPINDICATOR
 
2078
        /*create_app_indicator(); */
 
2079
        create_parcellite_menu(0, gtk_get_current_event_time());
 
2080
        /** GtkWidget * w=create_parcellite_menu(0, gtk_get_current_event_time());
 
2081
        app_indicator_set_menu (indicator, GTK_MENU (w));*/
 
2082
#else
 
2083
  show_parcellite_menu(status_icon, 0, 0, NULL);
 
2084
#endif
 
2085
}
 
2086
 
 
2087
/* Startup calls and initializations */
 
2088
static void parcellite_init()
 
2089
{
 
2090
        int i;
 
2091
/* Create clipboard */
 
2092
  primary = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
 
2093
  clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
 
2094
  
 
2095
        if(FALSE ==g_thread_supported()){
 
2096
                g_fprintf(stderr,"g_thread not init!\n");
 
2097
        }
 
2098
        clip_lock= g_mutex_new();
 
2099
        hist_lock= g_mutex_new();
 
2100
        g_mutex_unlock(clip_lock);
 
2101
 
 
2102
  show_icon=!get_pref_int32("no_icon");
 
2103
  /* Read history */
 
2104
  if (get_pref_int32("save_history")){
 
2105
                gchar *x;
 
2106
                /*g_printf("Calling read_hist\n"); */
 
2107
                read_history();
 
2108
                if(NULL != history_list){
 
2109
                        struct history_item *c;
 
2110
                        c=(struct history_item *)(history_list->data);  
 
2111
                        if(NULL == (x=is_clipboard_empty(primary)))
 
2112
                                update_clipboard(primary,c->text,H_MODE_LIST);
 
2113
                        else g_free (x);
 
2114
                        if(NULL == (x=is_clipboard_empty(clipboard)))
 
2115
                                update_clipboard(clipboard,c->text,H_MODE_LIST);
 
2116
                        else g_free(x);
 
2117
                }
 
2118
        }
 
2119
        
 
2120
  g_timeout_add(CHECK_INTERVAL, check_clipboards_tic, NULL);  
 
2121
#ifdef HAVE_APPINDICATOR
 
2122
        check_for_appindictor(NULL);
 
2123
        if(!have_appindicator) /**maybe it slept in, check for it every 30 seconds.  */
 
2124
                g_timeout_add(CHECK_APPINDICATOR_INTERVAL, check_for_appindictor, NULL);  
 
2125
#endif
 
2126
  
 
2127
  /* Bind global keys */
 
2128
  keybinder_init();
 
2129
        for (i=0;NULL != keylist[i].name; ++i)
 
2130
                bind_itemkey(keylist[i].name,keylist[i].keyfunc);
 
2131
  
 
2132
  /* Create status icon */
 
2133
  if (show_icon)
 
2134
  {
 
2135
#ifdef HAVE_APPINDICATOR
 
2136
        if(have_appindicator)/* Indicator */
 
2137
                create_app_indicator();
 
2138
#endif
 
2139
                if(!have_appindicator){
 
2140
                        status_icon = gtk_status_icon_new_from_icon_name(PARCELLITE_ICON); 
 
2141
            gtk_status_icon_set_tooltip((GtkStatusIcon*)status_icon, _("Clipboard Manager"));
 
2142
            g_signal_connect((GObject*)status_icon, "activate", (GCallback)status_icon_clicked, NULL);
 
2143
            g_signal_connect((GObject*)status_icon, "popup-menu", (GCallback)show_parcellite_menu, NULL);
 
2144
                }
 
2145
          
 
2146
  }
 
2147
}
 
2148
 
 
2149
 
 
2150
/***************************************************************************/
 
2151
/** .
 
2152
\n\b Arguments: 
 
2153
which - which fifo we write to.
 
2154
\n\b Returns:
 
2155
****************************************************************************/
 
2156
void write_stdin(struct p_fifo *fifo, int which)
 
2157
{
 
2158
  if (!isatty(fileno(stdin)))   {
 
2159
    GString* piped_string = g_string_new(NULL);
 
2160
    /* Append stdin to string */
 
2161
    while (1)    {
 
2162
      gchar* buffer = (gchar*)g_malloc(256);
 
2163
      if (fgets(buffer, 256, stdin) == NULL)  {
 
2164
        g_free(buffer);
 
2165
        break;
 
2166
      }
 
2167
      g_string_append(piped_string, buffer);
 
2168
      g_free(buffer);
 
2169
    }
 
2170
    /* Check if anything was piped in */
 
2171
    if (piped_string->len > 0) {
 
2172
      /* Truncate new line character */
 
2173
      /* g_string_truncate(piped_string, (piped_string->len - 1)); */
 
2174
      /* Copy to clipboard */
 
2175
           write_fifo(fifo,which,piped_string->str,piped_string->len); 
 
2176
     /*sleep(10); */
 
2177
      /* Exit */
 
2178
    }
 
2179
    g_string_free(piped_string, TRUE);
 
2180
                        
 
2181
        }
 
2182
}
 
2183
        
 
2184
/***************************************************************************/
 
2185
        /** .
 
2186
        \n\b Arguments:
 
2187
        \n\b Returns:
 
2188
        ****************************************************************************/
 
2189
int main(int argc, char *argv[])
 
2190
{
 
2191
        struct cmdline_opts *opts;
 
2192
        int mode;
 
2193
        
 
2194
  bindtextdomain(GETTEXT_PACKAGE, PARCELLITELOCALEDIR);
 
2195
  bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
 
2196
  textdomain(GETTEXT_PACKAGE);
 
2197
  
 
2198
  /* Initiate GTK+ */
 
2199
  gtk_init(&argc, &argv);
 
2200
   /* Read preferences */
 
2201
  read_preferences();
 
2202
#ifdef  DEBUG_UPDATE
 
2203
        if(get_pref_int32("debug_update")) debug_update=1;
 
2204
#endif
 
2205
  /* Parse options */
 
2206
        opts=parse_options(argc, argv);
 
2207
  if(NULL == opts)
 
2208
        return 1;
 
2209
        if(opts->exit)
 
2210
                return 0;
 
2211
        mode=PROC_MODE_EXACT;
 
2212
        if(get_pref_int32("multi_user"))
 
2213
          mode|=PROC_MODE_USER_QUALIFY;
 
2214
        /*g_printf("mode=0x%X\n",mode); */
 
2215
        if(proc_find(PARCELLITE_PROG_NAME,mode,NULL)<2) /**1 for me, and 1 for a running instance  */
 
2216
                mode=PROG_MODE_DAEMON; /**first instance  */
 
2217
        else
 
2218
                mode=PROG_MODE_CLIENT; /**already running, just access fifos & exit.  */
 
2219
        
 
2220
        /**get options/cmd line not parsed.  */
 
2221
        if( NULL != opts->leftovers)g_print("%s\n",opts->leftovers);
 
2222
        /**init fifo should set up the fifo and the callback (if we are daemon mode)  */
 
2223
                if(opts->primary)       {
 
2224
                        if(NULL == (fifo=init_fifo(FIFO_MODE_PRI|mode))) return 1;
 
2225
                        if(fifo->dbg) g_fprintf(stderr,"Hit PRI opt!\n");
 
2226
                        
 
2227
                        if(PROG_MODE_CLIENT & mode){
 
2228
                                if(NULL != opts->leftovers){
 
2229
                                        write_fifo(fifo,FIFO_MODE_PRI,opts->leftovers,strlen(opts->leftovers));
 
2230
                      g_free(opts->leftovers);  
 
2231
                                }
 
2232
                                
 
2233
                                if(fifo->dbg) g_fprintf(stderr,"checking stdin\n");
 
2234
                                write_stdin(fifo,FIFO_MODE_PRI);
 
2235
                                usleep(1000);
 
2236
                        }
 
2237
                        /* Grab primary */
 
2238
            GtkClipboard* prim = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
 
2239
            /* Print primary text (if any) */
 
2240
            gchar* prim_text = gtk_clipboard_wait_for_text(prim);
 
2241
            if (prim_text)
 
2242
              g_print("%s", prim_text);
 
2243
            g_free(prim_text);
 
2244
                        
 
2245
          }  else if(opts->clipboard){
 
2246
                        if(NULL == (fifo=init_fifo(FIFO_MODE_CLI|mode))) return 1;
 
2247
                        
 
2248
                        if(PROG_MODE_CLIENT & mode){
 
2249
                                if(NULL != opts->leftovers){
 
2250
                                        write_fifo(fifo,FIFO_MODE_CLI,opts->leftovers,strlen(opts->leftovers));
 
2251
                      g_free(opts->leftovers);
 
2252
                                }       
 
2253
                                write_stdin(fifo,FIFO_MODE_CLI);
 
2254
                                usleep(1000);
 
2255
                        }
 
2256
              
 
2257
                        GtkClipboard* clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
 
2258
            /* Print clipboard text (if any) */
 
2259
            gchar* clip_text = gtk_clipboard_wait_for_text(clip);
 
2260
            if (clip_text)
 
2261
              g_print("%s", clip_text);
 
2262
            g_free(clip_text);
 
2263
          }  else       { /*use CLIPBOARD*/
 
2264
                        GtkClipboard* clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
 
2265
                        if(NULL == (fifo=init_fifo(FIFO_MODE_NONE|mode))) return 1;
 
2266
                                /* Copy from unrecognized options */
 
2267
                        if(PROG_MODE_CLIENT & mode){
 
2268
                          if(NULL != opts->leftovers){
 
2269
                            write_fifo(fifo,FIFO_MODE_CLI,opts->leftovers,strlen(opts->leftovers));
 
2270
                      g_free(opts->leftovers);
 
2271
                                }       
 
2272
                                         /* Check if stdin is piped */
 
2273
                    write_stdin(fifo,FIFO_MODE_CLI);
 
2274
                                usleep(1000);
 
2275
                        }
 
2276
                        
 
2277
                        gchar* clip_text = gtk_clipboard_wait_for_text(clip);
 
2278
        if (clip_text)
 
2279
        g_print("%s", clip_text);
 
2280
         g_free(clip_text);
 
2281
            
 
2282
                }       
 
2283
                          /* Run as daemon option */
 
2284
  if (opts->daemon && (PROG_MODE_DAEMON & mode))  {
 
2285
    init_daemon_mode();
 
2286
  } 
 
2287
        if(PROG_MODE_CLIENT & mode){
 
2288
                close_fifos(fifo);
 
2289
                return 0;
 
2290
        }       
 
2291
  
 
2292
  /* Init Parcellite */
 
2293
  parcellite_init(mode);
 
2294
  /*g_printf("Start main loop\n"); */
 
2295
  /* Run GTK+ loop */
 
2296
  gtk_main();
 
2297
  
 
2298
#ifdef HAVE_APPINDICATOR
 
2299
        if (have_appindicator & show_icon)
 
2300
                app_indicator_set_status(indicator, APP_INDICATOR_STATUS_PASSIVE);
 
2301
#endif
 
2302
        
 
2303
  /* Unbind keys */
 
2304
        keybinder_unbind(get_pref_string("phistory_key"), phistory_hotkey);
 
2305
  keybinder_unbind(get_pref_string("history_key"), history_hotkey);
 
2306
  keybinder_unbind(get_pref_string("actions_key"), actions_hotkey);
 
2307
  keybinder_unbind(get_pref_string("menu_key"), menu_hotkey);
 
2308
  /* Cleanup */
 
2309
        /**  
 
2310
  g_free(prefs.history_key);
 
2311
  g_free(prefs.actions_key);
 
2312
  g_free(prefs.menu_key);
 
2313
        */
 
2314
  g_list_free(history_list);
 
2315
  close_fifos(fifo);
 
2316
  /* Exit */
 
2317
  return 0;
 
2318
}