Back to index

nux  3.0.0
XInputWindow.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2010 Inalogic® Inc.
00003  *
00004  * This program is free software: you can redistribute it and/or modify it
00005  * under the terms of the GNU Lesser General Public License, as
00006  * published by the  Free Software Foundation; either version 2.1 or 3.0
00007  * of the License.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranties of
00011  * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
00012  * PURPOSE.  See the applicable version of the GNU Lesser General Public
00013  * License for more details.
00014  *
00015  * You should have received a copy of both the GNU Lesser General Public
00016  * License along with this program. If not, see <http://www.gnu.org/licenses/>
00017  *
00018  * Authored by: Jay Taoko <jay.taoko_AT_gmail_DOT_com>
00019  *
00020  */
00021 
00022 #include "XInputWindow.h"
00023 #include "GraphicsDisplayX11.h"
00024 #include "GLThread.h"
00025 
00026 // Jay, what is this for?  It isn't referenced anywhere.
00027 #define xdnd_version 5
00028 
00029 namespace nux
00030 {
00031   std::vector<Window> XInputWindow::native_windows_;
00032 
00033   XInputWindow::XInputWindow(const char* title,
00034                              bool        take_focus,
00035                              int         override_redirect)
00036     : strutsEnabled_(false)
00037     , overlayStrutsEnabled_(false)
00038     , display_(GetGraphicsDisplay()->GetX11Display())
00039     , geometry_(0, 0, 1, 1)
00040     , shown_(false)
00041     , mapped_(false)
00042     , overlay_strut_atom_(0)
00043   {
00044     XSetWindowAttributes attrib;
00045 
00046     attrib.override_redirect = override_redirect;
00047     attrib.event_mask = KeyPressMask        |
00048                         KeyReleaseMask      |
00049                         ButtonPressMask     |
00050                         ButtonReleaseMask   |
00051                         EnterWindowMask     |
00052                         LeaveWindowMask     |
00053                         PointerMotionMask   |
00054                         ButtonMotionMask    |
00055                         PropertyChangeMask  |
00056                         StructureNotifyMask |
00057                         FocusChangeMask;
00058 
00059     window_ = XCreateWindow(display_, XDefaultRootWindow(display_),
00060                             geometry_.x, geometry_.y,
00061                             geometry_.width, geometry_.height, 0,
00062                             CopyFromParent, InputOutput, CopyFromParent,
00063                             CWOverrideRedirect | CWEventMask, &attrib);
00064 
00065     native_windows_.push_back(window_);
00066 
00067     Atom data[32];
00068     int     i = 0;
00069     data[i++] = XInternAtom(display_, "_NET_WM_STATE_STICKY", 0);
00070     data[i++] = XInternAtom(display_, "_NET_WM_STATE_SKIP_TASKBAR", 0);
00071     data[i++] = XInternAtom(display_, "_NET_WM_STATE_SKIP_PAGER", 0);
00072 
00073     XChangeProperty(display_, window_,
00074                     XInternAtom(display_, "_NET_WM_STATE", 0),
00075                     XA_ATOM, 32, PropModeReplace,
00076                     (unsigned char *) data, i);
00077 
00078     Atom type[1];
00079     type[0] = XInternAtom(display_, "_NET_WM_WINDOW_TYPE_DOCK", 0);
00080     XChangeProperty(display_, window_,
00081                     XInternAtom(display_, "_NET_WM_WINDOW_TYPE", 0),
00082                     XA_ATOM, 32, PropModeReplace,
00083                     (unsigned char *) type, 1);
00084 
00085     XStoreName(display_, window_, title);
00086     EnsureInputs();
00087 
00088     if (take_focus)
00089       EnableTakeFocus();
00090 
00091     EnableDnd();
00092   }
00093 
00094   XInputWindow::~XInputWindow()
00095   {
00096     native_windows_.erase(std::find(native_windows_.begin(), native_windows_.end(), window_));
00097     XDestroyWindow(display_, window_);
00098   }
00099 
00100   /* static */
00101   std::vector<Window> const& XInputWindow::NativeHandleList()
00102   {
00103     return native_windows_;
00104   }
00105 
00106   std::vector<long int> XInputWindow::GetStrutsData()
00107   {
00108     int n_info;
00109     XineramaScreenInfo *info = XineramaQueryScreens(display_, &n_info);
00110     Region             screen_region;
00111     Region             total_screen_region = XCreateRegion();
00112     Region             input_window_region = XCreateRegion();
00113     Region             intersection = XCreateRegion();
00114     XRectangle         monitor;
00115     XRectangle         tmp_rect;
00116     int largestWidth = 0, largestHeight = 0;
00117     int screenWidth, screenHeight;
00118     std::vector<long int> data(12, 0);
00119 
00120     /* Find the screen that this region intersects */
00121     tmp_rect.x = geometry_.x;
00122     tmp_rect.y = geometry_.y;
00123     tmp_rect.width = geometry_.width;
00124     tmp_rect.height = geometry_.height;
00125 
00126     XUnionRectWithRegion(&tmp_rect, input_window_region, input_window_region);
00127 
00128     /* If there is no Xinerama data available just use the geometry we have */
00129     if (!info)
00130     {
00131       monitor = tmp_rect;
00132       n_info = 0;
00133     }
00134 
00135     for (int i = 0; i < n_info; i++)
00136     {
00137       tmp_rect.x = info[i].x_org;
00138       tmp_rect.y = info[i].y_org;
00139       tmp_rect.width = info[i].width;
00140       tmp_rect.height = info[i].height;
00141 
00142       screen_region = XCreateRegion();
00143 
00144       XUnionRectWithRegion(&tmp_rect, screen_region, screen_region);
00145       XUnionRegion(screen_region, total_screen_region, total_screen_region);
00146       XIntersectRegion(screen_region, input_window_region, intersection);
00147 
00148       if (!XEmptyRegion(intersection))
00149       {
00150         int width = intersection->extents.x2 - intersection->extents.x1;
00151         int height = intersection->extents.y2 - intersection->extents.y1;
00152 
00153         if ((width * height) > (largestWidth * largestHeight))
00154         {
00155           largestWidth = width;
00156           largestHeight = height;
00157 
00158           monitor.x      = info[i].x_org;
00159           monitor.y      = info[i].y_org;
00160           monitor.width  = info[i].width;
00161           monitor.height = info[i].height;
00162         }
00163       }
00164 
00165       XDestroyRegion(screen_region);
00166     }
00167 
00168     screenWidth = total_screen_region->extents.x2 - total_screen_region->extents.x1;
00169     screenHeight = total_screen_region->extents.y2 - total_screen_region->extents.y1;
00170 
00171     XDestroyRegion(input_window_region);
00172     XDestroyRegion(intersection);
00173     XDestroyRegion(total_screen_region);
00174 
00175     if (info)
00176       XFree(info);
00177 
00178     if (geometry_.width > geometry_.height)
00179     {
00180       if (geometry_.y - monitor.y < monitor.height / 2)
00181       {
00182         /* top */
00183         data[2] = geometry_.y + geometry_.height;
00184         data[8] = geometry_.x;
00185         data[9] = geometry_.x + geometry_.width - 1;
00186       }
00187       else
00188       {
00189         /* bottom */
00190         data[3] = (screenHeight - 1) - geometry_.y;
00191         data[10] = geometry_.x;
00192         data[11] = geometry_.x + geometry_.width - 1;
00193       }
00194     }
00195     else
00196     {
00197       if (geometry_.x - monitor.x < monitor.width / 2)
00198       {
00199         /* left */
00200         data[0] = geometry_.x + geometry_.width;
00201         data[4] = geometry_.y;
00202         data[5] = geometry_.y + geometry_.height - 1;
00203       }
00204       else
00205       {
00206         /* right */
00207         data[1] = (screenWidth - 1) - geometry_.y;
00208         data[6] = geometry_.y;
00209         data[7] = geometry_.y + geometry_.height - 1;
00210       }
00211     }
00212 
00213     return data;
00214   }
00215 
00216   void XInputWindow::SetStruts()
00217   {
00218     std::vector<long int> data(GetStrutsData());
00219 
00220     XChangeProperty(display_, window_,
00221                     XInternAtom(display_, "_NET_WM_STRUT_PARTIAL", 0),
00222                     XA_CARDINAL, 32, PropModeReplace,
00223                     (unsigned char*) &data[0], 12);
00224   }
00225 
00226   void XInputWindow::UnsetStruts()
00227   {
00228     XDeleteProperty(display_, window_,
00229                     XInternAtom(display_, "_NET_WM_STRUT_PARTIAL", 0));
00230   }
00231 
00232   void XInputWindow::SetOverlayStruts()
00233   {
00234     std::vector<long int> data(GetStrutsData());
00235 
00236     XChangeProperty(display_, window_, overlay_strut_atom_,
00237                     XA_CARDINAL, 32, PropModeReplace,
00238                     (unsigned char*) &data[0], 12);
00239   }
00240 
00241   void XInputWindow::UnsetOverlayStruts()
00242   {
00243     XDeleteProperty(display_, window_, overlay_strut_atom_);
00244   }
00245 
00246   void XInputWindow::EnableStruts(bool enable)
00247   {
00248     if (strutsEnabled_ == enable)
00249       return;
00250 
00251     strutsEnabled_ = enable;
00252     if (enable)
00253       SetStruts();
00254     else
00255       UnsetStruts();
00256   }
00257 
00258   bool XInputWindow::StrutsEnabled()
00259   {
00260     return strutsEnabled_;
00261   }
00262 
00263   void XInputWindow::EnableOverlayStruts(bool enable)
00264   {
00265     if (overlayStrutsEnabled_ == enable)
00266       return;
00267 
00268     if (!overlay_strut_atom_)
00269       overlay_strut_atom_ = XInternAtom(display_, "_COMPIZ_NET_OVERLAY_STRUT", 0);
00270 
00271     overlayStrutsEnabled_ = enable;
00272     if (enable)
00273       SetOverlayStruts();
00274     else
00275       UnsetOverlayStruts();
00276   }
00277 
00278   bool XInputWindow::OverlayStrutsEnabled()
00279   {
00280     return overlayStrutsEnabled_;
00281   }
00282 
00283   void XInputWindow::EnsureInputs()
00284   {
00285     XSelectInput(display_, window_,
00286                   KeyPressMask        |
00287                   KeyReleaseMask      |
00288                   ButtonPressMask     |
00289                   ButtonReleaseMask   |
00290                   EnterWindowMask     |
00291                   LeaveWindowMask     |
00292                   PointerMotionMask   |
00293                   ButtonMotionMask    |
00294                   PropertyChangeMask  |
00295                   StructureNotifyMask |
00296                   FocusChangeMask);
00297   }
00298 
00299   void XInputWindow::EnableTakeFocus()
00300   {
00301     Atom wmTakeFocus = XInternAtom(display_, "WM_TAKE_FOCUS", False);
00302     XWMHints* wmHints = NULL;
00303 
00304     wmHints = (XWMHints*) calloc(1, sizeof(XWMHints));
00305     wmHints->flags |= InputHint;
00306     wmHints->input = False;
00307     XSetWMHints(display_, window_, wmHints);
00308     free(wmHints);
00309     XSetWMProtocols(display_, window_, &wmTakeFocus, 1);
00310   }
00311 
00312   void XInputWindow::EnableDnd()
00313   {
00314     int version = 5;
00315     XChangeProperty(display_, window_,
00316                     XInternAtom(display_, "XdndAware", false),
00317                     XA_ATOM, 32, PropModeReplace,
00318                     (unsigned char *) &version, 1);
00319   }
00320 
00321   void XInputWindow::DisableDnd()
00322   {
00323     XDeleteProperty(display_, window_,
00324                     XInternAtom(display_, "XdndAware", false));
00325   }
00326 
00328   void XInputWindow::SetGeometry(Rect const& geo)
00329   {
00330     geometry_ = geo;
00331 
00332     if (shown_)
00333       XMoveResizeWindow(display_, window_,
00334                         geo.x, geo.y, geo.width, geo.height);
00335     EnsureInputs();
00336 
00337     if (strutsEnabled_)
00338       SetStruts();
00339     if (overlayStrutsEnabled_)
00340       SetOverlayStruts();
00341   }
00342 
00344   void XInputWindow::SetGeometry(int x, int y, int width, int height)
00345   {
00346     SetGeometry(Rect(x, y, width, height));
00347   }
00348 
00350   Rect const& XInputWindow::GetGeometry() const
00351   {
00352     return geometry_;
00353   }
00354 
00355   Window XInputWindow::GetWindow()
00356   {
00357     return window_;
00358   }
00359 
00360   void XInputWindow::SetInputFocus()
00361   {
00362     XSetInputFocus(display_, window_, RevertToParent, CurrentTime);
00363   }
00364 
00365   void XInputWindow::Hide()
00366   {
00367     XMoveResizeWindow(display_, window_,
00368                       -100 - geometry_.width,
00369                       -100 - geometry_.height,
00370                       geometry_.width,
00371                       geometry_.height);
00372     shown_ = false;
00373   }
00374 
00375   void XInputWindow::Show()
00376   {
00377     shown_ = true;
00378 
00379     if (!mapped_)
00380     {
00381       XMapRaised(display_, window_);
00382       mapped_ = true;
00383 
00384       XEvent xevent;
00385       while (XCheckTypedWindowEvent(display_, window_, MapNotify, &xevent));
00386       XSetInputFocus(display_, window_, RevertToParent, CurrentTime);
00387 
00388     }
00389     XMoveResizeWindow(display_, window_,
00390                       geometry_.x, geometry_.y,
00391                       geometry_.width, geometry_.height);
00392   }
00393 }