xdrag.cc

Go to the documentation of this file.
00001 /*
00002  *  Xdrag.cc - Drag-and-drop under X.
00003  *
00004  *  Copyright (C) 2000-2001  The Exult Team
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019  */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #  include <config.h>
00023 #endif
00024 
00025 #if defined(USE_EXULTSTUDIO) && !defined(WIN32)
00026 
00027 #include <iostream>     /* Debugging messages */
00028 #include <X11/X.h>
00029 #include <X11/Xlib.h>
00030 #include <X11/Xatom.h>
00031 #include "xdrag.h"
00032 #include "u7drag.h"
00033 
00034 using std::cout;
00035 using std::endl;
00036 
00037 /*
00038  *  Get a window's screen coords.
00039  */
00040 
00041 static void Get_window_coords
00042   (
00043   Display *display,
00044   Window win,
00045   int &sx, int& sy    // Coords. returned.
00046   )
00047   {
00048   Window root, parent;    // Get parent window.
00049   Window *children;
00050   unsigned int nchildren;
00051   XQueryTree(display, win, &root, &parent, &children, &nchildren);
00052   if (children)
00053     XFree(children);
00054   if (parent && parent != root) // Recurse on parent.
00055     Get_window_coords(display, parent, sx, sy);
00056   else
00057     sx = sy = 0;
00058   XWindowAttributes atts;   // Get position within parent.
00059   XGetWindowAttributes(display, win, &atts);
00060   sx += atts.x;
00061   sy += atts.y;
00062   }
00063 
00064 /*
00065  *  Initialize.
00066  */
00067 
00068 Xdnd::Xdnd
00069   (
00070   Display *d,
00071   Window xw,      // Window-manager window.
00072   Window xgw,     // Game's display window in xw.
00073   Move_shape_handler_fun movefun,
00074   Move_combo_handler_fun movecmbfun,
00075   Drop_shape_handler_fun shapefun,
00076   Drop_chunk_handler_fun cfun,
00077   Drop_combo_handler_fun cmbfun
00078   ) : display(d), xwmwin(xw), xgamewin(xgw),
00079     num_types(0), lastx(-1), lasty(-1),
00080     file(-1), shape(-1), frame(-1), chunknum(-1), 
00081     combo_cnt(-1), combo(0), combo_xtiles(0), combo_ytiles(0),
00082     data_valid(false), move_shape_handler(movefun),
00083     move_combo_handler(movecmbfun),
00084     shape_handler(shapefun), chunk_handler(cfun),
00085     combo_handler(cmbfun)
00086   {
00087   shapeid_atom = XInternAtom(display, U7_TARGET_SHAPEID_NAME, 0);
00088   chunkid_atom = XInternAtom(display, U7_TARGET_CHUNKID_NAME, 0);
00089   comboid_atom = XInternAtom(display, U7_TARGET_COMBOID_NAME, 0);
00090           // Atom for Xdnd protocol:
00091   xdnd_aware = XInternAtom(display, "XdndAware", 0);
00092   xdnd_enter = XInternAtom(display, "XdndEnter", 0);
00093   xdnd_leave = XInternAtom(display, "XdndLeave", 0);
00094   xdnd_position = XInternAtom(display, "XdndPosition", 0);
00095   xdnd_drop = XInternAtom(display, "XdndDrop", 0);
00096   xdnd_status = XInternAtom(display, "XdndStatus", 0);
00097   xdnd_copy = XInternAtom(display, "XdndActionCopy", 0);
00098   xdnd_ask = XInternAtom(display, "XdndActionAsk", 0);
00099   xdnd_typelist = XInternAtom(display, "XdndTypeList", 0);
00100   xdnd_selection = XInternAtom(display, "XdndSelection", 0);
00101   xdnd_version = 3;
00102           // Create XdndAware property.
00103   if (xwmwin)
00104     XChangeProperty(display, xwmwin, xdnd_aware, XA_ATOM, 32,
00105       PropModeReplace, reinterpret_cast<unsigned char *>(
00106               &xdnd_version), 1);
00107   }
00108 
00109 /*
00110  *  Cleanup.
00111  */
00112 
00113 Xdnd::~Xdnd
00114   (
00115   )
00116   {
00117   delete combo;
00118   }
00119 
00120 /*
00121  *  Handle drag-and-drop.
00122  */
00123 
00124 void Xdnd::client_msg
00125   (
00126   XClientMessageEvent& cev  // Message received.
00127   )
00128   {
00129   cout << "Xwin client msg. received." << endl;
00130   char *nm = XGetAtomName(display, cev.message_type);
00131   if (nm)
00132     cout << "Type = " << nm << endl;
00133   XEvent xev;     // Return event.
00134   xev.xclient.type = ClientMessage;
00135   Window drag_win = cev.data.l[0];// Where drag comes from.
00136   xev.xclient.format = 32;
00137   xev.xclient.window = drag_win;
00138   xev.xclient.data.l[0] = xwmwin;
00139   if (cev.message_type == xdnd_enter)
00140     {
00141     data_valid = false;
00142     if (cev.data.l[1]&1)  // More than 3 types?
00143       {
00144       Atom type;
00145       int format;
00146       unsigned long nitems, after;
00147       Atom *data;
00148       XGetWindowProperty(display, drag_win,
00149         xdnd_typelist, 0, 65536,
00150         false, XA_ATOM, &type, &format, &nitems,
00151           &after, reinterpret_cast<unsigned char **>(
00152                 &data));
00153       if (format != 32 || type != XA_ATOM)
00154         return; // No good.
00155       if (nitems > max_types)
00156         nitems = max_types;
00157       for (num_types = 0; num_types < nitems; num_types++)
00158         drag_types[num_types] = data[num_types];
00159       }
00160     else
00161       {
00162       num_types = 0;
00163       for (int i = 0; i < 3; i++)
00164         if (cev.data.l[2+i])
00165           drag_types[num_types++] = 
00166               cev.data.l[2+i];
00167       cout << "num_types = " << num_types << endl;
00168       }
00169           // Save current window coords.
00170     Get_window_coords(display, xgamewin, winx, winy);
00171     }
00172   else if (cev.message_type == xdnd_position)
00173     {
00174     int i;      // For now, just do shapeid.
00175     for (i = 0; i < num_types; i++)
00176       if (drag_types[i] == shapeid_atom ||
00177           drag_types[i] == chunkid_atom ||
00178           drag_types[i] == comboid_atom)
00179         break;
00180     xev.xclient.message_type = xdnd_status;
00181           // Flags??:  3=good, 0=can't accept.
00182     xev.xclient.data.l[1] = i < num_types ? 3 : 0;
00183           // I think next 2 should be a rect.??
00184     xev.xclient.data.l[2] = 0;
00185     xev.xclient.data.l[3] = 0;
00186     xev.xclient.data.l[4] = xdnd_copy;
00187     XSendEvent(display, drag_win, false, 0, &xev);
00188           // Save mouse position.
00189     int x = ((cev.data.l[2]>>16)&0xffff) - winx;
00190     int y = (cev.data.l[2]&0xffff) - winy;
00191           // Get timestamp.
00192     unsigned long time = 0; //????++++++++++++++++
00193     if (i == num_types)
00194       return;
00195     if (!data_valid)  // Tell owner we want data.
00196       XConvertSelection(display, xdnd_selection, 
00197         drag_types[i], xdnd_selection, xwmwin, time);
00198     else if (file == U7_SHAPE_SHAPES)
00199       (*move_shape_handler)(shape, frame, x,y, 
00200               lastx, lasty, true);
00201     else if (combo_cnt > 0)
00202       (*move_combo_handler)(combo_xtiles, combo_ytiles,
00203         combo_tiles_right, combo_tiles_below,
00204             x, y, lastx, lasty, true);
00205     lastx = x;
00206     lasty = y;
00207     }
00208   else if (cev.message_type == xdnd_leave)
00209     {
00210     num_types = 0;    // Clear list.
00211           // Force repaint to clear grid.
00212     (*move_shape_handler)(-1, -1, 0, 0, lastx, lasty, true);
00213     data_valid = false;
00214     }
00215   else if (cev.message_type == xdnd_drop)
00216     {
00217     int i;      // For now, just do shapes, chunks.
00218     for (i = 0; i < num_types; i++)
00219       if (drag_types[i] == shapeid_atom ||
00220           drag_types[i] == chunkid_atom ||
00221           drag_types[i] == comboid_atom)
00222         break;
00223     bool okay = data_valid && i < num_types;
00224     num_types = 0;
00225     if (!okay)
00226       return;
00227     if (shape >= 0)   // Dropping a shape?
00228       {
00229       if (file == U7_SHAPE_SHAPES)
00230           // For now, just allow "shapes.vga".
00231         (*shape_handler)(shape, frame, lastx,lasty, 0);
00232       }
00233     else if (chunknum >= 0) // A whole chunk.
00234       (*chunk_handler)(chunknum, lastx, lasty, 0);
00235     else if (combo_cnt >= 0 && combo)
00236       (*combo_handler)(combo_cnt, combo, lastx, lasty, 0);
00237 
00238     data_valid = false;
00239     }
00240   }
00241 
00242 /*
00243  *  Get the selection data.
00244  */
00245 
00246 void Xdnd::select_msg
00247   (
00248   XSelectionEvent& sev
00249   )
00250   {
00251   cout << "SelectionEvent received with target type: " <<
00252     XGetAtomName(display, sev.target) << endl;
00253   if (sev.selection != xdnd_selection || 
00254     (sev.target != shapeid_atom && sev.target != chunkid_atom &&
00255      sev.target != comboid_atom) ||
00256       sev.property == None)
00257     return;     // Wrong type.
00258   cout << "HERE" << endl;
00259   file = shape = frame = -1;  // Invalidate old data.
00260   chunknum = -1;
00261   combo_cnt = -1;
00262   combo_xtiles = combo_ytiles = 0;
00263   delete combo;
00264   combo = 0;
00265   Atom type = None;   // Get data.
00266   int format;
00267   unsigned long nitems, after;
00268   unsigned char *data;    
00269   if (XGetWindowProperty(display, sev.requestor, sev.property,
00270           0, 65000, False, AnyPropertyType,
00271           &type, &format, &nitems, &after, &data) != Success)
00272     {
00273     cout << "Error in getting selection" << endl;
00274     return;
00275     }
00276   if (sev.target == shapeid_atom) // Dropping a shape?
00277     {
00278           // Get shape info.
00279     Get_u7_shapeid(data, file, shape, frame);
00280     data_valid = true;
00281     }
00282   else if (sev.target == chunkid_atom)
00283     {     // A whole chunk.
00284     Get_u7_chunkid(data, chunknum);
00285     data_valid = true;
00286     }
00287   else if (sev.target == comboid_atom)
00288     {
00289     Get_u7_comboid(data, combo_xtiles, combo_ytiles,
00290         combo_tiles_right, combo_tiles_below, combo_cnt, combo);
00291 cout << "Combo: xtiles=" << combo_xtiles << ", ytiles=" << combo_ytiles <<
00292   ", tiles_right=" << combo_tiles_right << ", tiles_below=" <<
00293           combo_tiles_below << endl;
00294     data_valid = true;
00295     }
00296   XFree(data);
00297   }
00298 
00299 
00300 #endif  /* USE_EXULTSTUDIO */
00301 
00302 

Generated on Mon Jul 9 14:42:52 2007 for ExultEngine by  doxygen 1.5.1