//=========================================== // Lumina-DE source code // Copyright (c) 2017, Ken Moore // Available under the 3-clause BSD license // See the LICENSE file for full details //=========================================== #include "LuminaRandR.h" //#include "X11/extensions/Xrandr.h" inline QString atomToName(xcb_atom_t atom){ xcb_get_atom_name_reply_t *nreply = xcb_get_atom_name_reply(QX11Info::connection(), xcb_get_atom_name_unchecked(QX11Info::connection(), atom), NULL); QString name = QString::fromLocal8Bit(xcb_get_atom_name_name(nreply), xcb_get_atom_name_name_length(nreply)); free(nreply); return name; }; //More efficient method for converting lots of atoms to strings inline QStringList atomsToNames(xcb_atom_t *atoms, unsigned int num){ //qDebug() << "atomsToNames:" << num; QList< xcb_get_atom_name_cookie_t > cookies; //qDebug() << " - Get cookies"; for(unsigned int i=0; icurrent_mode = 0; p_obj->geometry = QRect(); p_obj->physicalSizeMM = QSize(); p_obj->primary = false; p_obj->modes.clear(); p_obj->resolutions.clear(); //Get the information associated with the output and save it in the p_objects cache xcb_randr_get_output_info_reply_t *info = xcb_randr_get_output_info_reply(QX11Info::connection(), xcb_randr_get_output_info_unchecked(QX11Info::connection(), p_obj->output, QX11Info::appTime()), NULL); if(info==0){ return false; } //bad output value //First read off the information associated with the output itself if(p_obj->name.isEmpty()){ p_obj->name = QString::fromLocal8Bit( (char*) xcb_randr_get_output_info_name(info), xcb_randr_get_output_info_name_length(info)); } p_obj->physicalSizeMM = QSize(info->mm_width, info->mm_height); //Modes int mode_len = xcb_randr_get_output_info_modes_length(info); for(int j=0; jmodes.append( xcb_randr_get_output_info_modes(info)[j] ); } p_obj->crtc = info->crtc; free(info); //done with output_info //Now load the current status of the output (crtc information) xcb_randr_get_crtc_info_reply_t *cinfo = xcb_randr_get_crtc_info_reply(QX11Info::connection(), xcb_randr_get_crtc_info_unchecked(QX11Info::connection(), p_obj->crtc, QX11Info::appTime()), NULL); if(cinfo!=0){ p_obj->geometry = QRect(cinfo->x, cinfo->y, cinfo->width, cinfo->height); p_obj->current_mode = cinfo->mode; free(cinfo); //done with crtc_info } if(!p_obj->modes.isEmpty()){ //And see if this output is currently the primary output xcb_randr_get_output_primary_reply_t *preply = xcb_randr_get_output_primary_reply(QX11Info::connection(), xcb_randr_get_output_primary_unchecked(QX11Info::connection(), QX11Info::appRootWindow()), NULL); if(preply !=0){ p_obj->primary = (preply->output == p_obj->output); free(preply); } //Now load all the screen resources information, and find matches for the current modes xcb_randr_get_screen_resources_reply_t *srreply = xcb_randr_get_screen_resources_reply(QX11Info::connection(), xcb_randr_get_screen_resources_unchecked(QX11Info::connection(), QX11Info::appRootWindow()), NULL); if(srreply!=0){ for(int i=0; imodes.contains(minfo.id)){ QSize sz(minfo.width, minfo.height); if(!p_obj->resolutions.contains(sz)){ p_obj->resolutions.append( sz); } } } free(srreply); } } return true; } inline xcb_randr_mode_t modeForResolution(QSize res, QList modes){ xcb_randr_mode_t det_mode = XCB_NONE; xcb_randr_get_screen_resources_reply_t *srreply = xcb_randr_get_screen_resources_reply(QX11Info::connection(), xcb_randr_get_screen_resources_unchecked(QX11Info::connection(), QX11Info::appRootWindow()), NULL); if(srreply!=0){ unsigned int refreshrate = 0; for(int i=0; i refreshrate){ det_mode = minfo.id; refreshrate = minfo.dot_clock; } } } free(srreply); } return det_mode; } /* //Clones qDebug() << "Number of Clones:" << xcb_randr_get_output_info_clones_length(info); //Properties xcb_randr_list_output_properties_reply_t *pinfo = xcb_randr_list_output_properties_reply(QX11Info::connection(), xcb_randr_list_output_properties_unchecked(QX11Info::connection(), output), NULL); int pinfo_len = xcb_randr_list_output_properties_atoms_length(pinfo); qDebug() << "Properties:" << pinfo_len; for(int p=0; pstatus == XCB_RANDR_SET_CONFIG_SUCCESS); free(reply); return ok; } return false; } bool OutputDevice::enable(QRect geom){ //if no geom provided, will add as the right-most screen at optimal resolution if(this->isEnabled()){ return true; } //already enabled qDebug() << "Enable Monitor:" << geom; xcb_randr_mode_t mode = modeForResolution(geom.size(), p_obj.modes); if(mode==XCB_NONE){ return false; } //invalid resolution for this monitor xcb_randr_set_crtc_config_cookie_t cookie = xcb_randr_set_crtc_config_unchecked(QX11Info::connection(), p_obj.crtc, XCB_CURRENT_TIME, XCB_CURRENT_TIME, geom.x(), geom.y(), mode, XCB_RANDR_ROTATION_ROTATE_0, 1, &p_obj.output); //Now check the result of the configuration xcb_randr_set_crtc_config_reply_t *reply = xcb_randr_set_crtc_config_reply(QX11Info::connection(), cookie, NULL); if(reply==0){ return false; } bool ok = (reply->status == XCB_RANDR_SET_CONFIG_SUCCESS); free(reply); return ok; } void OutputDevice::changeResolution(QSize){ } void OutputDevice::updateInfoCache(){ if(p_obj.output==0){ //Only have a name (first run) - need to find the corresponding output for this ID xcb_randr_get_screen_resources_reply_t *reply = xcb_randr_get_screen_resources_reply(QX11Info::connection(), xcb_randr_get_screen_resources_unchecked(QX11Info::connection(), QX11Info::appRootWindow()), NULL); int outputnum = xcb_randr_get_screen_resources_outputs_length(reply); for(int i=0; i