Skip to content
New issue

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

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

Already on GitHub? Sign in 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants