Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Caja file manager support #14

Open
daf opened this issue Apr 25, 2012 · 1 comment · May be fixed by #144
Open

Caja file manager support #14

daf opened this issue Apr 25, 2012 · 1 comment · May be fixed by #144

Comments

@daf
Copy link
Member

daf commented Apr 25, 2012

A pro sent me an email with a patch. Must make it simultaneously work with Nautilus and Caja.

/*

This file is from Nitrogen, an X11 background setter.  
Copyright (C) 2006  Dave Foster & Javeed Shaikh

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.

*/

#include "SetBG.h"
#include "main.h"
#include <X11/Xatom.h>
#include "gcs-i18n.h"
#include "Util.h"

using namespace Util;

/**
* Sets the background to the image in the file specified.
*
* @param    disp    The display to set it on.  If "", uses the default
display, and passes is out by reference.
* @param    file    The file to set the bg to
* @param    mode    Stretch, tile, center, bestfit
* @param    bgcolor The background color for modes that do not cover
entire portions
* @return           If it went smoothly
*/
bool SetBG::set_bg( Glib::ustring &disp, Glib::ustring file, SetMode
mode, Gdk::Color bgcolor) {

    gint winx,winy,winw,winh,wind;
    Glib::RefPtr<Gdk::Display> _display;
    Glib::RefPtr<Gdk::Screen> screen;
    Glib::RefPtr<Gdk::Window> window;
    Glib::RefPtr<Gdk::GC> gc_;
    Glib::RefPtr<Gdk::Colormap> colormap;
    Glib::RefPtr<Gdk::Pixbuf> pixbuf, outpixbuf;
    Glib::RefPtr<Gdk::Pixmap> pixmap;

    // open display and screen
    _display = (disp == "") ?
Gdk::Display::open(Gdk::DisplayManager::get()->get_default_display()->get_name()) : Gdk::Display::open(disp);
    if (!_display) {
        std::cerr << _("Could not open display") << " " << disp << "\n";
        return false;
    }

    // get the screen
    screen = _display->get_default_screen();

    // restore the disp name
    disp = screen->make_display_name();

    // get window stuff
    window = screen->get_root_window();
    window->get_geometry(winx,winy,winw,winh,wind);

    // check to see if nautilus is running
    if (SetBG::get_rootwindowtype(window) == SetBG::NAUTILUS)
        return SetBG::set_bg_nautilus(screen, file, mode, bgcolor);

   // NOTE: although we now have a way of detecting XFCE, just setting
the bg like
   // in normal X seems to work just fine.

    // create gc and colormap
    gc_ = Gdk::GC::create(window);
    colormap = screen->get_default_colormap();

    // allocate bg color
    colormap->alloc_color(bgcolor, false, true);

    // create pixmap 
    pixmap = Gdk::Pixmap::create(window,winw,winh,window->get_depth());
    pixmap->set_colormap(colormap);

    // get our pixbuf from the file
    try {
        pixbuf = Gdk::Pixbuf::create_from_file(file);   
    } catch (Glib::FileError e) {
        std::cerr << _("ERROR: Could not load file in bg set") << ": " <<
e.what() << "\n";
        return false;
    }

    // apply the bg color to pixbuf here, because every make_ method would
    // have to do it anyway.
    pixbuf = pixbuf->composite_color_simple(pixbuf->get_width(),
        pixbuf->get_height(), Gdk::INTERP_NEAREST, 255, 1,
bgcolor.get_pixel(),
        bgcolor.get_pixel());

   // if automatic, figure out what mode we really want
   if (mode == SetBG::SET_AUTO)
       mode = SetBG::get_real_mode(pixbuf, winw, winh);

    switch(mode) {

        case SetBG::SET_SCALE:
            outpixbuf = SetBG::make_scale(pixbuf, winw, winh, bgcolor);
            break;

        case SetBG::SET_TILE:
            outpixbuf = SetBG::make_tile(pixbuf, winw, winh, bgcolor);
            break;

        case SetBG::SET_CENTER:
            outpixbuf = SetBG::make_center(pixbuf, winw, winh, bgcolor);
            break;

        case SetBG::SET_ZOOM:
            outpixbuf = SetBG::make_zoom(pixbuf, winw, winh, bgcolor);
            break;

        case SetBG::SET_ZOOM_FILL:
            outpixbuf = SetBG::make_zoom_fill(pixbuf, winw, winh, bgcolor);
            break;

        default:
            std::cerr << _("Unknown mode for saved bg on") << " " << disp <<
std::endl;
            return false;
    };

    // render it to the pixmap
    pixmap->draw_pixbuf(gc_, outpixbuf, 0,0,0,0, winw, winh,
Gdk::RGB_DITHER_NONE,0,0);

    // begin the X fun!
    Display *xdisp = GDK_DISPLAY_XDISPLAY(_display->gobj());
    XSetCloseDownMode(xdisp, RetainPermanent);
    Window xwin = DefaultRootWindow(xdisp);
    Pixmap xpm = GDK_PIXMAP_XID(pixmap->gobj());

    // FROM HERE, mostly ported from feh and 
    // http://www.eterm.org/docs/view.php?doc=ref#trans

    Atom prop_root, prop_esetroot, type;
    int format;
    unsigned long length, after;
    unsigned char *data_root, *data_esetroot;

    // set and make persistant

    prop_root = XInternAtom(xdisp, "_XROOTPMAP_ID", True);
    prop_esetroot = XInternAtom(xdisp, "ESETROOT_PMAP_ID", True);

    if (prop_root != None && prop_esetroot != None) {
        XGetWindowProperty(xdisp, xwin, prop_root, 0L, 1L, False,
AnyPropertyType, &type, &format, &length, &after, &data_root);
        if (type == XA_PIXMAP) {
            XGetWindowProperty(xdisp, xwin, prop_esetroot, 0L, 1L, False,
AnyPropertyType, &type, &format, &length, &after, &data_esetroot);
            if (data_root && data_esetroot)
                if (type == XA_PIXMAP && *((Pixmap *) data_root) == *((Pixmap *)
data_esetroot)) {
                    //XFreePixmap(xdisp, *((Pixmap*) data_root));
                    XKillClient(xdisp, *((Pixmap *) data_root));
                    //std::cout << "Shoulda killed\n";
                    //printf("Test says to remove %x\n", *((Pixmap*) data_root));
                }
        }
    }

    prop_root = XInternAtom(xdisp, "_XROOTPMAP_ID", False);
    prop_esetroot = XInternAtom(xdisp, "ESETROOT_PMAP_ID", False);

    if (prop_root == None || prop_esetroot == None) {
        std::cerr << _("ERROR: BG set could not make atoms.") << "\n";
        return false;
    }

    XChangeProperty(xdisp, xwin, prop_root, XA_PIXMAP, 32, PropModeReplace,
(unsigned char *) &xpm, 1);
    XChangeProperty(xdisp, xwin, prop_esetroot, XA_PIXMAP, 32,
PropModeReplace, (unsigned char *) &xpm, 1);

    // set it gtk style
    window->set_back_pixmap(pixmap, false);
    window->clear();

    gc_.clear();

   // close display
    _display->close();

    return true;
}

#ifdef USE_XINERAMA
/**
* Sets a bg on a Xinerama "screen", which is one of the virtual screens
on a Xinerama display.
*
*/
bool SetBG::set_bg_xinerama(XineramaScreenInfo* xinerama_info, gint
xinerama_num_screens, Glib::ustring xinerama_screen, Glib::ustring file,
SetMode mode, Gdk::Color bgcolor)
{
    gint winx,winy,winw,winh,wind;
    Glib::RefPtr<Gdk::Display> _display;
    Glib::RefPtr<Gdk::Screen> screen;
    Glib::RefPtr<Gdk::Window> window;
    Glib::RefPtr<Gdk::GC> gc_;
    Glib::RefPtr<Gdk::Colormap> colormap;
    Glib::RefPtr<Gdk::Pixbuf> pixbuf, outpixbuf;
    Glib::RefPtr<Gdk::Pixmap> pixmap;
    gint xin_screen_num; 
    int xin_offset = -1;

   program_log("set_bg_xinerama(): num screens %d, xin screen %s, file
%s", xinerama_num_screens, xinerama_screen.c_str(), file.c_str());

    // get specific xinerama "screen"
    // xinerama_screen is a string that should be "xin_#"
    // "xin_-1" refers to the whole thing
    Glib::ustring xin_numstr = xinerama_screen.substr(4);
    std::stringstream sstr;
    sstr << xin_numstr; 
    sstr >> xin_screen_num;

    if ( xin_screen_num != -1 ) {
        for (int i=0; i<xinerama_num_screens; i++)
            if (xinerama_info[i].screen_number == xin_screen_num)
                xin_offset = i;

        if (xin_offset == -1) {
            std::cerr << _("Could not find Xinerama screen number") << " " <<
xin_screen_num << "\n";
            return false;
        }
    }

    // open display and screen (make sure it is a copy of the default
display)
    _display =
Gdk::Display::open(Gdk::DisplayManager::get()->get_default_display()->get_name());
    if (!_display) {
        std::cerr << _("Could not open display") << "\n";
        return false;
    }

    // get the screen
    screen = _display->get_default_screen();

    // get window stuff
    window = screen->get_root_window();
    window->get_geometry(winx,winy,winw,winh,wind);

    // determine our target dimensions
    gint tarx, tary, tarw, tarh;
    if (xin_screen_num == -1) {
        tarx = winx;
        tary = winy;
        tarw = winw;
        tarh = winh;
    } else {
        tarx = xinerama_info[xin_offset].x_org;
        tary = xinerama_info[xin_offset].y_org;
        tarw = xinerama_info[xin_offset].width;
        tarh = xinerama_info[xin_offset].height;
    }

    Display *xdisp = GDK_DISPLAY_XDISPLAY(_display->gobj());
    XSetCloseDownMode(xdisp, RetainPermanent);
    Window xwin = DefaultRootWindow(xdisp);
    Pixmap* xoldpm = NULL;

    Atom prop_root, prop_esetroot, type;
    int format;
    unsigned long length, after;
    unsigned char *data_root, *data_esetroot;

    prop_root = XInternAtom(xdisp, "_XROOTPMAP_ID", True);
    prop_esetroot = XInternAtom(xdisp, "ESETROOT_PMAP_ID", True);

    if (prop_root != None && prop_esetroot != None) {
        XGetWindowProperty(xdisp, xwin, prop_root, 0L, 1L, False,
AnyPropertyType, &type, &format, &length, &after, &data_root);
        if (type == XA_PIXMAP) {
            XGetWindowProperty(xdisp, xwin, prop_esetroot, 0L, 1L, False,
AnyPropertyType, &type, &format, &length, &after, &data_esetroot);
            if (data_root && data_esetroot)
                if (type == XA_PIXMAP && *((Pixmap *) data_root) == *((Pixmap *)
data_esetroot)) {
                    xoldpm = (Pixmap*)data_root;
                }
        }
    }

    // we need to alloc a colormap every time
    colormap = Gdk::Colormap::get_system();

    // alloc our background color 
    colormap->alloc_color(bgcolor, false, true);

    if (xoldpm) {
        // grab the old pixmap and ref it into a gdk pixmap
        pixmap = Gdk::Pixmap::create(_display, *xoldpm);
        // check that this pixmap is the right size
        int width, height;
        pixmap->get_size(width, height);

        if ((width != winw) || (height != winh) || (pixmap->get_depth() !=
window->get_depth()) ) {
            XKillClient(xdisp, *((Pixmap *) data_root));
            xoldpm = NULL;
        }
    }

    if (!xoldpm) {
        // we have to create it
        pixmap = Gdk::Pixmap::create(window,winw,winh,window->get_depth());
       int width, height;
       pixmap->get_size(width, height);
    }

    // set the colormap 
    pixmap->set_colormap(colormap);

    // get our pixbuf from the file
    try {
        pixbuf = Gdk::Pixbuf::create_from_file(file);   
    } catch (Glib::FileError e) {
        std::cerr << _("ERROR: Could not load file in bg set") << ": " <<
e.what() << "\n";
        return false;
    }

    // apply the bg color to pixbuf here, because every make_ method would
    // have to do it anyway.
    pixbuf = pixbuf->composite_color_simple(pixbuf->get_width(),
        pixbuf->get_height(), Gdk::INTERP_NEAREST, 255, 1,
bgcolor.get_pixel(),
        bgcolor.get_pixel());

    // if automatic, figure out what mode we really want
   if (mode == SetBG::SET_AUTO)
       mode = SetBG::get_real_mode(pixbuf, winw, winh);

   switch(mode) {

        case SetBG::SET_SCALE:
            outpixbuf = SetBG::make_scale(pixbuf, tarw, tarh, bgcolor);
            break;

        case SetBG::SET_TILE:
            outpixbuf = SetBG::make_tile(pixbuf, tarw, tarh, bgcolor);
            break;

        case SetBG::SET_CENTER:
            outpixbuf = SetBG::make_center(pixbuf, tarw, tarh, bgcolor);
            break;

        case SetBG::SET_ZOOM:
            outpixbuf = SetBG::make_zoom(pixbuf, tarw, tarh, bgcolor);
            break;

        case SetBG::SET_ZOOM_FILL:
            outpixbuf = SetBG::make_zoom_fill(pixbuf, tarw, tarh, bgcolor);
            break;

        default:
            std::cerr << _("Unknown mode for saved bg") << " " << std::endl;
            return false;
    };

    // render it to the pixmap
    pixmap->draw_pixbuf(gc_, outpixbuf, 0,0, tarx, tary, tarw, tarh,
Gdk::RGB_DITHER_NONE,0,0);

    Pixmap xpm = GDK_PIXMAP_XID(pixmap->gobj());

    prop_root = XInternAtom(xdisp, "_XROOTPMAP_ID", False);
    prop_esetroot = XInternAtom(xdisp, "ESETROOT_PMAP_ID", False);

    if (prop_root == None || prop_esetroot == None) {
        std::cerr << _("ERROR: BG set could not make atoms.") << "\n";
        return false;
    }

    XChangeProperty(xdisp, xwin, prop_root, XA_PIXMAP, 32, PropModeReplace,
(unsigned char *) &xpm, 1);
    XChangeProperty(xdisp, xwin, prop_esetroot, XA_PIXMAP, 32,
PropModeReplace, (unsigned char *) &xpm, 1);

    // set it gtk style
    window->set_back_pixmap(pixmap, false);
    window->clear();

   _display->close();

    return true;

}

#endif

/**
* Determines if Nautilus is being used to draw the root desktop.
*
* @returns  True if nautilus is drawing the desktop.
*/
SetBG::RootWindowType
SetBG::get_rootwindowtype(Glib::RefPtr<Gdk::Window> rootwin)
{
    GdkAtom type;
   gint format;
   gint length;
    guchar *data;
   SetBG::RootWindowType retval = SetBG::DEFAULT;
   gboolean ret = FALSE;

    ret =    gdk_property_get(rootwin->gobj(),
                              gdk_atom_intern("CAJA_DESKTOP_WINDOW_ID", FALSE),
                             gdk_atom_intern("WINDOW", FALSE),
                              0,
                              4, /* length of a window is 32bits*/
                              FALSE, &type, &format, &length, &data);

   if (!ret)
       return SetBG::DEFAULT;

   guint wid = *(guint*)data;

   Display *xdisp =
GDK_DISPLAY_XDISPLAY(rootwin->get_display()->gobj());
   Atom propatom = XInternAtom(xdisp, "WM_CLASS", FALSE);

   XTextProperty tprop;

   gchar **list;
   gint num;

   if (XGetTextProperty(xdisp, wid, &tprop, propatom) && tprop.nitems)
   {
       if (XTextPropertyToStringList(&tprop, &list, &num))
       {
           // expect 2 strings here (XLib tells us there are 3)
           if (num != 3)
               retval = SetBG::DEFAULT;
           else
           {
               std::string strclass = std::string(list[1]);
               if (strclass == std::string("Xfdesktop")) retval =
SetBG::XFCE;     else
               if (strclass == std::string("Caja"))  retval =
SetBG::NAUTILUS; else
               {
                   std::cerr << _("UNKNOWN ROOT WINDOW TYPE DETECTED,
will attempt to set via normal X procedure") << "\n";
                   retval = SetBG::UNKNOWN;
               }

        }

           XFreeStringList(list);
       }
       XFree(tprop.value);
   }

   g_free(data);
   return retval;
}

/**
* Sets the bg if caja (of mate-desktop) is appearing to draw the
desktop image.
*
* Simply calls mateconftool-2 for now, until we find a better way to do
it.
*/
bool SetBG::set_bg_nautilus(Glib::RefPtr<Gdk::Screen> screen,
Glib::ustring file, SetMode mode, Gdk::Color bgcolor) {

    GError *error = NULL;

   Glib::ustring strmode = "scaled";       // in case of more modes
    switch(mode) {
        case SetBG::SET_SCALE:  strmode = "stretched";  break;
        case SetBG::SET_TILE:   strmode = "wallpaper"; break; 
        case SetBG::SET_CENTER: strmode = "centered"; break;
        case SetBG::SET_ZOOM:   strmode = "scaled"; break;
        case SetBG::SET_ZOOM_FILL:   strmode = "scaled"; break;
    };

   std::vector<std::string> vecCmdLine;
   vecCmdLine.push_back(std::string("mateconftool-2"));
   vecCmdLine.push_back(std::string("--type"));
   vecCmdLine.push_back(std::string("string"));
   vecCmdLine.push_back(std::string("--set"));

vecCmdLine.push_back(std::string("/desktop/mate/background/picture_options"));
   vecCmdLine.push_back(std::string(strmode));
   vecCmdLine.push_back(std::string("--set"));

vecCmdLine.push_back(std::string("/desktop/mate/background/picture_filename"));
   vecCmdLine.push_back(std::string(file));

   try
   {
       Glib::spawn_async("", vecCmdLine, Glib::SPAWN_SEARCH_PATH);
   }
   catch (Glib::SpawnError e)
   {
        std::cerr << _("ERROR") << "\n" << e.what() << "\n";

       for (std::vector<std::string>::const_iterator i =
vecCmdLine.begin(); i != vecCmdLine.end(); i++)
            std::cerr << *i << " ";

        std::cerr << "\n";

       return false;
    }

    return true;
}

/**
* Handles SET_SCALE mode.
*
* @param    orig    The original pixbuf
* @param    winw    Width of the window
* @param    winh    Height of the window
* @param    bgcolor Background color (Unused)
*/
Glib::RefPtr<Gdk::Pixbuf> SetBG::make_scale(const
Glib::RefPtr<Gdk::Pixbuf> orig, const gint winw, const gint winh,
Gdk::Color bgcolor) {
    Glib::RefPtr<Gdk::Pixbuf> retval = orig->scale_simple(winw, winh,
Gdk::INTERP_BILINEAR);
    return retval;
}

/**
* Handles SET_TILE mode.
*
* @param    orig    The original pixbuf
* @param    winw    Width of the window
* @param    winh    Height of the window
* @param    bgcolor Background color (Unused)
*/
Glib::RefPtr<Gdk::Pixbuf> SetBG::make_tile(const
Glib::RefPtr<Gdk::Pixbuf> orig, const gint winw, const gint winh,
Gdk::Color bgcolor) {
    // copy and resize (mainly just resize :)
    Glib::RefPtr<Gdk::Pixbuf> retval = orig->scale_simple(winw, winh,
Gdk::INTERP_NEAREST);

    int orig_width = orig->get_width();
    int orig_height = orig->get_height();

    unsigned count = 0;

    // copy across horizontally first
    unsigned iterations = (unsigned)ceil((double)winw /
(double)orig_width);
    for (count = 0; count < iterations; count++) {
        orig->copy_area(0, 0, ((count + 1) * orig_width) > winw ? orig_width -
(((count+1) * orig_width) - winw) : orig_width, orig_height, retval,
count * orig_width, 0);
    }

    // now vertically
    iterations = (unsigned)ceil((double)winh / (double)orig_height);
    // start at 1 because the first real (0) iteration is already done from
before (it's the source of our copy!)
    for (count = 1; count < iterations; count++) {
        retval->copy_area(0, 0, winw, ((count+ 1)*orig_height) > winh ?
orig_height - (((count+1) * orig_height) - winh) : orig_height, retval,
0, count * orig_height);
    }

    return retval;
}

/**
* Handles SET_CENTER mode.  Crops if needed.
*
* @param    orig    The original pixbuf
* @param    winw    Width of the window
* @param    winh    Height of the window
* @param    bgcolor Background color
*/
Glib::RefPtr<Gdk::Pixbuf> SetBG::make_center(const
Glib::RefPtr<Gdk::Pixbuf> orig, const gint winw, const gint winh,
Gdk::Color bgcolor) {

    Glib::RefPtr<Gdk::Pixbuf> retval = Gdk::Pixbuf::create(
orig->get_colorspace(),
                                                            orig->get_has_alpha(),
                                                            orig->get_bits_per_sample(),
                                                            winw,
                                                            winh);

    // use passed bg color
    retval->fill(GdkColorToUint32(bgcolor));

    int destx = (winw - orig->get_width()) >> 1;
    int desty = (winh - orig->get_height()) >> 1;
    int srcx = 0;
    int srcy = 0;
    int cpyw = orig->get_width();
    int cpyh = orig->get_height();

    if ( orig->get_width() > winw ) {
        srcx = (orig->get_width()-winw) >> 1;
        destx = 0;
        cpyw = winw;
    }
    if ( orig->get_height() > winh) {
        srcy = (orig->get_height()-winh) >> 1;
        desty = 0;
        cpyh = winh;
    }

    orig->copy_area(srcx, srcy, cpyw, cpyh, retval, destx, desty);

    return retval;
}

/**
* Handles SET_ZOOM mode.
*
* @param    orig    The original pixbuf
* @param    winw    Width of the window
* @param    winh    Height of the window
* @param    bgcolor Background color
*/
Glib::RefPtr<Gdk::Pixbuf> SetBG::make_zoom(const
Glib::RefPtr<Gdk::Pixbuf> orig, const gint winw, const gint winh,
Gdk::Color bgcolor) {

    int x, y, resx, resy;
    x = y = 0;

    // depends on bigger side
    unsigned orig_w = orig->get_width();
    unsigned orig_h = orig->get_height();
    // the second term (after the &&) is needed to ensure that the new
height
    // does not exceed the root window height
    if ( orig_w > orig_h && ((float)orig_w / (float)orig_h) >
((float)winw / (float)winh)) {
        resx = winw;
        resy =
(int)(((float)(orig->get_height()*resx))/(float)orig->get_width());
        x = 0;
        y = (winh - resy) >> 1;

    } else {
        resy = winh;
        resx =
(int)(((float)(orig->get_width()*resy))/(float)orig->get_height());
        y = 0;
        x = (winw - resx) >> 1;

    }

    // fix to make sure we can make it
    if ( resx > winw )
        resx = winw;
    if ( resy > winh )
        resy = winh;
    if ( x < 0 )
        x = 0;
    if ( y < 0 )
        y = 0;

    Glib::RefPtr<Gdk::Pixbuf> tmp = orig->scale_simple(resx, resy,
        Gdk::INTERP_BILINEAR);
    Glib::RefPtr<Gdk::Pixbuf> retval = Gdk::Pixbuf::create(
        orig->get_colorspace(), orig->get_has_alpha(),
        orig->get_bits_per_sample(), winw, winh);

    // use passed bg color
    retval->fill(GdkColorToUint32(bgcolor));

    // copy it in
    tmp->copy_area(0, 0, tmp->get_width(), tmp->get_height(), retval, x,
y);

    return retval;
}       

/**
* Handles SET_ZOOM_FILL mode.
*
* @param    orig    The original pixbuf
* @param    winw    Width of the window
* @param    winh    Height of the window
* @param    bgcolor Background color
*/
Glib::RefPtr<Gdk::Pixbuf> SetBG::make_zoom_fill(const
Glib::RefPtr<Gdk::Pixbuf> orig, const gint winw, const gint winh,
Gdk::Color bgcolor) {

    int x, y, w, h;

    // depends on bigger side
    unsigned orig_w = orig->get_width();
    unsigned orig_h = orig->get_height();

   int dw = winw - orig_w;
   int dh = winh - orig_h;

   // what if we expand it to fit the screen width?
   x = 0;
   w = winw;
   h = winw * orig_h / orig_w;
   y = (h - winh) / 2;

   if (!(h >= winh)) {
       // the image isn't tall enough that way!
       // expand it to fit the screen height
       y = 0;
       w = winh * orig_w / orig_h;
       h = winh;
       x = (w - winw) / 2;
   }

    Glib::RefPtr<Gdk::Pixbuf> tmp = orig->scale_simple(w, h,
        Gdk::INTERP_BILINEAR);
    Glib::RefPtr<Gdk::Pixbuf> retval = Gdk::Pixbuf::create(
        orig->get_colorspace(), orig->get_has_alpha(),
        orig->get_bits_per_sample(), winw, winh);

    // use passed bg color
    retval->fill(GdkColorToUint32(bgcolor));

    // copy it in
    tmp->copy_area(x, y, winw, winh, retval, 0, 0);

    return retval;
}

/**
* Utility function to convert a mode (an enum) to a string. 
*/
Glib::ustring SetBG::mode_to_string( const SetMode mode ) {

    Glib::ustring ret;

    switch ( mode ) {
        case SET_SCALE:
            ret = Glib::ustring(_("Scale"));
            break;
        case SET_CENTER:
            ret = Glib::ustring(_("Center"));
            break;
        case SET_TILE:
            ret = Glib::ustring(_("Tile"));
            break;
        case SET_ZOOM:
            ret = Glib::ustring(_("Zoom"));
            break;
        case SET_ZOOM_FILL:
            ret = Glib::ustring(_("ZoomFill"));
            break;
       case SET_AUTO:
           ret = Glib::ustring(_("Auto"));
           break;
    };

    return ret;
}

/**
* Utility function to translate to SetMode from a string.  Meant to be
used from the values
* produced in the above function.
*/
SetBG::SetMode SetBG::string_to_mode( const Glib::ustring str ) {

    if ( str == Glib::ustring(_("Scale")) )
        return SetBG::SET_SCALE;
    else if ( str == Glib::ustring(_("Center")) )
        return SetBG::SET_CENTER;
    else if ( str == Glib::ustring(_("Tile")) )
        return SetBG::SET_TILE;
    else if ( str == Glib::ustring(_("Zoom")) )
        return SetBG::SET_ZOOM;
    else if ( str == Glib::ustring(_("ZoomFill")) )
        return SetBG::SET_ZOOM_FILL;
   else if ( str == Glib::ustring(_("Auto")) )
       return SetBG::SET_AUTO;

    // shouldn't get here
    return SetBG::SET_AUTO;
}

/**
* Transforms the passed Gdk::Color object to a guint32.  Used for
filling a Gdk::Pixbuf.
*
* @param    col     The color to translate.
* @return           A guint32
*/
guint32 SetBG::GdkColorToUint32(const Gdk::Color col)
{
    guint32 ret = 0x00000000;
    ret |= ((unsigned int)(col.get_red_p() * 255) << 24);
    ret |= ((unsigned int)(col.get_green_p() * 255) << 16);
    ret |= ((unsigned int)(col.get_blue_p() * 255) << 8);

    // alpha should always be full (this caused ticket 4)
    ret |= 255;

    return ret;
}

/**
* Determines the best set mode for the pixbuf based on its size
relative to
* the window size.
*
* @param   pixbuf  The loaded pixbuf from the file, before it has been
sized.
* @param   width   The width of the root window.
* @param   height  The height of the root window.
*/
SetBG::SetMode SetBG::get_real_mode(const Glib::RefPtr<Gdk::Pixbuf>
pixbuf, const gint width, const gint height)
{
   SetBG::SetMode mode = SetBG::SET_ZOOM;
   float ratio = ((float)pixbuf->get_width()) /
((float)pixbuf->get_height());

   float f2t = 1.333f;
   float f2f = 1.25f;

   if (fabsf(ratio - f2t) < 0.001)
       mode = SetBG::SET_SCALE;
   else if (fabsf(ratio - f2f) < 0.001)
       mode = SetBG::SET_SCALE;
   else if (ratio == 1.0 && pixbuf->get_width() <= 640)
       mode = SetBG::SET_TILE;
   else if (pixbuf->get_width() <= width && pixbuf->get_height() <=
height)
       mode = SetBG::SET_CENTER;

   return mode;
}
@arisboch
Copy link

If I try to run nitrogen, it still gives me the error UNKNOWN ROOT WINDOW TYPE DETECTED (Caja), please file a bug

@benpicco benpicco linked a pull request May 22, 2021 that will close this issue
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants