Package: rox-filer Version: 2.4-1 Severity: wishlist Forwarded: http://sourceforge.net/tracker/index.php?func=detail&aid=1531890&group_id=7023&atid=307023
Pinboard click commands are useful in situations when enabling the forward-to-WM option isn't practical due to the WM not doing anything useful with the information. Here, I'm using it to have right-click open the XFCE menu via a lightly-hacked xfce4-menu-popup (since I happen to prefer ROX-Filer over Thunar). It may be worth tweaking the patch to provide a sensible default command to launch a standalone popup menu program; if so, rox-filer should at least recommend that package. (The patch is tested with rox-filer 2.5.) -- | Darren Salt | linux or ds at | nr. Ashington, | Toon | RISC OS, Linux | youmustbejoking,demon,co,uk | Northumberland | Army | + Output less CO2 => avoid massive flooding. TIME IS RUNNING OUT *FAST*. "There's nothing you can do that can't be done." - John Lennon.
diff -urNad rox-filer-2.5~/ROX-Filer/Options.xml rox-filer-2.5/ROX-Filer/Options.xml --- rox-filer-2.5~/ROX-Filer/Options.xml 2006-07-31 17:19:55.000000000 +0100 +++ rox-filer-2.5/ROX-Filer/Options.xml 2006-07-31 17:20:16.945598165 +0100 @@ -370,6 +370,11 @@ <toggle name='blackbox_hack' label='Blackbox root menus hack'>Blackbox, Fluxbox and similar window managers do not yet work well with the ROX-Filer pinboard. This option enables some workarounds. These window managers are expected to change their behaviour in new versions so that this isn't necessary.</toggle> <toggle name='panel_is_dock' label="Panel is a 'dock'">Disable this option if the panel stays above other windows against your wishes. Requires a restart to take effect.</toggle> </frame> + <frame label='Pinboard click commands'> + <entry name='pinboard_user_defined_command_0' label='Middle-click on pinboard or icon:'>The command to be executed when you middle-click on the pinboard or a pinboard icon (no distinction is made).</entry> + <entry name='pinboard_user_defined_command_1' label='Right-click on pinboard:'>The command to be executed when you right-click on the pinboard.</entry> + <label help='1'>If a command is present, then the button's normal behaviour is overridden.</label> + </frame> <frame label='Drag and drop'> <toggle name='dnd_no_hostnames' label="Don't use hostnames">Some older applications don't support XDND fully and may need to have this option turned on. Use this if dragging files to an application shows a + sign on the pointer but the drop doesn't work.</toggle> </frame> diff -urNad rox-filer-2.5~/ROX-Filer/src/bind.c rox-filer-2.5/ROX-Filer/src/bind.c --- rox-filer-2.5~/ROX-Filer/src/bind.c 2006-07-31 17:19:55.000000000 +0100 +++ rox-filer-2.5/ROX-Filer/src/bind.c 2006-07-31 17:19:58.285335695 +0100 @@ -63,6 +63,8 @@ gboolean release = event->type == GDK_BUTTON_RELEASE; gboolean select = event->button == 1; /* (old RISC OS names) */ gboolean adjust = event->button != 1; + gboolean pinboard = context == BIND_PINBOARD_ICON || + context == BIND_PINBOARD; gboolean dclick = event->type == GDK_2BUTTON_PRESS; gboolean dclick_mode = @@ -70,14 +72,17 @@ (context == BIND_PINBOARD_ICON && !o_single_pinboard.int_value); if (b > 3) - return ACT_IGNORE; + return (pinboard && press) ? ACT_PIN_USER_DEFINED : ACT_IGNORE; - if (context == BIND_PINBOARD_ICON || context == BIND_PINBOARD) + if (pinboard) menu_button = 3; /* Must work with window manager */ if (b == menu_button) return press ? ACT_POPUP_MENU : ACT_IGNORE; + if (b == 2 && pinboard) + return press ? ACT_PIN_USER_DEFINED : ACT_IGNORE; + if (item && dclick && dclick_mode) return shift ? ACT_EDIT_ITEM : ACT_OPEN_ITEM; diff -urNad rox-filer-2.5~/ROX-Filer/src/bind.h rox-filer-2.5/ROX-Filer/src/bind.h --- rox-filer-2.5~/ROX-Filer/src/bind.h 2006-07-31 17:19:55.000000000 +0100 +++ rox-filer-2.5/ROX-Filer/src/bind.h 2006-07-31 17:19:58.285335695 +0100 @@ -34,6 +34,7 @@ ACT_LASSO_CLEAR, /* Clear selection, and start lasso drag */ ACT_LASSO_MODIFY, /* Start lasso drag without clearing */ ACT_RESIZE, /* Auto-resize the filer window */ + ACT_PIN_USER_DEFINED, /* User-defined action on the pinboard */ } BindAction; void bind_init(void); diff -urNad rox-filer-2.5~/ROX-Filer/src/pinboard.c rox-filer-2.5/ROX-Filer/src/pinboard.c --- rox-filer-2.5~/ROX-Filer/src/pinboard.c 2006-07-31 17:19:56.000000000 +0100 +++ rox-filer-2.5/ROX-Filer/src/pinboard.c 2006-07-31 17:19:58.285335695 +0100 @@ -151,6 +151,8 @@ static Option o_top_margin, o_bottom_margin, o_left_margin, o_right_margin; static Option o_pinboard_image_scaling; +static Option o_pinboard_user_cmd[2]; /* index == button number - 2 */ + /* Static prototypes */ static GType pin_icon_get_type(void); static void set_size_and_style(PinIcon *pi); @@ -238,6 +240,8 @@ void pinboard_init(void) { + int i; + option_add_string(&o_pinboard_fg_colour, "pinboard_fg_colour", "#fff"); option_add_string(&o_pinboard_bg_colour, "pinboard_bg_colour", "#888"); option_add_string(&o_pinboard_shadow_colour, "pinboard_shadow_colour", @@ -265,6 +269,13 @@ option_add_int(&o_pinboard_image_scaling, "pinboard_image_scaling", 0); + for (i = 0; i < G_N_ELEMENTS (o_pinboard_user_cmd); ++i) + { + char *opt = g_strdup_printf ("pinboard_user_defined_command_%d", i); + option_add_string(&o_pinboard_user_cmd[i], opt, ""); + /* string not freed, avoiding use-after-free */ + } + option_add_notify(pinboard_check_options); gdk_color_parse(o_pinboard_fg_colour.value, &pin_text_fg_col); @@ -1174,6 +1185,40 @@ &edge, TRUE); } +static inline gboolean is_empty (const char *v) +{ + while (isspace (*v)) + ++v; + return !*v; +} + +static gboolean spawn_user_command(int button) +{ + GError *error = NULL; + gint argc; + gchar **argv = NULL; + char *msg; + + button -= 2; + if (button < 0 || button >= G_N_ELEMENTS (o_pinboard_user_cmd) || + is_empty (o_pinboard_user_cmd[button].value)) + return FALSE; /* nothing to do */ + + if (!g_shell_parse_argv (o_pinboard_user_cmd[button].value, + &argc, &argv, &error)) + { + delayed_error("%s", error ? error->message : "(null)"); + g_error_free(error); + } + else + { + rox_spawn (home_dir, argv); + g_strfreev (argv); + } + + return TRUE; +} + static void perform_action(PinIcon *pi, GdkEventButton *event) { BindAction action; @@ -1196,7 +1241,12 @@ return; case ACT_POPUP_MENU: dnd_motion_ungrab(); - pinboard_show_menu(event, pi); + if (pi || !spawn_user_command(event->button)) + pinboard_show_menu(event, pi); + return; + case ACT_PIN_USER_DEFINED: + dnd_motion_ungrab(); + spawn_user_command(event->button); return; case ACT_IGNORE: return; @@ -1275,8 +1325,19 @@ ButtonPressMask | ButtonReleaseMask, (XEvent *) &xev); } -#define FORWARDED_BUTTON(pi, b) ((b) == 2 || \ - (((b) == 3 || (b) == 1) && o_forward_buttons_13.int_value && !pi)) +static inline gboolean FORWARDED_BUTTON (const PinIcon *pi, int button) +{ + switch (button) + { + case 1: + case 3: + return o_forward_buttons_13.int_value && !pi; + case 2: + return TRUE; + default: + return FALSE; + } +} /* pi is NULL if this is a root event */ static gboolean button_release_event(GtkWidget *widget, @@ -1284,7 +1345,10 @@ PinIcon *pi) { if (FORWARDED_BUTTON(pi, event->button)) - forward_to_root(event); + { + if (spawn_user_command (event->button)) + forward_to_root(event); + } else if (dnd_motion_release(event)) { if (motion_buttons_pressed == 0 && lasso_in_progress)